def test_arp_static(self): """ ARP Static""" self.pg2.generate_remote_hosts(3) # # Add a static ARP entry # static_arp = VppNeighbor(self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].mac, self.pg2.remote_hosts[1].ip4, is_static=1) static_arp.add_vpp_config() # # Add the connected prefix to the interface # self.pg2.config_ip4() # # We should now find the adj-fib # self.assertTrue(find_nbr(self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].ip4, is_static=1)) self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32)) # # remove the connected # self.pg2.unconfig_ip4() # # put the interface into table 1 # self.pg2.set_table_ip4(1) # # configure the same connected and expect to find the # adj fib in the new table # self.pg2.config_ip4() self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1)) # # clean-up # self.pg2.unconfig_ip4() self.pg2.set_table_ip4(0)
def test_gbp(self): """ Group Based Policy """ nat_table = VppIpTable(self, 20) nat_table.add_vpp_config() nat_table = VppIpTable(self, 20, is_ip6=True) nat_table.add_vpp_config() # # Bridge Domains # self.vapi.bridge_domain_add_del(1, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) self.vapi.bridge_domain_add_del(2, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) self.vapi.bridge_domain_add_del(20, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) # # 3 EPGs, 2 of which share a BD. # epgs = [] recircs = [] epgs.append( VppGbpEndpointGroup(self, 220, 0, 1, self.pg4, self.loop0, "10.0.0.128", "2001:10::128")) recircs.append(VppGbpRecirc(self, epgs[0], self.loop3)) epgs.append( VppGbpEndpointGroup(self, 221, 0, 1, self.pg5, self.loop0, "10.0.1.128", "2001:10:1::128")) recircs.append(VppGbpRecirc(self, epgs[1], self.loop4)) epgs.append( VppGbpEndpointGroup(self, 222, 0, 2, self.pg6, self.loop1, "10.0.2.128", "2001:10:2::128")) recircs.append(VppGbpRecirc(self, epgs[2], self.loop5)) # # 2 NAT EPGs, one for floating-IP subnets, the other for internet # epgs.append( VppGbpEndpointGroup(self, 333, 20, 20, self.pg7, self.loop2, "11.0.0.128", "3001::128")) recircs.append(VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True)) epgs.append( VppGbpEndpointGroup(self, 444, 20, 20, self.pg8, self.loop2, "11.0.0.129", "3001::129")) recircs.append(VppGbpRecirc(self, epgs[4], self.loop8, is_ext=True)) epg_nat = epgs[3] recirc_nat = recircs[3] # # 4 end-points, 2 in the same subnet, 3 in the same BD # eps = [] eps.append( VppGbpEndpoint(self, self.pg0, epgs[0], recircs[0], "10.0.0.1", "11.0.0.1")) eps.append( VppGbpEndpoint(self, self.pg1, epgs[0], recircs[0], "10.0.0.2", "11.0.0.2")) eps.append( VppGbpEndpoint(self, self.pg2, epgs[1], recircs[1], "10.0.1.1", "11.0.0.3")) eps.append( VppGbpEndpoint(self, self.pg3, epgs[2], recircs[2], "10.0.2.1", "11.0.0.4")) eps.append( VppGbpEndpoint(self, self.pg0, epgs[0], recircs[0], "2001:10::1", "3001::1", is_ip6=True)) eps.append( VppGbpEndpoint(self, self.pg1, epgs[0], recircs[0], "2001:10::2", "3001::2", is_ip6=True)) eps.append( VppGbpEndpoint(self, self.pg2, epgs[1], recircs[1], "2001:10:1::1", "3001::3", is_ip6=True)) eps.append( VppGbpEndpoint(self, self.pg3, epgs[2], recircs[2], "2001:10:2::1", "3001::4", is_ip6=True)) # # Config related to each of the EPGs # for epg in epgs: # IP config on the BVI interfaces if epg != epgs[1] and epg != epgs[4]: epg.bvi.set_table_ip4(epg.rd) epg.bvi.set_table_ip6(epg.rd) # The BVIs are NAT inside interfaces self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index, is_inside=1, is_add=1) self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index, is_inside=1, is_add=1) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip4_n, 32) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip6_n, 128, is_ipv6=True) # EPG uplink interfaces in the BD epg.uplink.set_table_ip4(epg.rd) epg.uplink.set_table_ip6(epg.rd) self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index, epg.bd) # add the BD ARP termination entry for BVI IP self.vapi.bd_ip_mac_add_del(bd_id=epg.bd, mac=mactobinary(self.router_mac), ip=epg.bvi_ip4_n, is_ipv6=0, is_add=1) self.vapi.bd_ip_mac_add_del(bd_id=epg.bd, mac=mactobinary(self.router_mac), ip=epg.bvi_ip6_n, is_ipv6=1, is_add=1) # epg[1] shares the same BVI to epg[0] if epg != epgs[1] and epg != epgs[4]: # BVI in BD self.vapi.sw_interface_set_l2_bridge(epg.bvi.sw_if_index, epg.bd, bvi=1) # BVI L2 FIB entry self.vapi.l2fib_add_del(self.router_mac, epg.bd, epg.bvi.sw_if_index, is_add=1, bvi_mac=1) # EPG in VPP epg.add_vpp_config() for recirc in recircs: # EPG's ingress recirculation interface maps to its RD recirc.recirc.set_table_ip4(recirc.epg.rd) recirc.recirc.set_table_ip6(recirc.epg.rd) # in the bridge to allow DVR. L2 emulation to punt to L3 self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index, recirc.epg.bd) self.vapi.sw_interface_set_l2_emulation(recirc.recirc.sw_if_index) self.vapi.nat44_interface_add_del_feature( recirc.recirc.sw_if_index, is_inside=0, is_add=1) self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index, is_inside=0, is_add=1) recirc.add_vpp_config() ep_routes = [] ep_arps = [] for ep in eps: self.pg_enable_capture(self.pg_interfaces) self.pg_start() # # routes to the endpoints. We need these since there are no # adj-fibs due to the fact the the BVI address has /32 and # the subnet is not attached. # r = VppIpRoute( self, ep.ip, ep.ip_len, [VppRoutePath(ep.ip, ep.epg.bvi.sw_if_index, proto=ep.proto)], is_ip6=ep.is_ip6) r.add_vpp_config() ep_routes.append(r) # # ARP entries for the endpoints # a = VppNeighbor(self, ep.epg.bvi.sw_if_index, ep.itf.remote_mac, ep.ip, af=ep.af) a.add_vpp_config() ep_arps.append(a) # add each EP itf to the its BD self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index, ep.epg.bd) # add the BD ARP termination entry self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd, mac=ep.bin_mac, ip=ep.ip_n, is_ipv6=0, is_add=1) # L2 FIB entry self.vapi.l2fib_add_del(ep.mac, ep.epg.bd, ep.itf.sw_if_index, is_add=1) # Add static mappings for each EP from the 10/8 to 11/8 network if ep.af == AF_INET: self.vapi.nat44_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0, addr_only=1) else: self.vapi.nat66_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0) # VPP EP create ... ep.add_vpp_config() # ... results in a Gratuitous ARP/ND on the EPG's uplink rx = ep.epg.uplink.get_capture(1, timeout=0.2) if ep.is_ip6: self.assertTrue(rx[0].haslayer(ICMPv6ND_NA)) self.assertEqual(rx[0][ICMPv6ND_NA].tgt, ep.ip) else: self.assertTrue(rx[0].haslayer(ARP)) self.assertEqual(rx[0][ARP].psrc, ep.ip) self.assertEqual(rx[0][ARP].pdst, ep.ip) # add the BD ARP termination entry for floating IP self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd, mac=ep.bin_mac, ip=ep.floating_ip_n, is_ipv6=ep.is_ip6, is_add=1) # floating IPs route via EPG recirc r = VppIpRoute(self, ep.floating_ip, ep.ip_len, [ VppRoutePath(ep.floating_ip, ep.recirc.recirc.sw_if_index, is_dvr=1, proto=ep.proto) ], table_id=20, is_ip6=ep.is_ip6) r.add_vpp_config() ep_routes.append(r) # L2 FIB entries in the NAT EPG BD to bridge the packets from # the outside direct to the internal EPG self.vapi.l2fib_add_del(ep.mac, epg_nat.bd, ep.recirc.recirc.sw_if_index, is_add=1) # # ARP packets for unknown IP are flooded # pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.pg0.remote_mac, pdst=epgs[0].bvi_ip4, psrc="10.0.0.88")) self.send_and_expect(self.pg0, [pkt_arp], self.pg0) # # ARP/ND packets get a response # pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.pg0.remote_mac, pdst=epgs[0].bvi_ip4, psrc=eps[0].ip)) self.send_and_expect(self.pg0, [pkt_arp], self.pg0) nsma = in6_getnsma(inet_pton(AF_INET6, eps[4].ip)) d = inet_ntop(AF_INET6, nsma) pkt_nd = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=eps[4].ip) / ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) self.send_and_expect(self.pg0, [pkt_nd], self.pg0) # # broadcast packets are flooded # pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / IP(src=eps[0].ip, dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.vapi.cli("clear trace") self.pg0.add_stream(pkt_bcast) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = eps[1].itf.get_capture(1) self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) rxd = epgs[0].uplink.get_capture(1) self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) # # packets to non-local L3 destinations dropped # pkt_intra_epg_220_ip4 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_222_ip4 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst="10.0.1.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65) pkt_inter_epg_222_ip6 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[4].ip, dst="2001:10::99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65) # # Add the subnet routes # s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24) s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24) s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24) s41.add_vpp_config() s42.add_vpp_config() s43.add_vpp_config() s61 = VppGbpSubnet(self, 0, "2001:10::1", 64, is_ip6=True) s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64, is_ip6=True) s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64, is_ip6=True) s61.add_vpp_config() s62.add_vpp_config() s63.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_ip4 * 65, self.pg4) self.send_and_expect_bridged(self.pg3, pkt_inter_epg_222_ip4 * 65, self.pg6) self.send_and_expect_bridged6(self.pg3, pkt_inter_epg_222_ip6 * 65, self.pg6) self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2")) self.logger.info(self.vapi.cli("sh gbp endpoint-group")) self.logger.info(self.vapi.cli("sh gbp endpoint")) self.logger.info(self.vapi.cli("sh gbp recirc")) self.logger.info(self.vapi.cli("sh int")) self.logger.info(self.vapi.cli("sh int addr")) self.logger.info(self.vapi.cli("sh int feat loop6")) self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify")) self.logger.info(self.vapi.cli("sh int feat loop3")) # # Packet destined to unknown unicast is sent on the epg uplink ... # pkt_intra_epg_220_to_uplink = ( Ether(src=self.pg0.remote_mac, dst="00:00:00:33:44:55") / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_to_uplink * 65, self.pg4) # ... and nowhere else self.pg1.get_capture(0, timeout=0.1) self.pg1.assert_nothing_captured(remark="Flood onto other VMS") pkt_intra_epg_221_to_uplink = ( Ether(src=self.pg2.remote_mac, dst="00:00:00:33:44:66") / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg2, pkt_intra_epg_221_to_uplink * 65, self.pg5) # # Packets from the uplink are forwarded in the absence of a contract # pkt_intra_epg_220_from_uplink = ( Ether(src="00:00:00:33:44:55", dst=self.pg0.remote_mac) / IP(src=eps[0].ip, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg4, pkt_intra_epg_220_from_uplink * 65, self.pg0) # # in the absence of policy, endpoints in the same EPG # can communicate # pkt_intra_epg = ( Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src=eps[0].ip, dst=eps[1].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1) # # in the abscense of policy, endpoints in the different EPG # cannot communicate # pkt_inter_epg_220_to_221 = ( Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) / IP(src=eps[0].ip, dst=eps[2].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_221_to_220 = ( Ether(src=self.pg2.remote_mac, dst=self.pg0.remote_mac) / IP(src=eps[2].ip, dst=eps[0].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_220_to_222 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst=eps[3].ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221 * 65) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # A uni-directional contract from EPG 220 -> 221 # c1 = VppGbpContract(self, 220, 221, 0) c1.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65, self.pg2) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # contract for the return direction # c2 = VppGbpContract(self, 221, 220, 0) c2.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65, self.pg2) self.send_and_expect_bridged(self.pg2, pkt_inter_epg_221_to_220 * 65, self.pg0) # # check that inter group is still disabled for the groups # not in the contract. # self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # A uni-directional contract from EPG 220 -> 222 'L3 routed' # c3 = VppGbpContract(self, 220, 222, 0) c3.add_vpp_config() self.logger.info(self.vapi.cli("sh gbp contract")) self.send_and_expect_routed(self.pg0, pkt_inter_epg_220_to_222 * 65, self.pg3, self.router_mac) # # remove both contracts, traffic stops in both directions # c2.remove_vpp_config() c1.remove_vpp_config() c3.remove_vpp_config() self.send_and_assert_no_replies(self.pg2, pkt_inter_epg_221_to_220 * 65) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221 * 65) self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1) # # EPs to the outside world # # in the EP's RD an external subnet via the NAT EPG's recirc se1 = VppGbpSubnet(self, 0, "0.0.0.0", 0, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se1.add_vpp_config() se2 = VppGbpSubnet(self, 0, "11.0.0.0", 8, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se2.add_vpp_config() se16 = VppGbpSubnet(self, 0, "::", 0, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg, is_ip6=True) se16.add_vpp_config() # in the NAT RD an external subnet via the NAT EPG's uplink se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se36 = VppGbpSubnet(self, 20, "::", 0, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg, is_ip6=True) se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se3.add_vpp_config() se36.add_vpp_config() se4.add_vpp_config() self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0")) self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1")) self.logger.info(self.vapi.cli("sh ip6 fib ::/0")) self.logger.info(self.vapi.cli("sh ip6 fib %s" % eps[4].floating_ip)) # # From an EP to an outside addess: IN2OUT # pkt_inter_epg_220_to_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # no policy yet self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_global * 65) c4 = VppGbpContract(self, 220, 333, 0) c4.add_vpp_config() self.send_and_expect_natted(self.pg0, pkt_inter_epg_220_to_global * 65, self.pg7, eps[0].floating_ip) pkt_inter_epg_220_to_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[4].ip, dst="6001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_natted6(self.pg0, pkt_inter_epg_220_to_global * 65, self.pg7, eps[4].floating_ip) # # From a global address to an EP: OUT2IN # pkt_inter_epg_220_from_global = ( Ether(src=self.router_mac, dst=self.pg0.remote_mac) / IP(dst=eps[0].floating_ip, src="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg7, pkt_inter_epg_220_from_global * 65) c5 = VppGbpContract(self, 333, 220, 0) c5.add_vpp_config() self.send_and_expect_unnatted(self.pg7, pkt_inter_epg_220_from_global * 65, eps[0].itf, eps[0].ip) pkt_inter_epg_220_from_global = ( Ether(src=self.router_mac, dst=self.pg0.remote_mac) / IPv6(dst=eps[4].floating_ip, src="6001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_unnatted6(self.pg7, pkt_inter_epg_220_from_global * 65, eps[4].itf, eps[4].ip) # # From a local VM to another local VM using resp. public addresses: # IN2OUT2IN # pkt_intra_epg_220_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip, dst=eps[1].floating_ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_double_natted(eps[0].itf, pkt_intra_epg_220_global * 65, eps[1].itf, eps[0].floating_ip, eps[1].ip) pkt_intra_epg_220_global = ( Ether(src=self.pg4.remote_mac, dst=self.router_mac) / IPv6(src=eps[4].ip, dst=eps[5].floating_ip) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_double_natted6(eps[4].itf, pkt_intra_epg_220_global * 65, eps[5].itf, eps[4].floating_ip, eps[5].ip) # # cleanup # for ep in eps: # del static mappings for each EP from the 10/8 to 11/8 network if ep.af == AF_INET: self.vapi.nat44_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0, addr_only=1, is_add=0) else: self.vapi.nat66_add_del_static_mapping(ep.ip_n, ep.floating_ip_n, vrf_id=0, is_add=0) for epg in epgs: # IP config on the BVI interfaces self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip4_n, 32, is_add=0) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip6_n, 128, is_add=0, is_ipv6=True) self.logger.info(self.vapi.cli("sh int addr")) epg.uplink.set_table_ip4(0) epg.uplink.set_table_ip6(0) if epg != epgs[0] and epg != epgs[3]: epg.bvi.set_table_ip4(0) epg.bvi.set_table_ip6(0) self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index, is_inside=1, is_add=0) self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index, is_inside=1, is_add=0) for recirc in recircs: recirc.recirc.set_table_ip4(0) recirc.recirc.set_table_ip6(0) self.vapi.nat44_interface_add_del_feature( recirc.recirc.sw_if_index, is_inside=0, is_add=0) self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index, is_inside=0, is_add=0)
def test_arp_duplicates(self): """ ARP Duplicates""" # # Generate some hosts on the LAN # self.pg1.generate_remote_hosts(3) # # Add host 1 on pg1 and pg2 # arp_pg1 = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) arp_pg1.add_vpp_config() arp_pg2 = VppNeighbor(self, self.pg2.sw_if_index, self.pg2.remote_mac, self.pg1.remote_hosts[1].ip4) arp_pg2.add_vpp_config() # # IP packet destined for pg1 remote host arrives on pg1 again. # 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() rx1 = self.pg1.get_capture(1) self.verify_ip(rx1[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1.remote_hosts[1].ip4) # # remove the duplicate on pg1 # packet stream shoud generate ARPs out of pg1 # arp_pg1.remove_vpp_config() self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx1 = self.pg1.get_capture(1) self.verify_arp_req(rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4) # # Add it back # arp_pg1.add_vpp_config() self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx1 = self.pg1.get_capture(1) self.verify_ip(rx1[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1.remote_hosts[1].ip4)
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_arp(self): """ ARP """ # # Generate some hosts on the LAN # self.pg1.generate_remote_hosts(4) # # 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)) # # ERROR Cases # 1 - don't respond to ARP request for address not within the # 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, 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") # # 2 - don't respond to ARP request from an address not within the # 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") # # 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 # the router # 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") # # cleanup # dyn_arp.remove_vpp_config() static_arp.remove_vpp_config()
def test_dhcp6_proxy(self): """ DHCPv6 Proxy""" # # Verify no response to DHCP request without DHCP config # dhcp_solicit_dst = "ff02::1:2" dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg2.remote_mac) dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg3.remote_mac) server_addr_vrf0 = self.pg0.remote_ip6n src_addr_vrf0 = self.pg0.local_ip6n server_addr_vrf1 = self.pg1.remote_ip6n src_addr_vrf1 = self.pg1.local_ip6n dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst)) p_solicit_vrf0 = ( Ether(dst=dmac, src=self.pg2.remote_mac) / IPv6(src=dhcp_solicit_src_vrf0, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) p_solicit_vrf1 = ( Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # # DHCPv6 config in VRF 0. # Packets still dropped because the client facing interface has no # IPv6 config # self.vapi.dhcp_proxy_config(server_addr_vrf0, src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1) self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # # configure an IP address on the client facing interface # self.pg2.config_ip6() # # Now the DHCP requests are relayed to the server # self.pg2.add_stream(p_solicit_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg0, dhcp_solicit_src_vrf0, self.pg2.remote_mac) # # Exception cases for rejected relay responses # # 1 - not a relay reply p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 not a relay reply") # 2 - no relay message option p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP not a relay message") # 3 - no circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 no circuit ID") # 4 - wrong circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 wrong circuit ID") # # Send the relay response (the advertisement) # - no peer address p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts_adv_vrf0 = [p_adv_vrf0] self.pg0.add_stream(pkts_adv_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_dhcp6_advert(rx[0], self.pg2, "::") # # Send the relay response (the advertisement) # - with peer address p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts_adv_vrf0 = [p_adv_vrf0] self.pg0.add_stream(pkts_adv_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0) # # Add all the config for VRF 1 # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1) self.pg3.config_ip6() # # VRF 1 solicit # self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # # VRF 1 Advert # p_adv_vrf1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts_adv_vrf1 = [p_adv_vrf1] self.pg1.add_stream(pkts_adv_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(1) self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) # # Add VSS config # table=1, fib=id=1, oui=4 self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1) self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac, fib_id=1, oui=4) # # Remove the VSS config # relayed DHCP has default vlaues in the option. # self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0) self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # # Add a second DHCP server in VRF 1 # expect clients messages to be relay to both configured servers # self.pg1.generate_remote_hosts(2) server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6) self.vapi.dhcp_proxy_config(server_addr2, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1) # # We'll need an ND entry for the server to send it packets # nd_entry = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip6, af=AF_INET6) nd_entry.add_vpp_config() # # Send a discover from the client. expect two relayed messages # The frist packet is sent to the second server # We're not enforcing that here, it's just the way it is. # self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(2) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) self.verify_dhcp6_solicit(rx[1], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip6) # # Send both packets back. Client gets both. # p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts = [p1, p2] self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(2) self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) self.verify_dhcp6_advert(rx[1], self.pg3, dhcp_solicit_src_vrf1) # # Ensure only solicit messages are duplicated # p_request_vrf1 = ( Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Request()) self.pg3.add_stream(p_request_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Test we drop DHCP packets from addresses that are not configured as # DHCP servers # p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / IPv6(dst=self.pg1.local_ip6, src="3001::1") / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) self.send_and_assert_no_replies(self.pg1, p2, "DHCP6 not from server") # # Remove the second DHCP server # self.vapi.dhcp_proxy_config(server_addr2, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1, is_add=0) # # Test we can still relay with the first # self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # # Cleanup # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1, is_add=0) self.vapi.dhcp_proxy_config(server_addr_vrf0, src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1, is_add=0) # duplicate delete self.vapi.dhcp_proxy_config(server_addr_vrf0, src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1, is_add=0) self.pg2.unconfig_ip6() self.pg3.unconfig_ip6()
def test_dhcp_proxy(self): """ DHCPv4 Proxy """ # # Verify no response to DHCP request without DHCP config # p_disc_vrf0 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'discover'), ('end')])) pkts_disc_vrf0 = [p_disc_vrf0] p_disc_vrf1 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg3.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'discover'), ('end')])) pkts_disc_vrf1 = [p_disc_vrf0] self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP with no configuration") self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP with no configuration") # # Enable DHCP proxy in VRF 0 # server_addr = self.pg0.remote_ip4n src_addr = self.pg0.local_ip4n self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=0) # # Discover packets from the client are dropped because there is no # IP address configured on the client facing interface # self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "Discover DHCP no relay address") # # Inject a response from the server # dropped, because there is no IP addrees on the # client interfce to fill in the option. # 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=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('end')])) pkts = [p] self.send_and_assert_no_replies(self.pg2, pkts, "Offer DHCP no relay address") # # configure an IP address on the client facing interface # self.pg2.config_ip4() # # Try again with a discover packet # Rx'd packet should be to the server address and from the configured # source address # UDP source ports are unchanged # we've no option 82 config so that should be absent # self.pg2.add_stream(pkts_disc_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0, src_intf=self.pg2) # # Create an DHCP offer reply from the server with a correctly formatted # option 82. i.e. send back what we just captured # The offer, sent mcast to the client, still has option 82. # 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=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) pkts = [p] self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) rx = rx[0] self.verify_dhcp_offer(rx, self.pg2) # # Bogus Option 82: # # 1. not our IP address = not checked by VPP? so offer is replayed # to client bad_ip = option_82[0:8] + chr(33) + option_82[9:] 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=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', bad_ip), ('end')])) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, "DHCP offer option 82 bad address") # 2. Not a sw_if_index VPP knows bad_if_index = option_82[0:2] + chr(33) + option_82[3:] 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=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', bad_if_index), ('end')])) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, "DHCP offer option 82 bad if index") # # Send a DHCP request in VRF 1. should be dropped. # self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP with no configuration VRF 1") # # Delete the DHCP config in VRF 0 # Should now drop requests. # self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=0, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP config removed VRF 0") self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP config removed VRF 1") # # Add DHCP config for VRF 1 # server_addr = self.pg1.remote_ip4n src_addr = self.pg1.local_ip4n self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, server_table_id=1) # # Confim DHCP requests ok in VRF 1. # - dropped on IP config on client interface # self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP config removed VRF 1") # # configure an IP address on the client facing interface # self.pg3.config_ip4() self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) # # Add VSS config # table=1, fib=id=1, oui=4 self.vapi.dhcp_proxy_set_vss(1, 1, 4) self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3, fib_id=1, oui=4) # # Add a second DHCP server in VRF 1 # expect clients messages to be relay to both configured servers # self.pg1.generate_remote_hosts(2) server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4) self.vapi.dhcp_proxy_config(server_addr2, src_addr, rx_table_id=1, server_table_id=1, is_add=1) # # We'll need an ARP entry for the server to send it packets # arp_entry = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) arp_entry.add_vpp_config() # # Send a discover from the client. expect two relayed messages # The frist packet is sent to the second server # We're not enforcing that here, it's just the way it is. # self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(2) option_82 = self.verify_relayed_dhcp_discover( rx[0], self.pg1, src_intf=self.pg3, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip4, fib_id=1, oui=4) self.verify_relayed_dhcp_discover(rx[1], self.pg1, src_intf=self.pg3, fib_id=1, oui=4) # # Send both packets back. Client gets both. # p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) pkts = [p1, p2] self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(2) self.verify_dhcp_offer(rx[0], self.pg3, fib_id=1, oui=4) self.verify_dhcp_offer(rx[1], self.pg3, fib_id=1, oui=4) # # Ensure offers from non-servers are dropeed # p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src="8.8.8.8", dst=self.pg1.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) self.send_and_assert_no_replies(self.pg1, p2, "DHCP offer from non-server") # # Ensure only the discover is sent to multiple servers # p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg3.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'request'), ('end')])) self.pg3.add_stream(p_req_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Remove the second DHCP server # self.vapi.dhcp_proxy_config(server_addr2, src_addr, rx_table_id=1, server_table_id=1, is_add=0) # # Test we can still relay with the first # self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3, fib_id=1, oui=4) # # Remove the VSS config # relayed DHCP has default vlaues in the option. # self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_add=0) self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) # # remove DHCP config to cleanup # self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, server_table_id=1, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP cleanup VRF 0") self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP cleanup VRF 1") self.pg2.unconfig_ip4() self.pg3.unconfig_ip4()
def test_garp(self): """ GARP """ # # Generate some hosts on the LAN # self.pg1.generate_remote_hosts(4) # # And an ARP entry # arp = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) arp.add_vpp_config() self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].ip4, mac=self.pg1.remote_hosts[1].mac)) # # Send a GARP (request) to swap the host 1's address to that of host 2 # p1 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) / ARP(op="who-has", hwdst=self.pg1.local_mac, hwsrc=self.pg1.remote_hosts[2].mac, pdst=self.pg1.remote_hosts[1].ip4, psrc=self.pg1.remote_hosts[1].ip4)) self.pg1.add_stream(p1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].ip4, mac=self.pg1.remote_hosts[2].mac)) # # Send a GARP (reply) to swap the host 1's address to that of host 3 # p1 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(op="is-at", hwdst=self.pg1.local_mac, hwsrc=self.pg1.remote_hosts[3].mac, pdst=self.pg1.remote_hosts[1].ip4, psrc=self.pg1.remote_hosts[1].ip4)) self.pg1.add_stream(p1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].ip4, mac=self.pg1.remote_hosts[3].mac)) # # GARPs (requets nor replies) for host we don't know yet # don't result in new neighbour entries # p1 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(op="who-has", hwdst=self.pg1.local_mac, hwsrc=self.pg1.remote_hosts[3].mac, pdst=self.pg1.remote_hosts[2].ip4, psrc=self.pg1.remote_hosts[2].ip4)) self.pg1.add_stream(p1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.assertFalse( find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)) p1 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(op="is-at", hwdst=self.pg1.local_mac, hwsrc=self.pg1.remote_hosts[3].mac, pdst=self.pg1.remote_hosts[2].ip4, psrc=self.pg1.remote_hosts[2].ip4)) self.pg1.add_stream(p1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.assertFalse( find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4))
def test_arp_incomplete(self): """ ARP Incomplete""" self.pg1.generate_remote_hosts(3) p0 = (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()) p1 = (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()) # # a packet to an unresolved destination generates an ARP request # rx = self.send_and_expect(self.pg0, [p0], self.pg1) self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4) # # add a neighbour for remote host 1 # static_arp = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4, is_static=1) static_arp.add_vpp_config() # # change the interface's MAC # mac = [ chr(0x00), chr(0x00), chr(0x00), chr(0x33), chr(0x33), chr(0x33) ] mac_string = ''.join(mac) self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index, mac_string) # # now ARP requests come from the new source mac # rx = self.send_and_expect(self.pg0, [p1], self.pg1) self.verify_arp_req(rx[0], "00:00:00:33:33:33", self.pg1.local_ip4, self.pg1._remote_hosts[2].ip4) # # packets to the resolved host also have the new source mac # rx = self.send_and_expect(self.pg0, [p0], self.pg1) self.verify_ip(rx[0], "00:00:00:33:33:33", self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1.remote_hosts[1].ip4) # # set the mac address on the inteface that does not have a # configured subnet and thus no glean # self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index, mac_string)
def test_udp_decap(self): """ UDP Decap test """ # # construct a UDP decap object for each type of protocol # # IPv4 udp_api_proto = VppEnum.vl_api_udp_decap_next_proto_t next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP4 udp_decap_0 = VppUdpDecap(self, 1, 220, next_proto) # IPv6 next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP6 udp_decap_1 = VppUdpDecap(self, 0, 221, next_proto) # MPLS next_proto = udp_api_proto.UDP_API_DECAP_PROTO_MPLS udp_decap_2 = VppUdpDecap(self, 1, 222, next_proto) udp_decap_0.add_vpp_config() udp_decap_1.add_vpp_config() udp_decap_2.add_vpp_config() # # Routes via the corresponding pg after the UDP decap # route_4 = VppIpRoute(self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)], table_id=0) route_6 = VppIpRoute(self, "2001::1", 128, [VppRoutePath("::", self.pg1.sw_if_index)], table_id=1) route_mo4 = VppIpRoute(self, "3.3.3.3", 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)], table_id=2) route_4.add_vpp_config() route_6.add_vpp_config() route_mo4.add_vpp_config() # # Adding neighbors to route the packets # n_4 = VppNeighbor(self, self.pg0.sw_if_index, "00:11:22:33:44:55", "1.1.1.1") n_6 = VppNeighbor(self, self.pg1.sw_if_index, "11:22:33:44:55:66", "2001::1") n_mo4 = VppNeighbor(self, self.pg2.sw_if_index, "22:33:44:55:66:77", "3.3.3.3") n_4.add_vpp_config() n_6.add_vpp_config() n_mo4.add_vpp_config() # # MPLS decapsulation config # mpls_table = VppMplsTable(self, 0) mpls_table.add_vpp_config() mpls_route = VppMplsRoute(self, 77, 1, [ VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=2, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) mpls_route.add_vpp_config() # # UDP over ipv4 decap # p_4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=1111, dport=220) / IP(src="2.2.2.2", dst="1.1.1.1") / UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, p_4 * NUM_PKTS, self.pg0) p_4 = IP(p_4["UDP"].payload) for p in rx: p = IP(p["Ether"].payload) self.validate_inner4(p, p_4, ttl=63) # # UDP over ipv6 decap # p_6 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6) / UDP(sport=2222, dport=221) / IPv6(src="2001::100", dst="2001::1") / UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg1, p_6 * NUM_PKTS, self.pg1) p_6 = IPv6(p_6["UDP"].payload) p = IPv6(rx[0]["Ether"].payload) for p in rx: p = IPv6(p["Ether"].payload) self.validate_inner6(p, p_6, hlim=63) # # UDP over mpls decap # p_mo4 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / UDP(sport=3333, dport=222) / MPLS(label=77, ttl=1) / IP(src="4.4.4.4", dst="3.3.3.3") / UDP(sport=1234, dport=4321) / Raw(b'\xa5' * 100)) self.pg2.enable_mpls() rx = self.send_and_expect(self.pg2, p_mo4 * NUM_PKTS, self.pg2) self.pg2.disable_mpls() p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload) for p in rx: p = IP(p["Ether"].payload) self.validate_inner4(p, p_mo4, ttl=63)
def test_ns(self): """ IPv6 Neighbour Solicitation Exceptions Test scenario: - Send an NS Sourced from an address not covered by the link sub-net - Send an NS to an mcast address the router has not joined - Send NS for a target address the router does not onn. """ # # An NS from a non link source address # nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6)) d = inet_ntop(AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src="2002::2") / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS source by address not on sub-net") # # An NS for sent to a solicited mcast group the router is # not a member of FAILS # if 0: nsma = in6_getnsma(inet_pton(AF_INET6, "fd::ffff")) d = inet_ntop(AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS sent to unjoined mcast address") # # An NS whose target address is one the router does not own # nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6)) d = inet_ntop(AF_INET6, nsma) p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt="fd::ffff") / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( self.pg0, pkts, "No response to NS for unknown target") # # A neighbor entry that has no associated FIB-entry # self.pg0.generate_remote_hosts(4) nd_entry = VppNeighbor(self, self.pg0.sw_if_index, self.pg0.remote_hosts[2].mac, self.pg0.remote_hosts[2].ip6, af=AF_INET6, is_no_fib_entry=1) nd_entry.add_vpp_config() # # check we have the neighbor, but no route # self.assertTrue( find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[2].ip6, inet=AF_INET6)) self.assertFalse( find_route(self, self.pg0._remote_hosts[2].ip6, 128, inet=AF_INET6))