X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Ftest_neighbor.py;h=403e93ff2c4004ca0d52694efb85652be71166a7;hb=e3f59e2ae2201ba3007757b7567a3baa41e22879;hp=e1b37a0a1243e96aa9672f44f6a59fa126c256f9;hpb=d9b0c6fbf7aa5bd9af84264105b39c82028a4a29;p=vpp.git diff --git a/test/test_neighbor.py b/test/test_neighbor.py index e1b37a0a124..403e93ff2c4 100644 --- a/test/test_neighbor.py +++ b/test/test_neighbor.py @@ -4,7 +4,7 @@ import unittest import os from socket import AF_INET, AF_INET6, inet_pton -from framework import tag_fixme_vpp_workers +from framework import tag_fixme_vpp_workers, tag_fixme_ubuntu2204, tag_fixme_debian11 from framework import VppTestCase, VppTestRunner from vpp_neighbor import VppNeighbor, find_nbr from vpp_ip_route import ( @@ -16,8 +16,9 @@ from vpp_ip_route import ( FibPathType, VppIpInterfaceAddress, ) -from vpp_papi import VppEnum +from vpp_papi import VppEnum, MACAddress from vpp_ip import VppIpPuntRedirect +from vpp_sub_interface import VppDot1ADSubint import scapy.compat from scapy.packet import Raw @@ -86,11 +87,11 @@ class ARPTestCase(VppTestCase): super(ARPTestCase, self).tearDown() - def verify_arp_req(self, rx, smac, sip, dip): + def verify_arp_req(self, rx, smac, sip, dip, etype=0x0806): ether = rx[Ether] self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff") self.assertEqual(ether.src, smac) - self.assertEqual(ether.type, 0x0806) + self.assertEqual(ether.type, etype) arp = rx[ARP] self.assertEqual(arp.hwtype, 1) @@ -160,6 +161,30 @@ class ARPTestCase(VppTestCase): self.assertEqual(ip.src, sip) self.assertEqual(ip.dst, dip) + def get_arp_rx_requests(self, itf): + """Get ARP RX request stats for and interface""" + return self.statistics["/net/arp/rx/requests"][:, itf.sw_if_index].sum() + + def get_arp_tx_requests(self, itf): + """Get ARP TX request stats for and interface""" + return self.statistics["/net/arp/tx/requests"][:, itf.sw_if_index].sum() + + def get_arp_rx_replies(self, itf): + """Get ARP RX replies stats for and interface""" + return self.statistics["/net/arp/rx/replies"][:, itf.sw_if_index].sum() + + def get_arp_tx_replies(self, itf): + """Get ARP TX replies stats for and interface""" + return self.statistics["/net/arp/tx/replies"][:, itf.sw_if_index].sum() + + def get_arp_rx_garp(self, itf): + """Get ARP RX grat stats for and interface""" + return self.statistics["/net/arp/rx/gratuitous"][:, itf.sw_if_index].sum() + + def get_arp_tx_garp(self, itf): + """Get ARP RX grat stats for and interface""" + return self.statistics["/net/arp/tx/gratuitous"][:, itf.sw_if_index].sum() + def test_arp(self): """ARP""" @@ -208,6 +233,10 @@ class ARPTestCase(VppTestCase): rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4 ) + self.logger.info(self.vapi.cli("sh ip neighbor-stats")) + self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1")) + self.assert_equal(self.get_arp_tx_requests(self.pg1), 1) + # # And a dynamic ARP entry for host 1 # @@ -328,6 +357,7 @@ class ARPTestCase(VppTestCase): self.verify_arp_req( rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4 ) + self.assert_equal(self.get_arp_tx_requests(self.pg1), 2) self.assertFalse(dyn_arp.query_vpp_config()) self.assertTrue(static_arp.query_vpp_config()) @@ -353,6 +383,9 @@ class ARPTestCase(VppTestCase): self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4, ) + self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1")) + self.assert_equal(self.get_arp_rx_requests(self.pg1), 1) + self.assert_equal(self.get_arp_tx_replies(self.pg1), 1) # # VPP should have learned the mapping for the remote host @@ -813,6 +846,105 @@ class ARPTestCase(VppTestCase): self.pg2.admin_down() self.pg1.admin_down() + def test_arp_after_mac_change(self): + """ARP (after MAC address change)""" + + # + # Prepare a subinterface + # + subif0 = VppDot1ADSubint(self, self.pg1, 0, 300, 400) + subif0.admin_up() + subif0.config_ip4() + + # + # Send a packet to cause ARP generation for the parent interface's remote host + # + p1 = ( + Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) + / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) + / UDP(sport=1234, dport=1234) + / Raw() + ) + + self.pg0.add_stream(p1) + 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_ip4 + ) + + # + # Send a packet to cause ARP generation for the subinterface's remote host + # + p2 = ( + Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) + / IP(src=self.pg0.remote_ip4, dst=subif0.remote_ip4) + / UDP(sport=1234, dport=1234) + / Raw() + ) + + self.pg0.add_stream(p2) + 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, + subif0.local_ip4, + subif0.remote_ip4, + subif0.DOT1AD_TYPE, + ) + + # + # Change MAC address of the parent interface + # + pg1_mac_saved = self.pg1.local_mac + self.pg1.set_mac(MACAddress("00:00:00:11:22:33")) + + # + # Send a packet to cause ARP generation for the parent interface's remote host + # - expect new MAC address is used as the source + # + self.pg0.add_stream(p1) + 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_ip4 + ) + + # + # Send a packet to cause ARP generation for the subinterface's remote host + # - expect new MAC address is used as the source + # + + self.pg0.add_stream(p2) + 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, + subif0.local_ip4, + subif0.remote_ip4, + subif0.DOT1AD_TYPE, + ) + + # + # Cleanup + # + subif0.remove_vpp_config() + self.pg1.set_mac(MACAddress(pg1_mac_saved)) + def test_proxy_mirror_arp(self): """Interface Mirror Proxy ARP""" @@ -1662,6 +1794,7 @@ class ARPTestCase(VppTestCase): mac=self.pg1.remote_hosts[2].mac, ) ) + self.assert_equal(self.get_arp_rx_garp(self.pg1), 1) # # Send a GARP (reply) to swap the host 1's address to that of host 3 @@ -1686,6 +1819,7 @@ class ARPTestCase(VppTestCase): mac=self.pg1.remote_hosts[3].mac, ) ) + self.assert_equal(self.get_arp_rx_garp(self.pg1), 2) # # GARPs (request nor replies) for host we don't know yet @@ -1728,6 +1862,10 @@ class ARPTestCase(VppTestCase): # self.pg2.configure_ipv4_neighbors() + cntr = self.statistics.get_err_counter( + "/err/arp-reply/l3_dst_address_not_local" + ) + for op in ["is-at", "who-has"]: p1 = [ ( @@ -1759,10 +1897,8 @@ class ARPTestCase(VppTestCase): # they are all dropped because the subnet's don't match self.assertEqual( - 4, - self.statistics.get_err_counter( - "/err/arp-reply/IP4 destination address not local to subnet" - ), + cntr + 4, + self.statistics.get_err_counter("/err/arp-reply/l3_dst_address_not_local"), ) def test_arp_incomplete2(self): @@ -1990,27 +2126,30 @@ class ARPTestCase(VppTestCase): # # add a local address in the same subnet - # the source addresses are equivalent. VPP happens to - # choose the last one that was added + # the source addresses are equivalent. + # VPP leaves the glean address being used for a prefix + # in place until that address is deleted. + # conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config() rxs = self.send_and_expect(self.pg0, [p2], self.pg1) for rx in rxs: - self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128") + self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128") # - # remove + # remove first address, which is currently in use + # the second address should be used now # - conn3.remove_vpp_config() + conn2.remove_vpp_config() rxs = self.send_and_expect(self.pg0, [p2], self.pg1) for rx in rxs: - self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128") + self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128") # - # add back, this time remove the first one + # add first address back. Second address should continue + # being used. # - conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config() - + conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config() rxs = self.send_and_expect(self.pg0, [p2], self.pg1) for rx in rxs: self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128") @@ -2033,6 +2172,28 @@ class ARPTestCase(VppTestCase): for rx in rxs: self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128") + # apply an attached prefix to the interface + # since there's no local address in this prefix, + # any other address is used + p3 = ( + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) + / IP(src=self.pg1.remote_ip4, dst="10.0.2.128") + / Raw(b"0x5" * 100) + ) + + VppIpRoute( + self, + "10.0.2.0", + 24, + [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)], + ).add_vpp_config() + + rxs = self.send_and_expect(self.pg0, [p3], self.pg1) + for rx in rxs: + self.verify_arp_req( + rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128" + ) + # cleanup conn3.remove_vpp_config() conn2.remove_vpp_config() @@ -2160,6 +2321,7 @@ class NeighborStatsTestCase(VppTestCase): self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"]) +@tag_fixme_ubuntu2204 class NeighborAgeTestCase(VppTestCase): """ARP/ND Aging""" @@ -2210,6 +2372,14 @@ class NeighborAgeTestCase(VppTestCase): self.assertEqual(arp.psrc, sip) self.assertEqual(arp.pdst, dip) + def verify_ip_neighbor_config(self, af, max_number, max_age, recycle): + config = self.vapi.ip_neighbor_config_get(af) + + self.assertEqual(config.af, af) + self.assertEqual(config.max_number, max_number) + self.assertEqual(config.max_age, max_age) + self.assertEqual(config.recycle, recycle) + def test_age(self): """Aging/Recycle""" @@ -2225,6 +2395,13 @@ class NeighborAgeTestCase(VppTestCase): # self.pg_enable_capture(self.pg_interfaces) + # + # Verify neighbor configuration defaults + # + self.verify_ip_neighbor_config( + af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False + ) + # # Set the neighbor configuration: # limi = 200 @@ -2234,6 +2411,9 @@ class NeighborAgeTestCase(VppTestCase): self.vapi.ip_neighbor_config( af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False ) + self.verify_ip_neighbor_config( + af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False + ) self.vapi.cli("sh ip neighbor-config") @@ -2261,6 +2441,9 @@ class NeighborAgeTestCase(VppTestCase): self.vapi.ip_neighbor_config( af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True ) + self.verify_ip_neighbor_config( + af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True + ) # now new additions are allowed VppNeighbor( @@ -2284,6 +2467,9 @@ class NeighborAgeTestCase(VppTestCase): self.vapi.ip_neighbor_config( af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True ) + self.verify_ip_neighbor_config( + af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True + ) self.vapi.cli("sh ip4 neighbor-sorted") @@ -2362,6 +2548,9 @@ class NeighborAgeTestCase(VppTestCase): self.vapi.ip_neighbor_config( af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True ) + self.verify_ip_neighbor_config( + af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True + ) # # load up some neighbours again, then disable the aging @@ -2377,6 +2566,9 @@ class NeighborAgeTestCase(VppTestCase): self.vapi.ip_neighbor_config( af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False ) + self.verify_ip_neighbor_config( + af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False + ) self.virtual_sleep(10) self.assertTrue(