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)
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)
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)
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)
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)
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)
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])
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)
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")
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")
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
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)
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)