5 from socket import AF_INET, AF_INET6, inet_pton
7 from framework import tag_fixme_vpp_workers, tag_fixme_ubuntu2204, tag_fixme_debian11
8 from framework import VppTestCase, VppTestRunner
9 from vpp_neighbor import VppNeighbor, find_nbr
10 from vpp_ip_route import (
17 VppIpInterfaceAddress,
19 from vpp_papi import VppEnum
20 from vpp_ip import VppIpPuntRedirect
23 from scapy.packet import Raw
24 from scapy.layers.l2 import Ether, ARP, Dot1Q
25 from scapy.layers.inet import IP, UDP, TCP
26 from scapy.layers.inet6 import IPv6
27 from scapy.contrib.mpls import MPLS
28 from scapy.layers.inet6 import IPv6
33 # not exported by scapy, so redefined here
34 arp_opts = {"who-has": 1, "is-at": 2}
37 class ARPTestCase(VppTestCase):
42 super(ARPTestCase, cls).setUpClass()
45 def tearDownClass(cls):
46 super(ARPTestCase, cls).tearDownClass()
49 super(ARPTestCase, self).setUp()
51 # create 3 pg interfaces
52 self.create_pg_interfaces(range(4))
54 # pg0 configured with ip4 and 6 addresses used for input
55 # pg1 configured with ip4 and 6 addresses used for output
56 # pg2 is unnumbered to pg0
57 for i in self.pg_interfaces:
62 self.pg0.resolve_arp()
67 # pg3 in a different VRF
68 self.tbl = VppIpTable(self, 1)
69 self.tbl.add_vpp_config()
71 self.pg3.set_table_ip4(1)
75 self.pg0.unconfig_ip4()
76 self.pg0.unconfig_ip6()
78 self.pg1.unconfig_ip4()
79 self.pg1.unconfig_ip6()
81 self.pg3.unconfig_ip4()
82 self.pg3.set_table_ip4(0)
84 for i in self.pg_interfaces:
87 super(ARPTestCase, self).tearDown()
89 def verify_arp_req(self, rx, smac, sip, dip):
91 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
92 self.assertEqual(ether.src, smac)
93 self.assertEqual(ether.type, 0x0806)
96 self.assertEqual(arp.hwtype, 1)
97 self.assertEqual(arp.ptype, 0x800)
98 self.assertEqual(arp.hwlen, 6)
99 self.assertEqual(arp.plen, 4)
100 self.assertEqual(arp.op, arp_opts["who-has"])
101 self.assertEqual(arp.hwsrc, smac)
102 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
103 self.assertEqual(arp.psrc, sip)
104 self.assertEqual(arp.pdst, dip)
106 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
108 self.assertEqual(ether.dst, dmac)
109 self.assertEqual(ether.src, smac)
110 self.assertEqual(ether.type, 0x0806)
113 self.assertEqual(arp.hwtype, 1)
114 self.assertEqual(arp.ptype, 0x800)
115 self.assertEqual(arp.hwlen, 6)
116 self.assertEqual(arp.plen, 4)
117 self.assertEqual(arp.op, arp_opts["is-at"])
118 self.assertEqual(arp.hwsrc, smac)
119 self.assertEqual(arp.hwdst, dmac)
120 self.assertEqual(arp.psrc, sip)
121 self.assertEqual(arp.pdst, dip)
123 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
125 self.assertEqual(ether.dst, dmac)
126 self.assertEqual(ether.src, smac)
129 self.assertEqual(arp.hwtype, 1)
130 self.assertEqual(arp.ptype, 0x800)
131 self.assertEqual(arp.hwlen, 6)
132 self.assertEqual(arp.plen, 4)
133 self.assertEqual(arp.op, arp_opts["is-at"])
134 self.assertNotEqual(arp.hwsrc, smac)
135 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or "00:00:5E:00:01" in arp.hwsrc)
136 self.assertEqual(arp.hwdst, dmac)
137 self.assertEqual(arp.psrc, sip)
138 self.assertEqual(arp.pdst, dip)
140 def verify_ip(self, rx, smac, dmac, sip, dip):
142 self.assertEqual(ether.dst, dmac)
143 self.assertEqual(ether.src, smac)
144 self.assertEqual(ether.type, 0x0800)
147 self.assertEqual(ip.src, sip)
148 self.assertEqual(ip.dst, dip)
150 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
152 self.assertEqual(ether.dst, dmac)
153 self.assertEqual(ether.src, smac)
154 self.assertEqual(ether.type, 0x8847)
157 self.assertTrue(mpls.label, label)
160 self.assertEqual(ip.src, sip)
161 self.assertEqual(ip.dst, dip)
163 def get_arp_rx_requests(self, itf):
164 """Get ARP RX request stats for and interface"""
165 return self.statistics["/net/arp/rx/requests"][:, itf.sw_if_index].sum()
167 def get_arp_tx_requests(self, itf):
168 """Get ARP TX request stats for and interface"""
169 return self.statistics["/net/arp/tx/requests"][:, itf.sw_if_index].sum()
171 def get_arp_rx_replies(self, itf):
172 """Get ARP RX replies stats for and interface"""
173 return self.statistics["/net/arp/rx/replies"][:, itf.sw_if_index].sum()
175 def get_arp_tx_replies(self, itf):
176 """Get ARP TX replies stats for and interface"""
177 return self.statistics["/net/arp/tx/replies"][:, itf.sw_if_index].sum()
179 def get_arp_rx_garp(self, itf):
180 """Get ARP RX grat stats for and interface"""
181 return self.statistics["/net/arp/rx/gratuitous"][:, itf.sw_if_index].sum()
183 def get_arp_tx_garp(self, itf):
184 """Get ARP RX grat stats for and interface"""
185 return self.statistics["/net/arp/tx/gratuitous"][:, itf.sw_if_index].sum()
191 # Generate some hosts on the LAN
193 self.pg1.generate_remote_hosts(11)
197 # - all neighbour events
198 # - all neighbor events on pg1
199 # - neighbor events for host[1] on pg1
201 self.vapi.want_ip_neighbor_events(enable=1, pid=os.getpid())
202 self.vapi.want_ip_neighbor_events(
203 enable=1, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
205 self.vapi.want_ip_neighbor_events(
208 sw_if_index=self.pg1.sw_if_index,
209 ip=self.pg1.remote_hosts[1].ip4,
212 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
215 # Send IP traffic to one of these unresolved hosts.
216 # expect the generation of an ARP request
219 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
220 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
221 / UDP(sport=1234, dport=1234)
225 self.pg0.add_stream(p)
226 self.pg_enable_capture(self.pg_interfaces)
229 rx = self.pg1.get_capture(1)
232 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
235 self.logger.info(self.vapi.cli("sh ip neighbor-stats"))
236 self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1"))
237 self.assert_equal(self.get_arp_tx_requests(self.pg1), 1)
240 # And a dynamic ARP entry for host 1
242 dyn_arp = VppNeighbor(
244 self.pg1.sw_if_index,
245 self.pg1.remote_hosts[1].mac,
246 self.pg1.remote_hosts[1].ip4,
248 dyn_arp.add_vpp_config()
249 self.assertTrue(dyn_arp.query_vpp_config())
251 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
253 # this matches all of the listnerers
254 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(3)]
256 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[1].ip4)
259 # now we expect IP traffic forwarded
262 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
263 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
264 / UDP(sport=1234, dport=1234)
268 self.pg0.add_stream(dyn_p)
269 self.pg_enable_capture(self.pg_interfaces)
272 rx = self.pg1.get_capture(1)
277 self.pg1.remote_hosts[1].mac,
279 self.pg1._remote_hosts[1].ip4,
283 # And a Static ARP entry for host 2
285 static_arp = VppNeighbor(
287 self.pg1.sw_if_index,
288 self.pg1.remote_hosts[2].mac,
289 self.pg1.remote_hosts[2].ip4,
292 static_arp.add_vpp_config()
293 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(2)]
295 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[2].ip4)
298 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
299 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4)
300 / UDP(sport=1234, dport=1234)
304 self.pg0.add_stream(static_p)
305 self.pg_enable_capture(self.pg_interfaces)
308 rx = self.pg1.get_capture(1)
313 self.pg1.remote_hosts[2].mac,
315 self.pg1._remote_hosts[2].ip4,
319 # remove all the listeners
321 self.vapi.want_ip_neighbor_events(enable=0, pid=os.getpid())
322 self.vapi.want_ip_neighbor_events(
323 enable=0, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
325 self.vapi.want_ip_neighbor_events(
328 sw_if_index=self.pg1.sw_if_index,
329 ip=self.pg1.remote_hosts[1].ip4,
333 # flap the link. dynamic ARPs get flush, statics don't
335 self.pg1.admin_down()
338 self.pg0.add_stream(static_p)
339 self.pg_enable_capture(self.pg_interfaces)
341 rx = self.pg1.get_capture(1)
346 self.pg1.remote_hosts[2].mac,
348 self.pg1._remote_hosts[2].ip4,
351 self.pg0.add_stream(dyn_p)
352 self.pg_enable_capture(self.pg_interfaces)
355 rx = self.pg1.get_capture(1)
357 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
359 self.assert_equal(self.get_arp_tx_requests(self.pg1), 2)
361 self.assertFalse(dyn_arp.query_vpp_config())
362 self.assertTrue(static_arp.query_vpp_config())
364 # Send an ARP request from one of the so-far unlearned remote hosts
366 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) / ARP(
368 hwsrc=self.pg1._remote_hosts[3].mac,
369 pdst=self.pg1.local_ip4,
370 psrc=self.pg1._remote_hosts[3].ip4,
373 self.pg1.add_stream(p)
374 self.pg_enable_capture(self.pg_interfaces)
377 rx = self.pg1.get_capture(1)
378 self.verify_arp_resp(
381 self.pg1._remote_hosts[3].mac,
383 self.pg1._remote_hosts[3].ip4,
385 self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1"))
386 self.assert_equal(self.get_arp_rx_requests(self.pg1), 1)
387 self.assert_equal(self.get_arp_tx_replies(self.pg1), 1)
390 # VPP should have learned the mapping for the remote host
393 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)
396 # Fire in an ARP request before the interface becomes IP enabled
398 self.pg2.generate_remote_hosts(4)
400 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
402 hwsrc=self.pg2.remote_mac,
403 pdst=self.pg1.local_ip4,
404 psrc=self.pg2.remote_hosts[3].ip4,
407 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac)
411 hwsrc=self.pg2.remote_mac,
412 pdst=self.pg1.local_ip4,
413 psrc=self.pg2.remote_hosts[3].ip4,
416 self.send_and_assert_no_replies(self.pg2, p, "interface not IP enabled")
419 # Make pg2 un-numbered to pg1
421 self.pg2.set_unnumbered(self.pg1.sw_if_index)
424 # test the unnumbered dump both by all interfaces and just the enabled
427 unnum = self.vapi.ip_unnumbered_dump()
428 self.assertTrue(len(unnum))
429 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
430 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
431 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
432 self.assertTrue(len(unnum))
433 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
434 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
437 # We should respond to ARP requests for the unnumbered to address
438 # once an attached route to the source is known
440 self.send_and_assert_no_replies(
441 self.pg2, p, "ARP req for unnumbered address - no source"
444 attached_host = VppIpRoute(
446 self.pg2.remote_hosts[3].ip4,
448 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
450 attached_host.add_vpp_config()
452 self.pg2.add_stream(p)
453 self.pg_enable_capture(self.pg_interfaces)
456 rx = self.pg2.get_capture(1)
457 self.verify_arp_resp(
462 self.pg2.remote_hosts[3].ip4,
465 self.pg2.add_stream(pt)
466 self.pg_enable_capture(self.pg_interfaces)
469 rx = self.pg2.get_capture(1)
470 self.verify_arp_resp(
475 self.pg2.remote_hosts[3].ip4,
479 # A neighbor entry that has no associated FIB-entry
481 arp_no_fib = VppNeighbor(
483 self.pg1.sw_if_index,
484 self.pg1.remote_hosts[4].mac,
485 self.pg1.remote_hosts[4].ip4,
488 arp_no_fib.add_vpp_config()
491 # check we have the neighbor, but no route
494 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)
496 self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32))
498 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
499 # from within pg1's subnet
501 arp_unnum = VppNeighbor(
503 self.pg2.sw_if_index,
504 self.pg1.remote_hosts[5].mac,
505 self.pg1.remote_hosts[5].ip4,
507 arp_unnum.add_vpp_config()
510 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
511 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4)
512 / UDP(sport=1234, dport=1234)
516 self.pg0.add_stream(p)
517 self.pg_enable_capture(self.pg_interfaces)
520 rx = self.pg2.get_capture(1)
525 self.pg1.remote_hosts[5].mac,
527 self.pg1._remote_hosts[5].ip4,
531 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
532 # with the unnumbered interface's address as the source
534 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
536 hwsrc=self.pg2.remote_mac,
537 pdst=self.pg1.local_ip4,
538 psrc=self.pg1.remote_hosts[6].ip4,
541 self.pg2.add_stream(p)
542 self.pg_enable_capture(self.pg_interfaces)
545 rx = self.pg2.get_capture(1)
546 self.verify_arp_resp(
551 self.pg1.remote_hosts[6].ip4,
555 # An attached host route out of pg2 for an undiscovered hosts generates
556 # an ARP request with the unnumbered address as the source
558 att_unnum = VppIpRoute(
560 self.pg1.remote_hosts[7].ip4,
562 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
564 att_unnum.add_vpp_config()
567 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
568 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4)
569 / UDP(sport=1234, dport=1234)
573 self.pg0.add_stream(p)
574 self.pg_enable_capture(self.pg_interfaces)
577 rx = self.pg2.get_capture(1)
580 rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4
583 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
585 hwsrc=self.pg2.remote_mac,
586 pdst=self.pg1.local_ip4,
587 psrc=self.pg1.remote_hosts[7].ip4,
590 self.pg2.add_stream(p)
591 self.pg_enable_capture(self.pg_interfaces)
594 rx = self.pg2.get_capture(1)
595 self.verify_arp_resp(
600 self.pg1.remote_hosts[7].ip4,
604 # An attached host route as yet unresolved out of pg2 for an
605 # undiscovered host, an ARP requests begets a response.
607 att_unnum1 = VppIpRoute(
609 self.pg1.remote_hosts[8].ip4,
611 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
613 att_unnum1.add_vpp_config()
615 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
617 hwsrc=self.pg2.remote_mac,
618 pdst=self.pg1.local_ip4,
619 psrc=self.pg1.remote_hosts[8].ip4,
622 self.pg2.add_stream(p)
623 self.pg_enable_capture(self.pg_interfaces)
626 rx = self.pg2.get_capture(1)
627 self.verify_arp_resp(
632 self.pg1.remote_hosts[8].ip4,
636 # Send an ARP request from one of the so-far unlearned remote hosts
640 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac)
644 hwsrc=self.pg1._remote_hosts[9].mac,
645 pdst=self.pg1.local_ip4,
646 psrc=self.pg1._remote_hosts[9].ip4,
650 self.pg1.add_stream(p)
651 self.pg_enable_capture(self.pg_interfaces)
654 rx = self.pg1.get_capture(1)
655 self.verify_arp_resp(
658 self.pg1._remote_hosts[9].mac,
660 self.pg1._remote_hosts[9].ip4,
664 # Add a hierarchy of routes for a host in the sub-net.
665 # Should still get an ARP resp since the cover is attached
667 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(
669 hwsrc=self.pg1.remote_mac,
670 pdst=self.pg1.local_ip4,
671 psrc=self.pg1.remote_hosts[10].ip4,
676 self.pg1.remote_hosts[10].ip4,
678 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
682 self.pg1.add_stream(p)
683 self.pg_enable_capture(self.pg_interfaces)
685 rx = self.pg1.get_capture(1)
686 self.verify_arp_resp(
691 self.pg1.remote_hosts[10].ip4,
696 self.pg1.remote_hosts[10].ip4,
698 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
702 self.pg1.add_stream(p)
703 self.pg_enable_capture(self.pg_interfaces)
705 rx = self.pg1.get_capture(1)
706 self.verify_arp_resp(
711 self.pg1.remote_hosts[10].ip4,
715 # add an ARP entry that's not on the sub-net and so whose
716 # adj-fib fails the refinement check. then send an ARP request
720 self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50"
724 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
726 hwsrc=self.pg0.remote_mac,
727 psrc="100.100.100.50",
728 pdst=self.pg0.remote_ip4,
730 self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib")
734 # 1 - don't respond to ARP request for address not within the
735 # interface's sub-net
736 # 1b - nor within the unnumbered subnet
737 # 1c - nor within the subnet of a different interface
739 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
741 hwsrc=self.pg0.remote_mac,
743 psrc=self.pg0.remote_ip4,
745 self.send_and_assert_no_replies(
746 self.pg0, p, "ARP req for non-local destination"
748 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3"))
750 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
752 hwsrc=self.pg2.remote_mac,
754 psrc=self.pg1.remote_hosts[7].ip4,
756 self.send_and_assert_no_replies(
757 self.pg0, p, "ARP req for non-local destination - unnum"
760 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
762 hwsrc=self.pg0.remote_mac,
763 pdst=self.pg1.local_ip4,
764 psrc=self.pg1.remote_ip4,
766 self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net")
767 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4))
770 # 2 - don't respond to ARP request from an address not within the
771 # interface's sub-net
772 # 2b - to a proxied address
773 # 2c - not within a different interface's sub-net
774 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
776 hwsrc=self.pg0.remote_mac,
778 pdst=self.pg0.local_ip4,
780 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
781 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
783 hwsrc=self.pg2.remote_mac,
785 pdst=self.pg0.local_ip4,
787 self.send_and_assert_no_replies(
788 self.pg0, p, "ARP req for non-local source - unnum"
790 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
792 hwsrc=self.pg0.remote_mac,
793 psrc=self.pg1.remote_ip4,
794 pdst=self.pg0.local_ip4,
796 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c")
799 # 3 - don't respond to ARP request from an address that belongs to
802 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
804 hwsrc=self.pg0.remote_mac,
805 psrc=self.pg0.local_ip4,
806 pdst=self.pg0.local_ip4,
808 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
811 # 4 - don't respond to ARP requests that has mac source different
812 # from ARP request HW source
814 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
816 hwsrc="00:00:00:DE:AD:BE",
817 psrc=self.pg0.remote_ip4,
818 pdst=self.pg0.local_ip4,
820 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
823 # 5 - don't respond to ARP requests for address within the
824 # interface's sub-net but not the interface's address
826 self.pg0.generate_remote_hosts(2)
827 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
829 hwsrc=self.pg0.remote_mac,
830 psrc=self.pg0.remote_hosts[0].ip4,
831 pdst=self.pg0.remote_hosts[1].ip4,
833 self.send_and_assert_no_replies(
834 self.pg0, p, "ARP req for non-local destination"
840 static_arp.remove_vpp_config()
841 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
843 # need this to flush the adj-fibs
844 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
845 self.pg2.admin_down()
846 self.pg1.admin_down()
848 def test_proxy_mirror_arp(self):
849 """Interface Mirror Proxy ARP"""
852 # When VPP has an interface whose address is also applied to a TAP
853 # interface on the host, then VPP's TAP interface will be unnumbered
854 # to the 'real' interface and do proxy ARP from the host.
855 # the curious aspect of this setup is that ARP requests from the host
856 # will come from the VPP's own address.
858 self.pg0.generate_remote_hosts(2)
860 arp_req_from_me = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
862 hwsrc=self.pg2.remote_mac,
863 pdst=self.pg0.remote_hosts[1].ip4,
864 psrc=self.pg0.local_ip4,
868 # Configure Proxy ARP for the subnet on PG0addresses on pg0
870 self.vapi.proxy_arp_add_del(
873 "low": self.pg0._local_ip4_subnet,
874 "hi": self.pg0._local_ip4_bcast,
879 # Make pg2 un-numbered to pg0
881 self.pg2.set_unnumbered(self.pg0.sw_if_index)
884 # Enable pg2 for proxy ARP
886 self.pg2.set_proxy_arp()
889 # Send the ARP request with an originating address that
890 # is VPP's own address
892 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
893 self.verify_arp_resp(
897 self.pg0.remote_hosts[1].ip4,
902 # validate we have not learned an ARP entry as a result of this
904 self.assertFalse(find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4))
907 # setup a punt redirect so packets from the uplink go to the tap
909 redirect = VppIpPuntRedirect(
910 self, self.pg0.sw_if_index, self.pg2.sw_if_index, self.pg0.local_ip4
912 redirect.add_vpp_config()
916 src=self.pg0.remote_mac,
917 dst=self.pg0.local_mac,
919 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
920 / TCP(sport=80, dport=80)
923 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
925 # there's no ARP entry so this is an ARP req
926 self.assertTrue(rx[0].haslayer(ARP))
928 # and ARP entry for VPP's pg0 address on the host interface
931 self.pg2.sw_if_index,
934 is_no_fib_entry=True,
936 # now the packets shold forward
937 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
938 self.assertFalse(rx[0].haslayer(ARP))
939 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
942 # flush the neighbor cache on the uplink
944 af = VppEnum.vl_api_address_family_t
945 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
947 # ensure we can still resolve the ARPs on the uplink
948 self.pg0.resolve_arp()
950 self.assertTrue(find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_ip4))
955 self.vapi.proxy_arp_add_del(
958 "low": self.pg0._local_ip4_subnet,
959 "hi": self.pg0._local_ip4_bcast,
963 redirect.remove_vpp_config()
965 def test_proxy_arp(self):
968 self.pg1.generate_remote_hosts(2)
971 # Proxy ARP request packets for each interface
973 arp_req_pg0 = Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
975 hwsrc=self.pg0.remote_mac,
977 psrc=self.pg0.remote_ip4,
979 arp_req_pg0_tagged = (
980 Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff")
984 hwsrc=self.pg0.remote_mac,
986 psrc=self.pg0.remote_ip4,
989 arp_req_pg1 = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
991 hwsrc=self.pg1.remote_mac,
993 psrc=self.pg1.remote_ip4,
995 arp_req_pg2 = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
997 hwsrc=self.pg2.remote_mac,
999 psrc=self.pg1.remote_hosts[1].ip4,
1001 arp_req_pg3 = Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1003 hwsrc=self.pg3.remote_mac,
1005 psrc=self.pg3.remote_ip4,
1009 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
1011 self.vapi.proxy_arp_add_del(
1012 proxy={"table_id": 0, "low": "10.10.10.2", "hi": "10.10.10.124"}, is_add=1
1016 # No responses are sent when the interfaces are not enabled for proxy
1019 self.send_and_assert_no_replies(
1020 self.pg0, arp_req_pg0, "ARP req from unconfigured interface"
1022 self.send_and_assert_no_replies(
1023 self.pg2, arp_req_pg2, "ARP req from unconfigured interface"
1027 # Make pg2 un-numbered to pg1
1028 # still won't reply.
1030 self.pg2.set_unnumbered(self.pg1.sw_if_index)
1032 self.send_and_assert_no_replies(
1033 self.pg2, arp_req_pg2, "ARP req from unnumbered interface"
1037 # Enable each interface to reply to proxy ARPs
1039 for i in self.pg_interfaces:
1043 # Now each of the interfaces should reply to a request to a proxied
1046 self.pg0.add_stream(arp_req_pg0)
1047 self.pg_enable_capture(self.pg_interfaces)
1050 rx = self.pg0.get_capture(1)
1051 self.verify_arp_resp(
1054 self.pg0.remote_mac,
1056 self.pg0.remote_ip4,
1059 self.pg0.add_stream(arp_req_pg0_tagged)
1060 self.pg_enable_capture(self.pg_interfaces)
1063 rx = self.pg0.get_capture(1)
1064 self.verify_arp_resp(
1067 self.pg0.remote_mac,
1069 self.pg0.remote_ip4,
1072 self.pg1.add_stream(arp_req_pg1)
1073 self.pg_enable_capture(self.pg_interfaces)
1076 rx = self.pg1.get_capture(1)
1077 self.verify_arp_resp(
1080 self.pg1.remote_mac,
1082 self.pg1.remote_ip4,
1085 self.pg2.add_stream(arp_req_pg2)
1086 self.pg_enable_capture(self.pg_interfaces)
1089 rx = self.pg2.get_capture(1)
1090 self.verify_arp_resp(
1093 self.pg2.remote_mac,
1095 self.pg1.remote_hosts[1].ip4,
1099 # A request for an address out of the configured range
1101 arp_req_pg1_hi = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1103 hwsrc=self.pg1.remote_mac,
1104 pdst="10.10.10.125",
1105 psrc=self.pg1.remote_ip4,
1107 self.send_and_assert_no_replies(
1108 self.pg1, arp_req_pg1_hi, "ARP req out of range HI"
1110 arp_req_pg1_low = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1112 hwsrc=self.pg1.remote_mac,
1114 psrc=self.pg1.remote_ip4,
1116 self.send_and_assert_no_replies(
1117 self.pg1, arp_req_pg1_low, "ARP req out of range Low"
1121 # Request for an address in the proxy range but from an interface
1122 # in a different VRF
1124 self.send_and_assert_no_replies(
1125 self.pg3, arp_req_pg3, "ARP req from different VRF"
1129 # Disable Each interface for proxy ARP
1130 # - expect none to respond
1132 for i in self.pg_interfaces:
1135 self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from disable")
1136 self.send_and_assert_no_replies(self.pg1, arp_req_pg1, "ARP req from disable")
1137 self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from disable")
1140 # clean up on interface 2
1142 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1144 def test_mpls(self):
1148 # Interface 2 does not yet have ip4 config
1150 self.pg2.config_ip4()
1151 self.pg2.generate_remote_hosts(2)
1154 # Add a route with out going label via an ARP unresolved next-hop
1156 ip_10_0_0_1 = VppIpRoute(
1162 self.pg2.remote_hosts[1].ip4, self.pg2.sw_if_index, labels=[55]
1166 ip_10_0_0_1.add_vpp_config()
1169 # packets should generate an ARP request
1172 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1173 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
1174 / UDP(sport=1234, dport=1234)
1175 / Raw(b"\xa5" * 100)
1178 self.pg0.add_stream(p)
1179 self.pg_enable_capture(self.pg_interfaces)
1182 rx = self.pg2.get_capture(1)
1183 self.verify_arp_req(
1184 rx[0], self.pg2.local_mac, self.pg2.local_ip4, self.pg2._remote_hosts[1].ip4
1188 # now resolve the neighbours
1190 self.pg2.configure_ipv4_neighbors()
1193 # Now packet should be properly MPLS encapped.
1194 # This verifies that MPLS link-type adjacencies are completed
1195 # when the ARP entry resolves
1197 self.pg0.add_stream(p)
1198 self.pg_enable_capture(self.pg_interfaces)
1201 rx = self.pg2.get_capture(1)
1202 self.verify_ip_o_mpls(
1205 self.pg2.remote_hosts[1].mac,
1207 self.pg0.remote_ip4,
1210 self.pg2.unconfig_ip4()
1212 def test_arp_vrrp(self):
1213 """ARP reply with VRRP virtual src hw addr"""
1216 # IP packet destined for pg1 remote host arrives on pg0 resulting
1217 # in an ARP request for the address of the remote host on pg1
1220 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1221 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
1222 / UDP(sport=1234, dport=1234)
1226 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1228 self.verify_arp_req(
1229 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
1233 # ARP reply for address of pg1 remote host arrives on pg1 with
1234 # the hw src addr set to a value in the VRRP IPv4 range of
1237 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1239 hwdst=self.pg1.local_mac,
1240 hwsrc="00:00:5e:00:01:09",
1241 pdst=self.pg1.local_ip4,
1242 psrc=self.pg1.remote_ip4,
1245 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1248 # IP packet destined for pg1 remote host arrives on pg0 again.
1249 # VPP should have an ARP entry for that address now and the packet
1250 # should be sent out pg1.
1252 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1257 "00:00:5e:00:01:09",
1258 self.pg0.remote_ip4,
1259 self.pg1.remote_ip4,
1262 self.pg1.admin_down()
1265 def test_arp_duplicates(self):
1266 """ARP Duplicates"""
1269 # Generate some hosts on the LAN
1271 self.pg1.generate_remote_hosts(3)
1274 # Add host 1 on pg1 and pg2
1276 arp_pg1 = VppNeighbor(
1278 self.pg1.sw_if_index,
1279 self.pg1.remote_hosts[1].mac,
1280 self.pg1.remote_hosts[1].ip4,
1282 arp_pg1.add_vpp_config()
1283 arp_pg2 = VppNeighbor(
1285 self.pg2.sw_if_index,
1286 self.pg2.remote_mac,
1287 self.pg1.remote_hosts[1].ip4,
1289 arp_pg2.add_vpp_config()
1292 # IP packet destined for pg1 remote host arrives on pg1 again.
1295 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1296 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1297 / UDP(sport=1234, dport=1234)
1301 self.pg0.add_stream(p)
1302 self.pg_enable_capture(self.pg_interfaces)
1305 rx1 = self.pg1.get_capture(1)
1310 self.pg1.remote_hosts[1].mac,
1311 self.pg0.remote_ip4,
1312 self.pg1.remote_hosts[1].ip4,
1316 # remove the duplicate on pg1
1317 # packet stream should generate ARPs out of pg1
1319 arp_pg1.remove_vpp_config()
1321 self.pg0.add_stream(p)
1322 self.pg_enable_capture(self.pg_interfaces)
1325 rx1 = self.pg1.get_capture(1)
1327 self.verify_arp_req(
1328 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4
1334 arp_pg1.add_vpp_config()
1336 self.pg0.add_stream(p)
1337 self.pg_enable_capture(self.pg_interfaces)
1340 rx1 = self.pg1.get_capture(1)
1345 self.pg1.remote_hosts[1].mac,
1346 self.pg0.remote_ip4,
1347 self.pg1.remote_hosts[1].ip4,
1350 def test_arp_static(self):
1352 self.pg2.generate_remote_hosts(3)
1355 # Add a static ARP entry
1357 static_arp = VppNeighbor(
1359 self.pg2.sw_if_index,
1360 self.pg2.remote_hosts[1].mac,
1361 self.pg2.remote_hosts[1].ip4,
1364 static_arp.add_vpp_config()
1367 # Add the connected prefix to the interface
1369 self.pg2.config_ip4()
1372 # We should now find the adj-fib
1376 self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].ip4, is_static=1
1379 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32))
1382 # remove the connected
1384 self.pg2.unconfig_ip4()
1387 # put the interface into table 1
1389 self.pg2.set_table_ip4(1)
1392 # configure the same connected and expect to find the
1393 # adj fib in the new table
1395 self.pg2.config_ip4()
1396 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1))
1401 self.pg2.unconfig_ip4()
1402 static_arp.remove_vpp_config()
1403 self.pg2.set_table_ip4(0)
1405 def test_arp_static_replace_dynamic_same_mac(self):
1406 """ARP Static can replace Dynamic (same mac)"""
1407 self.pg2.generate_remote_hosts(1)
1409 dyn_arp = VppNeighbor(
1411 self.pg2.sw_if_index,
1412 self.pg2.remote_hosts[0].mac,
1413 self.pg2.remote_hosts[0].ip4,
1415 static_arp = VppNeighbor(
1417 self.pg2.sw_if_index,
1418 self.pg2.remote_hosts[0].mac,
1419 self.pg2.remote_hosts[0].ip4,
1424 # Add a dynamic ARP entry
1426 dyn_arp.add_vpp_config()
1429 # We should find the dynamic nbr
1433 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1439 self.pg2.sw_if_index,
1440 self.pg2.remote_hosts[0].ip4,
1442 mac=self.pg2.remote_hosts[0].mac,
1447 # Add a static ARP entry with the same mac
1449 static_arp.add_vpp_config()
1452 # We should now find the static nbr with the same mac
1456 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1462 self.pg2.sw_if_index,
1463 self.pg2.remote_hosts[0].ip4,
1465 mac=self.pg2.remote_hosts[0].mac,
1472 static_arp.remove_vpp_config()
1474 def test_arp_static_replace_dynamic_diff_mac(self):
1475 """ARP Static can replace Dynamic (diff mac)"""
1476 self.pg2.generate_remote_hosts(2)
1478 dyn_arp = VppNeighbor(
1480 self.pg2.sw_if_index,
1481 self.pg2.remote_hosts[0].mac,
1482 self.pg2.remote_hosts[0].ip4,
1484 static_arp = VppNeighbor(
1486 self.pg2.sw_if_index,
1487 self.pg2.remote_hosts[1].mac,
1488 self.pg2.remote_hosts[0].ip4,
1493 # Add a dynamic ARP entry
1495 dyn_arp.add_vpp_config()
1498 # We should find the dynamic nbr
1502 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1508 self.pg2.sw_if_index,
1509 self.pg2.remote_hosts[0].ip4,
1511 mac=self.pg2.remote_hosts[0].mac,
1516 # Add a static ARP entry with a changed mac
1518 static_arp.add_vpp_config()
1521 # We should now find the static nbr with a changed mac
1525 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1531 self.pg2.sw_if_index,
1532 self.pg2.remote_hosts[0].ip4,
1534 mac=self.pg2.remote_hosts[1].mac,
1541 static_arp.remove_vpp_config()
1543 def test_arp_incomplete(self):
1544 """ARP Incomplete"""
1545 self.pg1.generate_remote_hosts(4)
1548 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1549 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1550 / UDP(sport=1234, dport=1234)
1554 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1555 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
1556 / UDP(sport=1234, dport=1234)
1560 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1561 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
1562 / UDP(sport=1234, dport=1234)
1567 # a packet to an unresolved destination generates an ARP request
1569 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1570 self.verify_arp_req(
1571 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
1575 # add a neighbour for remote host 1
1577 static_arp = VppNeighbor(
1579 self.pg1.sw_if_index,
1580 self.pg1.remote_hosts[1].mac,
1581 self.pg1.remote_hosts[1].ip4,
1584 static_arp.add_vpp_config()
1587 # add a route through remote host 3 hence we get an incomplete
1593 [VppRoutePath(self.pg1.remote_hosts[3].ip4, self.pg1.sw_if_index)],
1595 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1596 self.verify_arp_req(
1597 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4
1601 # change the interface's MAC
1603 self.vapi.sw_interface_set_mac_address(
1604 self.pg1.sw_if_index, "00:00:00:33:33:33"
1608 # now ARP requests come from the new source mac
1610 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1611 self.verify_arp_req(
1613 "00:00:00:33:33:33",
1615 self.pg1._remote_hosts[2].ip4,
1617 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1618 self.verify_arp_req(
1620 "00:00:00:33:33:33",
1622 self.pg1._remote_hosts[3].ip4,
1626 # packets to the resolved host also have the new source mac
1628 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1631 "00:00:00:33:33:33",
1632 self.pg1.remote_hosts[1].mac,
1633 self.pg0.remote_ip4,
1634 self.pg1.remote_hosts[1].ip4,
1638 # set the mac address on the interface that does not have a
1639 # configured subnet and thus no glean
1641 self.vapi.sw_interface_set_mac_address(
1642 self.pg2.sw_if_index, "00:00:00:33:33:33"
1645 def test_garp(self):
1649 # Generate some hosts on the LAN
1651 self.pg1.generate_remote_hosts(4)
1652 self.pg2.generate_remote_hosts(4)
1659 self.pg1.sw_if_index,
1660 self.pg1.remote_hosts[1].mac,
1661 self.pg1.remote_hosts[1].ip4,
1663 arp.add_vpp_config()
1668 self.pg1.sw_if_index,
1669 self.pg1.remote_hosts[1].ip4,
1670 mac=self.pg1.remote_hosts[1].mac,
1675 # Send a GARP (request) to swap the host 1's address to that of host 2
1677 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) / ARP(
1679 hwdst=self.pg1.local_mac,
1680 hwsrc=self.pg1.remote_hosts[2].mac,
1681 pdst=self.pg1.remote_hosts[1].ip4,
1682 psrc=self.pg1.remote_hosts[1].ip4,
1685 self.pg1.add_stream(p1)
1686 self.pg_enable_capture(self.pg_interfaces)
1692 self.pg1.sw_if_index,
1693 self.pg1.remote_hosts[1].ip4,
1694 mac=self.pg1.remote_hosts[2].mac,
1697 self.assert_equal(self.get_arp_rx_garp(self.pg1), 1)
1700 # Send a GARP (reply) to swap the host 1's address to that of host 3
1702 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1704 hwdst=self.pg1.local_mac,
1705 hwsrc=self.pg1.remote_hosts[3].mac,
1706 pdst=self.pg1.remote_hosts[1].ip4,
1707 psrc=self.pg1.remote_hosts[1].ip4,
1710 self.pg1.add_stream(p1)
1711 self.pg_enable_capture(self.pg_interfaces)
1717 self.pg1.sw_if_index,
1718 self.pg1.remote_hosts[1].ip4,
1719 mac=self.pg1.remote_hosts[3].mac,
1722 self.assert_equal(self.get_arp_rx_garp(self.pg1), 2)
1725 # GARPs (request nor replies) for host we don't know yet
1726 # don't result in new neighbour entries
1728 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1730 hwdst=self.pg1.local_mac,
1731 hwsrc=self.pg1.remote_hosts[3].mac,
1732 pdst=self.pg1.remote_hosts[2].ip4,
1733 psrc=self.pg1.remote_hosts[2].ip4,
1736 self.pg1.add_stream(p1)
1737 self.pg_enable_capture(self.pg_interfaces)
1741 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1744 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1746 hwdst=self.pg1.local_mac,
1747 hwsrc=self.pg1.remote_hosts[3].mac,
1748 pdst=self.pg1.remote_hosts[2].ip4,
1749 psrc=self.pg1.remote_hosts[2].ip4,
1752 self.pg1.add_stream(p1)
1753 self.pg_enable_capture(self.pg_interfaces)
1757 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1761 # IP address in different subnets are not learnt
1763 self.pg2.configure_ipv4_neighbors()
1765 cntr = self.statistics.get_err_counter(
1766 "/err/arp-reply/l3_dst_address_not_local"
1769 for op in ["is-at", "who-has"]:
1772 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1775 hwdst=self.pg2.local_mac,
1776 hwsrc=self.pg2.remote_hosts[1].mac,
1777 pdst=self.pg2.remote_hosts[1].ip4,
1778 psrc=self.pg2.remote_hosts[1].ip4,
1782 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1785 hwdst="ff:ff:ff:ff:ff:ff",
1786 hwsrc=self.pg2.remote_hosts[1].mac,
1787 pdst=self.pg2.remote_hosts[1].ip4,
1788 psrc=self.pg2.remote_hosts[1].ip4,
1793 self.send_and_assert_no_replies(self.pg1, p1)
1795 find_nbr(self, self.pg1.sw_if_index, self.pg2.remote_hosts[1].ip4)
1798 # they are all dropped because the subnet's don't match
1801 self.statistics.get_err_counter("/err/arp-reply/l3_dst_address_not_local"),
1804 def test_arp_incomplete2(self):
1805 """Incomplete Entries"""
1808 # ensure that we throttle the ARP and ND requests
1810 self.pg0.generate_remote_hosts(2)
1815 ip_10_0_0_1 = VppIpRoute(
1819 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1821 ip_10_0_0_1.add_vpp_config()
1824 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1825 / IP(src=self.pg1.remote_ip4, dst="10.0.0.1")
1826 / UDP(sport=1234, dport=1234)
1830 self.pg1.add_stream(p1 * 257)
1831 self.pg_enable_capture(self.pg_interfaces)
1833 rx = self.pg0._get_capture(1)
1836 # how many we get is going to be dependent on the time for packet
1837 # processing but it should be small
1839 self.assertLess(len(rx), 64)
1844 ip_10_1 = VppIpRoute(
1850 self.pg0.remote_hosts[1].ip6,
1851 self.pg0.sw_if_index,
1852 proto=DpoProto.DPO_PROTO_IP6,
1856 ip_10_1.add_vpp_config()
1859 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1860 / IPv6(src=self.pg1.remote_ip6, dst="10::1")
1861 / UDP(sport=1234, dport=1234)
1865 self.pg1.add_stream(p1 * 257)
1866 self.pg_enable_capture(self.pg_interfaces)
1868 rx = self.pg0._get_capture(1)
1871 # how many we get is going to be dependent on the time for packet
1872 # processing but it should be small
1874 self.assertLess(len(rx), 64)
1876 def test_arp_forus(self):
1877 """ARP for for-us"""
1880 # Test that VPP responds with ARP requests to addresses that
1881 # are connected and local routes.
1882 # Use one of the 'remote' addresses in the subnet as a local address
1883 # The intention of this route is that it then acts like a secondary
1884 # address added to an interface
1886 self.pg0.generate_remote_hosts(2)
1890 self.pg0.remote_hosts[1].ip4,
1895 self.pg0.sw_if_index,
1896 type=FibPathType.FIB_PATH_TYPE_LOCAL,
1900 forus.add_vpp_config()
1902 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
1904 hwdst=self.pg0.local_mac,
1905 hwsrc=self.pg0.remote_mac,
1906 pdst=self.pg0.remote_hosts[1].ip4,
1907 psrc=self.pg0.remote_ip4,
1910 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1912 self.verify_arp_resp(
1915 self.pg0.remote_mac,
1916 self.pg0.remote_hosts[1].ip4,
1917 self.pg0.remote_ip4,
1920 def test_arp_table_swap(self):
1922 # Generate some hosts on the LAN
1925 self.pg1.generate_remote_hosts(N_NBRS)
1927 for n in range(N_NBRS):
1928 # a route thru each neighbour
1933 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
1936 # resolve each neighbour
1937 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1939 hwdst=self.pg1.local_mac,
1940 hwsrc="00:00:5e:00:01:09",
1941 pdst=self.pg1.local_ip4,
1942 psrc=self.pg1.remote_hosts[n].ip4,
1945 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1947 self.logger.info(self.vapi.cli("sh ip neighbors"))
1950 # swap the table pg1 is in
1952 table = VppIpTable(self, 100).add_vpp_config()
1954 self.pg1.unconfig_ip4()
1955 self.pg1.set_table_ip4(100)
1956 self.pg1.config_ip4()
1959 # all neighbours are cleared
1961 for n in range(N_NBRS):
1963 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip4)
1967 # packets to all neighbours generate ARP requests
1969 for n in range(N_NBRS):
1970 # a route thru each neighbour
1975 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
1980 Ether(src=self.pg1.remote_hosts[n].mac, dst=self.pg1.local_mac)
1981 / IP(src=self.pg1.remote_hosts[n].ip4, dst="10.0.0.%d" % n)
1984 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1986 self.verify_arp_req(
1990 self.pg1.remote_hosts[n].ip4,
1993 self.pg1.unconfig_ip4()
1994 self.pg1.set_table_ip4(0)
1996 def test_glean_src_select(self):
1997 """Multi Connecteds"""
2000 # configure multiple connected subnets on an interface
2001 # and ensure that ARP requests for hosts on those subnets
2002 # pick up the correct source address
2004 conn1 = VppIpInterfaceAddress(self, self.pg1, "10.0.0.1", 24).add_vpp_config()
2005 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2008 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2009 / IP(src=self.pg1.remote_ip4, dst="10.0.0.128")
2013 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
2015 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.0.1", "10.0.0.128")
2018 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2019 / IP(src=self.pg1.remote_ip4, dst="10.0.1.128")
2023 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2025 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2028 # add a local address in the same subnet
2029 # the source addresses are equivalent. VPP happens to
2030 # choose the last one that was added
2031 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2033 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2035 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2040 conn3.remove_vpp_config()
2041 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2043 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2046 # add back, this time remove the first one
2048 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2050 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2052 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2054 conn1.remove_vpp_config()
2055 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2057 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2059 # apply a connected prefix to an interface in a different table
2064 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2068 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2070 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2073 conn3.remove_vpp_config()
2074 conn2.remove_vpp_config()
2077 @tag_fixme_vpp_workers
2078 class NeighborStatsTestCase(VppTestCase):
2079 """ARP/ND Counters"""
2082 def setUpClass(cls):
2083 super(NeighborStatsTestCase, cls).setUpClass()
2086 def tearDownClass(cls):
2087 super(NeighborStatsTestCase, cls).tearDownClass()
2090 super(NeighborStatsTestCase, self).setUp()
2092 self.create_pg_interfaces(range(2))
2094 # pg0 configured with ip4 and 6 addresses used for input
2095 # pg1 configured with ip4 and 6 addresses used for output
2096 # pg2 is unnumbered to pg0
2097 for i in self.pg_interfaces:
2105 super(NeighborStatsTestCase, self).tearDown()
2107 for i in self.pg_interfaces:
2112 def test_arp_stats(self):
2115 self.vapi.cli("adj counters enable")
2116 self.pg1.generate_remote_hosts(2)
2120 self.pg1.sw_if_index,
2121 self.pg1.remote_hosts[0].mac,
2122 self.pg1.remote_hosts[0].ip4,
2124 arp1.add_vpp_config()
2127 self.pg1.sw_if_index,
2128 self.pg1.remote_hosts[1].mac,
2129 self.pg1.remote_hosts[1].ip4,
2131 arp2.add_vpp_config()
2134 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2135 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2136 / UDP(sport=1234, dport=1234)
2140 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2141 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2142 / UDP(sport=1234, dport=1234)
2146 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2147 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2149 self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2150 self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2152 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2153 self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2155 def test_nd_stats(self):
2158 self.vapi.cli("adj counters enable")
2159 self.pg0.generate_remote_hosts(3)
2163 self.pg0.sw_if_index,
2164 self.pg0.remote_hosts[1].mac,
2165 self.pg0.remote_hosts[1].ip6,
2167 nd1.add_vpp_config()
2170 self.pg0.sw_if_index,
2171 self.pg0.remote_hosts[2].mac,
2172 self.pg0.remote_hosts[2].ip6,
2174 nd2.add_vpp_config()
2177 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2178 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2179 / UDP(sport=1234, dport=1234)
2183 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2184 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2185 / UDP(sport=1234, dport=1234)
2189 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2190 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2192 self.assertEqual(16, nd1.get_stats()["packets"])
2193 self.assertEqual(16, nd2.get_stats()["packets"])
2195 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2196 self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2199 @tag_fixme_ubuntu2204
2200 class NeighborAgeTestCase(VppTestCase):
2204 def setUpClass(cls):
2205 super(NeighborAgeTestCase, cls).setUpClass()
2208 def tearDownClass(cls):
2209 super(NeighborAgeTestCase, cls).tearDownClass()
2212 super(NeighborAgeTestCase, self).setUp()
2214 self.create_pg_interfaces(range(1))
2216 # pg0 configured with ip4 and 6 addresses used for input
2217 # pg1 configured with ip4 and 6 addresses used for output
2218 # pg2 is unnumbered to pg0
2219 for i in self.pg_interfaces:
2227 super(NeighborAgeTestCase, self).tearDown()
2229 for i in self.pg_interfaces:
2234 def verify_arp_req(self, rx, smac, sip, dip):
2236 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2237 self.assertEqual(ether.src, smac)
2240 self.assertEqual(arp.hwtype, 1)
2241 self.assertEqual(arp.ptype, 0x800)
2242 self.assertEqual(arp.hwlen, 6)
2243 self.assertEqual(arp.plen, 4)
2244 self.assertEqual(arp.op, arp_opts["who-has"])
2245 self.assertEqual(arp.hwsrc, smac)
2246 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2247 self.assertEqual(arp.psrc, sip)
2248 self.assertEqual(arp.pdst, dip)
2250 def verify_ip_neighbor_config(self, af, max_number, max_age, recycle):
2251 config = self.vapi.ip_neighbor_config_get(af)
2253 self.assertEqual(config.af, af)
2254 self.assertEqual(config.max_number, max_number)
2255 self.assertEqual(config.max_age, max_age)
2256 self.assertEqual(config.recycle, recycle)
2261 self.vapi.cli("set logging unthrottle 0")
2262 self.vapi.cli("set logging size %d" % 0xFFFF)
2264 self.pg0.generate_remote_hosts(201)
2266 vaf = VppEnum.vl_api_address_family_t
2269 # start listening on all interfaces
2271 self.pg_enable_capture(self.pg_interfaces)
2274 # Verify neighbor configuration defaults
2276 self.verify_ip_neighbor_config(
2277 af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False
2281 # Set the neighbor configuration:
2286 self.vapi.ip_neighbor_config(
2287 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2289 self.verify_ip_neighbor_config(
2290 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2293 self.vapi.cli("sh ip neighbor-config")
2295 # add the 198 neighbours that should pass (-1 for one created in setup)
2296 for ii in range(200):
2299 self.pg0.sw_if_index,
2300 self.pg0.remote_hosts[ii].mac,
2301 self.pg0.remote_hosts[ii].ip4,
2304 # one more neighbor over the limit should fail
2305 with self.vapi.assert_negative_api_retval():
2308 self.pg0.sw_if_index,
2309 self.pg0.remote_hosts[200].mac,
2310 self.pg0.remote_hosts[200].ip4,
2314 # change the config to allow recycling the old neighbors
2316 self.vapi.ip_neighbor_config(
2317 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2319 self.verify_ip_neighbor_config(
2320 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2323 # now new additions are allowed
2326 self.pg0.sw_if_index,
2327 self.pg0.remote_hosts[200].mac,
2328 self.pg0.remote_hosts[200].ip4,
2331 # add the first neighbor we configured has been re-used
2333 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2336 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2340 # change the config to age old neighbors
2342 self.vapi.ip_neighbor_config(
2343 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2345 self.verify_ip_neighbor_config(
2346 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2349 self.vapi.cli("sh ip4 neighbor-sorted")
2352 self.virtual_sleep(3)
2355 # expect probes from all these ARP entries as they age
2356 # 3 probes for each neighbor 3*200 = 600
2357 rxs = self.pg0.get_capture(600, timeout=2)
2360 for jj in range(200):
2361 rx = rxs[ii * 200 + jj]
2365 # 3 probes sent then 1 more second to see if a reply comes, before
2368 self.virtual_sleep(1)
2371 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2375 # load up some neighbours again with 2s aging enabled
2376 # they should be removed after 10s (2s age + 4s for probes + gap)
2377 # check for the add and remove events
2379 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2381 self.vapi.want_ip_neighbor_events_v2(enable=1)
2382 for ii in range(10):
2385 self.pg0.sw_if_index,
2386 self.pg0.remote_hosts[ii].mac,
2387 self.pg0.remote_hosts[ii].ip4,
2390 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2391 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2392 self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2393 self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2395 self.virtual_sleep(10)
2397 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2401 for ii in range(10):
2402 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2403 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2406 # check we got the correct mac/ip pairs - done separately
2407 # because we don't care about the order the remove notifications
2409 for ii in range(10):
2411 mac = self.pg0.remote_hosts[ii].mac
2412 ip = self.pg0.remote_hosts[ii].ip4
2415 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2418 self.assertTrue(found)
2421 # check if we can set age and recycle with empty neighbor list
2423 self.vapi.ip_neighbor_config(
2424 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2426 self.verify_ip_neighbor_config(
2427 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2431 # load up some neighbours again, then disable the aging
2432 # they should still be there in 10 seconds time
2434 for ii in range(10):
2437 self.pg0.sw_if_index,
2438 self.pg0.remote_hosts[ii].mac,
2439 self.pg0.remote_hosts[ii].ip4,
2441 self.vapi.ip_neighbor_config(
2442 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2444 self.verify_ip_neighbor_config(
2445 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2448 self.virtual_sleep(10)
2450 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2454 class NeighborReplaceTestCase(VppTestCase):
2455 """ARP/ND Replacement"""
2458 def setUpClass(cls):
2459 super(NeighborReplaceTestCase, cls).setUpClass()
2462 def tearDownClass(cls):
2463 super(NeighborReplaceTestCase, cls).tearDownClass()
2466 super(NeighborReplaceTestCase, self).setUp()
2468 self.create_pg_interfaces(range(4))
2470 # pg0 configured with ip4 and 6 addresses used for input
2471 # pg1 configured with ip4 and 6 addresses used for output
2472 # pg2 is unnumbered to pg0
2473 for i in self.pg_interfaces:
2481 super(NeighborReplaceTestCase, self).tearDown()
2483 for i in self.pg_interfaces:
2488 def test_replace(self):
2493 for i in self.pg_interfaces:
2494 i.generate_remote_hosts(N_HOSTS)
2495 i.configure_ipv4_neighbors()
2496 i.configure_ipv6_neighbors()
2499 self.vapi.ip_neighbor_replace_begin()
2500 self.vapi.ip_neighbor_replace_end()
2502 for i in self.pg_interfaces:
2503 for h in range(N_HOSTS):
2505 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2508 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2512 # and them all back via the API
2514 for i in self.pg_interfaces:
2515 for h in range(N_HOSTS):
2517 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2520 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2524 # begin the replacement again, this time touch some
2525 # the neighbours on pg1 so they are not deleted
2527 self.vapi.ip_neighbor_replace_begin()
2529 # update from the API all neighbours on pg1
2530 for h in range(N_HOSTS):
2533 self.pg1.sw_if_index,
2534 self.pg1.remote_hosts[h].mac,
2535 self.pg1.remote_hosts[h].ip4,
2539 self.pg1.sw_if_index,
2540 self.pg1.remote_hosts[h].mac,
2541 self.pg1.remote_hosts[h].ip6,
2544 # update from the data-plane all neighbours on pg3
2545 self.pg3.configure_ipv4_neighbors()
2546 self.pg3.configure_ipv6_neighbors()
2548 # complete the replacement
2549 self.logger.info(self.vapi.cli("sh ip neighbors"))
2550 self.vapi.ip_neighbor_replace_end()
2552 for i in self.pg_interfaces:
2553 if i == self.pg1 or i == self.pg3:
2554 # neighbours on pg1 and pg3 are still present
2555 for h in range(N_HOSTS):
2557 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2560 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2563 # all other neighbours are toast
2564 for h in range(N_HOSTS):
2566 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2569 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2573 class NeighborFlush(VppTestCase):
2574 """Neighbor Flush"""
2577 def setUpClass(cls):
2578 super(NeighborFlush, cls).setUpClass()
2581 def tearDownClass(cls):
2582 super(NeighborFlush, cls).tearDownClass()
2585 super(NeighborFlush, self).setUp()
2587 self.create_pg_interfaces(range(2))
2589 for i in self.pg_interfaces:
2597 super(NeighborFlush, self).tearDown()
2599 for i in self.pg_interfaces:
2604 def test_flush(self):
2605 """Neighbour Flush"""
2608 nf = e.vl_api_ip_neighbor_flags_t
2609 af = e.vl_api_address_family_t
2611 static = [False, True]
2612 self.pg0.generate_remote_hosts(N_HOSTS)
2613 self.pg1.generate_remote_hosts(N_HOSTS)
2616 # a few v4 and v6 dynamic neoghbors
2617 for n in range(N_HOSTS):
2620 self.pg0.sw_if_index,
2621 self.pg0.remote_hosts[n].mac,
2622 self.pg0.remote_hosts[n].ip4,
2627 self.pg1.sw_if_index,
2628 self.pg1.remote_hosts[n].mac,
2629 self.pg1.remote_hosts[n].ip6,
2633 # flush the interfaces individually
2634 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2636 # check we haven't flushed that which we shouldn't
2637 for n in range(N_HOSTS):
2641 self.pg1.sw_if_index,
2642 self.pg1.remote_hosts[n].ip6,
2647 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2649 for n in range(N_HOSTS):
2651 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2654 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2657 # add the nieghbours back
2658 for n in range(N_HOSTS):
2661 self.pg0.sw_if_index,
2662 self.pg0.remote_hosts[n].mac,
2663 self.pg0.remote_hosts[n].ip4,
2668 self.pg1.sw_if_index,
2669 self.pg1.remote_hosts[n].mac,
2670 self.pg1.remote_hosts[n].ip6,
2674 self.logger.info(self.vapi.cli("sh ip neighbor"))
2676 # flush both interfaces at the same time
2677 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2679 # check we haven't flushed that which we shouldn't
2680 for n in range(N_HOSTS):
2684 self.pg0.sw_if_index,
2685 self.pg0.remote_hosts[n].ip4,
2690 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2692 for n in range(N_HOSTS):
2694 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2697 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2701 if __name__ == "__main__":
2702 unittest.main(testRunner=VppTestRunner)