def test_ip_sub_nets(self): """ IP Sub Nets """ # # Configure a covering route to forward so we know # when we are dropping # cover_route = VppIpRoute( self, "10.0.0.0", 8, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) cover_route.add_vpp_config() p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.10.10", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Configure some non-/24 subnets on an IP interface # ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10") self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 16) pn = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.0.0", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pb = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.255.255", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg1, pn, "IP Network address") self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address") # remove the sub-net and we are forwarding via the cover again self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 16, is_add=0) self.pg1.add_stream(pn) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.pg1.add_stream(pb) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # A /31 is a special case where the 'other-side' is an attached host # packets to that peer generate ARP requests # ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10") self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 31) pn = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(dst="10.10.10.11", src=self.pg0.local_ip4) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.pg1.add_stream(pn) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx[ARP] # remove the sub-net and we are forwarding via the cover again self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index, ip_addr_n, 31, is_add=0) self.pg1.add_stream(pn) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1)
def test_PPPoE_Encap_Multiple(self): """ PPPoE Encap Multiple Sessions 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 1 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 1 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 1 pppoe_if1 = VppPppoeInterface(self, self.pg0.remote_ip4, self.pg0.remote_mac, self.session_id) pppoe_if1.add_vpp_config() # Send PPPoE Discovery 2 tx3 = self.create_stream_pppoe_discovery(self.pg2, self.pg1, self.pg2.remote_mac) self.pg2.add_stream(tx3) self.pg_start() # Send PPPoE PPP LCP 2 tx4 = self.create_stream_pppoe_lcp(self.pg2, self.pg1, self.pg2.remote_mac, self.session_id + 1) self.pg2.add_stream(tx4) self.pg_start() # Create PPPoE session 2 pppoe_if2 = VppPppoeInterface(self, self.pg2.remote_ip4, self.pg2.remote_mac, self.session_id + 1) pppoe_if2.add_vpp_config() # # Send a packet stream that is routed into the session # - packets are PPPoE encapped # self.vapi.cli("clear trace") tx2 = self.create_stream_ip4(self.pg1, self.pg0, self.pg0.remote_ip4, self.dst_ip) self.pg1.add_stream(tx2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx2 = self.pg0.get_capture(len(tx2)) self.verify_encaped_pppoe(self.pg1, rx2, tx2, self.session_id) tx5 = self.create_stream_ip4(self.pg1, self.pg2, self.pg2.remote_ip4, self.dst_ip) self.pg1.add_stream(tx5) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx5 = self.pg2.get_capture(len(tx5)) self.verify_encaped_pppoe(self.pg1, rx5, tx5, self.session_id + 1) self.logger.info(self.vapi.cli("show pppoe fib")) self.logger.info(self.vapi.cli("show pppoe session")) self.logger.info(self.vapi.cli("show ip fib")) # # test case cleanup # # Delete PPPoE session pppoe_if1.remove_vpp_config() pppoe_if2.remove_vpp_config() # Delete a route that resolves the server's destination route_sever_dst.remove_vpp_config()
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_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_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, is_ip6=1)], 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, is_ip6=1)], 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, 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[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_punt(self): """ Exception Path testing """ # # dump the punt registered reasons # search for a few we know should be there # rs = self.vapi.punt_reason_dump() reasons = [ "ipsec6-no-such-tunnel", "ipsec4-no-such-tunnel", "ipsec4-spi-o-udp-0" ] for reason in reasons: found = False for r in rs: if r.reason.name == reason: found = True break self.assertTrue(found) # # Using the test CLI we will hook in a exception path to # send ACL deny packets out of pg0 and pg1. # the ACL is src,dst = 1.1.1.1,1.1.1.2 # ip_1_1_1_2 = VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) ip_1_1_1_2.add_vpp_config() ip_1_2 = VppIpRoute(self, "1::2", 128, [ VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) ip_1_2.add_vpp_config() p4 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) p6 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src="1::1", dst="1::2") / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) self.send_and_expect(self.pg2, p4 * 1, self.pg3) self.send_and_expect(self.pg2, p6 * 1, self.pg3) # # apply the punting features # self.vapi.cli("test punt pg2") # # dump the punt reasons to learn the IDs assigned # rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"}) r4 = rs[0].reason.id rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"}) r6 = rs[0].reason.id # # pkts now dropped # self.send_and_assert_no_replies(self.pg2, p4 * NUM_PKTS) self.send_and_assert_no_replies(self.pg2, p6 * NUM_PKTS) # # Check state: # 1 - node error counters # 2 - per-reason counters # 2, 3 are the index of the assigned punt reason # stats = self.statistics.get_err_counter( "/err/punt-dispatch/No registrations") self.assertEqual(stats, 2 * NUM_PKTS) stats = self.statistics.get_counter("/net/punt") self.assertEqual(stats[0][r4]['packets'], NUM_PKTS) self.assertEqual(stats[0][r6]['packets'], NUM_PKTS) # # use the test CLI to test a client that punts exception # packets out of pg0 # self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4) self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6) rx4s = self.send_and_expect(self.pg2, p4 * NUM_PKTS, self.pg0) rx6s = self.send_and_expect(self.pg2, p6 * NUM_PKTS, self.pg0) # # check the packets come out IP unmodified but destined to pg0 host # for rx in rx4s: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p4[IP].dst, rx[IP].dst) self.assertEqual(p4[IP].ttl, rx[IP].ttl) for rx in rx6s: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p6[IPv6].dst, rx[IPv6].dst) self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim) stats = self.statistics.get_counter("/net/punt") self.assertEqual(stats[0][r4]['packets'], 2 * NUM_PKTS) self.assertEqual(stats[0][r6]['packets'], 2 * NUM_PKTS) # # add another registration for the same reason to send packets # out of pg1 # self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4) self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6) self.vapi.cli("clear trace") self.pg2.add_stream(p4 * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = self.pg0.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p4[IP].dst, rx[IP].dst) self.assertEqual(p4[IP].ttl, rx[IP].ttl) rxd = self.pg1.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(p4[IP].dst, rx[IP].dst) self.assertEqual(p4[IP].ttl, rx[IP].ttl) self.vapi.cli("clear trace") self.pg2.add_stream(p6 * NUM_PKTS) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = self.pg0.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(p6[IPv6].dst, rx[IPv6].dst) self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim) rxd = self.pg1.get_capture(NUM_PKTS) for rx in rxd: self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(p6[IPv6].dst, rx[IPv6].dst) self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim) stats = self.statistics.get_counter("/net/punt") self.assertEqual(stats[0][r4]['packets'], 3 * NUM_PKTS) self.assertEqual(stats[0][r6]['packets'], 3 * NUM_PKTS) self.logger.info(self.vapi.cli("show vlib graph punt-dispatch")) self.logger.info(self.vapi.cli("show punt client")) self.logger.info(self.vapi.cli("show punt reason")) self.logger.info(self.vapi.cli("show punt stats")) self.logger.info(self.vapi.cli("show punt db"))
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 = VppGre6Interface(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, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_via_tun.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - they are all dropped since the tunnel's desintation 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.pg2.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg2.assert_nothing_captured( remark="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, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - packets are GRE encapped # self.vapi.cli("clear trace") tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1") self.pg2.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(len(tx)) 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) self.vapi.cli("clear trace") self.pg2.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(len(tx)) # # 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) # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config() self.pg2.unconfig_ip6() self.pg1.unconfig_ip6()
def test_map_t_pre_resolve(self): """ MAP-T pre-resolve""" # 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' tag = 'MAP-T Test Domain.' self.vapi.map_add_domain(ip6_prefix=map_dst, ip4_prefix=ip4_pfx, ip6_src=map_src, ea_bits_len=16, psid_offset=6, psid_length=4, mtu=1500, tag=tag) # 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) # Enable pre-resolve option self.vapi.map_param_add_del_pre_resolve(ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=1) # Add a route to 4001::1 and expect the translated traffic to be # sent via that route next-hop. pre_res_route6 = VppIpRoute( self, "4001::1", 128, [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)]) pre_res_route6.add_vpp_config() # Add a route to 10.1.2.3 and expect the "untranslated" traffic to be # sent via that route next-hop. pre_res_route4 = VppIpRoute( self, "10.1.2.3", 32, [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)]) pre_res_route4.add_vpp_config() # Send an IPv4 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.assertEqual(p[Ether].dst, self.pg1.remote_hosts[2].mac) 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.assertEqual(p[Ether].dst, self.pg0.remote_hosts[1].mac) self.validate(p[1], p4_translated) # Cleanup pre-resolve option self.vapi.map_param_add_del_pre_resolve(ip4_nh_address="10.1.2.3", ip6_nh_address="4001::1", is_add=0)
def test_abf4(self): """ IPv4 ACL Based Forwarding """ # # We are not testing the various matching capabilities # of ACLs, that's done elsewhere. Here ware are testing # the application of ACLs to a forwarding path to achieve # ABF # So we construct just a few ACLs to ensure the ABF policies # are correctly constructed and used. And a few path types # to test the API path decoding. # # # Rule 1 # rule_1 = ({ 'is_permit': 1, '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, "1.1.1.1"), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 32, 'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2") }) 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(self.pg1.remote_ip4, self.pg1.sw_if_index)]) abf_1.add_vpp_config() # # Attach the policy to input interface Pg0 # attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50) attach_1.add_vpp_config() # # fire in packet matching the ACL src,dst. If it's forwarded # then the ABF was successful, since default routing will drop it # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg0, p_1 * 65, self.pg1) # # Attach a 'better' priority policy to the same interface # abf_2 = VppAbfPolicy( self, 11, acl_1, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)]) abf_2.add_vpp_config() attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40) attach_2.add_vpp_config() self.send_and_expect(self.pg0, p_1 * 65, self.pg2) # # Attach a policy with priority in the middle # abf_3 = VppAbfPolicy( self, 12, acl_1, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) abf_3.add_vpp_config() attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45) attach_3.add_vpp_config() self.send_and_expect(self.pg0, p_1 * 65, self.pg2) # # remove the best priority # attach_2.remove_vpp_config() self.send_and_expect(self.pg0, p_1 * 65, self.pg3) # # Attach one of the same policies to Pg1 # attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45) attach_4.add_vpp_config() p_2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect(self.pg1, p_2 * 65, self.pg3) # # detach the policy from PG1, now expect traffic to be dropped # attach_4.remove_vpp_config() self.send_and_assert_no_replies(self.pg1, p_2 * 65, "Detached") # # Swap to route via a next-hop in the non-default table # table_20 = VppIpTable(self, 20) table_20.add_vpp_config() self.pg4.set_table_ip4(table_20.table_id) self.pg4.admin_up() self.pg4.config_ip4() self.pg4.resolve_arp() abf_13 = VppAbfPolicy(self, 13, acl_1, [ VppRoutePath( self.pg4.remote_ip4, 0xffffffff, nh_table_id=table_20.table_id) ]) abf_13.add_vpp_config() attach_5 = VppAbfAttach(self, 13, self.pg0.sw_if_index, 30) attach_5.add_vpp_config() self.send_and_expect(self.pg0, p_1 * 65, self.pg4) self.pg4.unconfig_ip4() self.pg4.set_table_ip4(0)
def test_map_e_tcp_mss(self): """ MAP-E TCP MSS""" # # 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:5000:0:c0a8:101:5' tag = 'MAP-E TCP 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) # Enable MAP on pg0 interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Enable MAP on pg1 interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0) # TCP MSS clamping mss_clamp = 1300 self.vapi.map_param_set_tcp(mss_clamp) # # Send a v4 packet that will be encapped. # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.1.1') p_tcp = TCP(sport=20000, dport=30000, flags="S", options=[("MSS", 1455)]) p4 = p_ether / p_ip4 / p_tcp self.pg1.add_stream(p4) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.assertTrue(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p4[IP].src) self.assertEqual(rx[IP].dst, p4[IP].dst) self.assertEqual(rx[IPv6].src, "3000::1") self.assertEqual(rx[TCP].options, TCP(options=[('MSS', mss_clamp)]).options)
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' tag = 'MAP-T Tag.' self.vapi.map_add_domain(ip6_prefix=map_dst, ip4_prefix=ip4_pfx, ip6_src=map_src, ea_bits_len=16, psid_offset=6, psid_length=4, mtu=1500, tag=tag) # 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(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) # 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) map_route = VppIpRoute(self, "2001:db8::", 32, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) 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=0 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) # IPv4 TTL=1 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=1) / 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) # UDP packet fragmentation payload_len = 1453 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len) p4 = (p_ether / p_ip4 / payload) self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) p_ip6_translated = IPv6(src='1234:5678:90ab:cdef:ac:1001:200:0', dst='2001:db8:1e0::c0a8:1:e') for p in rx: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, UDP, payload_len) # UDP packet fragmentation send fragments payload_len = 1453 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len) p4 = (p_ether / p_ip4 / payload) frags = fragment_rfc791(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: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, UDP, payload_len) # Send back an fragmented IPv6 UDP packet that will be "untranslated" payload = UDP(sport=4000, dport=40000) / self.payload(payload_len) p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1e0::c0a8:1:e', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) frags6 = fragment_rfc8200(p6, identification=0xdcba, fragsize=1000) p_ip4_translated = IP(src='192.168.0.1', dst=self.pg0.remote_ip4) p4_translated = (p_ip4_translated / payload) p4_translated.id = 0 p4_translated.ttl -= 1 self.pg_enable_capture() self.pg1.add_stream(frags6) self.pg_start() rx = self.pg0.get_capture(2) for p in rx: self.validate_frag4(p, p4_translated) self.validate_frag_payload_len4(rx, UDP, payload_len) # ICMP packet fragmentation payload = ICMP(id=6529) / self.payload(payload_len) p4 = (p_ether / p_ip4 / payload) self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) p_ip6_translated = IPv6(src='1234:5678:90ab:cdef:ac:1001:200:0', dst='2001:db8:160::c0a8:1:6') for p in rx: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len) # ICMP packet fragmentation send fragments payload = ICMP(id=6529) / self.payload(payload_len) p4 = (p_ether / p_ip4 / payload) frags = fragment_rfc791(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: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len) # 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) # TCP MSS clamping cleanup self.vapi.map_param_set_tcp(0) # Enable icmp6 param to get back ICMPv6 unreachable messages in case # of security check fails self.vapi.map_param_set_icmp6(enable_unreachable=1) # Send back an IPv6 packet that will be droppped due to security # check fail p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6_sec_check_fail = IPv6(src='2001:db8:1fe::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') payload = TCP(sport=0xabcd, dport=0xabcd) p6 = (p_ether6 / p_ip6_sec_check_fail / payload) self.pg_send(self.pg1, p6 * 1) self.pg0.get_capture(0, timeout=1) rx = self.pg1.get_capture(1) icmp6_reply = (IPv6( hlim=255, src=self.pg1.local_ip6, dst='2001:db8:1fe::c0a8:1:f') / ICMPv6DestUnreach(code=5) / p_ip6_sec_check_fail / payload) for p in rx: self.validate(p[1], icmp6_reply) # ICMPv6 unreachable messages cleanup self.vapi.map_param_set_icmp6(enable_unreachable=0)
def test_map_e_inner_frag(self): """ MAP-E Inner fragmentation """ # # 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, mtu=1000, tag=tag) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Enable inner fragmentation self.vapi.map_param_set_fragmentation(inner=1) 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' * 1300)) self.pg_send(self.pg0, v4 * 1) rx = self.pg1.get_capture(2) frags = fragment_rfc791(v4[1], 1000) frags[0].id = 0 frags[1].id = 0 frags[0].ttl -= 1 frags[1].ttl -= 1 frags[0].chksum = 0 frags[1].chksum = 0 v6_reply1 = (IPv6(src='3000::1', dst=map_translated_addr, hlim=63) / frags[0]) v6_reply2 = (IPv6(src='3000::1', dst=map_translated_addr, hlim=63) / frags[1]) rx[0][1].fl = 0 rx[1][1].fl = 0 rx[0][1][IP].id = 0 rx[1][1][IP].id = 0 rx[0][1][IP].chksum = 0 rx[1][1][IP].chksum = 0 self.validate(rx[0][1], v6_reply1) self.validate(rx[1][1], v6_reply2)
def test_map_e_udp(self): """ MAP-E UDP""" # # 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 * 4, 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(v4 * 4, "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_ip_load_balance(self): """ IP Load-Balancing """ # # An array of packets that differ only in the destination port # port_ip_pkts = [] port_mpls_pkts = [] # # An array of packets that differ only in the source address # src_ip_pkts = [] src_mpls_pkts = [] for ii in range(65): port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") / UDP(sport=1234, dport=1234 + ii) / Raw('\xa5' * 100)) port_ip_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)) port_mpls_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=66, ttl=2) / port_ip_hdr)) src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) src_ip_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)) src_mpls_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=66, ttl=2) / src_ip_hdr)) route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index), VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index) ]) route_10_0_0_1.add_vpp_config() binding = VppMplsIpBind(self, 66, "10.0.0.1", 32) binding.add_vpp_config() # # inject the packet on pg0 - expect load-balancing across the 2 paths # - since the default hash config is to use IP src,dst and port # src,dst # We are not going to ensure equal amounts of packets across each link, # since the hash algorithm is statistical and therefore this can never # be guaranteed. But wuth 64 different packets we do expect some # balancing. So instead just ensure there is traffic on each link. # self.send_and_expect_load_balancing(self.pg0, port_ip_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts, [self.pg1, self.pg2]) # # change the flow hash config so it's only IP src,dst # - now only the stream with differing source address will # load-balance # self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0) self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2]) self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts, [self.pg1, self.pg2]) self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2) # # change the flow hash config back to defaults # self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1) # # Recursive prefixes # - testing that 2 stages of load-balancing occurs and there is no # polarisation (i.e. only 2 of 4 paths are used) # port_pkts = [] src_pkts = [] for ii in range(257): port_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(dst="1.1.1.1", src="20.0.0.1") / UDP(sport=1234, dport=1234 + ii) / Raw('\xa5' * 100))) src_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(dst="1.1.1.1", src="20.0.0.%d" % ii) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))) route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32, [ VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index), VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index) ]) route_10_0_0_2.add_vpp_config() route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32, [ VppRoutePath("10.0.0.2", 0xffffffff), VppRoutePath("10.0.0.1", 0xffffffff) ]) route_1_1_1_1.add_vpp_config() # # inject the packet on pg0 - expect load-balancing across all 4 paths # self.vapi.cli("clear trace") self.send_and_expect_load_balancing( self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]) self.send_and_expect_load_balancing( self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]) # # Recursive prefixes # - testing that 2 stages of load-balancing, no choices # port_pkts = [] for ii in range(257): port_pkts.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(dst="1.1.1.2", src="20.0.0.2") / UDP(sport=1234, dport=1234 + ii) / Raw('\xa5' * 100))) route_10_0_0_3 = VppIpRoute( self, "10.0.0.3", 32, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]) route_10_0_0_3.add_vpp_config() route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath("10.0.0.3", 0xffffffff)]) route_1_1_1_2.add_vpp_config() # # inject the packet on pg0 - expect load-balancing across all 4 paths # self.vapi.cli("clear trace") self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
def test_map_t(self): """ MAP-T """ # # Add a domain that maps from pg0 to pg1 # self.vapi.map_add_domain('2001:db8::/32', '1234:5678:90ab:cdef::/64', '192.168.0.0/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_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 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)]) 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_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, bvi=1) self.vapi.sw_interface_set_l2_tag_rewrite(sub_if_on_pg2.sw_if_index, L2_VTR_OP.L2_POP_1, 92) self.vapi.sw_interface_set_l2_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, proto=DpoProto.DPO_PROTO_ETHERNET) ]) 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. # self.pg0.add_stream(pkt_no_tag) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.assertEqual(rx[0][Ether].dst, pkt_no_tag[Ether].dst) self.assertEqual(rx[0][Ether].src, pkt_no_tag[Ether].src) # # 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, proto=DpoProto.DPO_PROTO_ETHERNET) ]) route_with_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_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) # # cleanup # 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, bvi=1, enable=0) # # 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_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", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP, next_hop_id=udp_encap_0.id)]) 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.pg0.remote_mac, dst=self.pg0.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.pg0, 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_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(b'\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(b'\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(b'\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(b'\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(b'\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, type=FibPathType.FIB_PATH_TYPE_DVR) ]) route_2 = VppIpRoute(self, "1.1.1.2", 32, [ VppRoutePath("0.0.0.0", sub_if_on_pg2.sw_if_index, type=FibPathType.FIB_PATH_TYPE_DVR) ]) 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 * NUM_PKTS, 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 * NUM_PKTS, 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 * NUM_PKTS, 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 * NUM_PKTS, 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_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) # # Send tunneled packets that match the created tunnel and # but arrive on an interface that is not in the tunnel's # encap VRF, these are dropped # 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) self.pg1.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.assert_nothing_captured( remark="GRE decap packets in wrong VRF") # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()
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(b'\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(b'\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, type=FibPathType.FIB_PATH_TYPE_DVR) ]) 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 * NUM_PKTS, 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, type=FibPathType.FIB_PATH_TYPE_DVR) ]) 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 * NUM_PKTS, 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(b'\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * NUM_PKTS, 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(b'\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * NUM_PKTS, 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 = AclRule(is_permit=0, proto=17, ports=1234, src_prefix=IPv4Network((any_src_addr, 32)), dst_prefix=IPv4Network((ip_non_tag_bridged, 32))) acl = VppAcl(self, rules=[rule_1]) acl.add_vpp_config() # # Apply the ACL on the output interface # acl_if1 = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index, n_input=0, acls=[acl]) acl_if1.add_vpp_config() # # 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 * NUM_PKTS) # # cleanup # acl_if1.remove_vpp_config() acl.remove_vpp_config() 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_route_dump(0) for r in routes: if (ip_tag_bridged == str(r.route.prefix.network_address)): self.assertEqual(r.route.paths[0].sw_if_index, sub_if_on_pg3.sw_if_index) self.assertEqual(r.route.paths[0].type, FibPathType.FIB_PATH_TYPE_DVR) if (ip_non_tag_bridged == str(r.route.prefix.network_address)): self.assertEqual(r.route.paths[0].sw_if_index, self.pg1.sw_if_index) self.assertEqual(r.route.paths[0].type, FibPathType.FIB_PATH_TYPE_DVR) # # 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_flood(self): """ L2 Flood Tests """ # # Create a single bridge Domain # self.vapi.bridge_domain_add_del(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(i.sw_if_index, 1, 0) for i in self.pg_interfaces[4:8]: self.vapi.sw_interface_set_l2_bridge(i.sw_if_index, 1, 1) for i in self.pg_interfaces[8:12]: self.vapi.sw_interface_set_l2_bridge(i.sw_if_index, 1, 2) for i in self.lo_interfaces: self.vapi.sw_interface_set_l2_bridge(i.sw_if_index, 1, 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(i.sw_if_index, 1, enable=0) for i in self.lo_interfaces: self.vapi.sw_interface_set_l2_bridge(i.sw_if_index, 1, 2, port_type=L2_PORT_TYPE.BVI, enable=0) self.vapi.bridge_domain_add_del(1, is_add=0)
def test_ipip4(self): """ ip{v4,v6} over ip4 test """ self.pg1.generate_remote_hosts(5) self.pg1.configure_ipv4_neighbors() e = VppEnum.vl_api_tunnel_encap_decap_flags_t d = VppEnum.vl_api_ip_dscp_t self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100) # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits # are for the ECN. dscp = d.IP_API_DSCP_AF31 << 2 ecn = 3 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn # IPv4 transport that copies the DCSP from the payload tun_dscp = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[0].ip4, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) tun_dscp.add_vpp_config() # IPv4 transport that copies the DCSP and ECN from the payload tun_dscp_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[1].ip4, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) tun_dscp_ecn.add_vpp_config() # IPv4 transport that copies the ECN from the payload and sets the # DF bit on encap. copies the ECN on decap tun_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[2].ip4, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) tun_ecn.add_vpp_config() # IPv4 transport that sets a fixed DSCP in the encap and copies # the DF bit tun = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[3].ip4, dscp=d.IP_API_DSCP_AF11, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) tun.add_vpp_config() # array of all the tunnels tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun] # addresses for prefixes routed via each tunnel a4s = ["" for i in range(len(tuns))] a6s = ["" for i in range(len(tuns))] # IP headers with each combination of DSCp/ECN tested p_ip6s = [ IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff) ] p_ip4s = [ IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'), IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff) ] # Configure each tunnel for i, t in enumerate(tuns): # Set interface up and enable IP on it self.vapi.sw_interface_set_flags(t.sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=t.sw_if_index) # prefix for route / destination address for packets a4s[i] = "130.67.%d.0" % i a6s[i] = "dead:%d::" % i # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute(self, a4s[i], 24, [ VppRoutePath("0.0.0.0", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute(self, a6s[i], 64, [ VppRoutePath("::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) ip6_via_tunnel.add_vpp_config() # # Encapsulation # # tun_dscp copies only the dscp # expected TC values are thus only the DCSP value is present from the # inner exp_tcs = [dscp, dscp, 0, 0xfc] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, tos=tc) for tc in exp_tcs ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, proto='ipv6', id=0, tos=tc) for tc in exp_tcs ] # IPv4 in to IPv4 tunnel self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps) # IPv6 in to IPv4 tunnel self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps) # tun_dscp_ecn copies the dscp and the ecn exp_tcs = [dscp, dscp_ecn, ecn, 0xff] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, tos=tc) for tc in exp_tcs ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, proto='ipv6', id=0, tos=tc) for tc in exp_tcs ] self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps) self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps) # tun_ecn copies only the ecn and always sets DF exp_tcs = [0, ecn, ecn, ecn] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags='DF', tos=tc) for tc in exp_tcs ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags='DF', proto='ipv6', id=0, tos=tc) for tc in exp_tcs ] self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps) self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps) # tun sets a fixed dscp and copies DF fixed_dscp = tun.dscp << 2 flags = ['DF', 0, 0, 0] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun.dst, flags=f, tos=fixed_dscp) for f in flags ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun.dst, proto='ipv6', id=0, tos=fixed_dscp) for i in range(len(p_ip4s)) ] self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps) self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps) # # Decapsulation # n_packets_decapped = 0 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) # IPv4 tunnel to IPv4 tcs = [0, dscp, dscp_ecn, ecn] # one overlay packet and all combinations of its encap p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p_ip4_encaps = [ IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload for p_ip4_encap in p_ip4_encaps: p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4 / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # tun_ecn copies the ECN bits from the encap to the inner p_ip4_encaps = [ IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))] p_ip4_replys[2].tos = ecn p_ip4_replys[3].tos = ecn for i, p_ip4_encap in enumerate(p_ip4_encaps): p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4_replys[i] / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv4 tunnel to IPv6 # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload p_ip4_encaps = [ IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) for p_ip4_encap in p_ip4_encaps: p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6 / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv4 tunnel to IPv6 # tun_ecn copies the ECN bits from the encap to the inner p_ip4_encaps = [ IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))] p_ip6_replys[2].tc = ecn p_ip6_replys[3].tc = ecn for i, p_ip4_encap in enumerate(p_ip4_encaps): p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6_replys[i] / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # # Fragmentation / Reassembly and Re-fragmentation # rv = self.vapi.ip_reassembly_enable_disable( sw_if_index=self.pg1.sw_if_index, enable_ip4=1) self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000, max_reassembly_length=1000, expire_walk_interval_ms=10000, is_ip6=0) # Send lots of fragments, verify reassembled packet frags, p4_reply = self.generate_ip4_frags(3131, 1400) f = [] for i in range(0, 1000): f.extend(frags) self.pg1.add_stream(f) self.pg_enable_capture() self.pg_start() rx = self.pg0.get_capture(1000) n_packets_decapped += 1000 for p in rx: self.validate(p[1], p4_reply) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) f = [] r = [] for i in range(1, 90): frags, p4_reply = self.generate_ip4_frags(i * 100, 1000) f.extend(frags) r.extend(p4_reply) self.pg_enable_capture() self.pg1.add_stream(f) self.pg_start() rx = self.pg0.get_capture(89) i = 0 for p in rx: self.validate(p[1], r[i]) i += 1 # Now try with re-fragmentation # # Send fragments to tunnel head-end, for the tunnel head end # to reassemble and then refragment # self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0]) frags, p4_reply = self.generate_ip4_frags(3123, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg0.get_capture(6) reass_pkt = reassemble4(rx) p4_reply.id = 256 self.validate(reass_pkt, p4_reply) self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0]) frags, p4_reply = self.generate_ip4_frags(3123, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg0.get_capture(2) reass_pkt = reassemble4(rx) p4_reply.id = 512 self.validate(reass_pkt, p4_reply) # send large packets through the tunnel, expect them to be fragmented self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0]) p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="1.2.3.4", dst="130.67.0.1", tos=42) / UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000)) rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30) inners = [] for p in rx: inners.append(p[IP].payload) reass_pkt = reassemble4(inners) for p in reass_pkt: self.assert_packet_checksums_valid(p) self.assertEqual(p[IP].ttl, 63)
def test_PPPoE_Decap(self): """ PPPoE Decap 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() # # Send tunneled packets that match the created tunnel and # are decapped and forwarded # tx2 = self.create_stream_pppoe_ip4(self.pg0, self.pg1, self.pg0.remote_mac, self.session_id, self.pg0.remote_ip4) self.pg0.add_stream(tx2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx2 = self.pg1.get_capture(len(tx2)) self.verify_decapped_pppoe(self.pg0, rx2, tx2) self.logger.info(self.vapi.cli("show pppoe fib")) self.logger.info(self.vapi.cli("show pppoe session")) self.logger.info(self.vapi.cli("show ip fib")) # # test case cleanup # # Delete PPPoE session pppoe_if.remove_vpp_config() # Delete a route that resolves the server's destination route_sever_dst.remove_vpp_config()
def test_mipip4(self): """ p2mp IPv4 tunnel Tests """ for itf in self.pg_interfaces: # # one underlay nh for each overlay/tunnel peer # itf.generate_remote_hosts(4) itf.configure_ipv4_neighbors() # # Create an p2mo IPIP tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # ipip_if = VppIpIpTunInterface( self, itf, itf.local_ip4, "0.0.0.0", mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP)) ipip_if.add_vpp_config() ipip_if.admin_up() ipip_if.config_ip4() ipip_if.generate_remote_hosts(4) self.logger.info(self.vapi.cli("sh adj")) self.logger.info(self.vapi.cli("sh ip fib")) # # ensure we don't match to the tunnel if the source address # is all zeros # # tx = self.create_tunnel_stream_4o4(self.pg0, # "0.0.0.0", # itf.local_ip4, # self.pg0.local_ip4, # self.pg0.remote_ip4) # self.send_and_assert_no_replies(self.pg0, tx) # # for-each peer # for ii in range(1, 4): route_addr = "4.4.4.%d" % ii # # route traffic via the peer # route_via_tun = VppIpRoute(self, route_addr, 32, [ VppRoutePath(ipip_if._remote_hosts[ii].ip4, ipip_if.sw_if_index) ]) route_via_tun.add_vpp_config() # # Add a NHRP entry resolves the peer # teib = VppNhrp(self, ipip_if, ipip_if._remote_hosts[ii].ip4, itf._remote_hosts[ii].ip4) teib.add_vpp_config() self.logger.info( self.vapi.cli("sh adj nbr ipip0 %s" % ipip_if._remote_hosts[ii].ip4)) # # Send a packet stream that is routed into the tunnel # - packets are IPIP encapped # inner = (IP(dst=route_addr, src="5.5.5.5") / UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100)) tx_e = [ (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner) for x in range(63) ] rxs = self.send_and_expect(self.pg0, tx_e, itf) for rx in rxs: self.assertEqual(rx[IP].src, itf.local_ip4) self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4) tx_i = [ (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=itf._remote_hosts[ii].ip4, dst=itf.local_ip4) / IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100)) for x in range(63) ] self.logger.info(self.vapi.cli("sh ipip tunnel-hash")) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) # # delete and re-add the NHRP # teib.remove_vpp_config() self.send_and_assert_no_replies(self.pg0, tx_e) self.send_and_assert_no_replies(self.pg0, tx_i) teib.add_vpp_config() rx = self.send_and_expect(self.pg0, tx_e, itf) for rx in rxs: self.assertEqual(rx[IP].src, itf.local_ip4) self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) ipip_if.admin_down() ipip_if.unconfig_ip4()
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('\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( ':'.join(re.findall('..', record[56].encode('hex'))), self.pg8.local_mac) # dst mac self.assertEqual( ':'.join(re.findall('..', record[80].encode('hex'))), 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( '.'.join(re.findall('..', record[8].encode('hex'))), '.'.join('{:02x}'.format(int(n)) for n in self.pg7.remote_ip4.split('.'))) # dst ip self.assertEqual( '.'.join(re.findall('..', record[12].encode('hex'))), '.'.join('{:02x}'.format(int(n)) for n in "9.0.0.100".split('.'))) # 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_ipip6(self): """ ip{v4,v6} over ip6 test """ # that's annoying self.destroy_tunnel() self.pg1.generate_remote_hosts(5) self.pg1.configure_ipv6_neighbors() e = VppEnum.vl_api_tunnel_encap_decap_flags_t d = VppEnum.vl_api_ip_dscp_t self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100) # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits # are for the ECN. dscp = d.IP_API_DSCP_AF31 << 2 ecn = 3 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn # IPv4 transport that copies the DCSP from the payload tun_dscp = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[0].ip6, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) tun_dscp.add_vpp_config() # IPv4 transport that copies the DCSP and ECN from the payload tun_dscp_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[1].ip6, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) tun_dscp_ecn.add_vpp_config() # IPv4 transport that copies the ECN from the payload and sets the # DF bit on encap. copies the ECN on decap tun_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[2].ip6, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) tun_ecn.add_vpp_config() # IPv4 transport that sets a fixed DSCP in the encap and copies # the DF bit tun = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[3].ip6, dscp=d.IP_API_DSCP_AF11, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) tun.add_vpp_config() # array of all the tunnels tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun] # addresses for prefixes routed via each tunnel a4s = ["" for i in range(len(tuns))] a6s = ["" for i in range(len(tuns))] # IP headers for inner packets with each combination of DSCp/ECN tested p_ip6s = [ IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff) ] p_ip4s = [ IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'), IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff) ] # Configure each tunnel for i, t in enumerate(tuns): # Set interface up and enable IP on it self.vapi.sw_interface_set_flags(t.sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=t.sw_if_index) # prefix for route / destination address for packets a4s[i] = "130.67.%d.0" % i a6s[i] = "dead:%d::" % i # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute(self, a4s[i], 24, [ VppRoutePath("0.0.0.0", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute(self, a6s[i], 64, [ VppRoutePath("::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) ip6_via_tunnel.add_vpp_config() # # Encapsulation # # tun_dscp copies only the dscp # expected TC values are thus only the DCSP value is present from the # inner exp_tcs = [dscp, dscp, 0, 0xfc] p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun_dscp.dst, tc=tc) for tc in exp_tcs ] # IPv4 in to IPv4 tunnel self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps) # IPv6 in to IPv4 tunnel self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps) # tun_dscp_ecn copies the dscp and the ecn exp_tcs = [dscp, dscp_ecn, ecn, 0xff] p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun_dscp_ecn.dst, tc=tc) for tc in exp_tcs ] self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps) self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps) # tun_ecn copies only the ecn and always sets DF exp_tcs = [0, ecn, ecn, ecn] p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun_ecn.dst, tc=tc) for tc in exp_tcs ] self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps) self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps) # tun sets a fixed dscp fixed_dscp = tun.dscp << 2 p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun.dst, tc=fixed_dscp) for i in range(len(p_ip4s)) ] self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps) self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps) # # Decapsulation # n_packets_decapped = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) # IPv6 tunnel to IPv4 tcs = [0, dscp, dscp_ecn, ecn] # one overlay packet and all combinations of its encap p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p_ip6_encaps = [ IPv6(src=tun.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload for p_ip6_encap in p_ip6_encaps: p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4 / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # tun_ecn copies the ECN bits from the encap to the inner p_ip6_encaps = [ IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))] p_ip4_replys[2].tos = ecn p_ip4_replys[3].tos = ecn for i, p_ip6_encap in enumerate(p_ip6_encaps): p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4_replys[i] / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv6 tunnel to IPv6 # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload p_ip6_encaps = [ IPv6(src=tun.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) for p_ip6_encap in p_ip6_encaps: p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6 / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv6 tunnel to IPv6 # tun_ecn copies the ECN bits from the encap to the inner p_ip6_encaps = [ IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))] p_ip6_replys[2].tc = ecn p_ip6_replys[3].tc = ecn for i, p_ip6_encap in enumerate(p_ip6_encaps): p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6_replys[i] / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped)
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_ip_deag(self): """ IP Deag Routes """ # # Create a table to be used for: # 1 - another destination address lookup # 2 - a source address lookup # table_dst = VppIpTable(self, 1) table_src = VppIpTable(self, 2) table_dst.add_vpp_config() table_src.add_vpp_config() # # Add a route in the default table to point to a deag/ # second lookup in each of these tables # route_to_dst = VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=1)]) route_to_src = VppIpRoute(self, "1.1.1.2", 32, [ VppRoutePath( "0.0.0.0", 0xffffffff, nh_table_id=2, is_source_lookup=1) ]) route_to_dst.add_vpp_config() route_to_src.add_vpp_config() # # packets to these destination are dropped, since they'll # hit the respective default routes in the second table # p_dst = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="5.5.5.5", dst="1.1.1.1") / TCP(sport=1234, dport=1234) / Raw('\xa5' * 100)) p_src = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="2.2.2.2", dst="1.1.1.2") / TCP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkts_dst = p_dst * 257 pkts_src = p_src * 257 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table") self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table") # # add a route in the dst table to forward via pg1 # route_in_dst = VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)], table_id=1) route_in_dst.add_vpp_config() self.send_and_expect(self.pg0, pkts_dst, self.pg1) # # add a route in the src table to forward via pg2 # route_in_src = VppIpRoute( self, "2.2.2.2", 32, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)], table_id=2) route_in_src.add_vpp_config() self.send_and_expect(self.pg0, pkts_src, self.pg2)