Example #1
0
class VCLIpv6ThruHostStackTestCase(VCLTestCase):
    """ VCL IPv6 Thru Host Stack Tests """

    def setUp(self):
        super(VCLIpv6ThruHostStackTestCase, self).setUp()

        self.thru_host_stack_ipv6_setup()
        self.client_ipv6_echo_test_args = ["-6", "-E", self.echo_phrase, "-X",
                                           self.loop0.local_ip6,
                                           self.server_port]

    def tearDown(self):
        self.thru_host_stack_ipv6_tear_down()

        super(VCLIpv6ThruHostStackTestCase, self).tearDown()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_ipv6_thru_host_stack_echo(self):
        """ run LDP IPv6 thru host stack echo test """

        self.thru_host_stack_test("sock_test_server", self.server_ipv6_args,
                                  "sock_test_client",
                                  self.client_ipv6_echo_test_args)
        # TBD: Remove these when VPP thru host teardown config bug is fixed.
        self.thru_host_stack_test("vcl_test_server", self.server_ipv6_args,
                                  "vcl_test_client",
                                  self.client_ipv6_echo_test_args)

    def test_vcl_ipv6_thru_host_stack_echo(self):
        """ run VCL IPv6 thru host stack echo test """

        self.thru_host_stack_test("vcl_test_server", self.server_ipv6_args,
                                  "vcl_test_client",
                                  self.client_ipv6_echo_test_args)
Example #2
0
class VCLIpv6ThruHostStackExtendedBTestCase(VCLTestCase):
    """ VCL IPv6 Thru Host Stack Extended Tests """

    def setUp(self):
        super(VCLIpv6ThruHostStackExtendedBTestCase, self).setUp()

        self.thru_host_stack_ipv6_setup()
        if self.vppDebug:
            self.client_bi_dir_nsock_timeout = 120
            self.client_ipv6_bi_dir_nsock_test_args = ["-6", "-B", "-X",
                                                       self.loop0.local_ip6,
                                                       self.server_port]
        else:
            self.client_bi_dir_nsock_timeout = 60
            self.client_ipv6_bi_dir_nsock_test_args = ["-6", "-I", "2",
                                                       "-B", "-X",
                                                       self.loop0.local_ip6,
                                                       self.server_port]

    def tearDown(self):
        self.thru_host_stack_ipv6_tear_down()

        super(VCLIpv6ThruHostStackExtendedBTestCase, self).tearDown()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_thru_host_stack_bi_dir_nsock(self):
        """ run LDP thru host stack bi-directional (multiple sockets) test """

        self.timeout = self.client_bi_dir_nsock_timeout
        self.thru_host_stack_test("sock_test_server", self.server_ipv6_args,
                                  "sock_test_client",
                                  self.client_ipv6_bi_dir_nsock_test_args)
Example #3
0
class VCLThruHostStackExtendedDTestCase(VCLTestCase):
    """ VCL Thru Host Stack Extended Tests """

    def setUp(self):
        super(VCLThruHostStackExtendedDTestCase, self).setUp()

        self.thru_host_stack_setup()
        if self.vppDebug:
            self.client_uni_dir_nsock_timeout = 120
            self.numSockets = "2"
        else:
            self.client_uni_dir_nsock_timeout = 120
            self.numSockets = "5"

        self.client_uni_dir_nsock_test_args = ["-I", self.numSockets,
                                               "-U", "-X",
                                               self.loop0.local_ip4,
                                               self.server_port]

    def tearDown(self):
        self.thru_host_stack_tear_down()

        super(VCLThruHostStackExtendedDTestCase, self).tearDown()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_vcl_thru_host_stack_uni_dir_nsock(self):
        """ run VCL thru host stack uni-directional (multiple sockets) test """

        self.timeout = self.client_uni_dir_nsock_timeout
        self.thru_host_stack_test("vcl_test_server", self.server_args,
                                  "vcl_test_client",
                                  self.client_uni_dir_nsock_test_args)
Example #4
0
class VCLIpv6ThruHostStackIperfTestCase(VCLTestCase):
    """ VCL IPv6 Thru Host Stack Iperf Tests """
    def setUp(self):
        super(VCLIpv6ThruHostStackIperfTestCase, self).setUp()

        self.thru_host_stack_ipv6_setup()
        self.client_iperf3_timeout = 20
        self.client_ipv6_iperf3_args = ["-V6d", "-c", self.loop0.local_ip6]
        self.server_ipv6_iperf3_args = ["-V6d", "-s"]

    def tearDown(self):
        self.thru_host_stack_ipv6_tear_down()

        super(VCLIpv6ThruHostStackIperfTestCase, self).tearDown()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_thru_host_stack_iperf3(self):
        """ run LDP thru host stack iperf3 test """

        try:
            subprocess.check_output(['iperf3', '-v'])
        except:
            self.logger.error("WARNING: 'iperf3' is not installed,")
            self.logger.error(
                "         'test_ldp_thru_host_stack_iperf3' not run!")
            return

        self.timeout = self.client_iperf3_timeout
        self.thru_host_stack_test("iperf3", self.server_ipv6_iperf3_args,
                                  "iperf3", self.client_ipv6_iperf3_args)
Example #5
0
class VCLIpv6CutThruTestCase(VCLTestCase):
    """ VCL IPv6 Cut Thru Tests """
    def setUp(self):
        super(VCLIpv6CutThruTestCase, self).setUp()

        self.cut_thru_setup()
        self.client_iperf3_timeout = 20
        self.client_uni_dir_nsock_timeout = 60
        self.client_bi_dir_nsock_timeout = 120
        self.client_ipv6_echo_test_args = [
            "-6", "-E", self.echo_phrase, "-X", self.server_ipv6_addr,
            self.server_port
        ]
        self.client_ipv6_iperf3_args = ["-V6d", "-c", self.server_ipv6_addr]
        self.server_ipv6_iperf3_args = ["-V6d", "-s"]
        self.client_ipv6_uni_dir_nsock_test_args = [
            "-6", "-I", "5", "-U", "-X", self.server_ipv6_addr,
            self.server_port
        ]
        self.client_ipv6_bi_dir_nsock_test_args = [
            "-6", "-I", "2", "-B", "-X", self.server_ipv6_addr,
            self.server_port
        ]

    def tearDown(self):
        self.cut_thru_tear_down()

        super(VCLIpv6CutThruTestCase, self).tearDown()

    def test_ldp_ipv6_cut_thru_echo(self):
        """ run LDP IPv6 cut thru echo test """

        self.cut_thru_test("sock_test_server", self.server_ipv6_args,
                           "sock_test_client", self.client_ipv6_echo_test_args)

    def test_ldp_ipv6_cut_thru_iperf3(self):
        """ run LDP IPv6 cut thru iperf3 test """

        try:
            subprocess.check_output(['iperf3', '-v'])
        except:
            self.logger.error("WARNING: 'iperf3' is not installed,")
            self.logger.error(
                "         'test_ldp_ipv6_cut_thru_iperf3' not run!")
            return

        self.timeout = self.client_iperf3_timeout
        self.cut_thru_test("iperf3", self.server_ipv6_iperf3_args, "iperf3",
                           self.client_ipv6_iperf3_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_ipv6_cut_thru_uni_dir_nsock(self):
        """ run LDP IPv6 cut thru uni-directional (multiple sockets) test """

        self.timeout = self.client_uni_dir_nsock_timeout
        self.cut_thru_test("sock_test_server", self.server_ipv6_args,
                           "sock_test_client",
                           self.client_ipv6_uni_dir_nsock_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_ipv6_cut_thru_bi_dir_nsock(self):
        """ run LDP IPv6 cut thru bi-directional (multiple sockets) test """

        self.timeout = self.client_bi_dir_nsock_timeout
        self.cut_thru_test("sock_test_server", self.server_ipv6_args,
                           "sock_test_client",
                           self.client_ipv6_bi_dir_nsock_test_args)

    def test_vcl_ipv6_cut_thru_echo(self):
        """ run VCL IPv6 cut thru echo test """

        self.cut_thru_test("vcl_test_server", self.server_ipv6_args,
                           "vcl_test_client", self.client_ipv6_echo_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_vcl_ipv6_cut_thru_uni_dir_nsock(self):
        """ run VCL IPv6 cut thru uni-directional (multiple sockets) test """

        self.timeout = self.client_uni_dir_nsock_timeout
        self.cut_thru_test("vcl_test_server", self.server_ipv6_args,
                           "vcl_test_client",
                           self.client_ipv6_uni_dir_nsock_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_vcl_ipv6_cut_thru_bi_dir_nsock(self):
        """ run VCL IPv6 cut thru bi-directional (multiple sockets) test """

        self.timeout = self.client_bi_dir_nsock_timeout
        self.cut_thru_test("vcl_test_server", self.server_ipv6_args,
                           "vcl_test_client",
                           self.client_ipv6_bi_dir_nsock_test_args)
Example #6
0
        self.create_stream(packets=6)
        capture = self.send_packets()

        # make sure the one packet we expect actually showed up
        cflows = []
        self.vapi.cli("ipfix flush")
        cflows.append(self.wait_for_cflow_packet(self.collector, templates[1]))
        cflows.append(self.wait_for_cflow_packet(self.collector, templates[1]))
        self.verify_cflow_data_notimer(ipfix_decoder, capture, cflows)
        self.collector.get_capture(5)

        ipfix.remove_vpp_config()
        self.logger.info("FFP_TEST_FINISH_0002")


@unittest.skipUnless(running_extended_tests(), "part of extended tests")
class DisableIPFIX(MethodHolder):
    """Disable IPFIX"""
    def test_0001(self):
        """ disable IPFIX after first packets"""
        self.logger.info("FFP_TEST_START_0001")
        self.pg_enable_capture(self.pg_interfaces)
        self.pkts = []

        ipfix = VppCFLOW(test=self)
        ipfix.add_vpp_config()

        ipfix_decoder = IPFIXDecoder()
        # template packet should arrive immediately
        templates = ipfix.verify_templates(ipfix_decoder)
Example #7
0
    tests_amount = 0
    for testcase_suite in cb.suites.values():
        tests_amount += testcase_suite.countTestCases()
        suites.append(testcase_suite)

    if concurrent_tests == 1:
        new_suite = unittest.TestSuite()
        for suite in suites:
            new_suite.addTest(suite)

        suites = [new_suite]

    print("%s out of %s tests match specified filters" % (
        tests_amount, tests_amount + cb.filtered.countTestCases()))

    if not running_extended_tests():
        print("Not running extended tests (some tests will be skipped)")

    attempts = retries + 1
    if attempts > 1:
        print("Perform %s attempts to pass the suite..." % attempts)

    if run_interactive:
        # don't fork if requiring interactive terminal
        sys.exit(not VppTestRunner(
            verbosity=verbose, failfast=failfast)
                 .run(suites[0]).wasSuccessful())
    else:
        exit_code = 0
        while len(suites) > 0 and attempts > 0:
            tests_amount = sum([x.countTestCases() for x in suites])
Example #8
0
class VCLCutThruTestCase(VclTestCase):
    """ VCL Cut Thru Tests """

    def setUp(self):
        super(VCLCutThruTestCase, self).setUp()

        self.cut_thru_setup()
        self.client_echo_test_args = [self.server_addr, self.server_port,
                                      "-E", self.echo_phrase, "-X"]
        self.client_uni_dir_nsock_timeout = 60
        self.client_uni_dir_nsock_test_args = [self.server_addr,
                                               self.server_port,
                                               "-I", "5", "-U", "-X"]
        self.client_bi_dir_nsock_timeout = 120
        self.client_bi_dir_nsock_test_args = [self.server_addr,
                                              self.server_port,
                                              "-I", "2", "-B", "-X"]

    def tearDown(self):
        self.cut_thru_tear_down()

        super(VCLCutThruTestCase, self).tearDown()

    def test_ldp_cut_thru_echo(self):
        """ run LDP cut thru echo test """

        self.cut_thru_test("sock_test_server", "sock_test_client",
                           self.client_echo_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_cut_thru_uni_dir_nsock(self):
        """ run LDP cut thru uni-directional (multiple sockets) test """

        self.timeout = self.client_uni_dir_nsock_timeout
        self.cut_thru_test("sock_test_server", "sock_test_client",
                           self.client_uni_dir_nsock_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_ldp_cut_thru_bi_dir_nsock(self):
        """ run LDP cut thru bi-directional (multiple sockets) test """

        self.timeout = self.client_bi_dir_nsock_timeout
        self.cut_thru_test("sock_test_server", "sock_test_client",
                           self.client_bi_dir_nsock_test_args)

    def test_vcl_cut_thru_echo(self):
        """ run VCL cut thru echo test """

        self.cut_thru_test("vcl_test_server", "vcl_test_client",
                           self.client_echo_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_vcl_cut_thru_uni_dir_nsock(self):
        """ run VCL cut thru uni-directional (multiple sockets) test """

        self.timeout = self.client_uni_dir_nsock_timeout
        self.cut_thru_test("vcl_test_server", "vcl_test_client",
                           self.client_uni_dir_nsock_test_args)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_vcl_cut_thru_bi_dir_nsock(self):
        """ run VCL cut thru bi-directional (multiple sockets) test """

        self.timeout = self.client_bi_dir_nsock_timeout
        self.cut_thru_test("vcl_test_server", "vcl_test_client",
                           self.client_bi_dir_nsock_test_args)
Example #9
0
class TestKP(VppTestCase):
    """ Kube-proxy Test Case """

    @classmethod
    def setUpClass(cls):
        super(TestKP, cls).setUpClass()
        cls.pods = range(5)
        cls.packets = range(5)

        try:
            cls.create_pg_interfaces(range(2))
            cls.interfaces = list(cls.pg_interfaces)

            for i in cls.interfaces:
                i.admin_up()
                i.config_ip4()
                i.config_ip6()
                i.disable_ipv6_ra()
                i.resolve_arp()
                i.resolve_ndp()
            dst4 = socket.inet_pton(socket.AF_INET, "10.0.0.0")
            dst6 = socket.inet_pton(socket.AF_INET6, "2002::")
            cls.vapi.ip_add_del_route(dst4, 24, cls.pg1.remote_ip4n)
            cls.vapi.ip_add_del_route(dst6, 16, cls.pg1.remote_ip6n, is_ipv6=1)
        except Exception:
            super(TestKP, cls).tearDownClass()
            raise

    def tearDown(self):
        super(TestKP, self).tearDown()
        if not self.vpp_dead:
            self.logger.info(self.vapi.cli("show ku vip verbose"))

    def getIPv4Flow(self, id):
        return (IP(dst="90.0.%u.%u" % (id / 255, id % 255),
                   src="40.0.%u.%u" % (id / 255, id % 255)) /
                UDP(sport=10000 + id, dport=3306))

    def getIPv6Flow(self, id):
        return (IPv6(dst="2001::%u" % (id), src="fd00:f00d:ffff::%u" % (id)) /
                UDP(sport=10000 + id, dport=3306))

    def generatePackets(self, src_if, isv4):
        self.reset_packet_infos()
        pkts = []
        for pktid in self.packets:
            info = self.create_packet_info(src_if, self.pg1)
            payload = self.info_to_payload(info)
            ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
            packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                      ip /
                      Raw(payload))
            self.extend_packet(packet, 128)
            info.data = packet.copy()
            pkts.append(packet)
        return pkts

    def checkInner(self, udp):
        self.assertEqual(udp.dport, 3307)

    def checkCapture(self, nat4, isv4):
        self.pg0.assert_nothing_captured()
        out = self.pg1.get_capture(len(self.packets))

        load = [0] * len(self.pods)
        self.info = None
        for p in out:
            try:
                podid = 0
                udp = None
                if nat4:
                    ip = p[IP]
                    podid = int(ip.dst.split(".")[3])
                    self.assertEqual(ip.version, 4)
                    self.assertEqual(ip.flags, 0)
                    self.assertEqual(ip.dst, "10.0.0.%u" % podid)
                    self.assertEqual(ip.proto, 17)
                    self.assertEqual(len(ip.options), 0)
                    self.assertGreaterEqual(ip.ttl, 63)
                    udp = p[UDP]
                else:
                    ip = p[IPv6]
                    podid = ip.dst.split(":")
                    podid = podid[len(podid) - 1]
                    podid = 0 if podid == "" else int(podid)
                    self.assertEqual(ip.version, 6)
                    self.assertEqual(ip.tc, 0)
                    self.assertEqual(ip.fl, 0)
                    self.assertEqual(
                        socket.inet_pton(socket.AF_INET6, ip.dst),
                        socket.inet_pton(socket.AF_INET6, "2002::%u" % podid)
                    )
                    self.assertEqual(ip.nh, 17)
                    self.assertGreaterEqual(ip.hlim, 63)
                    udp = UDP(str(p[IPv6].payload))
                    # self.assertEqual(len(ip.options), 0)
                self.checkInner(udp)
                load[podid] += 1
            except:
                self.logger.error(ppp("Unexpected or invalid packet:", p))
                raise

        # This is just to roughly check that the balancing algorithm
        # is not completly biased.
        for podid in self.pods:
            if load[podid] < len(self.packets) / (len(self.pods) * 2):
                self.log(
                    "Pod isn't balanced: load[%d] = %d" % (podid, load[podid]))
                raise Exception("Kube-proxy algorithm is biased")

    def test_kp_ip4_nat4(self):
        """ Kube-proxy NAT44 """
        try:
            self.vapi.cli("ku vip 90.0.0.0/8 port 3306 target_port 3307 nat4")
            for podid in self.pods:
                self.vapi.cli("ku pod 90.0.0.0/8 10.0.0.%u" % (podid))

            self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()
            self.checkCapture(nat4=True, isv4=True)

        finally:
            for podid in self.pods:
                self.vapi.cli("ku pod 90.0.0.0/8 10.0.0.%u del" % (podid))
            self.vapi.cli("ku vip 90.0.0.0/8 nat4 del")
            self.vapi.cli("test kube-proxy flowtable flush")

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_kp_ip6_nat4(self):
        """ Kube-proxy NAT64 """

        try:
            self.vapi.cli("ku vip 90.0.0.0/8 port 3306 target_port 3307 nat4")
            for podid in self.pods:
                self.vapi.cli("ku pod 2001::/16 10.0.0.%u" % (podid))

            self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

            self.checkCapture(nat4=True, isv4=False)
        finally:
            for podid in self.pods:
                self.vapi.cli("ku pod 2001::/16 10.0.0.%u del" % (podid))
            self.vapi.cli("ku vip 2001::/16 nat4 del")
            self.vapi.cli("test kube-proxy flowtable flush")

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_kp_ip4_nat6(self):
        """ Kube-proxy NAT46 """
        try:
            self.vapi.cli("ku vip 90.0.0.0/8 port 3306 target_port 3307 nat6")
            for podid in self.pods:
                self.vapi.cli("ku pod 90.0.0.0/8 2002::%u" % (podid))

            self.pg0.add_stream(self.generatePackets(self.pg0, isv4=True))
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

            self.checkCapture(nat4=False, isv4=True)
        finally:
            for podid in self.pods:
                self.vapi.cli("ku pod 90.0.0.0/8 2002::%u del" % (podid))
            self.vapi.cli("ku vip 90.0.0.0/8 nat6 del")
            self.vapi.cli("test kube-proxy flowtable flush")

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_kp_ip6_nat6(self):
        """ Kube-proxy NAT66 """
        try:
            self.vapi.cli("ku vip 2001::/16 port 3306 target_port 3307 nat6")
            for podid in self.pods:
                self.vapi.cli("ku pod 2001::/16 2002::%u" % (podid))

            self.pg0.add_stream(self.generatePackets(self.pg0, isv4=False))
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

            self.checkCapture(nat4=False, isv4=False)
        finally:
            for podid in self.pods:
                self.vapi.cli("ku pod 2001::/16 2002::%u del" % (podid))
            self.vapi.cli("ku vip 2001::/16 nat6 del")
            self.vapi.cli("test kube-proxy flowtable flush")
Example #10
0
class P2PEthernetAPI(VppTestCase):
    """P2P Ethernet tests"""

    p2p_sub_ifs = []

    @classmethod
    def setUpClass(cls):
        super(P2PEthernetAPI, cls).setUpClass()

        # Create pg interfaces
        cls.create_pg_interfaces(range(4))

        # Set up all interfaces
        for i in cls.pg_interfaces:
            i.admin_up()

    def create_p2p_ethernet(self, parent_if, sub_id, remote_mac):
        p2p = VppP2PSubint(self, parent_if, sub_id, mactobinary(remote_mac))
        self.p2p_sub_ifs.append(p2p)

    def delete_p2p_ethernet(self, parent_if, remote_mac):
        self.vapi.delete_p2pethernet_subif(parent_if.sw_if_index,
                                           mactobinary(remote_mac))

    def test_api(self):
        """delete/create p2p subif"""
        self.logger.info("FFP_TEST_START_0000")

        self.create_p2p_ethernet(self.pg0, 1, "de:ad:00:00:00:01")
        self.create_p2p_ethernet(self.pg0, 2, "de:ad:00:00:00:02")
        intfs = self.vapi.cli("show interface")

        self.assertNotEqual(intfs.find('pg0.1'), -1)
        self.assertNotEqual(intfs.find('pg0.2'), -1)
        self.assertEqual(intfs.find('pg0.5'), -1)

        # create pg2.5 subif
        self.create_p2p_ethernet(self.pg0, 5, "de:ad:00:00:00:ff")
        intfs = self.vapi.cli("show interface")
        self.assertNotEqual(intfs.find('pg0.5'), -1)
        # delete pg2.5 subif
        self.delete_p2p_ethernet(self.pg0, "de:ad:00:00:00:ff")

        intfs = self.vapi.cli("show interface")

        self.assertNotEqual(intfs.find('pg0.1'), -1)
        self.assertNotEqual(intfs.find('pg0.2'), -1)
        self.assertEqual(intfs.find('pg0.5'), -1)

        self.logger.info("FFP_TEST_FINISH_0000")

    def test_p2p_subif_creation_1k(self):
        """create 1k of p2p subifs"""
        self.logger.info("FFP_TEST_START_0001")

        macs = []
        clients = 1000
        mac = int("dead00000000", 16)

        for i in range(1, clients + 1):
            try:
                macs.append(':'.join(re.findall('..',
                                                '{:02x}'.format(mac + i))))
                self.vapi.create_p2pethernet_subif(self.pg2.sw_if_index,
                                                   mactobinary(macs[i - 1]), i)
            except Exception:
                print "Failed to create subif %d %s" % (i, macs[i - 1])
                raise

        intfs = self.vapi.cli("show interface").split("\n")
        count = 0
        for intf in intfs:
            if intf.startswith('pg2.'):
                count += 1
        self.assertEqual(count, clients)

        self.logger.info("FFP_TEST_FINISH_0001")

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_p2p_subif_creation_10k(self):
        """create 100k of p2p subifs"""
        self.logger.info("FFP_TEST_START_0001")

        macs = []
        clients = 100000
        mac = int("dead00000000", 16)

        s_time = datetime.datetime.now()
        for i in range(1, clients + 1):
            if i % 1000 == 0:
                e_time = datetime.datetime.now()
                print "Created 1000 subifs in %s secs" % (e_time - s_time)
                s_time = e_time
            try:
                macs.append(':'.join(re.findall('..',
                                                '{:02x}'.format(mac + i))))
                self.vapi.create_p2pethernet_subif(self.pg3.sw_if_index,
                                                   mactobinary(macs[i - 1]), i)
            except Exception:
                print "Failed to create subif %d %s" % (i, macs[i - 1])
                raise

        intfs = self.vapi.cli("show interface").split("\n")
        count = 0
        for intf in intfs:
            if intf.startswith('pg3.'):
                count += 1
        self.assertEqual(count, clients)

        self.logger.info("FFP_TEST_FINISH_0001")
Example #11
0
class TestMACIP(VppTestCase):
    """MACIP Test Case"""

    DEBUG = False

    BRIDGED = True
    ROUTED = False

    IS_IP4 = False
    IS_IP6 = True

    # rule types
    DENY = 0
    PERMIT = 1

    # ACL types
    EXACT_IP = 1
    SUBNET_IP = 2
    WILD_IP = 3

    EXACT_MAC = 1
    WILD_MAC = 2
    OUI_MAC = 3

    ACLS = []

    @classmethod
    def setUpClass(cls):
        """
        Perform standard class setup (defined by class method setUpClass in
        class VppTestCase) before running the test case, set test case related
        variables and configure VPP.
        """
        super(TestMACIP, cls).setUpClass()

        cls.pg_if_packet_sizes = [64, 512, 1518, 9018]  # packet sizes
        cls.bd_id = 10
        cls.remote_hosts_count = 250

        try:
            # create 3 pg interfaces, 1 loopback interface
            cls.create_pg_interfaces(range(3))
            cls.create_loopback_interfaces(range(1))

            cls.interfaces = list(cls.pg_interfaces)
            cls.interfaces.extend(cls.lo_interfaces)

            for i in cls.interfaces:
                i.admin_up()

            # Create BD with MAC learning enabled and put interfaces to this BD
            cls.vapi.sw_interface_set_l2_bridge(cls.loop0.sw_if_index,
                                                bd_id=cls.bd_id,
                                                bvi=1)
            cls.vapi.sw_interface_set_l2_bridge(cls.pg0.sw_if_index,
                                                bd_id=cls.bd_id)
            cls.vapi.sw_interface_set_l2_bridge(cls.pg1.sw_if_index,
                                                bd_id=cls.bd_id)

            # Configure IPv4 addresses on loop interface and routed interface
            cls.loop0.config_ip4()
            cls.loop0.config_ip6()
            cls.pg2.config_ip4()
            cls.pg2.config_ip6()

            # Configure MAC address binding to IPv4 neighbors on loop0
            cls.loop0.generate_remote_hosts(cls.remote_hosts_count)
            # Modify host mac addresses to have different OUI parts
            for i in range(2, cls.remote_hosts_count + 2):
                mac = cls.loop0.remote_hosts[i - 2]._mac.split(':')
                mac[2] = format(int(mac[2], 16) + i, "02x")
                cls.loop0.remote_hosts[i - 2]._mac = ":".join(mac)

            cls.loop0.configure_ipv4_neighbors()
            cls.loop0.configure_ipv6_neighbors()
            # configure MAC address on pg2
            cls.pg2.resolve_arp()
            cls.pg2.resolve_ndp()

            # Loopback BVI interface has remote hosts
            # one half of hosts are behind pg0 second behind pg1
            half = cls.remote_hosts_count // 2
            cls.pg0.remote_hosts = cls.loop0.remote_hosts[:half]
            cls.pg1.remote_hosts = cls.loop0.remote_hosts[half:]

        except Exception:
            super(TestMACIP, cls).tearDownClass()
            raise

    def setUp(self):
        super(TestMACIP, self).setUp()
        self.reset_packet_infos()
        del self.ACLS[:]

    def tearDown(self):
        """
        Show various debug prints after each test.
        """
        super(TestMACIP, self).tearDown()
        if not self.vpp_dead:
            self.logger.info(self.vapi.ppcli("show interface address"))
            self.logger.info(self.vapi.ppcli("show hardware"))
            self.logger.info(self.vapi.ppcli("sh acl-plugin macip acl"))
            self.logger.info(self.vapi.ppcli("sh acl-plugin macip interface"))
            self.logger.info(self.vapi.ppcli("sh classify tables verbose"))
            # print self.vapi.ppcli("show interface address")
            # print self.vapi.ppcli("show hardware")
            # print self.vapi.ppcli("sh acl-plugin macip interface")
            # print self.vapi.ppcli("sh acl-plugin macip acl")
        self.delete_acls()

    def macip_acl_dump_debug(self):
        acls = self.vapi.macip_acl_dump()
        if self.DEBUG:
            for acl in acls:
                for r in acl.r:
                    rule = "ACTION"
                    if r.is_permit == 1:
                        rule = "PERMIT"
                    elif r.is_permit == 0:
                        rule = "DENY  "
                    print "IP6" if r.is_ipv6 else "IP4", \
                          rule, \
                          r.src_mac.encode('hex'), \
                          r.src_mac_mask.encode('hex'),\
                          unpack('<16B', r.src_ip_addr), \
                          r.src_ip_prefix_len
        return acls

    def create_acls(self, mac_type, ip_type, acl_count, rules_count):
        rules = []
        src_mac = int("220000dead00", 16)
        for acl in range(2, (acl_count + 1) * 2):
            host = random.choice(self.loop0.remote_hosts)
            is_ip6 = acl % 2
            ip4 = host.ip4.split('.')
            ip6 = list(unpack('<16B', inet_pton(AF_INET6, host.ip6)))

            if ip_type == self.EXACT_IP:
                prefix_len4 = 32
                prefix_len6 = 128
            elif ip_type == self.WILD_IP:
                ip4 = [0, 0, 0, 0]
                ip6 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
                prefix_len4 = 0
                prefix_len6 = 0
                rules_count[(acl / 2) - 1] = 1
            else:
                prefix_len4 = 24
                prefix_len6 = 64

            if mac_type == self.EXACT_MAC:
                mask = "ff:ff:ff:ff:ff:ff"
            elif mac_type == self.WILD_MAC:
                mask = "00:00:00:00:00:00"
            elif mac_type == self.OUI_MAC:
                mask = "ff:ff:ff:00:00:00"
            else:
                mask = "ff:ff:ff:ff:ff:00"

            ip = ip6 if is_ip6 else ip4
            ip_len = prefix_len6 if is_ip6 else prefix_len4

            for i in range(0, rules_count[(acl / 2) - 1]):
                src_mac += 16777217
                if mac_type == self.WILD_MAC:
                    mac = "00:00:00:00:00:00"
                elif mac_type == self.OUI_MAC:
                    mac = ':'.join(
                        re.findall('..',
                                   '{:02x}'.format(src_mac))[:3]) + ":00:00:00"
                else:
                    mac = ':'.join(re.findall('..', '{:02x}'.format(src_mac)))

                if ip_type == self.EXACT_IP:
                    ip4[3] = random.randint(100, 200)
                    ip6[15] = random.randint(100, 200)
                elif ip_type == self.SUBNET_IP:
                    ip4[2] = random.randint(100, 200)
                    ip4[3] = 0
                    ip6[8] = random.randint(100, 200)
                    ip6[15] = 0
                ip_pack = ''
                for j in range(0, len(ip)):
                    ip_pack += pack('<B', int(ip[j]))

                rule = ({
                    'is_permit': self.PERMIT,
                    'is_ipv6': is_ip6,
                    'src_ip_addr': ip_pack,
                    'src_ip_prefix_len': ip_len,
                    'src_mac': mac.replace(':', '').decode('hex'),
                    'src_mac_mask': mask.replace(':', '').decode('hex')
                })
                rules.append(rule)
                if ip_type == self.WILD_IP:
                    break

            reply = self.vapi.macip_acl_add_replace(rules)
            self.assertEqual(reply.retval, 0)
            self.ACLS.append(reply.acl_index)
            del rules[:]

            src_mac += 1099511627776

    def verify_acls(self, acl_count, rules_count, expected_count=2):
        reply = self.macip_acl_dump_debug()
        for acl in range(2, (acl_count + 1) * 2):
            self.assertEqual(reply[acl - 2].count, rules_count[acl / 2 - 1])

        self.vapi.macip_acl_interface_get()

        self.vapi.macip_acl_interface_add_del(sw_if_index=0, acl_index=0)
        self.vapi.macip_acl_interface_add_del(sw_if_index=1, acl_index=1)

        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.count, expected_count)

    def delete_acls(self):
        for acl in range(len(self.ACLS) - 1, -1, -1):
            self.vapi.macip_acl_del(self.ACLS[acl])

        reply = self.vapi.macip_acl_dump()
        self.assertEqual(len(reply), 0)

    def create_stream(self, mac_type, ip_type, packet_count, src_ip_if,
                      dst_ip_if, bridged_routed, is_ip6):
        # exact MAC and exact IP
        # exact MAC and subnet of IPs
        # exact MAC and wildcard IP
        # wildcard MAC and exact IP
        # wildcard MAC and subnet of IPs
        # wildcard MAC and wildcard IP
        # OUI restricted MAC and exact IP
        # OUI restricted MAC and subnet of IPs
        # OUI restricted MAC and wildcard IP

        packets = []
        rules = []
        ip_permit = ""
        mac_permit = ""
        dst_mac = ""
        mac_rule = "00:00:00:00:00:00"
        mac_mask = "00:00:00:00:00:00"
        for p in range(0, packet_count):
            remote_dst_index = p % len(dst_ip_if.remote_hosts)
            remote_dst_host = dst_ip_if.remote_hosts[remote_dst_index]

            dst_port = 1234 + p
            src_port = 4321 + p
            is_permit = self.PERMIT if p % 3 == 0 else self.DENY
            denyMAC = True if not is_permit and p % 3 == 1 else False
            denyIP = True if not is_permit and p % 3 == 2 else False
            if not is_permit and ip_type == self.WILD_IP:
                denyMAC = True
            if not is_permit and mac_type == self.WILD_MAC:
                denyIP = True
            if bridged_routed:
                if is_permit:
                    src_mac = remote_dst_host._mac
                    dst_mac = 'de:ad:00:00:00:00'
                    dst_ip6 = src_ip_if.remote_ip6
                    src_ip6 = remote_dst_host.ip6
                    dst_ip4 = src_ip_if.remote_ip4
                    src_ip4 = remote_dst_host.ip4
                    ip_permit = src_ip6 if is_ip6 else src_ip4
                    mac_permit = src_mac

                if denyMAC:
                    mac = src_mac.split(':')
                    mac[0] = format(int(mac[0], 16) + 1, "02x")
                    src_mac = ":".join(mac)
                    if is_ip6:
                        src_ip6 = ip_permit
                    else:
                        src_ip4 = ip_permit
                if denyIP:
                    if ip_type != self.WILD_IP:
                        src_mac = mac_permit
                    dst_ip6 = src_ip_if.remote_ip6
                    src_ip6 = remote_dst_host.ip6
                    dst_ip4 = src_ip_if.remote_ip4
                    src_ip4 = remote_dst_host.ip4
            else:  # TODO
                src_mac = src_ip_if.remote_mac
                dst_mac = src_ip_if.local_mac
                src_ip6 = src_ip_if.remote_ip6
                dst_ip6 = remote_dst_host.ip6
                src_ip4 = src_ip_if.remote_ip4
                dst_ip4 = remote_dst_host.ip4

            if is_permit:
                info = self.create_packet_info(src_ip_if, dst_ip_if)
                payload = self.info_to_payload(info)
            else:
                payload = "to be blocked"

            if mac_type == self.WILD_MAC:
                mac = src_mac.split(':')
                for i in range(1, 5):
                    mac[i] = format(random.randint(0, 255), "02x")
                src_mac = ":".join(mac)

            # create packet
            packet = Ether(src=src_mac, dst=dst_mac)
            if bridged_routed:
                ip_rule = src_ip6 if is_ip6 else src_ip4
            else:
                ip_rule = dst_ip6 if is_ip6 else dst_ip4
            if is_ip6:
                if ip_type != self.EXACT_IP:
                    sub_ip = list(unpack('<16B', inet_pton(AF_INET6, ip_rule)))
                    if ip_type == self.WILD_IP:
                        sub_ip[0] = random.randint(240, 254)
                        sub_ip[1] = random.randint(230, 239)
                        sub_ip[14] = random.randint(100, 199)
                        sub_ip[15] = random.randint(200, 255)
                    elif ip_type == self.SUBNET_IP:
                        if denyIP:
                            sub_ip[2] = str(int(sub_ip[2]) + 1)
                        sub_ip[14] = random.randint(100, 199)
                        sub_ip[15] = random.randint(200, 255)
                    if bridged_routed:
                        src_ip6 = inet_ntop(AF_INET6, str(bytearray(sub_ip)))
                    else:
                        dst_ip6 = inet_ntop(AF_INET6, str(bytearray(sub_ip)))
                packet /= IPv6(src=src_ip6, dst=dst_ip6)
            else:
                if ip_type != self.EXACT_IP:
                    sub_ip = ip_rule.split('.')
                    if ip_type == self.WILD_IP:
                        sub_ip[0] = str(random.randint(1, 49))
                        sub_ip[1] = str(random.randint(50, 99))
                        sub_ip[2] = str(random.randint(100, 199))
                        sub_ip[3] = str(random.randint(200, 255))
                    elif ip_type == self.SUBNET_IP:
                        if denyIP:
                            sub_ip[1] = str(int(sub_ip[1]) + 1)
                        sub_ip[2] = str(random.randint(100, 199))
                        sub_ip[3] = str(random.randint(200, 255))
                    if bridged_routed:
                        src_ip4 = ".".join(sub_ip)
                    else:
                        # TODO
                        dst_ip4 = ".".join(sub_ip)
                packet /= IP(src=src_ip4, dst=dst_ip4, frag=0, flags=0)

            packet /= UDP(sport=src_port, dport=dst_port) / Raw(payload)

            packet[Raw].load += " mac:" + src_mac

            size = self.pg_if_packet_sizes[p % len(self.pg_if_packet_sizes)]
            self.extend_packet(packet, size)
            packets.append(packet)

            # create suitable rule
            if mac_type == self.EXACT_MAC:
                mac_rule = src_mac
                mac_mask = "ff:ff:ff:ff:ff:ff"
            elif mac_type == self.WILD_MAC:
                mac_rule = "00:00:00:00:00:00"
                mac_mask = "00:00:00:00:00:00"
            elif mac_type == self.OUI_MAC:
                mac = src_mac.split(':')
                mac[3] = mac[4] = mac[5] = '00'
                mac_rule = ":".join(mac)
                mac_mask = "ff:ff:ff:00:00:00"

            if is_ip6:
                if ip_type == self.WILD_IP:
                    ip = "0::0"
                else:
                    if bridged_routed:
                        ip = src_ip6
                    else:
                        ip = dst_ip6
                    if ip_type == self.SUBNET_IP:
                        sub_ip = list(unpack('<16B', inet_pton(AF_INET6, ip)))
                        for i in range(8, 16):
                            sub_ip[i] = 0
                        ip = inet_ntop(AF_INET6, str(bytearray(sub_ip)))
            else:
                if ip_type == self.WILD_IP:
                    ip = "0.0.0.0"
                else:
                    if bridged_routed:
                        ip = src_ip4
                    else:
                        ip = dst_ip4
                    if ip_type == self.SUBNET_IP:
                        sub_ip = ip.split('.')
                        sub_ip[2] = sub_ip[3] = '0'
                        ip = ".".join(sub_ip)

            prefix_len = 128 if is_ip6 else 32
            if ip_type == self.WILD_IP:
                prefix_len = 0
            elif ip_type == self.SUBNET_IP:
                prefix_len = 64 if is_ip6 else 16
            ip_rule = inet_pton(AF_INET6 if is_ip6 else AF_INET, ip)

            if mac_type == self.WILD_MAC and ip_type == self.WILD_IP and p > 0:
                continue

            if is_permit:
                rule = ({
                    'is_permit': is_permit,
                    'is_ipv6': is_ip6,
                    'src_ip_addr': ip_rule,
                    'src_ip_prefix_len': prefix_len,
                    'src_mac': mac_rule.replace(':', '').decode('hex'),
                    'src_mac_mask': mac_mask.replace(':', '').decode('hex')
                })
                rules.append(rule)

        # deny all other packets
        if not (mac_type == self.WILD_MAC and ip_type == self.WILD_IP):
            rule = ({
                'is_permit': 0,
                'is_ipv6': is_ip6,
                'src_ip_addr': "",
                'src_ip_prefix_len': 0,
                'src_mac': "",
                'src_mac_mask': ""
            })
            rules.append(rule)

        return {'stream': packets, 'rules': rules}

    def verify_capture(self, stream, capture, is_ip6):
        p_l3 = IPv6 if is_ip6 else IP
        if self.DEBUG:
            for p in stream:
                print p[Ether].src, p[Ether].dst, p[p_l3].src, p[p_l3].dst

        acls = self.macip_acl_dump_debug()

        # TODO : verify
        # for acl in acls:
        #     for r in acl.r:
        #         print r.src_mac.encode('hex'), \
        #               r.src_mac_mask.encode('hex'),\
        #               unpack('<16B', r.src_ip_addr), \
        #               r.src_ip_prefix_len
        #
        # for p in capture:
        #     print p[Ether].src, p[Ether].dst, p[p_l3].src, p[p_l3].dst
        #     data = p[Raw].load.split(':',1)[1]
        #     print p[p_l3].src, data

    def run_traffic(self, mac_type, ip_type, bridged_routed, is_ip6, packets):
        self.reset_packet_infos()

        tx_if = self.pg0 if bridged_routed else self.pg2
        rx_if = self.pg2 if bridged_routed else self.pg0

        test_dict = self.create_stream(mac_type, ip_type, packets, self.pg2,
                                       self.loop0, bridged_routed, is_ip6)

        reply = self.vapi.macip_acl_add_replace(test_dict['rules'])
        self.assertEqual(reply.retval, 0)
        acl_index = reply.acl_index

        self.vapi.macip_acl_interface_add_del(sw_if_index=tx_if.sw_if_index,
                                              acl_index=acl_index)
        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.acls[tx_if.sw_if_index], acl_index)
        self.ACLS.append(reply.acls[tx_if.sw_if_index])

        tx_if.add_stream(test_dict['stream'])
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        packet_count = self.get_packet_count_for_if_idx(self.loop0.sw_if_index)
        if mac_type == self.WILD_MAC and ip_type == self.WILD_IP:
            packet_count = packets
        capture = rx_if.get_capture(packet_count)
        self.verify_capture(test_dict['stream'], capture, is_ip6)

    def run_test_acls(self,
                      mac_type,
                      ip_type,
                      acl_count,
                      rules_count,
                      traffic=None,
                      ip=None):
        self.create_acls(mac_type, ip_type, acl_count, rules_count)
        self.verify_acls(acl_count, rules_count)

        if traffic is not None:
            self.run_traffic(self.EXACT_MAC, self.EXACT_IP, traffic, ip, 9)

    def test_acl_ip4_exactMAC_exactIP(self):
        """ IP4 MACIP exactMAC|exactIP ACL
        """
        self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_exactMAC_exactIP(self):
        """ IP6 MACIP exactMAC|exactIP ACL
        """

        self.run_traffic(self.EXACT_MAC, self.EXACT_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_exactMAC_subnetIP(self):
        """ IP4 MACIP exactMAC|subnetIP ACL
        """

        self.run_traffic(self.EXACT_MAC, self.SUBNET_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_exactMAC_subnetIP(self):
        """ IP6 MACIP exactMAC|subnetIP ACL
        """

        self.run_traffic(self.EXACT_MAC, self.SUBNET_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_exactMAC_wildIP(self):
        """ IP4 MACIP exactMAC|wildIP ACL
        """

        self.run_traffic(self.EXACT_MAC, self.WILD_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_exactMAC_wildIP(self):
        """ IP6 MACIP exactMAC|wildIP ACL
        """

        self.run_traffic(self.EXACT_MAC, self.WILD_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_ouiMAC_exactIP(self):
        """ IP4 MACIP ouiMAC|exactIP ACL
        """

        self.run_traffic(self.OUI_MAC, self.EXACT_IP, self.BRIDGED,
                         self.IS_IP4, 3)

    def test_acl_ip6_ouiMAC_exactIP(self):
        """ IP6 MACIP oui_MAC|exactIP ACL
        """

        self.run_traffic(self.OUI_MAC, self.EXACT_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_ouiMAC_subnetIP(self):
        """ IP4 MACIP ouiMAC|subnetIP ACL
        """

        self.run_traffic(self.OUI_MAC, self.SUBNET_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_ouiMAC_subnetIP(self):
        """ IP6 MACIP ouiMAC|subnetIP ACL
        """

        self.run_traffic(self.OUI_MAC, self.SUBNET_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_ouiMAC_wildIP(self):
        """ IP4 MACIP ouiMAC|wildIP ACL
        """

        self.run_traffic(self.OUI_MAC, self.WILD_IP, self.BRIDGED, self.IS_IP4,
                         9)

    def test_acl_ip6_ouiMAC_wildIP(self):
        """ IP6 MACIP ouiMAC|wildIP ACL
        """

        self.run_traffic(self.OUI_MAC, self.WILD_IP, self.BRIDGED, self.IS_IP6,
                         9)

    def test_acl_ip4_wildMAC_exactIP(self):
        """ IP4 MACIP wildcardMAC|exactIP ACL
        """

        self.run_traffic(self.WILD_MAC, self.EXACT_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_wildMAC_exactIP(self):
        """ IP6 MACIP wildcardMAC|exactIP ACL
        """

        self.run_traffic(self.WILD_MAC, self.EXACT_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_wildMAC_subnetIP(self):
        """ IP4 MACIP wildcardMAC|subnetIP ACL
        """

        self.run_traffic(self.WILD_MAC, self.SUBNET_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_wildMAC_subnetIP(self):
        """ IP6 MACIP wildcardMAC|subnetIP ACL
        """

        self.run_traffic(self.WILD_MAC, self.SUBNET_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_ip4_wildMAC_wildIP(self):
        """ IP4 MACIP wildcardMAC|wildIP ACL
        """

        self.run_traffic(self.WILD_MAC, self.WILD_IP, self.BRIDGED,
                         self.IS_IP4, 9)

    def test_acl_ip6_wildMAC_wildIP(self):
        """ IP6 MACIP wildcardMAC|wildIP ACL
        """

        self.run_traffic(self.WILD_MAC, self.WILD_IP, self.BRIDGED,
                         self.IS_IP6, 9)

    def test_acl_1_2(self):
        """ MACIP ACL with 2 entries
        """

        self.run_test_acls(self.EXACT_MAC, self.WILD_IP, 1, [2])

    def test_acl_1_5(self):
        """ MACIP ACL with 5 entries
        """

        self.run_test_acls(self.EXACT_MAC, self.SUBNET_IP, 1, [5])

    def test_acl_1_10(self):
        """ MACIP ACL with 10 entries
        """

        self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 1, [10])

    def test_acl_1_20(self):
        """ MACIP ACL with 20 entries
        """

        self.run_test_acls(self.OUI_MAC, self.WILD_IP, 1, [20])

    def test_acl_1_50(self):
        """ MACIP ACL with 50 entries
        """

        self.run_test_acls(self.OUI_MAC, self.SUBNET_IP, 1, [50])

    def test_acl_1_100(self):
        """ MACIP ACL with 100 entries
        """

        self.run_test_acls(self.OUI_MAC, self.EXACT_IP, 1, [100])

    def test_acl_2_X(self):
        """ MACIP 2 ACLs each with 100+ entries
        """

        self.run_test_acls(self.OUI_MAC, self.SUBNET_IP, 2, [100, 200])

    def test_acl_10_X(self):
        """ MACIP 10 ACLs each with 100+ entries
        """

        self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 10,
                           [100, 120, 140, 160, 180, 200, 210, 220, 230, 240])

    def test_acl_10_X_traffic_ip4(self):
        """ MACIP 10 ACLs each with 100+ entries with IP4 traffic
        """

        self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 10,
                           [100, 120, 140, 160, 180, 200, 210, 220, 230, 240],
                           self.BRIDGED, self.IS_IP4)

    def test_acl_10_X_traffic_ip6(self):
        """ MACIP 10 ACLs each with 100+ entries with IP6 traffic
        """

        self.run_test_acls(self.EXACT_MAC, self.EXACT_IP, 10,
                           [100, 120, 140, 160, 180, 200, 210, 220, 230, 240],
                           self.BRIDGED, self.IS_IP6)

    def test_delete_intf(self):
        """ MACIP ACL delete intf with acl
        """

        intf_count = len(self.interfaces) + 1
        rules_count = [3, 5, 4]
        intf = []
        self.create_acls(self.EXACT_IP, self.EXACT_MAC, 3, rules_count)

        intf.append(VppLoInterface(self, 0))
        intf.append(VppLoInterface(self, 1))

        sw_if_index0 = intf[0].sw_if_index
        self.vapi.macip_acl_interface_add_del(sw_if_index0, 1)

        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.count, intf_count + 1)
        self.assertEqual(reply.acls[sw_if_index0], 1)

        sw_if_index1 = intf[1].sw_if_index
        self.vapi.macip_acl_interface_add_del(sw_if_index1, 0)

        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.count, intf_count + 2)
        self.assertEqual(reply.acls[sw_if_index1], 0)

        intf[0].remove_vpp_config()
        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.count, intf_count + 2)
        self.assertEqual(reply.acls[sw_if_index0], 4294967295)
        self.assertEqual(reply.acls[sw_if_index1], 0)

        intf.append(VppLoInterface(self, 2))
        intf.append(VppLoInterface(self, 3))
        sw_if_index2 = intf[2].sw_if_index
        sw_if_index3 = intf[3].sw_if_index
        self.vapi.macip_acl_interface_add_del(sw_if_index2, 1)
        self.vapi.macip_acl_interface_add_del(sw_if_index3, 1)

        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.count, intf_count + 3)
        self.assertEqual(reply.acls[sw_if_index1], 0)
        self.assertEqual(reply.acls[sw_if_index2], 1)
        self.assertEqual(reply.acls[sw_if_index3], 1)

        intf[2].remove_vpp_config()
        intf[1].remove_vpp_config()

        reply = self.vapi.macip_acl_interface_get()
        self.assertEqual(reply.count, intf_count + 3)
        self.assertEqual(reply.acls[sw_if_index0], 4294967295)
        self.assertEqual(reply.acls[sw_if_index1], 4294967295)
        self.assertEqual(reply.acls[sw_if_index2], 4294967295)
        self.assertEqual(reply.acls[sw_if_index3], 1)

        intf[3].remove_vpp_config()
        reply = self.vapi.macip_acl_interface_get()

        self.assertEqual(len([x for x in reply.acls if x != 4294967295]), 0)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_check(self):
        """ MACIP with routed traffic
Example #12
0
class TestBier(VppTestCase):
    """ BIER Test Case """
    def setUp(self):
        super(TestBier, self).setUp()

        # create 2 pg interfaces
        self.create_pg_interfaces(range(3))

        # create the default MPLS table
        self.tables = []
        tbl = VppMplsTable(self, 0)
        tbl.add_vpp_config()
        self.tables.append(tbl)

        tbl = VppIpTable(self, 10)
        tbl.add_vpp_config()
        self.tables.append(tbl)

        # setup both interfaces
        for i in self.pg_interfaces:
            if i == self.pg2:
                i.set_table_ip4(10)
            i.admin_up()
            i.config_ip4()
            i.resolve_arp()
            i.enable_mpls()

    def tearDown(self):
        for i in self.pg_interfaces:
            i.disable_mpls()
            i.unconfig_ip4()
            i.set_table_ip4(0)
            i.admin_down()
        super(TestBier, self).tearDown()

    def bier_midpoint(self, hdr_len_id, n_bytes, max_bp):
        """BIER midpoint"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, hdr_len_id)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # A packet with no bits set gets dropped
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             MPLS(label=77, ttl=255) / BIER(length=hdr_len_id) /
             IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
             UDP(sport=1234, dport=1234) / Raw())
        pkts = [p]

        self.send_and_assert_no_replies(self.pg0, pkts, "Empty Bit-String")

        #
        # Add a BIER route for each bit-position in the table via a different
        # next-hop. Testing whether the BIER walk and replicate forwarding
        # function works for all bit posisitons.
        #
        nh_routes = []
        bier_routes = []
        for i in range(1, max_bp + 1):
            nh = "10.0.%d.%d" % (i / 255, i % 255)
            nh_routes.append(
                VppIpRoute(self, nh, 32, [
                    VppRoutePath(self.pg1.remote_ip4,
                                 self.pg1.sw_if_index,
                                 labels=[VppMplsLabel(2000 + i)])
                ]))
            nh_routes[-1].add_vpp_config()

            bier_routes.append(
                VppBierRoute(self, bti, i, [
                    VppRoutePath(
                        nh, 0xffffffff, labels=[VppMplsLabel(100 + i)])
                ]))
            bier_routes[-1].add_vpp_config()

        #
        # A packet with all bits set gets replicated once for each bit
        #
        pkt_sizes = [64, 1400]

        for pkt_size in pkt_sizes:
            p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 MPLS(label=77, ttl=255) /
                 BIER(length=hdr_len_id, BitString=chr(255) * n_bytes) /
                 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) /
                 UDP(sport=1234, dport=1234) / Raw(chr(5) * pkt_size))
            pkts = p

            self.pg0.add_stream(pkts)
            self.pg_enable_capture(self.pg_interfaces)
            self.pg_start()

            rx = self.pg1.get_capture(max_bp)

            for rxp in rx:
                #
                # The packets are not required to be sent in bit-position order
                # when we setup the routes above we used the bit-position to
                # construct the out-label. so use that here to determine the BP
                #
                olabel = rxp[MPLS]
                bp = olabel.label - 2000

                blabel = olabel[MPLS].payload
                self.assertEqual(blabel.label, 100 + bp)
                self.assertEqual(blabel.ttl, 254)

                bier_hdr = blabel[MPLS].payload

                self.assertEqual(bier_hdr.id, 5)
                self.assertEqual(bier_hdr.version, 0)
                self.assertEqual(bier_hdr.length, hdr_len_id)
                self.assertEqual(bier_hdr.entropy, 0)
                self.assertEqual(bier_hdr.OAM, 0)
                self.assertEqual(bier_hdr.RSV, 0)
                self.assertEqual(bier_hdr.DSCP, 0)
                self.assertEqual(bier_hdr.Proto, 5)

                # The bit-string should consist only of the BP given by i.
                byte_array = ['\0'] * (n_bytes)
                byte_val = chr(1 << (bp - 1) % 8)
                byte_pos = n_bytes - (((bp - 1) / 8) + 1)
                byte_array[byte_pos] = byte_val
                bitstring = ''.join(byte_array)

                self.assertEqual(len(bitstring), len(bier_hdr.BitString))
                self.assertEqual(bitstring, bier_hdr.BitString)

        #
        # cleanup. not strictly necessary, but it's much quicker this way
        # becuase the bier_fib_dump and ip_fib_dump will be empty when the
        # auto-cleanup kicks in
        #
        for br in bier_routes:
            br.remove_vpp_config()
        for nhr in nh_routes:
            nhr.remove_vpp_config()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_1024(self):
        """BIER midpoint BSL:1024"""
        self.bier_midpoint(BIERLength.BIER_LEN_1024, 128, 1024)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_512(self):
        """BIER midpoint BSL:512"""
        self.bier_midpoint(BIERLength.BIER_LEN_512, 64, 512)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_256(self):
        """BIER midpoint BSL:256"""
        self.bier_midpoint(BIERLength.BIER_LEN_256, 32, 256)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_midpoint_128(self):
        """BIER midpoint BSL:128"""
        self.bier_midpoint(BIERLength.BIER_LEN_128, 16, 128)

    def test_bier_midpoint_64(self):
        """BIER midpoint BSL:64"""
        self.bier_midpoint(BIERLength.BIER_LEN_64, 8, 64)

    def test_bier_head(self):
        """BIER head"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # 2 bit positions via two next hops
        #
        nh1 = "10.0.0.1"
        nh2 = "10.0.0.2"
        ip_route_1 = VppIpRoute(self, nh1, 32, [
            VppRoutePath(self.pg1.remote_ip4,
                         self.pg1.sw_if_index,
                         labels=[VppMplsLabel(2001)])
        ])
        ip_route_2 = VppIpRoute(self, nh2, 32, [
            VppRoutePath(self.pg1.remote_ip4,
                         self.pg1.sw_if_index,
                         labels=[VppMplsLabel(2002)])
        ])
        ip_route_1.add_vpp_config()
        ip_route_2.add_vpp_config()

        bier_route_1 = VppBierRoute(
            self, bti, 1,
            [VppRoutePath(nh1, 0xffffffff, labels=[VppMplsLabel(101)])])
        bier_route_2 = VppBierRoute(
            self, bti, 2,
            [VppRoutePath(nh2, 0xffffffff, labels=[VppMplsLabel(102)])])
        bier_route_1.add_vpp_config()
        bier_route_2.add_vpp_config()

        #
        # An imposition object with both bit-positions set
        #
        bi = VppBierImp(self, bti, 333, chr(0x3) * 32)
        bi.add_vpp_config()

        #
        # Add a multicast route that will forward into the BIER doamin
        #
        route_ing_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[
                VppMRoutePath(self.pg0.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                VppMRoutePath(0xffffffff,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                              proto=DpoProto.DPO_PROTO_BIER,
                              bier_imp=bi.bi_index)
            ])
        route_ing_232_1_1_1.add_vpp_config()

        #
        # inject an IP packet. We expect it to be BIER encapped and
        # replicated.
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234))

        self.pg0.add_stream([p])
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(2)

        #
        # Encap Stack is; eth, MPLS, MPLS, BIER
        #
        igp_mpls = rx[0][MPLS]
        self.assertEqual(igp_mpls.label, 2001)
        self.assertEqual(igp_mpls.ttl, 64)
        self.assertEqual(igp_mpls.s, 0)
        bier_mpls = igp_mpls[MPLS].payload
        self.assertEqual(bier_mpls.label, 101)
        self.assertEqual(bier_mpls.ttl, 64)
        self.assertEqual(bier_mpls.s, 1)
        self.assertEqual(rx[0][BIER].length, 2)

        igp_mpls = rx[1][MPLS]
        self.assertEqual(igp_mpls.label, 2002)
        self.assertEqual(igp_mpls.ttl, 64)
        self.assertEqual(igp_mpls.s, 0)
        bier_mpls = igp_mpls[MPLS].payload
        self.assertEqual(bier_mpls.label, 102)
        self.assertEqual(bier_mpls.ttl, 64)
        self.assertEqual(bier_mpls.s, 1)
        self.assertEqual(rx[0][BIER].length, 2)

    def test_bier_tail(self):
        """BIER Tail"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # disposition table
        #
        bdt = VppBierDispTable(self, 8)
        bdt.add_vpp_config()

        #
        # BIER route in table that's for-us
        #
        bier_route_1 = VppBierRoute(self, bti, 1, [
            VppRoutePath("0.0.0.0",
                         0xffffffff,
                         proto=DpoProto.DPO_PROTO_BIER,
                         nh_table_id=8)
        ])
        bier_route_1.add_vpp_config()

        #
        # An entry in the disposition table
        #
        bier_de_1 = VppBierDispEntry(self,
                                     bdt.id,
                                     99,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0",
                                     0,
                                     rpf_id=8192)
        bier_de_1.add_vpp_config()

        #
        # A multicast route to forward post BIER disposition
        #
        route_eg_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[
                VppMRoutePath(self.pg1.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)
            ])
        route_eg_232_1_1_1.add_vpp_config()
        route_eg_232_1_1_1.update_rpf_id(8192)

        #
        # A packet with all bits set gets spat out to BP:1
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_256,
                                            BitString=chr(255) * 32,
                                            BFRID=99) /
             IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) /
             Raw())

        self.send_and_expect(self.pg0, [p], self.pg1)

        #
        # A packet that does not match the Disposition entry gets dropped
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_256,
                                            BitString=chr(255) * 32,
                                            BFRID=77) /
             IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) /
             Raw())
        self.send_and_assert_no_replies(self.pg0, p * 2,
                                        "no matching disposition entry")

        #
        # Add the default route to the disposition table
        #
        bier_de_2 = VppBierDispEntry(self,
                                     bdt.id,
                                     0,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0",
                                     0,
                                     rpf_id=8192)
        bier_de_2.add_vpp_config()

        #
        # now the previous packet is forwarded
        #
        self.send_and_expect(self.pg0, [p], self.pg1)

    def bier_e2e(self, hdr_len_id, n_bytes, max_bp):
        """ BIER end-to-end"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(0, 0, hdr_len_id)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        lowest = ['\0'] * (n_bytes)
        lowest[-1] = chr(1)
        highest = ['\0'] * (n_bytes)
        highest[0] = chr(128)

        #
        # Impostion Sets bit strings
        #
        bi_low = VppBierImp(self, bti, 333, lowest)
        bi_low.add_vpp_config()
        bi_high = VppBierImp(self, bti, 334, highest)
        bi_high.add_vpp_config()

        #
        # Add a multicast route that will forward into the BIER doamin
        #
        route_ing_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[
                VppMRoutePath(self.pg0.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                VppMRoutePath(0xffffffff,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                              proto=DpoProto.DPO_PROTO_BIER,
                              bier_imp=bi_low.bi_index)
            ])
        route_ing_232_1_1_1.add_vpp_config()
        route_ing_232_1_1_2 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.2",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[
                VppMRoutePath(self.pg0.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                VppMRoutePath(0xffffffff,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                              proto=DpoProto.DPO_PROTO_BIER,
                              bier_imp=bi_high.bi_index)
            ])
        route_ing_232_1_1_2.add_vpp_config()

        #
        # disposition table 8
        #
        bdt = VppBierDispTable(self, 8)
        bdt.add_vpp_config()

        #
        # BIER routes in table that are for-us, resolving through
        # disp table 8.
        #
        bier_route_1 = VppBierRoute(self, bti, 1, [
            VppRoutePath("0.0.0.0",
                         0xffffffff,
                         proto=DpoProto.DPO_PROTO_BIER,
                         nh_table_id=8)
        ])
        bier_route_1.add_vpp_config()
        bier_route_max = VppBierRoute(
            self, bti, max_bp,
            [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=8)])
        bier_route_max.add_vpp_config()

        #
        # An entry in the disposition table for sender 333
        #  lookup in VRF 10
        #
        bier_de_1 = VppBierDispEntry(self,
                                     bdt.id,
                                     333,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0",
                                     10,
                                     rpf_id=8192)
        bier_de_1.add_vpp_config()
        bier_de_1 = VppBierDispEntry(self,
                                     bdt.id,
                                     334,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0",
                                     10,
                                     rpf_id=8193)
        bier_de_1.add_vpp_config()

        #
        # Add a multicast routes that will forward the traffic
        # post-disposition
        #
        route_eg_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            table_id=10,
            paths=[
                VppMRoutePath(self.pg1.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)
            ])
        route_eg_232_1_1_1.add_vpp_config()
        route_eg_232_1_1_1.update_rpf_id(8192)
        route_eg_232_1_1_2 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.2",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            table_id=10,
            paths=[
                VppMRoutePath(self.pg1.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)
            ])
        route_eg_232_1_1_2.add_vpp_config()
        route_eg_232_1_1_2.update_rpf_id(8193)

        #
        # inject a packet in VRF-0. We expect it to be BIER encapped,
        # replicated, then hit the disposition and be forwarded
        # out of VRF 10, i.e. on pg1
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) /
             Raw(chr(5) * 32))

        rx = self.send_and_expect(self.pg0, p * 65, self.pg1)

        self.assertEqual(rx[0][IP].src, "1.1.1.1")
        self.assertEqual(rx[0][IP].dst, "232.1.1.1")

        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.2") / UDP(sport=1234, dport=1234) /
             Raw(chr(5) * 512))

        rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
        self.assertEqual(rx[0][IP].src, "1.1.1.1")
        self.assertEqual(rx[0][IP].dst, "232.1.1.2")

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_1024(self):
        """ BIER end-to-end BSL:1024"""
        self.bier_e2e(BIERLength.BIER_LEN_1024, 128, 1024)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_512(self):
        """ BIER end-to-end BSL:512"""
        self.bier_e2e(BIERLength.BIER_LEN_512, 64, 512)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_256(self):
        """ BIER end-to-end BSL:256"""
        self.bier_e2e(BIERLength.BIER_LEN_256, 32, 256)

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_bier_e2e_128(self):
        """ BIER end-to-end BSL:128"""
        self.bier_e2e(BIERLength.BIER_LEN_128, 16, 128)

    def test_bier_e2e_64(self):
        """ BIER end-to-end BSL:64"""
        self.bier_e2e(BIERLength.BIER_LEN_64, 8, 64)

    def test_bier_head_o_udp(self):
        """BIER head over UDP"""

        #
        # Add a BIER table for sub-domain 1, set 0, and BSL 256
        #
        bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, 77)
        bt.add_vpp_config()

        #
        # 1 bit positions via 1 next hops
        #
        nh1 = "10.0.0.1"
        ip_route = VppIpRoute(self, nh1, 32, [
            VppRoutePath(self.pg1.remote_ip4,
                         self.pg1.sw_if_index,
                         labels=[VppMplsLabel(2001)])
        ])
        ip_route.add_vpp_config()

        udp_encap = VppUdpEncap(self, 4, self.pg0.local_ip4, nh1, 330, 8138)
        udp_encap.add_vpp_config()

        bier_route = VppBierRoute(self, bti, 1, [
            VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=4)
        ])
        bier_route.add_vpp_config()

        #
        # An 2 imposition objects with all bit-positions set
        # only use the second, but creating 2 tests with a non-zero
        # value index in the route add
        #
        bi = VppBierImp(self, bti, 333, chr(0xff) * 32)
        bi.add_vpp_config()
        bi2 = VppBierImp(self, bti, 334, chr(0xff) * 32)
        bi2.add_vpp_config()

        #
        # Add a multicast route that will forward into the BIER doamin
        #
        route_ing_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[
                VppMRoutePath(self.pg0.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
                VppMRoutePath(0xffffffff,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
                              proto=DpoProto.DPO_PROTO_BIER,
                              bier_imp=bi2.bi_index)
            ])
        route_ing_232_1_1_1.add_vpp_config()

        #
        # inject a packet an IP. We expect it to be BIER and UDP encapped,
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234))

        self.pg0.add_stream([p])
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture(1)

        #
        # Encap Stack is, eth, IP, UDP, BIFT, BIER
        #
        self.assertEqual(rx[0][IP].src, self.pg0.local_ip4)
        self.assertEqual(rx[0][IP].dst, nh1)
        self.assertEqual(rx[0][UDP].sport, 330)
        self.assertEqual(rx[0][UDP].dport, 8138)
        self.assertEqual(rx[0][BIFT].bsl, 2)
        self.assertEqual(rx[0][BIFT].sd, 1)
        self.assertEqual(rx[0][BIFT].set, 0)
        self.assertEqual(rx[0][BIFT].ttl, 64)
        self.assertEqual(rx[0][BIER].length, 2)

    def test_bier_tail_o_udp(self):
        """BIER Tail over UDP"""

        #
        # Add a BIER table for sub-domain 0, set 0, and BSL 256
        #
        bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256)
        bt = VppBierTable(self, bti, MPLS_LABEL_INVALID)
        bt.add_vpp_config()

        #
        # disposition table
        #
        bdt = VppBierDispTable(self, 8)
        bdt.add_vpp_config()

        #
        # BIER route in table that's for-us
        #
        bier_route_1 = VppBierRoute(self, bti, 1, [
            VppRoutePath("0.0.0.0",
                         0xffffffff,
                         proto=DpoProto.DPO_PROTO_BIER,
                         nh_table_id=8)
        ])
        bier_route_1.add_vpp_config()

        #
        # An entry in the disposition table
        #
        bier_de_1 = VppBierDispEntry(self,
                                     bdt.id,
                                     99,
                                     BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4,
                                     DpoProto.DPO_PROTO_BIER,
                                     "0.0.0.0",
                                     0,
                                     rpf_id=8192)
        bier_de_1.add_vpp_config()

        #
        # A multicast route to forward post BIER disposition
        #
        route_eg_232_1_1_1 = VppIpMRoute(
            self,
            "0.0.0.0",
            "232.1.1.1",
            32,
            MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
            paths=[
                VppMRoutePath(self.pg1.sw_if_index,
                              MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)
            ])
        route_eg_232_1_1_1.add_vpp_config()
        route_eg_232_1_1_1.update_rpf_id(8192)

        #
        # A packet with all bits set gets spat out to BP:1
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
             UDP(sport=333, dport=8138) / BIFT(sd=1, set=0, bsl=2, ttl=255) /
             BIER(length=BIERLength.BIER_LEN_256,
                  BitString=chr(255) * 32,
                  BFRID=99) / IP(src="1.1.1.1", dst="232.1.1.1") /
             UDP(sport=1234, dport=1234) / Raw())

        rx = self.send_and_expect(self.pg0, [p], self.pg1)
Example #13
0
class TestIgmp(VppTestCase):
    """ IGMP Test Case """

    def setUp(self):
        super(TestIgmp, self).setUp()

        self.create_pg_interfaces(range(2))
        self.sg_list = []
        self.config_list = []

        self.ip_addr = []
        for pg in self.pg_interfaces:
            pg.admin_up()
            pg.config_ip4()
            pg.resolve_arp()

    def tearDown(self):
        for pg in self.pg_interfaces:
            self.vapi.igmp_clear_interface(pg.sw_if_index)
            pg.unconfig_ip4()
            pg.admin_down()
        super(TestIgmp, self).tearDown()

    def send(self, ti, pkts):
        ti.add_stream(pkts)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

    def test_igmp_parse_report(self):
        """ IGMP parse Membership Report """

        #
        # VPP acts as a router
        #
        self.vapi.want_igmp_events(1)

        # hos sends join IGMP 'join'
        p_join = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                  IP(src=self.pg0.remote_ip4, dst='224.0.0.22',
                     tos=0xc0, ttl=1,
                     options=IPOption(copy_flag=1, optclass=0,
                                      option="router_alert",
                                      length=2, value=0)) /
                  IGMPv3() /
                  IGMPv3mr(numgrp=1) /
                  IGMPv3gr(rtype=3, maddr="224.1.1.1", srcaddrs=["10.1.1.1"]))

        self.send(self.pg0, p_join)

        # search for the corresponding state created in VPP
        dump = self.vapi.igmp_dump()
        self.assertEqual(len(dump), 1)
        self.assertEqual(dump[0].sw_if_index, self.pg0.sw_if_index)
        self.assertEqual(dump[0].gaddr,
                         socket.inet_pton(socket.AF_INET,
                                          "224.1.1.1"))
        self.assertEqual(dump[0].saddr,
                         socket.inet_pton(socket.AF_INET,
                                          "10.1.1.1"))

        # VPP sends a notification that a new group has been joined
        ev = self.vapi.wait_for_event(2, "igmp_event")

        self.assertEqual(ev.saddr,
                         socket.inet_pton(socket.AF_INET,
                                          "10.1.1.1"))
        self.assertEqual(ev.gaddr,
                         socket.inet_pton(socket.AF_INET,
                                          "224.1.1.1"))
        self.assertEqual(ev.is_join, 1)

        # host sends IGMP leave
        p_leave = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                   IP(src=self.pg0.remote_ip4, dst='224.0.0.22', tos=0xc0) /
                   IGMPv3() /
                   IGMPv3mr(numgrp=1) /
                   IGMPv3gr(rtype=4, maddr="224.1.1.1", srcaddrs=["10.1.1.1"]))

        self.send(self.pg0, p_leave)

        # VPP sends a notification that a new group has been left
        ev = self.vapi.wait_for_event(2, "igmp_event")

        self.assertEqual(ev.saddr,
                         socket.inet_pton(socket.AF_INET,
                                          "10.1.1.1"))
        self.assertEqual(ev.gaddr,
                         socket.inet_pton(socket.AF_INET,
                                          "224.1.1.1"))
        self.assertEqual(ev.is_join, 0)

        # state gone
        dump = self.vapi.igmp_dump()
        self.assertFalse(dump)

        # resend the join
        self.send(self.pg0, p_join)
        dump = self.vapi.igmp_dump()
        self.assertEqual(len(dump), 1)
        self.assertEqual(dump[0].sw_if_index, self.pg0.sw_if_index)
        self.assertEqual(dump[0].gaddr,
                         socket.inet_pton(socket.AF_INET,
                                          "224.1.1.1"))
        self.assertEqual(dump[0].saddr,
                         socket.inet_pton(socket.AF_INET,
                                          "10.1.1.1"))

        # IGMP block
        p_block = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                   IP(src=self.pg0.remote_ip4, dst='224.0.0.22', tos=0xc0) /
                   IGMPv3() /
                   IGMPv3mr(numgrp=1) /
                   IGMPv3gr(rtype=6, maddr="224.1.1.1", srcaddrs=["10.1.1.1"]))

        self.send(self.pg0, p_block)

        dump = self.vapi.igmp_dump()
        self.assertFalse(dump)

    def verify_general_query(self, p):
        ip = p[IP]
        self.assertEqual(ip.dst, "224.0.0.1")
        self.assertEqual(ip.proto, 2)
        igmp = p[IGMPv3]
        self.assertEqual(igmp.type, 0x11)
        self.assertEqual(igmp.gaddr, "0.0.0.0")

    def test_igmp_send_query(self):
        """ IGMP send General Query """

        #
        # VPP acts as a router.
        #   Send a membership report so VPP builds state
        #
        p_mr = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                IP(src=self.pg0.remote_ip4, dst='224.0.0.22') /
                IGMPv3() /
                IGMPv3mr(numgrp=1) /
                IGMPv3gr(rtype=3, maddr="224.1.1.1", srcaddrs=["10.1.1.1"]))

        self.send(self.pg0, p_mr)
        self.logger.info(self.vapi.cli("sh igmp config"))

        #
        # wait for VPP to send out the General Query
        #
        capture = self.pg0.get_capture(1, timeout=61)

        self.verify_general_query(capture[0])

        #
        # the state will expire in 10 more seconds
        #
        self.sleep(10)
        self.assertFalse(self.vapi.igmp_dump())

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_igmp_src_exp(self):
        """ IGMP per source timer """

        #
        # VPP Acts as a router
        #

        # Host join for (10.1.1.1,224.1.1.1)
        p_mr1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 IP(src=self.pg0.remote_ip4, dst='224.0.0.22') /
                 IGMPv3() /
                 IGMPv3mr(numgrp=1) /
                 IGMPv3gr(rtype=3, maddr="224.1.1.1", srcaddrs=["10.1.1.1"]))

        self.send(self.pg0, p_mr1)

        # VPP (router) sends General Query
        capture = self.pg0.get_capture(1, timeout=61)

        self.verify_general_query(capture[0])

        # host join for same G and another S: (10.1.1.2,224.1.1.1)
        # therefore leaving (10.1.1.1,224.1.1.1)
        p_mr2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
                 IP(src=self.pg0.remote_ip4, dst='224.0.0.22') /
                 IGMPv3() /
                 IGMPv3mr(numgrp=1) /
                 IGMPv3gr(rtype=2, maddr="224.1.1.1", srcaddrs=["10.1.1.2"]))

        self.send(self.pg0, p_mr2)

        # wait for VPP to send general query
        capture = self.pg0.get_capture(1, timeout=61)
        self.verify_general_query(capture[0])

        # host leaves (10.1.1.2,224.1.1.1)
        p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst='224.0.0.22') /
               IGMPv3() /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype=2, maddr="224.1.1.1", srcaddrs=["10.1.1.2"]))

        self.send(self.pg0, p_l)

        # FIXME BUG
        p_l = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
               IP(src=self.pg0.remote_ip4, dst='224.0.0.22') /
               IGMPv3() /
               IGMPv3mr(numgrp=1) /
               IGMPv3gr(rtype=2, maddr="224.1.1.1", srcaddrs=["10.1.1.1"]))
        self.send(self.pg0, p_l)

        #
        # host has left all groups, no state left.
        #
        self.sleep(10)
        self.logger.error(self.vapi.cli("sh igmp config"))
        self.assertFalse(self.vapi.igmp_dump())

    def test_igmp_query_resp(self):
        """ IGMP General Query response """

        #
        # VPP acting as a host.
        #  Add a listener in VPP for (10.1.1.1,244.1.1.1)
        #
        self.config_list.append(
            VppIgmpConfig(
                self, self.pg0.sw_if_index, IgmpSG(
                    socket.inet_pton(
                        socket.AF_INET, "10.1.1.1"), socket.inet_pton(
                        socket.AF_INET, "224.1.1.1"))))
        self.config_list[0].add_vpp_config()

        # verify state exists
        self.assertTrue(self.vapi.igmp_dump(self.pg0.sw_if_index))

        #
        # Send a general query (from a router)
        #
        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
             IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) /
             IGMPv3(type=0x11, mrcode=100) /
             IGMPv3mq(gaddr="0.0.0.0"))

        self.send(self.pg0, p)

        #
        # expect VPP to respond with a membership report for the
        # (10.1.1.1, 224.1.1.1) state
        #
        capture = self.pg0.get_capture(1, timeout=10)

        self.assertEqual(capture[0][IGMPv3].type, 0x22)
        self.assertEqual(capture[0][IGMPv3mr].numgrp, 1)
        self.assertEqual(capture[0][IGMPv3gr].rtype, 1)
        self.assertEqual(capture[0][IGMPv3gr].numsrc, 1)
        self.assertEqual(capture[0][IGMPv3gr].maddr, "224.1.1.1")
        self.assertEqual(len(capture[0][IGMPv3gr].srcaddrs), 1)
        self.assertEqual(capture[0][IGMPv3gr].srcaddrs[0], "10.1.1.1")

    def test_igmp_listen(self):
        """ IGMP listen (S,G)s """

        #
        # VPP acts as a host
        #  Add IGMP group state to multiple interfaces and validate its
        #  presence
        #
        for pg in self.pg_interfaces:
            self.sg_list.append(IgmpSG(socket.inet_pton(
                socket.AF_INET, "10.1.1.%d" % pg._sw_if_index),
                socket.inet_pton(socket.AF_INET, "224.1.1.1")))

        for pg in self.pg_interfaces:
            self.config_list.append(
                VppIgmpConfig(
                    self,
                    pg._sw_if_index,
                    self.sg_list))
            self.config_list[-1].add_vpp_config()

        for config in self.config_list:
            dump = self.vapi.igmp_dump(config.sw_if_index)
            self.assertTrue(dump)
            self.assertEqual(len(dump), len(config.sg_list))
            for idx, e in enumerate(dump):
                self.assertEqual(e.sw_if_index, config.sw_if_index)
                self.assertEqual(e.saddr, config.sg_list[idx].saddr)
                self.assertEqual(e.gaddr, config.sg_list[idx].gaddr)

        for config in self.config_list:
            config.remove_vpp_config()

        dump = self.vapi.igmp_dump()
        self.assertFalse(dump)
class TestL2bdMultiInst(VppTestCase):
    """ L2BD Multi-instance Test Case """
    @classmethod
    def setUpClass(cls):
        """
        Perform standard class setup (defined by class method setUpClass in
        class VppTestCase) before running the test case, set test case related
        variables and configure VPP.
        """
        super(TestL2bdMultiInst, cls).setUpClass()

        try:
            # Create pg interfaces
            n_bd = 5
            cls.ifs_per_bd = ifs_per_bd = 3
            n_ifs = n_bd * ifs_per_bd
            cls.create_pg_interfaces(range(n_ifs))

            # Packet flows mapping pg0 -> pg1, pg2 etc.
            cls.flows = dict()
            for b in range(n_bd):
                bd_ifs = cls.bd_if_range(b + 1)
                for j in bd_ifs:
                    cls.flows[cls.pg_interfaces[j]] = [
                        cls.pg_interfaces[x] for x in bd_ifs if x != j
                    ]
                    assert (len(
                        cls.flows[cls.pg_interfaces[j]]) == ifs_per_bd - 1)

            # Mapping between packet-generator index and lists of test hosts
            cls.hosts_by_pg_idx = dict()

            # Create test host entries
            cls.create_hosts(5)

            # Packet sizes - jumbo packet (9018 bytes) skipped
            cls.pg_if_packet_sizes = [64, 512, 1518]

            # Set up all interfaces
            for i in cls.pg_interfaces:
                i.admin_up()

            # Create list of BDs
            cls.bd_list = list()

            # Create list of deleted BDs
            cls.bd_deleted_list = list()

            # Create list of pg_interfaces in BDs
            cls.pg_in_bd = list()

        except Exception:
            super(TestL2bdMultiInst, cls).tearDownClass()
            raise

    def setUp(self):
        """
        Clear trace and packet infos before running each test.
        """
        self.reset_packet_infos()
        super(TestL2bdMultiInst, self).setUp()

    def tearDown(self):
        """
        Show various debug prints after each test.
        """
        super(TestL2bdMultiInst, self).tearDown()
        if not self.vpp_dead:
            self.logger.info(self.vapi.ppcli("show l2fib verbose"))
            self.logger.info(self.vapi.ppcli("show bridge-domain"))

    @classmethod
    def create_hosts(cls, hosts_per_if):
        """
        Create required number of host MAC addresses and distribute them
        among interfaces. Create host IPv4 address for every host MAC
        address.

        :param int hosts_per_if: Number of hosts per if to create MAC/IPv4
                                 addresses for.
        """
        c = hosts_per_if
        assert (not cls.hosts_by_pg_idx)
        for i in range(len(cls.pg_interfaces)):
            pg_idx = cls.pg_interfaces[i].sw_if_index
            cls.hosts_by_pg_idx[pg_idx] = [
                Host("00:00:00:ff:%02x:%02x" % (pg_idx, j + 1),
                     "172.17.1%02u.%u" % (pg_idx, j + 1)) for j in range(c)
            ]

    @classmethod
    def bd_if_range(cls, b):
        n = cls.ifs_per_bd
        start = (b - 1) * n
        return range(start, start + n)

    def create_bd_and_mac_learn(self, count, start=1):
        """
        Create required number of bridge domains with MAC learning enabled,
        put 3 l2-pg interfaces to every bridge domain and send MAC learning
        packets.

        :param int count: Number of bridge domains to be created.
        :param int start: Starting number of the bridge domain ID.
            (Default value = 1)
        """
        for b in range(start, start + count):
            self.vapi.bridge_domain_add_del(bd_id=b)
            self.logger.info("Bridge domain ID %d created" % b)
            if self.bd_list.count(b) == 0:
                self.bd_list.append(b)
            if self.bd_deleted_list.count(b) == 1:
                self.bd_deleted_list.remove(b)
            for j in self.bd_if_range(b):
                pg_if = self.pg_interfaces[j]
                self.vapi.sw_interface_set_l2_bridge(pg_if.sw_if_index,
                                                     bd_id=b)
                self.logger.info(
                    "pg-interface %s added to bridge domain ID %d" %
                    (pg_if.name, b))
                self.pg_in_bd.append(pg_if)
                hosts = self.hosts_by_pg_idx[pg_if.sw_if_index]
                packets = [
                    Ether(dst="ff:ff:ff:ff:ff:ff", src=host.mac)
                    for host in hosts
                ]
                pg_if.add_stream(packets)
        self.logger.info("Sending broadcast eth frames for MAC learning")
        self.pg_start()
        self.logger.info(self.vapi.ppcli("show bridge-domain"))
        self.logger.info(self.vapi.ppcli("show l2fib"))

    def delete_bd(self, count, start=1):
        """
        Delete required number of bridge domains.

        :param int count: Number of bridge domains to be created.
        :param int start: Starting number of the bridge domain ID.
            (Default value = 1)
        """
        for b in range(start, start + count):
            for j in self.bd_if_range(b):
                pg_if = self.pg_interfaces[j]
                self.vapi.sw_interface_set_l2_bridge(pg_if.sw_if_index,
                                                     bd_id=b,
                                                     enable=0)
                self.pg_in_bd.remove(pg_if)
            self.vapi.bridge_domain_add_del(bd_id=b, is_add=0)
            self.bd_list.remove(b)
            self.bd_deleted_list.append(b)
            self.logger.info("Bridge domain ID %d deleted" % b)

    def create_stream(self, src_if):
        """
        Create input packet stream for defined interface using hosts list.

        :param object src_if: Interface to create packet stream for.
        :param list packet_sizes: List of required packet sizes.
        :return: Stream of packets.
        """
        packet_sizes = self.pg_if_packet_sizes
        pkts = []
        src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index]
        for dst_if in self.flows[src_if]:
            dst_hosts = self.hosts_by_pg_idx[dst_if.sw_if_index]
            for dst_host in dst_hosts:
                pkt_info = self.create_packet_info(src_if, dst_if)
                payload = self.info_to_payload(pkt_info)
                src_host = random.choice(src_hosts)
                p = (Ether(dst=dst_host.mac, src=src_host.mac) /
                     IP(src=src_host.ip4, dst=dst_host.ip4) /
                     UDP(sport=1234, dport=1234) / Raw(payload))
                pkt_info.data = p.copy()
                size = random.choice(packet_sizes)
                self.extend_packet(p, size)
                pkts.append(p)
        self.logger.debug(
            "Input stream created for port %s. Length: %u pkt(s)" %
            (src_if.name, len(pkts)))
        return pkts

    def verify_capture(self, dst_if):
        """
        Verify captured input packet stream for defined interface.

        :param object dst_if: Interface to verify captured packet stream for.
        """
        last_info = dict()
        for i in self.flows[dst_if]:
            last_info[i.sw_if_index] = None
        dst = dst_if.sw_if_index
        for packet in dst_if.get_capture():
            try:
                ip = packet[IP]
                udp = packet[UDP]
                info = self.payload_to_info(str(packet[Raw]))
                self.assertEqual(info.dst, dst)
                self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
                                  (dst_if.name, info.src, info.index))
                last_info[info.src] = self.get_next_packet_info_for_interface2(
                    info.src, dst, last_info[info.src])
                pkt_info = last_info[info.src]
                self.assertTrue(pkt_info is not None)
                self.assertEqual(info.index, pkt_info.index)
                # Check standard fields against saved data in pkt
                saved = pkt_info.data
                self.assertEqual(ip.src, saved[IP].src)
                self.assertEqual(ip.dst, saved[IP].dst)
                self.assertEqual(udp.sport, saved[UDP].sport)
                self.assertEqual(udp.dport, saved[UDP].dport)
            except:
                self.logger.error(ppp("Unexpected or invalid packet:", packet))
                raise
        s = ""
        remaining = 0
        for src in self.flows[dst_if]:
            remaining_packet = self.get_next_packet_info_for_interface2(
                src.sw_if_index, dst, last_info[src.sw_if_index])
            if remaining_packet is None:
                s += "Port %u: Packet expected from source %u didn't arrive\n"\
                     % (dst, src.sw_if_index)
                remaining += 1
            self.assertNotEqual(0, remaining, s)

    def set_bd_flags(self, bd_id, **args):
        """
        Enable/disable defined feature(s) of the bridge domain.

        :param int bd_id: Bridge domain ID.
        :param list args: List of feature/status pairs. Allowed features: \
        learn, forward, flood, uu_flood and arp_term. Status False means \
        disable, status True means enable the feature.
        :raise: ValueError in case of unknown feature in the input.
        """
        for flag in args:
            if flag == "learn":
                feature_bitmap = 1 << 0
            elif flag == "forward":
                feature_bitmap = 1 << 1
            elif flag == "flood":
                feature_bitmap = 1 << 2
            elif flag == "uu_flood":
                feature_bitmap = 1 << 3
            elif flag == "arp_term":
                feature_bitmap = 1 << 4
            else:
                raise ValueError("Unknown feature used: %s" % flag)
            is_set = 1 if args[flag] else 0
            self.vapi.bridge_flags(bd_id, is_set, feature_bitmap)
        self.logger.info("Bridge domain ID %d updated" % bd_id)

    def verify_bd(self, bd_id, **args):
        """
        Check if the bridge domain is configured and verify expected status
        of listed features.

        :param int bd_id: Bridge domain ID.
        :param list args: List of feature/status pairs. Allowed features: \
        learn, forward, flood, uu_flood and arp_term. Status False means \
        disable, status True means enable the feature.
        :return: 1 if bridge domain is configured, otherwise return 0.
        :raise: ValueError in case of unknown feature in the input.
        """
        bd_dump = self.vapi.bridge_domain_dump(bd_id)
        if len(bd_dump) == 0:
            self.logger.info("Bridge domain ID %d is not configured" % bd_id)
            return 0
        else:
            bd_dump = bd_dump[0]
            if len(args) > 0:
                for flag in args:
                    expected_status = 1 if args[flag] else 0
                    if flag == "learn":
                        flag_status = bd_dump[6]
                    elif flag == "forward":
                        flag_status = bd_dump[5]
                    elif flag == "flood":
                        flag_status = bd_dump[3]
                    elif flag == "uu_flood":
                        flag_status = bd_dump[4]
                    elif flag == "arp_term":
                        flag_status = bd_dump[7]
                    else:
                        raise ValueError("Unknown feature used: %s" % flag)
                    self.assertEqual(expected_status, flag_status)
            return 1

    def run_verify_test(self):
        """
        Create packet streams for all configured l2-pg interfaces, send all \
        prepared packet streams and verify that:
            - all packets received correctly on all pg-l2 interfaces assigned
              to bridge domains
            - no packet received on all pg-l2 interfaces not assigned to
              bridge domains

        :raise RuntimeError: if no packet captured on l2-pg interface assigned
                             to the bridge domain or if any packet is captured
                             on l2-pg interface not assigned to the bridge
                             domain.
        """
        # Test
        # Create incoming packet streams for packet-generator interfaces
        # for pg_if in self.pg_interfaces:
        assert (len(self._packet_count_for_dst_if_idx) == 0)
        for pg_if in self.pg_in_bd:
            pkts = self.create_stream(pg_if)
            pg_if.add_stream(pkts)

        # Enable packet capture and start packet sending
        self.pg_enable_capture(self.pg_in_bd)
        self.pg_start()

        # Verify
        # Verify outgoing packet streams per packet-generator interface
        for pg_if in self.pg_in_bd:
            self.verify_capture(pg_if)

    def test_l2bd_inst_01(self):
        """ L2BD Multi-instance test 1 - create 5 BDs
        """
        # Config 1
        # Create 5 BDs, put interfaces to these BDs and send MAC learning
        # packets
        self.create_bd_and_mac_learn(5)

        # Verify 1
        for bd_id in self.bd_list:
            self.assertEqual(self.verify_bd(bd_id), 1)

        # Test 1
        # self.vapi.cli("clear trace")
        self.run_verify_test()

    def test_l2bd_inst_02(self):
        """ L2BD Multi-instance test 2 - update data of 5 BDs
        """
        # Config 2
        # Update data of 5 BDs (disable learn, forward, flood, uu-flood)
        self.set_bd_flags(self.bd_list[0],
                          learn=False,
                          forward=False,
                          flood=False,
                          uu_flood=False)
        self.set_bd_flags(self.bd_list[1], forward=False)
        self.set_bd_flags(self.bd_list[2], flood=False)
        self.set_bd_flags(self.bd_list[3], uu_flood=False)
        self.set_bd_flags(self.bd_list[4], learn=False)

        # Verify 2
        # Skipping check of uu_flood as it is not returned by
        # bridge_domain_dump api command
        self.verify_bd(self.bd_list[0],
                       learn=False,
                       forward=False,
                       flood=False,
                       uu_flood=False)
        self.verify_bd(self.bd_list[1],
                       learn=True,
                       forward=False,
                       flood=True,
                       uu_flood=True)
        self.verify_bd(self.bd_list[2],
                       learn=True,
                       forward=True,
                       flood=False,
                       uu_flood=True)
        self.verify_bd(self.bd_list[3],
                       learn=True,
                       forward=True,
                       flood=True,
                       uu_flood=False)
        self.verify_bd(self.bd_list[4],
                       learn=False,
                       forward=True,
                       flood=True,
                       uu_flood=True)

    def test_l2bd_inst_03(self):
        """ L2BD Multi-instance test 3 - delete 2 BDs
        """
        # Config 3
        # Delete 2 BDs
        self.delete_bd(2)

        # Verify 3
        for bd_id in self.bd_deleted_list:
            self.assertEqual(self.verify_bd(bd_id), 0)
        for bd_id in self.bd_list:
            self.assertEqual(self.verify_bd(bd_id), 1)

        # Test 3
        self.run_verify_test()

    def test_l2bd_inst_04(self):
        """ L2BD Multi-instance test 4 - add 2 BDs
        """
        # Config 4
        # Create 5 BDs, put interfaces to these BDs and send MAC learning
        # packets
        self.create_bd_and_mac_learn(2)

        # Verify 4
        for bd_id in self.bd_list:
            self.assertEqual(self.verify_bd(bd_id), 1)

        # Test 4
        # self.vapi.cli("clear trace")
        self.run_verify_test()

    @unittest.skipUnless(running_extended_tests(), "part of extended tests")
    def test_l2bd_inst_05(self):
        """ L2BD Multi-instance test 5 - delete 5 BDs
        """
        # Config 5
        # Delete 5 BDs
        self.delete_bd(5)

        # Verify 5
        for bd_id in self.bd_deleted_list:
            self.assertEqual(self.verify_bd(bd_id), 0)
        for bd_id in self.bd_list:
            self.assertEqual(self.verify_bd(bd_id), 1)