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()
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(record[10].encode('hex'), 16), 8) # egress interface self.assertEqual(int(record[14].encode('hex'), 16), 9) # packets self.assertEqual(int(record[2].encode('hex'), 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(record[156].encode('hex'), 16) >> 32 # flow start timestamp self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) flowTimestamp = int(record[157].encode('hex'), 16) >> 32 # flow end timestamp self.assertAlmostEqual(flowTimestamp, nowUNIX, delta=1) # ethernet type self.assertEqual(int(record[256].encode('hex'), 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(record[4].encode('hex'), 16), 6) # src port self.assertEqual(int(record[7].encode('hex'), 16), 1234) # dst port self.assertEqual(int(record[11].encode('hex'), 16), 4321) # tcp flags self.assertEqual(int(record[6].encode('hex'), 16), 80) ipfix.remove_vpp_config() self.logger.info("FFP_TEST_FINISH_0000")
def test_bier_head(self): """BIER head""" MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() # # 2 bit positions via two next hops # nh1 = "10.0.0.1" nh2 = "10.0.0.2" ip_route_1 = VppIpRoute(self, nh1, 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(2001)]) ]) ip_route_2 = VppIpRoute(self, nh2, 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(2002)]) ]) ip_route_1.add_vpp_config() ip_route_2.add_vpp_config() bier_route_1 = VppBierRoute( self, bti, 1, [VppRoutePath(nh1, 0xffffffff, labels=[VppMplsLabel(101)])]) bier_route_2 = VppBierRoute( self, bti, 2, [VppRoutePath(nh2, 0xffffffff, labels=[VppMplsLabel(102)])]) bier_route_1.add_vpp_config() bier_route_2.add_vpp_config() # # An imposition object with both bit-positions set # bi = VppBierImp(self, bti, 333, scapy.compat.chb(0x3) * 32) bi.add_vpp_config() # # Add a multicast route that will forward into the BIER doamin # route_ing_232_1_1_1 = VppIpMRoute( self, "0.0.0.0", "232.1.1.1", 32, MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT), VppMRoutePath(0xffffffff, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD, proto=FibPathProto.FIB_PATH_NH_PROTO_BIER, type=FibPathType.FIB_PATH_TYPE_BIER_IMP, bier_imp=bi.bi_index) ]) route_ing_232_1_1_1.add_vpp_config() # # inject an IP packet. We expect it to be BIER encapped and # replicated. # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234)) self.pg0.add_stream([p]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(2) # # Encap Stack is; eth, MPLS, MPLS, BIER # igp_mpls = rx[0][MPLS] self.assertEqual(igp_mpls.label, 2001) self.assertEqual(igp_mpls.ttl, 64) self.assertEqual(igp_mpls.s, 0) bier_mpls = igp_mpls[MPLS].payload self.assertEqual(bier_mpls.label, 101) self.assertEqual(bier_mpls.ttl, 64) self.assertEqual(bier_mpls.s, 1) self.assertEqual(rx[0][BIER].length, 2) igp_mpls = rx[1][MPLS] self.assertEqual(igp_mpls.label, 2002) self.assertEqual(igp_mpls.ttl, 64) self.assertEqual(igp_mpls.s, 0) bier_mpls = igp_mpls[MPLS].payload self.assertEqual(bier_mpls.label, 102) self.assertEqual(bier_mpls.ttl, 64) self.assertEqual(bier_mpls.s, 1) self.assertEqual(rx[0][BIER].length, 2)
def bier_e2e(self, hdr_len_id, n_bytes, max_bp): """ BIER end-to-end""" # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(0, 0, hdr_len_id) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() lowest = [b'\0'] * (n_bytes) lowest[-1] = scapy.compat.chb(1) highest = [b'\0'] * (n_bytes) highest[0] = scapy.compat.chb(128) # # Impostion Sets bit strings # bi_low = VppBierImp(self, bti, 333, lowest) bi_low.add_vpp_config() bi_high = VppBierImp(self, bti, 334, highest) bi_high.add_vpp_config() # # Add a multicast route that will forward into the BIER doamin # route_ing_232_1_1_1 = VppIpMRoute( self, "0.0.0.0", "232.1.1.1", 32, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(self.pg0.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), VppMRoutePath(0xffffffff, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD, proto=DpoProto.DPO_PROTO_BIER, bier_imp=bi_low.bi_index) ]) route_ing_232_1_1_1.add_vpp_config() route_ing_232_1_1_2 = VppIpMRoute( self, "0.0.0.0", "232.1.1.2", 32, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(self.pg0.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), VppMRoutePath(0xffffffff, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD, proto=DpoProto.DPO_PROTO_BIER, bier_imp=bi_high.bi_index) ]) route_ing_232_1_1_2.add_vpp_config() # # disposition table 8 # bdt = VppBierDispTable(self, 8) bdt.add_vpp_config() # # BIER routes in table that are for-us, resolving through # disp table 8. # bier_route_1 = VppBierRoute(self, bti, 1, [ VppRoutePath("0.0.0.0", 0xffffffff, proto=DpoProto.DPO_PROTO_BIER, nh_table_id=8) ]) bier_route_1.add_vpp_config() bier_route_max = VppBierRoute( self, bti, max_bp, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=8)]) bier_route_max.add_vpp_config() # # An entry in the disposition table for sender 333 # lookup in VRF 10 # bier_de_1 = VppBierDispEntry(self, bdt.id, 333, BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4, DpoProto.DPO_PROTO_BIER, "0.0.0.0", 10, rpf_id=8192) bier_de_1.add_vpp_config() bier_de_1 = VppBierDispEntry(self, bdt.id, 334, BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4, DpoProto.DPO_PROTO_BIER, "0.0.0.0", 10, rpf_id=8193) bier_de_1.add_vpp_config() # # Add a multicast routes that will forward the traffic # post-disposition # route_eg_232_1_1_1 = VppIpMRoute( self, "0.0.0.0", "232.1.1.1", 32, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, table_id=10, paths=[ VppMRoutePath(self.pg1.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD) ]) route_eg_232_1_1_1.add_vpp_config() route_eg_232_1_1_1.update_rpf_id(8192) route_eg_232_1_1_2 = VppIpMRoute( self, "0.0.0.0", "232.1.1.2", 32, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, table_id=10, paths=[ VppMRoutePath(self.pg1.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD) ]) route_eg_232_1_1_2.add_vpp_config() route_eg_232_1_1_2.update_rpf_id(8193) # # inject a packet in VRF-0. We expect it to be BIER encapped, # replicated, then hit the disposition and be forwarded # out of VRF 10, i.e. on pg1 # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(5) * 32)) rx = self.send_and_expect(self.pg0, p * 65, self.pg1) self.assertEqual(rx[0][IP].src, "1.1.1.1") self.assertEqual(rx[0][IP].dst, "232.1.1.1") p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="1.1.1.1", dst="232.1.1.2") / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(5) * 512)) rx = self.send_and_expect(self.pg0, p * 65, self.pg1) self.assertEqual(rx[0][IP].src, "1.1.1.1") self.assertEqual(rx[0][IP].dst, "232.1.1.2")
def test_bier_head_o_udp(self): """BIER head over UDP""" # # Add a BIER table for sub-domain 1, set 0, and BSL 256 # bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() # # 1 bit positions via 1 next hops # nh1 = "10.0.0.1" ip_route = VppIpRoute(self, nh1, 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(2001)]) ]) ip_route.add_vpp_config() udp_encap = VppUdpEncap(self, self.pg0.local_ip4, nh1, 330, 8138) udp_encap.add_vpp_config() bier_route = VppBierRoute(self, bti, 1, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=udp_encap.id) ]) bier_route.add_vpp_config() # # An 2 imposition objects with all bit-positions set # only use the second, but creating 2 tests with a non-zero # value index in the route add # bi = VppBierImp(self, bti, 333, scapy.compat.chb(0xff) * 32) bi.add_vpp_config() bi2 = VppBierImp(self, bti, 334, scapy.compat.chb(0xff) * 32) bi2.add_vpp_config() # # Add a multicast route that will forward into the BIER doamin # route_ing_232_1_1_1 = VppIpMRoute( self, "0.0.0.0", "232.1.1.1", 32, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(self.pg0.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), VppMRoutePath(0xffffffff, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD, proto=DpoProto.DPO_PROTO_BIER, bier_imp=bi2.bi_index) ]) route_ing_232_1_1_1.add_vpp_config() # # inject a packet an IP. We expect it to be BIER and UDP encapped, # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234)) self.pg0.add_stream([p]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Encap Stack is, eth, IP, UDP, BIFT, BIER # self.assertEqual(rx[0][IP].src, self.pg0.local_ip4) self.assertEqual(rx[0][IP].dst, nh1) self.assertEqual(rx[0][UDP].sport, 330) self.assertEqual(rx[0][UDP].dport, 8138) self.assertEqual(rx[0][BIFT].bsl, BIERLength.BIER_LEN_256) self.assertEqual(rx[0][BIFT].sd, 1) self.assertEqual(rx[0][BIFT].set, 0) self.assertEqual(rx[0][BIFT].ttl, 64) self.assertEqual(rx[0][BIER].length, 2)
def test_arp(self): """ ARP """ # # Generate some hosts on the LAN # self.pg1.generate_remote_hosts(11) # # Send IP traffic to one of these unresolved hosts. # expect the generation of an ARP request # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4) # # And a dynamic ARP entry for host 1 # dyn_arp = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) dyn_arp.add_vpp_config() # # now we expect IP traffic forwarded # dyn_p = ( Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(dyn_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[1].ip4) # # And a Static ARP entry for host 2 # static_arp = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].mac, self.pg1.remote_hosts[2].ip4, is_static=1) static_arp.add_vpp_config() static_p = ( Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(static_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[2].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[2].ip4) # # flap the link. dynamic ARPs get flush, statics don't # self.pg1.admin_down() self.pg1.admin_up() self.pg0.add_stream(static_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[2].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[2].ip4) self.pg0.add_stream(dyn_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4) # # Send an ARP request from one of the so-far unlearned remote hosts # p = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) / ARP(op="who-has", hwsrc=self.pg1._remote_hosts[3].mac, pdst=self.pg1.local_ip4, psrc=self.pg1._remote_hosts[3].ip4)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1._remote_hosts[3].mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4) # # VPP should have learned the mapping for the remote host # self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)) # # Fire in an ARP request before the interface becomes IP enabled # self.pg2.generate_remote_hosts(4) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg2.remote_hosts[3].ip4)) pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / Dot1Q(vlan=0) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg2.remote_hosts[3].ip4)) self.send_and_assert_no_replies(self.pg2, p, "interface not IP enabled") # # Make pg2 un-numbered to pg1 # self.pg2.set_unnumbered(self.pg1.sw_if_index) # # We should respond to ARP requests for the unnumbered to address # once an attached route to the source is known # self.send_and_assert_no_replies( self.pg2, p, "ARP req for unnumbered address - no source") attached_host = VppIpRoute( self, self.pg2.remote_hosts[3].ip4, 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)]) attached_host.add_vpp_config() self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg2.remote_hosts[3].ip4) self.pg2.add_stream(pt) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg2.remote_hosts[3].ip4) # # A neighbor entry that has no associated FIB-entry # arp_no_fib = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[4].mac, self.pg1.remote_hosts[4].ip4, is_no_fib_entry=1) arp_no_fib.add_vpp_config() # # check we have the neighbor, but no route # self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)) self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32)) # # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2 # from within pg1's subnet # arp_unnum = VppNeighbor(self, self.pg2.sw_if_index, self.pg1.remote_hosts[5].mac, self.pg1.remote_hosts[5].ip4) arp_unnum.add_vpp_config() p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_ip(rx[0], self.pg2.local_mac, self.pg1.remote_hosts[5].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[5].ip4) # # ARP requests from hosts in pg1's subnet sent on pg2 are replied to # with the unnumbered interface's address as the source # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[6].ip4)) self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[6].ip4) # # An attached host route out of pg2 for an undiscovered hosts generates # an ARP request with the unnumbered address as the source # att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)]) att_unnum.add_vpp_config() p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_req(rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[7].ip4)) self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[7].ip4) # # An attached host route as yet unresolved out of pg2 for an # undiscovered host, an ARP requests begets a response. # att_unnum1 = VppIpRoute( self, self.pg1.remote_hosts[8].ip4, 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)]) att_unnum1.add_vpp_config() p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[8].ip4)) self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[8].ip4) # # Send an ARP request from one of the so-far unlearned remote hosts # with a VLAN0 tag # p = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac) / Dot1Q(vlan=0) / ARP(op="who-has", hwsrc=self.pg1._remote_hosts[9].mac, pdst=self.pg1.local_ip4, psrc=self.pg1._remote_hosts[9].ip4)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1._remote_hosts[9].mac, self.pg1.local_ip4, self.pg1._remote_hosts[9].ip4) # # Add a hierachy of routes for a host in the sub-net. # Should still get an ARP resp since the cover is attached # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(op="who-has", hwsrc=self.pg1.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[10].ip4)) r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30, [ VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index) ]) r1.add_vpp_config() self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[10].ip4) r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32, [ VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index) ]) r2.add_vpp_config() self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[10].ip4) # # add an ARP entry that's not on the sub-net and so whose # adj-fib fails the refinement check. then send an ARP request # from that source # a1 = VppNeighbor(self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50") a1.add_vpp_config() p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc="100.100.100.50", pdst=self.pg0.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib") # # ERROR Cases # 1 - don't respond to ARP request for address not within the # interface's sub-net # 1b - nor within the unnumbered subnet # 1c - nor within the subnet of a different interface # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, pdst="10.10.10.3", psrc=self.pg0.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local destination") self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3")) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst="10.10.10.3", psrc=self.pg1.remote_hosts[7].ip4)) self.send_and_assert_no_replies( self.pg0, p, "ARP req for non-local destination - unnum") p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net") self.assertFalse( find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4)) # # 2 - don't respond to ARP request from an address not within the # interface's sub-net # 2b - to a prxied address # 2c - not within a differents interface's sub-net p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc="10.10.10.3", pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, psrc="10.10.10.3", pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies( self.pg0, p, "ARP req for non-local source - unnum") p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc=self.pg1.remote_ip4, pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c") # # 3 - don't respond to ARP request from an address that belongs to # the router # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc=self.pg0.local_ip4, pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") # # 4 - don't respond to ARP requests that has mac source different # from ARP request HW source # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc="00:00:00:DE:AD:BE", psrc=self.pg0.remote_ip4, pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") # # 5 - don't respond to ARP requests for address within the # interface's sub-net but not the interface's address # self.pg0.generate_remote_hosts(2) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc=self.pg0.remote_hosts[0].ip4, pdst=self.pg0.remote_hosts[1].ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local destination") # # cleanup # dyn_arp.remove_vpp_config() static_arp.remove_vpp_config() self.pg2.unset_unnumbered(self.pg1.sw_if_index) # need this to flush the adj-fibs self.pg2.unset_unnumbered(self.pg1.sw_if_index) self.pg2.admin_down() self.pg1.admin_down()
def test_SRv6_End_AD_L2(self): """ Test SRv6 End.AD behavior with L2 traffic. """ self.src_addr = 'a0::' self.sid_list = ['a1::', 'a2::a4', 'a3::'] self.test_sid_index = 1 # send traffic to one destination interface # source and destination interfaces are IPv6 only self.setup_interfaces(ipv6=[True, False]) # configure route to next segment route = VppIpRoute(self, self.sid_list[self.test_sid_index + 1], 128, [ VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) route.add_vpp_config() # configure SRv6 localSID behavior cli_str = "sr localsid address " + \ self.sid_list[self.test_sid_index] + \ " behavior end.ad" + \ " oif " + self.pg1.name + \ " iif " + self.pg1.name self.vapi.cli(cli_str) # log the localsids self.logger.debug(self.vapi.cli("show sr localsid")) # send one packet per packet size count = len(self.pg_packet_sizes) # prepare L2 in SRv6 headers packet_header1 = self.create_packet_header_IPv6_SRH_L2( srcaddr=self.src_addr, sidlist=self.sid_list[::-1], segleft=len(self.sid_list) - self.test_sid_index - 1, vlan=0) # generate packets (pg0->pg1) pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, self.compare_rx_tx_packet_End_AD_L2_out) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # prepare L2 header for returning packets packet_header2 = self.create_packet_header_L2() # generate returning packets (pg1->pg0) pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, self.compare_rx_tx_packet_End_AD_L2_in) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # remove SRv6 localSIDs cli_str = "sr localsid del address " + \ self.sid_list[self.test_sid_index] self.vapi.cli(cli_str) # cleanup interfaces self.teardown_interfaces()
def test_l2_emulation(self): """ L2 Emulation """ # # non distinct L3 packets, in the tag/non-tag combos # pkt_no_tag = (Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_to_tag = (Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) / IP(src="2.2.2.2", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_from_tag = ( Ether(src=self.pg3.remote_mac, dst=self.pg2.remote_mac) / Dot1Q(vlan=93) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_from_to_tag = ( Ether(src=self.pg3.remote_mac, dst=self.pg2.remote_mac) / Dot1Q(vlan=93) / IP(src="2.2.2.2", dst="1.1.1.2") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_bcast = (Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / IP(src="2.2.2.2", dst="255.255.255.255") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # A couple of sub-interfaces for tags # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=92) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=93) # # Disable UU flooding, learning and ARP termination. makes this test # easier as unicast packets are dropped if not extracted. # self.vapi.bridge_flags(bd_id=1, is_set=0, flags=(1 << 0) | (1 << 3) | (1 << 4)) # # Add a DVR route to steer traffic at L3 # route_1 = VppIpRoute( self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", self.pg1.sw_if_index, is_dvr=1)]) route_2 = VppIpRoute( self, "1.1.1.2", 32, [VppRoutePath("0.0.0.0", sub_if_on_pg2.sw_if_index, is_dvr=1)]) route_1.add_vpp_config() route_2.add_vpp_config() # # packets are dropped because bridge does not flood unknown unicast # self.send_and_assert_no_replies(self.pg0, pkt_no_tag) # # Enable L3 extraction on pgs # self.vapi.l2_emulation(self.pg0.sw_if_index) self.vapi.l2_emulation(self.pg1.sw_if_index) self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index) self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index) # # now we expect the packet forward according to the DVR route # rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) rx = self.send_and_expect(self.pg0, pkt_to_tag * 65, self.pg2) self.assert_same_mac_addr(pkt_to_tag, rx) self.assert_has_vlan_tag(92, rx) rx = self.send_and_expect(self.pg3, pkt_from_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_from_tag, rx) self.assert_has_no_tag(rx) rx = self.send_and_expect(self.pg3, pkt_from_to_tag * 65, self.pg2) self.assert_same_mac_addr(pkt_from_tag, rx) self.assert_has_vlan_tag(92, rx) # # but broadcast packets are still flooded # self.send_and_expect(self.pg0, pkt_bcast * 33, self.pg2) # # cleanup # self.vapi.l2_emulation(self.pg0.sw_if_index, enable=0) self.vapi.l2_emulation(self.pg1.sw_if_index, enable=0) self.vapi.l2_emulation(sub_if_on_pg2.sw_if_index, enable=0) self.vapi.l2_emulation(sub_if_on_pg3.sw_if_index, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0) route_1.remove_vpp_config() route_2.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def test_dvr(self): """ Distributed Virtual Router """ # # A packet destined to an IP address that is L2 bridged via # a non-tag interface # ip_non_tag_bridged = "10.10.10.10" ip_tag_bridged = "10.10.10.11" any_src_addr = "1.1.1.1" pkt_no_tag = ( Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_tag = (Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # Two sub-interfaces so we can test VLAN tag push/pop # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=92) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=93) # # Add routes to bridge the traffic via a tagged an nontagged interface # route_no_tag = VppIpRoute( self, ip_non_tag_bridged, 32, [VppRoutePath("0.0.0.0", self.pg1.sw_if_index, is_dvr=1)]) route_no_tag.add_vpp_config() # # Inject the packet that arrives and leaves on a non-tagged interface # Since it's 'bridged' expect that the MAC headed is unchanged. # rx = self.send_and_expect(self.pg0, pkt_no_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) # # Add routes to bridge the traffic via a tagged interface # route_with_tag = VppIpRoute( self, ip_tag_bridged, 32, [VppRoutePath("0.0.0.0", sub_if_on_pg3.sw_if_index, is_dvr=1)]) route_with_tag.add_vpp_config() # # Inject the packet that arrives non-tag and leaves on a tagged # interface # rx = self.send_and_expect(self.pg0, pkt_tag * 65, self.pg3) self.assert_same_mac_addr(pkt_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to tag # pkt_tag_to_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * 65, self.pg3) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to non-Tag # pkt_tag_to_non_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * 65, self.pg1) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_no_tag(rx) # # Add an output L3 ACL that will block the traffic # rule_1 = ({ 'is_permit': 0, 'is_ipv6': 0, 'proto': 17, 'srcport_or_icmptype_first': 1234, 'srcport_or_icmptype_last': 1234, 'src_ip_prefix_len': 32, 'src_ip_addr': inet_pton(AF_INET, any_src_addr), 'dstport_or_icmpcode_first': 1234, 'dstport_or_icmpcode_last': 1234, 'dst_ip_prefix_len': 32, 'dst_ip_addr': inet_pton(AF_INET, ip_non_tag_bridged) }) acl = self.vapi.acl_add_replace(acl_index=4294967295, r=[rule_1]) # # Apply the ACL on the output interface # self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index, 0, [acl.acl_index]) # # Send packet's that should match the ACL and be dropped # rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * 65) # # cleanup # self.vapi.acl_interface_set_acl_list(self.pg1.sw_if_index, 0, []) self.vapi.acl_del(acl.acl_index) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI, enable=0) # # Do a FIB dump to make sure the paths are correctly reported as DVR # routes = self.vapi.ip_fib_dump() for r in routes: if (inet_pton(AF_INET, ip_tag_bridged) == r.address): self.assertEqual(r.path[0].sw_if_index, sub_if_on_pg3.sw_if_index) self.assertEqual(r.path[0].is_dvr, 1) if (inet_pton(AF_INET, ip_non_tag_bridged) == r.address): self.assertEqual(r.path[0].sw_if_index, self.pg1.sw_if_index) self.assertEqual(r.path[0].is_dvr, 1) # # the explicit route delete is require so it happens before # the sbu-interface delete. subinterface delete is required # because that object type does not use the object registry # route_no_tag.remove_vpp_config() route_with_tag.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def run_SRv6_End_AS_IPv4(self, sid_list, test_sid_index, rewrite_src_addr): """ Run SRv6 End.AS test with IPv4 traffic. """ self.rewrite_src_addr = rewrite_src_addr self.rewrite_sid_list = sid_list[test_sid_index + 1::] # send traffic to one destination interface # source and destination interfaces are IPv6 only self.setup_interfaces(ipv6=[True, False], ipv4=[True, True]) # configure route to next segment route = VppIpRoute(self, sid_list[test_sid_index + 1], 128, [ VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route.add_vpp_config() # configure SRv6 localSID behavior cli_str = "sr localsid address " + sid_list[test_sid_index] \ + " behavior end.as" \ + " nh " + self.pg1.remote_ip4 \ + " oif " + self.pg1.name \ + " iif " + self.pg1.name \ + " src " + self.rewrite_src_addr for s in self.rewrite_sid_list: cli_str += " next " + s self.vapi.cli(cli_str) # log the localsids self.logger.debug(self.vapi.cli("show sr localsid")) # send one packet per packet size count = len(self.pg_packet_sizes) # prepare IPv4 in SRv6 headers packet_header1 = self.create_packet_header_IPv6_SRH_IPv4( sidlist=sid_list[::-1], segleft=len(sid_list) - test_sid_index - 1) # generate packets (pg0->pg1) pkts1 = self.create_stream(self.pg0, self.pg1, packet_header1, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg0, pkts1, self.pg1, self.compare_rx_tx_packet_End_AS_IPv4_out) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # prepare IPv6 header for returning packets packet_header2 = self.create_packet_header_IPv4() # generate returning packets (pg1->pg0) pkts2 = self.create_stream(self.pg1, self.pg0, packet_header2, self.pg_packet_sizes, count) # send packets and verify received packets self.send_and_verify_pkts(self.pg1, pkts2, self.pg0, self.compare_rx_tx_packet_End_AS_IPv4_in) # log the localsid counters self.logger.info(self.vapi.cli("show sr localsid")) # remove SRv6 localSIDs self.vapi.cli("sr localsid del address " + sid_list[test_sid_index]) # cleanup interfaces self.teardown_interfaces()
def test_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_no_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_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_tag) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(1) self.assertEqual(rx[0][Ether].dst, pkt_tag[Ether].dst) self.assertEqual(rx[0][Ether].src, pkt_tag[Ether].src) self.assertEqual(rx[0][Dot1Q].vlan, 93) # # 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)) self.pg2.add_stream(pkt_tag_to_tag) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(1) self.assertEqual(rx[0][Ether].dst, pkt_tag_to_tag[Ether].dst) self.assertEqual(rx[0][Ether].src, pkt_tag_to_tag[Ether].src) self.assertEqual(rx[0][Dot1Q].vlan, 93) # # 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)) self.pg2.add_stream(pkt_tag_to_non_tag) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.assertEqual(rx[0][Ether].dst, pkt_tag_to_tag[Ether].dst) self.assertEqual(rx[0][Ether].src, pkt_tag_to_tag[Ether].src) self.assertFalse(rx[0].haslayer(Dot1Q))
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_vrf(self): """ GRE tunnel VRF Tests """ # # Create an L3 GRE tunnel whose destination is in the non-default # table. The underlay is thus non-default - the overlay is still # the default. # - set it admin up # - assign an IP Addres # gre_if = VppGreInterface(self, self.pg1.local_ip4, "2.2.2.2", outer_fib_id=1) gre_if.add_vpp_config() gre_if.admin_up() gre_if.config_ip4() # # Add a route via the tunnel - in the overlay # route_via_tun = VppIpRoute( self, "9.9.9.9", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]) route_via_tun.add_vpp_config() # # Add a route that resolves the tunnel's destination - in the # underlay table # route_tun_dst = VppIpRoute( self, "2.2.2.2", 32, table_id=1, paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_tun_dst.add_vpp_config() # # Send a packet stream that is routed into the tunnel # packets are sent in on pg0 which is in the default table # - packets are GRE encapped # self.vapi.cli("clear trace") tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9") self.pg0.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(len(tx)) self.verify_tunneled_4o4(self.pg1, rx, tx, self.pg1.local_ip4, "2.2.2.2") # # Send tunneled packets that match the created tunnel and # are decapped and forwarded. This tests the decap lookup # does not happen in the encap table # self.vapi.cli("clear trace") tx = self.create_tunnel_stream_4o4(self.pg1, "2.2.2.2", self.pg1.local_ip4, self.pg0.local_ip4, self.pg0.remote_ip4) self.pg1.add_stream(tx) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(tx)) self.verify_decapped_4o4(self.pg0, rx, tx) # # test case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config()
def test_gre6(self): """ GRE IPv6 tunnel Tests """ # # 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 case cleanup # route_tun_dst.remove_vpp_config() route_via_tun.remove_vpp_config() gre_if.remove_vpp_config() self.pg2.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_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_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_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_sr_mpls(self): """ SR MPLS """ # # A simple MPLS xconnect - neos label in label out # route_32_eos = VppMplsRoute(self, 32, 0, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)])]) route_32_eos.add_vpp_config() # # A binding SID with only one label # self.vapi.sr_mpls_policy_add(999, 1, 0, [32]) # # A labeled IP route that resolves thru the binding SID # ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=999, labels=[VppMplsLabel(55)])]) ip_10_0_0_1.add_vpp_config() tx = self.create_stream_ip4(self.pg1, "10.0.0.1") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(55)]) # # An unlabeled IP route that resolves thru the binding SID # ip_10_0_0_1 = VppIpRoute(self, "10.0.0.2", 32, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=999)]) ip_10_0_0_1.add_vpp_config() tx = self.create_stream_ip4(self.pg1, "10.0.0.2") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)]) self.vapi.sr_mpls_policy_del(999) # # this time the SID has many labels pushed # self.vapi.sr_mpls_policy_add(999, 1, 0, [32, 33, 34]) tx = self.create_stream_ip4(self.pg1, "10.0.0.1") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34), VppMplsLabel(55)]) tx = self.create_stream_ip4(self.pg1, "10.0.0.2") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)]) # # Resolve an MPLS tunnel via the SID # mpls_tun = VppMPLSTunnelInterface( self, [VppRoutePath("0.0.0.0", 0xffffffff, nh_via_label=999, labels=[VppMplsLabel(44), VppMplsLabel(46)])]) mpls_tun.add_vpp_config() mpls_tun.admin_up() # # add an unlabelled route through the new tunnel # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]) route_10_0_0_3.add_vpp_config() self.logger.info(self.vapi.cli("sh mpls tun 0")) self.logger.info(self.vapi.cli("sh adj 21")) tx = self.create_stream_ip4(self.pg1, "10.0.0.3") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34), VppMplsLabel(44), VppMplsLabel(46)]) # # add a labelled route through the new tunnel # route_10_0_0_3 = VppIpRoute(self, "10.0.0.4", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[VppMplsLabel(55)])]) route_10_0_0_3.add_vpp_config() tx = self.create_stream_ip4(self.pg1, "10.0.0.4") rx = self.send_and_expect(self.pg1, tx, self.pg0) self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34), VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(55)]) self.vapi.sr_mpls_policy_del(999)
def test_flood(self): """ L2 Flood Tests """ # # Create a single bridge Domain # self.vapi.bridge_domain_add_del(bd_id=1) # # add each interface to the BD. 3 interfaces per split horizon group # for i in self.pg_interfaces[0:4]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=0) for i in self.pg_interfaces[4:8]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=1) for i in self.pg_interfaces[8:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2) for i in self.lo_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:de:ad:be:ef") / IP(src="10.10.10.10", dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # input on pg0 expect copies on pg1->11 # this is in SHG=0 so its flooded to all, expect the pg0 since that's # the ingress link # self.pg0.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[1:12]: rx0 = i.get_capture(65, timeout=1) # # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0) # and pg8->11 (SHG=2) # self.pg4.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[:4]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[8:12]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[4:8]: i.assert_nothing_captured(remark="Different SH group") # # An IP route so the packet that hits the BVI is sent out of pg12 # ip_route = VppIpRoute(self, "1.1.1.1", 32, [VppRoutePath(self.pg12.remote_ip4, self.pg12.sw_if_index)]) ip_route.add_vpp_config() self.logger.info(self.vapi.cli("sh bridge 1 detail")) # # input on pg0 expect copies on pg1->12 # this is in SHG=0 so its flooded to all, expect the pg0 since that's # the ingress link # self.pg0.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[1:]: rx0 = i.get_capture(65, timeout=1) # # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0) # and pg8->12 (SHG=2) # self.pg4.add_stream(p*65) self.pg_enable_capture(self.pg_interfaces) self.pg_start() for i in self.pg_interfaces[:4]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[8:13]: rx0 = i.get_capture(65, timeout=1) for i in self.pg_interfaces[4:8]: i.assert_nothing_captured(remark="Different SH group") # # cleanup # for i in self.pg_interfaces[:12]: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0) for i in self.lo_interfaces: self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI, enable=0) self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
def test_udp_encap(self): """ UDP Encap test """ # # construct a UDP encap object through each of the peers # v4 through the first two peears, v6 through the second. # udp_encap_0 = VppUdpEncap(self, 0, self.pg0.local_ip4, self.pg0.remote_ip4, 330, 440) udp_encap_1 = VppUdpEncap(self, 1, self.pg1.local_ip4, self.pg1.remote_ip4, 331, 441, table_id=1) udp_encap_2 = VppUdpEncap(self, 2, self.pg2.local_ip6, self.pg2.remote_ip6, 332, 442, table_id=2, is_ip6=1) udp_encap_3 = VppUdpEncap(self, 3, self.pg3.local_ip6, self.pg3.remote_ip6, 333, 443, table_id=3, is_ip6=1) udp_encap_0.add_vpp_config() udp_encap_1.add_vpp_config() udp_encap_2.add_vpp_config() udp_encap_3.add_vpp_config() # # 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, is_udp_encap=1, next_hop_id=0)]) route_4o6 = VppIpRoute(self, "1.1.2.1", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=2)]) route_6o4 = VppIpRoute(self, "2001::1", 128, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=1)], is_ip6=1) route_6o6 = VppIpRoute(self, "2001::3", 128, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, is_udp_encap=1, next_hop_id=3)], is_ip6=1) route_4o4.add_vpp_config() route_4o6.add_vpp_config() route_6o6.add_vpp_config() route_6o4.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('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4o4*65, 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) # # 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('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4o6*65, 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) # # 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('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_6o4*65, 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) # # 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('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_6o6*65, 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) # # 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, is_udp_encap=1, 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('\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4omo4*65, 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)
def test_qos_mpls(self): """ QoS Mark MPLS """ # # 255 QoS for all input values # output = [chr(255)] * 256 os = ''.join(output) rows = [{'outputs': os}, {'outputs': os}, {'outputs': os}, {'outputs': os}] self.vapi.qos_egress_map_update(1, rows) # # a route with 1 MPLS label # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[32])]) route_10_0_0_1.add_vpp_config() # # a route with 3 MPLS labels # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[63, 33, 34])]) route_10_0_0_3.add_vpp_config() # # enable IP QoS recording on the input Pg0 and MPLS egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 1) # # packet that will get one label added and 3 labels added resp. # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_3 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.3", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_1 * 65, self.pg1) # # only 3 bits of ToS value in MPLS make sure tos is correct # and the label and EOS bit have not been corrupted # for p in rx: self.assertEqual(p[MPLS].cos, 7) self.assertEqual(p[MPLS].label, 32) self.assertEqual(p[MPLS].s, 1) rx = self.send_and_expect(self.pg0, p_3 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, 7) self.assertEqual(p[MPLS].label, 63) self.assertEqual(p[MPLS].s, 0) h = p[MPLS].payload self.assertEqual(h[MPLS].cos, 7) self.assertEqual(h[MPLS].label, 33) self.assertEqual(h[MPLS].s, 0) h = h[MPLS].payload self.assertEqual(h[MPLS].cos, 7) self.assertEqual(h[MPLS].label, 34) self.assertEqual(h[MPLS].s, 1) # # cleanup # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 0) self.vapi.qos_egress_map_delete(1)
def bier_midpoint(self, hdr_len_id, n_bytes, max_bp): """BIER midpoint""" # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(0, 0, hdr_len_id) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() # # A packet with no bits set gets dropped # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=hdr_len_id) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) / UDP(sport=1234, dport=1234) / Raw()) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, "Empty Bit-String") # # Add a BIER route for each bit-position in the table via a different # next-hop. Testing whether the BIER walk and replicate forwarding # function works for all bit posisitons. # nh_routes = [] bier_routes = [] for i in range(1, max_bp + 1): nh = "10.0.%d.%d" % (i / 255, i % 255) nh_routes.append( VppIpRoute(self, nh, 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(2000 + i)]) ])) nh_routes[-1].add_vpp_config() bier_routes.append( VppBierRoute(self, bti, i, [ VppRoutePath( nh, 0xffffffff, labels=[VppMplsLabel(100 + i)]) ])) bier_routes[-1].add_vpp_config() # # A packet with all bits set gets replicated once for each bit # pkt_sizes = [64, 1400] for pkt_size in pkt_sizes: p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=hdr_len_id, BitString=scapy.compat.chb(255) * n_bytes) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) / UDP(sport=1234, dport=1234) / Raw(scapy.compat.chb(5) * pkt_size)) pkts = p self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(max_bp) for rxp in rx: # # The packets are not required to be sent in bit-position order # when we setup the routes above we used the bit-position to # construct the out-label. so use that here to determine the BP # olabel = rxp[MPLS] bp = olabel.label - 2000 blabel = olabel[MPLS].payload self.assertEqual(blabel.label, 100 + bp) self.assertEqual(blabel.ttl, 254) bier_hdr = blabel[MPLS].payload self.assertEqual(bier_hdr.id, 5) self.assertEqual(bier_hdr.version, 0) self.assertEqual(bier_hdr.length, hdr_len_id) self.assertEqual(bier_hdr.entropy, 0) self.assertEqual(bier_hdr.OAM, 0) self.assertEqual(bier_hdr.RSV, 0) self.assertEqual(bier_hdr.DSCP, 0) self.assertEqual(bier_hdr.Proto, 5) # The bit-string should consist only of the BP given by i. byte_array = [b'\0'] * (n_bytes) byte_val = scapy.compat.chb(1 << (bp - 1) % 8) byte_pos = n_bytes - (((bp - 1) // 8) + 1) byte_array[byte_pos] = byte_val bitstring = ''.join([scapy.compat.chb(x) for x in byte_array]) self.assertEqual(len(bitstring), len(bier_hdr.BitString)) self.assertEqual(bitstring, bier_hdr.BitString) # # cleanup. not strictly necessary, but it's much quicker this way # because the bier_fib_dump and ip_fib_dump will be empty when the # auto-cleanup kicks in # for br in bier_routes: br.remove_vpp_config() for nhr in nh_routes: nhr.remove_vpp_config()
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_bier_tail_o_udp(self): """BIER Tail over UDP""" # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(1, 0, BIERLength.BIER_LEN_256) bt = VppBierTable(self, bti, MPLS_LABEL_INVALID) bt.add_vpp_config() # # disposition table # bdt = VppBierDispTable(self, 8) bdt.add_vpp_config() # # BIER route in table that's for-us # bier_route_1 = VppBierRoute(self, bti, 1, [ VppRoutePath("0.0.0.0", 0xffffffff, proto=DpoProto.DPO_PROTO_BIER, nh_table_id=8) ]) bier_route_1.add_vpp_config() # # An entry in the disposition table # bier_de_1 = VppBierDispEntry(self, bdt.id, 99, BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4, DpoProto.DPO_PROTO_BIER, "0.0.0.0", 0, rpf_id=8192) bier_de_1.add_vpp_config() # # A multicast route to forward post BIER disposition # route_eg_232_1_1_1 = VppIpMRoute( self, "0.0.0.0", "232.1.1.1", 32, MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(self.pg1.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_FORWARD) ]) route_eg_232_1_1_1.add_vpp_config() route_eg_232_1_1_1.update_rpf_id(8192) # # A packet with all bits set gets spat out to BP:1 # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=333, dport=8138) / BIFT(sd=1, set=0, bsl=2, ttl=255) / BIER(length=BIERLength.BIER_LEN_256, BitString=scapy.compat.chb(255) * 32, BFRID=99) / IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw()) rx = self.send_and_expect(self.pg0, [p], self.pg1)
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_bier_load_balance(self): """BIER load-balance""" # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_64) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() # # packets with varying entropy # pkts = [] for ii in range(257): pkts.append( (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_64, entropy=ii, BitString=scapy.compat.chb(255) * 16) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) / UDP(sport=1234, dport=1234) / Raw())) # # 4 next hops # nhs = [{ 'ip': "10.0.0.1", 'label': 201 }, { 'ip': "10.0.0.2", 'label': 202 }, { 'ip': "10.0.0.3", 'label': 203 }, { 'ip': "10.0.0.4", 'label': 204 }] for nh in nhs: ipr = VppIpRoute(self, nh['ip'], 32, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(nh['label'])]) ]) ipr.add_vpp_config() bier_route = VppBierRoute(self, bti, 1, [ VppRoutePath(nhs[0]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[1]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]) ]) bier_route.add_vpp_config() rx = self.send_and_expect(self.pg0, pkts, self.pg1) # # we should have recieved a packet from each neighbor # for nh in nhs[:2]: self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) # # add the other paths # bier_route.update_paths([ VppRoutePath(nhs[0]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[1]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[2]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]), VppRoutePath(nhs[3]['ip'], 0xffffffff, labels=[VppMplsLabel(101)]) ]) rx = self.send_and_expect(self.pg0, pkts, self.pg1) for nh in nhs: self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) # # remove first two paths # bier_route.remove_path( VppRoutePath(nhs[0]['ip'], 0xffffffff, labels=[VppMplsLabel(101)])) bier_route.remove_path( VppRoutePath(nhs[1]['ip'], 0xffffffff, labels=[VppMplsLabel(101)])) rx = self.send_and_expect(self.pg0, pkts, self.pg1) for nh in nhs[2:]: self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) # # remove the last of the paths, deleteing the entry # bier_route.remove_all_paths() self.send_and_assert_no_replies(self.pg0, pkts)
def test_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_bier_tail(self): """BIER Tail""" MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t # # Add a BIER table for sub-domain 0, set 0, and BSL 256 # bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_256) bt = VppBierTable(self, bti, 77) bt.add_vpp_config() # # disposition table # bdt = VppBierDispTable(self, 8) bdt.add_vpp_config() # # BIER route in table that's for-us # bier_route_1 = VppBierRoute(self, bti, 1, [ VppRoutePath("0.0.0.0", 0xffffffff, proto=FibPathProto.FIB_PATH_NH_PROTO_BIER, nh_table_id=8) ]) bier_route_1.add_vpp_config() # # An entry in the disposition table # bier_de_1 = VppBierDispEntry(self, bdt.id, 99, BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4, FibPathProto.FIB_PATH_NH_PROTO_BIER, "0.0.0.0", 0, rpf_id=8192) bier_de_1.add_vpp_config() # # A multicast route to forward post BIER disposition # route_eg_232_1_1_1 = VppIpMRoute( self, "0.0.0.0", "232.1.1.1", 32, MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD) ]) route_eg_232_1_1_1.add_vpp_config() route_eg_232_1_1_1.update_rpf_id(8192) # # A packet with all bits set gets spat out to BP:1 # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_256, BitString=scapy.compat.chb(255) * 32, BFRID=99) / IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw()) self.send_and_expect(self.pg0, [p], self.pg1) # # A packet that does not match the Disposition entry gets dropped # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_256, BitString=scapy.compat.chb(255) * 32, BFRID=77) / IP(src="1.1.1.1", dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw()) self.send_and_assert_no_replies(self.pg0, p * 2, "no matching disposition entry") # # Add the default route to the disposition table # bier_de_2 = VppBierDispEntry(self, bdt.id, 0, BIER_HDR_PAYLOAD.BIER_HDR_PROTO_IPV4, FibPathProto.FIB_PATH_NH_PROTO_BIER, "0.0.0.0", 0, rpf_id=8192) bier_de_2.add_vpp_config() # # now the previous packet is forwarded # self.send_and_expect(self.pg0, [p], self.pg1) # # A multicast route to forward post BIER disposition that needs # a check against sending back into the BIER core # bi = VppBierImp(self, bti, 333, scapy.compat.chb(0x3) * 32) bi.add_vpp_config() route_eg_232_1_1_2 = VppIpMRoute( self, "0.0.0.0", "232.1.1.2", 32, MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE, paths=[ VppMRoutePath(0xffffffff, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD, proto=DpoProto.DPO_PROTO_BIER, type=FibPathType.FIB_PATH_TYPE_BIER_IMP, bier_imp=bi.bi_index), VppMRoutePath(self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD) ]) route_eg_232_1_1_2.add_vpp_config() route_eg_232_1_1_2.update_rpf_id(8192) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / MPLS(label=77, ttl=255) / BIER(length=BIERLength.BIER_LEN_256, BitString=scapy.compat.chb(255) * 32, BFRID=77) / IP(src="1.1.1.1", dst="232.1.1.2") / UDP(sport=1234, dport=1234) / Raw()) self.send_and_expect(self.pg0, [p], self.pg1)
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()