def test_gre_loop(self): """ GRE tunnel loop Tests """ # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2") gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() # # add a route to the tunnel's destination that points # through the tunnel, hence forming a loop in the forwarding # graph # route_dst = VppIpRoute(self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_dst.add_vpp_config() # # packets to the tunnels destination should be dropped # tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "1.1.1.2") self.send_and_assert_no_replies(self.pg2, tx) self.logger.info(self.vapi.ppcli("sh adj 7")) # # break the loop # route_dst.modify([VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_dst.add_vpp_config() rx = self.send_and_expect(self.pg0, tx, self.pg1) # # a good route throught the tunnel to check it restacked # route_via_tun_2 = VppIpRoute(self, "2.2.2.2", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun_2.add_vpp_config() tx = self.create_stream_ip4(self.pg0, "2.2.2.3", "2.2.2.2") rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg0.local_ip4, "1.1.1.2") # # cleanup # route_via_tun_2.remove_vpp_config() gre_if.remove_vpp_config()
def test_gre_input_node(self): """ GRE gre input nodes not registerd unless configured """ pkt = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE()) self.pg0.add_stream(pkt) self.pg_start() # no tunnel created, gre-input not registered err = self.statistics.get_counter( '/err/ip4-local/unknown ip protocol')[0] self.assertEqual(err, 1) err_count = err # create gre tunnel gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2") gre_if.add_vpp_config() self.pg0.add_stream(pkt) self.pg_start() # tunnel created, gre-input registered err = self.statistics.get_counter( '/err/ip4-local/unknown ip protocol')[0] # expect no new errors self.assertEqual(err, err_count)
def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.pg0.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.route4 = VppIpRoute( self, self.tun_ip4, 32, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.pg0, self.pg0) payload = self.info_to_payload(info) p = (IP(id=i, src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=1234, dport=self.punt_port) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p fragments = [ x for _, p in self._packet_infos.iteritems() for x in fragment_rfc791(p.data, 400) ] encapped_fragments = \ [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.tun_ip4, dst=self.pg0.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.pg0.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.assert_nothing_captured() packets = self.punt4_socket.wait_for_packets(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config()
def test_span_l2_rx_dst_gre_subif_vtr(self): """SPAN l2 rx mirror into gre-subif+vtr""" self.sub_if.admin_up() gre_if = VppGreInterface( self, self.pg2.local_ip4, self.pg2.remote_ip4, type=(VppEnum.vl_api_gre_tunnel_type_t.GRE_API_TUNNEL_TYPE_TEB), ) gre_if.add_vpp_config() gre_if.admin_up() gre_sub_if = VppDot1QSubint(self, gre_if, 500) gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500) gre_sub_if.admin_up() self.bridge(gre_sub_if.sw_if_index) # Create bi-directional cross-connects between pg0 and pg1 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) # Create incoming packet streams for packet-generator interfaces pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes, do_dot1=True) self.pg0.add_stream(pkts) # Enable SPAN on pg0 sub if (mirrored to gre sub if) self.vapi.sw_interface_span_enable_disable(self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1) # Enable packet capturing and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() # Verify packets outgoing packet streams on mirrored interface (pg2) n_pkts = len(pkts) pg1_pkts = self.pg1.get_capture(n_pkts) pg2_pkts = self.pg2.get_capture(n_pkts) def decap(p): return self.remove_tags(self.decap_gre(p), [Tag(dot1=DOT1Q, vlan=500)]) pg2_decaped = [decap(p) for p in pg2_pkts] self.bridge(gre_sub_if.sw_if_index, is_add=0) # Disable SPAN on pg0 sub if self.vapi.sw_interface_span_enable_disable(self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1) gre_if.remove_vpp_config() self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) self.verify_capture(pg1_pkts, pg2_decaped)
def test_span_l2_rx_dst_gre_subif_vtr(self): """ SPAN l2 rx mirror into gre-subif+vtr """ self.sub_if.admin_up() gre_if = VppGreInterface(self, self.pg2.local_ip4, self.pg2.remote_ip4, is_teb=1) gre_if.add_vpp_config() gre_if.admin_up() gre_sub_if = VppDot1QSubint(self, gre_if, 500) gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500) gre_sub_if.admin_up() self.bridge(gre_sub_if.sw_if_index) # Create bi-directional cross-connects between pg0 and pg1 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) # Create incoming packet streams for packet-generator interfaces pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes, do_dot1=True) self.pg0.add_stream(pkts) self.vapi.sw_interface_span_enable_disable(self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1) # Enable packet capturing and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() # Verify packets outgoing packet streams on mirrored interface (pg2) self.logger.info("Verifying capture on interfaces %s and %s" % (self.pg1.name, self.pg2.name)) pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index) pg1_pkts = self.pg1.get_capture() pg2_pkts = self.pg2.get_capture(pg2_expected) pg2_decaped = [ self.remove_tags(self.decap_gre(p), [Tag(dot1=DOT1Q, vlan=500)]) for p in pg2_pkts ] self.verify_capture(self.pg1, pg1_pkts, pg2_decaped) self.bridge(gre_sub_if.sw_if_index, is_add=0) # Disable SPAN on pg0 sub if self.vapi.sw_interface_span_enable_disable(self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1) gre_if.remove_vpp_config() self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
def test_span_l2_rx_dst_gre_erspan(self): """ SPAN l2 rx mirror into gre-erspan """ self.sub_if.admin_up() gre_if = VppGreInterface(self, self.pg2.local_ip4, self.pg2.remote_ip4, type=2, session=543) gre_if.add_vpp_config() gre_if.admin_up() self.bridge(gre_if.sw_if_index) # Create bi-directional cross-connects between pg0 and pg1 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) # Create incoming packet streams for packet-generator interfaces pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes, do_dot1=True) self.pg0.add_stream(pkts) # Enable SPAN on pg0 sub if (mirrored to gre-erspan) self.vapi.sw_interface_span_enable_disable(self.sub_if.sw_if_index, gre_if.sw_if_index, is_l2=1) # Enable packet capturing and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() # Verify packets outgoing packet streams on mirrored interface (pg2) n_pkts = len(pkts) pg1_pkts = self.pg1.get_capture(n_pkts) pg2_pkts = self.pg2.get_capture(n_pkts) def decap(p): return self.decap_erspan(p, session=543) pg2_decaped = [decap(p) for p in pg2_pkts] self.bridge(gre_if.sw_if_index, is_add=0) # Disable SPAN on pg0 sub if self.vapi.sw_interface_span_enable_disable(self.sub_if.sw_if_index, gre_if.sw_if_index, state=0, is_l2=1) gre_if.remove_vpp_config() self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) self.verify_capture(pg1_pkts, pg2_decaped)
def setUp(self): super(TestIpsecGreTebIfEsp, self).setUp() self.tun_if = self.pg0 p = self.ipv4_params bd1 = VppBridgeDomain(self, 1) bd1.add_vpp_config() p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi, p.auth_algo_vpp_id, p.auth_key, p.crypt_algo_vpp_id, p.crypt_key, self.vpp_esp_protocol, self.pg0.local_ip4, self.pg0.remote_ip4) p.tun_sa_out.add_vpp_config() p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi, p.auth_algo_vpp_id, p.auth_key, p.crypt_algo_vpp_id, p.crypt_key, self.vpp_esp_protocol, self.pg0.remote_ip4, self.pg0.local_ip4) p.tun_sa_in.add_vpp_config() self.tun = VppGreInterface( self, self.pg0.local_ip4, self.pg0.remote_ip4, type=(VppEnum.vl_api_gre_tunnel_type_t.GRE_API_TUNNEL_TYPE_TEB)) self.tun.add_vpp_config() p.tun_protect = VppIpsecTunProtect(self, self.tun, p.tun_sa_out, [p.tun_sa_in]) p.tun_protect.add_vpp_config() self.tun.admin_up() self.tun.config_ip4() VppBridgeDomainPort(self, bd1, self.tun).add_vpp_config() VppBridgeDomainPort(self, bd1, self.pg1).add_vpp_config() self.vapi.cli("clear ipsec sa")
def setUp(self): super(TestIpsecGreIfEsp, self).setUp() self.tun_if = self.pg0 p = self.ipv4_params bd1 = VppBridgeDomain(self, 1) bd1.add_vpp_config() p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi, p.auth_algo_vpp_id, p.auth_key, p.crypt_algo_vpp_id, p.crypt_key, self.vpp_esp_protocol, self.pg0.local_ip4, self.pg0.remote_ip4) p.tun_sa_out.add_vpp_config() p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi, p.auth_algo_vpp_id, p.auth_key, p.crypt_algo_vpp_id, p.crypt_key, self.vpp_esp_protocol, self.pg0.remote_ip4, self.pg0.local_ip4) p.tun_sa_in.add_vpp_config() self.tun = VppGreInterface(self, self.pg0.local_ip4, self.pg0.remote_ip4) self.tun.add_vpp_config() p.tun_protect = VppIpsecTunProtect(self, self.tun, p.tun_sa_out, [p.tun_sa_in]) p.tun_protect.add_vpp_config() self.tun.admin_up() self.tun.config_ip4() VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath(self.tun.remote_ip4, 0xffffffff)]).add_vpp_config()
def test_span_l2_rx_dst_gre_subif_vtr(self): """ SPAN l2 rx mirror into gre-subif+vtr """ self.sub_if.admin_up() gre_if = VppGreInterface(self, self.pg2.local_ip4, self.pg2.remote_ip4, type=(VppEnum.vl_api_gre_tunnel_type_t. GRE_API_TUNNEL_TYPE_TEB)) gre_if.add_vpp_config() gre_if.admin_up() gre_sub_if = VppDot1QSubint(self, gre_if, 500) gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500) gre_sub_if.admin_up() self.bridge(gre_sub_if.sw_if_index) # Create bi-directional cross-connects between pg0 and pg1 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) # Create incoming packet streams for packet-generator interfaces pkts = self.create_stream( self.pg0, self.pg_if_packet_sizes, do_dot1=True) self.pg0.add_stream(pkts) # Enable SPAN on pg0 sub if (mirrored to gre sub if) self.vapi.sw_interface_span_enable_disable( self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1) # Enable packet capturing and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() # Verify packets outgoing packet streams on mirrored interface (pg2) n_pkts = len(pkts) pg1_pkts = self.pg1.get_capture(n_pkts) pg2_pkts = self.pg2.get_capture(n_pkts) def decap(p): return self.remove_tags( self.decap_gre(p), [Tag(dot1=DOT1Q, vlan=500)]) pg2_decaped = [decap(p) for p in pg2_pkts] self.bridge(gre_sub_if.sw_if_index, is_add=0) # Disable SPAN on pg0 sub if self.vapi.sw_interface_span_enable_disable( self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1) gre_if.remove_vpp_config() self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) self.verify_capture(pg1_pkts, pg2_decaped)
def test_span_l2_rx_dst_gre_erspan(self): """ SPAN l2 rx mirror into gre-erspan """ self.sub_if.admin_up() gre_if = VppGreInterface(self, self.pg2.local_ip4, self.pg2.remote_ip4, type=2, session=543) gre_if.add_vpp_config() gre_if.admin_up() self.bridge(gre_if.sw_if_index) # Create bi-directional cross-connects between pg0 and pg1 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) # Create incoming packet streams for packet-generator interfaces pkts = self.create_stream( self.pg0, self.pg_if_packet_sizes, do_dot1=True) self.pg0.add_stream(pkts) # Enable SPAN on pg0 sub if (mirrored to gre-erspan) self.vapi.sw_interface_span_enable_disable( self.sub_if.sw_if_index, gre_if.sw_if_index, is_l2=1) # Enable packet capturing and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() # Verify packets outgoing packet streams on mirrored interface (pg2) n_pkts = len(pkts) pg1_pkts = self.pg1.get_capture(n_pkts) pg2_pkts = self.pg2.get_capture(n_pkts) def decap(p): return self.decap_erspan(p, session=543) pg2_decaped = [decap(p) for p in pg2_pkts] self.bridge(gre_if.sw_if_index, is_add=0) # Disable SPAN on pg0 sub if self.vapi.sw_interface_span_enable_disable( self.sub_if.sw_if_index, gre_if.sw_if_index, state=0, is_l2=1) gre_if.remove_vpp_config() self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) self.verify_capture(pg1_pkts, pg2_decaped)
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, 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 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, 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 # 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_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", type=(VppEnum.vl_api_gre_tunnel_type_t.GRE_API_TUNNEL_TYPE_TEB)) gre_if2 = VppGreInterface( self, self.pg0.local_ip4, "2.2.2.3", type=(VppEnum.vl_api_gre_tunnel_type_t.GRE_API_TUNNEL_TYPE_TEB)) 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 # tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.2", self.pg0.local_ip4) rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_tunneled_l2o4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.3") tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.3", self.pg0.local_ip4) rx = self.send_and_expect(self.pg0, tx, self.pg0) 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.l2_interface_vlan_tag_rewrite( sw_if_index=gre_if_12.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=12) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=gre_if_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=11) # # Send traffic in both directiond - expect the VLAN tags to # be swapped. # tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.2", self.pg0.local_ip4, 11) rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_tunneled_vlano4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.3", 12) tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.3", self.pg0.local_ip4, 12) rx = self.send_and_expect(self.pg0, tx, self.pg0) 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_ip_mcast_gre(self): """ IP Multicast Replication over GRE""" gre_if_1 = VppGreInterface(self, self.pg1.local_ip4, self.pg1.remote_ip4).add_vpp_config() gre_if_2 = VppGreInterface(self, self.pg2.local_ip4, self.pg2.remote_ip4).add_vpp_config() gre_if_3 = VppGreInterface(self, self.pg3.local_ip4, self.pg3.remote_ip4).add_vpp_config() gre_if_1.admin_up() gre_if_1.config_ip4() gre_if_2.admin_up() gre_if_2.config_ip4() gre_if_3.admin_up() gre_if_3.config_ip4() # # An (S,G). # one accepting interface, pg0, 2 forwarding interfaces # route_1_1_1_1_232_1_1_1 = VppIpMRoute( self, "1.1.1.1", "232.2.2.2", 64, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, [ VppMRoutePath(gre_if_1.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), VppMRoutePath(gre_if_2.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD), VppMRoutePath(gre_if_3.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD) ]) route_1_1_1_1_232_1_1_1.add_vpp_config() # # a stream that matches the route for (1.1.1.1,232.2.2.2) # small packets # tx = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / GRE() / IP(src="1.1.1.1", dst="232.2.2.2") / UDP(sport=1234, dport=1234) / Raw('\a5' * 64)) * 63 self.vapi.cli("clear trace") self.pg1.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() # We expect replications on Pg2 & 3 # check the encap headers are as expected based on the egress tunnel rxs = self.pg2.get_capture(len(tx)) for rx in rxs: self.assertEqual(rx[IP].src, gre_if_2.t_src) self.assertEqual(rx[IP].dst, gre_if_2.t_dst) self.assert_packet_checksums_valid(rx) rxs = self.pg3.get_capture(len(tx)) for rx in rxs: self.assertEqual(rx[IP].src, gre_if_3.t_src) self.assertEqual(rx[IP].dst, gre_if_3.t_dst) self.assert_packet_checksums_valid(rx)
def test_mgre(self): """ mGRE IPv4 tunnel Tests """ for itf in self.pg_interfaces[3:]: # # one underlay nh for each overlay/tunnel peer # itf.generate_remote_hosts(4) itf.configure_ipv4_neighbors() # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # gre_if = VppGreInterface(self, itf.local_ip4, "0.0.0.0", mode=(VppEnum.vl_api_tunnel_mode_t. TUNNEL_API_MODE_MP)) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() gre_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(gre_if._remote_hosts[ii].ip4, gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Add a TEIB entry resolves the peer # teib = VppTeib(self, gre_if, gre_if._remote_hosts[ii].ip4, itf._remote_hosts[ii].ip4) teib.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - packets are GRE encapped # tx_e = self.create_stream_ip4(self.pg0, "5.5.5.5", route_addr) rx = self.send_and_expect(self.pg0, tx_e, itf) self.verify_tunneled_4o4(self.pg0, rx, tx_e, itf.local_ip4, itf._remote_hosts[ii].ip4) tx_i = self.create_tunnel_stream_4o4(self.pg0, itf._remote_hosts[ii].ip4, itf.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) self.verify_decapped_4o4(self.pg0, rx, tx_i) # # delete and re-add the TEIB # 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) self.verify_tunneled_4o4(self.pg0, rx, tx_e, itf.local_ip4, itf._remote_hosts[ii].ip4) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) self.verify_decapped_4o4(self.pg0, rx, tx_i) gre_if.admin_down() gre_if.unconfig_ip4()
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") rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4, "2.2.2.2") # # Send tunneled packets that match the created tunnel and # are decapped and forwarded. This tests the decap lookup # does not happen in the encap table # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_decapped_4o4(self.pg0, rx, tx) # # Send tunneled packets that match the created tunnel # but arrive on an interface that is not in the tunnel's # encap VRF, these are dropped. # IP enable the interface so they aren't dropped due to # IP not being enabled. # self.pg2.config_ip4() self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg2, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_assert_no_replies(self.pg2, tx, "GRE decap packets in wrong VRF") self.pg2.unconfig_ip4() # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()
def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre4.sw_if_index, enable_ip4=True) self.route4 = VppIpRoute( self, self.tun_ip4, 32, [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IP( id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IP] # use only IP part, without ethernet header fragments = [ x for _, p in six.iteritems(self._packet_infos) for x in fragment_rfc791(p.data, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IP(src=self.tun_ip4, dst=self.src_if.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config() self.logger.debug(self.vapi.ppcli("show interface"))
class TestFIFReassembly(VppTestCase): """ Fragments in fragments reassembly """ @classmethod def setUpClass(cls): super(TestFIFReassembly, cls).setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 cls.dst_if = cls.pg1 for i in cls.pg_interfaces: i.admin_up() i.config_ip4() i.resolve_arp() i.config_ip6() i.resolve_ndp() cls.packet_sizes = [64, 512, 1518, 9018] cls.padding = " abcdefghijklmn" @classmethod def tearDownClass(cls): super(TestFIFReassembly, cls).tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ super(TestFIFReassembly, self).setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip4=True, enable_ip6=True) self.vapi.ip_reassembly_enable_disable( sw_if_index=self.dst_if.sw_if_index, enable_ip4=True, enable_ip6=True) self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, expire_walk_interval_ms=10) self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, expire_walk_interval_ms=10, is_ip6=1) self.sleep(.25) self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, expire_walk_interval_ms=10000) self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, expire_walk_interval_ms=10000, is_ip6=1) def tearDown(self): super(TestFIFReassembly, self).tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip4-reassembly details")) self.logger.debug(self.vapi.ppcli("show ip6-reassembly details")) self.logger.debug(self.vapi.ppcli("show buffers")) def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]): """Verify captured packet stream. :param list capture: Captured packet stream. """ info = None seen = set() for packet in capture: try: self.logger.debug(ppp("Got packet:", packet)) ip = packet[ip_class] udp = packet[UDP] payload_info = self.payload_to_info(packet[Raw]) packet_index = payload_info.index self.assertTrue( packet_index not in dropped_packet_indexes, ppp("Packet received, but should be dropped:", packet)) if packet_index in seen: raise Exception(ppp("Duplicate packet received", packet)) seen.add(packet_index) self.assertEqual(payload_info.dst, self.dst_if.sw_if_index) info = self._packet_infos[packet_index] self.assertTrue(info is not None) self.assertEqual(packet_index, info.index) saved_packet = info.data self.assertEqual(ip.src, saved_packet[ip_class].src) self.assertEqual(ip.dst, saved_packet[ip_class].dst) self.assertEqual(udp.payload, saved_packet[UDP].payload) except Exception: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise for index in self._packet_infos: self.assertTrue(index in seen or index in dropped_packet_indexes, "Packet with packet_index %d not received" % index) def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre4.sw_if_index, enable_ip4=True) self.route4 = VppIpRoute( self, self.tun_ip4, 32, [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IP( id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IP] # use only IP part, without ethernet header fragments = [ x for _, p in six.iteritems(self._packet_infos) for x in fragment_rfc791(p.data, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IP(src=self.tun_ip4, dst=self.src_if.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config() self.logger.debug(self.vapi.ppcli("show interface")) def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [ x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
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", type=(VppEnum.vl_api_gre_tunnel_type_t. GRE_API_TUNNEL_TYPE_TEB)) gre_if2 = VppGreInterface(self, self.pg0.local_ip4, "2.2.2.3", type=(VppEnum.vl_api_gre_tunnel_type_t. GRE_API_TUNNEL_TYPE_TEB)) 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 # tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.2", self.pg0.local_ip4) rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_tunneled_l2o4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.3") tx = self.create_tunnel_stream_l2o4(self.pg0, "2.2.2.3", self.pg0.local_ip4) rx = self.send_and_expect(self.pg0, tx, self.pg0) 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.l2_interface_vlan_tag_rewrite( sw_if_index=gre_if_12.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=12) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=gre_if_11.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=11) # # Send traffic in both directiond - expect the VLAN tags to # be swapped. # tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.2", self.pg0.local_ip4, 11) rx = self.send_and_expect(self.pg0, tx, self.pg0) self.verify_tunneled_vlano4(self.pg0, rx, tx, self.pg0.local_ip4, "2.2.2.3", 12) tx = self.create_tunnel_stream_vlano4(self.pg0, "2.2.2.3", self.pg0.local_ip4, 12) rx = self.send_and_expect(self.pg0, tx, self.pg0) 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_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") rx = self.send_and_expect(self.pg0, tx, self.pg1) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4, "2.2.2.2") # # Send tunneled packets that match the created tunnel and # are decapped and forwarded. This tests the decap lookup # does not happen in the encap table # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_decapped_4o4(self.pg0, rx, tx) # # Send tunneled packets that match the created tunnel # but arrive on an interface that is not in the tunnel's # encap VRF, these are dropped. # IP enable the interface so they aren't dropped due to # IP not being enabled. # self.pg2.config_ip4() self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg2, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) rx = self.send_and_assert_no_replies( self.pg2, tx, "GRE decap packets in wrong VRF") self.pg2.unconfig_ip4() # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()
def test_gre(self): """ GRE 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 = IpRoute(self, "4.4.4.4", 32, [IpPath("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 desintation 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.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() try: self.assertEqual(0, len(rx)) except: error("GRE packets forwarded without DIP resolved") error(rx.show()) raise # # Add a route that resolves the tunnel's destination # route_tun_dst = IpRoute( self, "1.1.1.2", 32, [IpPath(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 # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() 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 # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg0, "1.1.1.2", self.pg0.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() 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.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() try: self.assertEqual(0, len(rx)) except: error("GRE packets forwarded despite no SRC address match") error(rx.show()) raise # # 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 # self.vapi.cli("clear trace") 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.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() try: self.assertEqual(0, len(rx)) except: error( "IPv6 GRE packets forwarded despite IPv6 not enabled on tunnel" ) error(rx.show()) raise # # Enable IPv6 on the tunnel # gre_if.config_ip6() # # Send IPv6 tunnel encapslated packets # - forwarded since IPv6 is enabled on the tunnel # self.vapi.cli("clear trace") 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.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture() self.verify_decapped_6o4(self.pg0, rx, tx) # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config() self.pg0.unconfig_ip6()
def test_mgre(self): """ mGRE IPv4 tunnel Tests """ for itf in self.pg_interfaces[3:]: # # one underlay nh for each overlay/tunnel peer # itf.generate_remote_hosts(4) itf.configure_ipv4_neighbors() # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # gre_if = VppGreInterface( self, itf.local_ip4, "0.0.0.0", mode=(VppEnum.vl_api_gre_tunnel_mode_t.GRE_API_TUNNEL_MODE_MP)) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() gre_if.generate_remote_hosts(4) # # 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(gre_if._remote_hosts[ii].ip4, gre_if.sw_if_index) ]) route_via_tun.add_vpp_config() # # Add a NHRP entry resolves the peer # nhrp = VppNhrp(self, gre_if, gre_if._remote_hosts[ii].ip4, itf._remote_hosts[ii].ip4) nhrp.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", route_addr) rx = self.send_and_expect(self.pg0, tx, itf) self.verify_tunneled_4o4(self.pg0, rx, tx, itf.local_ip4, gre_if._remote_hosts[ii].ip4) # # delete and re-add the NHRP # nhrp.remove_vpp_config() self.send_and_assert_no_replies(self.pg0, tx) nhrp.add_vpp_config() rx = self.send_and_expect(self.pg0, tx, itf) self.verify_tunneled_4o4(self.pg0, rx, tx, itf.local_ip4, gre_if._remote_hosts[ii].ip4)
def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre4.sw_if_index, enable_ip4=True) self.route4 = VppIpRoute(self, self.tun_ip4, 32, [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IP(id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IP] # use only IP part, without ethernet header fragments = [x for _, p in six.iteritems(self._packet_infos) for x in fragment_rfc791(p.data, 400)] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IP(src=self.tun_ip4, dst=self.src_if.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config() self.logger.debug(self.vapi.ppcli("show interface"))
def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200( i.data, i.index, 400)] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
def test_mgre6(self): """ mGRE IPv6 tunnel Tests """ self.pg0.config_ip6() self.pg0.resolve_ndp() e = VppEnum.vl_api_tunnel_encap_decap_flags_t for itf in self.pg_interfaces[3:]: # # one underlay nh for each overlay/tunnel peer # itf.config_ip6() itf.generate_remote_hosts(4) itf.configure_ipv6_neighbors() # # Create an L3 GRE tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # gre_if = VppGreInterface( self, itf.local_ip6, "::", mode=(VppEnum.vl_api_tunnel_mode_t. TUNNEL_API_MODE_MP), flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip6() gre_if.generate_remote_hosts(4) # # for-each peer # for ii in range(1, 4): route_addr = "4::%d" % ii # # Add a TEIB entry resolves the peer # teib = VppTeib(self, gre_if, gre_if._remote_hosts[ii].ip6, itf._remote_hosts[ii].ip6) teib.add_vpp_config() # # route traffic via the peer # route_via_tun = VppIpRoute( self, route_addr, 128, [VppRoutePath(gre_if._remote_hosts[ii].ip6, gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Send a packet stream that is routed into the tunnel # - packets are GRE encapped # tx_e = self.create_stream_ip6(self.pg0, "5::5", route_addr, dscp=2, ecn=1) rx = self.send_and_expect(self.pg0, tx_e, itf) self.verify_tunneled_6o6(self.pg0, rx, tx_e, itf.local_ip6, itf._remote_hosts[ii].ip6, dscp=2) tx_i = self.create_tunnel_stream_6o6(self.pg0, itf._remote_hosts[ii].ip6, itf.local_ip6, self.pg0.local_ip6, self.pg0.remote_ip6) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) self.verify_decapped_6o6(self.pg0, rx, tx_i) # # delete and re-add the TEIB # teib.remove_vpp_config() self.send_and_assert_no_replies(self.pg0, tx_e) teib.add_vpp_config() rx = self.send_and_expect(self.pg0, tx_e, itf) self.verify_tunneled_6o6(self.pg0, rx, tx_e, itf.local_ip6, itf._remote_hosts[ii].ip6, dscp=2) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) self.verify_decapped_6o6(self.pg0, rx, tx_i) gre_if.admin_down() gre_if.unconfig_ip4() itf.unconfig_ip6() self.pg0.unconfig_ip6()
class TestIpsecGreIfEsp(TemplateIpsec, IpsecTun4Tests): """ Ipsec GRE ESP - TUN tests """ tun4_encrypt_node_name = "esp4-encrypt-tun" tun4_decrypt_node_name = "esp4-decrypt-tun" encryption_type = ESP def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / sa.encrypt( IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE() / IP(src=self.pg1.local_ip4, dst=self.pg1.remote_ip4) / UDP(sport=1144, dport=2233) / Raw('X' * payload_size)) for i in range(count) ] def gen_pkts(self, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1144, dport=2233) / Raw('X' * payload_size) for i in range(count) ] def verify_decrypted(self, p, rxs): for rx in rxs: self.assert_equal(rx[Ether].dst, self.pg1.remote_mac) self.assert_equal(rx[IP].dst, self.pg1.remote_ip4) def verify_encrypted(self, p, sa, rxs): for rx in rxs: try: pkt = sa.decrypt(rx[IP]) if not pkt.haslayer(IP): pkt = IP(pkt[Raw].load) self.assert_packet_checksums_valid(pkt) self.assert_equal(pkt[IP].dst, self.pg0.remote_ip4) self.assert_equal(pkt[IP].src, self.pg0.local_ip4) self.assertTrue(pkt.haslayer(GRE)) e = pkt[GRE] self.assertEqual(e[IP].dst, "1.1.1.2") except (IndexError, AssertionError): self.logger.debug(ppp("Unexpected packet:", rx)) try: self.logger.debug(ppp("Decrypted packet:", pkt)) except: pass raise def setUp(self): super(TestIpsecGreIfEsp, self).setUp() self.tun_if = self.pg0 p = self.ipv4_params bd1 = VppBridgeDomain(self, 1) bd1.add_vpp_config() p.tun_sa_out = VppIpsecSA(self, p.scapy_tun_sa_id, p.scapy_tun_spi, p.auth_algo_vpp_id, p.auth_key, p.crypt_algo_vpp_id, p.crypt_key, self.vpp_esp_protocol, self.pg0.local_ip4, self.pg0.remote_ip4) p.tun_sa_out.add_vpp_config() p.tun_sa_in = VppIpsecSA(self, p.vpp_tun_sa_id, p.vpp_tun_spi, p.auth_algo_vpp_id, p.auth_key, p.crypt_algo_vpp_id, p.crypt_key, self.vpp_esp_protocol, self.pg0.remote_ip4, self.pg0.local_ip4) p.tun_sa_in.add_vpp_config() self.tun = VppGreInterface(self, self.pg0.local_ip4, self.pg0.remote_ip4) self.tun.add_vpp_config() p.tun_protect = VppIpsecTunProtect(self, self.tun, p.tun_sa_out, [p.tun_sa_in]) p.tun_protect.add_vpp_config() self.tun.admin_up() self.tun.config_ip4() VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath(self.tun.remote_ip4, 0xffffffff)]).add_vpp_config() def tearDown(self): self.tun.unconfig_ip4() super(TestIpsecGreIfEsp, self).tearDown()
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_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)], is_ip6=1) 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(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_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [ x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
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_gre_vrf(self): """ GRE tunnel VRF Tests """ # # Create an L3 GRE tunnel whose destination is in the non-default # table. The underlay is thus non-default - the overlay is still # the default. # - set it admin up # - assign an IP Addres # gre_if = VppGreInterface(self, self.pg1.local_ip4, "2.2.2.2", outer_fib_id=1) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() # # Add a route via the tunnel - in the overlay # route_via_tun = VppIpRoute( self, "9.9.9.9", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Add a route that resolves the tunnel's destination - in the # underlay table # route_tun_dst = VppIpRoute( self, "2.2.2.2", 32, table_id=1, paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # packets are sent in on pg0 which is in the default table # - packets are GRE encapped # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(len(tx)) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4, "2.2.2.2") # # Send tunneled packets that match the created tunnel and # are decapped and forwarded. This tests the decap lookup # does not happen in the encap table # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) self.pg1.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_decapped_4o4(self.pg0, rx, tx) # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()
class TestFIFReassembly(VppTestCase): """ Fragments in fragments reassembly """ @classmethod def setUpClass(cls): super(TestFIFReassembly, cls).setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 cls.dst_if = cls.pg1 for i in cls.pg_interfaces: i.admin_up() i.config_ip4() i.resolve_arp() i.config_ip6() i.resolve_ndp() cls.packet_sizes = [64, 512, 1518, 9018] cls.padding = " abcdefghijklmn" @classmethod def tearDownClass(cls): super(TestFIFReassembly, cls).tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ super(TestFIFReassembly, self).setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip4=True, enable_ip6=True) self.vapi.ip_reassembly_enable_disable( sw_if_index=self.dst_if.sw_if_index, enable_ip4=True, enable_ip6=True) self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, expire_walk_interval_ms=10) self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, expire_walk_interval_ms=10, is_ip6=1) self.sleep(.25) self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, expire_walk_interval_ms=10000) self.vapi.ip_reassembly_set(timeout_ms=1000000, max_reassemblies=1000, expire_walk_interval_ms=10000, is_ip6=1) def tearDown(self): super(TestFIFReassembly, self).tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip4-reassembly details")) self.logger.debug(self.vapi.ppcli("show ip6-reassembly details")) self.logger.debug(self.vapi.ppcli("show buffers")) def verify_capture(self, capture, ip_class, dropped_packet_indexes=[]): """Verify captured packet stream. :param list capture: Captured packet stream. """ info = None seen = set() for packet in capture: try: self.logger.debug(ppp("Got packet:", packet)) ip = packet[ip_class] udp = packet[UDP] payload_info = self.payload_to_info(packet[Raw]) packet_index = payload_info.index self.assertTrue( packet_index not in dropped_packet_indexes, ppp("Packet received, but should be dropped:", packet)) if packet_index in seen: raise Exception(ppp("Duplicate packet received", packet)) seen.add(packet_index) self.assertEqual(payload_info.dst, self.dst_if.sw_if_index) info = self._packet_infos[packet_index] self.assertTrue(info is not None) self.assertEqual(packet_index, info.index) saved_packet = info.data self.assertEqual(ip.src, saved_packet[ip_class].src) self.assertEqual(ip.dst, saved_packet[ip_class].dst) self.assertEqual(udp.payload, saved_packet[UDP].payload) except Exception: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise for index in self._packet_infos: self.assertTrue(index in seen or index in dropped_packet_indexes, "Packet with packet_index %d not received" % index) def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre4.sw_if_index, enable_ip4=True) self.route4 = VppIpRoute(self, self.tun_ip4, 32, [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IP(id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IP] # use only IP part, without ethernet header fragments = [x for _, p in six.iteritems(self._packet_infos) for x in fragment_rfc791(p.data, 400)] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IP(src=self.tun_ip4, dst=self.src_if.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config() self.logger.debug(self.vapi.ppcli("show interface")) def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200( i.data, i.index, 400)] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()