def test_proxy_mirror_arp(self): """ Interface Mirror Proxy ARP """ # # When VPP has an interface whose address is also applied to a TAP # interface on the host, then VPP's TAP interface will be unnumbered # to the 'real' interface and do proxy ARP from the host. # the curious aspect of this setup is that ARP requests from the host # will come from the VPP's own address. # self.pg0.generate_remote_hosts(2) arp_req_from_me = ( Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg0.remote_hosts[1].ip4, psrc=self.pg0.local_ip4)) # # Configure Proxy ARP for the subnet on PG0addresses on pg0 # self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet, self.pg0._local_ip4n_bcast) # Make pg2 un-numbered to pg0 # self.pg2.set_unnumbered(self.pg0.sw_if_index) # # Enable pg2 for proxy ARP # self.pg2.set_proxy_arp() # # Send the ARP request with an originating address that # is VPP's own address # self.pg2.add_stream(arp_req_from_me) 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.pg0.remote_hosts[1].ip4, self.pg0.local_ip4) # # validate we have not learned an ARP entry as a result of this # self.assertFalse( find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4)) # # cleanup # self.pg2.set_proxy_arp(0) self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet, self.pg0._local_ip4n_bcast, is_add=0)
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_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_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_nd_proxy(self): """ IPv6 Proxy ND """ # # Generate some hosts in the subnet that we are proxying # self.pg0.generate_remote_hosts(8) nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6)) d = inet_ntop(AF_INET6, nsma) # # Send an NS for one of those remote hosts on one of the proxy links # expect no response since it's from an address that is not # on the link that has the prefix configured # ns_pg1 = (Ether(dst=in6_getnsmac(nsma), src=self.pg1.remote_mac) / IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)) self.send_and_assert_no_replies(self.pg1, ns_pg1, "Off link NS") # # Add proxy support for the host # self.vapi.ip6_nd_proxy( inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), self.pg1.sw_if_index) # # try that NS again. this time we expect an NA back # self.pg1.add_stream(ns_pg1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.validate_na(self.pg1, rx[0], dst_ip=self.pg0._remote_hosts[2].ip6, tgt_ip=self.pg0.local_ip6) # # ... and that we have an entry in the ND cache # self.assertTrue( find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6, inet=AF_INET6)) # # ... and we can route traffic to it # t = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0.remote_ip6) / UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) self.pg0.add_stream(t) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[IPv6].src, t[IPv6].src) self.assertEqual(rx[IPv6].dst, t[IPv6].dst) # # Test we proxy for the host on the main interface # ns_pg0 = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=self.pg0._remote_hosts[2].ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) self.pg0.add_stream(ns_pg0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.validate_na(self.pg0, rx[0], tgt_ip=self.pg0._remote_hosts[2].ip6, dst_ip=self.pg0.remote_ip6) # # Setup and resolve proxy for another host on another interface # ns_pg2 = (Ether(dst=in6_getnsmac(nsma), src=self.pg2.remote_mac) / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)) self.vapi.ip6_nd_proxy( inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), self.pg2.sw_if_index) self.pg2.add_stream(ns_pg2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.validate_na(self.pg2, rx[0], dst_ip=self.pg0._remote_hosts[3].ip6, tgt_ip=self.pg0.local_ip6) self.assertTrue( find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6, inet=AF_INET6)) # # hosts can communicate. pg2->pg1 # t2 = (Ether(dst=self.pg2.local_mac, src=self.pg0.remote_hosts[3].mac) / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0._remote_hosts[3].ip6) / UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) self.pg2.add_stream(t2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[IPv6].src, t2[IPv6].src) self.assertEqual(rx[IPv6].dst, t2[IPv6].dst) # # remove the proxy configs # self.vapi.ip6_nd_proxy(inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), self.pg1.sw_if_index, is_del=1) self.vapi.ip6_nd_proxy(inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), self.pg2.sw_if_index, is_del=1) self.assertFalse( find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6, inet=AF_INET6)) self.assertFalse( find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6, inet=AF_INET6)) # # no longer proxy-ing... # self.send_and_assert_no_replies(self.pg0, ns_pg0, "Proxy unconfigured") self.send_and_assert_no_replies(self.pg1, ns_pg1, "Proxy unconfigured") self.send_and_assert_no_replies(self.pg2, ns_pg2, "Proxy unconfigured") # # no longer forwarding. traffic generates NS out of the glean/main # interface # self.pg2.add_stream(t2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.assertTrue(rx[0].haslayer(ICMPv6ND_NS))
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))