5 from socket import AF_INET, AF_INET6, inet_pton
7 from framework import tag_fixme_vpp_workers
8 from framework import VppTestCase, VppTestRunner
9 from vpp_neighbor import VppNeighbor, find_nbr
10 from vpp_ip_route import (
17 VppIpInterfaceAddress,
19 from vpp_papi import VppEnum
20 from vpp_ip import VppIpPuntRedirect
23 from scapy.packet import Raw
24 from scapy.layers.l2 import Ether, ARP, Dot1Q
25 from scapy.layers.inet import IP, UDP, TCP
26 from scapy.layers.inet6 import IPv6
27 from scapy.contrib.mpls import MPLS
28 from scapy.layers.inet6 import IPv6
33 # not exported by scapy, so redefined here
34 arp_opts = {"who-has": 1, "is-at": 2}
37 class ARPTestCase(VppTestCase):
42 super(ARPTestCase, cls).setUpClass()
45 def tearDownClass(cls):
46 super(ARPTestCase, cls).tearDownClass()
49 super(ARPTestCase, self).setUp()
51 # create 3 pg interfaces
52 self.create_pg_interfaces(range(4))
54 # pg0 configured with ip4 and 6 addresses used for input
55 # pg1 configured with ip4 and 6 addresses used for output
56 # pg2 is unnumbered to pg0
57 for i in self.pg_interfaces:
62 self.pg0.resolve_arp()
67 # pg3 in a different VRF
68 self.tbl = VppIpTable(self, 1)
69 self.tbl.add_vpp_config()
71 self.pg3.set_table_ip4(1)
75 self.pg0.unconfig_ip4()
76 self.pg0.unconfig_ip6()
78 self.pg1.unconfig_ip4()
79 self.pg1.unconfig_ip6()
81 self.pg3.unconfig_ip4()
82 self.pg3.set_table_ip4(0)
84 for i in self.pg_interfaces:
87 super(ARPTestCase, self).tearDown()
89 def verify_arp_req(self, rx, smac, sip, dip):
91 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
92 self.assertEqual(ether.src, smac)
93 self.assertEqual(ether.type, 0x0806)
96 self.assertEqual(arp.hwtype, 1)
97 self.assertEqual(arp.ptype, 0x800)
98 self.assertEqual(arp.hwlen, 6)
99 self.assertEqual(arp.plen, 4)
100 self.assertEqual(arp.op, arp_opts["who-has"])
101 self.assertEqual(arp.hwsrc, smac)
102 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
103 self.assertEqual(arp.psrc, sip)
104 self.assertEqual(arp.pdst, dip)
106 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
108 self.assertEqual(ether.dst, dmac)
109 self.assertEqual(ether.src, smac)
110 self.assertEqual(ether.type, 0x0806)
113 self.assertEqual(arp.hwtype, 1)
114 self.assertEqual(arp.ptype, 0x800)
115 self.assertEqual(arp.hwlen, 6)
116 self.assertEqual(arp.plen, 4)
117 self.assertEqual(arp.op, arp_opts["is-at"])
118 self.assertEqual(arp.hwsrc, smac)
119 self.assertEqual(arp.hwdst, dmac)
120 self.assertEqual(arp.psrc, sip)
121 self.assertEqual(arp.pdst, dip)
123 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
125 self.assertEqual(ether.dst, dmac)
126 self.assertEqual(ether.src, smac)
129 self.assertEqual(arp.hwtype, 1)
130 self.assertEqual(arp.ptype, 0x800)
131 self.assertEqual(arp.hwlen, 6)
132 self.assertEqual(arp.plen, 4)
133 self.assertEqual(arp.op, arp_opts["is-at"])
134 self.assertNotEqual(arp.hwsrc, smac)
135 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or "00:00:5E:00:01" in arp.hwsrc)
136 self.assertEqual(arp.hwdst, dmac)
137 self.assertEqual(arp.psrc, sip)
138 self.assertEqual(arp.pdst, dip)
140 def verify_ip(self, rx, smac, dmac, sip, dip):
142 self.assertEqual(ether.dst, dmac)
143 self.assertEqual(ether.src, smac)
144 self.assertEqual(ether.type, 0x0800)
147 self.assertEqual(ip.src, sip)
148 self.assertEqual(ip.dst, dip)
150 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
152 self.assertEqual(ether.dst, dmac)
153 self.assertEqual(ether.src, smac)
154 self.assertEqual(ether.type, 0x8847)
157 self.assertTrue(mpls.label, label)
160 self.assertEqual(ip.src, sip)
161 self.assertEqual(ip.dst, dip)
167 # Generate some hosts on the LAN
169 self.pg1.generate_remote_hosts(11)
173 # - all neighbour events
174 # - all neighbor events on pg1
175 # - neighbor events for host[1] on pg1
177 self.vapi.want_ip_neighbor_events(enable=1, pid=os.getpid())
178 self.vapi.want_ip_neighbor_events(
179 enable=1, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
181 self.vapi.want_ip_neighbor_events(
184 sw_if_index=self.pg1.sw_if_index,
185 ip=self.pg1.remote_hosts[1].ip4,
188 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
191 # Send IP traffic to one of these unresolved hosts.
192 # expect the generation of an ARP request
195 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
196 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
197 / UDP(sport=1234, dport=1234)
201 self.pg0.add_stream(p)
202 self.pg_enable_capture(self.pg_interfaces)
205 rx = self.pg1.get_capture(1)
208 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
212 # And a dynamic ARP entry for host 1
214 dyn_arp = VppNeighbor(
216 self.pg1.sw_if_index,
217 self.pg1.remote_hosts[1].mac,
218 self.pg1.remote_hosts[1].ip4,
220 dyn_arp.add_vpp_config()
221 self.assertTrue(dyn_arp.query_vpp_config())
223 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
225 # this matches all of the listnerers
226 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(3)]
228 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[1].ip4)
231 # now we expect IP traffic forwarded
234 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
235 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4)
236 / UDP(sport=1234, dport=1234)
240 self.pg0.add_stream(dyn_p)
241 self.pg_enable_capture(self.pg_interfaces)
244 rx = self.pg1.get_capture(1)
249 self.pg1.remote_hosts[1].mac,
251 self.pg1._remote_hosts[1].ip4,
255 # And a Static ARP entry for host 2
257 static_arp = VppNeighbor(
259 self.pg1.sw_if_index,
260 self.pg1.remote_hosts[2].mac,
261 self.pg1.remote_hosts[2].ip4,
264 static_arp.add_vpp_config()
265 es = [self.vapi.wait_for_event(1, "ip_neighbor_event") for i in range(2)]
267 self.assertEqual(str(e.neighbor.ip_address), self.pg1.remote_hosts[2].ip4)
270 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
271 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4)
272 / UDP(sport=1234, dport=1234)
276 self.pg0.add_stream(static_p)
277 self.pg_enable_capture(self.pg_interfaces)
280 rx = self.pg1.get_capture(1)
285 self.pg1.remote_hosts[2].mac,
287 self.pg1._remote_hosts[2].ip4,
291 # remove all the listeners
293 self.vapi.want_ip_neighbor_events(enable=0, pid=os.getpid())
294 self.vapi.want_ip_neighbor_events(
295 enable=0, pid=os.getpid(), sw_if_index=self.pg1.sw_if_index
297 self.vapi.want_ip_neighbor_events(
300 sw_if_index=self.pg1.sw_if_index,
301 ip=self.pg1.remote_hosts[1].ip4,
305 # flap the link. dynamic ARPs get flush, statics don't
307 self.pg1.admin_down()
310 self.pg0.add_stream(static_p)
311 self.pg_enable_capture(self.pg_interfaces)
313 rx = self.pg1.get_capture(1)
318 self.pg1.remote_hosts[2].mac,
320 self.pg1._remote_hosts[2].ip4,
323 self.pg0.add_stream(dyn_p)
324 self.pg_enable_capture(self.pg_interfaces)
327 rx = self.pg1.get_capture(1)
329 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
332 self.assertFalse(dyn_arp.query_vpp_config())
333 self.assertTrue(static_arp.query_vpp_config())
335 # Send an ARP request from one of the so-far unlearned remote hosts
337 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) / ARP(
339 hwsrc=self.pg1._remote_hosts[3].mac,
340 pdst=self.pg1.local_ip4,
341 psrc=self.pg1._remote_hosts[3].ip4,
344 self.pg1.add_stream(p)
345 self.pg_enable_capture(self.pg_interfaces)
348 rx = self.pg1.get_capture(1)
349 self.verify_arp_resp(
352 self.pg1._remote_hosts[3].mac,
354 self.pg1._remote_hosts[3].ip4,
358 # VPP should have learned the mapping for the remote host
361 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)
364 # Fire in an ARP request before the interface becomes IP enabled
366 self.pg2.generate_remote_hosts(4)
368 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
370 hwsrc=self.pg2.remote_mac,
371 pdst=self.pg1.local_ip4,
372 psrc=self.pg2.remote_hosts[3].ip4,
375 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac)
379 hwsrc=self.pg2.remote_mac,
380 pdst=self.pg1.local_ip4,
381 psrc=self.pg2.remote_hosts[3].ip4,
384 self.send_and_assert_no_replies(self.pg2, p, "interface not IP enabled")
387 # Make pg2 un-numbered to pg1
389 self.pg2.set_unnumbered(self.pg1.sw_if_index)
392 # test the unnumbered dump both by all interfaces and just the enabled
395 unnum = self.vapi.ip_unnumbered_dump()
396 self.assertTrue(len(unnum))
397 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
398 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
399 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
400 self.assertTrue(len(unnum))
401 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
402 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
405 # We should respond to ARP requests for the unnumbered to address
406 # once an attached route to the source is known
408 self.send_and_assert_no_replies(
409 self.pg2, p, "ARP req for unnumbered address - no source"
412 attached_host = VppIpRoute(
414 self.pg2.remote_hosts[3].ip4,
416 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
418 attached_host.add_vpp_config()
420 self.pg2.add_stream(p)
421 self.pg_enable_capture(self.pg_interfaces)
424 rx = self.pg2.get_capture(1)
425 self.verify_arp_resp(
430 self.pg2.remote_hosts[3].ip4,
433 self.pg2.add_stream(pt)
434 self.pg_enable_capture(self.pg_interfaces)
437 rx = self.pg2.get_capture(1)
438 self.verify_arp_resp(
443 self.pg2.remote_hosts[3].ip4,
447 # A neighbor entry that has no associated FIB-entry
449 arp_no_fib = VppNeighbor(
451 self.pg1.sw_if_index,
452 self.pg1.remote_hosts[4].mac,
453 self.pg1.remote_hosts[4].ip4,
456 arp_no_fib.add_vpp_config()
459 # check we have the neighbor, but no route
462 find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)
464 self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32))
466 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
467 # from within pg1's subnet
469 arp_unnum = VppNeighbor(
471 self.pg2.sw_if_index,
472 self.pg1.remote_hosts[5].mac,
473 self.pg1.remote_hosts[5].ip4,
475 arp_unnum.add_vpp_config()
478 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
479 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4)
480 / UDP(sport=1234, dport=1234)
484 self.pg0.add_stream(p)
485 self.pg_enable_capture(self.pg_interfaces)
488 rx = self.pg2.get_capture(1)
493 self.pg1.remote_hosts[5].mac,
495 self.pg1._remote_hosts[5].ip4,
499 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
500 # with the unnumbered interface's address as the source
502 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
504 hwsrc=self.pg2.remote_mac,
505 pdst=self.pg1.local_ip4,
506 psrc=self.pg1.remote_hosts[6].ip4,
509 self.pg2.add_stream(p)
510 self.pg_enable_capture(self.pg_interfaces)
513 rx = self.pg2.get_capture(1)
514 self.verify_arp_resp(
519 self.pg1.remote_hosts[6].ip4,
523 # An attached host route out of pg2 for an undiscovered hosts generates
524 # an ARP request with the unnumbered address as the source
526 att_unnum = VppIpRoute(
528 self.pg1.remote_hosts[7].ip4,
530 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
532 att_unnum.add_vpp_config()
535 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
536 / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4)
537 / UDP(sport=1234, dport=1234)
541 self.pg0.add_stream(p)
542 self.pg_enable_capture(self.pg_interfaces)
545 rx = self.pg2.get_capture(1)
548 rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4
551 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
553 hwsrc=self.pg2.remote_mac,
554 pdst=self.pg1.local_ip4,
555 psrc=self.pg1.remote_hosts[7].ip4,
558 self.pg2.add_stream(p)
559 self.pg_enable_capture(self.pg_interfaces)
562 rx = self.pg2.get_capture(1)
563 self.verify_arp_resp(
568 self.pg1.remote_hosts[7].ip4,
572 # An attached host route as yet unresolved out of pg2 for an
573 # undiscovered host, an ARP requests begets a response.
575 att_unnum1 = VppIpRoute(
577 self.pg1.remote_hosts[8].ip4,
579 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
581 att_unnum1.add_vpp_config()
583 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
585 hwsrc=self.pg2.remote_mac,
586 pdst=self.pg1.local_ip4,
587 psrc=self.pg1.remote_hosts[8].ip4,
590 self.pg2.add_stream(p)
591 self.pg_enable_capture(self.pg_interfaces)
594 rx = self.pg2.get_capture(1)
595 self.verify_arp_resp(
600 self.pg1.remote_hosts[8].ip4,
604 # Send an ARP request from one of the so-far unlearned remote hosts
608 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac)
612 hwsrc=self.pg1._remote_hosts[9].mac,
613 pdst=self.pg1.local_ip4,
614 psrc=self.pg1._remote_hosts[9].ip4,
618 self.pg1.add_stream(p)
619 self.pg_enable_capture(self.pg_interfaces)
622 rx = self.pg1.get_capture(1)
623 self.verify_arp_resp(
626 self.pg1._remote_hosts[9].mac,
628 self.pg1._remote_hosts[9].ip4,
632 # Add a hierarchy of routes for a host in the sub-net.
633 # Should still get an ARP resp since the cover is attached
635 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(
637 hwsrc=self.pg1.remote_mac,
638 pdst=self.pg1.local_ip4,
639 psrc=self.pg1.remote_hosts[10].ip4,
644 self.pg1.remote_hosts[10].ip4,
646 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
650 self.pg1.add_stream(p)
651 self.pg_enable_capture(self.pg_interfaces)
653 rx = self.pg1.get_capture(1)
654 self.verify_arp_resp(
659 self.pg1.remote_hosts[10].ip4,
664 self.pg1.remote_hosts[10].ip4,
666 [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)],
670 self.pg1.add_stream(p)
671 self.pg_enable_capture(self.pg_interfaces)
673 rx = self.pg1.get_capture(1)
674 self.verify_arp_resp(
679 self.pg1.remote_hosts[10].ip4,
683 # add an ARP entry that's not on the sub-net and so whose
684 # adj-fib fails the refinement check. then send an ARP request
688 self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50"
692 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
694 hwsrc=self.pg0.remote_mac,
695 psrc="100.100.100.50",
696 pdst=self.pg0.remote_ip4,
698 self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib")
702 # 1 - don't respond to ARP request for address not within the
703 # interface's sub-net
704 # 1b - nor within the unnumbered subnet
705 # 1c - nor within the subnet of a different interface
707 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
709 hwsrc=self.pg0.remote_mac,
711 psrc=self.pg0.remote_ip4,
713 self.send_and_assert_no_replies(
714 self.pg0, p, "ARP req for non-local destination"
716 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3"))
718 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
720 hwsrc=self.pg2.remote_mac,
722 psrc=self.pg1.remote_hosts[7].ip4,
724 self.send_and_assert_no_replies(
725 self.pg0, p, "ARP req for non-local destination - unnum"
728 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
730 hwsrc=self.pg0.remote_mac,
731 pdst=self.pg1.local_ip4,
732 psrc=self.pg1.remote_ip4,
734 self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net")
735 self.assertFalse(find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4))
738 # 2 - don't respond to ARP request from an address not within the
739 # interface's sub-net
740 # 2b - to a proxied address
741 # 2c - not within a different interface's sub-net
742 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
744 hwsrc=self.pg0.remote_mac,
746 pdst=self.pg0.local_ip4,
748 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
749 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(
751 hwsrc=self.pg2.remote_mac,
753 pdst=self.pg0.local_ip4,
755 self.send_and_assert_no_replies(
756 self.pg0, p, "ARP req for non-local source - unnum"
758 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
760 hwsrc=self.pg0.remote_mac,
761 psrc=self.pg1.remote_ip4,
762 pdst=self.pg0.local_ip4,
764 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c")
767 # 3 - don't respond to ARP request from an address that belongs to
770 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
772 hwsrc=self.pg0.remote_mac,
773 psrc=self.pg0.local_ip4,
774 pdst=self.pg0.local_ip4,
776 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
779 # 4 - don't respond to ARP requests that has mac source different
780 # from ARP request HW source
782 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
784 hwsrc="00:00:00:DE:AD:BE",
785 psrc=self.pg0.remote_ip4,
786 pdst=self.pg0.local_ip4,
788 self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source")
791 # 5 - don't respond to ARP requests for address within the
792 # interface's sub-net but not the interface's address
794 self.pg0.generate_remote_hosts(2)
795 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
797 hwsrc=self.pg0.remote_mac,
798 psrc=self.pg0.remote_hosts[0].ip4,
799 pdst=self.pg0.remote_hosts[1].ip4,
801 self.send_and_assert_no_replies(
802 self.pg0, p, "ARP req for non-local destination"
808 static_arp.remove_vpp_config()
809 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
811 # need this to flush the adj-fibs
812 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
813 self.pg2.admin_down()
814 self.pg1.admin_down()
816 def test_proxy_mirror_arp(self):
817 """Interface Mirror Proxy ARP"""
820 # When VPP has an interface whose address is also applied to a TAP
821 # interface on the host, then VPP's TAP interface will be unnumbered
822 # to the 'real' interface and do proxy ARP from the host.
823 # the curious aspect of this setup is that ARP requests from the host
824 # will come from the VPP's own address.
826 self.pg0.generate_remote_hosts(2)
828 arp_req_from_me = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
830 hwsrc=self.pg2.remote_mac,
831 pdst=self.pg0.remote_hosts[1].ip4,
832 psrc=self.pg0.local_ip4,
836 # Configure Proxy ARP for the subnet on PG0addresses on pg0
838 self.vapi.proxy_arp_add_del(
841 "low": self.pg0._local_ip4_subnet,
842 "hi": self.pg0._local_ip4_bcast,
847 # Make pg2 un-numbered to pg0
849 self.pg2.set_unnumbered(self.pg0.sw_if_index)
852 # Enable pg2 for proxy ARP
854 self.pg2.set_proxy_arp()
857 # Send the ARP request with an originating address that
858 # is VPP's own address
860 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
861 self.verify_arp_resp(
865 self.pg0.remote_hosts[1].ip4,
870 # validate we have not learned an ARP entry as a result of this
872 self.assertFalse(find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4))
875 # setup a punt redirect so packets from the uplink go to the tap
877 redirect = VppIpPuntRedirect(
878 self, self.pg0.sw_if_index, self.pg2.sw_if_index, self.pg0.local_ip4
880 redirect.add_vpp_config()
884 src=self.pg0.remote_mac,
885 dst=self.pg0.local_mac,
887 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
888 / TCP(sport=80, dport=80)
891 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
893 # there's no ARP entry so this is an ARP req
894 self.assertTrue(rx[0].haslayer(ARP))
896 # and ARP entry for VPP's pg0 address on the host interface
899 self.pg2.sw_if_index,
902 is_no_fib_entry=True,
904 # now the packets shold forward
905 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
906 self.assertFalse(rx[0].haslayer(ARP))
907 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
910 # flush the neighbor cache on the uplink
912 af = VppEnum.vl_api_address_family_t
913 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
915 # ensure we can still resolve the ARPs on the uplink
916 self.pg0.resolve_arp()
918 self.assertTrue(find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_ip4))
923 self.vapi.proxy_arp_add_del(
926 "low": self.pg0._local_ip4_subnet,
927 "hi": self.pg0._local_ip4_bcast,
931 redirect.remove_vpp_config()
933 def test_proxy_arp(self):
936 self.pg1.generate_remote_hosts(2)
939 # Proxy ARP request packets for each interface
941 arp_req_pg0 = Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
943 hwsrc=self.pg0.remote_mac,
945 psrc=self.pg0.remote_ip4,
947 arp_req_pg0_tagged = (
948 Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff")
952 hwsrc=self.pg0.remote_mac,
954 psrc=self.pg0.remote_ip4,
957 arp_req_pg1 = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
959 hwsrc=self.pg1.remote_mac,
961 psrc=self.pg1.remote_ip4,
963 arp_req_pg2 = Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
965 hwsrc=self.pg2.remote_mac,
967 psrc=self.pg1.remote_hosts[1].ip4,
969 arp_req_pg3 = Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
971 hwsrc=self.pg3.remote_mac,
973 psrc=self.pg3.remote_ip4,
977 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
979 self.vapi.proxy_arp_add_del(
980 proxy={"table_id": 0, "low": "10.10.10.2", "hi": "10.10.10.124"}, is_add=1
984 # No responses are sent when the interfaces are not enabled for proxy
987 self.send_and_assert_no_replies(
988 self.pg0, arp_req_pg0, "ARP req from unconfigured interface"
990 self.send_and_assert_no_replies(
991 self.pg2, arp_req_pg2, "ARP req from unconfigured interface"
995 # Make pg2 un-numbered to pg1
998 self.pg2.set_unnumbered(self.pg1.sw_if_index)
1000 self.send_and_assert_no_replies(
1001 self.pg2, arp_req_pg2, "ARP req from unnumbered interface"
1005 # Enable each interface to reply to proxy ARPs
1007 for i in self.pg_interfaces:
1011 # Now each of the interfaces should reply to a request to a proxied
1014 self.pg0.add_stream(arp_req_pg0)
1015 self.pg_enable_capture(self.pg_interfaces)
1018 rx = self.pg0.get_capture(1)
1019 self.verify_arp_resp(
1022 self.pg0.remote_mac,
1024 self.pg0.remote_ip4,
1027 self.pg0.add_stream(arp_req_pg0_tagged)
1028 self.pg_enable_capture(self.pg_interfaces)
1031 rx = self.pg0.get_capture(1)
1032 self.verify_arp_resp(
1035 self.pg0.remote_mac,
1037 self.pg0.remote_ip4,
1040 self.pg1.add_stream(arp_req_pg1)
1041 self.pg_enable_capture(self.pg_interfaces)
1044 rx = self.pg1.get_capture(1)
1045 self.verify_arp_resp(
1048 self.pg1.remote_mac,
1050 self.pg1.remote_ip4,
1053 self.pg2.add_stream(arp_req_pg2)
1054 self.pg_enable_capture(self.pg_interfaces)
1057 rx = self.pg2.get_capture(1)
1058 self.verify_arp_resp(
1061 self.pg2.remote_mac,
1063 self.pg1.remote_hosts[1].ip4,
1067 # A request for an address out of the configured range
1069 arp_req_pg1_hi = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1071 hwsrc=self.pg1.remote_mac,
1072 pdst="10.10.10.125",
1073 psrc=self.pg1.remote_ip4,
1075 self.send_and_assert_no_replies(
1076 self.pg1, arp_req_pg1_hi, "ARP req out of range HI"
1078 arp_req_pg1_low = Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(
1080 hwsrc=self.pg1.remote_mac,
1082 psrc=self.pg1.remote_ip4,
1084 self.send_and_assert_no_replies(
1085 self.pg1, arp_req_pg1_low, "ARP req out of range Low"
1089 # Request for an address in the proxy range but from an interface
1090 # in a different VRF
1092 self.send_and_assert_no_replies(
1093 self.pg3, arp_req_pg3, "ARP req from different VRF"
1097 # Disable Each interface for proxy ARP
1098 # - expect none to respond
1100 for i in self.pg_interfaces:
1103 self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from disable")
1104 self.send_and_assert_no_replies(self.pg1, arp_req_pg1, "ARP req from disable")
1105 self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from disable")
1108 # clean up on interface 2
1110 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1112 def test_mpls(self):
1116 # Interface 2 does not yet have ip4 config
1118 self.pg2.config_ip4()
1119 self.pg2.generate_remote_hosts(2)
1122 # Add a route with out going label via an ARP unresolved next-hop
1124 ip_10_0_0_1 = VppIpRoute(
1130 self.pg2.remote_hosts[1].ip4, self.pg2.sw_if_index, labels=[55]
1134 ip_10_0_0_1.add_vpp_config()
1137 # packets should generate an ARP request
1140 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1141 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
1142 / UDP(sport=1234, dport=1234)
1143 / Raw(b"\xa5" * 100)
1146 self.pg0.add_stream(p)
1147 self.pg_enable_capture(self.pg_interfaces)
1150 rx = self.pg2.get_capture(1)
1151 self.verify_arp_req(
1152 rx[0], self.pg2.local_mac, self.pg2.local_ip4, self.pg2._remote_hosts[1].ip4
1156 # now resolve the neighbours
1158 self.pg2.configure_ipv4_neighbors()
1161 # Now packet should be properly MPLS encapped.
1162 # This verifies that MPLS link-type adjacencies are completed
1163 # when the ARP entry resolves
1165 self.pg0.add_stream(p)
1166 self.pg_enable_capture(self.pg_interfaces)
1169 rx = self.pg2.get_capture(1)
1170 self.verify_ip_o_mpls(
1173 self.pg2.remote_hosts[1].mac,
1175 self.pg0.remote_ip4,
1178 self.pg2.unconfig_ip4()
1180 def test_arp_vrrp(self):
1181 """ARP reply with VRRP virtual src hw addr"""
1184 # IP packet destined for pg1 remote host arrives on pg0 resulting
1185 # in an ARP request for the address of the remote host on pg1
1188 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1189 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
1190 / UDP(sport=1234, dport=1234)
1194 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1196 self.verify_arp_req(
1197 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_ip4
1201 # ARP reply for address of pg1 remote host arrives on pg1 with
1202 # the hw src addr set to a value in the VRRP IPv4 range of
1205 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1207 hwdst=self.pg1.local_mac,
1208 hwsrc="00:00:5e:00:01:09",
1209 pdst=self.pg1.local_ip4,
1210 psrc=self.pg1.remote_ip4,
1213 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1216 # IP packet destined for pg1 remote host arrives on pg0 again.
1217 # VPP should have an ARP entry for that address now and the packet
1218 # should be sent out pg1.
1220 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1225 "00:00:5e:00:01:09",
1226 self.pg0.remote_ip4,
1227 self.pg1.remote_ip4,
1230 self.pg1.admin_down()
1233 def test_arp_duplicates(self):
1234 """ARP Duplicates"""
1237 # Generate some hosts on the LAN
1239 self.pg1.generate_remote_hosts(3)
1242 # Add host 1 on pg1 and pg2
1244 arp_pg1 = VppNeighbor(
1246 self.pg1.sw_if_index,
1247 self.pg1.remote_hosts[1].mac,
1248 self.pg1.remote_hosts[1].ip4,
1250 arp_pg1.add_vpp_config()
1251 arp_pg2 = VppNeighbor(
1253 self.pg2.sw_if_index,
1254 self.pg2.remote_mac,
1255 self.pg1.remote_hosts[1].ip4,
1257 arp_pg2.add_vpp_config()
1260 # IP packet destined for pg1 remote host arrives on pg1 again.
1263 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1264 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1265 / UDP(sport=1234, dport=1234)
1269 self.pg0.add_stream(p)
1270 self.pg_enable_capture(self.pg_interfaces)
1273 rx1 = self.pg1.get_capture(1)
1278 self.pg1.remote_hosts[1].mac,
1279 self.pg0.remote_ip4,
1280 self.pg1.remote_hosts[1].ip4,
1284 # remove the duplicate on pg1
1285 # packet stream should generate ARPs out of pg1
1287 arp_pg1.remove_vpp_config()
1289 self.pg0.add_stream(p)
1290 self.pg_enable_capture(self.pg_interfaces)
1293 rx1 = self.pg1.get_capture(1)
1295 self.verify_arp_req(
1296 rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4
1302 arp_pg1.add_vpp_config()
1304 self.pg0.add_stream(p)
1305 self.pg_enable_capture(self.pg_interfaces)
1308 rx1 = self.pg1.get_capture(1)
1313 self.pg1.remote_hosts[1].mac,
1314 self.pg0.remote_ip4,
1315 self.pg1.remote_hosts[1].ip4,
1318 def test_arp_static(self):
1320 self.pg2.generate_remote_hosts(3)
1323 # Add a static ARP entry
1325 static_arp = VppNeighbor(
1327 self.pg2.sw_if_index,
1328 self.pg2.remote_hosts[1].mac,
1329 self.pg2.remote_hosts[1].ip4,
1332 static_arp.add_vpp_config()
1335 # Add the connected prefix to the interface
1337 self.pg2.config_ip4()
1340 # We should now find the adj-fib
1344 self, self.pg2.sw_if_index, self.pg2.remote_hosts[1].ip4, is_static=1
1347 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32))
1350 # remove the connected
1352 self.pg2.unconfig_ip4()
1355 # put the interface into table 1
1357 self.pg2.set_table_ip4(1)
1360 # configure the same connected and expect to find the
1361 # adj fib in the new table
1363 self.pg2.config_ip4()
1364 self.assertTrue(find_route(self, self.pg2.remote_hosts[1].ip4, 32, table_id=1))
1369 self.pg2.unconfig_ip4()
1370 static_arp.remove_vpp_config()
1371 self.pg2.set_table_ip4(0)
1373 def test_arp_static_replace_dynamic_same_mac(self):
1374 """ARP Static can replace Dynamic (same mac)"""
1375 self.pg2.generate_remote_hosts(1)
1377 dyn_arp = VppNeighbor(
1379 self.pg2.sw_if_index,
1380 self.pg2.remote_hosts[0].mac,
1381 self.pg2.remote_hosts[0].ip4,
1383 static_arp = VppNeighbor(
1385 self.pg2.sw_if_index,
1386 self.pg2.remote_hosts[0].mac,
1387 self.pg2.remote_hosts[0].ip4,
1392 # Add a dynamic ARP entry
1394 dyn_arp.add_vpp_config()
1397 # We should find the dynamic nbr
1401 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1407 self.pg2.sw_if_index,
1408 self.pg2.remote_hosts[0].ip4,
1410 mac=self.pg2.remote_hosts[0].mac,
1415 # Add a static ARP entry with the same mac
1417 static_arp.add_vpp_config()
1420 # We should now find the static nbr with the same mac
1424 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1430 self.pg2.sw_if_index,
1431 self.pg2.remote_hosts[0].ip4,
1433 mac=self.pg2.remote_hosts[0].mac,
1440 static_arp.remove_vpp_config()
1442 def test_arp_static_replace_dynamic_diff_mac(self):
1443 """ARP Static can replace Dynamic (diff mac)"""
1444 self.pg2.generate_remote_hosts(2)
1446 dyn_arp = VppNeighbor(
1448 self.pg2.sw_if_index,
1449 self.pg2.remote_hosts[0].mac,
1450 self.pg2.remote_hosts[0].ip4,
1452 static_arp = VppNeighbor(
1454 self.pg2.sw_if_index,
1455 self.pg2.remote_hosts[1].mac,
1456 self.pg2.remote_hosts[0].ip4,
1461 # Add a dynamic ARP entry
1463 dyn_arp.add_vpp_config()
1466 # We should find the dynamic nbr
1470 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=1
1476 self.pg2.sw_if_index,
1477 self.pg2.remote_hosts[0].ip4,
1479 mac=self.pg2.remote_hosts[0].mac,
1484 # Add a static ARP entry with a changed mac
1486 static_arp.add_vpp_config()
1489 # We should now find the static nbr with a changed mac
1493 self, self.pg2.sw_if_index, self.pg2.remote_hosts[0].ip4, is_static=0
1499 self.pg2.sw_if_index,
1500 self.pg2.remote_hosts[0].ip4,
1502 mac=self.pg2.remote_hosts[1].mac,
1509 static_arp.remove_vpp_config()
1511 def test_arp_incomplete(self):
1512 """ARP Incomplete"""
1513 self.pg1.generate_remote_hosts(4)
1516 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1517 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
1518 / UDP(sport=1234, dport=1234)
1522 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1523 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
1524 / UDP(sport=1234, dport=1234)
1528 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1529 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
1530 / UDP(sport=1234, dport=1234)
1535 # a packet to an unresolved destination generates an ARP request
1537 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1538 self.verify_arp_req(
1539 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4
1543 # add a neighbour for remote host 1
1545 static_arp = VppNeighbor(
1547 self.pg1.sw_if_index,
1548 self.pg1.remote_hosts[1].mac,
1549 self.pg1.remote_hosts[1].ip4,
1552 static_arp.add_vpp_config()
1555 # add a route through remote host 3 hence we get an incomplete
1561 [VppRoutePath(self.pg1.remote_hosts[3].ip4, self.pg1.sw_if_index)],
1563 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1564 self.verify_arp_req(
1565 rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4
1569 # change the interface's MAC
1571 self.vapi.sw_interface_set_mac_address(
1572 self.pg1.sw_if_index, "00:00:00:33:33:33"
1576 # now ARP requests come from the new source mac
1578 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1579 self.verify_arp_req(
1581 "00:00:00:33:33:33",
1583 self.pg1._remote_hosts[2].ip4,
1585 rx = self.send_and_expect(self.pg0, [p2], self.pg1)
1586 self.verify_arp_req(
1588 "00:00:00:33:33:33",
1590 self.pg1._remote_hosts[3].ip4,
1594 # packets to the resolved host also have the new source mac
1596 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1599 "00:00:00:33:33:33",
1600 self.pg1.remote_hosts[1].mac,
1601 self.pg0.remote_ip4,
1602 self.pg1.remote_hosts[1].ip4,
1606 # set the mac address on the interface that does not have a
1607 # configured subnet and thus no glean
1609 self.vapi.sw_interface_set_mac_address(
1610 self.pg2.sw_if_index, "00:00:00:33:33:33"
1613 def test_garp(self):
1617 # Generate some hosts on the LAN
1619 self.pg1.generate_remote_hosts(4)
1620 self.pg2.generate_remote_hosts(4)
1627 self.pg1.sw_if_index,
1628 self.pg1.remote_hosts[1].mac,
1629 self.pg1.remote_hosts[1].ip4,
1631 arp.add_vpp_config()
1636 self.pg1.sw_if_index,
1637 self.pg1.remote_hosts[1].ip4,
1638 mac=self.pg1.remote_hosts[1].mac,
1643 # Send a GARP (request) to swap the host 1's address to that of host 2
1645 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[2].mac) / ARP(
1647 hwdst=self.pg1.local_mac,
1648 hwsrc=self.pg1.remote_hosts[2].mac,
1649 pdst=self.pg1.remote_hosts[1].ip4,
1650 psrc=self.pg1.remote_hosts[1].ip4,
1653 self.pg1.add_stream(p1)
1654 self.pg_enable_capture(self.pg_interfaces)
1660 self.pg1.sw_if_index,
1661 self.pg1.remote_hosts[1].ip4,
1662 mac=self.pg1.remote_hosts[2].mac,
1667 # Send a GARP (reply) to swap the host 1's address to that of host 3
1669 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1671 hwdst=self.pg1.local_mac,
1672 hwsrc=self.pg1.remote_hosts[3].mac,
1673 pdst=self.pg1.remote_hosts[1].ip4,
1674 psrc=self.pg1.remote_hosts[1].ip4,
1677 self.pg1.add_stream(p1)
1678 self.pg_enable_capture(self.pg_interfaces)
1684 self.pg1.sw_if_index,
1685 self.pg1.remote_hosts[1].ip4,
1686 mac=self.pg1.remote_hosts[3].mac,
1691 # GARPs (request nor replies) for host we don't know yet
1692 # don't result in new neighbour entries
1694 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1696 hwdst=self.pg1.local_mac,
1697 hwsrc=self.pg1.remote_hosts[3].mac,
1698 pdst=self.pg1.remote_hosts[2].ip4,
1699 psrc=self.pg1.remote_hosts[2].ip4,
1702 self.pg1.add_stream(p1)
1703 self.pg_enable_capture(self.pg_interfaces)
1707 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1710 p1 = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_hosts[3].mac) / ARP(
1712 hwdst=self.pg1.local_mac,
1713 hwsrc=self.pg1.remote_hosts[3].mac,
1714 pdst=self.pg1.remote_hosts[2].ip4,
1715 psrc=self.pg1.remote_hosts[2].ip4,
1718 self.pg1.add_stream(p1)
1719 self.pg_enable_capture(self.pg_interfaces)
1723 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].ip4)
1727 # IP address in different subnets are not learnt
1729 self.pg2.configure_ipv4_neighbors()
1731 for op in ["is-at", "who-has"]:
1734 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1737 hwdst=self.pg2.local_mac,
1738 hwsrc=self.pg2.remote_hosts[1].mac,
1739 pdst=self.pg2.remote_hosts[1].ip4,
1740 psrc=self.pg2.remote_hosts[1].ip4,
1744 Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1747 hwdst="ff:ff:ff:ff:ff:ff",
1748 hwsrc=self.pg2.remote_hosts[1].mac,
1749 pdst=self.pg2.remote_hosts[1].ip4,
1750 psrc=self.pg2.remote_hosts[1].ip4,
1755 self.send_and_assert_no_replies(self.pg1, p1)
1757 find_nbr(self, self.pg1.sw_if_index, self.pg2.remote_hosts[1].ip4)
1760 # they are all dropped because the subnet's don't match
1763 self.statistics.get_err_counter(
1764 "/err/arp-reply/IP4 destination address not local to subnet"
1768 def test_arp_incomplete2(self):
1769 """Incomplete Entries"""
1772 # ensure that we throttle the ARP and ND requests
1774 self.pg0.generate_remote_hosts(2)
1779 ip_10_0_0_1 = VppIpRoute(
1783 [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1785 ip_10_0_0_1.add_vpp_config()
1788 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1789 / IP(src=self.pg1.remote_ip4, dst="10.0.0.1")
1790 / UDP(sport=1234, dport=1234)
1794 self.pg1.add_stream(p1 * 257)
1795 self.pg_enable_capture(self.pg_interfaces)
1797 rx = self.pg0._get_capture(1)
1800 # how many we get is going to be dependent on the time for packet
1801 # processing but it should be small
1803 self.assertLess(len(rx), 64)
1808 ip_10_1 = VppIpRoute(
1814 self.pg0.remote_hosts[1].ip6,
1815 self.pg0.sw_if_index,
1816 proto=DpoProto.DPO_PROTO_IP6,
1820 ip_10_1.add_vpp_config()
1823 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1824 / IPv6(src=self.pg1.remote_ip6, dst="10::1")
1825 / UDP(sport=1234, dport=1234)
1829 self.pg1.add_stream(p1 * 257)
1830 self.pg_enable_capture(self.pg_interfaces)
1832 rx = self.pg0._get_capture(1)
1835 # how many we get is going to be dependent on the time for packet
1836 # processing but it should be small
1838 self.assertLess(len(rx), 64)
1840 def test_arp_forus(self):
1841 """ARP for for-us"""
1844 # Test that VPP responds with ARP requests to addresses that
1845 # are connected and local routes.
1846 # Use one of the 'remote' addresses in the subnet as a local address
1847 # The intention of this route is that it then acts like a secondary
1848 # address added to an interface
1850 self.pg0.generate_remote_hosts(2)
1854 self.pg0.remote_hosts[1].ip4,
1859 self.pg0.sw_if_index,
1860 type=FibPathType.FIB_PATH_TYPE_LOCAL,
1864 forus.add_vpp_config()
1866 p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
1868 hwdst=self.pg0.local_mac,
1869 hwsrc=self.pg0.remote_mac,
1870 pdst=self.pg0.remote_hosts[1].ip4,
1871 psrc=self.pg0.remote_ip4,
1874 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1876 self.verify_arp_resp(
1879 self.pg0.remote_mac,
1880 self.pg0.remote_hosts[1].ip4,
1881 self.pg0.remote_ip4,
1884 def test_arp_table_swap(self):
1886 # Generate some hosts on the LAN
1889 self.pg1.generate_remote_hosts(N_NBRS)
1891 for n in range(N_NBRS):
1892 # a route thru each neighbour
1897 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
1900 # resolve each neighbour
1901 p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1903 hwdst=self.pg1.local_mac,
1904 hwsrc="00:00:5e:00:01:09",
1905 pdst=self.pg1.local_ip4,
1906 psrc=self.pg1.remote_hosts[n].ip4,
1909 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1911 self.logger.info(self.vapi.cli("sh ip neighbors"))
1914 # swap the table pg1 is in
1916 table = VppIpTable(self, 100).add_vpp_config()
1918 self.pg1.unconfig_ip4()
1919 self.pg1.set_table_ip4(100)
1920 self.pg1.config_ip4()
1923 # all neighbours are cleared
1925 for n in range(N_NBRS):
1927 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip4)
1931 # packets to all neighbours generate ARP requests
1933 for n in range(N_NBRS):
1934 # a route thru each neighbour
1939 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
1944 Ether(src=self.pg1.remote_hosts[n].mac, dst=self.pg1.local_mac)
1945 / IP(src=self.pg1.remote_hosts[n].ip4, dst="10.0.0.%d" % n)
1948 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1950 self.verify_arp_req(
1954 self.pg1.remote_hosts[n].ip4,
1957 self.pg1.unconfig_ip4()
1958 self.pg1.set_table_ip4(0)
1960 def test_glean_src_select(self):
1961 """Multi Connecteds"""
1964 # configure multiple connected subnets on an interface
1965 # and ensure that ARP requests for hosts on those subnets
1966 # pick up the correct source address
1968 conn1 = VppIpInterfaceAddress(self, self.pg1, "10.0.0.1", 24).add_vpp_config()
1969 conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
1972 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1973 / IP(src=self.pg1.remote_ip4, dst="10.0.0.128")
1977 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
1979 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.0.1", "10.0.0.128")
1982 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1983 / IP(src=self.pg1.remote_ip4, dst="10.0.1.128")
1987 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1989 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
1992 # add a local address in the same subnet
1993 # the source addresses are equivalent. VPP happens to
1994 # choose the last one that was added
1995 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
1997 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1999 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2004 conn3.remove_vpp_config()
2005 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2007 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2010 # add back, this time remove the first one
2012 conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2014 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2016 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2018 conn1.remove_vpp_config()
2019 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2021 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2023 # apply a connected prefix to an interface in a different table
2028 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2032 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2034 self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2037 conn3.remove_vpp_config()
2038 conn2.remove_vpp_config()
2041 @tag_fixme_vpp_workers
2042 class NeighborStatsTestCase(VppTestCase):
2043 """ARP/ND Counters"""
2046 def setUpClass(cls):
2047 super(NeighborStatsTestCase, cls).setUpClass()
2050 def tearDownClass(cls):
2051 super(NeighborStatsTestCase, cls).tearDownClass()
2054 super(NeighborStatsTestCase, self).setUp()
2056 self.create_pg_interfaces(range(2))
2058 # pg0 configured with ip4 and 6 addresses used for input
2059 # pg1 configured with ip4 and 6 addresses used for output
2060 # pg2 is unnumbered to pg0
2061 for i in self.pg_interfaces:
2069 super(NeighborStatsTestCase, self).tearDown()
2071 for i in self.pg_interfaces:
2076 def test_arp_stats(self):
2079 self.vapi.cli("adj counters enable")
2080 self.pg1.generate_remote_hosts(2)
2084 self.pg1.sw_if_index,
2085 self.pg1.remote_hosts[0].mac,
2086 self.pg1.remote_hosts[0].ip4,
2088 arp1.add_vpp_config()
2091 self.pg1.sw_if_index,
2092 self.pg1.remote_hosts[1].mac,
2093 self.pg1.remote_hosts[1].ip4,
2095 arp2.add_vpp_config()
2098 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2099 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2100 / UDP(sport=1234, dport=1234)
2104 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2105 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2106 / UDP(sport=1234, dport=1234)
2110 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2111 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2113 self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2114 self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2116 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2117 self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2119 def test_nd_stats(self):
2122 self.vapi.cli("adj counters enable")
2123 self.pg0.generate_remote_hosts(3)
2127 self.pg0.sw_if_index,
2128 self.pg0.remote_hosts[1].mac,
2129 self.pg0.remote_hosts[1].ip6,
2131 nd1.add_vpp_config()
2134 self.pg0.sw_if_index,
2135 self.pg0.remote_hosts[2].mac,
2136 self.pg0.remote_hosts[2].ip6,
2138 nd2.add_vpp_config()
2141 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2142 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2143 / UDP(sport=1234, dport=1234)
2147 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2148 / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2149 / UDP(sport=1234, dport=1234)
2153 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2154 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2156 self.assertEqual(16, nd1.get_stats()["packets"])
2157 self.assertEqual(16, nd2.get_stats()["packets"])
2159 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2160 self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2163 class NeighborAgeTestCase(VppTestCase):
2167 def setUpClass(cls):
2168 super(NeighborAgeTestCase, cls).setUpClass()
2171 def tearDownClass(cls):
2172 super(NeighborAgeTestCase, cls).tearDownClass()
2175 super(NeighborAgeTestCase, self).setUp()
2177 self.create_pg_interfaces(range(1))
2179 # pg0 configured with ip4 and 6 addresses used for input
2180 # pg1 configured with ip4 and 6 addresses used for output
2181 # pg2 is unnumbered to pg0
2182 for i in self.pg_interfaces:
2190 super(NeighborAgeTestCase, self).tearDown()
2192 for i in self.pg_interfaces:
2197 def verify_arp_req(self, rx, smac, sip, dip):
2199 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2200 self.assertEqual(ether.src, smac)
2203 self.assertEqual(arp.hwtype, 1)
2204 self.assertEqual(arp.ptype, 0x800)
2205 self.assertEqual(arp.hwlen, 6)
2206 self.assertEqual(arp.plen, 4)
2207 self.assertEqual(arp.op, arp_opts["who-has"])
2208 self.assertEqual(arp.hwsrc, smac)
2209 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2210 self.assertEqual(arp.psrc, sip)
2211 self.assertEqual(arp.pdst, dip)
2216 self.vapi.cli("set logging unthrottle 0")
2217 self.vapi.cli("set logging size %d" % 0xFFFF)
2219 self.pg0.generate_remote_hosts(201)
2221 vaf = VppEnum.vl_api_address_family_t
2224 # start listening on all interfaces
2226 self.pg_enable_capture(self.pg_interfaces)
2229 # Set the neighbor configuration:
2234 self.vapi.ip_neighbor_config(
2235 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2238 self.vapi.cli("sh ip neighbor-config")
2240 # add the 198 neighbours that should pass (-1 for one created in setup)
2241 for ii in range(200):
2244 self.pg0.sw_if_index,
2245 self.pg0.remote_hosts[ii].mac,
2246 self.pg0.remote_hosts[ii].ip4,
2249 # one more neighbor over the limit should fail
2250 with self.vapi.assert_negative_api_retval():
2253 self.pg0.sw_if_index,
2254 self.pg0.remote_hosts[200].mac,
2255 self.pg0.remote_hosts[200].ip4,
2259 # change the config to allow recycling the old neighbors
2261 self.vapi.ip_neighbor_config(
2262 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2265 # now new additions are allowed
2268 self.pg0.sw_if_index,
2269 self.pg0.remote_hosts[200].mac,
2270 self.pg0.remote_hosts[200].ip4,
2273 # add the first neighbor we configured has been re-used
2275 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2278 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2282 # change the config to age old neighbors
2284 self.vapi.ip_neighbor_config(
2285 af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2288 self.vapi.cli("sh ip4 neighbor-sorted")
2291 self.virtual_sleep(3)
2294 # expect probes from all these ARP entries as they age
2295 # 3 probes for each neighbor 3*200 = 600
2296 rxs = self.pg0.get_capture(600, timeout=2)
2299 for jj in range(200):
2300 rx = rxs[ii * 200 + jj]
2304 # 3 probes sent then 1 more second to see if a reply comes, before
2307 self.virtual_sleep(1)
2310 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2314 # load up some neighbours again with 2s aging enabled
2315 # they should be removed after 10s (2s age + 4s for probes + gap)
2316 # check for the add and remove events
2318 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2320 self.vapi.want_ip_neighbor_events_v2(enable=1)
2321 for ii in range(10):
2324 self.pg0.sw_if_index,
2325 self.pg0.remote_hosts[ii].mac,
2326 self.pg0.remote_hosts[ii].ip4,
2329 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2330 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2331 self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2332 self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2334 self.virtual_sleep(10)
2336 self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2340 for ii in range(10):
2341 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2342 self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2345 # check we got the correct mac/ip pairs - done separately
2346 # because we don't care about the order the remove notifications
2348 for ii in range(10):
2350 mac = self.pg0.remote_hosts[ii].mac
2351 ip = self.pg0.remote_hosts[ii].ip4
2354 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2357 self.assertTrue(found)
2360 # check if we can set age and recycle with empty neighbor list
2362 self.vapi.ip_neighbor_config(
2363 af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2367 # load up some neighbours again, then disable the aging
2368 # they should still be there in 10 seconds time
2370 for ii in range(10):
2373 self.pg0.sw_if_index,
2374 self.pg0.remote_hosts[ii].mac,
2375 self.pg0.remote_hosts[ii].ip4,
2377 self.vapi.ip_neighbor_config(
2378 af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2381 self.virtual_sleep(10)
2383 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2387 class NeighborReplaceTestCase(VppTestCase):
2388 """ARP/ND Replacement"""
2391 def setUpClass(cls):
2392 super(NeighborReplaceTestCase, cls).setUpClass()
2395 def tearDownClass(cls):
2396 super(NeighborReplaceTestCase, cls).tearDownClass()
2399 super(NeighborReplaceTestCase, self).setUp()
2401 self.create_pg_interfaces(range(4))
2403 # pg0 configured with ip4 and 6 addresses used for input
2404 # pg1 configured with ip4 and 6 addresses used for output
2405 # pg2 is unnumbered to pg0
2406 for i in self.pg_interfaces:
2414 super(NeighborReplaceTestCase, self).tearDown()
2416 for i in self.pg_interfaces:
2421 def test_replace(self):
2426 for i in self.pg_interfaces:
2427 i.generate_remote_hosts(N_HOSTS)
2428 i.configure_ipv4_neighbors()
2429 i.configure_ipv6_neighbors()
2432 self.vapi.ip_neighbor_replace_begin()
2433 self.vapi.ip_neighbor_replace_end()
2435 for i in self.pg_interfaces:
2436 for h in range(N_HOSTS):
2438 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2441 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2445 # and them all back via the API
2447 for i in self.pg_interfaces:
2448 for h in range(N_HOSTS):
2450 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2453 self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2457 # begin the replacement again, this time touch some
2458 # the neighbours on pg1 so they are not deleted
2460 self.vapi.ip_neighbor_replace_begin()
2462 # update from the API all neighbours on pg1
2463 for h in range(N_HOSTS):
2466 self.pg1.sw_if_index,
2467 self.pg1.remote_hosts[h].mac,
2468 self.pg1.remote_hosts[h].ip4,
2472 self.pg1.sw_if_index,
2473 self.pg1.remote_hosts[h].mac,
2474 self.pg1.remote_hosts[h].ip6,
2477 # update from the data-plane all neighbours on pg3
2478 self.pg3.configure_ipv4_neighbors()
2479 self.pg3.configure_ipv6_neighbors()
2481 # complete the replacement
2482 self.logger.info(self.vapi.cli("sh ip neighbors"))
2483 self.vapi.ip_neighbor_replace_end()
2485 for i in self.pg_interfaces:
2486 if i == self.pg1 or i == self.pg3:
2487 # neighbours on pg1 and pg3 are still present
2488 for h in range(N_HOSTS):
2490 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2493 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2496 # all other neighbours are toast
2497 for h in range(N_HOSTS):
2499 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2502 find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2506 class NeighborFlush(VppTestCase):
2507 """Neighbor Flush"""
2510 def setUpClass(cls):
2511 super(NeighborFlush, cls).setUpClass()
2514 def tearDownClass(cls):
2515 super(NeighborFlush, cls).tearDownClass()
2518 super(NeighborFlush, self).setUp()
2520 self.create_pg_interfaces(range(2))
2522 for i in self.pg_interfaces:
2530 super(NeighborFlush, self).tearDown()
2532 for i in self.pg_interfaces:
2537 def test_flush(self):
2538 """Neighbour Flush"""
2541 nf = e.vl_api_ip_neighbor_flags_t
2542 af = e.vl_api_address_family_t
2544 static = [False, True]
2545 self.pg0.generate_remote_hosts(N_HOSTS)
2546 self.pg1.generate_remote_hosts(N_HOSTS)
2549 # a few v4 and v6 dynamic neoghbors
2550 for n in range(N_HOSTS):
2553 self.pg0.sw_if_index,
2554 self.pg0.remote_hosts[n].mac,
2555 self.pg0.remote_hosts[n].ip4,
2560 self.pg1.sw_if_index,
2561 self.pg1.remote_hosts[n].mac,
2562 self.pg1.remote_hosts[n].ip6,
2566 # flush the interfaces individually
2567 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2569 # check we haven't flushed that which we shouldn't
2570 for n in range(N_HOSTS):
2574 self.pg1.sw_if_index,
2575 self.pg1.remote_hosts[n].ip6,
2580 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2582 for n in range(N_HOSTS):
2584 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2587 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2590 # add the nieghbours back
2591 for n in range(N_HOSTS):
2594 self.pg0.sw_if_index,
2595 self.pg0.remote_hosts[n].mac,
2596 self.pg0.remote_hosts[n].ip4,
2601 self.pg1.sw_if_index,
2602 self.pg1.remote_hosts[n].mac,
2603 self.pg1.remote_hosts[n].ip6,
2607 self.logger.info(self.vapi.cli("sh ip neighbor"))
2609 # flush both interfaces at the same time
2610 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2612 # check we haven't flushed that which we shouldn't
2613 for n in range(N_HOSTS):
2617 self.pg0.sw_if_index,
2618 self.pg0.remote_hosts[n].ip4,
2623 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2625 for n in range(N_HOSTS):
2627 find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2630 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2634 if __name__ == "__main__":
2635 unittest.main(testRunner=VppTestRunner)