6 from framework import VppTestCase
7 from asfframework import VppTestRunner, tag_fixme_vpp_workers, tag_fixme_ubuntu2204
8 from vpp_neighbor import VppNeighbor, find_nbr
9 from vpp_ip_route import (
16 VppIpInterfaceAddress,
18 from vpp_papi import VppEnum, MACAddress
19 from vpp_ip import VppIpPuntRedirect
20 from vpp_sub_interface import VppDot1ADSubint
22 from scapy.packet import Raw
23 from scapy.layers.l2 import Ether, ARP, Dot1Q
24 from scapy.layers.inet import IP, UDP, TCP
25 from scapy.layers.inet6 import IPv6
26 from scapy.contrib.mpls import MPLS
27 from scapy.layers.inet6 import IPv6
32 # not exported by scapy, so redefined here
33 arp_opts = {"who-has": 1, "is-at": 2}
36 class ARPTestCase(VppTestCase):
41 super(ARPTestCase, cls).setUpClass()
44 def tearDownClass(cls):
45 super(ARPTestCase, cls).tearDownClass()
48 super(ARPTestCase, self).setUp()
50 # create 3 pg interfaces
51 self.create_pg_interfaces(range(4))
53 # pg0 configured with ip4 and 6 addresses used for input
54 # pg1 configured with ip4 and 6 addresses used for output
55 # pg2 is unnumbered to pg0
56 for i in self.pg_interfaces:
61 self.pg0.resolve_arp()
66 # pg3 in a different VRF
67 self.tbl = VppIpTable(self, 1)
68 self.tbl.add_vpp_config()
70 self.pg3.set_table_ip4(1)
74 self.pg0.unconfig_ip4()
75 self.pg0.unconfig_ip6()
77 self.pg1.unconfig_ip4()
78 self.pg1.unconfig_ip6()
80 self.pg3.unconfig_ip4()
81 self.pg3.set_table_ip4(0)
83 for i in self.pg_interfaces:
86 super(ARPTestCase, self).tearDown()
88 def verify_arp_req(self, rx, smac, sip, dip, etype=0x0806):
90 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
91 self.assertEqual(ether.src, smac)
92 self.assertEqual(ether.type, etype)
95 self.assertEqual(arp.hwtype, 1)
96 self.assertEqual(arp.ptype, 0x800)
97 self.assertEqual(arp.hwlen, 6)
98 self.assertEqual(arp.plen, 4)
99 self.assertEqual(arp.op, arp_opts["who-has"])
100 self.assertEqual(arp.hwsrc, smac)
101 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
102 self.assertEqual(arp.psrc, sip)
103 self.assertEqual(arp.pdst, dip)
105 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
107 self.assertEqual(ether.dst, dmac)
108 self.assertEqual(ether.src, smac)
109 self.assertEqual(ether.type, 0x0806)
112 self.assertEqual(arp.hwtype, 1)
113 self.assertEqual(arp.ptype, 0x800)
114 self.assertEqual(arp.hwlen, 6)
115 self.assertEqual(arp.plen, 4)
116 self.assertEqual(arp.op, arp_opts["is-at"])
117 self.assertEqual(arp.hwsrc, smac)
118 self.assertEqual(arp.hwdst, dmac)
119 self.assertEqual(arp.psrc, sip)
120 self.assertEqual(arp.pdst, dip)
122 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
124 self.assertEqual(ether.dst, dmac)
125 self.assertEqual(ether.src, smac)
128 self.assertEqual(arp.hwtype, 1)
129 self.assertEqual(arp.ptype, 0x800)
130 self.assertEqual(arp.hwlen, 6)
131 self.assertEqual(arp.plen, 4)
132 self.assertEqual(arp.op, arp_opts["is-at"])
133 self.assertNotEqual(arp.hwsrc, smac)
134 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or "00:00:5E:00:01" in arp.hwsrc)
135 self.assertEqual(arp.hwdst, dmac)
136 self.assertEqual(arp.psrc, sip)
137 self.assertEqual(arp.pdst, dip)
139 def verify_ip(self, rx, smac, dmac, sip, dip):
141 self.assertEqual(ether.dst, dmac)
142 self.assertEqual(ether.src, smac)
143 self.assertEqual(ether.type, 0x0800)
146 self.assertEqual(ip.src, sip)
147 self.assertEqual(ip.dst, dip)
149 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
151 self.assertEqual(ether.dst, dmac)
152 self.assertEqual(ether.src, smac)
153 self.assertEqual(ether.type, 0x8847)
156 self.assertTrue(mpls.label, label)
159 self.assertEqual(ip.src, sip)
160 self.assertEqual(ip.dst, dip)
162 def get_arp_rx_requests(self, itf):
163 """Get ARP RX request stats for and interface"""
164 return self.statistics["/net/arp/rx/requests"][:, itf.sw_if_index].sum()
166 def get_arp_tx_requests(self, itf):
167 """Get ARP TX request stats for and interface"""
168 return self.statistics["/net/arp/tx/requests"][:, itf.sw_if_index].sum()
170 def get_arp_rx_replies(self, itf):
171 """Get ARP RX replies stats for and interface"""
172 return self.statistics["/net/arp/rx/replies"][:, itf.sw_if_index].sum()
174 def get_arp_tx_replies(self, itf):
175 """Get ARP TX replies stats for and interface"""
176 return self.statistics["/net/arp/tx/replies"][:, itf.sw_if_index].sum()
178 def get_arp_rx_garp(self, itf):
179 """Get ARP RX grat stats for and interface"""
180 return self.statistics["/net/arp/rx/gratuitous"][:, itf.sw_if_index].sum()
182 def get_arp_tx_garp(self, itf):
183 """Get ARP RX grat stats for and interface"""
184 return self.statistics["/net/arp/tx/gratuitous"][:, itf.sw_if_index].sum()
190 # Generate some hosts on the LAN
192 self.pg1.generate_remote_hosts(11)
196 # - all neighbour events
197 # - all neighbor events on pg1
198 # - neighbor events for host[1] on pg1
200 self.vapi.want_ip_neighbor_events(enable=1, pid=os.getpid())
201 self.vapi.want_ip_neighbor_events(
202 enable=1, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
204 self.vapi.want_ip_neighbor_events(
207 sw_if_index=self.pg1.sw_if_index,
208 ip=self.pg1.remote_hosts[1].ip4,
211 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
214 # Send IP traffic to one of these unresolved hosts.
215 # expect the generation of an ARP request
218 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
219 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
220 / UDP(sport=1234, dport=1234)
224 self.pg0.add_stream(p)
225 self.pg_enable_capture(self.pg_interfaces)
228 rx = self.pg1.get_capture(1)
231 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
234 self.logger.info(self.vapi.cli("sh ip neighbor-stats"))
235 self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1"))
236 self.assert_equal(self.get_arp_tx_requests(self.pg1), 1)
239 # And a dynamic ARP entry for host 1
241 dyn_arp = VppNeighbor(
243 self.pg1.sw_if_index,
244 self.pg1.remote_hosts[1].mac,
245 self.pg1.remote_hosts[1].ip4,
247 dyn_arp.add_vpp_config()
248 self.assertTrue(dyn_arp.query_vpp_config())
250 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
252 # this matches all of the listnerers
253 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(3)]
255 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[1].ip4)
258 # now we expect IP traffic forwarded
261 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
262 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
263 / UDP(sport=1234, dport=1234)
267 self.pg0.add_stream(dyn_p)
268 self.pg_enable_capture(self.pg_interfaces)
271 rx = self.pg1.get_capture(1)
276 self.pg1.remote_hosts[1].mac,
278 self.pg1._remote_hosts[1].ip4,
282 # And a Static ARP entry for host 2
284 static_arp = VppNeighbor(
286 self.pg1.sw_if_index,
287 self.pg1.remote_hosts[2].mac,
288 self.pg1.remote_hosts[2].ip4,
291 static_arp.add_vpp_config()
292 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(2)]
294 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[2].ip4)
297 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
298 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4)
299 / UDP(sport=1234, dport=1234)
303 self.pg0.add_stream(static_p)
304 self.pg_enable_capture(self.pg_interfaces)
307 rx = self.pg1.get_capture(1)
312 self.pg1.remote_hosts[2].mac,
314 self.pg1._remote_hosts[2].ip4,
318 # remove all the listeners
320 self.vapi.want_ip_neighbor_events(enable=0, pid=os.getpid())
321 self.vapi.want_ip_neighbor_events(
322 enable=0, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
324 self.vapi.want_ip_neighbor_events(
327 sw_if_index=self.pg1.sw_if_index,
328 ip=self.pg1.remote_hosts[1].ip4,
332 # flap the link. dynamic ARPs get flush, statics don't
334 self.pg1.admin_down()
337 self.pg0.add_stream(static_p)
338 self.pg_enable_capture(self.pg_interfaces)
340 rx = self.pg1.get_capture(1)
345 self.pg1.remote_hosts[2].mac,
347 self.pg1._remote_hosts[2].ip4,
350 self.pg0.add_stream(dyn_p)
351 self.pg_enable_capture(self.pg_interfaces)
354 rx = self.pg1.get_capture(1)
356 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
358 self.assert_equal(self.get_arp_tx_requests(self.pg1), 2)
360 self.assertFalse(dyn_arp.query_vpp_config())
361 self.assertTrue(static_arp.query_vpp_config())
363 # Send an ARP request from one of the so-far unlearned remote hosts
365 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) / ARP(
367 hwsrc=self.pg1._remote_hosts[3].mac,
368 pdst=self.pg1.local_ip4,
369 psrc=self.pg1._remote_hosts[3].ip4,
372 self.pg1.add_stream(p)
373 self.pg_enable_capture(self.pg_interfaces)
376 rx = self.pg1.get_capture(1)
377 self.verify_arp_resp(
380 self.pg1._remote_hosts[3].mac,
382 self.pg1._remote_hosts[3].ip4,
384 self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1"))
385 self.assert_equal(self.get_arp_rx_requests(self.pg1), 1)
386 self.assert_equal(self.get_arp_tx_replies(self.pg1), 1)
389 # VPP should have learned the mapping for the remote host
392 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)
395 # Fire in an ARP request before the interface becomes IP enabled
397 self.pg2.generate_remote_hosts(4)
399 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
401 hwsrc=self.pg2.remote_mac,
402 pdst=self.pg1.local_ip4,
403 psrc=self.pg2.remote_hosts[3].ip4,
406 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac)
410 hwsrc=self.pg2.remote_mac,
411 pdst=self.pg1.local_ip4,
412 psrc=self.pg2.remote_hosts[3].ip4,
415 self.send_and_assert_no_replies(self.pg2, p, "interface not IP enabled")
418 # Make pg2 un-numbered to pg1
420 self.pg2.set_unnumbered(self.pg1.sw_if_index)
423 # test the unnumbered dump both by all interfaces and just the enabled
426 unnum = self.vapi.ip_unnumbered_dump()
427 self.assertTrue(len(unnum))
428 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
429 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
430 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
431 self.assertTrue(len(unnum))
432 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
433 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
436 # We should respond to ARP requests for the unnumbered to address
437 # once an attached route to the source is known
439 self.send_and_assert_no_replies(
440 self.pg2, p, "ARP req for unnumbered address - no source"
443 attached_host = VppIpRoute(
445 self.pg2.remote_hosts[3].ip4,
447 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
449 attached_host.add_vpp_config()
451 self.pg2.add_stream(p)
452 self.pg_enable_capture(self.pg_interfaces)
455 rx = self.pg2.get_capture(1)
456 self.verify_arp_resp(
461 self.pg2.remote_hosts[3].ip4,
464 self.pg2.add_stream(pt)
465 self.pg_enable_capture(self.pg_interfaces)
468 rx = self.pg2.get_capture(1)
469 self.verify_arp_resp(
474 self.pg2.remote_hosts[3].ip4,
478 # A neighbor entry that has no associated FIB-entry
480 arp_no_fib = VppNeighbor(
482 self.pg1.sw_if_index,
483 self.pg1.remote_hosts[4].mac,
484 self.pg1.remote_hosts[4].ip4,
487 arp_no_fib.add_vpp_config()
490 # check we have the neighbor, but no route
493 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)
495 self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32))
497 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
498 # from within pg1's subnet
500 arp_unnum = VppNeighbor(
502 self.pg2.sw_if_index,
503 self.pg1.remote_hosts[5].mac,
504 self.pg1.remote_hosts[5].ip4,
506 arp_unnum.add_vpp_config()
509 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
510 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4)
511 / UDP(sport=1234, dport=1234)
515 self.pg0.add_stream(p)
516 self.pg_enable_capture(self.pg_interfaces)
519 rx = self.pg2.get_capture(1)
524 self.pg1.remote_hosts[5].mac,
526 self.pg1._remote_hosts[5].ip4,
530 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
531 # with the unnumbered interface's address as the source
533 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
535 hwsrc=self.pg2.remote_mac,
536 pdst=self.pg1.local_ip4,
537 psrc=self.pg1.remote_hosts[6].ip4,
540 self.pg2.add_stream(p)
541 self.pg_enable_capture(self.pg_interfaces)
544 rx = self.pg2.get_capture(1)
545 self.verify_arp_resp(
550 self.pg1.remote_hosts[6].ip4,
554 # An attached host route out of pg2 for an undiscovered hosts generates
555 # an ARP request with the unnumbered address as the source
557 att_unnum = VppIpRoute(
559 self.pg1.remote_hosts[7].ip4,
561 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
563 att_unnum.add_vpp_config()
566 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
567 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4)
568 / UDP(sport=1234, dport=1234)
572 self.pg0.add_stream(p)
573 self.pg_enable_capture(self.pg_interfaces)
576 rx = self.pg2.get_capture(1)
579 rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4
582 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
584 hwsrc=self.pg2.remote_mac,
585 pdst=self.pg1.local_ip4,
586 psrc=self.pg1.remote_hosts[7].ip4,
589 self.pg2.add_stream(p)
590 self.pg_enable_capture(self.pg_interfaces)
593 rx = self.pg2.get_capture(1)
594 self.verify_arp_resp(
599 self.pg1.remote_hosts[7].ip4,
603 # An attached host route as yet unresolved out of pg2 for an
604 # undiscovered host, an ARP requests begets a response.
606 att_unnum1 = VppIpRoute(
608 self.pg1.remote_hosts[8].ip4,
610 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
612 att_unnum1.add_vpp_config()
614 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
616 hwsrc=self.pg2.remote_mac,
617 pdst=self.pg1.local_ip4,
618 psrc=self.pg1.remote_hosts[8].ip4,
621 self.pg2.add_stream(p)
622 self.pg_enable_capture(self.pg_interfaces)
625 rx = self.pg2.get_capture(1)
626 self.verify_arp_resp(
631 self.pg1.remote_hosts[8].ip4,
635 # Send an ARP request from one of the so-far unlearned remote hosts
639 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac)
643 hwsrc=self.pg1._remote_hosts[9].mac,
644 pdst=self.pg1.local_ip4,
645 psrc=self.pg1._remote_hosts[9].ip4,
649 self.pg1.add_stream(p)
650 self.pg_enable_capture(self.pg_interfaces)
653 rx = self.pg1.get_capture(1)
654 self.verify_arp_resp(
657 self.pg1._remote_hosts[9].mac,
659 self.pg1._remote_hosts[9].ip4,
663 # Add a hierarchy of routes for a host in the sub-net.
664 # Should still get an ARP resp since the cover is attached
666 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(
668 hwsrc=self.pg1.remote_mac,
669 pdst=self.pg1.local_ip4,
670 psrc=self.pg1.remote_hosts[10].ip4,
675 self.pg1.remote_hosts[10].ip4,
677 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
681 self.pg1.add_stream(p)
682 self.pg_enable_capture(self.pg_interfaces)
684 rx = self.pg1.get_capture(1)
685 self.verify_arp_resp(
690 self.pg1.remote_hosts[10].ip4,
695 self.pg1.remote_hosts[10].ip4,
697 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
701 self.pg1.add_stream(p)
702 self.pg_enable_capture(self.pg_interfaces)
704 rx = self.pg1.get_capture(1)
705 self.verify_arp_resp(
710 self.pg1.remote_hosts[10].ip4,
714 # add an ARP entry that's not on the sub-net and so whose
715 # adj-fib fails the refinement check. then send an ARP request
719 self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50"
723 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
725 hwsrc=self.pg0.remote_mac,
726 psrc="100.100.100.50",
727 pdst=self.pg0.remote_ip4,
729 self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib")
733 # 1 - don't respond to ARP request for address not within the
734 # interface's sub-net
735 # 1b - nor within the unnumbered subnet
736 # 1c - nor within the subnet of a different interface
738 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
740 hwsrc=self.pg0.remote_mac,
742 psrc=self.pg0.remote_ip4,
744 self.send_and_assert_no_replies(
745 self.pg0, p, "ARP req for non-local destination"
747 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3"))
749 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
751 hwsrc=self.pg2.remote_mac,
753 psrc=self.pg1.remote_hosts[7].ip4,
755 self.send_and_assert_no_replies(
756 self.pg0, p, "ARP req for non-local destination - unnum"
759 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
761 hwsrc=self.pg0.remote_mac,
762 pdst=self.pg1.local_ip4,
763 psrc=self.pg1.remote_ip4,
765 self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net")
766 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4))
769 # 2 - don't respond to ARP request from an address not within the
770 # interface's sub-net
771 # 2b - to a proxied address
772 # 2c - not within a different interface's sub-net
773 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
775 hwsrc=self.pg0.remote_mac,
777 pdst=self.pg0.local_ip4,
779 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
780 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
782 hwsrc=self.pg2.remote_mac,
784 pdst=self.pg0.local_ip4,
786 self.send_and_assert_no_replies(
787 self.pg0, p, "ARP req for non-local source - unnum"
789 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
791 hwsrc=self.pg0.remote_mac,
792 psrc=self.pg1.remote_ip4,
793 pdst=self.pg0.local_ip4,
795 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c")
798 # 3 - don't respond to ARP request from an address that belongs to
801 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
803 hwsrc=self.pg0.remote_mac,
804 psrc=self.pg0.local_ip4,
805 pdst=self.pg0.local_ip4,
807 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
810 # 4 - don't respond to ARP requests that has mac source different
811 # from ARP request HW source
813 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
815 hwsrc="00:00:00:DE:AD:BE",
816 psrc=self.pg0.remote_ip4,
817 pdst=self.pg0.local_ip4,
819 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
822 # 5 - don't respond to ARP requests for address within the
823 # interface's sub-net but not the interface's address
825 self.pg0.generate_remote_hosts(2)
826 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
828 hwsrc=self.pg0.remote_mac,
829 psrc=self.pg0.remote_hosts[0].ip4,
830 pdst=self.pg0.remote_hosts[1].ip4,
832 self.send_and_assert_no_replies(
833 self.pg0, p, "ARP req for non-local destination"
839 static_arp.remove_vpp_config()
840 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
842 # need this to flush the adj-fibs
843 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
844 self.pg2.admin_down()
845 self.pg1.admin_down()
847 def test_arp_after_mac_change(self):
848 """ARP (after MAC address change)"""
851 # Prepare a subinterface
853 subif0 = VppDot1ADSubint(self, self.pg1, 0, 300, 400)
858 # Send a packet to cause ARP generation for the parent interface's remote host
861 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
862 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
863 / UDP(sport=1234, dport=1234)
867 self.pg0.add_stream(p1)
868 self.pg_enable_capture(self.pg_interfaces)
871 rx = self.pg1.get_capture(1)
874 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
878 # Send a packet to cause ARP generation for the subinterface's remote host
881 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
882 / IP(src=self.pg0.remote_ip4, dst=subif0.remote_ip4)
883 / UDP(sport=1234, dport=1234)
887 self.pg0.add_stream(p2)
888 self.pg_enable_capture(self.pg_interfaces)
891 rx = self.pg1.get_capture(1)
902 # Change MAC address of the parent interface
904 pg1_mac_saved = self.pg1.local_mac
905 self.pg1.set_mac(MACAddress("00:00:00:11:22:33"))
908 # Send a packet to cause ARP generation for the parent interface's remote host
909 # - expect new MAC address is used as the source
911 self.pg0.add_stream(p1)
912 self.pg_enable_capture(self.pg_interfaces)
915 rx = self.pg1.get_capture(1)
918 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
922 # Send a packet to cause ARP generation for the subinterface's remote host
923 # - expect new MAC address is used as the source
926 self.pg0.add_stream(p2)
927 self.pg_enable_capture(self.pg_interfaces)
930 rx = self.pg1.get_capture(1)
943 subif0.remove_vpp_config()
944 self.pg1.set_mac(MACAddress(pg1_mac_saved))
946 def test_proxy_mirror_arp(self):
947 """Interface Mirror Proxy ARP"""
950 # When VPP has an interface whose address is also applied to a TAP
951 # interface on the host, then VPP's TAP interface will be unnumbered
952 # to the 'real' interface and do proxy ARP from the host.
953 # the curious aspect of this setup is that ARP requests from the host
954 # will come from the VPP's own address.
956 self.pg0.generate_remote_hosts(2)
958 arp_req_from_me = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
960 hwsrc=self.pg2.remote_mac,
961 pdst=self.pg0.remote_hosts[1].ip4,
962 psrc=self.pg0.local_ip4,
966 # Configure Proxy ARP for the subnet on PG0addresses on pg0
968 self.vapi.proxy_arp_add_del(
971 "low": self.pg0._local_ip4_subnet,
972 "hi": self.pg0._local_ip4_bcast,
977 # Make pg2 un-numbered to pg0
979 self.pg2.set_unnumbered(self.pg0.sw_if_index)
982 # Enable pg2 for proxy ARP
984 self.pg2.set_proxy_arp()
987 # Send the ARP request with an originating address that
988 # is VPP's own address
990 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
991 self.verify_arp_resp(
995 self.pg0.remote_hosts[1].ip4,
1000 # validate we have not learned an ARP entry as a result of this
1002 self.assertFalse(find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4))
1005 # setup a punt redirect so packets from the uplink go to the tap
1007 redirect = VppIpPuntRedirect(
1008 self, self.pg0.sw_if_index, self.pg2.sw_if_index, self.pg0.local_ip4
1010 redirect.add_vpp_config()
1014 src=self.pg0.remote_mac,
1015 dst=self.pg0.local_mac,
1017 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1018 / TCP(sport=80, dport=80)
1021 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
1023 # there's no ARP entry so this is an ARP req
1024 self.assertTrue(rx[0].haslayer(ARP))
1026 # and ARP entry for VPP's pg0 address on the host interface
1029 self.pg2.sw_if_index,
1030 self.pg2.remote_mac,
1032 is_no_fib_entry=True,
1034 # now the packets shold forward
1035 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
1036 self.assertFalse(rx[0].haslayer(ARP))
1037 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
1040 # flush the neighbor cache on the uplink
1042 af = VppEnum.vl_api_address_family_t
1043 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
1045 # ensure we can still resolve the ARPs on the uplink
1046 self.pg0.resolve_arp()
1048 self.assertTrue(find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_ip4))
1053 self.vapi.proxy_arp_add_del(
1056 "low": self.pg0._local_ip4_subnet,
1057 "hi": self.pg0._local_ip4_bcast,
1061 redirect.remove_vpp_config()
1063 def test_proxy_arp(self):
1066 self.pg1.generate_remote_hosts(2)
1069 # Proxy ARP request packets for each interface
1071 arp_req_pg0 = Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1073 hwsrc=self.pg0.remote_mac,
1075 psrc=self.pg0.remote_ip4,
1077 arp_req_pg0_tagged = (
1078 Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff")
1082 hwsrc=self.pg0.remote_mac,
1084 psrc=self.pg0.remote_ip4,
1087 arp_req_pg1 = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1089 hwsrc=self.pg1.remote_mac,
1091 psrc=self.pg1.remote_ip4,
1093 arp_req_pg2 = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1095 hwsrc=self.pg2.remote_mac,
1097 psrc=self.pg1.remote_hosts[1].ip4,
1099 arp_req_pg3 = Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1101 hwsrc=self.pg3.remote_mac,
1103 psrc=self.pg3.remote_ip4,
1107 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
1109 self.vapi.proxy_arp_add_del(
1110 proxy={"table_id": 0, "low": "10.10.10.2", "hi": "10.10.10.124"}, is_add=1
1114 # No responses are sent when the interfaces are not enabled for proxy
1117 self.send_and_assert_no_replies(
1118 self.pg0, arp_req_pg0, "ARP req from unconfigured interface"
1120 self.send_and_assert_no_replies(
1121 self.pg2, arp_req_pg2, "ARP req from unconfigured interface"
1125 # Make pg2 un-numbered to pg1
1126 # still won't reply.
1128 self.pg2.set_unnumbered(self.pg1.sw_if_index)
1130 self.send_and_assert_no_replies(
1131 self.pg2, arp_req_pg2, "ARP req from unnumbered interface"
1135 # Enable each interface to reply to proxy ARPs
1137 for i in self.pg_interfaces:
1141 # Now each of the interfaces should reply to a request to a proxied
1144 self.pg0.add_stream(arp_req_pg0)
1145 self.pg_enable_capture(self.pg_interfaces)
1148 rx = self.pg0.get_capture(1)
1149 self.verify_arp_resp(
1152 self.pg0.remote_mac,
1154 self.pg0.remote_ip4,
1157 self.pg0.add_stream(arp_req_pg0_tagged)
1158 self.pg_enable_capture(self.pg_interfaces)
1161 rx = self.pg0.get_capture(1)
1162 self.verify_arp_resp(
1165 self.pg0.remote_mac,
1167 self.pg0.remote_ip4,
1170 self.pg1.add_stream(arp_req_pg1)
1171 self.pg_enable_capture(self.pg_interfaces)
1174 rx = self.pg1.get_capture(1)
1175 self.verify_arp_resp(
1178 self.pg1.remote_mac,
1180 self.pg1.remote_ip4,
1183 self.pg2.add_stream(arp_req_pg2)
1184 self.pg_enable_capture(self.pg_interfaces)
1187 rx = self.pg2.get_capture(1)
1188 self.verify_arp_resp(
1191 self.pg2.remote_mac,
1193 self.pg1.remote_hosts[1].ip4,
1197 # A request for an address out of the configured range
1199 arp_req_pg1_hi = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1201 hwsrc=self.pg1.remote_mac,
1202 pdst="10.10.10.125",
1203 psrc=self.pg1.remote_ip4,
1205 self.send_and_assert_no_replies(
1206 self.pg1, arp_req_pg1_hi, "ARP req out of range HI"
1208 arp_req_pg1_low = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1210 hwsrc=self.pg1.remote_mac,
1212 psrc=self.pg1.remote_ip4,
1214 self.send_and_assert_no_replies(
1215 self.pg1, arp_req_pg1_low, "ARP req out of range Low"
1219 # Request for an address in the proxy range but from an interface
1220 # in a different VRF
1222 self.send_and_assert_no_replies(
1223 self.pg3, arp_req_pg3, "ARP req from different VRF"
1227 # Disable Each interface for proxy ARP
1228 # - expect none to respond
1230 for i in self.pg_interfaces:
1233 self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from disable")
1234 self.send_and_assert_no_replies(self.pg1, arp_req_pg1, "ARP req from disable")
1235 self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from disable")
1238 # clean up on interface 2
1240 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1242 def test_mpls(self):
1246 # Interface 2 does not yet have ip4 config
1248 self.pg2.config_ip4()
1249 self.pg2.generate_remote_hosts(2)
1252 # Add a route with out going label via an ARP unresolved next-hop
1254 ip_10_0_0_1 = VppIpRoute(
1260 self.pg2.remote_hosts[1].ip4, self.pg2.sw_if_index, labels=[55]
1264 ip_10_0_0_1.add_vpp_config()
1267 # packets should generate an ARP request
1270 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1271 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
1272 / UDP(sport=1234, dport=1234)
1273 / Raw(b"\xa5" * 100)
1276 self.pg0.add_stream(p)
1277 self.pg_enable_capture(self.pg_interfaces)
1280 rx = self.pg2.get_capture(1)
1281 self.verify_arp_req(
1282 rx[0], self.pg2.local_mac, self.pg2.local_ip4, self.pg2._remote_hosts[1].ip4
1286 # now resolve the neighbours
1288 self.pg2.configure_ipv4_neighbors()
1291 # Now packet should be properly MPLS encapped.
1292 # This verifies that MPLS link-type adjacencies are completed
1293 # when the ARP entry resolves
1295 self.pg0.add_stream(p)
1296 self.pg_enable_capture(self.pg_interfaces)
1299 rx = self.pg2.get_capture(1)
1300 self.verify_ip_o_mpls(
1303 self.pg2.remote_hosts[1].mac,
1305 self.pg0.remote_ip4,
1308 self.pg2.unconfig_ip4()
1310 def test_arp_vrrp(self):
1311 """ARP reply with VRRP virtual src hw addr"""
1314 # IP packet destined for pg1 remote host arrives on pg0 resulting
1315 # in an ARP request for the address of the remote host on pg1
1318 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1319 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
1320 / UDP(sport=1234, dport=1234)
1324 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1326 self.verify_arp_req(
1327 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
1331 # ARP reply for address of pg1 remote host arrives on pg1 with
1332 # the hw src addr set to a value in the VRRP IPv4 range of
1335 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1337 hwdst=self.pg1.local_mac,
1338 hwsrc="00:00:5e:00:01:09",
1339 pdst=self.pg1.local_ip4,
1340 psrc=self.pg1.remote_ip4,
1343 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1346 # IP packet destined for pg1 remote host arrives on pg0 again.
1347 # VPP should have an ARP entry for that address now and the packet
1348 # should be sent out pg1.
1350 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1355 "00:00:5e:00:01:09",
1356 self.pg0.remote_ip4,
1357 self.pg1.remote_ip4,
1360 self.pg1.admin_down()
1363 def test_arp_duplicates(self):
1364 """ARP Duplicates"""
1367 # Generate some hosts on the LAN
1369 self.pg1.generate_remote_hosts(3)
1372 # Add host 1 on pg1 and pg2
1374 arp_pg1 = VppNeighbor(
1376 self.pg1.sw_if_index,
1377 self.pg1.remote_hosts[1].mac,
1378 self.pg1.remote_hosts[1].ip4,
1380 arp_pg1.add_vpp_config()
1381 arp_pg2 = VppNeighbor(
1383 self.pg2.sw_if_index,
1384 self.pg2.remote_mac,
1385 self.pg1.remote_hosts[1].ip4,
1387 arp_pg2.add_vpp_config()
1390 # IP packet destined for pg1 remote host arrives on pg1 again.
1393 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1394 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1395 / UDP(sport=1234, dport=1234)
1399 self.pg0.add_stream(p)
1400 self.pg_enable_capture(self.pg_interfaces)
1403 rx1 = self.pg1.get_capture(1)
1408 self.pg1.remote_hosts[1].mac,
1409 self.pg0.remote_ip4,
1410 self.pg1.remote_hosts[1].ip4,
1414 # remove the duplicate on pg1
1415 # packet stream should generate ARPs out of pg1
1417 arp_pg1.remove_vpp_config()
1419 self.pg0.add_stream(p)
1420 self.pg_enable_capture(self.pg_interfaces)
1423 rx1 = self.pg1.get_capture(1)
1425 self.verify_arp_req(
1426 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4
1432 arp_pg1.add_vpp_config()
1434 self.pg0.add_stream(p)
1435 self.pg_enable_capture(self.pg_interfaces)
1438 rx1 = self.pg1.get_capture(1)
1443 self.pg1.remote_hosts[1].mac,
1444 self.pg0.remote_ip4,
1445 self.pg1.remote_hosts[1].ip4,
1448 def test_arp_static(self):
1450 self.pg2.generate_remote_hosts(3)
1453 # Add a static ARP entry
1455 static_arp = VppNeighbor(
1457 self.pg2.sw_if_index,
1458 self.pg2.remote_hosts[1].mac,
1459 self.pg2.remote_hosts[1].ip4,
1462 static_arp.add_vpp_config()
1465 # Add the connected prefix to the interface
1467 self.pg2.config_ip4()
1470 # We should now find the adj-fib
1474 self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].ip4, is_static=1
1477 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32))
1480 # remove the connected
1482 self.pg2.unconfig_ip4()
1485 # put the interface into table 1
1487 self.pg2.set_table_ip4(1)
1490 # configure the same connected and expect to find the
1491 # adj fib in the new table
1493 self.pg2.config_ip4()
1494 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1))
1499 self.pg2.unconfig_ip4()
1500 static_arp.remove_vpp_config()
1501 self.pg2.set_table_ip4(0)
1503 def test_arp_static_replace_dynamic_same_mac(self):
1504 """ARP Static can replace Dynamic (same mac)"""
1505 self.pg2.generate_remote_hosts(1)
1507 dyn_arp = VppNeighbor(
1509 self.pg2.sw_if_index,
1510 self.pg2.remote_hosts[0].mac,
1511 self.pg2.remote_hosts[0].ip4,
1513 static_arp = VppNeighbor(
1515 self.pg2.sw_if_index,
1516 self.pg2.remote_hosts[0].mac,
1517 self.pg2.remote_hosts[0].ip4,
1522 # Add a dynamic ARP entry
1524 dyn_arp.add_vpp_config()
1527 # We should find the dynamic nbr
1531 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1537 self.pg2.sw_if_index,
1538 self.pg2.remote_hosts[0].ip4,
1540 mac=self.pg2.remote_hosts[0].mac,
1545 # Add a static ARP entry with the same mac
1547 static_arp.add_vpp_config()
1550 # We should now find the static nbr with the same mac
1554 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1560 self.pg2.sw_if_index,
1561 self.pg2.remote_hosts[0].ip4,
1563 mac=self.pg2.remote_hosts[0].mac,
1570 static_arp.remove_vpp_config()
1572 def test_arp_static_replace_dynamic_diff_mac(self):
1573 """ARP Static can replace Dynamic (diff mac)"""
1574 self.pg2.generate_remote_hosts(2)
1576 dyn_arp = VppNeighbor(
1578 self.pg2.sw_if_index,
1579 self.pg2.remote_hosts[0].mac,
1580 self.pg2.remote_hosts[0].ip4,
1582 static_arp = VppNeighbor(
1584 self.pg2.sw_if_index,
1585 self.pg2.remote_hosts[1].mac,
1586 self.pg2.remote_hosts[0].ip4,
1591 # Add a dynamic ARP entry
1593 dyn_arp.add_vpp_config()
1596 # We should find the dynamic nbr
1600 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1606 self.pg2.sw_if_index,
1607 self.pg2.remote_hosts[0].ip4,
1609 mac=self.pg2.remote_hosts[0].mac,
1614 # Add a static ARP entry with a changed mac
1616 static_arp.add_vpp_config()
1619 # We should now find the static nbr with a changed mac
1623 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1629 self.pg2.sw_if_index,
1630 self.pg2.remote_hosts[0].ip4,
1632 mac=self.pg2.remote_hosts[1].mac,
1639 static_arp.remove_vpp_config()
1641 def test_arp_incomplete(self):
1642 """ARP Incomplete"""
1643 self.pg1.generate_remote_hosts(4)
1646 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1647 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1648 / UDP(sport=1234, dport=1234)
1652 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1653 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
1654 / UDP(sport=1234, dport=1234)
1658 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1659 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
1660 / UDP(sport=1234, dport=1234)
1665 # a packet to an unresolved destination generates an ARP request
1667 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1668 self.verify_arp_req(
1669 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
1673 # add a neighbour for remote host 1
1675 static_arp = VppNeighbor(
1677 self.pg1.sw_if_index,
1678 self.pg1.remote_hosts[1].mac,
1679 self.pg1.remote_hosts[1].ip4,
1682 static_arp.add_vpp_config()
1685 # add a route through remote host 3 hence we get an incomplete
1691 [VppRoutePath(self.pg1.remote_hosts[3].ip4, self.pg1.sw_if_index)],
1693 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1694 self.verify_arp_req(
1695 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4
1699 # change the interface's MAC
1701 self.vapi.sw_interface_set_mac_address(
1702 self.pg1.sw_if_index, "00:00:00:33:33:33"
1706 # now ARP requests come from the new source mac
1708 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1709 self.verify_arp_req(
1711 "00:00:00:33:33:33",
1713 self.pg1._remote_hosts[2].ip4,
1715 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1716 self.verify_arp_req(
1718 "00:00:00:33:33:33",
1720 self.pg1._remote_hosts[3].ip4,
1724 # packets to the resolved host also have the new source mac
1726 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1729 "00:00:00:33:33:33",
1730 self.pg1.remote_hosts[1].mac,
1731 self.pg0.remote_ip4,
1732 self.pg1.remote_hosts[1].ip4,
1736 # set the mac address on the interface that does not have a
1737 # configured subnet and thus no glean
1739 self.vapi.sw_interface_set_mac_address(
1740 self.pg2.sw_if_index, "00:00:00:33:33:33"
1743 def test_garp(self):
1747 # Generate some hosts on the LAN
1749 self.pg1.generate_remote_hosts(4)
1750 self.pg2.generate_remote_hosts(4)
1757 self.pg1.sw_if_index,
1758 self.pg1.remote_hosts[1].mac,
1759 self.pg1.remote_hosts[1].ip4,
1761 arp.add_vpp_config()
1766 self.pg1.sw_if_index,
1767 self.pg1.remote_hosts[1].ip4,
1768 mac=self.pg1.remote_hosts[1].mac,
1773 # Send a GARP (request) to swap the host 1's address to that of host 2
1775 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) / ARP(
1777 hwdst=self.pg1.local_mac,
1778 hwsrc=self.pg1.remote_hosts[2].mac,
1779 pdst=self.pg1.remote_hosts[1].ip4,
1780 psrc=self.pg1.remote_hosts[1].ip4,
1783 self.pg1.add_stream(p1)
1784 self.pg_enable_capture(self.pg_interfaces)
1790 self.pg1.sw_if_index,
1791 self.pg1.remote_hosts[1].ip4,
1792 mac=self.pg1.remote_hosts[2].mac,
1795 self.assert_equal(self.get_arp_rx_garp(self.pg1), 1)
1798 # Send a GARP (reply) to swap the host 1's address to that of host 3
1800 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1802 hwdst=self.pg1.local_mac,
1803 hwsrc=self.pg1.remote_hosts[3].mac,
1804 pdst=self.pg1.remote_hosts[1].ip4,
1805 psrc=self.pg1.remote_hosts[1].ip4,
1808 self.pg1.add_stream(p1)
1809 self.pg_enable_capture(self.pg_interfaces)
1815 self.pg1.sw_if_index,
1816 self.pg1.remote_hosts[1].ip4,
1817 mac=self.pg1.remote_hosts[3].mac,
1820 self.assert_equal(self.get_arp_rx_garp(self.pg1), 2)
1823 # GARPs (request nor replies) for host we don't know yet
1824 # don't result in new neighbour entries
1826 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1828 hwdst=self.pg1.local_mac,
1829 hwsrc=self.pg1.remote_hosts[3].mac,
1830 pdst=self.pg1.remote_hosts[2].ip4,
1831 psrc=self.pg1.remote_hosts[2].ip4,
1834 self.pg1.add_stream(p1)
1835 self.pg_enable_capture(self.pg_interfaces)
1839 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1842 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1844 hwdst=self.pg1.local_mac,
1845 hwsrc=self.pg1.remote_hosts[3].mac,
1846 pdst=self.pg1.remote_hosts[2].ip4,
1847 psrc=self.pg1.remote_hosts[2].ip4,
1850 self.pg1.add_stream(p1)
1851 self.pg_enable_capture(self.pg_interfaces)
1855 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1859 # IP address in different subnets are not learnt
1861 self.pg2.configure_ipv4_neighbors()
1863 cntr = self.statistics.get_err_counter(
1864 "/err/arp-reply/l3_dst_address_not_local"
1867 for op in ["is-at", "who-has"]:
1870 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1873 hwdst=self.pg2.local_mac,
1874 hwsrc=self.pg2.remote_hosts[1].mac,
1875 pdst=self.pg2.remote_hosts[1].ip4,
1876 psrc=self.pg2.remote_hosts[1].ip4,
1880 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1883 hwdst="ff:ff:ff:ff:ff:ff",
1884 hwsrc=self.pg2.remote_hosts[1].mac,
1885 pdst=self.pg2.remote_hosts[1].ip4,
1886 psrc=self.pg2.remote_hosts[1].ip4,
1891 self.send_and_assert_no_replies(self.pg1, p1)
1893 find_nbr(self, self.pg1.sw_if_index, self.pg2.remote_hosts[1].ip4)
1896 # they are all dropped because the subnet's don't match
1899 self.statistics.get_err_counter("/err/arp-reply/l3_dst_address_not_local"),
1902 def test_arp_incomplete2(self):
1903 """Incomplete Entries"""
1906 # ensure that we throttle the ARP and ND requests
1908 self.pg0.generate_remote_hosts(2)
1913 ip_10_0_0_1 = VppIpRoute(
1917 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1919 ip_10_0_0_1.add_vpp_config()
1922 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1923 / IP(src=self.pg1.remote_ip4, dst="10.0.0.1")
1924 / UDP(sport=1234, dport=1234)
1928 self.pg1.add_stream(p1 * 257)
1929 self.pg_enable_capture(self.pg_interfaces)
1931 rx = self.pg0._get_capture(1)
1934 # how many we get is going to be dependent on the time for packet
1935 # processing but it should be small
1937 self.assertLess(len(rx), 64)
1942 ip_10_1 = VppIpRoute(
1948 self.pg0.remote_hosts[1].ip6,
1949 self.pg0.sw_if_index,
1950 proto=DpoProto.DPO_PROTO_IP6,
1954 ip_10_1.add_vpp_config()
1957 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1958 / IPv6(src=self.pg1.remote_ip6, dst="10::1")
1959 / UDP(sport=1234, dport=1234)
1963 self.pg1.add_stream(p1 * 257)
1964 self.pg_enable_capture(self.pg_interfaces)
1966 rx = self.pg0._get_capture(1)
1969 # how many we get is going to be dependent on the time for packet
1970 # processing but it should be small
1972 self.assertLess(len(rx), 64)
1974 def test_arp_forus(self):
1975 """ARP for for-us"""
1978 # Test that VPP responds with ARP requests to addresses that
1979 # are connected and local routes.
1980 # Use one of the 'remote' addresses in the subnet as a local address
1981 # The intention of this route is that it then acts like a secondary
1982 # address added to an interface
1984 self.pg0.generate_remote_hosts(2)
1988 self.pg0.remote_hosts[1].ip4,
1993 self.pg0.sw_if_index,
1994 type=FibPathType.FIB_PATH_TYPE_LOCAL,
1998 forus.add_vpp_config()
2000 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
2002 hwdst=self.pg0.local_mac,
2003 hwsrc=self.pg0.remote_mac,
2004 pdst=self.pg0.remote_hosts[1].ip4,
2005 psrc=self.pg0.remote_ip4,
2008 rx = self.send_and_expect(self.pg0, [p], self.pg0)
2010 self.verify_arp_resp(
2013 self.pg0.remote_mac,
2014 self.pg0.remote_hosts[1].ip4,
2015 self.pg0.remote_ip4,
2018 def test_arp_table_swap(self):
2020 # Generate some hosts on the LAN
2023 self.pg1.generate_remote_hosts(N_NBRS)
2025 for n in range(N_NBRS):
2026 # a route thru each neighbour
2031 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
2034 # resolve each neighbour
2035 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
2037 hwdst=self.pg1.local_mac,
2038 hwsrc="00:00:5e:00:01:09",
2039 pdst=self.pg1.local_ip4,
2040 psrc=self.pg1.remote_hosts[n].ip4,
2043 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
2045 self.logger.info(self.vapi.cli("sh ip neighbors"))
2048 # swap the table pg1 is in
2050 table = VppIpTable(self, 100).add_vpp_config()
2052 self.pg1.unconfig_ip4()
2053 self.pg1.set_table_ip4(100)
2054 self.pg1.config_ip4()
2057 # all neighbours are cleared
2059 for n in range(N_NBRS):
2061 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip4)
2065 # packets to all neighbours generate ARP requests
2067 for n in range(N_NBRS):
2068 # a route thru each neighbour
2073 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
2078 Ether(src=self.pg1.remote_hosts[n].mac, dst=self.pg1.local_mac)
2079 / IP(src=self.pg1.remote_hosts[n].ip4, dst="10.0.0.%d" % n)
2082 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
2084 self.verify_arp_req(
2088 self.pg1.remote_hosts[n].ip4,
2091 self.pg1.unconfig_ip4()
2092 self.pg1.set_table_ip4(0)
2094 def test_glean_src_select(self):
2095 """Multi Connecteds"""
2098 # configure multiple connected subnets on an interface
2099 # and ensure that ARP requests for hosts on those subnets
2100 # pick up the correct source address
2102 conn1 = VppIpInterfaceAddress(self, self.pg1, "10.0.0.1", 24).add_vpp_config()
2103 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2106 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2107 / IP(src=self.pg1.remote_ip4, dst="10.0.0.128")
2111 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
2113 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.0.1", "10.0.0.128")
2116 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2117 / IP(src=self.pg1.remote_ip4, dst="10.0.1.128")
2121 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2123 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2126 # add a local address in the same subnet
2127 # the source addresses are equivalent.
2128 # VPP leaves the glean address being used for a prefix
2129 # in place until that address is deleted.
2131 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2133 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2135 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2138 # remove first address, which is currently in use
2139 # the second address should be used now
2141 conn2.remove_vpp_config()
2142 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2144 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2147 # add first address back. Second address should continue
2150 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2151 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2153 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2155 conn1.remove_vpp_config()
2156 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2158 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2160 # apply a connected prefix to an interface in a different table
2165 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2169 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2171 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2173 # apply an attached prefix to the interface
2174 # since there's no local address in this prefix,
2175 # any other address is used
2177 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2178 / IP(src=self.pg1.remote_ip4, dst="10.0.2.128")
2186 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2189 rxs = self.send_and_expect(self.pg0, [p3], self.pg1)
2191 self.verify_arp_req(
2192 rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128"
2196 conn3.remove_vpp_config()
2197 conn2.remove_vpp_config()
2200 @tag_fixme_vpp_workers
2201 class NeighborStatsTestCase(VppTestCase):
2202 """ARP/ND Counters"""
2205 def setUpClass(cls):
2206 super(NeighborStatsTestCase, cls).setUpClass()
2209 def tearDownClass(cls):
2210 super(NeighborStatsTestCase, cls).tearDownClass()
2213 super(NeighborStatsTestCase, self).setUp()
2215 self.create_pg_interfaces(range(2))
2217 # pg0 configured with ip4 and 6 addresses used for input
2218 # pg1 configured with ip4 and 6 addresses used for output
2219 # pg2 is unnumbered to pg0
2220 for i in self.pg_interfaces:
2228 super(NeighborStatsTestCase, self).tearDown()
2230 for i in self.pg_interfaces:
2235 def test_arp_stats(self):
2238 self.vapi.cli("adj counters enable")
2239 self.pg1.generate_remote_hosts(2)
2243 self.pg1.sw_if_index,
2244 self.pg1.remote_hosts[0].mac,
2245 self.pg1.remote_hosts[0].ip4,
2247 arp1.add_vpp_config()
2250 self.pg1.sw_if_index,
2251 self.pg1.remote_hosts[1].mac,
2252 self.pg1.remote_hosts[1].ip4,
2254 arp2.add_vpp_config()
2257 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2258 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2259 / UDP(sport=1234, dport=1234)
2263 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2264 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2265 / UDP(sport=1234, dport=1234)
2269 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2270 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2272 self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2273 self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2275 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2276 self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2278 def test_nd_stats(self):
2281 self.vapi.cli("adj counters enable")
2282 self.pg0.generate_remote_hosts(3)
2286 self.pg0.sw_if_index,
2287 self.pg0.remote_hosts[1].mac,
2288 self.pg0.remote_hosts[1].ip6,
2290 nd1.add_vpp_config()
2293 self.pg0.sw_if_index,
2294 self.pg0.remote_hosts[2].mac,
2295 self.pg0.remote_hosts[2].ip6,
2297 nd2.add_vpp_config()
2300 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2301 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2302 / UDP(sport=1234, dport=1234)
2306 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2307 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2308 / UDP(sport=1234, dport=1234)
2312 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2313 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2315 self.assertEqual(16, nd1.get_stats()["packets"])
2316 self.assertEqual(16, nd2.get_stats()["packets"])
2318 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2319 self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2322 @tag_fixme_ubuntu2204
2323 class NeighborAgeTestCase(VppTestCase):
2327 def setUpClass(cls):
2328 super(NeighborAgeTestCase, cls).setUpClass()
2331 def tearDownClass(cls):
2332 super(NeighborAgeTestCase, cls).tearDownClass()
2335 super(NeighborAgeTestCase, self).setUp()
2337 self.create_pg_interfaces(range(1))
2339 # pg0 configured with ip4 and 6 addresses used for input
2340 # pg1 configured with ip4 and 6 addresses used for output
2341 # pg2 is unnumbered to pg0
2342 for i in self.pg_interfaces:
2350 super(NeighborAgeTestCase, self).tearDown()
2352 for i in self.pg_interfaces:
2357 def verify_arp_req(self, rx, smac, sip, dip):
2359 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2360 self.assertEqual(ether.src, smac)
2363 self.assertEqual(arp.hwtype, 1)
2364 self.assertEqual(arp.ptype, 0x800)
2365 self.assertEqual(arp.hwlen, 6)
2366 self.assertEqual(arp.plen, 4)
2367 self.assertEqual(arp.op, arp_opts["who-has"])
2368 self.assertEqual(arp.hwsrc, smac)
2369 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2370 self.assertEqual(arp.psrc, sip)
2371 self.assertEqual(arp.pdst, dip)
2373 def verify_ip_neighbor_config(self, af, max_number, max_age, recycle):
2374 config = self.vapi.ip_neighbor_config_get(af)
2376 self.assertEqual(config.af, af)
2377 self.assertEqual(config.max_number, max_number)
2378 self.assertEqual(config.max_age, max_age)
2379 self.assertEqual(config.recycle, recycle)
2384 self.vapi.cli("set logging unthrottle 0")
2385 self.vapi.cli("set logging size %d" % 0xFFFF)
2387 self.pg0.generate_remote_hosts(201)
2389 vaf = VppEnum.vl_api_address_family_t
2392 # start listening on all interfaces
2394 self.pg_enable_capture(self.pg_interfaces)
2397 # Verify neighbor configuration defaults
2399 self.verify_ip_neighbor_config(
2400 af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False
2404 # Set the neighbor configuration:
2409 self.vapi.ip_neighbor_config(
2410 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2412 self.verify_ip_neighbor_config(
2413 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2416 self.vapi.cli("sh ip neighbor-config")
2418 # add the 198 neighbours that should pass (-1 for one created in setup)
2419 for ii in range(200):
2422 self.pg0.sw_if_index,
2423 self.pg0.remote_hosts[ii].mac,
2424 self.pg0.remote_hosts[ii].ip4,
2427 # one more neighbor over the limit should fail
2428 with self.vapi.assert_negative_api_retval():
2431 self.pg0.sw_if_index,
2432 self.pg0.remote_hosts[200].mac,
2433 self.pg0.remote_hosts[200].ip4,
2437 # change the config to allow recycling the old neighbors
2439 self.vapi.ip_neighbor_config(
2440 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2442 self.verify_ip_neighbor_config(
2443 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2446 # now new additions are allowed
2449 self.pg0.sw_if_index,
2450 self.pg0.remote_hosts[200].mac,
2451 self.pg0.remote_hosts[200].ip4,
2454 # add the first neighbor we configured has been re-used
2456 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2459 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2463 # change the config to age old neighbors
2465 self.vapi.ip_neighbor_config(
2466 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2468 self.verify_ip_neighbor_config(
2469 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2472 self.vapi.cli("sh ip4 neighbor-sorted")
2475 self.virtual_sleep(3)
2478 # expect probes from all these ARP entries as they age
2479 # 3 probes for each neighbor 3*200 = 600
2480 rxs = self.pg0.get_capture(600, timeout=2)
2483 for jj in range(200):
2484 rx = rxs[ii * 200 + jj]
2488 # 3 probes sent then 1 more second to see if a reply comes, before
2491 self.virtual_sleep(1)
2494 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2498 # load up some neighbours again with 2s aging enabled
2499 # they should be removed after 10s (2s age + 4s for probes + gap)
2500 # check for the add and remove events
2502 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2504 self.vapi.want_ip_neighbor_events_v2(enable=1)
2505 for ii in range(10):
2508 self.pg0.sw_if_index,
2509 self.pg0.remote_hosts[ii].mac,
2510 self.pg0.remote_hosts[ii].ip4,
2513 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2514 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2515 self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2516 self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2518 self.virtual_sleep(10)
2520 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2524 for ii in range(10):
2525 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2526 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2529 # check we got the correct mac/ip pairs - done separately
2530 # because we don't care about the order the remove notifications
2532 for ii in range(10):
2534 mac = self.pg0.remote_hosts[ii].mac
2535 ip = self.pg0.remote_hosts[ii].ip4
2538 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2541 self.assertTrue(found)
2544 # check if we can set age and recycle with empty neighbor list
2546 self.vapi.ip_neighbor_config(
2547 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2549 self.verify_ip_neighbor_config(
2550 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2554 # load up some neighbours again, then disable the aging
2555 # they should still be there in 10 seconds time
2557 for ii in range(10):
2560 self.pg0.sw_if_index,
2561 self.pg0.remote_hosts[ii].mac,
2562 self.pg0.remote_hosts[ii].ip4,
2564 self.vapi.ip_neighbor_config(
2565 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2567 self.verify_ip_neighbor_config(
2568 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2571 self.virtual_sleep(10)
2573 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2577 class NeighborReplaceTestCase(VppTestCase):
2578 """ARP/ND Replacement"""
2581 def setUpClass(cls):
2582 super(NeighborReplaceTestCase, cls).setUpClass()
2585 def tearDownClass(cls):
2586 super(NeighborReplaceTestCase, cls).tearDownClass()
2589 super(NeighborReplaceTestCase, self).setUp()
2591 self.create_pg_interfaces(range(4))
2593 # pg0 configured with ip4 and 6 addresses used for input
2594 # pg1 configured with ip4 and 6 addresses used for output
2595 # pg2 is unnumbered to pg0
2596 for i in self.pg_interfaces:
2604 super(NeighborReplaceTestCase, self).tearDown()
2606 for i in self.pg_interfaces:
2611 def test_replace(self):
2616 for i in self.pg_interfaces:
2617 i.generate_remote_hosts(N_HOSTS)
2618 i.configure_ipv4_neighbors()
2619 i.configure_ipv6_neighbors()
2622 self.vapi.ip_neighbor_replace_begin()
2623 self.vapi.ip_neighbor_replace_end()
2625 for i in self.pg_interfaces:
2626 for h in range(N_HOSTS):
2628 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2631 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2635 # and them all back via the API
2637 for i in self.pg_interfaces:
2638 for h in range(N_HOSTS):
2640 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2643 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2647 # begin the replacement again, this time touch some
2648 # the neighbours on pg1 so they are not deleted
2650 self.vapi.ip_neighbor_replace_begin()
2652 # update from the API all neighbours on pg1
2653 for h in range(N_HOSTS):
2656 self.pg1.sw_if_index,
2657 self.pg1.remote_hosts[h].mac,
2658 self.pg1.remote_hosts[h].ip4,
2662 self.pg1.sw_if_index,
2663 self.pg1.remote_hosts[h].mac,
2664 self.pg1.remote_hosts[h].ip6,
2667 # update from the data-plane all neighbours on pg3
2668 self.pg3.configure_ipv4_neighbors()
2669 self.pg3.configure_ipv6_neighbors()
2671 # complete the replacement
2672 self.logger.info(self.vapi.cli("sh ip neighbors"))
2673 self.vapi.ip_neighbor_replace_end()
2675 for i in self.pg_interfaces:
2676 if i == self.pg1 or i == self.pg3:
2677 # neighbours on pg1 and pg3 are still present
2678 for h in range(N_HOSTS):
2680 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2683 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2686 # all other neighbours are toast
2687 for h in range(N_HOSTS):
2689 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2692 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2696 class NeighborFlush(VppTestCase):
2697 """Neighbor Flush"""
2700 def setUpClass(cls):
2701 super(NeighborFlush, cls).setUpClass()
2704 def tearDownClass(cls):
2705 super(NeighborFlush, cls).tearDownClass()
2708 super(NeighborFlush, self).setUp()
2710 self.create_pg_interfaces(range(2))
2712 for i in self.pg_interfaces:
2720 super(NeighborFlush, self).tearDown()
2722 for i in self.pg_interfaces:
2727 def test_flush(self):
2728 """Neighbour Flush"""
2731 nf = e.vl_api_ip_neighbor_flags_t
2732 af = e.vl_api_address_family_t
2734 static = [False, True]
2735 self.pg0.generate_remote_hosts(N_HOSTS)
2736 self.pg1.generate_remote_hosts(N_HOSTS)
2739 # a few v4 and v6 dynamic neoghbors
2740 for n in range(N_HOSTS):
2743 self.pg0.sw_if_index,
2744 self.pg0.remote_hosts[n].mac,
2745 self.pg0.remote_hosts[n].ip4,
2750 self.pg1.sw_if_index,
2751 self.pg1.remote_hosts[n].mac,
2752 self.pg1.remote_hosts[n].ip6,
2756 # flush the interfaces individually
2757 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2759 # check we haven't flushed that which we shouldn't
2760 for n in range(N_HOSTS):
2764 self.pg1.sw_if_index,
2765 self.pg1.remote_hosts[n].ip6,
2770 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2772 for n in range(N_HOSTS):
2774 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2777 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2780 # add the nieghbours back
2781 for n in range(N_HOSTS):
2784 self.pg0.sw_if_index,
2785 self.pg0.remote_hosts[n].mac,
2786 self.pg0.remote_hosts[n].ip4,
2791 self.pg1.sw_if_index,
2792 self.pg1.remote_hosts[n].mac,
2793 self.pg1.remote_hosts[n].ip6,
2797 self.logger.info(self.vapi.cli("sh ip neighbor"))
2799 # flush both interfaces at the same time
2800 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2802 # check we haven't flushed that which we shouldn't
2803 for n in range(N_HOSTS):
2807 self.pg0.sw_if_index,
2808 self.pg0.remote_hosts[n].ip4,
2813 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2815 for n in range(N_HOSTS):
2817 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2820 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2824 if __name__ == "__main__":
2825 unittest.main(testRunner=VppTestRunner)