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)
435 # Allow for ARP requests from point-to-point ethernet neighbors
436 # without an attached route on pg2
437 self.pg2.add_stream(p)
438 self.pg_enable_capture(self.pg_interfaces)
441 rx = self.pg2.get_capture(1)
442 self.verify_arp_resp(
447 self.pg2.remote_hosts[3].ip4,
451 # Allow for ARP requests from neighbors on unnumbered with
452 # an attached route on pg2
453 attached_host = VppIpRoute(
455 self.pg2.remote_hosts[3].ip4,
457 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
459 attached_host.add_vpp_config()
461 self.pg2.add_stream(p)
462 self.pg_enable_capture(self.pg_interfaces)
465 rx = self.pg2.get_capture(1)
466 self.verify_arp_resp(
471 self.pg2.remote_hosts[3].ip4,
474 self.pg2.add_stream(pt)
475 self.pg_enable_capture(self.pg_interfaces)
478 rx = self.pg2.get_capture(1)
479 self.verify_arp_resp(
484 self.pg2.remote_hosts[3].ip4,
488 # A neighbor entry that has no associated FIB-entry
490 arp_no_fib = VppNeighbor(
492 self.pg1.sw_if_index,
493 self.pg1.remote_hosts[4].mac,
494 self.pg1.remote_hosts[4].ip4,
497 arp_no_fib.add_vpp_config()
500 # check we have the neighbor, but no route
503 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)
505 self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32))
507 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
508 # from within pg1's subnet
510 arp_unnum = VppNeighbor(
512 self.pg2.sw_if_index,
513 self.pg1.remote_hosts[5].mac,
514 self.pg1.remote_hosts[5].ip4,
516 arp_unnum.add_vpp_config()
519 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
520 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4)
521 / UDP(sport=1234, dport=1234)
525 self.pg0.add_stream(p)
526 self.pg_enable_capture(self.pg_interfaces)
529 rx = self.pg2.get_capture(1)
534 self.pg1.remote_hosts[5].mac,
536 self.pg1._remote_hosts[5].ip4,
540 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
541 # with the unnumbered interface's address as the source
543 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
545 hwsrc=self.pg2.remote_mac,
546 pdst=self.pg1.local_ip4,
547 psrc=self.pg1.remote_hosts[6].ip4,
550 self.pg2.add_stream(p)
551 self.pg_enable_capture(self.pg_interfaces)
554 rx = self.pg2.get_capture(1)
555 self.verify_arp_resp(
560 self.pg1.remote_hosts[6].ip4,
564 # An attached host route out of pg2 for an undiscovered hosts generates
565 # an ARP request with the unnumbered address as the source
567 att_unnum = VppIpRoute(
569 self.pg1.remote_hosts[7].ip4,
571 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
573 att_unnum.add_vpp_config()
576 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
577 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4)
578 / UDP(sport=1234, dport=1234)
582 self.pg0.add_stream(p)
583 self.pg_enable_capture(self.pg_interfaces)
586 rx = self.pg2.get_capture(1)
589 rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4
592 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
594 hwsrc=self.pg2.remote_mac,
595 pdst=self.pg1.local_ip4,
596 psrc=self.pg1.remote_hosts[7].ip4,
599 self.pg2.add_stream(p)
600 self.pg_enable_capture(self.pg_interfaces)
603 rx = self.pg2.get_capture(1)
604 self.verify_arp_resp(
609 self.pg1.remote_hosts[7].ip4,
613 # An attached host route as yet unresolved out of pg2 for an
614 # undiscovered host, an ARP requests begets a response.
616 att_unnum1 = VppIpRoute(
618 self.pg1.remote_hosts[8].ip4,
620 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
622 att_unnum1.add_vpp_config()
624 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
626 hwsrc=self.pg2.remote_mac,
627 pdst=self.pg1.local_ip4,
628 psrc=self.pg1.remote_hosts[8].ip4,
631 self.pg2.add_stream(p)
632 self.pg_enable_capture(self.pg_interfaces)
635 rx = self.pg2.get_capture(1)
636 self.verify_arp_resp(
641 self.pg1.remote_hosts[8].ip4,
645 # Send an ARP request from one of the so-far unlearned remote hosts
649 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac)
653 hwsrc=self.pg1._remote_hosts[9].mac,
654 pdst=self.pg1.local_ip4,
655 psrc=self.pg1._remote_hosts[9].ip4,
659 self.pg1.add_stream(p)
660 self.pg_enable_capture(self.pg_interfaces)
663 rx = self.pg1.get_capture(1)
664 self.verify_arp_resp(
667 self.pg1._remote_hosts[9].mac,
669 self.pg1._remote_hosts[9].ip4,
673 # Add a hierarchy of routes for a host in the sub-net.
674 # Should still get an ARP resp since the cover is attached
676 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(
678 hwsrc=self.pg1.remote_mac,
679 pdst=self.pg1.local_ip4,
680 psrc=self.pg1.remote_hosts[10].ip4,
685 self.pg1.remote_hosts[10].ip4,
687 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
691 self.pg1.add_stream(p)
692 self.pg_enable_capture(self.pg_interfaces)
694 rx = self.pg1.get_capture(1)
695 self.verify_arp_resp(
700 self.pg1.remote_hosts[10].ip4,
705 self.pg1.remote_hosts[10].ip4,
707 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
711 self.pg1.add_stream(p)
712 self.pg_enable_capture(self.pg_interfaces)
714 rx = self.pg1.get_capture(1)
715 self.verify_arp_resp(
720 self.pg1.remote_hosts[10].ip4,
724 # add an ARP entry that's not on the sub-net and so whose
725 # adj-fib fails the refinement check. then send an ARP request
729 self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50"
733 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
735 hwsrc=self.pg0.remote_mac,
736 psrc="100.100.100.50",
737 pdst=self.pg0.remote_ip4,
739 self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib")
743 # 1 - don't respond to ARP request for address not within the
744 # interface's sub-net
745 # 1b - nor within the unnumbered subnet
746 # 1c - nor within the subnet of a different interface
748 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
750 hwsrc=self.pg0.remote_mac,
752 psrc=self.pg0.remote_ip4,
754 self.send_and_assert_no_replies(
755 self.pg0, p, "ARP req for non-local destination"
757 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3"))
759 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
761 hwsrc=self.pg2.remote_mac,
763 psrc=self.pg1.remote_hosts[7].ip4,
765 self.send_and_assert_no_replies(
766 self.pg0, p, "ARP req for non-local destination - unnum"
769 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
771 hwsrc=self.pg0.remote_mac,
772 pdst=self.pg1.local_ip4,
773 psrc=self.pg1.remote_ip4,
775 self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net")
776 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4))
779 # 2 - don't respond to ARP request from an address not within the
780 # interface's sub-net
781 # 2b - to a proxied address
782 # 2c - not within a different interface's sub-net
783 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
785 hwsrc=self.pg0.remote_mac,
787 pdst=self.pg0.local_ip4,
789 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
790 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
792 hwsrc=self.pg2.remote_mac,
794 pdst=self.pg0.local_ip4,
796 self.send_and_assert_no_replies(
797 self.pg0, p, "ARP req for non-local source - unnum"
799 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
801 hwsrc=self.pg0.remote_mac,
802 psrc=self.pg1.remote_ip4,
803 pdst=self.pg0.local_ip4,
805 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c")
808 # 3 - don't respond to ARP request from an address that belongs to
811 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
813 hwsrc=self.pg0.remote_mac,
814 psrc=self.pg0.local_ip4,
815 pdst=self.pg0.local_ip4,
817 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
820 # 4 - don't respond to ARP requests that has mac source different
821 # from ARP request HW source
823 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
825 hwsrc="00:00:00:DE:AD:BE",
826 psrc=self.pg0.remote_ip4,
827 pdst=self.pg0.local_ip4,
829 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
832 # 5 - don't respond to ARP requests for address within the
833 # interface's sub-net but not the interface's address
835 self.pg0.generate_remote_hosts(2)
836 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
838 hwsrc=self.pg0.remote_mac,
839 psrc=self.pg0.remote_hosts[0].ip4,
840 pdst=self.pg0.remote_hosts[1].ip4,
842 self.send_and_assert_no_replies(
843 self.pg0, p, "ARP req for non-local destination"
849 static_arp.remove_vpp_config()
850 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
852 # need this to flush the adj-fibs
853 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
854 self.pg2.admin_down()
855 self.pg1.admin_down()
857 def test_arp_after_mac_change(self):
858 """ARP (after MAC address change)"""
861 # Prepare a subinterface
863 subif0 = VppDot1ADSubint(self, self.pg1, 0, 300, 400)
868 # Send a packet to cause ARP generation for the parent interface's remote host
871 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
872 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
873 / UDP(sport=1234, dport=1234)
877 self.pg0.add_stream(p1)
878 self.pg_enable_capture(self.pg_interfaces)
881 rx = self.pg1.get_capture(1)
884 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
888 # Send a packet to cause ARP generation for the subinterface's remote host
891 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
892 / IP(src=self.pg0.remote_ip4, dst=subif0.remote_ip4)
893 / UDP(sport=1234, dport=1234)
897 self.pg0.add_stream(p2)
898 self.pg_enable_capture(self.pg_interfaces)
901 rx = self.pg1.get_capture(1)
912 # Change MAC address of the parent interface
914 pg1_mac_saved = self.pg1.local_mac
915 self.pg1.set_mac(MACAddress("00:00:00:11:22:33"))
918 # Send a packet to cause ARP generation for the parent interface's remote host
919 # - expect new MAC address is used as the source
921 self.pg0.add_stream(p1)
922 self.pg_enable_capture(self.pg_interfaces)
925 rx = self.pg1.get_capture(1)
928 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
932 # Send a packet to cause ARP generation for the subinterface's remote host
933 # - expect new MAC address is used as the source
936 self.pg0.add_stream(p2)
937 self.pg_enable_capture(self.pg_interfaces)
940 rx = self.pg1.get_capture(1)
953 subif0.remove_vpp_config()
954 self.pg1.set_mac(MACAddress(pg1_mac_saved))
956 def test_proxy_mirror_arp(self):
957 """Interface Mirror Proxy ARP"""
960 # When VPP has an interface whose address is also applied to a TAP
961 # interface on the host, then VPP's TAP interface will be unnumbered
962 # to the 'real' interface and do proxy ARP from the host.
963 # the curious aspect of this setup is that ARP requests from the host
964 # will come from the VPP's own address.
966 self.pg0.generate_remote_hosts(2)
968 arp_req_from_me = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
970 hwsrc=self.pg2.remote_mac,
971 pdst=self.pg0.remote_hosts[1].ip4,
972 psrc=self.pg0.local_ip4,
976 # Configure Proxy ARP for the subnet on PG0addresses on pg0
978 self.vapi.proxy_arp_add_del(
981 "low": self.pg0._local_ip4_subnet,
982 "hi": self.pg0._local_ip4_bcast,
987 # Make pg2 un-numbered to pg0
989 self.pg2.set_unnumbered(self.pg0.sw_if_index)
992 # Enable pg2 for proxy ARP
994 self.pg2.set_proxy_arp()
997 # Send the ARP request with an originating address that
998 # is VPP's own address
1000 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
1001 self.verify_arp_resp(
1004 self.pg2.remote_mac,
1005 self.pg0.remote_hosts[1].ip4,
1010 # validate we have not learned an ARP entry as a result of this
1012 self.assertFalse(find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4))
1015 # setup a punt redirect so packets from the uplink go to the tap
1017 redirect = VppIpPuntRedirect(
1018 self, self.pg0.sw_if_index, self.pg2.sw_if_index, self.pg0.local_ip4
1020 redirect.add_vpp_config()
1024 src=self.pg0.remote_mac,
1025 dst=self.pg0.local_mac,
1027 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1028 / TCP(sport=80, dport=80)
1031 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
1033 # there's no ARP entry so this is an ARP req
1034 self.assertTrue(rx[0].haslayer(ARP))
1036 # and ARP entry for VPP's pg0 address on the host interface
1039 self.pg2.sw_if_index,
1040 self.pg2.remote_mac,
1042 is_no_fib_entry=True,
1044 # now the packets shold forward
1045 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
1046 self.assertFalse(rx[0].haslayer(ARP))
1047 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
1050 # flush the neighbor cache on the uplink
1052 af = VppEnum.vl_api_address_family_t
1053 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
1055 # ensure we can still resolve the ARPs on the uplink
1056 self.pg0.resolve_arp()
1058 self.assertTrue(find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_ip4))
1063 self.vapi.proxy_arp_add_del(
1066 "low": self.pg0._local_ip4_subnet,
1067 "hi": self.pg0._local_ip4_bcast,
1071 redirect.remove_vpp_config()
1073 def test_proxy_arp(self):
1076 self.pg1.generate_remote_hosts(2)
1079 # Proxy ARP request packets for each interface
1081 arp_req_pg0 = Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1083 hwsrc=self.pg0.remote_mac,
1085 psrc=self.pg0.remote_ip4,
1087 arp_req_pg0_tagged = (
1088 Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff")
1092 hwsrc=self.pg0.remote_mac,
1094 psrc=self.pg0.remote_ip4,
1097 arp_req_pg1 = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1099 hwsrc=self.pg1.remote_mac,
1101 psrc=self.pg1.remote_ip4,
1103 arp_req_pg2 = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1105 hwsrc=self.pg2.remote_mac,
1107 psrc=self.pg1.remote_hosts[1].ip4,
1109 arp_req_pg3 = Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1111 hwsrc=self.pg3.remote_mac,
1113 psrc=self.pg3.remote_ip4,
1117 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
1119 self.vapi.proxy_arp_add_del(
1120 proxy={"table_id": 0, "low": "10.10.10.2", "hi": "10.10.10.124"}, is_add=1
1124 # No responses are sent when the interfaces are not enabled for proxy
1127 self.send_and_assert_no_replies(
1128 self.pg0, arp_req_pg0, "ARP req from unconfigured interface"
1130 self.send_and_assert_no_replies(
1131 self.pg2, arp_req_pg2, "ARP req from unconfigured interface"
1135 # Make pg2 un-numbered to pg1
1136 # still won't reply.
1138 self.pg2.set_unnumbered(self.pg1.sw_if_index)
1140 self.send_and_assert_no_replies(
1141 self.pg2, arp_req_pg2, "ARP req from unnumbered interface"
1145 # Enable each interface to reply to proxy ARPs
1147 for i in self.pg_interfaces:
1151 # Now each of the interfaces should reply to a request to a proxied
1154 self.pg0.add_stream(arp_req_pg0)
1155 self.pg_enable_capture(self.pg_interfaces)
1158 rx = self.pg0.get_capture(1)
1159 self.verify_arp_resp(
1162 self.pg0.remote_mac,
1164 self.pg0.remote_ip4,
1167 self.pg0.add_stream(arp_req_pg0_tagged)
1168 self.pg_enable_capture(self.pg_interfaces)
1171 rx = self.pg0.get_capture(1)
1172 self.verify_arp_resp(
1175 self.pg0.remote_mac,
1177 self.pg0.remote_ip4,
1180 self.pg1.add_stream(arp_req_pg1)
1181 self.pg_enable_capture(self.pg_interfaces)
1184 rx = self.pg1.get_capture(1)
1185 self.verify_arp_resp(
1188 self.pg1.remote_mac,
1190 self.pg1.remote_ip4,
1193 self.pg2.add_stream(arp_req_pg2)
1194 self.pg_enable_capture(self.pg_interfaces)
1197 rx = self.pg2.get_capture(1)
1198 self.verify_arp_resp(
1201 self.pg2.remote_mac,
1203 self.pg1.remote_hosts[1].ip4,
1207 # A request for an address out of the configured range
1209 arp_req_pg1_hi = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1211 hwsrc=self.pg1.remote_mac,
1212 pdst="10.10.10.125",
1213 psrc=self.pg1.remote_ip4,
1215 self.send_and_assert_no_replies(
1216 self.pg1, arp_req_pg1_hi, "ARP req out of range HI"
1218 arp_req_pg1_low = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1220 hwsrc=self.pg1.remote_mac,
1222 psrc=self.pg1.remote_ip4,
1224 self.send_and_assert_no_replies(
1225 self.pg1, arp_req_pg1_low, "ARP req out of range Low"
1229 # Request for an address in the proxy range but from an interface
1230 # in a different VRF
1232 self.send_and_assert_no_replies(
1233 self.pg3, arp_req_pg3, "ARP req from different VRF"
1237 # Disable Each interface for proxy ARP
1238 # - expect none to respond
1240 for i in self.pg_interfaces:
1243 self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from disable")
1244 self.send_and_assert_no_replies(self.pg1, arp_req_pg1, "ARP req from disable")
1245 self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from disable")
1248 # clean up on interface 2
1250 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1252 def test_mpls(self):
1256 # Interface 2 does not yet have ip4 config
1258 self.pg2.config_ip4()
1259 self.pg2.generate_remote_hosts(2)
1262 # Add a route with out going label via an ARP unresolved next-hop
1264 ip_10_0_0_1 = VppIpRoute(
1270 self.pg2.remote_hosts[1].ip4, self.pg2.sw_if_index, labels=[55]
1274 ip_10_0_0_1.add_vpp_config()
1277 # packets should generate an ARP request
1280 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1281 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
1282 / UDP(sport=1234, dport=1234)
1283 / Raw(b"\xa5" * 100)
1286 self.pg0.add_stream(p)
1287 self.pg_enable_capture(self.pg_interfaces)
1290 rx = self.pg2.get_capture(1)
1291 self.verify_arp_req(
1292 rx[0], self.pg2.local_mac, self.pg2.local_ip4, self.pg2._remote_hosts[1].ip4
1296 # now resolve the neighbours
1298 self.pg2.configure_ipv4_neighbors()
1301 # Now packet should be properly MPLS encapped.
1302 # This verifies that MPLS link-type adjacencies are completed
1303 # when the ARP entry resolves
1305 self.pg0.add_stream(p)
1306 self.pg_enable_capture(self.pg_interfaces)
1309 rx = self.pg2.get_capture(1)
1310 self.verify_ip_o_mpls(
1313 self.pg2.remote_hosts[1].mac,
1315 self.pg0.remote_ip4,
1318 self.pg2.unconfig_ip4()
1320 def test_arp_vrrp(self):
1321 """ARP reply with VRRP virtual src hw addr"""
1324 # IP packet destined for pg1 remote host arrives on pg0 resulting
1325 # in an ARP request for the address of the remote host on pg1
1328 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1329 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
1330 / UDP(sport=1234, dport=1234)
1334 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1336 self.verify_arp_req(
1337 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
1341 # ARP reply for address of pg1 remote host arrives on pg1 with
1342 # the hw src addr set to a value in the VRRP IPv4 range of
1345 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1347 hwdst=self.pg1.local_mac,
1348 hwsrc="00:00:5e:00:01:09",
1349 pdst=self.pg1.local_ip4,
1350 psrc=self.pg1.remote_ip4,
1353 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1356 # IP packet destined for pg1 remote host arrives on pg0 again.
1357 # VPP should have an ARP entry for that address now and the packet
1358 # should be sent out pg1.
1360 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1365 "00:00:5e:00:01:09",
1366 self.pg0.remote_ip4,
1367 self.pg1.remote_ip4,
1370 self.pg1.admin_down()
1373 def test_arp_duplicates(self):
1374 """ARP Duplicates"""
1377 # Generate some hosts on the LAN
1379 self.pg1.generate_remote_hosts(3)
1382 # Add host 1 on pg1 and pg2
1384 arp_pg1 = VppNeighbor(
1386 self.pg1.sw_if_index,
1387 self.pg1.remote_hosts[1].mac,
1388 self.pg1.remote_hosts[1].ip4,
1390 arp_pg1.add_vpp_config()
1391 arp_pg2 = VppNeighbor(
1393 self.pg2.sw_if_index,
1394 self.pg2.remote_mac,
1395 self.pg1.remote_hosts[1].ip4,
1397 arp_pg2.add_vpp_config()
1400 # IP packet destined for pg1 remote host arrives on pg1 again.
1403 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1404 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1405 / UDP(sport=1234, dport=1234)
1409 self.pg0.add_stream(p)
1410 self.pg_enable_capture(self.pg_interfaces)
1413 rx1 = self.pg1.get_capture(1)
1418 self.pg1.remote_hosts[1].mac,
1419 self.pg0.remote_ip4,
1420 self.pg1.remote_hosts[1].ip4,
1424 # remove the duplicate on pg1
1425 # packet stream should generate ARPs out of pg1
1427 arp_pg1.remove_vpp_config()
1429 self.pg0.add_stream(p)
1430 self.pg_enable_capture(self.pg_interfaces)
1433 rx1 = self.pg1.get_capture(1)
1435 self.verify_arp_req(
1436 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4
1442 arp_pg1.add_vpp_config()
1444 self.pg0.add_stream(p)
1445 self.pg_enable_capture(self.pg_interfaces)
1448 rx1 = self.pg1.get_capture(1)
1453 self.pg1.remote_hosts[1].mac,
1454 self.pg0.remote_ip4,
1455 self.pg1.remote_hosts[1].ip4,
1458 def test_arp_static(self):
1460 self.pg2.generate_remote_hosts(3)
1463 # Add a static ARP entry
1465 static_arp = VppNeighbor(
1467 self.pg2.sw_if_index,
1468 self.pg2.remote_hosts[1].mac,
1469 self.pg2.remote_hosts[1].ip4,
1472 static_arp.add_vpp_config()
1475 # Add the connected prefix to the interface
1477 self.pg2.config_ip4()
1480 # We should now find the adj-fib
1484 self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].ip4, is_static=1
1487 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32))
1490 # remove the connected
1492 self.pg2.unconfig_ip4()
1495 # put the interface into table 1
1497 self.pg2.set_table_ip4(1)
1500 # configure the same connected and expect to find the
1501 # adj fib in the new table
1503 self.pg2.config_ip4()
1504 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1))
1509 self.pg2.unconfig_ip4()
1510 static_arp.remove_vpp_config()
1511 self.pg2.set_table_ip4(0)
1513 def test_arp_static_replace_dynamic_same_mac(self):
1514 """ARP Static can replace Dynamic (same mac)"""
1515 self.pg2.generate_remote_hosts(1)
1517 dyn_arp = VppNeighbor(
1519 self.pg2.sw_if_index,
1520 self.pg2.remote_hosts[0].mac,
1521 self.pg2.remote_hosts[0].ip4,
1523 static_arp = VppNeighbor(
1525 self.pg2.sw_if_index,
1526 self.pg2.remote_hosts[0].mac,
1527 self.pg2.remote_hosts[0].ip4,
1532 # Add a dynamic ARP entry
1534 dyn_arp.add_vpp_config()
1537 # We should find the dynamic nbr
1541 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1547 self.pg2.sw_if_index,
1548 self.pg2.remote_hosts[0].ip4,
1550 mac=self.pg2.remote_hosts[0].mac,
1555 # Add a static ARP entry with the same mac
1557 static_arp.add_vpp_config()
1560 # We should now find the static nbr with the same mac
1564 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1570 self.pg2.sw_if_index,
1571 self.pg2.remote_hosts[0].ip4,
1573 mac=self.pg2.remote_hosts[0].mac,
1580 static_arp.remove_vpp_config()
1582 def test_arp_static_replace_dynamic_diff_mac(self):
1583 """ARP Static can replace Dynamic (diff mac)"""
1584 self.pg2.generate_remote_hosts(2)
1586 dyn_arp = VppNeighbor(
1588 self.pg2.sw_if_index,
1589 self.pg2.remote_hosts[0].mac,
1590 self.pg2.remote_hosts[0].ip4,
1592 static_arp = VppNeighbor(
1594 self.pg2.sw_if_index,
1595 self.pg2.remote_hosts[1].mac,
1596 self.pg2.remote_hosts[0].ip4,
1601 # Add a dynamic ARP entry
1603 dyn_arp.add_vpp_config()
1606 # We should find the dynamic nbr
1610 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1616 self.pg2.sw_if_index,
1617 self.pg2.remote_hosts[0].ip4,
1619 mac=self.pg2.remote_hosts[0].mac,
1624 # Add a static ARP entry with a changed mac
1626 static_arp.add_vpp_config()
1629 # We should now find the static nbr with a changed mac
1633 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1639 self.pg2.sw_if_index,
1640 self.pg2.remote_hosts[0].ip4,
1642 mac=self.pg2.remote_hosts[1].mac,
1649 static_arp.remove_vpp_config()
1651 def test_arp_incomplete(self):
1652 """ARP Incomplete"""
1653 self.pg1.generate_remote_hosts(4)
1656 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1657 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1658 / UDP(sport=1234, dport=1234)
1662 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1663 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
1664 / UDP(sport=1234, dport=1234)
1668 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1669 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
1670 / UDP(sport=1234, dport=1234)
1675 # a packet to an unresolved destination generates an ARP request
1677 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1678 self.verify_arp_req(
1679 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
1683 # add a neighbour for remote host 1
1685 static_arp = VppNeighbor(
1687 self.pg1.sw_if_index,
1688 self.pg1.remote_hosts[1].mac,
1689 self.pg1.remote_hosts[1].ip4,
1692 static_arp.add_vpp_config()
1695 # add a route through remote host 3 hence we get an incomplete
1701 [VppRoutePath(self.pg1.remote_hosts[3].ip4, self.pg1.sw_if_index)],
1703 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1704 self.verify_arp_req(
1705 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4
1709 # change the interface's MAC
1711 self.vapi.sw_interface_set_mac_address(
1712 self.pg1.sw_if_index, "00:00:00:33:33:33"
1716 # now ARP requests come from the new source mac
1718 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1719 self.verify_arp_req(
1721 "00:00:00:33:33:33",
1723 self.pg1._remote_hosts[2].ip4,
1725 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1726 self.verify_arp_req(
1728 "00:00:00:33:33:33",
1730 self.pg1._remote_hosts[3].ip4,
1734 # packets to the resolved host also have the new source mac
1736 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1739 "00:00:00:33:33:33",
1740 self.pg1.remote_hosts[1].mac,
1741 self.pg0.remote_ip4,
1742 self.pg1.remote_hosts[1].ip4,
1746 # set the mac address on the interface that does not have a
1747 # configured subnet and thus no glean
1749 self.vapi.sw_interface_set_mac_address(
1750 self.pg2.sw_if_index, "00:00:00:33:33:33"
1753 def test_garp(self):
1757 # Generate some hosts on the LAN
1759 self.pg1.generate_remote_hosts(4)
1760 self.pg2.generate_remote_hosts(4)
1767 self.pg1.sw_if_index,
1768 self.pg1.remote_hosts[1].mac,
1769 self.pg1.remote_hosts[1].ip4,
1771 arp.add_vpp_config()
1776 self.pg1.sw_if_index,
1777 self.pg1.remote_hosts[1].ip4,
1778 mac=self.pg1.remote_hosts[1].mac,
1783 # Send a GARP (request) to swap the host 1's address to that of host 2
1785 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) / ARP(
1787 hwdst=self.pg1.local_mac,
1788 hwsrc=self.pg1.remote_hosts[2].mac,
1789 pdst=self.pg1.remote_hosts[1].ip4,
1790 psrc=self.pg1.remote_hosts[1].ip4,
1793 self.pg1.add_stream(p1)
1794 self.pg_enable_capture(self.pg_interfaces)
1800 self.pg1.sw_if_index,
1801 self.pg1.remote_hosts[1].ip4,
1802 mac=self.pg1.remote_hosts[2].mac,
1805 self.assert_equal(self.get_arp_rx_garp(self.pg1), 1)
1808 # Send a GARP (reply) to swap the host 1's address to that of host 3
1810 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1812 hwdst=self.pg1.local_mac,
1813 hwsrc=self.pg1.remote_hosts[3].mac,
1814 pdst=self.pg1.remote_hosts[1].ip4,
1815 psrc=self.pg1.remote_hosts[1].ip4,
1818 self.pg1.add_stream(p1)
1819 self.pg_enable_capture(self.pg_interfaces)
1825 self.pg1.sw_if_index,
1826 self.pg1.remote_hosts[1].ip4,
1827 mac=self.pg1.remote_hosts[3].mac,
1830 self.assert_equal(self.get_arp_rx_garp(self.pg1), 2)
1833 # GARPs (request nor replies) for host we don't know yet
1834 # don't result in new neighbour entries
1836 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1838 hwdst=self.pg1.local_mac,
1839 hwsrc=self.pg1.remote_hosts[3].mac,
1840 pdst=self.pg1.remote_hosts[2].ip4,
1841 psrc=self.pg1.remote_hosts[2].ip4,
1844 self.pg1.add_stream(p1)
1845 self.pg_enable_capture(self.pg_interfaces)
1849 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1852 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1854 hwdst=self.pg1.local_mac,
1855 hwsrc=self.pg1.remote_hosts[3].mac,
1856 pdst=self.pg1.remote_hosts[2].ip4,
1857 psrc=self.pg1.remote_hosts[2].ip4,
1860 self.pg1.add_stream(p1)
1861 self.pg_enable_capture(self.pg_interfaces)
1865 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1869 # IP address in different subnets are not learnt
1871 self.pg2.configure_ipv4_neighbors()
1873 cntr = self.statistics.get_err_counter(
1874 "/err/arp-reply/l3_dst_address_not_local"
1877 for op in ["is-at", "who-has"]:
1880 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1883 hwdst=self.pg2.local_mac,
1884 hwsrc=self.pg2.remote_hosts[1].mac,
1885 pdst=self.pg2.remote_hosts[1].ip4,
1886 psrc=self.pg2.remote_hosts[1].ip4,
1890 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1893 hwdst="ff:ff:ff:ff:ff:ff",
1894 hwsrc=self.pg2.remote_hosts[1].mac,
1895 pdst=self.pg2.remote_hosts[1].ip4,
1896 psrc=self.pg2.remote_hosts[1].ip4,
1901 self.send_and_assert_no_replies(self.pg1, p1)
1903 find_nbr(self, self.pg1.sw_if_index, self.pg2.remote_hosts[1].ip4)
1906 # they are all dropped because the subnet's don't match
1909 self.statistics.get_err_counter("/err/arp-reply/l3_dst_address_not_local"),
1912 def test_arp_incomplete2(self):
1913 """Incomplete Entries"""
1916 # ensure that we throttle the ARP and ND requests
1918 self.pg0.generate_remote_hosts(2)
1923 ip_10_0_0_1 = VppIpRoute(
1927 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1929 ip_10_0_0_1.add_vpp_config()
1932 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1933 / IP(src=self.pg1.remote_ip4, dst="10.0.0.1")
1934 / UDP(sport=1234, dport=1234)
1938 self.pg1.add_stream(p1 * 257)
1939 self.pg_enable_capture(self.pg_interfaces)
1941 rx = self.pg0._get_capture(1)
1944 # how many we get is going to be dependent on the time for packet
1945 # processing but it should be small
1947 self.assertLess(len(rx), 64)
1952 ip_10_1 = VppIpRoute(
1958 self.pg0.remote_hosts[1].ip6,
1959 self.pg0.sw_if_index,
1960 proto=DpoProto.DPO_PROTO_IP6,
1964 ip_10_1.add_vpp_config()
1967 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1968 / IPv6(src=self.pg1.remote_ip6, dst="10::1")
1969 / UDP(sport=1234, dport=1234)
1973 self.pg1.add_stream(p1 * 257)
1974 self.pg_enable_capture(self.pg_interfaces)
1976 rx = self.pg0._get_capture(1)
1979 # how many we get is going to be dependent on the time for packet
1980 # processing but it should be small
1982 self.assertLess(len(rx), 64)
1984 def test_arp_forus(self):
1985 """ARP for for-us"""
1988 # Test that VPP responds with ARP requests to addresses that
1989 # are connected and local routes.
1990 # Use one of the 'remote' addresses in the subnet as a local address
1991 # The intention of this route is that it then acts like a secondary
1992 # address added to an interface
1994 self.pg0.generate_remote_hosts(2)
1998 self.pg0.remote_hosts[1].ip4,
2003 self.pg0.sw_if_index,
2004 type=FibPathType.FIB_PATH_TYPE_LOCAL,
2008 forus.add_vpp_config()
2010 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
2012 hwdst=self.pg0.local_mac,
2013 hwsrc=self.pg0.remote_mac,
2014 pdst=self.pg0.remote_hosts[1].ip4,
2015 psrc=self.pg0.remote_ip4,
2018 rx = self.send_and_expect(self.pg0, [p], self.pg0)
2020 self.verify_arp_resp(
2023 self.pg0.remote_mac,
2024 self.pg0.remote_hosts[1].ip4,
2025 self.pg0.remote_ip4,
2028 def test_arp_table_swap(self):
2030 # Generate some hosts on the LAN
2033 self.pg1.generate_remote_hosts(N_NBRS)
2035 for n in range(N_NBRS):
2036 # a route thru each neighbour
2041 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
2044 # resolve each neighbour
2045 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
2047 hwdst=self.pg1.local_mac,
2048 hwsrc="00:00:5e:00:01:09",
2049 pdst=self.pg1.local_ip4,
2050 psrc=self.pg1.remote_hosts[n].ip4,
2053 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
2055 self.logger.info(self.vapi.cli("sh ip neighbors"))
2058 # swap the table pg1 is in
2060 table = VppIpTable(self, 100).add_vpp_config()
2062 self.pg1.unconfig_ip4()
2063 self.pg1.set_table_ip4(100)
2064 self.pg1.config_ip4()
2067 # all neighbours are cleared
2069 for n in range(N_NBRS):
2071 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip4)
2075 # packets to all neighbours generate ARP requests
2077 for n in range(N_NBRS):
2078 # a route thru each neighbour
2083 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
2088 Ether(src=self.pg1.remote_hosts[n].mac, dst=self.pg1.local_mac)
2089 / IP(src=self.pg1.remote_hosts[n].ip4, dst="10.0.0.%d" % n)
2092 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
2094 self.verify_arp_req(
2098 self.pg1.remote_hosts[n].ip4,
2101 self.pg1.unconfig_ip4()
2102 self.pg1.set_table_ip4(0)
2104 def test_glean_src_select(self):
2105 """Multi Connecteds"""
2108 # configure multiple connected subnets on an interface
2109 # and ensure that ARP requests for hosts on those subnets
2110 # pick up the correct source address
2112 conn1 = VppIpInterfaceAddress(self, self.pg1, "10.0.0.1", 24).add_vpp_config()
2113 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2116 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2117 / IP(src=self.pg1.remote_ip4, dst="10.0.0.128")
2121 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
2123 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.0.1", "10.0.0.128")
2126 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2127 / IP(src=self.pg1.remote_ip4, dst="10.0.1.128")
2131 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2133 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2136 # add a local address in the same subnet
2137 # the source addresses are equivalent.
2138 # VPP leaves the glean address being used for a prefix
2139 # in place until that address is deleted.
2141 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2143 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2145 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2148 # remove first address, which is currently in use
2149 # the second address should be used now
2151 conn2.remove_vpp_config()
2152 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2154 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2157 # add first address back. Second address should continue
2160 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2161 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2163 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2165 conn1.remove_vpp_config()
2166 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2168 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2170 # apply a connected prefix to an interface in a different table
2175 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2179 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2181 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2183 # apply an attached prefix to the interface
2184 # since there's no local address in this prefix,
2185 # any other address is used
2187 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2188 / IP(src=self.pg1.remote_ip4, dst="10.0.2.128")
2196 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2199 rxs = self.send_and_expect(self.pg0, [p3], self.pg1)
2201 self.verify_arp_req(
2202 rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128"
2206 conn3.remove_vpp_config()
2207 conn2.remove_vpp_config()
2210 @tag_fixme_vpp_workers
2211 class NeighborStatsTestCase(VppTestCase):
2212 """ARP/ND Counters"""
2215 def setUpClass(cls):
2216 super(NeighborStatsTestCase, cls).setUpClass()
2219 def tearDownClass(cls):
2220 super(NeighborStatsTestCase, cls).tearDownClass()
2223 super(NeighborStatsTestCase, self).setUp()
2225 self.create_pg_interfaces(range(2))
2227 # pg0 configured with ip4 and 6 addresses used for input
2228 # pg1 configured with ip4 and 6 addresses used for output
2229 # pg2 is unnumbered to pg0
2230 for i in self.pg_interfaces:
2238 super(NeighborStatsTestCase, self).tearDown()
2240 for i in self.pg_interfaces:
2245 def test_arp_stats(self):
2248 self.vapi.cli("adj counters enable")
2249 self.pg1.generate_remote_hosts(2)
2253 self.pg1.sw_if_index,
2254 self.pg1.remote_hosts[0].mac,
2255 self.pg1.remote_hosts[0].ip4,
2257 arp1.add_vpp_config()
2260 self.pg1.sw_if_index,
2261 self.pg1.remote_hosts[1].mac,
2262 self.pg1.remote_hosts[1].ip4,
2264 arp2.add_vpp_config()
2267 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2268 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2269 / UDP(sport=1234, dport=1234)
2273 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2274 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2275 / UDP(sport=1234, dport=1234)
2279 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2280 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2282 self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2283 self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2285 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2286 self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2288 def test_nd_stats(self):
2291 self.vapi.cli("adj counters enable")
2292 self.pg0.generate_remote_hosts(3)
2296 self.pg0.sw_if_index,
2297 self.pg0.remote_hosts[1].mac,
2298 self.pg0.remote_hosts[1].ip6,
2300 nd1.add_vpp_config()
2303 self.pg0.sw_if_index,
2304 self.pg0.remote_hosts[2].mac,
2305 self.pg0.remote_hosts[2].ip6,
2307 nd2.add_vpp_config()
2310 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2311 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2312 / UDP(sport=1234, dport=1234)
2316 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2317 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2318 / UDP(sport=1234, dport=1234)
2322 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2323 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2325 self.assertEqual(16, nd1.get_stats()["packets"])
2326 self.assertEqual(16, nd2.get_stats()["packets"])
2328 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2329 self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2332 @tag_fixme_ubuntu2204
2333 class NeighborAgeTestCase(VppTestCase):
2337 def setUpClass(cls):
2338 super(NeighborAgeTestCase, cls).setUpClass()
2341 def tearDownClass(cls):
2342 super(NeighborAgeTestCase, cls).tearDownClass()
2345 super(NeighborAgeTestCase, self).setUp()
2347 self.create_pg_interfaces(range(1))
2349 # pg0 configured with ip4 and 6 addresses used for input
2350 # pg1 configured with ip4 and 6 addresses used for output
2351 # pg2 is unnumbered to pg0
2352 for i in self.pg_interfaces:
2360 super(NeighborAgeTestCase, self).tearDown()
2362 for i in self.pg_interfaces:
2367 def verify_arp_req(self, rx, smac, sip, dip):
2369 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2370 self.assertEqual(ether.src, smac)
2373 self.assertEqual(arp.hwtype, 1)
2374 self.assertEqual(arp.ptype, 0x800)
2375 self.assertEqual(arp.hwlen, 6)
2376 self.assertEqual(arp.plen, 4)
2377 self.assertEqual(arp.op, arp_opts["who-has"])
2378 self.assertEqual(arp.hwsrc, smac)
2379 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2380 self.assertEqual(arp.psrc, sip)
2381 self.assertEqual(arp.pdst, dip)
2383 def verify_ip_neighbor_config(self, af, max_number, max_age, recycle):
2384 config = self.vapi.ip_neighbor_config_get(af)
2386 self.assertEqual(config.af, af)
2387 self.assertEqual(config.max_number, max_number)
2388 self.assertEqual(config.max_age, max_age)
2389 self.assertEqual(config.recycle, recycle)
2394 self.vapi.cli("set logging unthrottle 0")
2395 self.vapi.cli("set logging size %d" % 0xFFFF)
2397 self.pg0.generate_remote_hosts(201)
2399 vaf = VppEnum.vl_api_address_family_t
2402 # start listening on all interfaces
2404 self.pg_enable_capture(self.pg_interfaces)
2407 # Verify neighbor configuration defaults
2409 self.verify_ip_neighbor_config(
2410 af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False
2414 # Set the neighbor configuration:
2419 self.vapi.ip_neighbor_config(
2420 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2422 self.verify_ip_neighbor_config(
2423 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2426 self.vapi.cli("sh ip neighbor-config")
2428 # add the 198 neighbours that should pass (-1 for one created in setup)
2429 for ii in range(200):
2432 self.pg0.sw_if_index,
2433 self.pg0.remote_hosts[ii].mac,
2434 self.pg0.remote_hosts[ii].ip4,
2437 # one more neighbor over the limit should fail
2438 with self.vapi.assert_negative_api_retval():
2441 self.pg0.sw_if_index,
2442 self.pg0.remote_hosts[200].mac,
2443 self.pg0.remote_hosts[200].ip4,
2447 # change the config to allow recycling the old neighbors
2449 self.vapi.ip_neighbor_config(
2450 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2452 self.verify_ip_neighbor_config(
2453 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2456 # now new additions are allowed
2459 self.pg0.sw_if_index,
2460 self.pg0.remote_hosts[200].mac,
2461 self.pg0.remote_hosts[200].ip4,
2464 # add the first neighbor we configured has been re-used
2466 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2469 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2473 # change the config to age old neighbors
2475 self.vapi.ip_neighbor_config(
2476 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2478 self.verify_ip_neighbor_config(
2479 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2482 self.vapi.cli("sh ip4 neighbor-sorted")
2485 self.virtual_sleep(3)
2488 # expect probes from all these ARP entries as they age
2489 # 3 probes for each neighbor 3*200 = 600
2490 rxs = self.pg0.get_capture(600, timeout=2)
2493 for jj in range(200):
2494 rx = rxs[ii * 200 + jj]
2498 # 3 probes sent then 1 more second to see if a reply comes, before
2501 self.virtual_sleep(1)
2504 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2508 # load up some neighbours again with 2s aging enabled
2509 # they should be removed after 10s (2s age + 4s for probes + gap)
2510 # check for the add and remove events
2512 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2514 self.vapi.want_ip_neighbor_events_v2(enable=1)
2515 for ii in range(10):
2518 self.pg0.sw_if_index,
2519 self.pg0.remote_hosts[ii].mac,
2520 self.pg0.remote_hosts[ii].ip4,
2523 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2524 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2525 self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2526 self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2528 self.virtual_sleep(10)
2530 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2534 for ii in range(10):
2535 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2536 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2539 # check we got the correct mac/ip pairs - done separately
2540 # because we don't care about the order the remove notifications
2542 for ii in range(10):
2544 mac = self.pg0.remote_hosts[ii].mac
2545 ip = self.pg0.remote_hosts[ii].ip4
2548 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2551 self.assertTrue(found)
2554 # check if we can set age and recycle with empty neighbor list
2556 self.vapi.ip_neighbor_config(
2557 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2559 self.verify_ip_neighbor_config(
2560 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2564 # load up some neighbours again, then disable the aging
2565 # they should still be there in 10 seconds time
2567 for ii in range(10):
2570 self.pg0.sw_if_index,
2571 self.pg0.remote_hosts[ii].mac,
2572 self.pg0.remote_hosts[ii].ip4,
2574 self.vapi.ip_neighbor_config(
2575 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2577 self.verify_ip_neighbor_config(
2578 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2581 self.virtual_sleep(10)
2583 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2587 class NeighborReplaceTestCase(VppTestCase):
2588 """ARP/ND Replacement"""
2591 def setUpClass(cls):
2592 super(NeighborReplaceTestCase, cls).setUpClass()
2595 def tearDownClass(cls):
2596 super(NeighborReplaceTestCase, cls).tearDownClass()
2599 super(NeighborReplaceTestCase, self).setUp()
2601 self.create_pg_interfaces(range(4))
2603 # pg0 configured with ip4 and 6 addresses used for input
2604 # pg1 configured with ip4 and 6 addresses used for output
2605 # pg2 is unnumbered to pg0
2606 for i in self.pg_interfaces:
2614 super(NeighborReplaceTestCase, self).tearDown()
2616 for i in self.pg_interfaces:
2621 def test_replace(self):
2626 for i in self.pg_interfaces:
2627 i.generate_remote_hosts(N_HOSTS)
2628 i.configure_ipv4_neighbors()
2629 i.configure_ipv6_neighbors()
2632 self.vapi.ip_neighbor_replace_begin()
2633 self.vapi.ip_neighbor_replace_end()
2635 for i in self.pg_interfaces:
2636 for h in range(N_HOSTS):
2638 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2641 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2645 # and them all back via the API
2647 for i in self.pg_interfaces:
2648 for h in range(N_HOSTS):
2650 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2653 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2657 # begin the replacement again, this time touch some
2658 # the neighbours on pg1 so they are not deleted
2660 self.vapi.ip_neighbor_replace_begin()
2662 # update from the API all neighbours on pg1
2663 for h in range(N_HOSTS):
2666 self.pg1.sw_if_index,
2667 self.pg1.remote_hosts[h].mac,
2668 self.pg1.remote_hosts[h].ip4,
2672 self.pg1.sw_if_index,
2673 self.pg1.remote_hosts[h].mac,
2674 self.pg1.remote_hosts[h].ip6,
2677 # update from the data-plane all neighbours on pg3
2678 self.pg3.configure_ipv4_neighbors()
2679 self.pg3.configure_ipv6_neighbors()
2681 # complete the replacement
2682 self.logger.info(self.vapi.cli("sh ip neighbors"))
2683 self.vapi.ip_neighbor_replace_end()
2685 for i in self.pg_interfaces:
2686 if i == self.pg1 or i == self.pg3:
2687 # neighbours on pg1 and pg3 are still present
2688 for h in range(N_HOSTS):
2690 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2693 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2696 # all other neighbours are toast
2697 for h in range(N_HOSTS):
2699 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2702 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2706 class NeighborFlush(VppTestCase):
2707 """Neighbor Flush"""
2710 def setUpClass(cls):
2711 super(NeighborFlush, cls).setUpClass()
2714 def tearDownClass(cls):
2715 super(NeighborFlush, cls).tearDownClass()
2718 super(NeighborFlush, self).setUp()
2720 self.create_pg_interfaces(range(2))
2722 for i in self.pg_interfaces:
2730 super(NeighborFlush, self).tearDown()
2732 for i in self.pg_interfaces:
2737 def test_flush(self):
2738 """Neighbour Flush"""
2741 nf = e.vl_api_ip_neighbor_flags_t
2742 af = e.vl_api_address_family_t
2744 static = [False, True]
2745 self.pg0.generate_remote_hosts(N_HOSTS)
2746 self.pg1.generate_remote_hosts(N_HOSTS)
2749 # a few v4 and v6 dynamic neoghbors
2750 for n in range(N_HOSTS):
2753 self.pg0.sw_if_index,
2754 self.pg0.remote_hosts[n].mac,
2755 self.pg0.remote_hosts[n].ip4,
2760 self.pg1.sw_if_index,
2761 self.pg1.remote_hosts[n].mac,
2762 self.pg1.remote_hosts[n].ip6,
2766 # flush the interfaces individually
2767 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2769 # check we haven't flushed that which we shouldn't
2770 for n in range(N_HOSTS):
2774 self.pg1.sw_if_index,
2775 self.pg1.remote_hosts[n].ip6,
2780 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2782 for n in range(N_HOSTS):
2784 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2787 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2790 # add the nieghbours back
2791 for n in range(N_HOSTS):
2794 self.pg0.sw_if_index,
2795 self.pg0.remote_hosts[n].mac,
2796 self.pg0.remote_hosts[n].ip4,
2801 self.pg1.sw_if_index,
2802 self.pg1.remote_hosts[n].mac,
2803 self.pg1.remote_hosts[n].ip6,
2807 self.logger.info(self.vapi.cli("sh ip neighbor"))
2809 # flush both interfaces at the same time
2810 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2812 # check we haven't flushed that which we shouldn't
2813 for n in range(N_HOSTS):
2817 self.pg0.sw_if_index,
2818 self.pg0.remote_hosts[n].ip4,
2823 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2825 for n in range(N_HOSTS):
2827 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2830 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2834 if __name__ == "__main__":
2835 unittest.main(testRunner=VppTestRunner)