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. VPP happens to
2130 # choose the last one that was added
2131 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2133 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2135 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2140 conn3.remove_vpp_config()
2141 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2143 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2146 # add back, this time remove the first one
2148 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2150 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2152 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2154 conn1.remove_vpp_config()
2155 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2157 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2159 # apply a connected prefix to an interface in a different table
2164 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2168 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2170 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2172 # apply an attached prefix to the interface
2173 # since there's no local address in this prefix,
2174 # any other address is used
2176 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2177 / IP(src=self.pg1.remote_ip4, dst="10.0.2.128")
2185 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2188 rxs = self.send_and_expect(self.pg0, [p3], self.pg1)
2190 self.verify_arp_req(
2191 rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128"
2195 conn3.remove_vpp_config()
2196 conn2.remove_vpp_config()
2199 @tag_fixme_vpp_workers
2200 class NeighborStatsTestCase(VppTestCase):
2201 """ARP/ND Counters"""
2204 def setUpClass(cls):
2205 super(NeighborStatsTestCase, cls).setUpClass()
2208 def tearDownClass(cls):
2209 super(NeighborStatsTestCase, cls).tearDownClass()
2212 super(NeighborStatsTestCase, self).setUp()
2214 self.create_pg_interfaces(range(2))
2216 # pg0 configured with ip4 and 6 addresses used for input
2217 # pg1 configured with ip4 and 6 addresses used for output
2218 # pg2 is unnumbered to pg0
2219 for i in self.pg_interfaces:
2227 super(NeighborStatsTestCase, self).tearDown()
2229 for i in self.pg_interfaces:
2234 def test_arp_stats(self):
2237 self.vapi.cli("adj counters enable")
2238 self.pg1.generate_remote_hosts(2)
2242 self.pg1.sw_if_index,
2243 self.pg1.remote_hosts[0].mac,
2244 self.pg1.remote_hosts[0].ip4,
2246 arp1.add_vpp_config()
2249 self.pg1.sw_if_index,
2250 self.pg1.remote_hosts[1].mac,
2251 self.pg1.remote_hosts[1].ip4,
2253 arp2.add_vpp_config()
2256 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2257 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2258 / UDP(sport=1234, dport=1234)
2262 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2263 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2264 / UDP(sport=1234, dport=1234)
2268 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2269 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2271 self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2272 self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2274 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2275 self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2277 def test_nd_stats(self):
2280 self.vapi.cli("adj counters enable")
2281 self.pg0.generate_remote_hosts(3)
2285 self.pg0.sw_if_index,
2286 self.pg0.remote_hosts[1].mac,
2287 self.pg0.remote_hosts[1].ip6,
2289 nd1.add_vpp_config()
2292 self.pg0.sw_if_index,
2293 self.pg0.remote_hosts[2].mac,
2294 self.pg0.remote_hosts[2].ip6,
2296 nd2.add_vpp_config()
2299 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2300 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2301 / UDP(sport=1234, dport=1234)
2305 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2306 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2307 / UDP(sport=1234, dport=1234)
2311 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2312 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2314 self.assertEqual(16, nd1.get_stats()["packets"])
2315 self.assertEqual(16, nd2.get_stats()["packets"])
2317 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2318 self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2321 @tag_fixme_ubuntu2204
2322 class NeighborAgeTestCase(VppTestCase):
2326 def setUpClass(cls):
2327 super(NeighborAgeTestCase, cls).setUpClass()
2330 def tearDownClass(cls):
2331 super(NeighborAgeTestCase, cls).tearDownClass()
2334 super(NeighborAgeTestCase, self).setUp()
2336 self.create_pg_interfaces(range(1))
2338 # pg0 configured with ip4 and 6 addresses used for input
2339 # pg1 configured with ip4 and 6 addresses used for output
2340 # pg2 is unnumbered to pg0
2341 for i in self.pg_interfaces:
2349 super(NeighborAgeTestCase, self).tearDown()
2351 for i in self.pg_interfaces:
2356 def verify_arp_req(self, rx, smac, sip, dip):
2358 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2359 self.assertEqual(ether.src, smac)
2362 self.assertEqual(arp.hwtype, 1)
2363 self.assertEqual(arp.ptype, 0x800)
2364 self.assertEqual(arp.hwlen, 6)
2365 self.assertEqual(arp.plen, 4)
2366 self.assertEqual(arp.op, arp_opts["who-has"])
2367 self.assertEqual(arp.hwsrc, smac)
2368 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2369 self.assertEqual(arp.psrc, sip)
2370 self.assertEqual(arp.pdst, dip)
2372 def verify_ip_neighbor_config(self, af, max_number, max_age, recycle):
2373 config = self.vapi.ip_neighbor_config_get(af)
2375 self.assertEqual(config.af, af)
2376 self.assertEqual(config.max_number, max_number)
2377 self.assertEqual(config.max_age, max_age)
2378 self.assertEqual(config.recycle, recycle)
2383 self.vapi.cli("set logging unthrottle 0")
2384 self.vapi.cli("set logging size %d" % 0xFFFF)
2386 self.pg0.generate_remote_hosts(201)
2388 vaf = VppEnum.vl_api_address_family_t
2391 # start listening on all interfaces
2393 self.pg_enable_capture(self.pg_interfaces)
2396 # Verify neighbor configuration defaults
2398 self.verify_ip_neighbor_config(
2399 af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False
2403 # Set the neighbor configuration:
2408 self.vapi.ip_neighbor_config(
2409 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2411 self.verify_ip_neighbor_config(
2412 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2415 self.vapi.cli("sh ip neighbor-config")
2417 # add the 198 neighbours that should pass (-1 for one created in setup)
2418 for ii in range(200):
2421 self.pg0.sw_if_index,
2422 self.pg0.remote_hosts[ii].mac,
2423 self.pg0.remote_hosts[ii].ip4,
2426 # one more neighbor over the limit should fail
2427 with self.vapi.assert_negative_api_retval():
2430 self.pg0.sw_if_index,
2431 self.pg0.remote_hosts[200].mac,
2432 self.pg0.remote_hosts[200].ip4,
2436 # change the config to allow recycling the old neighbors
2438 self.vapi.ip_neighbor_config(
2439 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2441 self.verify_ip_neighbor_config(
2442 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2445 # now new additions are allowed
2448 self.pg0.sw_if_index,
2449 self.pg0.remote_hosts[200].mac,
2450 self.pg0.remote_hosts[200].ip4,
2453 # add the first neighbor we configured has been re-used
2455 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2458 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2462 # change the config to age old neighbors
2464 self.vapi.ip_neighbor_config(
2465 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2467 self.verify_ip_neighbor_config(
2468 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2471 self.vapi.cli("sh ip4 neighbor-sorted")
2474 self.virtual_sleep(3)
2477 # expect probes from all these ARP entries as they age
2478 # 3 probes for each neighbor 3*200 = 600
2479 rxs = self.pg0.get_capture(600, timeout=2)
2482 for jj in range(200):
2483 rx = rxs[ii * 200 + jj]
2487 # 3 probes sent then 1 more second to see if a reply comes, before
2490 self.virtual_sleep(1)
2493 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2497 # load up some neighbours again with 2s aging enabled
2498 # they should be removed after 10s (2s age + 4s for probes + gap)
2499 # check for the add and remove events
2501 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2503 self.vapi.want_ip_neighbor_events_v2(enable=1)
2504 for ii in range(10):
2507 self.pg0.sw_if_index,
2508 self.pg0.remote_hosts[ii].mac,
2509 self.pg0.remote_hosts[ii].ip4,
2512 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2513 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2514 self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2515 self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2517 self.virtual_sleep(10)
2519 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2523 for ii in range(10):
2524 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2525 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2528 # check we got the correct mac/ip pairs - done separately
2529 # because we don't care about the order the remove notifications
2531 for ii in range(10):
2533 mac = self.pg0.remote_hosts[ii].mac
2534 ip = self.pg0.remote_hosts[ii].ip4
2537 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2540 self.assertTrue(found)
2543 # check if we can set age and recycle with empty neighbor list
2545 self.vapi.ip_neighbor_config(
2546 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2548 self.verify_ip_neighbor_config(
2549 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2553 # load up some neighbours again, then disable the aging
2554 # they should still be there in 10 seconds time
2556 for ii in range(10):
2559 self.pg0.sw_if_index,
2560 self.pg0.remote_hosts[ii].mac,
2561 self.pg0.remote_hosts[ii].ip4,
2563 self.vapi.ip_neighbor_config(
2564 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2566 self.verify_ip_neighbor_config(
2567 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2570 self.virtual_sleep(10)
2572 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2576 class NeighborReplaceTestCase(VppTestCase):
2577 """ARP/ND Replacement"""
2580 def setUpClass(cls):
2581 super(NeighborReplaceTestCase, cls).setUpClass()
2584 def tearDownClass(cls):
2585 super(NeighborReplaceTestCase, cls).tearDownClass()
2588 super(NeighborReplaceTestCase, self).setUp()
2590 self.create_pg_interfaces(range(4))
2592 # pg0 configured with ip4 and 6 addresses used for input
2593 # pg1 configured with ip4 and 6 addresses used for output
2594 # pg2 is unnumbered to pg0
2595 for i in self.pg_interfaces:
2603 super(NeighborReplaceTestCase, self).tearDown()
2605 for i in self.pg_interfaces:
2610 def test_replace(self):
2615 for i in self.pg_interfaces:
2616 i.generate_remote_hosts(N_HOSTS)
2617 i.configure_ipv4_neighbors()
2618 i.configure_ipv6_neighbors()
2621 self.vapi.ip_neighbor_replace_begin()
2622 self.vapi.ip_neighbor_replace_end()
2624 for i in self.pg_interfaces:
2625 for h in range(N_HOSTS):
2627 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2630 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2634 # and them all back via the API
2636 for i in self.pg_interfaces:
2637 for h in range(N_HOSTS):
2639 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2642 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2646 # begin the replacement again, this time touch some
2647 # the neighbours on pg1 so they are not deleted
2649 self.vapi.ip_neighbor_replace_begin()
2651 # update from the API all neighbours on pg1
2652 for h in range(N_HOSTS):
2655 self.pg1.sw_if_index,
2656 self.pg1.remote_hosts[h].mac,
2657 self.pg1.remote_hosts[h].ip4,
2661 self.pg1.sw_if_index,
2662 self.pg1.remote_hosts[h].mac,
2663 self.pg1.remote_hosts[h].ip6,
2666 # update from the data-plane all neighbours on pg3
2667 self.pg3.configure_ipv4_neighbors()
2668 self.pg3.configure_ipv6_neighbors()
2670 # complete the replacement
2671 self.logger.info(self.vapi.cli("sh ip neighbors"))
2672 self.vapi.ip_neighbor_replace_end()
2674 for i in self.pg_interfaces:
2675 if i == self.pg1 or i == self.pg3:
2676 # neighbours on pg1 and pg3 are still present
2677 for h in range(N_HOSTS):
2679 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2682 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2685 # all other neighbours are toast
2686 for h in range(N_HOSTS):
2688 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2691 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2695 class NeighborFlush(VppTestCase):
2696 """Neighbor Flush"""
2699 def setUpClass(cls):
2700 super(NeighborFlush, cls).setUpClass()
2703 def tearDownClass(cls):
2704 super(NeighborFlush, cls).tearDownClass()
2707 super(NeighborFlush, self).setUp()
2709 self.create_pg_interfaces(range(2))
2711 for i in self.pg_interfaces:
2719 super(NeighborFlush, self).tearDown()
2721 for i in self.pg_interfaces:
2726 def test_flush(self):
2727 """Neighbour Flush"""
2730 nf = e.vl_api_ip_neighbor_flags_t
2731 af = e.vl_api_address_family_t
2733 static = [False, True]
2734 self.pg0.generate_remote_hosts(N_HOSTS)
2735 self.pg1.generate_remote_hosts(N_HOSTS)
2738 # a few v4 and v6 dynamic neoghbors
2739 for n in range(N_HOSTS):
2742 self.pg0.sw_if_index,
2743 self.pg0.remote_hosts[n].mac,
2744 self.pg0.remote_hosts[n].ip4,
2749 self.pg1.sw_if_index,
2750 self.pg1.remote_hosts[n].mac,
2751 self.pg1.remote_hosts[n].ip6,
2755 # flush the interfaces individually
2756 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2758 # check we haven't flushed that which we shouldn't
2759 for n in range(N_HOSTS):
2763 self.pg1.sw_if_index,
2764 self.pg1.remote_hosts[n].ip6,
2769 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2771 for n in range(N_HOSTS):
2773 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2776 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2779 # add the nieghbours back
2780 for n in range(N_HOSTS):
2783 self.pg0.sw_if_index,
2784 self.pg0.remote_hosts[n].mac,
2785 self.pg0.remote_hosts[n].ip4,
2790 self.pg1.sw_if_index,
2791 self.pg1.remote_hosts[n].mac,
2792 self.pg1.remote_hosts[n].ip6,
2796 self.logger.info(self.vapi.cli("sh ip neighbor"))
2798 # flush both interfaces at the same time
2799 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2801 # check we haven't flushed that which we shouldn't
2802 for n in range(N_HOSTS):
2806 self.pg0.sw_if_index,
2807 self.pg0.remote_hosts[n].ip4,
2812 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2814 for n in range(N_HOSTS):
2816 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2819 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2823 if __name__ == "__main__":
2824 unittest.main(testRunner=VppTestRunner)