5 from socket import AF_INET, AF_INET6, inet_pton
7 from framework import tag_fixme_vpp_workers, tag_fixme_ubuntu2204, tag_fixme_debian11
8 from framework import VppTestCase, VppTestRunner
9 from vpp_neighbor import VppNeighbor, find_nbr
10 from vpp_ip_route import (
17 VppIpInterfaceAddress,
19 from vpp_papi import VppEnum, MACAddress
20 from vpp_ip import VppIpPuntRedirect
21 from vpp_sub_interface import VppDot1ADSubint
24 from scapy.packet import Raw
25 from scapy.layers.l2 import Ether, ARP, Dot1Q
26 from scapy.layers.inet import IP, UDP, TCP
27 from scapy.layers.inet6 import IPv6
28 from scapy.contrib.mpls import MPLS
29 from scapy.layers.inet6 import IPv6
34 # not exported by scapy, so redefined here
35 arp_opts = {"who-has": 1, "is-at": 2}
38 class ARPTestCase(VppTestCase):
43 super(ARPTestCase, cls).setUpClass()
46 def tearDownClass(cls):
47 super(ARPTestCase, cls).tearDownClass()
50 super(ARPTestCase, self).setUp()
52 # create 3 pg interfaces
53 self.create_pg_interfaces(range(4))
55 # pg0 configured with ip4 and 6 addresses used for input
56 # pg1 configured with ip4 and 6 addresses used for output
57 # pg2 is unnumbered to pg0
58 for i in self.pg_interfaces:
63 self.pg0.resolve_arp()
68 # pg3 in a different VRF
69 self.tbl = VppIpTable(self, 1)
70 self.tbl.add_vpp_config()
72 self.pg3.set_table_ip4(1)
76 self.pg0.unconfig_ip4()
77 self.pg0.unconfig_ip6()
79 self.pg1.unconfig_ip4()
80 self.pg1.unconfig_ip6()
82 self.pg3.unconfig_ip4()
83 self.pg3.set_table_ip4(0)
85 for i in self.pg_interfaces:
88 super(ARPTestCase, self).tearDown()
90 def verify_arp_req(self, rx, smac, sip, dip, etype=0x0806):
92 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
93 self.assertEqual(ether.src, smac)
94 self.assertEqual(ether.type, etype)
97 self.assertEqual(arp.hwtype, 1)
98 self.assertEqual(arp.ptype, 0x800)
99 self.assertEqual(arp.hwlen, 6)
100 self.assertEqual(arp.plen, 4)
101 self.assertEqual(arp.op, arp_opts["who-has"])
102 self.assertEqual(arp.hwsrc, smac)
103 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
104 self.assertEqual(arp.psrc, sip)
105 self.assertEqual(arp.pdst, dip)
107 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
109 self.assertEqual(ether.dst, dmac)
110 self.assertEqual(ether.src, smac)
111 self.assertEqual(ether.type, 0x0806)
114 self.assertEqual(arp.hwtype, 1)
115 self.assertEqual(arp.ptype, 0x800)
116 self.assertEqual(arp.hwlen, 6)
117 self.assertEqual(arp.plen, 4)
118 self.assertEqual(arp.op, arp_opts["is-at"])
119 self.assertEqual(arp.hwsrc, smac)
120 self.assertEqual(arp.hwdst, dmac)
121 self.assertEqual(arp.psrc, sip)
122 self.assertEqual(arp.pdst, dip)
124 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
126 self.assertEqual(ether.dst, dmac)
127 self.assertEqual(ether.src, smac)
130 self.assertEqual(arp.hwtype, 1)
131 self.assertEqual(arp.ptype, 0x800)
132 self.assertEqual(arp.hwlen, 6)
133 self.assertEqual(arp.plen, 4)
134 self.assertEqual(arp.op, arp_opts["is-at"])
135 self.assertNotEqual(arp.hwsrc, smac)
136 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or "00:00:5E:00:01" in arp.hwsrc)
137 self.assertEqual(arp.hwdst, dmac)
138 self.assertEqual(arp.psrc, sip)
139 self.assertEqual(arp.pdst, dip)
141 def verify_ip(self, rx, smac, dmac, sip, dip):
143 self.assertEqual(ether.dst, dmac)
144 self.assertEqual(ether.src, smac)
145 self.assertEqual(ether.type, 0x0800)
148 self.assertEqual(ip.src, sip)
149 self.assertEqual(ip.dst, dip)
151 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
153 self.assertEqual(ether.dst, dmac)
154 self.assertEqual(ether.src, smac)
155 self.assertEqual(ether.type, 0x8847)
158 self.assertTrue(mpls.label, label)
161 self.assertEqual(ip.src, sip)
162 self.assertEqual(ip.dst, dip)
164 def get_arp_rx_requests(self, itf):
165 """Get ARP RX request stats for and interface"""
166 return self.statistics["/net/arp/rx/requests"][:, itf.sw_if_index].sum()
168 def get_arp_tx_requests(self, itf):
169 """Get ARP TX request stats for and interface"""
170 return self.statistics["/net/arp/tx/requests"][:, itf.sw_if_index].sum()
172 def get_arp_rx_replies(self, itf):
173 """Get ARP RX replies stats for and interface"""
174 return self.statistics["/net/arp/rx/replies"][:, itf.sw_if_index].sum()
176 def get_arp_tx_replies(self, itf):
177 """Get ARP TX replies stats for and interface"""
178 return self.statistics["/net/arp/tx/replies"][:, itf.sw_if_index].sum()
180 def get_arp_rx_garp(self, itf):
181 """Get ARP RX grat stats for and interface"""
182 return self.statistics["/net/arp/rx/gratuitous"][:, itf.sw_if_index].sum()
184 def get_arp_tx_garp(self, itf):
185 """Get ARP RX grat stats for and interface"""
186 return self.statistics["/net/arp/tx/gratuitous"][:, itf.sw_if_index].sum()
192 # Generate some hosts on the LAN
194 self.pg1.generate_remote_hosts(11)
198 # - all neighbour events
199 # - all neighbor events on pg1
200 # - neighbor events for host[1] on pg1
202 self.vapi.want_ip_neighbor_events(enable=1, pid=os.getpid())
203 self.vapi.want_ip_neighbor_events(
204 enable=1, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
206 self.vapi.want_ip_neighbor_events(
209 sw_if_index=self.pg1.sw_if_index,
210 ip=self.pg1.remote_hosts[1].ip4,
213 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
216 # Send IP traffic to one of these unresolved hosts.
217 # expect the generation of an ARP request
220 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
221 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
222 / UDP(sport=1234, dport=1234)
226 self.pg0.add_stream(p)
227 self.pg_enable_capture(self.pg_interfaces)
230 rx = self.pg1.get_capture(1)
233 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
236 self.logger.info(self.vapi.cli("sh ip neighbor-stats"))
237 self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1"))
238 self.assert_equal(self.get_arp_tx_requests(self.pg1), 1)
241 # And a dynamic ARP entry for host 1
243 dyn_arp = VppNeighbor(
245 self.pg1.sw_if_index,
246 self.pg1.remote_hosts[1].mac,
247 self.pg1.remote_hosts[1].ip4,
249 dyn_arp.add_vpp_config()
250 self.assertTrue(dyn_arp.query_vpp_config())
252 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
254 # this matches all of the listnerers
255 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(3)]
257 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[1].ip4)
260 # now we expect IP traffic forwarded
263 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
264 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
265 / UDP(sport=1234, dport=1234)
269 self.pg0.add_stream(dyn_p)
270 self.pg_enable_capture(self.pg_interfaces)
273 rx = self.pg1.get_capture(1)
278 self.pg1.remote_hosts[1].mac,
280 self.pg1._remote_hosts[1].ip4,
284 # And a Static ARP entry for host 2
286 static_arp = VppNeighbor(
288 self.pg1.sw_if_index,
289 self.pg1.remote_hosts[2].mac,
290 self.pg1.remote_hosts[2].ip4,
293 static_arp.add_vpp_config()
294 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(2)]
296 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[2].ip4)
299 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
300 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4)
301 / UDP(sport=1234, dport=1234)
305 self.pg0.add_stream(static_p)
306 self.pg_enable_capture(self.pg_interfaces)
309 rx = self.pg1.get_capture(1)
314 self.pg1.remote_hosts[2].mac,
316 self.pg1._remote_hosts[2].ip4,
320 # remove all the listeners
322 self.vapi.want_ip_neighbor_events(enable=0, pid=os.getpid())
323 self.vapi.want_ip_neighbor_events(
324 enable=0, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
326 self.vapi.want_ip_neighbor_events(
329 sw_if_index=self.pg1.sw_if_index,
330 ip=self.pg1.remote_hosts[1].ip4,
334 # flap the link. dynamic ARPs get flush, statics don't
336 self.pg1.admin_down()
339 self.pg0.add_stream(static_p)
340 self.pg_enable_capture(self.pg_interfaces)
342 rx = self.pg1.get_capture(1)
347 self.pg1.remote_hosts[2].mac,
349 self.pg1._remote_hosts[2].ip4,
352 self.pg0.add_stream(dyn_p)
353 self.pg_enable_capture(self.pg_interfaces)
356 rx = self.pg1.get_capture(1)
358 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
360 self.assert_equal(self.get_arp_tx_requests(self.pg1), 2)
362 self.assertFalse(dyn_arp.query_vpp_config())
363 self.assertTrue(static_arp.query_vpp_config())
365 # Send an ARP request from one of the so-far unlearned remote hosts
367 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) / ARP(
369 hwsrc=self.pg1._remote_hosts[3].mac,
370 pdst=self.pg1.local_ip4,
371 psrc=self.pg1._remote_hosts[3].ip4,
374 self.pg1.add_stream(p)
375 self.pg_enable_capture(self.pg_interfaces)
378 rx = self.pg1.get_capture(1)
379 self.verify_arp_resp(
382 self.pg1._remote_hosts[3].mac,
384 self.pg1._remote_hosts[3].ip4,
386 self.logger.info(self.vapi.cli("sh ip neighbor-stats pg1"))
387 self.assert_equal(self.get_arp_rx_requests(self.pg1), 1)
388 self.assert_equal(self.get_arp_tx_replies(self.pg1), 1)
391 # VPP should have learned the mapping for the remote host
394 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)
397 # Fire in an ARP request before the interface becomes IP enabled
399 self.pg2.generate_remote_hosts(4)
401 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
403 hwsrc=self.pg2.remote_mac,
404 pdst=self.pg1.local_ip4,
405 psrc=self.pg2.remote_hosts[3].ip4,
408 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac)
412 hwsrc=self.pg2.remote_mac,
413 pdst=self.pg1.local_ip4,
414 psrc=self.pg2.remote_hosts[3].ip4,
417 self.send_and_assert_no_replies(self.pg2, p, "interface not IP enabled")
420 # Make pg2 un-numbered to pg1
422 self.pg2.set_unnumbered(self.pg1.sw_if_index)
425 # test the unnumbered dump both by all interfaces and just the enabled
428 unnum = self.vapi.ip_unnumbered_dump()
429 self.assertTrue(len(unnum))
430 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
431 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
432 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
433 self.assertTrue(len(unnum))
434 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
435 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
438 # We should respond to ARP requests for the unnumbered to address
439 # once an attached route to the source is known
441 self.send_and_assert_no_replies(
442 self.pg2, p, "ARP req for unnumbered address - no source"
445 attached_host = VppIpRoute(
447 self.pg2.remote_hosts[3].ip4,
449 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
451 attached_host.add_vpp_config()
453 self.pg2.add_stream(p)
454 self.pg_enable_capture(self.pg_interfaces)
457 rx = self.pg2.get_capture(1)
458 self.verify_arp_resp(
463 self.pg2.remote_hosts[3].ip4,
466 self.pg2.add_stream(pt)
467 self.pg_enable_capture(self.pg_interfaces)
470 rx = self.pg2.get_capture(1)
471 self.verify_arp_resp(
476 self.pg2.remote_hosts[3].ip4,
480 # A neighbor entry that has no associated FIB-entry
482 arp_no_fib = VppNeighbor(
484 self.pg1.sw_if_index,
485 self.pg1.remote_hosts[4].mac,
486 self.pg1.remote_hosts[4].ip4,
489 arp_no_fib.add_vpp_config()
492 # check we have the neighbor, but no route
495 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)
497 self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32))
499 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
500 # from within pg1's subnet
502 arp_unnum = VppNeighbor(
504 self.pg2.sw_if_index,
505 self.pg1.remote_hosts[5].mac,
506 self.pg1.remote_hosts[5].ip4,
508 arp_unnum.add_vpp_config()
511 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
512 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4)
513 / UDP(sport=1234, dport=1234)
517 self.pg0.add_stream(p)
518 self.pg_enable_capture(self.pg_interfaces)
521 rx = self.pg2.get_capture(1)
526 self.pg1.remote_hosts[5].mac,
528 self.pg1._remote_hosts[5].ip4,
532 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
533 # with the unnumbered interface's address as the source
535 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
537 hwsrc=self.pg2.remote_mac,
538 pdst=self.pg1.local_ip4,
539 psrc=self.pg1.remote_hosts[6].ip4,
542 self.pg2.add_stream(p)
543 self.pg_enable_capture(self.pg_interfaces)
546 rx = self.pg2.get_capture(1)
547 self.verify_arp_resp(
552 self.pg1.remote_hosts[6].ip4,
556 # An attached host route out of pg2 for an undiscovered hosts generates
557 # an ARP request with the unnumbered address as the source
559 att_unnum = VppIpRoute(
561 self.pg1.remote_hosts[7].ip4,
563 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
565 att_unnum.add_vpp_config()
568 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
569 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4)
570 / UDP(sport=1234, dport=1234)
574 self.pg0.add_stream(p)
575 self.pg_enable_capture(self.pg_interfaces)
578 rx = self.pg2.get_capture(1)
581 rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4
584 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
586 hwsrc=self.pg2.remote_mac,
587 pdst=self.pg1.local_ip4,
588 psrc=self.pg1.remote_hosts[7].ip4,
591 self.pg2.add_stream(p)
592 self.pg_enable_capture(self.pg_interfaces)
595 rx = self.pg2.get_capture(1)
596 self.verify_arp_resp(
601 self.pg1.remote_hosts[7].ip4,
605 # An attached host route as yet unresolved out of pg2 for an
606 # undiscovered host, an ARP requests begets a response.
608 att_unnum1 = VppIpRoute(
610 self.pg1.remote_hosts[8].ip4,
612 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
614 att_unnum1.add_vpp_config()
616 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
618 hwsrc=self.pg2.remote_mac,
619 pdst=self.pg1.local_ip4,
620 psrc=self.pg1.remote_hosts[8].ip4,
623 self.pg2.add_stream(p)
624 self.pg_enable_capture(self.pg_interfaces)
627 rx = self.pg2.get_capture(1)
628 self.verify_arp_resp(
633 self.pg1.remote_hosts[8].ip4,
637 # Send an ARP request from one of the so-far unlearned remote hosts
641 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac)
645 hwsrc=self.pg1._remote_hosts[9].mac,
646 pdst=self.pg1.local_ip4,
647 psrc=self.pg1._remote_hosts[9].ip4,
651 self.pg1.add_stream(p)
652 self.pg_enable_capture(self.pg_interfaces)
655 rx = self.pg1.get_capture(1)
656 self.verify_arp_resp(
659 self.pg1._remote_hosts[9].mac,
661 self.pg1._remote_hosts[9].ip4,
665 # Add a hierarchy of routes for a host in the sub-net.
666 # Should still get an ARP resp since the cover is attached
668 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(
670 hwsrc=self.pg1.remote_mac,
671 pdst=self.pg1.local_ip4,
672 psrc=self.pg1.remote_hosts[10].ip4,
677 self.pg1.remote_hosts[10].ip4,
679 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
683 self.pg1.add_stream(p)
684 self.pg_enable_capture(self.pg_interfaces)
686 rx = self.pg1.get_capture(1)
687 self.verify_arp_resp(
692 self.pg1.remote_hosts[10].ip4,
697 self.pg1.remote_hosts[10].ip4,
699 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
703 self.pg1.add_stream(p)
704 self.pg_enable_capture(self.pg_interfaces)
706 rx = self.pg1.get_capture(1)
707 self.verify_arp_resp(
712 self.pg1.remote_hosts[10].ip4,
716 # add an ARP entry that's not on the sub-net and so whose
717 # adj-fib fails the refinement check. then send an ARP request
721 self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50"
725 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
727 hwsrc=self.pg0.remote_mac,
728 psrc="100.100.100.50",
729 pdst=self.pg0.remote_ip4,
731 self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib")
735 # 1 - don't respond to ARP request for address not within the
736 # interface's sub-net
737 # 1b - nor within the unnumbered subnet
738 # 1c - nor within the subnet of a different interface
740 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
742 hwsrc=self.pg0.remote_mac,
744 psrc=self.pg0.remote_ip4,
746 self.send_and_assert_no_replies(
747 self.pg0, p, "ARP req for non-local destination"
749 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3"))
751 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
753 hwsrc=self.pg2.remote_mac,
755 psrc=self.pg1.remote_hosts[7].ip4,
757 self.send_and_assert_no_replies(
758 self.pg0, p, "ARP req for non-local destination - unnum"
761 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
763 hwsrc=self.pg0.remote_mac,
764 pdst=self.pg1.local_ip4,
765 psrc=self.pg1.remote_ip4,
767 self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net")
768 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4))
771 # 2 - don't respond to ARP request from an address not within the
772 # interface's sub-net
773 # 2b - to a proxied address
774 # 2c - not within a different interface's sub-net
775 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
777 hwsrc=self.pg0.remote_mac,
779 pdst=self.pg0.local_ip4,
781 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
782 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
784 hwsrc=self.pg2.remote_mac,
786 pdst=self.pg0.local_ip4,
788 self.send_and_assert_no_replies(
789 self.pg0, p, "ARP req for non-local source - unnum"
791 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
793 hwsrc=self.pg0.remote_mac,
794 psrc=self.pg1.remote_ip4,
795 pdst=self.pg0.local_ip4,
797 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c")
800 # 3 - don't respond to ARP request from an address that belongs to
803 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
805 hwsrc=self.pg0.remote_mac,
806 psrc=self.pg0.local_ip4,
807 pdst=self.pg0.local_ip4,
809 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
812 # 4 - don't respond to ARP requests that has mac source different
813 # from ARP request HW source
815 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
817 hwsrc="00:00:00:DE:AD:BE",
818 psrc=self.pg0.remote_ip4,
819 pdst=self.pg0.local_ip4,
821 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
824 # 5 - don't respond to ARP requests for address within the
825 # interface's sub-net but not the interface's address
827 self.pg0.generate_remote_hosts(2)
828 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
830 hwsrc=self.pg0.remote_mac,
831 psrc=self.pg0.remote_hosts[0].ip4,
832 pdst=self.pg0.remote_hosts[1].ip4,
834 self.send_and_assert_no_replies(
835 self.pg0, p, "ARP req for non-local destination"
841 static_arp.remove_vpp_config()
842 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
844 # need this to flush the adj-fibs
845 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
846 self.pg2.admin_down()
847 self.pg1.admin_down()
849 def test_arp_after_mac_change(self):
850 """ARP (after MAC address change)"""
853 # Prepare a subinterface
855 subif0 = VppDot1ADSubint(self, self.pg1, 0, 300, 400)
860 # Send a packet to cause ARP generation for the parent interface's remote host
863 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
864 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
865 / UDP(sport=1234, dport=1234)
869 self.pg0.add_stream(p1)
870 self.pg_enable_capture(self.pg_interfaces)
873 rx = self.pg1.get_capture(1)
876 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
880 # Send a packet to cause ARP generation for the subinterface's remote host
883 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
884 / IP(src=self.pg0.remote_ip4, dst=subif0.remote_ip4)
885 / UDP(sport=1234, dport=1234)
889 self.pg0.add_stream(p2)
890 self.pg_enable_capture(self.pg_interfaces)
893 rx = self.pg1.get_capture(1)
904 # Change MAC address of the parent interface
906 pg1_mac_saved = self.pg1.local_mac
907 self.pg1.set_mac(MACAddress("00:00:00:11:22:33"))
910 # Send a packet to cause ARP generation for the parent interface's remote host
911 # - expect new MAC address is used as the source
913 self.pg0.add_stream(p1)
914 self.pg_enable_capture(self.pg_interfaces)
917 rx = self.pg1.get_capture(1)
920 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
924 # Send a packet to cause ARP generation for the subinterface's remote host
925 # - expect new MAC address is used as the source
928 self.pg0.add_stream(p2)
929 self.pg_enable_capture(self.pg_interfaces)
932 rx = self.pg1.get_capture(1)
945 subif0.remove_vpp_config()
946 self.pg1.set_mac(MACAddress(pg1_mac_saved))
948 def test_proxy_mirror_arp(self):
949 """Interface Mirror Proxy ARP"""
952 # When VPP has an interface whose address is also applied to a TAP
953 # interface on the host, then VPP's TAP interface will be unnumbered
954 # to the 'real' interface and do proxy ARP from the host.
955 # the curious aspect of this setup is that ARP requests from the host
956 # will come from the VPP's own address.
958 self.pg0.generate_remote_hosts(2)
960 arp_req_from_me = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
962 hwsrc=self.pg2.remote_mac,
963 pdst=self.pg0.remote_hosts[1].ip4,
964 psrc=self.pg0.local_ip4,
968 # Configure Proxy ARP for the subnet on PG0addresses on pg0
970 self.vapi.proxy_arp_add_del(
973 "low": self.pg0._local_ip4_subnet,
974 "hi": self.pg0._local_ip4_bcast,
979 # Make pg2 un-numbered to pg0
981 self.pg2.set_unnumbered(self.pg0.sw_if_index)
984 # Enable pg2 for proxy ARP
986 self.pg2.set_proxy_arp()
989 # Send the ARP request with an originating address that
990 # is VPP's own address
992 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
993 self.verify_arp_resp(
997 self.pg0.remote_hosts[1].ip4,
1002 # validate we have not learned an ARP entry as a result of this
1004 self.assertFalse(find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4))
1007 # setup a punt redirect so packets from the uplink go to the tap
1009 redirect = VppIpPuntRedirect(
1010 self, self.pg0.sw_if_index, self.pg2.sw_if_index, self.pg0.local_ip4
1012 redirect.add_vpp_config()
1016 src=self.pg0.remote_mac,
1017 dst=self.pg0.local_mac,
1019 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1020 / TCP(sport=80, dport=80)
1023 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
1025 # there's no ARP entry so this is an ARP req
1026 self.assertTrue(rx[0].haslayer(ARP))
1028 # and ARP entry for VPP's pg0 address on the host interface
1031 self.pg2.sw_if_index,
1032 self.pg2.remote_mac,
1034 is_no_fib_entry=True,
1036 # now the packets shold forward
1037 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
1038 self.assertFalse(rx[0].haslayer(ARP))
1039 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
1042 # flush the neighbor cache on the uplink
1044 af = VppEnum.vl_api_address_family_t
1045 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
1047 # ensure we can still resolve the ARPs on the uplink
1048 self.pg0.resolve_arp()
1050 self.assertTrue(find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_ip4))
1055 self.vapi.proxy_arp_add_del(
1058 "low": self.pg0._local_ip4_subnet,
1059 "hi": self.pg0._local_ip4_bcast,
1063 redirect.remove_vpp_config()
1065 def test_proxy_arp(self):
1068 self.pg1.generate_remote_hosts(2)
1071 # Proxy ARP request packets for each interface
1073 arp_req_pg0 = Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1075 hwsrc=self.pg0.remote_mac,
1077 psrc=self.pg0.remote_ip4,
1079 arp_req_pg0_tagged = (
1080 Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff")
1084 hwsrc=self.pg0.remote_mac,
1086 psrc=self.pg0.remote_ip4,
1089 arp_req_pg1 = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1091 hwsrc=self.pg1.remote_mac,
1093 psrc=self.pg1.remote_ip4,
1095 arp_req_pg2 = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1097 hwsrc=self.pg2.remote_mac,
1099 psrc=self.pg1.remote_hosts[1].ip4,
1101 arp_req_pg3 = Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1103 hwsrc=self.pg3.remote_mac,
1105 psrc=self.pg3.remote_ip4,
1109 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
1111 self.vapi.proxy_arp_add_del(
1112 proxy={"table_id": 0, "low": "10.10.10.2", "hi": "10.10.10.124"}, is_add=1
1116 # No responses are sent when the interfaces are not enabled for proxy
1119 self.send_and_assert_no_replies(
1120 self.pg0, arp_req_pg0, "ARP req from unconfigured interface"
1122 self.send_and_assert_no_replies(
1123 self.pg2, arp_req_pg2, "ARP req from unconfigured interface"
1127 # Make pg2 un-numbered to pg1
1128 # still won't reply.
1130 self.pg2.set_unnumbered(self.pg1.sw_if_index)
1132 self.send_and_assert_no_replies(
1133 self.pg2, arp_req_pg2, "ARP req from unnumbered interface"
1137 # Enable each interface to reply to proxy ARPs
1139 for i in self.pg_interfaces:
1143 # Now each of the interfaces should reply to a request to a proxied
1146 self.pg0.add_stream(arp_req_pg0)
1147 self.pg_enable_capture(self.pg_interfaces)
1150 rx = self.pg0.get_capture(1)
1151 self.verify_arp_resp(
1154 self.pg0.remote_mac,
1156 self.pg0.remote_ip4,
1159 self.pg0.add_stream(arp_req_pg0_tagged)
1160 self.pg_enable_capture(self.pg_interfaces)
1163 rx = self.pg0.get_capture(1)
1164 self.verify_arp_resp(
1167 self.pg0.remote_mac,
1169 self.pg0.remote_ip4,
1172 self.pg1.add_stream(arp_req_pg1)
1173 self.pg_enable_capture(self.pg_interfaces)
1176 rx = self.pg1.get_capture(1)
1177 self.verify_arp_resp(
1180 self.pg1.remote_mac,
1182 self.pg1.remote_ip4,
1185 self.pg2.add_stream(arp_req_pg2)
1186 self.pg_enable_capture(self.pg_interfaces)
1189 rx = self.pg2.get_capture(1)
1190 self.verify_arp_resp(
1193 self.pg2.remote_mac,
1195 self.pg1.remote_hosts[1].ip4,
1199 # A request for an address out of the configured range
1201 arp_req_pg1_hi = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1203 hwsrc=self.pg1.remote_mac,
1204 pdst="10.10.10.125",
1205 psrc=self.pg1.remote_ip4,
1207 self.send_and_assert_no_replies(
1208 self.pg1, arp_req_pg1_hi, "ARP req out of range HI"
1210 arp_req_pg1_low = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1212 hwsrc=self.pg1.remote_mac,
1214 psrc=self.pg1.remote_ip4,
1216 self.send_and_assert_no_replies(
1217 self.pg1, arp_req_pg1_low, "ARP req out of range Low"
1221 # Request for an address in the proxy range but from an interface
1222 # in a different VRF
1224 self.send_and_assert_no_replies(
1225 self.pg3, arp_req_pg3, "ARP req from different VRF"
1229 # Disable Each interface for proxy ARP
1230 # - expect none to respond
1232 for i in self.pg_interfaces:
1235 self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from disable")
1236 self.send_and_assert_no_replies(self.pg1, arp_req_pg1, "ARP req from disable")
1237 self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from disable")
1240 # clean up on interface 2
1242 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1244 def test_mpls(self):
1248 # Interface 2 does not yet have ip4 config
1250 self.pg2.config_ip4()
1251 self.pg2.generate_remote_hosts(2)
1254 # Add a route with out going label via an ARP unresolved next-hop
1256 ip_10_0_0_1 = VppIpRoute(
1262 self.pg2.remote_hosts[1].ip4, self.pg2.sw_if_index, labels=[55]
1266 ip_10_0_0_1.add_vpp_config()
1269 # packets should generate an ARP request
1272 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1273 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
1274 / UDP(sport=1234, dport=1234)
1275 / Raw(b"\xa5" * 100)
1278 self.pg0.add_stream(p)
1279 self.pg_enable_capture(self.pg_interfaces)
1282 rx = self.pg2.get_capture(1)
1283 self.verify_arp_req(
1284 rx[0], self.pg2.local_mac, self.pg2.local_ip4, self.pg2._remote_hosts[1].ip4
1288 # now resolve the neighbours
1290 self.pg2.configure_ipv4_neighbors()
1293 # Now packet should be properly MPLS encapped.
1294 # This verifies that MPLS link-type adjacencies are completed
1295 # when the ARP entry resolves
1297 self.pg0.add_stream(p)
1298 self.pg_enable_capture(self.pg_interfaces)
1301 rx = self.pg2.get_capture(1)
1302 self.verify_ip_o_mpls(
1305 self.pg2.remote_hosts[1].mac,
1307 self.pg0.remote_ip4,
1310 self.pg2.unconfig_ip4()
1312 def test_arp_vrrp(self):
1313 """ARP reply with VRRP virtual src hw addr"""
1316 # IP packet destined for pg1 remote host arrives on pg0 resulting
1317 # in an ARP request for the address of the remote host on pg1
1320 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1321 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
1322 / UDP(sport=1234, dport=1234)
1326 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1328 self.verify_arp_req(
1329 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
1333 # ARP reply for address of pg1 remote host arrives on pg1 with
1334 # the hw src addr set to a value in the VRRP IPv4 range of
1337 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1339 hwdst=self.pg1.local_mac,
1340 hwsrc="00:00:5e:00:01:09",
1341 pdst=self.pg1.local_ip4,
1342 psrc=self.pg1.remote_ip4,
1345 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1348 # IP packet destined for pg1 remote host arrives on pg0 again.
1349 # VPP should have an ARP entry for that address now and the packet
1350 # should be sent out pg1.
1352 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1357 "00:00:5e:00:01:09",
1358 self.pg0.remote_ip4,
1359 self.pg1.remote_ip4,
1362 self.pg1.admin_down()
1365 def test_arp_duplicates(self):
1366 """ARP Duplicates"""
1369 # Generate some hosts on the LAN
1371 self.pg1.generate_remote_hosts(3)
1374 # Add host 1 on pg1 and pg2
1376 arp_pg1 = VppNeighbor(
1378 self.pg1.sw_if_index,
1379 self.pg1.remote_hosts[1].mac,
1380 self.pg1.remote_hosts[1].ip4,
1382 arp_pg1.add_vpp_config()
1383 arp_pg2 = VppNeighbor(
1385 self.pg2.sw_if_index,
1386 self.pg2.remote_mac,
1387 self.pg1.remote_hosts[1].ip4,
1389 arp_pg2.add_vpp_config()
1392 # IP packet destined for pg1 remote host arrives on pg1 again.
1395 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1396 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1397 / UDP(sport=1234, dport=1234)
1401 self.pg0.add_stream(p)
1402 self.pg_enable_capture(self.pg_interfaces)
1405 rx1 = self.pg1.get_capture(1)
1410 self.pg1.remote_hosts[1].mac,
1411 self.pg0.remote_ip4,
1412 self.pg1.remote_hosts[1].ip4,
1416 # remove the duplicate on pg1
1417 # packet stream should generate ARPs out of pg1
1419 arp_pg1.remove_vpp_config()
1421 self.pg0.add_stream(p)
1422 self.pg_enable_capture(self.pg_interfaces)
1425 rx1 = self.pg1.get_capture(1)
1427 self.verify_arp_req(
1428 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4
1434 arp_pg1.add_vpp_config()
1436 self.pg0.add_stream(p)
1437 self.pg_enable_capture(self.pg_interfaces)
1440 rx1 = self.pg1.get_capture(1)
1445 self.pg1.remote_hosts[1].mac,
1446 self.pg0.remote_ip4,
1447 self.pg1.remote_hosts[1].ip4,
1450 def test_arp_static(self):
1452 self.pg2.generate_remote_hosts(3)
1455 # Add a static ARP entry
1457 static_arp = VppNeighbor(
1459 self.pg2.sw_if_index,
1460 self.pg2.remote_hosts[1].mac,
1461 self.pg2.remote_hosts[1].ip4,
1464 static_arp.add_vpp_config()
1467 # Add the connected prefix to the interface
1469 self.pg2.config_ip4()
1472 # We should now find the adj-fib
1476 self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].ip4, is_static=1
1479 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32))
1482 # remove the connected
1484 self.pg2.unconfig_ip4()
1487 # put the interface into table 1
1489 self.pg2.set_table_ip4(1)
1492 # configure the same connected and expect to find the
1493 # adj fib in the new table
1495 self.pg2.config_ip4()
1496 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1))
1501 self.pg2.unconfig_ip4()
1502 static_arp.remove_vpp_config()
1503 self.pg2.set_table_ip4(0)
1505 def test_arp_static_replace_dynamic_same_mac(self):
1506 """ARP Static can replace Dynamic (same mac)"""
1507 self.pg2.generate_remote_hosts(1)
1509 dyn_arp = VppNeighbor(
1511 self.pg2.sw_if_index,
1512 self.pg2.remote_hosts[0].mac,
1513 self.pg2.remote_hosts[0].ip4,
1515 static_arp = VppNeighbor(
1517 self.pg2.sw_if_index,
1518 self.pg2.remote_hosts[0].mac,
1519 self.pg2.remote_hosts[0].ip4,
1524 # Add a dynamic ARP entry
1526 dyn_arp.add_vpp_config()
1529 # We should find the dynamic nbr
1533 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1539 self.pg2.sw_if_index,
1540 self.pg2.remote_hosts[0].ip4,
1542 mac=self.pg2.remote_hosts[0].mac,
1547 # Add a static ARP entry with the same mac
1549 static_arp.add_vpp_config()
1552 # We should now find the static nbr with the same mac
1556 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1562 self.pg2.sw_if_index,
1563 self.pg2.remote_hosts[0].ip4,
1565 mac=self.pg2.remote_hosts[0].mac,
1572 static_arp.remove_vpp_config()
1574 def test_arp_static_replace_dynamic_diff_mac(self):
1575 """ARP Static can replace Dynamic (diff mac)"""
1576 self.pg2.generate_remote_hosts(2)
1578 dyn_arp = VppNeighbor(
1580 self.pg2.sw_if_index,
1581 self.pg2.remote_hosts[0].mac,
1582 self.pg2.remote_hosts[0].ip4,
1584 static_arp = VppNeighbor(
1586 self.pg2.sw_if_index,
1587 self.pg2.remote_hosts[1].mac,
1588 self.pg2.remote_hosts[0].ip4,
1593 # Add a dynamic ARP entry
1595 dyn_arp.add_vpp_config()
1598 # We should find the dynamic nbr
1602 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1608 self.pg2.sw_if_index,
1609 self.pg2.remote_hosts[0].ip4,
1611 mac=self.pg2.remote_hosts[0].mac,
1616 # Add a static ARP entry with a changed mac
1618 static_arp.add_vpp_config()
1621 # We should now find the static nbr with a changed mac
1625 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1631 self.pg2.sw_if_index,
1632 self.pg2.remote_hosts[0].ip4,
1634 mac=self.pg2.remote_hosts[1].mac,
1641 static_arp.remove_vpp_config()
1643 def test_arp_incomplete(self):
1644 """ARP Incomplete"""
1645 self.pg1.generate_remote_hosts(4)
1648 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1649 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1650 / UDP(sport=1234, dport=1234)
1654 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1655 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
1656 / UDP(sport=1234, dport=1234)
1660 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1661 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
1662 / UDP(sport=1234, dport=1234)
1667 # a packet to an unresolved destination generates an ARP request
1669 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1670 self.verify_arp_req(
1671 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
1675 # add a neighbour for remote host 1
1677 static_arp = VppNeighbor(
1679 self.pg1.sw_if_index,
1680 self.pg1.remote_hosts[1].mac,
1681 self.pg1.remote_hosts[1].ip4,
1684 static_arp.add_vpp_config()
1687 # add a route through remote host 3 hence we get an incomplete
1693 [VppRoutePath(self.pg1.remote_hosts[3].ip4, self.pg1.sw_if_index)],
1695 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1696 self.verify_arp_req(
1697 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4
1701 # change the interface's MAC
1703 self.vapi.sw_interface_set_mac_address(
1704 self.pg1.sw_if_index, "00:00:00:33:33:33"
1708 # now ARP requests come from the new source mac
1710 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1711 self.verify_arp_req(
1713 "00:00:00:33:33:33",
1715 self.pg1._remote_hosts[2].ip4,
1717 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1718 self.verify_arp_req(
1720 "00:00:00:33:33:33",
1722 self.pg1._remote_hosts[3].ip4,
1726 # packets to the resolved host also have the new source mac
1728 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1731 "00:00:00:33:33:33",
1732 self.pg1.remote_hosts[1].mac,
1733 self.pg0.remote_ip4,
1734 self.pg1.remote_hosts[1].ip4,
1738 # set the mac address on the interface that does not have a
1739 # configured subnet and thus no glean
1741 self.vapi.sw_interface_set_mac_address(
1742 self.pg2.sw_if_index, "00:00:00:33:33:33"
1745 def test_garp(self):
1749 # Generate some hosts on the LAN
1751 self.pg1.generate_remote_hosts(4)
1752 self.pg2.generate_remote_hosts(4)
1759 self.pg1.sw_if_index,
1760 self.pg1.remote_hosts[1].mac,
1761 self.pg1.remote_hosts[1].ip4,
1763 arp.add_vpp_config()
1768 self.pg1.sw_if_index,
1769 self.pg1.remote_hosts[1].ip4,
1770 mac=self.pg1.remote_hosts[1].mac,
1775 # Send a GARP (request) to swap the host 1's address to that of host 2
1777 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) / ARP(
1779 hwdst=self.pg1.local_mac,
1780 hwsrc=self.pg1.remote_hosts[2].mac,
1781 pdst=self.pg1.remote_hosts[1].ip4,
1782 psrc=self.pg1.remote_hosts[1].ip4,
1785 self.pg1.add_stream(p1)
1786 self.pg_enable_capture(self.pg_interfaces)
1792 self.pg1.sw_if_index,
1793 self.pg1.remote_hosts[1].ip4,
1794 mac=self.pg1.remote_hosts[2].mac,
1797 self.assert_equal(self.get_arp_rx_garp(self.pg1), 1)
1800 # Send a GARP (reply) to swap the host 1's address to that of host 3
1802 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1804 hwdst=self.pg1.local_mac,
1805 hwsrc=self.pg1.remote_hosts[3].mac,
1806 pdst=self.pg1.remote_hosts[1].ip4,
1807 psrc=self.pg1.remote_hosts[1].ip4,
1810 self.pg1.add_stream(p1)
1811 self.pg_enable_capture(self.pg_interfaces)
1817 self.pg1.sw_if_index,
1818 self.pg1.remote_hosts[1].ip4,
1819 mac=self.pg1.remote_hosts[3].mac,
1822 self.assert_equal(self.get_arp_rx_garp(self.pg1), 2)
1825 # GARPs (request nor replies) for host we don't know yet
1826 # don't result in new neighbour entries
1828 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1830 hwdst=self.pg1.local_mac,
1831 hwsrc=self.pg1.remote_hosts[3].mac,
1832 pdst=self.pg1.remote_hosts[2].ip4,
1833 psrc=self.pg1.remote_hosts[2].ip4,
1836 self.pg1.add_stream(p1)
1837 self.pg_enable_capture(self.pg_interfaces)
1841 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1844 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1846 hwdst=self.pg1.local_mac,
1847 hwsrc=self.pg1.remote_hosts[3].mac,
1848 pdst=self.pg1.remote_hosts[2].ip4,
1849 psrc=self.pg1.remote_hosts[2].ip4,
1852 self.pg1.add_stream(p1)
1853 self.pg_enable_capture(self.pg_interfaces)
1857 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1861 # IP address in different subnets are not learnt
1863 self.pg2.configure_ipv4_neighbors()
1865 cntr = self.statistics.get_err_counter(
1866 "/err/arp-reply/l3_dst_address_not_local"
1869 for op in ["is-at", "who-has"]:
1872 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1875 hwdst=self.pg2.local_mac,
1876 hwsrc=self.pg2.remote_hosts[1].mac,
1877 pdst=self.pg2.remote_hosts[1].ip4,
1878 psrc=self.pg2.remote_hosts[1].ip4,
1882 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1885 hwdst="ff:ff:ff:ff:ff:ff",
1886 hwsrc=self.pg2.remote_hosts[1].mac,
1887 pdst=self.pg2.remote_hosts[1].ip4,
1888 psrc=self.pg2.remote_hosts[1].ip4,
1893 self.send_and_assert_no_replies(self.pg1, p1)
1895 find_nbr(self, self.pg1.sw_if_index, self.pg2.remote_hosts[1].ip4)
1898 # they are all dropped because the subnet's don't match
1901 self.statistics.get_err_counter("/err/arp-reply/l3_dst_address_not_local"),
1904 def test_arp_incomplete2(self):
1905 """Incomplete Entries"""
1908 # ensure that we throttle the ARP and ND requests
1910 self.pg0.generate_remote_hosts(2)
1915 ip_10_0_0_1 = VppIpRoute(
1919 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1921 ip_10_0_0_1.add_vpp_config()
1924 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1925 / IP(src=self.pg1.remote_ip4, dst="10.0.0.1")
1926 / UDP(sport=1234, dport=1234)
1930 self.pg1.add_stream(p1 * 257)
1931 self.pg_enable_capture(self.pg_interfaces)
1933 rx = self.pg0._get_capture(1)
1936 # how many we get is going to be dependent on the time for packet
1937 # processing but it should be small
1939 self.assertLess(len(rx), 64)
1944 ip_10_1 = VppIpRoute(
1950 self.pg0.remote_hosts[1].ip6,
1951 self.pg0.sw_if_index,
1952 proto=DpoProto.DPO_PROTO_IP6,
1956 ip_10_1.add_vpp_config()
1959 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1960 / IPv6(src=self.pg1.remote_ip6, dst="10::1")
1961 / UDP(sport=1234, dport=1234)
1965 self.pg1.add_stream(p1 * 257)
1966 self.pg_enable_capture(self.pg_interfaces)
1968 rx = self.pg0._get_capture(1)
1971 # how many we get is going to be dependent on the time for packet
1972 # processing but it should be small
1974 self.assertLess(len(rx), 64)
1976 def test_arp_forus(self):
1977 """ARP for for-us"""
1980 # Test that VPP responds with ARP requests to addresses that
1981 # are connected and local routes.
1982 # Use one of the 'remote' addresses in the subnet as a local address
1983 # The intention of this route is that it then acts like a secondary
1984 # address added to an interface
1986 self.pg0.generate_remote_hosts(2)
1990 self.pg0.remote_hosts[1].ip4,
1995 self.pg0.sw_if_index,
1996 type=FibPathType.FIB_PATH_TYPE_LOCAL,
2000 forus.add_vpp_config()
2002 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
2004 hwdst=self.pg0.local_mac,
2005 hwsrc=self.pg0.remote_mac,
2006 pdst=self.pg0.remote_hosts[1].ip4,
2007 psrc=self.pg0.remote_ip4,
2010 rx = self.send_and_expect(self.pg0, [p], self.pg0)
2012 self.verify_arp_resp(
2015 self.pg0.remote_mac,
2016 self.pg0.remote_hosts[1].ip4,
2017 self.pg0.remote_ip4,
2020 def test_arp_table_swap(self):
2022 # Generate some hosts on the LAN
2025 self.pg1.generate_remote_hosts(N_NBRS)
2027 for n in range(N_NBRS):
2028 # a route thru each neighbour
2033 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
2036 # resolve each neighbour
2037 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
2039 hwdst=self.pg1.local_mac,
2040 hwsrc="00:00:5e:00:01:09",
2041 pdst=self.pg1.local_ip4,
2042 psrc=self.pg1.remote_hosts[n].ip4,
2045 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
2047 self.logger.info(self.vapi.cli("sh ip neighbors"))
2050 # swap the table pg1 is in
2052 table = VppIpTable(self, 100).add_vpp_config()
2054 self.pg1.unconfig_ip4()
2055 self.pg1.set_table_ip4(100)
2056 self.pg1.config_ip4()
2059 # all neighbours are cleared
2061 for n in range(N_NBRS):
2063 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip4)
2067 # packets to all neighbours generate ARP requests
2069 for n in range(N_NBRS):
2070 # a route thru each neighbour
2075 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
2080 Ether(src=self.pg1.remote_hosts[n].mac, dst=self.pg1.local_mac)
2081 / IP(src=self.pg1.remote_hosts[n].ip4, dst="10.0.0.%d" % n)
2084 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
2086 self.verify_arp_req(
2090 self.pg1.remote_hosts[n].ip4,
2093 self.pg1.unconfig_ip4()
2094 self.pg1.set_table_ip4(0)
2096 def test_glean_src_select(self):
2097 """Multi Connecteds"""
2100 # configure multiple connected subnets on an interface
2101 # and ensure that ARP requests for hosts on those subnets
2102 # pick up the correct source address
2104 conn1 = VppIpInterfaceAddress(self, self.pg1, "10.0.0.1", 24).add_vpp_config()
2105 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2108 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2109 / IP(src=self.pg1.remote_ip4, dst="10.0.0.128")
2113 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
2115 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.0.1", "10.0.0.128")
2118 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2119 / IP(src=self.pg1.remote_ip4, dst="10.0.1.128")
2123 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2125 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2128 # add a local address in the same subnet
2129 # the source addresses are equivalent.
2130 # VPP leaves the glean address being used for a prefix
2131 # in place until that address is deleted.
2133 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2135 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2137 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2140 # remove first address, which is currently in use
2141 # the second address should be used now
2143 conn2.remove_vpp_config()
2144 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2146 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2149 # add first address back. Second address should continue
2152 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2153 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2155 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2157 conn1.remove_vpp_config()
2158 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2160 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2162 # apply a connected prefix to an interface in a different table
2167 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2171 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2173 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2175 # apply an attached prefix to the interface
2176 # since there's no local address in this prefix,
2177 # any other address is used
2179 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2180 / IP(src=self.pg1.remote_ip4, dst="10.0.2.128")
2188 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2191 rxs = self.send_and_expect(self.pg0, [p3], self.pg1)
2193 self.verify_arp_req(
2194 rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128"
2198 conn3.remove_vpp_config()
2199 conn2.remove_vpp_config()
2202 @tag_fixme_vpp_workers
2203 class NeighborStatsTestCase(VppTestCase):
2204 """ARP/ND Counters"""
2207 def setUpClass(cls):
2208 super(NeighborStatsTestCase, cls).setUpClass()
2211 def tearDownClass(cls):
2212 super(NeighborStatsTestCase, cls).tearDownClass()
2215 super(NeighborStatsTestCase, self).setUp()
2217 self.create_pg_interfaces(range(2))
2219 # pg0 configured with ip4 and 6 addresses used for input
2220 # pg1 configured with ip4 and 6 addresses used for output
2221 # pg2 is unnumbered to pg0
2222 for i in self.pg_interfaces:
2230 super(NeighborStatsTestCase, self).tearDown()
2232 for i in self.pg_interfaces:
2237 def test_arp_stats(self):
2240 self.vapi.cli("adj counters enable")
2241 self.pg1.generate_remote_hosts(2)
2245 self.pg1.sw_if_index,
2246 self.pg1.remote_hosts[0].mac,
2247 self.pg1.remote_hosts[0].ip4,
2249 arp1.add_vpp_config()
2252 self.pg1.sw_if_index,
2253 self.pg1.remote_hosts[1].mac,
2254 self.pg1.remote_hosts[1].ip4,
2256 arp2.add_vpp_config()
2259 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2260 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2261 / UDP(sport=1234, dport=1234)
2265 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2266 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2267 / UDP(sport=1234, dport=1234)
2271 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2272 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2274 self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2275 self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2277 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2278 self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2280 def test_nd_stats(self):
2283 self.vapi.cli("adj counters enable")
2284 self.pg0.generate_remote_hosts(3)
2288 self.pg0.sw_if_index,
2289 self.pg0.remote_hosts[1].mac,
2290 self.pg0.remote_hosts[1].ip6,
2292 nd1.add_vpp_config()
2295 self.pg0.sw_if_index,
2296 self.pg0.remote_hosts[2].mac,
2297 self.pg0.remote_hosts[2].ip6,
2299 nd2.add_vpp_config()
2302 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2303 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2304 / UDP(sport=1234, dport=1234)
2308 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2309 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2310 / UDP(sport=1234, dport=1234)
2314 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2315 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2317 self.assertEqual(16, nd1.get_stats()["packets"])
2318 self.assertEqual(16, nd2.get_stats()["packets"])
2320 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2321 self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2324 @tag_fixme_ubuntu2204
2325 class NeighborAgeTestCase(VppTestCase):
2329 def setUpClass(cls):
2330 super(NeighborAgeTestCase, cls).setUpClass()
2333 def tearDownClass(cls):
2334 super(NeighborAgeTestCase, cls).tearDownClass()
2337 super(NeighborAgeTestCase, self).setUp()
2339 self.create_pg_interfaces(range(1))
2341 # pg0 configured with ip4 and 6 addresses used for input
2342 # pg1 configured with ip4 and 6 addresses used for output
2343 # pg2 is unnumbered to pg0
2344 for i in self.pg_interfaces:
2352 super(NeighborAgeTestCase, self).tearDown()
2354 for i in self.pg_interfaces:
2359 def verify_arp_req(self, rx, smac, sip, dip):
2361 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2362 self.assertEqual(ether.src, smac)
2365 self.assertEqual(arp.hwtype, 1)
2366 self.assertEqual(arp.ptype, 0x800)
2367 self.assertEqual(arp.hwlen, 6)
2368 self.assertEqual(arp.plen, 4)
2369 self.assertEqual(arp.op, arp_opts["who-has"])
2370 self.assertEqual(arp.hwsrc, smac)
2371 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2372 self.assertEqual(arp.psrc, sip)
2373 self.assertEqual(arp.pdst, dip)
2375 def verify_ip_neighbor_config(self, af, max_number, max_age, recycle):
2376 config = self.vapi.ip_neighbor_config_get(af)
2378 self.assertEqual(config.af, af)
2379 self.assertEqual(config.max_number, max_number)
2380 self.assertEqual(config.max_age, max_age)
2381 self.assertEqual(config.recycle, recycle)
2386 self.vapi.cli("set logging unthrottle 0")
2387 self.vapi.cli("set logging size %d" % 0xFFFF)
2389 self.pg0.generate_remote_hosts(201)
2391 vaf = VppEnum.vl_api_address_family_t
2394 # start listening on all interfaces
2396 self.pg_enable_capture(self.pg_interfaces)
2399 # Verify neighbor configuration defaults
2401 self.verify_ip_neighbor_config(
2402 af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False
2406 # Set the neighbor configuration:
2411 self.vapi.ip_neighbor_config(
2412 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2414 self.verify_ip_neighbor_config(
2415 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2418 self.vapi.cli("sh ip neighbor-config")
2420 # add the 198 neighbours that should pass (-1 for one created in setup)
2421 for ii in range(200):
2424 self.pg0.sw_if_index,
2425 self.pg0.remote_hosts[ii].mac,
2426 self.pg0.remote_hosts[ii].ip4,
2429 # one more neighbor over the limit should fail
2430 with self.vapi.assert_negative_api_retval():
2433 self.pg0.sw_if_index,
2434 self.pg0.remote_hosts[200].mac,
2435 self.pg0.remote_hosts[200].ip4,
2439 # change the config to allow recycling the old neighbors
2441 self.vapi.ip_neighbor_config(
2442 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2444 self.verify_ip_neighbor_config(
2445 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2448 # now new additions are allowed
2451 self.pg0.sw_if_index,
2452 self.pg0.remote_hosts[200].mac,
2453 self.pg0.remote_hosts[200].ip4,
2456 # add the first neighbor we configured has been re-used
2458 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2461 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2465 # change the config to age old neighbors
2467 self.vapi.ip_neighbor_config(
2468 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2470 self.verify_ip_neighbor_config(
2471 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2474 self.vapi.cli("sh ip4 neighbor-sorted")
2477 self.virtual_sleep(3)
2480 # expect probes from all these ARP entries as they age
2481 # 3 probes for each neighbor 3*200 = 600
2482 rxs = self.pg0.get_capture(600, timeout=2)
2485 for jj in range(200):
2486 rx = rxs[ii * 200 + jj]
2490 # 3 probes sent then 1 more second to see if a reply comes, before
2493 self.virtual_sleep(1)
2496 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2500 # load up some neighbours again with 2s aging enabled
2501 # they should be removed after 10s (2s age + 4s for probes + gap)
2502 # check for the add and remove events
2504 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2506 self.vapi.want_ip_neighbor_events_v2(enable=1)
2507 for ii in range(10):
2510 self.pg0.sw_if_index,
2511 self.pg0.remote_hosts[ii].mac,
2512 self.pg0.remote_hosts[ii].ip4,
2515 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2516 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2517 self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2518 self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2520 self.virtual_sleep(10)
2522 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2526 for ii in range(10):
2527 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2528 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2531 # check we got the correct mac/ip pairs - done separately
2532 # because we don't care about the order the remove notifications
2534 for ii in range(10):
2536 mac = self.pg0.remote_hosts[ii].mac
2537 ip = self.pg0.remote_hosts[ii].ip4
2540 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2543 self.assertTrue(found)
2546 # check if we can set age and recycle with empty neighbor list
2548 self.vapi.ip_neighbor_config(
2549 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2551 self.verify_ip_neighbor_config(
2552 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2556 # load up some neighbours again, then disable the aging
2557 # they should still be there in 10 seconds time
2559 for ii in range(10):
2562 self.pg0.sw_if_index,
2563 self.pg0.remote_hosts[ii].mac,
2564 self.pg0.remote_hosts[ii].ip4,
2566 self.vapi.ip_neighbor_config(
2567 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2569 self.verify_ip_neighbor_config(
2570 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2573 self.virtual_sleep(10)
2575 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2579 class NeighborReplaceTestCase(VppTestCase):
2580 """ARP/ND Replacement"""
2583 def setUpClass(cls):
2584 super(NeighborReplaceTestCase, cls).setUpClass()
2587 def tearDownClass(cls):
2588 super(NeighborReplaceTestCase, cls).tearDownClass()
2591 super(NeighborReplaceTestCase, self).setUp()
2593 self.create_pg_interfaces(range(4))
2595 # pg0 configured with ip4 and 6 addresses used for input
2596 # pg1 configured with ip4 and 6 addresses used for output
2597 # pg2 is unnumbered to pg0
2598 for i in self.pg_interfaces:
2606 super(NeighborReplaceTestCase, self).tearDown()
2608 for i in self.pg_interfaces:
2613 def test_replace(self):
2618 for i in self.pg_interfaces:
2619 i.generate_remote_hosts(N_HOSTS)
2620 i.configure_ipv4_neighbors()
2621 i.configure_ipv6_neighbors()
2624 self.vapi.ip_neighbor_replace_begin()
2625 self.vapi.ip_neighbor_replace_end()
2627 for i in self.pg_interfaces:
2628 for h in range(N_HOSTS):
2630 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2633 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2637 # and them all back via the API
2639 for i in self.pg_interfaces:
2640 for h in range(N_HOSTS):
2642 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2645 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2649 # begin the replacement again, this time touch some
2650 # the neighbours on pg1 so they are not deleted
2652 self.vapi.ip_neighbor_replace_begin()
2654 # update from the API all neighbours on pg1
2655 for h in range(N_HOSTS):
2658 self.pg1.sw_if_index,
2659 self.pg1.remote_hosts[h].mac,
2660 self.pg1.remote_hosts[h].ip4,
2664 self.pg1.sw_if_index,
2665 self.pg1.remote_hosts[h].mac,
2666 self.pg1.remote_hosts[h].ip6,
2669 # update from the data-plane all neighbours on pg3
2670 self.pg3.configure_ipv4_neighbors()
2671 self.pg3.configure_ipv6_neighbors()
2673 # complete the replacement
2674 self.logger.info(self.vapi.cli("sh ip neighbors"))
2675 self.vapi.ip_neighbor_replace_end()
2677 for i in self.pg_interfaces:
2678 if i == self.pg1 or i == self.pg3:
2679 # neighbours on pg1 and pg3 are still present
2680 for h in range(N_HOSTS):
2682 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2685 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2688 # all other neighbours are toast
2689 for h in range(N_HOSTS):
2691 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2694 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2698 class NeighborFlush(VppTestCase):
2699 """Neighbor Flush"""
2702 def setUpClass(cls):
2703 super(NeighborFlush, cls).setUpClass()
2706 def tearDownClass(cls):
2707 super(NeighborFlush, cls).tearDownClass()
2710 super(NeighborFlush, self).setUp()
2712 self.create_pg_interfaces(range(2))
2714 for i in self.pg_interfaces:
2722 super(NeighborFlush, self).tearDown()
2724 for i in self.pg_interfaces:
2729 def test_flush(self):
2730 """Neighbour Flush"""
2733 nf = e.vl_api_ip_neighbor_flags_t
2734 af = e.vl_api_address_family_t
2736 static = [False, True]
2737 self.pg0.generate_remote_hosts(N_HOSTS)
2738 self.pg1.generate_remote_hosts(N_HOSTS)
2741 # a few v4 and v6 dynamic neoghbors
2742 for n in range(N_HOSTS):
2745 self.pg0.sw_if_index,
2746 self.pg0.remote_hosts[n].mac,
2747 self.pg0.remote_hosts[n].ip4,
2752 self.pg1.sw_if_index,
2753 self.pg1.remote_hosts[n].mac,
2754 self.pg1.remote_hosts[n].ip6,
2758 # flush the interfaces individually
2759 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2761 # check we haven't flushed that which we shouldn't
2762 for n in range(N_HOSTS):
2766 self.pg1.sw_if_index,
2767 self.pg1.remote_hosts[n].ip6,
2772 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2774 for n in range(N_HOSTS):
2776 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2779 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2782 # add the nieghbours back
2783 for n in range(N_HOSTS):
2786 self.pg0.sw_if_index,
2787 self.pg0.remote_hosts[n].mac,
2788 self.pg0.remote_hosts[n].ip4,
2793 self.pg1.sw_if_index,
2794 self.pg1.remote_hosts[n].mac,
2795 self.pg1.remote_hosts[n].ip6,
2799 self.logger.info(self.vapi.cli("sh ip neighbor"))
2801 # flush both interfaces at the same time
2802 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2804 # check we haven't flushed that which we shouldn't
2805 for n in range(N_HOSTS):
2809 self.pg0.sw_if_index,
2810 self.pg0.remote_hosts[n].ip4,
2815 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2817 for n in range(N_HOSTS):
2819 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2822 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2826 if __name__ == "__main__":
2827 unittest.main(testRunner=VppTestRunner)