def test_ip6_rx_p2p_subif_route(self): """route rx ip6 packet not matching p2p subinterface""" self.logger.info("FFP_TEST_START_0003") self.pg0.config_ip6() route_3 = VppIpRoute(self, "9000::", 64, [VppRoutePath(self.pg1._remote_hosts[0].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_3.add_vpp_config() self.packets.append( self.create_stream(src_mac="02:03:00:00:ff:ff", dst_mac=self.pg0.local_mac, src_ip="a000::100", dst_ip="9000::100")) self.send_packets(self.pg0, self.pg1) self.pg0.unconfig_ip6() route_3.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0003")
def test_quic_transfer(self): """ QUIC echo client/server transfer """ # Add inter-table routes ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=2)], table_id=1) ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)], table_id=2) ip_t01.add_vpp_config() ip_t10.add_vpp_config() self.logger.debug(self.vapi.cli("show ip fib")) # Start builtin server and client uri = "quic://%s/1234" % self.loop0.local_ip4 error = self.vapi.cli("test echo server appns 1 fifo-size 4 uri %s" % uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) error = self.vapi.cli("test echo client bytes 1024 appns 2 " + "fifo-size 4 test-bytes no-output " + "uri %s" % uri) self.logger.critical(error) if error: self.logger.critical(error) self.assertNotIn("failed", error) # Delete inter-table routes ip_t01.remove_vpp_config() ip_t10.remove_vpp_config()
def test_tcp_transfer(self): """ TCP echo client/server transfer """ # Add inter-table routes ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)]) ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)], table_id=1) ip_t01.add_vpp_config() ip_t10.add_vpp_config() # Start builtin server and client uri = "tcp://" + self.loop0.local_ip4 + "/1234" error = self.vapi.cli("test echo server appns 0 fifo-size 4 uri " + uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) error = self.vapi.cli("test echo client mbytes 10 appns 1 " + "fifo-size 4 no-output test-bytes " + "syn-timeout 2 uri " + uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) # Delete inter-table routes ip_t01.remove_vpp_config() ip_t10.remove_vpp_config()
def test_PPPoE_Del_Twice(self): """ PPPoE Delete Same Session Twice Test """ self.vapi.cli("clear trace") # # Add a route that resolves the server's destination # route_sever_dst = VppIpRoute(self, "100.1.1.100", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_sever_dst.add_vpp_config() # Send PPPoE Discovery tx0 = self.create_stream_pppoe_discovery(self.pg0, self.pg1, self.pg0.remote_mac) self.pg0.add_stream(tx0) self.pg_start() # Send PPPoE PPP LCP tx1 = self.create_stream_pppoe_lcp(self.pg0, self.pg1, self.pg0.remote_mac, self.session_id) self.pg0.add_stream(tx1) self.pg_start() # Create PPPoE session pppoe_if = VppPppoeInterface(self, self.pg0.remote_ip4, self.pg0.remote_mac, self.session_id) pppoe_if.add_vpp_config() # Delete PPPoE session pppoe_if.remove_vpp_config() # # The double del (del the same session twice) should fail, # and we should still be able to use the original # try: pppoe_if.remove_vpp_config() except Exception: pass else: self.fail("Double GRE tunnel del does not fail") # # test case cleanup # # Delete a route that resolves the server's destination route_sever_dst.remove_vpp_config()
def test_6rd_bgp_tunnel(self): """ 6rd BGP tunnel """ rv = self.vapi.ipip_6rd_add_tunnel(0, 0, inet_pton(AF_INET6, '2002::'), inet_pton(AF_INET, '0.0.0.0'), self.pg0.local_ip4n, 16, 0, False) self.tunnel_index = rv.sw_if_index default_route = VppIpRoute( self, "DEAD::", 16, [VppRoutePath("2002:0808:0808::", self.tunnel_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) default_route.add_vpp_config() ip4_route = VppIpRoute(self, "8.0.0.0", 8, [VppRoutePath(self.pg1.remote_ip4, 0xFFFFFFFF)]) ip4_route.add_vpp_config() # Via recursive route 6 -> 4 p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="1::1", dst="DEAD:BEEF::1") / UDP(sport=1234, dport=1234)) p_reply = (IP(src=self.pg0.local_ip4, dst="8.8.8.8", proto='ipv6') / IPv6(src='1::1', dst='DEAD:BEEF::1', nh='UDP')) rx = self.send_and_expect(self.pg0, p * 10, self.pg1) for p in rx: self.validate_6in4(p, p_reply) # Via recursive route 4 -> 6 (Security check must be disabled) p_ip6 = (IPv6(src="DEAD:BEEF::1", dst=self.pg1.remote_ip6) / UDP(sport=1234, dport=1234)) p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="8.8.8.8", dst=self.pg0.local_ip4) / p_ip6) p_reply = p_ip6 rx = self.send_and_expect(self.pg0, p * 10, self.pg1) for p in rx: self.validate_4in6(p, p_reply) ip4_route.remove_vpp_config() default_route.remove_vpp_config() self.vapi.ipip_6rd_del_tunnel(self.tunnel_index)
def test_no_p2p_subif(self): """standard routing without p2p subinterfaces""" self.logger.info("FFP_TEST_START_0001") route_8000 = VppIpRoute(self, "8000::", 64, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8000.add_vpp_config() self.packets = [(Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src="3001::1", dst="8000::100") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))] self.send_packets(self.pg1, self.pg0) self.logger.info("FFP_TEST_FINISH_0001")
def test_ip6_rx_p2p_subif_drop(self): """drop rx packet not matching p2p subinterface""" self.logger.info("FFP_TEST_START_0004") route_9001 = VppIpRoute(self, "9000::", 64, [VppRoutePath(self.pg1._remote_hosts[0].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_9001.add_vpp_config() self.packets.append( self.create_stream(src_mac="02:03:00:00:ff:ff", dst_mac=self.pg0.local_mac, src_ip="a000::100", dst_ip="9000::100")) # no packet received self.send_packets(self.pg0, self.pg1, count=0) self.logger.info("FFP_TEST_FINISH_0004")
def test_ip4_rx_p2p_subif_route(self): """route rx packet not matching p2p subinterface""" self.logger.info("FFP_TEST_START_0003") route_9001 = VppIpRoute(self, "9.0.0.0", 24, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_9001.add_vpp_config() self.packets.append( self.create_stream(src_mac="02:01:00:00:ff:ff", dst_mac=self.pg0.local_mac, src_ip="8.0.0.100", dst_ip="9.0.0.100")) self.send_packets(self.pg0, self.pg1) route_9001.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0003")
def test_ip4_rx_p2p_subif(self): """receive ipv4 packet via p2p subinterface""" self.logger.info("FFP_TEST_START_0002") route_9000 = VppIpRoute(self, "9.0.0.0", 16, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_9000.add_vpp_config() self.packets.append( self.create_stream(src_mac=self.pg0._remote_hosts[0].mac, dst_mac=self.pg0.local_mac, src_ip=self.p2p_sub_ifs[0].remote_ip4, dst_ip="9.0.0.100")) self.send_packets(self.pg0, self.pg1, self.packets) self.assert_packet_counter_equal('p2p-ethernet-input', 1) route_9000.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0002")
def setup_tunnel(self): # IPv6 transport rv = self.vapi.ipip_add_tunnel( src_address=self.pg0.local_ip6n, dst_address=self.pg1.remote_ip6n, tc_tos=255) sw_if_index = rv.sw_if_index self.tunnel_if_index = sw_if_index self.vapi.sw_interface_set_flags(sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=sw_if_index) # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute( self, "130.67.0.0", 16, [VppRoutePath("0.0.0.0", sw_if_index, proto=DpoProto.DPO_PROTO_IP4)], is_ip6=0) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute( self, "dead::", 16, [VppRoutePath("::", sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) ip6_via_tunnel.add_vpp_config() self.tunnel_ip6_via_tunnel = ip6_via_tunnel self.tunnel_ip4_via_tunnel = ip4_via_tunnel
def thru_host_stack_setup(self): self.vapi.session_enable_disable(is_enabled=1) self.create_loopback_interfaces(2) table_id = 1 for i in self.lo_interfaces: i.admin_up() if table_id != 0: tbl = VppIpTable(self, table_id) tbl.add_vpp_config() i.set_table_ip4(table_id) i.config_ip4() table_id += 1 # Configure namespaces self.vapi.app_namespace_add_del(namespace_id=b"1", secret=1234, sw_if_index=self.loop0.sw_if_index) self.vapi.app_namespace_add_del(namespace_id=b"2", secret=5678, sw_if_index=self.loop1.sw_if_index) # Add inter-table routes ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=2)], table_id=1) ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)], table_id=2) ip_t01.add_vpp_config() ip_t10.add_vpp_config() self.logger.debug(self.vapi.cli("show ip fib"))
def test_ip6_rx_p2p_subif(self): """receive ipv6 packet via p2p subinterface""" self.logger.info("FFP_TEST_START_0002") route_9001 = VppIpRoute(self, "9001::", 64, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_9001.add_vpp_config() self.packets.append( self.create_stream(src_mac=self.pg0._remote_hosts[0].mac, dst_mac=self.pg0.local_mac, src_ip=self.p2p_sub_ifs[0].remote_ip6, dst_ip="9001::100")) self.send_packets(self.pg0, self.pg1, self.packets) self.assert_packet_counter_equal('p2p-ethernet-input', 1) route_9001.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0002")
def thru_host_stack_ipv4_setup(self): super(QUICTestCase, self).setUp() self.create_loopback_interfaces(2) self.uri = "quic://%s/1234" % self.loop0.local_ip4 common_args = ["uri", self.uri, "fifo-size", "64"] self.server_echo_test_args = common_args + ["appns", "server"] self.client_echo_test_args = common_args + ["appns", "client", "test-bytes"] table_id = 1 for i in self.lo_interfaces: i.admin_up() if table_id != 0: tbl = VppIpTable(self, table_id) tbl.add_vpp_config() i.set_table_ip4(table_id) i.config_ip4() table_id += 1 # Configure namespaces self.vapi.app_namespace_add_del(namespace_id=b"server", sw_if_index=self.loop0.sw_if_index) self.vapi.app_namespace_add_del(namespace_id=b"client", sw_if_index=self.loop1.sw_if_index) # Add inter-table routes self.ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=2)], table_id=1) self.ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)], table_id=2) self.ip_t01.add_vpp_config() self.ip_t10.add_vpp_config() self.logger.debug(self.vapi.cli("show ip fib"))
def config_network(self, params): self.net_objs = [] self.tun_if = self.pg0 self.tra_if = self.pg2 self.logger.info(self.vapi.ppcli("show int addr")) self.tra_spd = VppIpsecSpd(self, self.tra_spd_id) self.tra_spd.add_vpp_config() self.net_objs.append(self.tra_spd) self.tun_spd = VppIpsecSpd(self, self.tun_spd_id) self.tun_spd.add_vpp_config() self.net_objs.append(self.tun_spd) b = VppIpsecSpdItfBinding(self, self.tra_spd, self.tra_if) b.add_vpp_config() self.net_objs.append(b) b = VppIpsecSpdItfBinding(self, self.tun_spd, self.tun_if) b.add_vpp_config() self.net_objs.append(b) for p in params: self.config_ah_tra(p) config_tra_params(p, self.encryption_type) for p in params: self.config_ah_tun(p) for p in params: d = DpoProto.DPO_PROTO_IP6 if p.is_ipv6 else DpoProto.DPO_PROTO_IP4 r = VppIpRoute(self, p.remote_tun_if_host, p.addr_len, [VppRoutePath(self.tun_if.remote_addr[p.addr_type], 0xffffffff, proto=d)], is_ip6=p.is_ipv6) r.add_vpp_config() self.net_objs.append(r) self.logger.info(self.vapi.ppcli("show ipsec all"))
def test_segment_manager_alloc(self): """ Session Segment Manager Multiple Segment Allocation """ # Add inter-table routes ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)]) ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)], table_id=1) ip_t01.add_vpp_config() ip_t10.add_vpp_config() # Start builtin server and client with small private segments uri = "tcp://" + self.loop0.local_ip4 + "/1234" error = self.vapi.cli("test echo server appns 0 fifo-size 64 " + "private-segment-size 1m uri " + uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) error = self.vapi.cli("test echo client nclients 100 appns 1 " + "no-output fifo-size 64 syn-timeout 2 " + "private-segment-size 1m uri " + uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) if self.vpp_dead: self.assert_equal(0) # Delete inter-table routes ip_t01.remove_vpp_config() ip_t10.remove_vpp_config()
def thru_host_stack_ipv6_setup(self): self.vapi.session_enable_disable(is_enabled=1) self.create_loopback_interfaces(2) table_id = 1 for i in self.lo_interfaces: i.admin_up() tbl = VppIpTable(self, table_id, is_ip6=1) tbl.add_vpp_config() i.set_table_ip6(table_id) i.config_ip6() table_id += 1 # Configure namespaces self.vapi.app_namespace_add_del(namespace_id=b"1", secret=1234, sw_if_index=self.loop0.sw_if_index) self.vapi.app_namespace_add_del(namespace_id=b"2", secret=5678, sw_if_index=self.loop1.sw_if_index) # Add inter-table routes ip_t01 = VppIpRoute(self, self.loop1.local_ip6, 128, [VppRoutePath("::0", 0xffffffff, nh_table_id=2, proto=DpoProto.DPO_PROTO_IP6)], table_id=1, is_ip6=1) ip_t10 = VppIpRoute(self, self.loop0.local_ip6, 128, [VppRoutePath("::0", 0xffffffff, nh_table_id=1, proto=DpoProto.DPO_PROTO_IP6)], table_id=2, is_ip6=1) ip_t01.add_vpp_config() ip_t10.add_vpp_config() self.logger.debug(self.vapi.cli("show interface addr")) self.logger.debug(self.vapi.cli("show ip6 fib"))
def test_ip4_tx_p2p_subif(self): """send ip4 packet via p2p subinterface""" self.logger.info("FFP_TEST_START_0005") route_9100 = VppIpRoute( self, "9.1.0.100", 24, [VppRoutePath( self.pg0.remote_ip4, self.pg0.sw_if_index, )]) route_9100.add_vpp_config() route_9200 = VppIpRoute(self, "9.2.0.100", 24, [ VppRoutePath( self.p2p_sub_ifs[0].remote_ip4, self.p2p_sub_ifs[0].sw_if_index, ) ]) route_9200.add_vpp_config() route_9300 = VppIpRoute(self, "9.3.0.100", 24, [ VppRoutePath(self.p2p_sub_ifs[1].remote_ip4, self.p2p_sub_ifs[1].sw_if_index) ]) route_9300.add_vpp_config() for i in range(0, 3): self.packets.append( self.create_stream(src_mac=self.pg1.remote_mac, dst_mac=self.pg1.local_mac, src_ip=self.pg1.remote_ip4, dst_ip="9.%d.0.100" % (i + 1))) self.send_packets(self.pg1, self.pg0) # route_7000.remove_vpp_config() route_9100.remove_vpp_config() route_9200.remove_vpp_config() route_9300.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0005")
def test_gre_loop(self): """ GRE tunnel loop Tests """ # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2") gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() # # add a route to the tunnel's destination that points # through the tunnel, hence forming a loop in the forwarding # graph # route_dst = VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_dst.add_vpp_config() # # packets to the tunnels destination should be dropped # tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "1.1.1.2") self.send_and_assert_no_replies(self.pg2, tx) self.logger.info(self.vapi.ppcli("sh adj 7")) # # break the loop # route_dst.modify( [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_dst.add_vpp_config() rx = self.send_and_expect(self.pg0, tx, self.pg1) # # a good route throught the tunnel to check it restacked # route_via_tun_2 = VppIpRoute( self, "2.2.2.2", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun_2.add_vpp_config() tx = self.create_stream_ip4(self.pg0, "2.2.2.3", "2.2.2.2") rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg0.local_ip4, "1.1.1.2") # # cleanup # route_via_tun_2.remove_vpp_config() gre_if.remove_vpp_config()
def test_cflow_packet(self): """verify cflow packet fields""" self.logger.info("FFP_TEST_START_0000") self.pg_enable_capture(self.pg_interfaces) self.pkts = [] ipfix = VppCFLOW(test=self, intf='pg8', datapath="ip4", layer='l2 l3 l4', active=2) ipfix.add_vpp_config() route_9001 = VppIpRoute(self, "9.0.0.0", 24, [ VppRoutePath(self.pg8._remote_hosts[0].ip4, self.pg8.sw_if_index) ]) route_9001.add_vpp_config() ipfix_decoder = IPFIXDecoder() templates = ipfix.verify_templates(ipfix_decoder, count=1) self.pkts = [ (Ether(dst=self.pg7.local_mac, src=self.pg7.remote_mac) / IP(src=self.pg7.remote_ip4, dst="9.0.0.100") / TCP(sport=1234, dport=4321, flags=80) / Raw(b'\xa5' * 100)) ] nowUTC = int(time.time()) nowUNIX = nowUTC + 2208988800 self.send_packets(src_if=self.pg7, dst_if=self.pg8) cflow = self.wait_for_cflow_packet(self.collector, templates[0], 10) self.collector.get_capture(2) if cflow[0].haslayer(IPFIX): self.assertEqual(cflow[IPFIX].version, 10) self.assertEqual(cflow[IPFIX].observationDomainID, 1) self.assertEqual(cflow[IPFIX].sequenceNumber, 0) self.assertAlmostEqual(cflow[IPFIX].exportTime, nowUTC, delta=5) if cflow.haslayer(Data): record = ipfix_decoder.decode_data_set(cflow[0].getlayer(Set))[0] # ingress interface self.assertEqual(int(binascii.hexlify(record[10]), 16), 8) # egress interface self.assertEqual(int(binascii.hexlify(record[14]), 16), 9) # packets self.assertEqual(int(binascii.hexlify(record[2]), 16), 1) # src mac self.assertEqual(mac_ntop(record[56]), self.pg8.local_mac) # dst mac self.assertEqual(mac_ntop(record[80]), self.pg8.remote_mac) flowTimestamp = int(binascii.hexlify(record[156]), 16) >> 32 # flow start timestamp self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) flowTimestamp = int(binascii.hexlify(record[157]), 16) >> 32 # flow end timestamp self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) # ethernet type self.assertEqual(int(binascii.hexlify(record[256]), 16), 8) # src ip self.assertEqual(inet_ntop(socket.AF_INET, record[8]), self.pg7.remote_ip4) # dst ip self.assertEqual(inet_ntop(socket.AF_INET, record[12]), "9.0.0.100") # protocol (TCP) self.assertEqual(int(binascii.hexlify(record[4]), 16), 6) # src port self.assertEqual(int(binascii.hexlify(record[7]), 16), 1234) # dst port self.assertEqual(int(binascii.hexlify(record[11]), 16), 4321) # tcp flags self.assertEqual(int(binascii.hexlify(record[6]), 16), 80) ipfix.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0000")
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 32 map_route = VppIpRoute( self, map_br_pfx, map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = '2001::/32' map_src = '3000::1/128' client_pfx = '192.168.0.0/16' map_translated_addr = '2001:0:101:7000:0:c0a8:101:7' tag = 'MAP-E tag.' self.vapi.map_add_domain(ip4_prefix=client_pfx, ip6_prefix=map_dst, ip6_src=map_src, ea_bits_len=20, psid_offset=4, psid_length=4, tag=tag) self.vapi.map_param_set_security_check(enable=1, fragments=1) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) self.send_and_assert_encapped_one(v4, "3000::1", map_translated_addr) # # Verify reordered fragments are able to pass as well # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(id=1, src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 1000)) frags = fragment_rfc791(v4, 400) frags.reverse() self.send_and_assert_encapped(frags, "3000::1", map_translated_addr) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src=map_translated_addr) / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=10000, dport=20000) / Raw(b'\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Verify encapped reordered fragments pass as well # p = (IP(id=1, dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=10000, dport=20000) / Raw(b'\xa5' * 1500)) frags = fragment_rfc791(p, 400) frags.reverse() stream = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src=map_translated_addr) / x for x in frags) self.pg1.add_stream(stream) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(frags)) for r in rx: self.assertFalse(r.haslayer(IPv6)) self.assertEqual(r[IP].src, p[IP].src) self.assertEqual(r[IP].dst, p[IP].dst) # Verify that fragments pass even if ipv6 layer is fragmented stream = (IPv6(dst='3000::1', src=map_translated_addr) / x for x in frags) v6_stream = [ Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / x for i in range(len(frags)) for x in fragment_rfc8200( IPv6(dst='3000::1', src=map_translated_addr) / frags[i], i, 200) ] self.pg1.add_stream(v6_stream) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(frags)) for r in rx: self.assertFalse(r.haslayer(IPv6)) self.assertEqual(r[IP].src, p[IP].src) self.assertEqual(r[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resolved via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped_one(v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify( [VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped_one(v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def test_dvr(self): """ Distributed Virtual Router """ # # A packet destined to an IP address that is L2 bridged via # a non-tag interface # ip_non_tag_bridged = "10.10.10.10" ip_tag_bridged = "10.10.10.11" any_src_addr = "1.1.1.1" pkt_no_tag = (Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_tag = (Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # Two sub-interfaces so we can test VLAN tag push/pop # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=92) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=93) # # Add routes to bridge the traffic via a tagged an nontagged interface # route_no_tag = VppIpRoute( self, ip_non_tag_bridged, 32, [VppRoutePath("0.0.0.0", self.pg1.sw_if_index, is_dvr=1)]) route_no_tag.add_vpp_config() # # Inject the packet that arrives and leaves on a non-tagged interface # Since it's 'bridged' expect that the MAC headed is unchanged. # rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) # # Add routes to bridge the traffic via a tagged interface # route_with_tag = VppIpRoute( self, ip_tag_bridged, 32, [VppRoutePath("0.0.0.0", sub_if_on_pg3.sw_if_index, is_dvr=1)]) route_with_tag.add_vpp_config() # # Inject the packet that arrives non-tag and leaves on a tagged # interface # rx = self.send_and_expect(self.pg0, pkt_tag * 65, self.pg3) self.assert_same_mac_addr(pkt_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to tag # pkt_tag_to_tag = (Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * 65, self.pg3) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to non-Tag # pkt_tag_to_non_tag = (Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_no_tag(rx) # # Add an output L3 ACL that will block the traffic # rule_1 = ({'is_permit': 0, 'is_ipv6': 0, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 32, 'src_ip_addr': inet_pton(AF_INET, any_src_addr), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 32, 'dst_ip_addr': inet_pton(AF_INET, ip_non_tag_bridged)}) acl = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # Apply the ACL on the output interface # self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index, 0, [acl.acl_index]) # # Send packet's that should match the ACL and be dropped # rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * 65) # # cleanup # self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index, 0, []) self.vapi.acl_del(acl.acl_index) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI, enable=0) # # Do a FIB dump to make sure the paths are correctly reported as DVR # routes = self.vapi.ip_fib_dump() for r in routes: if (inet_pton(AF_INET, ip_tag_bridged) == r.address): self.assertEqual(r.path[0].sw_if_index, sub_if_on_pg3.sw_if_index) self.assertEqual(r.path[0].is_dvr, 1) if (inet_pton(AF_INET, ip_non_tag_bridged) == r.address): self.assertEqual(r.path[0].sw_if_index, self.pg1.sw_if_index) self.assertEqual(r.path[0].is_dvr, 1) # # the explicit route delete is require so it happens before # the sbu-interface delete. subinterface delete is required # because that object type does not use the object registry # route_no_tag.remove_vpp_config() route_with_tag.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def test_qos_vlan(self): """QoS mark/record VLAN """ # # QoS for all input values # output = [chr(0)] * 256 for i in range(0, 255): output[i] = chr(255 - i) os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(1, rows) sub_if = VppDot1QSubint(self, self.pg0, 11) sub_if.admin_up() sub_if.config_ip4() sub_if.resolve_arp() sub_if.config_ip6() sub_if.resolve_ndp() # # enable VLAN QoS recording/marking on the input Pg0 subinterface and # self.vapi.qos_record_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1) self.vapi.qos_mark_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1, 1) # # IP marking/recording on pg1 # self.vapi.qos_record_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) # # a routes to/from sub-interface # route_10_0_0_1 = VppIpRoute( self, "10.0.0.1", 32, [VppRoutePath(sub_if.remote_ip4, sub_if.sw_if_index)]) route_10_0_0_1.add_vpp_config() route_10_0_0_2 = VppIpRoute( self, "10.0.0.2", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_2.add_vpp_config() route_2001_1 = VppIpRoute( self, "2001::1", 128, [ VppRoutePath(sub_if.remote_ip6, sub_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_2001_1.add_vpp_config() route_2001_2 = VppIpRoute( self, "2001::2", 128, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_2001_2.add_vpp_config() p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=1) / IP(src="1.1.1.1", dst="10.0.0.2", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 6) rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 254) p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=2) / IPv6(src="2001::1", dst="2001::2", tc=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src="3001::1", dst="2001::1", tc=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 6) rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 253) # # cleanup # sub_if.unconfig_ip4() sub_if.unconfig_ip6() self.vapi.qos_record_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 0) self.vapi.qos_mark_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1, 0) self.vapi.qos_record_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0)
def test_abf6(self): """ IPv6 ACL Based Forwarding """ # # Simple test for matching IPv6 packets # # # Rule 1 # rule_1 = ({'is_permit': 1, 'is_ipv6': 1, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 128, 'src_ip_addr': inet_pton(AF_INET6, "2001::2"), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 128, 'dst_ip_addr': inet_pton(AF_INET6, "2001::1")}) acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # ABF policy for ACL 1 - path via interface 1 # abf_1 = VppAbfPolicy(self, 10, acl_1, [VppRoutePath("3001::1", 0xffffffff, proto=DpoProto.DPO_PROTO_IP6)]) abf_1.add_vpp_config() attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 45, is_ipv6=True) attach_1.add_vpp_config() # # a packet matching the rule # p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::2", dst="2001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # packets are dropped because there is no route to the policy's # next hop # self.send_and_assert_no_replies(self.pg1, p * 65, "no route") # # add a route resolving the next-hop # route = VppIpRoute(self, "3001::1", 32, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route.add_vpp_config() # # now expect packets forwarded. # self.send_and_expect(self.pg0, p * 65, self.pg1)
def test_gre_vrf(self): """ GRE tunnel VRF Tests """ # # Create an L3 GRE tunnel whose destination is in the non-default # table. The underlay is thus non-default - the overlay is still # the default. # - set it admin up # - assign an IP Addres # gre_if = VppGreInterface(self, self.pg1.local_ip4, "2.2.2.2", outer_fib_id=1) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() # # Add a route via the tunnel - in the overlay # route_via_tun = VppIpRoute( self, "9.9.9.9", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Add a route that resolves the tunnel's destination - in the # underlay table # route_tun_dst = VppIpRoute( self, "2.2.2.2", 32, table_id=1, paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # packets are sent in on pg0 which is in the default table # - packets are GRE encapped # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(len(tx)) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4, "2.2.2.2") # # Send tunneled packets that match the created tunnel and # are decapped and forwarded. This tests the decap lookup # does not happen in the encap table # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) self.pg1.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_decapped_4o4(self.pg0, rx, tx) # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()
def test_imposition(self): """ MPLS label imposition test """ # # Add a non-recursive route with a single out label # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[32])]) route_10_0_0_1.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "10.0.0.1") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32]) # # Add a non-recursive route with a 3 out labels # route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[32, 33, 34])]) route_10_0_0_2.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "10.0.0.2") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34]) # # add a recursive path, with output label, via the 1 label route # route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32, [VppRoutePath("10.0.0.1", 0xffffffff, labels=[44])]) route_11_0_0_1.add_vpp_config() # # a stream that matches the route for 11.0.0.1, should pick up # the label stack for 11.0.0.1 and 10.0.0.1 # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "11.0.0.1") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44]) # # add a recursive path, with 2 labels, via the 3 label route # route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32, [VppRoutePath("10.0.0.2", 0xffffffff, labels=[44, 45])]) route_11_0_0_2.add_vpp_config() # # a stream that matches the route for 11.0.0.1, should pick up # the label stack for 11.0.0.1 and 10.0.0.1 # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "11.0.0.2") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4( self.pg0, rx, tx, [32, 33, 34, 44, 45]) # # cleanup # route_11_0_0_2.remove_vpp_config() route_11_0_0_1.remove_vpp_config() route_10_0_0_2.remove_vpp_config() route_10_0_0_1.remove_vpp_config()
def test_swap(self): """ MPLS label swap tests """ # # A simple MPLS xconnect - eos label in label out # route_32_eos = VppMplsRoute(self, 32, 1, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[33])]) route_32_eos.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # self.vapi.cli("clear trace") tx = self.create_stream_labelled_ip4(self.pg0, [32]) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33]) # # A simple MPLS xconnect - non-eos label in label out # route_32_neos = VppMplsRoute(self, 32, 0, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[33])]) route_32_neos.add_vpp_config() # # a stream that matches the route for 10.0.0.1 # PG0 is in the default table # self.vapi.cli("clear trace") tx = self.create_stream_labelled_ip4(self.pg0, [32, 99]) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled(self.pg0, rx, tx, [33, 99]) # # An MPLS xconnect - EOS label in IP out # route_33_eos = VppMplsRoute(self, 33, 1, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])]) route_33_eos.add_vpp_config() self.vapi.cli("clear trace") tx = self.create_stream_labelled_ip4(self.pg0, [33]) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_ip4(self.pg0, rx, tx) # # An MPLS xconnect - non-EOS label in IP out - an invalid configuration # so this traffic should be dropped. # route_33_neos = VppMplsRoute(self, 33, 0, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])]) route_33_neos.add_vpp_config() self.vapi.cli("clear trace") tx = self.create_stream_labelled_ip4(self.pg0, [33, 99]) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.assert_nothing_captured( remark="MPLS non-EOS packets popped and forwarded") # # A recursive EOS x-connect, which resolves through another x-connect # route_34_eos = VppMplsRoute(self, 34, 1, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=32, labels=[44, 45])]) route_34_eos.add_vpp_config() tx = self.create_stream_labelled_ip4(self.pg0, [34]) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 45]) # # A recursive non-EOS x-connect, which resolves through another # x-connect # route_34_neos = VppMplsRoute(self, 34, 0, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=32, labels=[44, 46])]) route_34_neos.add_vpp_config() self.vapi.cli("clear trace") tx = self.create_stream_labelled_ip4(self.pg0, [34, 99]) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() # it's the 2nd (counting from 0) label in the stack that is swapped self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2) # # an recursive IP route that resolves through the recursive non-eos # x-connect # ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=34, labels=[55])]) ip_10_0_0_1.add_vpp_config() self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "10.0.0.1") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55]) ip_10_0_0_1.remove_vpp_config() route_34_neos.remove_vpp_config() route_34_eos.remove_vpp_config() route_33_neos.remove_vpp_config() route_33_eos.remove_vpp_config() route_32_neos.remove_vpp_config() route_32_eos.remove_vpp_config()
def test_udp_encap(self): """ UDP Encap test """ # # construct a UDP encap object through each of the peers # v4 through the first two peers, v6 through the second. # udp_encap_0 = VppUdpEncap(self, self.pg0.local_ip4, self.pg0.remote_ip4, 330, 440) udp_encap_1 = VppUdpEncap(self, self.pg1.local_ip4, self.pg1.remote_ip4, 331, 441, table_id=1) udp_encap_2 = VppUdpEncap(self, self.pg2.local_ip6, self.pg2.remote_ip6, 332, 442, table_id=2) udp_encap_3 = VppUdpEncap(self, self.pg3.local_ip6, self.pg3.remote_ip6, 333, 443, table_id=3) udp_encap_0.add_vpp_config() udp_encap_1.add_vpp_config() udp_encap_2.add_vpp_config() udp_encap_3.add_vpp_config() self.logger.info(self.vapi.cli("sh udp encap")) self.assertTrue(find_udp_encap(self, udp_encap_2)) self.assertTrue(find_udp_encap(self, udp_encap_3)) self.assertTrue(find_udp_encap(self, udp_encap_0)) self.assertTrue(find_udp_encap(self, udp_encap_1)) # # Routes via each UDP encap object - all combinations of v4 and v6. # route_4o4 = VppIpRoute( self, "1.1.0.1", 24, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP, next_hop_id=udp_encap_0.id) ], table_id=1) route_4o6 = VppIpRoute(self, "1.1.2.1", 32, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP, next_hop_id=udp_encap_2.id) ]) route_6o4 = VppIpRoute(self, "2001::1", 128, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP, next_hop_id=udp_encap_1.id) ]) route_6o6 = VppIpRoute(self, "2001::3", 128, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP, next_hop_id=udp_encap_3.id) ]) route_4o6.add_vpp_config() route_6o6.add_vpp_config() route_6o4.add_vpp_config() route_4o4.add_vpp_config() # # 4o4 encap # p_4o4 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="2.2.2.2", dst="1.1.0.1") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg1, p_4o4 * NUM_PKTS, self.pg0) for p in rx: self.validate_outer4(p, udp_encap_0) p = IP(p["UDP"].payload.load) self.validate_inner4(p, p_4o4) self.assertEqual(udp_encap_0.get_stats()['packets'], NUM_PKTS) # # 4o6 encap # p_4o6 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="2.2.2.2", dst="1.1.2.1") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4o6 * NUM_PKTS, self.pg2) for p in rx: self.validate_outer6(p, udp_encap_2) p = IP(p["UDP"].payload.load) self.validate_inner4(p, p_4o6) self.assertEqual(udp_encap_2.get_stats()['packets'], NUM_PKTS) # # 6o4 encap # p_6o4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::100", dst="2001::1") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_6o4 * NUM_PKTS, self.pg1) for p in rx: self.validate_outer4(p, udp_encap_1) p = IPv6(p["UDP"].payload.load) self.validate_inner6(p, p_6o4) self.assertEqual(udp_encap_1.get_stats()['packets'], NUM_PKTS) # # 6o6 encap # p_6o6 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::100", dst="2001::3") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_6o6 * NUM_PKTS, self.pg3) for p in rx: self.validate_outer6(p, udp_encap_3) p = IPv6(p["UDP"].payload.load) self.validate_inner6(p, p_6o6) self.assertEqual(udp_encap_3.get_stats()['packets'], NUM_PKTS) # # A route with an output label # the TTL of the inner packet is decremented on LSP ingress # route_4oMPLSo4 = VppIpRoute(self, "1.1.2.22", 32, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP, next_hop_id=1, labels=[VppMplsLabel(66)]) ]) route_4oMPLSo4.add_vpp_config() p_4omo4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="2.2.2.2", dst="1.1.2.22") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4omo4 * NUM_PKTS, self.pg1) for p in rx: self.validate_outer4(p, udp_encap_1) p = MPLS(p["UDP"].payload.load) self.validate_inner4(p, p_4omo4, ttl=63) self.assertEqual(udp_encap_1.get_stats()['packets'], 2 * NUM_PKTS)
def test_udp_transfer(self): """ UDP echo client/server transfer """ # Add inter-table routes ip_t01 = VppIpRoute( self, self.loop1.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)]) ip_t10 = VppIpRoute( self, self.loop0.local_ip4, 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)], table_id=1) ip_t01.add_vpp_config() ip_t10.add_vpp_config() # Start builtin server and client uri = "udp://" + self.loop0.local_ip4 + "/1234" error = self.vapi.cli("test echo server appns 0 fifo-size 4 no-echo" + "uri " + uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) error = self.vapi.cli("test echo client mbytes 10 appns 1 " + "fifo-size 4 no-output test-bytes " + "syn-timeout 2 no-return uri " + uri) if error: self.logger.critical(error) self.assertNotIn("failed", error) self.logger.debug(self.vapi.cli("show session verbose 2")) # Delete inter-table routes ip_t01.remove_vpp_config() ip_t10.remove_vpp_config()
def test_udp_decap(self): """ UDP Decap test """ # # construct a UDP decap object for each type of protocol # # IPv4 udp_api_proto = VppEnum.vl_api_udp_decap_next_proto_t next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP4 udp_decap_0 = VppUdpDecap(self, 1, 220, next_proto) # IPv6 next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP6 udp_decap_1 = VppUdpDecap(self, 0, 221, next_proto) # MPLS next_proto = udp_api_proto.UDP_API_DECAP_PROTO_MPLS udp_decap_2 = VppUdpDecap(self, 1, 222, next_proto) udp_decap_0.add_vpp_config() udp_decap_1.add_vpp_config() udp_decap_2.add_vpp_config() # # Routes via the corresponding pg after the UDP decap # route_4 = VppIpRoute(self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)], table_id=0) route_6 = VppIpRoute(self, "2001::1", 128, [VppRoutePath("::", self.pg1.sw_if_index)], table_id=1) route_mo4 = VppIpRoute(self, "3.3.3.3", 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)], table_id=2) route_4.add_vpp_config() route_6.add_vpp_config() route_mo4.add_vpp_config() # # Adding neighbors to route the packets # n_4 = VppNeighbor(self, self.pg0.sw_if_index, "00:11:22:33:44:55", "1.1.1.1") n_6 = VppNeighbor(self, self.pg1.sw_if_index, "11:22:33:44:55:66", "2001::1") n_mo4 = VppNeighbor(self, self.pg2.sw_if_index, "22:33:44:55:66:77", "3.3.3.3") n_4.add_vpp_config() n_6.add_vpp_config() n_mo4.add_vpp_config() # # MPLS decapsulation config # mpls_table = VppMplsTable(self, 0) mpls_table.add_vpp_config() mpls_route = VppMplsRoute(self, 77, 1, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=2, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) mpls_route.add_vpp_config() # # UDP over ipv4 decap # p_4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=1111, dport=220) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4 * NUM_PKTS, self.pg0) p_4 = IP(p_4["UDP"].payload) for p in rx: p = IP(p["Ether"].payload) self.validate_inner4(p, p_4, ttl=63) # # UDP over ipv6 decap # p_6 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6) / UDP(sport=2222, dport=221) / IPv6(src="2001::100", dst="2001::1") / UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg1, p_6 * NUM_PKTS, self.pg1) p_6 = IPv6(p_6["UDP"].payload) p = IPv6(rx[0]["Ether"].payload) for p in rx: p = IPv6(p["Ether"].payload) self.validate_inner6(p, p_6, hlim=63) # # UDP over mpls decap # p_mo4 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / UDP(sport=3333, dport=222) / MPLS(label=77, ttl=1) / IP(src="4.4.4.4", dst="3.3.3.3") / UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 100)) self.pg2.enable_mpls() rx = self.send_and_expect(self.pg2, p_mo4 * NUM_PKTS, self.pg2) self.pg2.disable_mpls() p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload) for p in rx: p = IP(p["Ether"].payload) self.validate_inner4(p, p_mo4, ttl=63)
def test_ip4_tx_p2p_subif(self): """send ip4 packet via p2p subinterface""" self.logger.info("FFP_TEST_START_0005") route_9100 = VppIpRoute(self, "9.1.0.100", 24, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, )]) route_9100.add_vpp_config() route_9200 = VppIpRoute(self, "9.2.0.100", 24, [VppRoutePath(self.p2p_sub_ifs[0].remote_ip4, self.p2p_sub_ifs[0].sw_if_index, )]) route_9200.add_vpp_config() route_9300 = VppIpRoute(self, "9.3.0.100", 24, [VppRoutePath(self.p2p_sub_ifs[1].remote_ip4, self.p2p_sub_ifs[1].sw_if_index )]) route_9300.add_vpp_config() for i in range(0, 3): self.packets.append( self.create_stream(src_mac=self.pg1.remote_mac, dst_mac=self.pg1.local_mac, src_ip=self.pg1.remote_ip4, dst_ip="9.%d.0.100" % (i+1))) self.send_packets(self.pg1, self.pg0) # route_7000.remove_vpp_config() route_9100.remove_vpp_config() route_9200.remove_vpp_config() route_9300.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0005")
def test_gre_l2(self): """ GRE tunnel L2 Tests """ # # Add routes to resolve the tunnel destinations # route_tun1_dst = VppIpRoute( self, "2.2.2.2", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]) route_tun2_dst = VppIpRoute( self, "2.2.2.3", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]) route_tun1_dst.add_vpp_config() route_tun2_dst.add_vpp_config() # # Create 2 L2 GRE tunnels and x-connect them # gre_if1 = VppGreInterface(self, self.pg0.local_ip4, "2.2.2.2", is_teb=1) gre_if2 = VppGreInterface(self, self.pg0.local_ip4, "2.2.2.3", is_teb=1) gre_if1.add_vpp_config() gre_if2.add_vpp_config() gre_if1.admin_up() gre_if2.admin_up() self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index, gre_if2.sw_if_index, enable=1) self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index, gre_if1.sw_if_index, enable=1) # # Send in tunnel encapped L2. expect out tunnel encapped L2 # in both directions # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.2", self.pg0.local_ip4) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_tunneled_l2o4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.3") self.vapi.cli("clear trace") tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.3", self.pg0.local_ip4) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_tunneled_l2o4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.2") self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index, gre_if2.sw_if_index, enable=0) self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index, gre_if1.sw_if_index, enable=0) # # Create a VLAN sub-interfaces on the GRE TEB interfaces # then x-connect them # gre_if_11 = VppDot1QSubint(self, gre_if1, 11) gre_if_12 = VppDot1QSubint(self, gre_if2, 12) # gre_if_11.add_vpp_config() # gre_if_12.add_vpp_config() gre_if_11.admin_up() gre_if_12.admin_up() self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index, gre_if_12.sw_if_index, enable=1) self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index, gre_if_11.sw_if_index, enable=1) # # Configure both to pop thier respective VLAN tags, # so that during the x-coonect they will subsequently push # self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index, L2_VTR_OP.L2_POP_1, 12) self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index, L2_VTR_OP.L2_POP_1, 11) # # Send traffic in both directiond - expect the VLAN tags to # be swapped. # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.2", self.pg0.local_ip4, 11) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_tunneled_vlano4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.3", 12) self.vapi.cli("clear trace") tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.3", self.pg0.local_ip4, 12) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_tunneled_vlano4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.2", 11) # # Cleanup Test resources # gre_if_11.remove_vpp_config() gre_if_12.remove_vpp_config() gre_if1.remove_vpp_config() gre_if2.remove_vpp_config() route_tun1_dst.add_vpp_config() route_tun2_dst.add_vpp_config()
def test_abf6(self): """ IPv6 ACL Based Forwarding """ # # Simple test for matching IPv6 packets # # # Rule 1 # rule_1 = ({ 'is_permit': 1, 'is_ipv6': 1, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 128, 'src_ip_addr': inet_pton(AF_INET6, "2001::2"), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 128, 'dst_ip_addr': inet_pton(AF_INET6, "2001::1") }) acl_1 = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # ABF policy for ACL 1 - path via interface 1 # abf_1 = VppAbfPolicy(self, 10, acl_1, [ VppRoutePath("3001::1", 0xffffffff, proto=DpoProto.DPO_PROTO_IP6) ]) abf_1.add_vpp_config() attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 45, is_ipv6=True) attach_1.add_vpp_config() # # a packet matching the rule # p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src="2001::2", dst="2001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # packets are dropped because there is no route to the policy's # next hop # self.send_and_assert_no_replies(self.pg1, p * 65, "no route") # # add a route resolving the next-hop # route = VppIpRoute(self, "3001::1", 32, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route.add_vpp_config() # # now expect packets forwarded. # self.send_and_expect(self.pg0, p * 65, self.pg1)
def test_qos_vlan(self): """QoS mark/record VLAN """ # # QoS for all input values # output = [scapy.compat.chb(0)] * 256 for i in range(0, 255): output[i] = scapy.compat.chb(255 - i) os = b''.join(output) rows = [{'outputs': os}, {'outputs': os}, {'outputs': os}, {'outputs': os}] qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config() sub_if = VppDot1QSubint(self, self.pg0, 11) sub_if.admin_up() sub_if.config_ip4() sub_if.resolve_arp() sub_if.config_ip6() sub_if.resolve_ndp() # # enable VLAN QoS recording/marking on the input Pg0 subinterface and # qr_v = VppQosRecord( self, sub_if, self.QOS_SOURCE.QOS_API_SOURCE_VLAN).add_vpp_config() qm_v = VppQosMark( self, sub_if, qem1, self.QOS_SOURCE.QOS_API_SOURCE_VLAN).add_vpp_config() # # IP marking/recording on pg1 # qr_ip = VppQosRecord( self, self.pg1, self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config() qm_ip = VppQosMark( self, self.pg1, qem1, self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config() # # a routes to/from sub-interface # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(sub_if.remote_ip4, sub_if.sw_if_index)]) route_10_0_0_1.add_vpp_config() route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_2.add_vpp_config() route_2001_1 = VppIpRoute(self, "2001::1", 128, [VppRoutePath(sub_if.remote_ip6, sub_if.sw_if_index)]) route_2001_1.add_vpp_config() route_2001_2 = VppIpRoute(self, "2001::2", 128, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]) route_2001_2.add_vpp_config() p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=1) / IP(src="1.1.1.1", dst="10.0.0.2", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) p_v3 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=1, id=1) / IP(src="1.1.1.1", dst="10.0.0.2", tos=2) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) rx = self.send_and_expect(self.pg1, p_v2 * NUM_PKTS, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 7) self.assertEqual(p[Dot1Q].id, 0) rx = self.send_and_expect(self.pg0, p_v3 * NUM_PKTS, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 252) rx = self.send_and_expect(self.pg0, p_v1 * NUM_PKTS, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 253) p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=2) / IPv6(src="2001::1", dst="2001::2", tc=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src="3001::1", dst="2001::1", tc=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) rx = self.send_and_expect(self.pg1, p_v2 * NUM_PKTS, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 7) self.assertEqual(p[Dot1Q].id, 0) rx = self.send_and_expect(self.pg0, p_v1 * NUM_PKTS, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 251) # # cleanup # sub_if.unconfig_ip4() sub_if.unconfig_ip6()
def test_map_t(self): """ MAP-T """ # # Add a domain that maps from pg0 to pg1 # map_dst = '2001:db8::/32' map_src = '1234:5678:90ab:cdef::/64' ip4_pfx = '192.168.0.0/24' self.vapi.map_add_domain(map_dst, ip4_pfx, map_src, 16, 6, 4, mtu=1500) # Enable MAP-T on interfaces. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1) self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) map_route = VppIpRoute(self, "2001:db8::", 32, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) map_route.add_vpp_config() # # Send a v4 packet that will be translated # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0) for p in rx: self.validate(p[1], p4_translated) # IPv4 TTL ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = ( IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / ICMP(type='time-exceeded', code='ttl-zero-during-transit') / IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload) rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' This one is broken, cause it would require hairpinning... # IPv4 TTL TTL1 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=1) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / \ ICMP(type='time-exceeded', code='ttl-zero-during-transit' ) / \ IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload rx = self.send_and_expect(self.pg0, p4*1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' # IPv6 Hop limit ip6_hlim_expired = IPv6(hlim=0, src='2001:db8:1ab::c0a8:1:ab', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / ip6_hlim_expired / payload) icmp6_reply = (IPv6( hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab") / ICMPv6TimeExceeded(code=0) / IPv6(src="2001:db8:1ab::c0a8:1:ab", dst='1234:5678:90ab:cdef:ac:1001:200:0', hlim=0) / payload) rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1) for p in rx: self.validate(p[1], icmp6_reply) # IPv4 Well-known port p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = UDP(sport=200, dport=200) p4 = (p_ether / p_ip4 / payload) self.send_and_assert_no_replies(self.pg0, p4 * 1) # IPv6 Well-known port payload = UDP(sport=200, dport=200) p6 = (p_ether6 / p_ip6 / payload) self.send_and_assert_no_replies(self.pg1, p6 * 1) # Packet fragmentation payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # TODO: Manual validation # self.validate(p[1], icmp4_reply) # Packet fragmentation send fragments payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) frags = fragment(p4, fragsize=1000) self.pg_enable_capture() self.pg0.add_stream(frags) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # p.show2() # reass_pkt = reassemble(rx) # p4_reply.ttl -= 1 # p4_reply.id = 256 # self.validate(reass_pkt, p4_reply) # TCP MSS clamping self.vapi.map_param_set_tcp(1300) # # Send a v4 TCP SYN packet that will be translated and MSS clamped # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd, flags="S", options=[('MSS', 1460)]) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 p6_translated[TCP].options = [('MSS', 1300)] rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 p4_translated[TCP].options = [('MSS', 1300)] rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0) for p in rx: self.validate(p[1], p4_translated)
def test_l2_emulation(self): """ L2 Emulation """ # # non distinct L3 packets, in the tag/non-tag combos # pkt_no_tag = (Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_to_tag = (Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) / IP(src="2.2.2.2", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_from_tag = (Ether(src=self.pg3.remote_mac, dst=self.pg2.remote_mac) / Dot1Q(vlan=93) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_from_to_tag = (Ether(src=self.pg3.remote_mac, dst=self.pg2.remote_mac) / Dot1Q(vlan=93) / IP(src="2.2.2.2", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_bcast = (Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / IP(src="2.2.2.2", dst="255.255.255.255") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # A couple of sub-interfaces for tags # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=92) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=93) # # Disable UU flooding, learning and ARP termination. makes this test # easier as unicast packets are dropped if not extracted. # self.vapi.bridge_flags(bd_id=1, is_set=0, flags=(1 << 0) | (1 << 3) | (1 << 4)) # # Add a DVR route to steer traffic at L3 # route_1 = VppIpRoute(self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", self.pg1.sw_if_index, is_dvr=1)]) route_2 = VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", sub_if_on_pg2.sw_if_index, is_dvr=1)]) route_1.add_vpp_config() route_2.add_vpp_config() # # packets are dropped because bridge does not flood unknown unicast # self.send_and_assert_no_replies(self.pg0, pkt_no_tag) # # Enable L3 extraction on pgs # self.vapi.l2_emulation(self.pg0.sw_if_index) self.vapi.l2_emulation(self.pg1.sw_if_index) self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index) self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index) # # now we expect the packet forward according to the DVR route # rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) rx = self.send_and_expect(self.pg0, pkt_to_tag * 65, self.pg2) self.assert_same_mac_addr(pkt_to_tag, rx) self.assert_has_vlan_tag(92, rx) rx = self.send_and_expect(self.pg3, pkt_from_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_from_tag, rx) self.assert_has_no_tag(rx) rx = self.send_and_expect(self.pg3, pkt_from_to_tag * 65, self.pg2) self.assert_same_mac_addr(pkt_from_tag, rx) self.assert_has_vlan_tag(92, rx) # # but broadcast packets are still flooded # self.send_and_expect(self.pg0, pkt_bcast * 33, self.pg2) # # cleanup # self.vapi.l2_emulation(self.pg0.sw_if_index, enable=0) self.vapi.l2_emulation(self.pg1.sw_if_index, enable=0) self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index, enable=0) self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0) route_1.remove_vpp_config() route_2.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 64 map_route = VppIpRoute(self, map_br_pfx, map_br_pfx_len, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = '2001::/64' map_src = '3000::1/128' client_pfx = '192.168.0.0/16' self.vapi.map_add_domain(map_dst, client_pfx, map_src) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0") # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src="2001::1") / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resolved via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [ VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify([ VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def test_sr_mpls(self): """ SR MPLS """ # # A simple MPLS xconnect - neos label in label out # route_32_eos = VppMplsRoute(self, 32, 0, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)])]) route_32_eos.add_vpp_config() # # A binding SID with only one label # self.vapi.sr_mpls_policy_add(999, 1, 0, [32]) # # A labeled IP route that resolves thru the binding SID # ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=999, labels=[VppMplsLabel(55)])]) ip_10_0_0_1.add_vpp_config() tx = self.create_stream_ip4(self.pg1, "10.0.0.1") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(55)]) # # An unlabeled IP route that resolves thru the binding SID # ip_10_0_0_1 = VppIpRoute(self, "10.0.0.2", 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=999)]) ip_10_0_0_1.add_vpp_config() tx = self.create_stream_ip4(self.pg1, "10.0.0.2") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)]) self.vapi.sr_mpls_policy_del(999) # # this time the SID has many labels pushed # self.vapi.sr_mpls_policy_add(999, 1, 0, [32, 33, 34]) tx = self.create_stream_ip4(self.pg1, "10.0.0.1") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34), VppMplsLabel(55)]) tx = self.create_stream_ip4(self.pg1, "10.0.0.2") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)]) # # Resolve an MPLS tunnel via the SID # mpls_tun = VppMPLSTunnelInterface( self, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=999, labels=[VppMplsLabel(44), VppMplsLabel(46)])]) mpls_tun.add_vpp_config() mpls_tun.admin_up() # # add an unlabelled route through the new tunnel # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]) route_10_0_0_3.add_vpp_config() self.logger.info(self.vapi.cli("sh mpls tun 0")) self.logger.info(self.vapi.cli("sh adj 21")) tx = self.create_stream_ip4(self.pg1, "10.0.0.3") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34), VppMplsLabel(44), VppMplsLabel(46)]) # # add a labelled route through the new tunnel # route_10_0_0_3 = VppIpRoute(self, "10.0.0.4", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[VppMplsLabel(55)])]) route_10_0_0_3.add_vpp_config() tx = self.create_stream_ip4(self.pg1, "10.0.0.4") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34), VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(55)]) self.vapi.sr_mpls_policy_del(999)
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 64 map_route = VppIpRoute(self, map_br_pfx, map_br_pfx_len, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = socket.inet_pton(socket.AF_INET6, map_br_pfx) map_src = "3001::1" map_src_n = socket.inet_pton(socket.AF_INET6, map_src) client_pfx = socket.inet_pton(socket.AF_INET, "192.168.0.0") self.vapi.map_add_domain(map_dst, map_br_pfx_len, map_src_n, 128, client_pfx, 16) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.send_and_assert_encapped(v4, map_src, "2001::c0a8:0:0") # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=map_src, src="2001::1") / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resovled via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [ VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, map_src, "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify([ VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, map_src, "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def test_qos_mpls(self): """ QoS Mark/Record MPLS """ # # 255 QoS for all input values # output = [chr(255)] * 256 os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(1, rows) # # a route with 1 MPLS label # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [ VppRoutePath( self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[32]) ]) route_10_0_0_1.add_vpp_config() # # a route with 3 MPLS labels # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [ VppRoutePath( self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[63, 33, 34]) ]) route_10_0_0_3.add_vpp_config() # # enable IP QoS recording on the input Pg0 and MPLS egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 1) # # packet that will get one label added and 3 labels added resp. # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_3 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.3", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_1 * 65, self.pg1) # # only 3 bits of ToS value in MPLS make sure tos is correct # and the label and EOS bit have not been corrupted # for p in rx: self.assertEqual(p[MPLS].cos, 7) self.assertEqual(p[MPLS].label, 32) self.assertEqual(p[MPLS].s, 1) rx = self.send_and_expect(self.pg0, p_3 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, 7) self.assertEqual(p[MPLS].label, 63) self.assertEqual(p[MPLS].s, 0) h = p[MPLS].payload self.assertEqual(h[MPLS].cos, 7) self.assertEqual(h[MPLS].label, 33) self.assertEqual(h[MPLS].s, 0) h = h[MPLS].payload self.assertEqual(h[MPLS].cos, 7) self.assertEqual(h[MPLS].label, 34) self.assertEqual(h[MPLS].s, 1) # # enable MPLS QoS recording on the input Pg0 and IP egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.MPLS, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) # # MPLS x-connect - COS is preserved # route_32_eos = VppMplsRoute(self, 32, 1, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(33)]) ]) route_32_eos.add_vpp_config() p_m1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=32, cos=3, ttl=2) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_m1 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, 7) self.assertEqual(p[MPLS].label, 33) self.assertEqual(p[MPLS].s, 1) # # MPLS deag - COS is copied from MPLS to IP # route_33_eos = VppMplsRoute( self, 33, 1, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)]) route_33_eos.add_vpp_config() route_10_0_0_4 = VppIpRoute( self, "10.0.0.4", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_4.add_vpp_config() p_m2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=33, ttl=2, cos=3) / IP(src=self.pg0.remote_ip4, dst="10.0.0.4", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_m2 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 255) # # cleanup # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 0) self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.MPLS, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0) self.vapi.qos_egress_map_delete(1)
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 64 map_route = VppIpRoute(self, map_br_pfx, map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = '2001::/64' map_src = '3000::1/128' client_pfx = '192.168.0.0/16' self.vapi.map_add_domain(map_dst, client_pfx, map_src) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4*1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0") # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6*1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src="2001::1") / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resovled via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify([VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def test_flood(self): """ L2 Flood Tests """ # # Create a single bridge Domain # self.vapi.bridge_domain_add_del(bd_id=1) # # add each interface to the BD. 3 interfaces per split horizon group # for i in self.pg_interfaces[0:4]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=0) for i in self.pg_interfaces[4:8]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=1) for i in self.pg_interfaces[8:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2) for i in self.bvi_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:de:ad:be:ef") / IP(src="10.10.10.10", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # input on pg0 expect copies on pg1->11 # this is in SHG=0 so its flooded to all, expect the pg0 since that's # the ingress link # self.pg0.add_stream(p * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[1:12]: rx0 = i.get_capture(NUM_PKTS, timeout=1) # # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0) # and pg8->11 (SHG=2) # self.pg4.add_stream(p * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[:4]: rx0 = i.get_capture(NUM_PKTS, timeout=1) for i in self.pg_interfaces[8:12]: rx0 = i.get_capture(NUM_PKTS, timeout=1) for i in self.pg_interfaces[4:8]: i.assert_nothing_captured(remark="Different SH group") # # An IP route so the packet that hits the BVI is sent out of pg12 # ip_route = VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath(self.pg12.remote_ip4, self.pg12.sw_if_index)]) ip_route.add_vpp_config() self.logger.info(self.vapi.cli("sh bridge 1 detail")) # # input on pg0 expect copies on pg1->12 # this is in SHG=0 so its flooded to all, expect the pg0 since that's # the ingress link # self.pg0.add_stream(p * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[1:]: rx0 = i.get_capture(NUM_PKTS, timeout=1) # # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0) # and pg8->12 (SHG=2) # self.pg4.add_stream(p * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[:4]: rx0 = i.get_capture(NUM_PKTS, timeout=1) for i in self.pg_interfaces[8:13]: rx0 = i.get_capture(NUM_PKTS, timeout=1) for i in self.pg_interfaces[4:8]: i.assert_nothing_captured(remark="Different SH group") # # cleanup # for i in self.pg_interfaces[:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0) for i in self.bvi_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI, enable=0) self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
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, scapy.compat.chb(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_ip6_tx_p2p_subif(self): """send packet via p2p subinterface""" self.logger.info("FFP_TEST_START_0005") route_8000 = VppIpRoute(self, "8000::", 64, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8000.add_vpp_config() route_8001 = VppIpRoute(self, "8001::", 64, [VppRoutePath(self.p2p_sub_ifs[0].remote_ip6, self.p2p_sub_ifs[0].sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8001.add_vpp_config() route_8002 = VppIpRoute(self, "8002::", 64, [VppRoutePath(self.p2p_sub_ifs[1].remote_ip6, self.p2p_sub_ifs[1].sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_8002.add_vpp_config() for i in range(0, 3): self.packets.append( self.create_stream(src_mac=self.pg1.remote_mac, dst_mac=self.pg1.local_mac, src_ip=self.pg1.remote_ip6, dst_ip="800%d::100" % i)) self.send_packets(self.pg1, self.pg0, count=3) route_8000.remove_vpp_config() route_8001.remove_vpp_config() route_8002.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0005")
def test_SRv6_End_AD_L2(self): """ Test SRv6 End.AD behavior with L2 traffic. """ self.src_addr = 'a0::' self.sid_list = ['a1::', 'a2::a4', 'a3::'] self.test_sid_index = 1 # send traffic to one destination interface # source and destination interfaces are IPv6 only self.setup_interfaces(ipv6=[True, False]) # configure route to next segment route = VppIpRoute(self, self.sid_list[self.test_sid_index + 1], 128, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route.add_vpp_config() # configure SRv6 localSID behavior cli_str = "sr localsid address " + \ self.sid_list[self.test_sid_index] + \ " behavior end.ad" + \ " oif " + self.pg1.name + \ " iif " + self.pg1.name self.vapi.cli(cli_str) # log the localsids self.logger.debug(self.vapi.cli("show sr localsid")) # send one packet per packet size count = len(self.pg_packet_sizes) # prepare L2 in SRv6 headers packet_header1 = self.create_packet_header_IPv6_SRH_L2( srcaddr=self.src_addr, sidlist=self.sid_list[::-1], segleft=len(self.sid_list) - self.test_sid_index - 1, vlan=0) # generate packets (pg0->pg1) pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, self.compare_rx_tx_packet_End_AD_L2_out) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # prepare L2 header for returning packets packet_header2 = self.create_packet_header_L2() # generate returning packets (pg1->pg0) pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, self.compare_rx_tx_packet_End_AD_L2_in) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # remove SRv6 localSIDs cli_str = "sr localsid del address " + \ self.sid_list[self.test_sid_index] self.vapi.cli(cli_str) # cleanup interfaces self.teardown_interfaces()
def test_ip6_tx_p2p_subif(self): """send packet via p2p subinterface""" self.logger.info("FFP_TEST_START_0005") route_8000 = VppIpRoute(self, "8000::", 64, [ VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_8000.add_vpp_config() route_8001 = VppIpRoute( self, "8001::", 64, [ VppRoutePath(self.p2p_sub_ifs[0].remote_ip6, self.p2p_sub_ifs[0].sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_8001.add_vpp_config() route_8002 = VppIpRoute( self, "8002::", 64, [ VppRoutePath(self.p2p_sub_ifs[1].remote_ip6, self.p2p_sub_ifs[1].sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_8002.add_vpp_config() for i in range(0, 3): self.packets.append( self.create_stream(src_mac=self.pg1.remote_mac, dst_mac=self.pg1.local_mac, src_ip=self.pg1.remote_ip6, dst_ip="800%d::100" % i)) self.send_packets(self.pg1, self.pg0, count=3) route_8000.remove_vpp_config() route_8001.remove_vpp_config() route_8002.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0005")
def test_qos_vlan(self): """QoS mark/record VLAN """ # # QoS for all input values # output = [scapy.compat.chb(0)] * 256 for i in range(0, 255): output[i] = scapy.compat.chb(255 - i) os = b''.join(output) rows = [{'outputs': os}, {'outputs': os}, {'outputs': os}, {'outputs': os}] self.vapi.qos_egress_map_update(1, rows) sub_if = VppDot1QSubint(self, self.pg0, 11) sub_if.admin_up() sub_if.config_ip4() sub_if.resolve_arp() sub_if.config_ip6() sub_if.resolve_ndp() # # enable VLAN QoS recording/marking on the input Pg0 subinterface and # self.vapi.qos_record_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1) self.vapi.qos_mark_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1, 1) # # IP marking/recording on pg1 # self.vapi.qos_record_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) # # a routes to/from sub-interface # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(sub_if.remote_ip4, sub_if.sw_if_index)]) route_10_0_0_1.add_vpp_config() route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_2.add_vpp_config() route_2001_1 = VppIpRoute(self, "2001::1", 128, [VppRoutePath(sub_if.remote_ip6, sub_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_2001_1.add_vpp_config() route_2001_2 = VppIpRoute(self, "2001::2", 128, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_2001_2.add_vpp_config() p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=1) / IP(src="1.1.1.1", dst="10.0.0.2", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 6) rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 254) p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=2) / IPv6(src="2001::1", dst="2001::2", tc=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src="3001::1", dst="2001::1", tc=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 6) rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 253) # # cleanup # sub_if.unconfig_ip4() sub_if.unconfig_ip6() self.vapi.qos_record_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 0) self.vapi.qos_mark_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1, 0) self.vapi.qos_record_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0)
def test_flood(self): """ L2 Flood Tests """ # # Create a single bridge Domain # self.vapi.bridge_domain_add_del(bd_id=1) # # add each interface to the BD. 3 interfaces per split horizon group # for i in self.pg_interfaces[0:4]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=0) for i in self.pg_interfaces[4:8]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=1) for i in self.pg_interfaces[8:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2) for i in self.bvi_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:de:ad:be:ef") / IP(src="10.10.10.10", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # input on pg0 expect copies on pg1->11 # this is in SHG=0 so its flooded to all, expect the pg0 since that's # the ingress link # self.pg0.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[1:12]: rx0 = i.get_capture(65, timeout=1) # # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0) # and pg8->11 (SHG=2) # self.pg4.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[:4]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[8:12]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[4:8]: i.assert_nothing_captured(remark="Different SH group") # # An IP route so the packet that hits the BVI is sent out of pg12 # ip_route = VppIpRoute(self, "1.1.1.1", 32, [VppRoutePath(self.pg12.remote_ip4, self.pg12.sw_if_index)]) ip_route.add_vpp_config() self.logger.info(self.vapi.cli("sh bridge 1 detail")) # # input on pg0 expect copies on pg1->12 # this is in SHG=0 so its flooded to all, expect the pg0 since that's # the ingress link # self.pg0.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[1:]: rx0 = i.get_capture(65, timeout=1) # # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0) # and pg8->12 (SHG=2) # self.pg4.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[:4]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[8:13]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[4:8]: i.assert_nothing_captured(remark="Different SH group") # # cleanup # for i in self.pg_interfaces[:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0) for i in self.bvi_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI, enable=0) self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
def test_dvr(self): """ Distributed Virtual Router """ # # A packet destined to an IP address that is L2 bridged via # a non-tag interface # ip_non_tag_bridged = "10.10.10.10" ip_tag_bridged = "10.10.10.11" any_src_addr = "1.1.1.1" pkt_no_tag = ( Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_tag = (Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # Two sub-interfaces so we can test VLAN tag push/pop # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index, 1, port_type=L2_PORT_TYPE.BVI) self.vapi.l2_interface_vlan_tag_rewrite(sub_if_on_pg2.sw_if_index, L2_VTR_OP.L2_POP_1, 92) self.vapi.l2_interface_vlan_tag_rewrite(sub_if_on_pg3.sw_if_index, L2_VTR_OP.L2_POP_1, 93) # # Add routes to bridge the traffic via a tagged an nontagged interface # route_no_tag = VppIpRoute( self, ip_non_tag_bridged, 32, [VppRoutePath("0.0.0.0", self.pg1.sw_if_index, is_dvr=1)]) route_no_tag.add_vpp_config() # # Inject the packet that arrives and leaves on a non-tagged interface # Since it's 'bridged' expect that the MAC headed is unchanged. # rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) # # Add routes to bridge the traffic via a tagged interface # route_with_tag = VppIpRoute( self, ip_tag_bridged, 32, [VppRoutePath("0.0.0.0", sub_if_on_pg3.sw_if_index, is_dvr=1)]) route_with_tag.add_vpp_config() # # Inject the packet that arrives non-tag and leaves on a tagged # interface # rx = self.send_and_expect(self.pg0, pkt_tag * 65, self.pg3) self.assert_same_mac_addr(pkt_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to tag # pkt_tag_to_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * 65, self.pg3) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to non-Tag # pkt_tag_to_non_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_no_tag(rx) # # Add an output L3 ACL that will block the traffic # rule_1 = ({ 'is_permit': 0, 'is_ipv6': 0, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 32, 'src_ip_addr': inet_pton(AF_INET, any_src_addr), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 32, 'dst_ip_addr': inet_pton(AF_INET, ip_non_tag_bridged) }) acl = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # Apply the ACL on the output interface # self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index, 0, [acl.acl_index]) # # Send packet's that should match the ACL and be dropped # rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * 65) # # cleanup # self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index, 0, []) self.vapi.acl_del(acl.acl_index) self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(self.loop0.sw_if_index, 1, port_type=L2_PORT_TYPE.BVI, enable=0) # # Do a FIB dump to make sure the paths are correctly reported as DVR # routes = self.vapi.ip_fib_dump() for r in routes: if (inet_pton(AF_INET, ip_tag_bridged) == r.address): self.assertEqual(r.path[0].sw_if_index, sub_if_on_pg3.sw_if_index) self.assertEqual(r.path[0].is_dvr, 1) if (inet_pton(AF_INET, ip_non_tag_bridged) == r.address): self.assertEqual(r.path[0].sw_if_index, self.pg1.sw_if_index) self.assertEqual(r.path[0].is_dvr, 1) # # the explicit route delete is require so it happens before # the sbu-interface delete. subinterface delete is required # because that object type does not use the object registry # route_no_tag.remove_vpp_config() route_with_tag.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def run_SRv6_End_AS_IPv4(self, sid_list, test_sid_index, rewrite_src_addr): """ Run SRv6 End.AS test with IPv4 traffic. """ self.rewrite_src_addr = rewrite_src_addr self.rewrite_sid_list = sid_list[test_sid_index + 1::] # send traffic to one destination interface # source and destination interfaces are IPv6 only self.setup_interfaces(ipv6=[True, False], ipv4=[True, True]) # configure route to next segment route = VppIpRoute(self, sid_list[test_sid_index + 1], 128, [ VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route.add_vpp_config() # configure SRv6 localSID behavior cli_str = "sr localsid address " + sid_list[test_sid_index] \ + " behavior end.as" \ + " nh " + self.pg1.remote_ip4 \ + " oif " + self.pg1.name \ + " iif " + self.pg1.name \ + " src " + self.rewrite_src_addr for s in self.rewrite_sid_list: cli_str += " next " + s self.vapi.cli(cli_str) # log the localsids self.logger.debug(self.vapi.cli("show sr localsid")) # send one packet per packet size count = len(self.pg_packet_sizes) # prepare IPv4 in SRv6 headers packet_header1 = self.create_packet_header_IPv6_SRH_IPv4( sidlist=sid_list[::-1], segleft=len(sid_list) - test_sid_index - 1) # generate packets (pg0->pg1) pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, self.compare_rx_tx_packet_End_AS_IPv4_out) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # prepare IPv6 header for returning packets packet_header2 = self.create_packet_header_IPv4() # generate returning packets (pg1->pg0) pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, self.compare_rx_tx_packet_End_AS_IPv4_in) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # remove SRv6 localSIDs self.vapi.cli("sr localsid del address " + sid_list[test_sid_index]) # cleanup interfaces self.teardown_interfaces()
def test_map_t(self): """ MAP-T """ # # Add a domain that maps from pg0 to pg1 # map_dst = socket.inet_pton(socket.AF_INET6, "2001:db8::") map_src = socket.inet_pton(socket.AF_INET6, "1234:5678:90ab:cdef::") ip4_pfx = socket.inet_pton(socket.AF_INET, "192.168.0.0") self.vapi.map_add_domain(map_dst, 32, map_src, 64, ip4_pfx, 24, 16, 6, 4, 1) # Enable MAP-T on interfaces. # self.vapi.map_if_enable_disable(1, self.pg0.sw_if_index, 1) # self.vapi.map_if_enable_disable(1, self.pg1.sw_if_index, 1) map_route = VppIpRoute(self, "2001:db8::", 32, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) map_route.add_vpp_config() # # Send a v4 packet that will be translated # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0) for p in rx: self.validate(p[1], p4_translated) # IPv4 TTL ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = ( IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / ICMP(type='time-exceeded', code='ttl-zero-during-transit') / IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload) rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' This one is broken, cause it would require hairpinning... # IPv4 TTL TTL1 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=1) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / \ ICMP(type='time-exceeded', code='ttl-zero-during-transit' ) / \ IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload rx = self.send_and_expect(self.pg0, p4*1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' # IPv6 Hop limit ip6_hlim_expired = IPv6(hlim=0, src='2001:db8:1ab::c0a8:1:ab', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / ip6_hlim_expired / payload) icmp6_reply = (IPv6( hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab") / ICMPv6TimeExceeded(code=0) / IPv6(src="2001:db8:1ab::c0a8:1:ab", dst='1234:5678:90ab:cdef:ac:1001:200:0', hlim=0) / payload) rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1) for p in rx: self.validate(p[1], icmp6_reply) # IPv4 Well-known port p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = UDP(sport=200, dport=200) p4 = (p_ether / p_ip4 / payload) self.send_and_assert_no_replies(self.pg0, p4 * 1) # IPv6 Well-known port payload = UDP(sport=200, dport=200) p6 = (p_ether6 / p_ip6 / payload) self.send_and_assert_no_replies(self.pg1, p6 * 1) # Packet fragmentation payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # TODO: Manual validation # self.validate(p[1], icmp4_reply) # Packet fragmentation send fragments payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) frags = fragment(p4, fragsize=1000) self.pg_enable_capture() self.pg0.add_stream(frags) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass
def test_qos_mpls(self): """ QoS Mark/Record MPLS """ # # 255 QoS for all input values # from_ext = 7 from_ip = 6 from_mpls = 5 from_vlan = 4 output = [scapy.compat.chb(from_ext)] * 256 os1 = b''.join(output) output = [scapy.compat.chb(from_vlan)] * 256 os2 = b''.join(output) output = [scapy.compat.chb(from_mpls)] * 256 os3 = b''.join(output) output = [scapy.compat.chb(from_ip)] * 256 os4 = b''.join(output) rows = [{'outputs': os1}, {'outputs': os2}, {'outputs': os3}, {'outputs': os4}] self.vapi.qos_egress_map_update(1, rows) # # a route with 1 MPLS label # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[32])]) route_10_0_0_1.add_vpp_config() # # a route with 3 MPLS labels # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[63, 33, 34])]) route_10_0_0_3.add_vpp_config() # # enable IP QoS recording on the input Pg0 and MPLS egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 1) # # packet that will get one label added and 3 labels added resp. # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) p_3 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.3", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) rx = self.send_and_expect(self.pg0, p_1 * 65, self.pg1) # # only 3 bits of ToS value in MPLS make sure tos is correct # and the label and EOS bit have not been corrupted # for p in rx: self.assertEqual(p[MPLS].cos, from_ip) self.assertEqual(p[MPLS].label, 32) self.assertEqual(p[MPLS].s, 1) rx = self.send_and_expect(self.pg0, p_3 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, from_ip) self.assertEqual(p[MPLS].label, 63) self.assertEqual(p[MPLS].s, 0) h = p[MPLS].payload self.assertEqual(h[MPLS].cos, from_ip) self.assertEqual(h[MPLS].label, 33) self.assertEqual(h[MPLS].s, 0) h = h[MPLS].payload self.assertEqual(h[MPLS].cos, from_ip) self.assertEqual(h[MPLS].label, 34) self.assertEqual(h[MPLS].s, 1) # # enable MPLS QoS recording on the input Pg0 and IP egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.MPLS, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) # # MPLS x-connect - COS according to pg1 map # route_32_eos = VppMplsRoute(self, 32, 1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(33)])]) route_32_eos.add_vpp_config() p_m1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=32, cos=3, ttl=2) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) rx = self.send_and_expect(self.pg0, p_m1 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, from_mpls) self.assertEqual(p[MPLS].label, 33) self.assertEqual(p[MPLS].s, 1) # # MPLS deag - COS is copied from MPLS to IP # route_33_eos = VppMplsRoute(self, 33, 1, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)]) route_33_eos.add_vpp_config() route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_4.add_vpp_config() p_m2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=33, ttl=2, cos=3) / IP(src=self.pg0.remote_ip4, dst="10.0.0.4", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * 65)) rx = self.send_and_expect(self.pg0, p_m2 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, from_mpls) # # cleanup # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 0) self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.MPLS, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0) self.vapi.qos_egress_map_delete(1)
def test_qos_mpls(self): """ QoS Mark/Record MPLS """ # # 255 QoS for all input values # from_ext = 7 from_ip = 6 from_mpls = 5 from_vlan = 4 output = [scapy.compat.chb(from_ext)] * 256 os1 = b''.join(output) output = [scapy.compat.chb(from_vlan)] * 256 os2 = b''.join(output) output = [scapy.compat.chb(from_mpls)] * 256 os3 = b''.join(output) output = [scapy.compat.chb(from_ip)] * 256 os4 = b''.join(output) rows = [{'outputs': os1}, {'outputs': os2}, {'outputs': os3}, {'outputs': os4}] qem1 = VppQosEgressMap(self, 1, rows).add_vpp_config() # # a route with 1 MPLS label # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[32])]) route_10_0_0_1.add_vpp_config() # # a route with 3 MPLS labels # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[63, 33, 34])]) route_10_0_0_3.add_vpp_config() # # enable IP QoS recording on the input Pg0 and MPLS egress marking # on Pg1 # qr1 = VppQosRecord(self, self.pg0, self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config() qm1 = VppQosMark(self, self.pg1, qem1, self.QOS_SOURCE.QOS_API_SOURCE_MPLS).add_vpp_config() # # packet that will get one label added and 3 labels added resp. # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) p_3 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.3", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) rx = self.send_and_expect(self.pg0, p_1 * NUM_PKTS, self.pg1) # # only 3 bits of ToS value in MPLS make sure tos is correct # and the label and EOS bit have not been corrupted # for p in rx: self.assertEqual(p[MPLS].cos, from_ip) self.assertEqual(p[MPLS].label, 32) self.assertEqual(p[MPLS].s, 1) rx = self.send_and_expect(self.pg0, p_3 * NUM_PKTS, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, from_ip) self.assertEqual(p[MPLS].label, 63) self.assertEqual(p[MPLS].s, 0) h = p[MPLS].payload self.assertEqual(h[MPLS].cos, from_ip) self.assertEqual(h[MPLS].label, 33) self.assertEqual(h[MPLS].s, 0) h = h[MPLS].payload self.assertEqual(h[MPLS].cos, from_ip) self.assertEqual(h[MPLS].label, 34) self.assertEqual(h[MPLS].s, 1) # # enable MPLS QoS recording on the input Pg0 and IP egress marking # on Pg1 # qr2 = VppQosRecord( self, self.pg0, self.QOS_SOURCE.QOS_API_SOURCE_MPLS).add_vpp_config() qm2 = VppQosMark( self, self.pg1, qem1, self.QOS_SOURCE.QOS_API_SOURCE_IP).add_vpp_config() # # MPLS x-connect - COS according to pg1 map # route_32_eos = VppMplsRoute(self, 32, 1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(33)])]) route_32_eos.add_vpp_config() p_m1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=32, cos=3, ttl=2) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) rx = self.send_and_expect(self.pg0, p_m1 * NUM_PKTS, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, from_mpls) self.assertEqual(p[MPLS].label, 33) self.assertEqual(p[MPLS].s, 1) # # MPLS deag - COS is copied from MPLS to IP # route_33_eos = VppMplsRoute(self, 33, 1, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)]) route_33_eos.add_vpp_config() route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_4.add_vpp_config() p_m2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=33, ttl=2, cos=3) / IP(src=self.pg0.remote_ip4, dst="10.0.0.4", tos=1) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(100) * NUM_PKTS)) rx = self.send_and_expect(self.pg0, p_m2 * NUM_PKTS, self.pg1) for p in rx: self.assertEqual(p[IP].tos, from_mpls)
def test_mgre6(self): """ mGRE IPv6 tunnel Tests """ self.pg0.config_ip6() self.pg0.resolve_ndp() e = VppEnum.vl_api_tunnel_encap_decap_flags_t for itf in self.pg_interfaces[3:]: # # one underlay nh for each overlay/tunnel peer # itf.config_ip6() itf.generate_remote_hosts(4) itf.configure_ipv6_neighbors() # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # gre_if = VppGreInterface( self, itf.local_ip6, "::", mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP), flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip6() gre_if.generate_remote_hosts(4) # # for-each peer # for ii in range(1, 4): route_addr = "4::%d" % ii # # Add a NHRP entry resolves the peer # teib = VppNhrp(self, gre_if, gre_if._remote_hosts[ii].ip6, itf._remote_hosts[ii].ip6) teib.add_vpp_config() # # route traffic via the peer # route_via_tun = VppIpRoute(self, route_addr, 128, [ VppRoutePath(gre_if._remote_hosts[ii].ip6, gre_if.sw_if_index) ]) route_via_tun.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - packets are GRE encapped # tx_e = self.create_stream_ip6(self.pg0, "5::5", route_addr, dscp=2, ecn=1) rx = self.send_and_expect(self.pg0, tx_e, itf) self.verify_tunneled_6o6(self.pg0, rx, tx_e, itf.local_ip6, itf._remote_hosts[ii].ip6, dscp=2) tx_i = self.create_tunnel_stream_6o6(self.pg0, itf._remote_hosts[ii].ip6, itf.local_ip6, self.pg0.local_ip6, self.pg0.remote_ip6) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) self.verify_decapped_6o6(self.pg0, rx, tx_i) # # delete and re-add the NHRP # teib.remove_vpp_config() self.send_and_assert_no_replies(self.pg0, tx_e) teib.add_vpp_config() rx = self.send_and_expect(self.pg0, tx_e, itf) self.verify_tunneled_6o6(self.pg0, rx, tx_e, itf.local_ip6, itf._remote_hosts[ii].ip6, dscp=2) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) self.verify_decapped_6o6(self.pg0, rx, tx_i) gre_if.admin_down() gre_if.unconfig_ip4() itf.unconfig_ip6() self.pg0.unconfig_ip6()
def test_l2_emulation(self): """ L2 Emulation """ # # non distinct L3 packets, in the tag/non-tag combos # pkt_no_tag = (Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_to_tag = (Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) / IP(src="2.2.2.2", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_from_tag = ( Ether(src=self.pg3.remote_mac, dst=self.pg2.remote_mac) / Dot1Q(vlan=93) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_from_to_tag = ( Ether(src=self.pg3.remote_mac, dst=self.pg2.remote_mac) / Dot1Q(vlan=93) / IP(src="2.2.2.2", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_bcast = (Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / IP(src="2.2.2.2", dst="255.255.255.255") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # A couple of sub-interfaces for tags # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1) self.vapi.l2_interface_vlan_tag_rewrite(sub_if_on_pg2.sw_if_index, L2_VTR_OP.L2_POP_1, 92) self.vapi.l2_interface_vlan_tag_rewrite(sub_if_on_pg3.sw_if_index, L2_VTR_OP.L2_POP_1, 93) # # Disable UU flooding, learning and ARP terminaation. makes this test # easier as unicast packets are dropped if not extracted. # self.vapi.bridge_flags(1, 0, (1 << 0) | (1 << 3) | (1 << 4)) # # Add a DVR route to steer traffic at L3 # route_1 = VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", self.pg1.sw_if_index, is_dvr=1)]) route_2 = VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", sub_if_on_pg2.sw_if_index, is_dvr=1)]) route_1.add_vpp_config() route_2.add_vpp_config() # # packets are dropped because bridge does not flood unknown unicast # self.send_and_assert_no_replies(self.pg0, pkt_no_tag) # # Enable L3 extraction on pgs # self.vapi.l2_emulation(self.pg0.sw_if_index) self.vapi.l2_emulation(self.pg1.sw_if_index) self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index) self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index) # # now we expect the packet forward according to the DVR route # rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) rx = self.send_and_expect(self.pg0, pkt_to_tag * 65, self.pg2) self.assert_same_mac_addr(pkt_to_tag, rx) self.assert_has_vlan_tag(92, rx) rx = self.send_and_expect(self.pg3, pkt_from_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_from_tag, rx) self.assert_has_no_tag(rx) rx = self.send_and_expect(self.pg3, pkt_from_to_tag * 65, self.pg2) self.assert_same_mac_addr(pkt_from_tag, rx) self.assert_has_vlan_tag(92, rx) # # but broadcast packets are still flooded # self.send_and_expect(self.pg0, pkt_bcast * 33, self.pg2) # # cleanup # self.vapi.l2_emulation(self.pg0.sw_if_index, enable=0) self.vapi.l2_emulation(self.pg1.sw_if_index, enable=0) self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index, enable=0) self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index, enable=0) self.vapi.sw_interface_set_l2_bridge(self.pg0.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg2.sw_if_index, 1, enable=0) self.vapi.sw_interface_set_l2_bridge(sub_if_on_pg3.sw_if_index, 1, enable=0) route_1.remove_vpp_config() route_2.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def test_map_t(self): """ MAP-T """ # # Add a domain that maps from pg0 to pg1 # map_dst = '2001:db8::/32' map_src = '1234:5678:90ab:cdef::/64' ip4_pfx = '192.168.0.0/24' self.vapi.map_add_domain(map_dst, ip4_pfx, map_src, 16, 6, 4, mtu=1500) # Enable MAP-T on interfaces. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1) self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4*1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6*1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) map_route = VppIpRoute(self, "2001:db8::", 32, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) map_route.add_vpp_config() # # Send a v4 packet that will be translated # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 rx = self.send_and_expect(self.pg0, p4*1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 rx = self.send_and_expect(self.pg1, p6*1, self.pg0) for p in rx: self.validate(p[1], p4_translated) # IPv4 TTL ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = (IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / ICMP(type='time-exceeded', code='ttl-zero-during-transit') / IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload) rx = self.send_and_expect(self.pg0, p4*1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' This one is broken, cause it would require hairpinning... # IPv4 TTL TTL1 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=1) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / \ ICMP(type='time-exceeded', code='ttl-zero-during-transit' ) / \ IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload rx = self.send_and_expect(self.pg0, p4*1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' # IPv6 Hop limit ip6_hlim_expired = IPv6(hlim=0, src='2001:db8:1ab::c0a8:1:ab', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / ip6_hlim_expired / payload) icmp6_reply = (IPv6(hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab") / ICMPv6TimeExceeded(code=0) / IPv6(src="2001:db8:1ab::c0a8:1:ab", dst='1234:5678:90ab:cdef:ac:1001:200:0', hlim=0) / payload) rx = self.send_and_expect(self.pg1, p6*1, self.pg1) for p in rx: self.validate(p[1], icmp6_reply) # IPv4 Well-known port p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = UDP(sport=200, dport=200) p4 = (p_ether / p_ip4 / payload) self.send_and_assert_no_replies(self.pg0, p4*1) # IPv6 Well-known port payload = UDP(sport=200, dport=200) p6 = (p_ether6 / p_ip6 / payload) self.send_and_assert_no_replies(self.pg1, p6*1) # Packet fragmentation payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # TODO: Manual validation # self.validate(p[1], icmp4_reply) # Packet fragmentation send fragments payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) frags = fragment(p4, fragsize=1000) self.pg_enable_capture() self.pg0.add_stream(frags) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # p.show2() # reass_pkt = reassemble(rx) # p4_reply.ttl -= 1 # p4_reply.id = 256 # self.validate(reass_pkt, p4_reply) # TCP MSS clamping self.vapi.map_param_set_tcp(1300) # # Send a v4 TCP SYN packet that will be translated and MSS clamped # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd, flags="S", options=[('MSS', 1460)]) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 p6_translated[TCP].options = [('MSS', 1300)] rx = self.send_and_expect(self.pg0, p4*1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 p4_translated[TCP].options = [('MSS', 1300)] rx = self.send_and_expect(self.pg1, p6*1, self.pg0) for p in rx: self.validate(p[1], p4_translated)
def test_gre(self): """ GRE IPv4 tunnel Tests """ # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2") gre_if.add_vpp_config() # # The double create (create the same tunnel twice) should fail, # and we should still be able to use the original # try: gre_if.add_vpp_config() except Exception: pass else: self.fail("Double GRE tunnel add does not fail") gre_if.admin_up() gre_if.config_ip4() route_via_tun = VppIpRoute( self, "4.4.4.4", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - they are all dropped since the tunnel's destintation IP # is unresolved - or resolves via the default route - which # which is a drop. # tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4") self.send_and_assert_no_replies(self.pg0, tx) # # Add a route that resolves the tunnel's destination # route_tun_dst = VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - packets are GRE encapped # tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4") rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_tunneled_4o4(self.pg0, rx, tx, self.pg0.local_ip4, "1.1.1.2") # # Send tunneled packets that match the created tunnel and # are decapped and forwarded # tx = self.create_tunnel_stream_4o4(self.pg0, "1.1.1.2", self.pg0.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_decapped_4o4(self.pg0, rx, tx) # # Send tunneled packets that do not match the tunnel's src # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg0, "1.1.1.3", self.pg0.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) self.send_and_assert_no_replies( self.pg0, tx, remark="GRE packets forwarded despite no SRC address match") # # Configure IPv6 on the PG interface so we can route IPv6 # packets # self.pg0.config_ip6() self.pg0.resolve_ndp() # # Send IPv6 tunnel encapslated packets # - dropped since IPv6 is not enabled on the tunnel # tx = self.create_tunnel_stream_6o4(self.pg0, "1.1.1.2", self.pg0.local_ip4, self.pg0.local_ip6, self.pg0.remote_ip6) self.send_and_assert_no_replies( self.pg0, tx, "IPv6 GRE packets forwarded " "despite IPv6 not enabled on tunnel") # # Enable IPv6 on the tunnel # gre_if.config_ip6() # # Send IPv6 tunnel encapslated packets # - forwarded since IPv6 is enabled on the tunnel # tx = self.create_tunnel_stream_6o4(self.pg0, "1.1.1.2", self.pg0.local_ip4, self.pg0.local_ip6, self.pg0.remote_ip6) rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_decapped_6o4(self.pg0, rx, tx) # # Send v6 packets for v4 encap # route6_via_tun = VppIpRoute(self, "2001::1", 128, [ VppRoutePath( "::", gre_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) route6_via_tun.add_vpp_config() tx = self.create_stream_ip6(self.pg0, "2001::2", "2001::1") rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_tunneled_6o4(self.pg0, rx, tx, self.pg0.local_ip4, "1.1.1.2") # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() route6_via_tun.remove_vpp_config() gre_if.remove_vpp_config() self.pg0.unconfig_ip6()
def test_bier_load_balance(self): """BIER load-balance""" # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_64) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() # # packets with varying entropy # pkts = [] for ii in range(257): pkts.append((Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_64, entropy=ii, BitString=scapy.compat.chb(255)*16) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) / UDP(sport=1234, dport=1234) / Raw())) # # 4 next hops # nhs = [{'ip': "10.0.0.1", 'label': 201}, {'ip': "10.0.0.2", 'label': 202}, {'ip': "10.0.0.3", 'label': 203}, {'ip': "10.0.0.4", 'label': 204}] for nh in nhs: ipr = VppIpRoute( self, nh['ip'], 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(nh['label'])])]) ipr.add_vpp_config() bier_route = VppBierRoute( self, bti, 1, [VppRoutePath(nhs[0]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[1]['ip'], 0xffffffff, labels=[VppMplsLabel(101)])]) bier_route.add_vpp_config() rx = self.send_and_expect(self.pg0, pkts, self.pg1) # # we should have recieved a packet from each neighbor # for nh in nhs[:2]: self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) # # add the other paths # bier_route.update_paths( [VppRoutePath(nhs[0]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[1]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[2]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[3]['ip'], 0xffffffff, labels=[VppMplsLabel(101)])]) rx = self.send_and_expect(self.pg0, pkts, self.pg1) for nh in nhs: self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) # # remove first two paths # bier_route.remove_path(VppRoutePath(nhs[0]['ip'], 0xffffffff, labels=[VppMplsLabel(101)])) bier_route.remove_path(VppRoutePath(nhs[1]['ip'], 0xffffffff, labels=[VppMplsLabel(101)])) rx = self.send_and_expect(self.pg0, pkts, self.pg1) for nh in nhs[2:]: self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) # # remove the last of the paths, deleteing the entry # bier_route.remove_all_paths() self.send_and_assert_no_replies(self.pg0, pkts)
def test_gre6(self): """ GRE IPv6 tunnel Tests """ self.pg1.config_ip6() self.pg1.resolve_ndp() # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Address # - Add a route via the tunnel # gre_if = VppGreInterface(self, self.pg2.local_ip6, "1002::1") gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip6() route_via_tun = VppIpRoute(self, "4004::1", 128, [VppRoutePath("0::0", gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - they are all dropped since the tunnel's destintation IP # is unresolved - or resolves via the default route - which # which is a drop. # tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1") self.send_and_assert_no_replies( self.pg2, tx, "GRE packets forwarded without DIP resolved") # # Add a route that resolves the tunnel's destination # route_tun_dst = VppIpRoute( self, "1002::1", 128, [VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index)]) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - packets are GRE encapped # tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1") rx = self.send_and_expect(self.pg2, tx, self.pg2) self.verify_tunneled_6o6(self.pg2, rx, tx, self.pg2.local_ip6, "1002::1") # # Test decap. decapped packets go out pg1 # tx = self.create_tunnel_stream_6o6(self.pg2, "1002::1", self.pg2.local_ip6, "2001::1", self.pg1.remote_ip6) rx = self.send_and_expect(self.pg2, tx, self.pg1) # # RX'd packet is UDP over IPv6, test the GRE header is gone. # self.assertFalse(rx[0].haslayer(GRE)) self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6) # # Send v4 over v6 # route4_via_tun = VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route4_via_tun.add_vpp_config() tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "1.1.1.1") rx = self.send_and_expect(self.pg0, tx, self.pg2) self.verify_tunneled_4o6(self.pg0, rx, tx, self.pg2.local_ip6, "1002::1") # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() route4_via_tun.remove_vpp_config() gre_if.remove_vpp_config() self.pg2.unconfig_ip6() self.pg1.unconfig_ip6()
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, 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=udp_encap.id)]) 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, scapy.compat.chb(0xff) * 32) bi.add_vpp_config() bi2 = VppBierImp(self, bti, 334, scapy.compat.chb(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, BIERLength.BIER_LEN_256) 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_gre_vrf(self): """ GRE tunnel VRF Tests """ e = VppEnum.vl_api_tunnel_encap_decap_flags_t # # Create an L3 GRE tunnel whose destination is in the non-default # table. The underlay is thus non-default - the overlay is still # the default. # - set it admin up # - assign an IP Addres # gre_if = VppGreInterface( self, self.pg1.local_ip4, "2.2.2.2", outer_table_id=1, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() # # Add a route via the tunnel - in the overlay # route_via_tun = VppIpRoute( self, "9.9.9.9", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Add a route that resolves the tunnel's destination - in the # underlay table # route_tun_dst = VppIpRoute( self, "2.2.2.2", 32, table_id=1, paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # packets are sent in on pg0 which is in the default table # - packets are GRE encapped # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9", dscp=5, ecn=3) rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4, "2.2.2.2", dscp=5, ecn=3) # # Send tunneled packets that match the created tunnel and # are decapped and forwarded. This tests the decap lookup # does not happen in the encap table # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_decapped_4o4(self.pg0, rx, tx) # # Send tunneled packets that match the created tunnel # but arrive on an interface that is not in the tunnel's # encap VRF, these are dropped. # IP enable the interface so they aren't dropped due to # IP not being enabled. # self.pg2.config_ip4() self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg2, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_assert_no_replies(self.pg2, tx, "GRE decap packets in wrong VRF") self.pg2.unconfig_ip4() # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()