4 from socket import AF_INET, AF_INET6, inet_pton
6 from framework import VppTestCase, VppTestRunner
7 from vpp_neighbor import VppNeighbor, find_nbr
8 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
9 VppIpTable, DpoProto, FibPathType
10 from vpp_papi import VppEnum
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, ARP, Dot1Q
15 from scapy.layers.inet import IP, UDP
16 from scapy.layers.inet6 import IPv6
17 from scapy.contrib.mpls import MPLS
18 from scapy.layers.inet6 import IPv6
23 # not exported by scapy, so redefined here
24 arp_opts = {"who-has": 1, "is-at": 2}
27 class ARPTestCase(VppTestCase):
32 super(ARPTestCase, cls).setUpClass()
35 def tearDownClass(cls):
36 super(ARPTestCase, cls).tearDownClass()
39 super(ARPTestCase, self).setUp()
41 # create 3 pg interfaces
42 self.create_pg_interfaces(range(4))
44 # pg0 configured with ip4 and 6 addresses used for input
45 # pg1 configured with ip4 and 6 addresses used for output
46 # pg2 is unnumbered to pg0
47 for i in self.pg_interfaces:
52 self.pg0.resolve_arp()
57 # pg3 in a different VRF
58 self.tbl = VppIpTable(self, 1)
59 self.tbl.add_vpp_config()
61 self.pg3.set_table_ip4(1)
65 self.pg0.unconfig_ip4()
66 self.pg0.unconfig_ip6()
68 self.pg1.unconfig_ip4()
69 self.pg1.unconfig_ip6()
71 self.pg3.unconfig_ip4()
72 self.pg3.set_table_ip4(0)
74 for i in self.pg_interfaces:
77 super(ARPTestCase, self).tearDown()
79 def verify_arp_req(self, rx, smac, sip, dip):
81 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
82 self.assertEqual(ether.src, smac)
85 self.assertEqual(arp.hwtype, 1)
86 self.assertEqual(arp.ptype, 0x800)
87 self.assertEqual(arp.hwlen, 6)
88 self.assertEqual(arp.plen, 4)
89 self.assertEqual(arp.op, arp_opts["who-has"])
90 self.assertEqual(arp.hwsrc, smac)
91 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
92 self.assertEqual(arp.psrc, sip)
93 self.assertEqual(arp.pdst, dip)
95 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
97 self.assertEqual(ether.dst, dmac)
98 self.assertEqual(ether.src, smac)
101 self.assertEqual(arp.hwtype, 1)
102 self.assertEqual(arp.ptype, 0x800)
103 self.assertEqual(arp.hwlen, 6)
104 self.assertEqual(arp.plen, 4)
105 self.assertEqual(arp.op, arp_opts["is-at"])
106 self.assertEqual(arp.hwsrc, smac)
107 self.assertEqual(arp.hwdst, dmac)
108 self.assertEqual(arp.psrc, sip)
109 self.assertEqual(arp.pdst, dip)
111 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
113 self.assertEqual(ether.dst, dmac)
114 self.assertEqual(ether.src, smac)
117 self.assertEqual(arp.hwtype, 1)
118 self.assertEqual(arp.ptype, 0x800)
119 self.assertEqual(arp.hwlen, 6)
120 self.assertEqual(arp.plen, 4)
121 self.assertEqual(arp.op, arp_opts["is-at"])
122 self.assertNotEqual(arp.hwsrc, smac)
123 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
124 "00:00:5E:00:01" in arp.hwsrc)
125 self.assertEqual(arp.hwdst, dmac)
126 self.assertEqual(arp.psrc, sip)
127 self.assertEqual(arp.pdst, dip)
129 def verify_ip(self, rx, smac, dmac, sip, dip):
131 self.assertEqual(ether.dst, dmac)
132 self.assertEqual(ether.src, smac)
135 self.assertEqual(ip.src, sip)
136 self.assertEqual(ip.dst, dip)
138 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
140 self.assertEqual(ether.dst, dmac)
141 self.assertEqual(ether.src, smac)
144 self.assertTrue(mpls.label, label)
147 self.assertEqual(ip.src, sip)
148 self.assertEqual(ip.dst, dip)
154 # Generate some hosts on the LAN
156 self.pg1.generate_remote_hosts(11)
159 # Send IP traffic to one of these unresolved hosts.
160 # expect the generation of an ARP request
162 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
163 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
164 UDP(sport=1234, dport=1234) /
167 self.pg0.add_stream(p)
168 self.pg_enable_capture(self.pg_interfaces)
171 rx = self.pg1.get_capture(1)
173 self.verify_arp_req(rx[0],
176 self.pg1._remote_hosts[1].ip4)
179 # And a dynamic ARP entry for host 1
181 dyn_arp = VppNeighbor(self,
182 self.pg1.sw_if_index,
183 self.pg1.remote_hosts[1].mac,
184 self.pg1.remote_hosts[1].ip4)
185 dyn_arp.add_vpp_config()
188 # now we expect IP traffic forwarded
190 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
191 IP(src=self.pg0.remote_ip4,
192 dst=self.pg1._remote_hosts[1].ip4) /
193 UDP(sport=1234, dport=1234) /
196 self.pg0.add_stream(dyn_p)
197 self.pg_enable_capture(self.pg_interfaces)
200 rx = self.pg1.get_capture(1)
202 self.verify_ip(rx[0],
204 self.pg1.remote_hosts[1].mac,
206 self.pg1._remote_hosts[1].ip4)
209 # And a Static ARP entry for host 2
211 static_arp = VppNeighbor(self,
212 self.pg1.sw_if_index,
213 self.pg1.remote_hosts[2].mac,
214 self.pg1.remote_hosts[2].ip4,
216 static_arp.add_vpp_config()
218 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
219 IP(src=self.pg0.remote_ip4,
220 dst=self.pg1._remote_hosts[2].ip4) /
221 UDP(sport=1234, dport=1234) /
224 self.pg0.add_stream(static_p)
225 self.pg_enable_capture(self.pg_interfaces)
228 rx = self.pg1.get_capture(1)
230 self.verify_ip(rx[0],
232 self.pg1.remote_hosts[2].mac,
234 self.pg1._remote_hosts[2].ip4)
237 # flap the link. dynamic ARPs get flush, statics don't
239 self.pg1.admin_down()
242 self.pg0.add_stream(static_p)
243 self.pg_enable_capture(self.pg_interfaces)
245 rx = self.pg1.get_capture(1)
247 self.verify_ip(rx[0],
249 self.pg1.remote_hosts[2].mac,
251 self.pg1._remote_hosts[2].ip4)
253 self.pg0.add_stream(dyn_p)
254 self.pg_enable_capture(self.pg_interfaces)
257 rx = self.pg1.get_capture(1)
258 self.verify_arp_req(rx[0],
261 self.pg1._remote_hosts[1].ip4)
264 # Send an ARP request from one of the so-far unlearned remote hosts
266 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
267 src=self.pg1._remote_hosts[3].mac) /
269 hwsrc=self.pg1._remote_hosts[3].mac,
270 pdst=self.pg1.local_ip4,
271 psrc=self.pg1._remote_hosts[3].ip4))
273 self.pg1.add_stream(p)
274 self.pg_enable_capture(self.pg_interfaces)
277 rx = self.pg1.get_capture(1)
278 self.verify_arp_resp(rx[0],
280 self.pg1._remote_hosts[3].mac,
282 self.pg1._remote_hosts[3].ip4)
285 # VPP should have learned the mapping for the remote host
287 self.assertTrue(find_nbr(self,
288 self.pg1.sw_if_index,
289 self.pg1._remote_hosts[3].ip4))
291 # Fire in an ARP request before the interface becomes IP enabled
293 self.pg2.generate_remote_hosts(4)
295 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
297 hwsrc=self.pg2.remote_mac,
298 pdst=self.pg1.local_ip4,
299 psrc=self.pg2.remote_hosts[3].ip4))
300 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
303 hwsrc=self.pg2.remote_mac,
304 pdst=self.pg1.local_ip4,
305 psrc=self.pg2.remote_hosts[3].ip4))
306 self.send_and_assert_no_replies(self.pg2, p,
307 "interface not IP enabled")
310 # Make pg2 un-numbered to pg1
312 self.pg2.set_unnumbered(self.pg1.sw_if_index)
315 # test the unnumbered dump both by all interfaces and just the enabled
318 unnum = self.vapi.ip_unnumbered_dump()
319 self.assertTrue(len(unnum))
320 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
321 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
322 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
323 self.assertTrue(len(unnum))
324 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
325 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
328 # We should respond to ARP requests for the unnumbered to address
329 # once an attached route to the source is known
331 self.send_and_assert_no_replies(
333 "ARP req for unnumbered address - no source")
335 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
336 [VppRoutePath("0.0.0.0",
337 self.pg2.sw_if_index)])
338 attached_host.add_vpp_config()
340 self.pg2.add_stream(p)
341 self.pg_enable_capture(self.pg_interfaces)
344 rx = self.pg2.get_capture(1)
345 self.verify_arp_resp(rx[0],
349 self.pg2.remote_hosts[3].ip4)
351 self.pg2.add_stream(pt)
352 self.pg_enable_capture(self.pg_interfaces)
355 rx = self.pg2.get_capture(1)
356 self.verify_arp_resp(rx[0],
360 self.pg2.remote_hosts[3].ip4)
363 # A neighbor entry that has no associated FIB-entry
365 arp_no_fib = VppNeighbor(self,
366 self.pg1.sw_if_index,
367 self.pg1.remote_hosts[4].mac,
368 self.pg1.remote_hosts[4].ip4,
370 arp_no_fib.add_vpp_config()
373 # check we have the neighbor, but no route
375 self.assertTrue(find_nbr(self,
376 self.pg1.sw_if_index,
377 self.pg1._remote_hosts[4].ip4))
378 self.assertFalse(find_route(self,
379 self.pg1._remote_hosts[4].ip4,
382 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
383 # from within pg1's subnet
385 arp_unnum = VppNeighbor(self,
386 self.pg2.sw_if_index,
387 self.pg1.remote_hosts[5].mac,
388 self.pg1.remote_hosts[5].ip4)
389 arp_unnum.add_vpp_config()
391 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
392 IP(src=self.pg0.remote_ip4,
393 dst=self.pg1._remote_hosts[5].ip4) /
394 UDP(sport=1234, dport=1234) /
397 self.pg0.add_stream(p)
398 self.pg_enable_capture(self.pg_interfaces)
401 rx = self.pg2.get_capture(1)
403 self.verify_ip(rx[0],
405 self.pg1.remote_hosts[5].mac,
407 self.pg1._remote_hosts[5].ip4)
410 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
411 # with the unnumbered interface's address as the source
413 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
415 hwsrc=self.pg2.remote_mac,
416 pdst=self.pg1.local_ip4,
417 psrc=self.pg1.remote_hosts[6].ip4))
419 self.pg2.add_stream(p)
420 self.pg_enable_capture(self.pg_interfaces)
423 rx = self.pg2.get_capture(1)
424 self.verify_arp_resp(rx[0],
428 self.pg1.remote_hosts[6].ip4)
431 # An attached host route out of pg2 for an undiscovered hosts generates
432 # an ARP request with the unnumbered address as the source
434 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
435 [VppRoutePath("0.0.0.0",
436 self.pg2.sw_if_index)])
437 att_unnum.add_vpp_config()
439 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
440 IP(src=self.pg0.remote_ip4,
441 dst=self.pg1._remote_hosts[7].ip4) /
442 UDP(sport=1234, dport=1234) /
445 self.pg0.add_stream(p)
446 self.pg_enable_capture(self.pg_interfaces)
449 rx = self.pg2.get_capture(1)
451 self.verify_arp_req(rx[0],
454 self.pg1._remote_hosts[7].ip4)
456 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
458 hwsrc=self.pg2.remote_mac,
459 pdst=self.pg1.local_ip4,
460 psrc=self.pg1.remote_hosts[7].ip4))
462 self.pg2.add_stream(p)
463 self.pg_enable_capture(self.pg_interfaces)
466 rx = self.pg2.get_capture(1)
467 self.verify_arp_resp(rx[0],
471 self.pg1.remote_hosts[7].ip4)
474 # An attached host route as yet unresolved out of pg2 for an
475 # undiscovered host, an ARP requests begets a response.
477 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
478 [VppRoutePath("0.0.0.0",
479 self.pg2.sw_if_index)])
480 att_unnum1.add_vpp_config()
482 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
484 hwsrc=self.pg2.remote_mac,
485 pdst=self.pg1.local_ip4,
486 psrc=self.pg1.remote_hosts[8].ip4))
488 self.pg2.add_stream(p)
489 self.pg_enable_capture(self.pg_interfaces)
492 rx = self.pg2.get_capture(1)
493 self.verify_arp_resp(rx[0],
497 self.pg1.remote_hosts[8].ip4)
500 # Send an ARP request from one of the so-far unlearned remote hosts
503 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
504 src=self.pg1._remote_hosts[9].mac) /
507 hwsrc=self.pg1._remote_hosts[9].mac,
508 pdst=self.pg1.local_ip4,
509 psrc=self.pg1._remote_hosts[9].ip4))
511 self.pg1.add_stream(p)
512 self.pg_enable_capture(self.pg_interfaces)
515 rx = self.pg1.get_capture(1)
516 self.verify_arp_resp(rx[0],
518 self.pg1._remote_hosts[9].mac,
520 self.pg1._remote_hosts[9].ip4)
523 # Add a hierarchy of routes for a host in the sub-net.
524 # Should still get an ARP resp since the cover is attached
526 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
528 hwsrc=self.pg1.remote_mac,
529 pdst=self.pg1.local_ip4,
530 psrc=self.pg1.remote_hosts[10].ip4))
532 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
533 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
534 self.pg1.sw_if_index)])
537 self.pg1.add_stream(p)
538 self.pg_enable_capture(self.pg_interfaces)
540 rx = self.pg1.get_capture(1)
541 self.verify_arp_resp(rx[0],
545 self.pg1.remote_hosts[10].ip4)
547 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
548 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
549 self.pg1.sw_if_index)])
552 self.pg1.add_stream(p)
553 self.pg_enable_capture(self.pg_interfaces)
555 rx = self.pg1.get_capture(1)
556 self.verify_arp_resp(rx[0],
560 self.pg1.remote_hosts[10].ip4)
563 # add an ARP entry that's not on the sub-net and so whose
564 # adj-fib fails the refinement check. then send an ARP request
567 a1 = VppNeighbor(self,
568 self.pg0.sw_if_index,
573 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
575 hwsrc=self.pg0.remote_mac,
576 psrc="100.100.100.50",
577 pdst=self.pg0.remote_ip4))
578 self.send_and_assert_no_replies(self.pg0, p,
579 "ARP req for from failed adj-fib")
583 # 1 - don't respond to ARP request for address not within the
584 # interface's sub-net
585 # 1b - nor within the unnumbered subnet
586 # 1c - nor within the subnet of a different interface
588 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
590 hwsrc=self.pg0.remote_mac,
592 psrc=self.pg0.remote_ip4))
593 self.send_and_assert_no_replies(self.pg0, p,
594 "ARP req for non-local destination")
595 self.assertFalse(find_nbr(self,
596 self.pg0.sw_if_index,
599 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
601 hwsrc=self.pg2.remote_mac,
603 psrc=self.pg1.remote_hosts[7].ip4))
604 self.send_and_assert_no_replies(
606 "ARP req for non-local destination - unnum")
608 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
610 hwsrc=self.pg0.remote_mac,
611 pdst=self.pg1.local_ip4,
612 psrc=self.pg1.remote_ip4))
613 self.send_and_assert_no_replies(self.pg0, p,
614 "ARP req diff sub-net")
615 self.assertFalse(find_nbr(self,
616 self.pg0.sw_if_index,
617 self.pg1.remote_ip4))
620 # 2 - don't respond to ARP request from an address not within the
621 # interface's sub-net
622 # 2b - to a proxied address
623 # 2c - not within a different interface's sub-net
624 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
626 hwsrc=self.pg0.remote_mac,
628 pdst=self.pg0.local_ip4))
629 self.send_and_assert_no_replies(self.pg0, p,
630 "ARP req for non-local source")
631 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
633 hwsrc=self.pg2.remote_mac,
635 pdst=self.pg0.local_ip4))
636 self.send_and_assert_no_replies(
638 "ARP req for non-local source - unnum")
639 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
641 hwsrc=self.pg0.remote_mac,
642 psrc=self.pg1.remote_ip4,
643 pdst=self.pg0.local_ip4))
644 self.send_and_assert_no_replies(self.pg0, p,
645 "ARP req for non-local source 2c")
648 # 3 - don't respond to ARP request from an address that belongs to
651 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
653 hwsrc=self.pg0.remote_mac,
654 psrc=self.pg0.local_ip4,
655 pdst=self.pg0.local_ip4))
656 self.send_and_assert_no_replies(self.pg0, p,
657 "ARP req for non-local source")
660 # 4 - don't respond to ARP requests that has mac source different
661 # from ARP request HW source
663 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
665 hwsrc="00:00:00:DE:AD:BE",
666 psrc=self.pg0.remote_ip4,
667 pdst=self.pg0.local_ip4))
668 self.send_and_assert_no_replies(self.pg0, p,
669 "ARP req for non-local source")
672 # 5 - don't respond to ARP requests for address within the
673 # interface's sub-net but not the interface's address
675 self.pg0.generate_remote_hosts(2)
676 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
678 hwsrc=self.pg0.remote_mac,
679 psrc=self.pg0.remote_hosts[0].ip4,
680 pdst=self.pg0.remote_hosts[1].ip4))
681 self.send_and_assert_no_replies(self.pg0, p,
682 "ARP req for non-local destination")
687 dyn_arp.remove_vpp_config()
688 static_arp.remove_vpp_config()
689 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
691 # need this to flush the adj-fibs
692 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
693 self.pg2.admin_down()
694 self.pg1.admin_down()
696 def test_proxy_mirror_arp(self):
697 """ Interface Mirror Proxy ARP """
700 # When VPP has an interface whose address is also applied to a TAP
701 # interface on the host, then VPP's TAP interface will be unnumbered
702 # to the 'real' interface and do proxy ARP from the host.
703 # the curious aspect of this setup is that ARP requests from the host
704 # will come from the VPP's own address.
706 self.pg0.generate_remote_hosts(2)
708 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
709 dst="ff:ff:ff:ff:ff:ff") /
711 hwsrc=self.pg2.remote_mac,
712 pdst=self.pg0.remote_hosts[1].ip4,
713 psrc=self.pg0.local_ip4))
716 # Configure Proxy ARP for the subnet on PG0addresses on pg0
718 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
719 self.pg0._local_ip4_bcast)
721 # Make pg2 un-numbered to pg0
723 self.pg2.set_unnumbered(self.pg0.sw_if_index)
726 # Enable pg2 for proxy ARP
728 self.pg2.set_proxy_arp()
731 # Send the ARP request with an originating address that
732 # is VPP's own address
734 self.pg2.add_stream(arp_req_from_me)
735 self.pg_enable_capture(self.pg_interfaces)
738 rx = self.pg2.get_capture(1)
739 self.verify_arp_resp(rx[0],
742 self.pg0.remote_hosts[1].ip4,
746 # validate we have not learned an ARP entry as a result of this
748 self.assertFalse(find_nbr(self,
749 self.pg2.sw_if_index,
755 self.pg2.set_proxy_arp(0)
756 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
757 self.pg0._local_ip4_bcast,
760 def test_proxy_arp(self):
763 self.pg1.generate_remote_hosts(2)
766 # Proxy ARP request packets for each interface
768 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
769 dst="ff:ff:ff:ff:ff:ff") /
771 hwsrc=self.pg0.remote_mac,
773 psrc=self.pg0.remote_ip4))
774 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
775 dst="ff:ff:ff:ff:ff:ff") /
778 hwsrc=self.pg0.remote_mac,
780 psrc=self.pg0.remote_ip4))
781 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
782 dst="ff:ff:ff:ff:ff:ff") /
784 hwsrc=self.pg1.remote_mac,
786 psrc=self.pg1.remote_ip4))
787 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
788 dst="ff:ff:ff:ff:ff:ff") /
790 hwsrc=self.pg2.remote_mac,
792 psrc=self.pg1.remote_hosts[1].ip4))
793 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
794 dst="ff:ff:ff:ff:ff:ff") /
796 hwsrc=self.pg3.remote_mac,
798 psrc=self.pg3.remote_ip4))
801 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
803 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
804 inet_pton(AF_INET, "10.10.10.124"))
807 # No responses are sent when the interfaces are not enabled for proxy
810 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
811 "ARP req from unconfigured interface")
812 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
813 "ARP req from unconfigured interface")
816 # Make pg2 un-numbered to pg1
819 self.pg2.set_unnumbered(self.pg1.sw_if_index)
821 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
822 "ARP req from unnumbered interface")
825 # Enable each interface to reply to proxy ARPs
827 for i in self.pg_interfaces:
831 # Now each of the interfaces should reply to a request to a proxied
834 self.pg0.add_stream(arp_req_pg0)
835 self.pg_enable_capture(self.pg_interfaces)
838 rx = self.pg0.get_capture(1)
839 self.verify_arp_resp(rx[0],
845 self.pg0.add_stream(arp_req_pg0_tagged)
846 self.pg_enable_capture(self.pg_interfaces)
849 rx = self.pg0.get_capture(1)
850 self.verify_arp_resp(rx[0],
856 self.pg1.add_stream(arp_req_pg1)
857 self.pg_enable_capture(self.pg_interfaces)
860 rx = self.pg1.get_capture(1)
861 self.verify_arp_resp(rx[0],
867 self.pg2.add_stream(arp_req_pg2)
868 self.pg_enable_capture(self.pg_interfaces)
871 rx = self.pg2.get_capture(1)
872 self.verify_arp_resp(rx[0],
876 self.pg1.remote_hosts[1].ip4)
879 # A request for an address out of the configured range
881 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
882 dst="ff:ff:ff:ff:ff:ff") /
884 hwsrc=self.pg1.remote_mac,
886 psrc=self.pg1.remote_ip4))
887 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
888 "ARP req out of range HI")
889 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
890 dst="ff:ff:ff:ff:ff:ff") /
892 hwsrc=self.pg1.remote_mac,
894 psrc=self.pg1.remote_ip4))
895 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
896 "ARP req out of range Low")
899 # Request for an address in the proxy range but from an interface
902 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
903 "ARP req from different VRF")
906 # Disable Each interface for proxy ARP
907 # - expect none to respond
909 for i in self.pg_interfaces:
912 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
913 "ARP req from disable")
914 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
915 "ARP req from disable")
916 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
917 "ARP req from disable")
920 # clean up on interface 2
922 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
928 # Interface 2 does not yet have ip4 config
930 self.pg2.config_ip4()
931 self.pg2.generate_remote_hosts(2)
934 # Add a route with out going label via an ARP unresolved next-hop
936 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
937 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
938 self.pg2.sw_if_index,
940 ip_10_0_0_1.add_vpp_config()
943 # packets should generate an ARP request
945 p = (Ether(src=self.pg0.remote_mac,
946 dst=self.pg0.local_mac) /
947 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
948 UDP(sport=1234, dport=1234) /
951 self.pg0.add_stream(p)
952 self.pg_enable_capture(self.pg_interfaces)
955 rx = self.pg2.get_capture(1)
956 self.verify_arp_req(rx[0],
959 self.pg2._remote_hosts[1].ip4)
962 # now resolve the neighbours
964 self.pg2.configure_ipv4_neighbors()
967 # Now packet should be properly MPLS encapped.
968 # This verifies that MPLS link-type adjacencies are completed
969 # when the ARP entry resolves
971 self.pg0.add_stream(p)
972 self.pg_enable_capture(self.pg_interfaces)
975 rx = self.pg2.get_capture(1)
976 self.verify_ip_o_mpls(rx[0],
978 self.pg2.remote_hosts[1].mac,
982 self.pg2.unconfig_ip4()
984 def test_arp_vrrp(self):
985 """ ARP reply with VRRP virtual src hw addr """
988 # IP packet destined for pg1 remote host arrives on pg0 resulting
989 # in an ARP request for the address of the remote host on pg1
991 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
992 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
993 UDP(sport=1234, dport=1234) /
996 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
998 self.verify_arp_req(rx1[0],
1001 self.pg1.remote_ip4)
1004 # ARP reply for address of pg1 remote host arrives on pg1 with
1005 # the hw src addr set to a value in the VRRP IPv4 range of
1008 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1009 ARP(op="is-at", hwdst=self.pg1.local_mac,
1010 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1011 psrc=self.pg1.remote_ip4))
1013 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1016 # IP packet destined for pg1 remote host arrives on pg0 again.
1017 # VPP should have an ARP entry for that address now and the packet
1018 # should be sent out pg1.
1020 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1022 self.verify_ip(rx1[0],
1024 "00:00:5e:00:01:09",
1025 self.pg0.remote_ip4,
1026 self.pg1.remote_ip4)
1028 self.pg1.admin_down()
1031 def test_arp_duplicates(self):
1032 """ ARP Duplicates"""
1035 # Generate some hosts on the LAN
1037 self.pg1.generate_remote_hosts(3)
1040 # Add host 1 on pg1 and pg2
1042 arp_pg1 = VppNeighbor(self,
1043 self.pg1.sw_if_index,
1044 self.pg1.remote_hosts[1].mac,
1045 self.pg1.remote_hosts[1].ip4)
1046 arp_pg1.add_vpp_config()
1047 arp_pg2 = VppNeighbor(self,
1048 self.pg2.sw_if_index,
1049 self.pg2.remote_mac,
1050 self.pg1.remote_hosts[1].ip4)
1051 arp_pg2.add_vpp_config()
1054 # IP packet destined for pg1 remote host arrives on pg1 again.
1056 p = (Ether(dst=self.pg0.local_mac,
1057 src=self.pg0.remote_mac) /
1058 IP(src=self.pg0.remote_ip4,
1059 dst=self.pg1.remote_hosts[1].ip4) /
1060 UDP(sport=1234, dport=1234) /
1063 self.pg0.add_stream(p)
1064 self.pg_enable_capture(self.pg_interfaces)
1067 rx1 = self.pg1.get_capture(1)
1069 self.verify_ip(rx1[0],
1071 self.pg1.remote_hosts[1].mac,
1072 self.pg0.remote_ip4,
1073 self.pg1.remote_hosts[1].ip4)
1076 # remove the duplicate on pg1
1077 # packet stream should generate ARPs out of pg1
1079 arp_pg1.remove_vpp_config()
1081 self.pg0.add_stream(p)
1082 self.pg_enable_capture(self.pg_interfaces)
1085 rx1 = self.pg1.get_capture(1)
1087 self.verify_arp_req(rx1[0],
1090 self.pg1.remote_hosts[1].ip4)
1095 arp_pg1.add_vpp_config()
1097 self.pg0.add_stream(p)
1098 self.pg_enable_capture(self.pg_interfaces)
1101 rx1 = self.pg1.get_capture(1)
1103 self.verify_ip(rx1[0],
1105 self.pg1.remote_hosts[1].mac,
1106 self.pg0.remote_ip4,
1107 self.pg1.remote_hosts[1].ip4)
1109 def test_arp_static(self):
1111 self.pg2.generate_remote_hosts(3)
1114 # Add a static ARP entry
1116 static_arp = VppNeighbor(self,
1117 self.pg2.sw_if_index,
1118 self.pg2.remote_hosts[1].mac,
1119 self.pg2.remote_hosts[1].ip4,
1121 static_arp.add_vpp_config()
1124 # Add the connected prefix to the interface
1126 self.pg2.config_ip4()
1129 # We should now find the adj-fib
1131 self.assertTrue(find_nbr(self,
1132 self.pg2.sw_if_index,
1133 self.pg2.remote_hosts[1].ip4,
1135 self.assertTrue(find_route(self,
1136 self.pg2.remote_hosts[1].ip4,
1140 # remove the connected
1142 self.pg2.unconfig_ip4()
1145 # put the interface into table 1
1147 self.pg2.set_table_ip4(1)
1150 # configure the same connected and expect to find the
1151 # adj fib in the new table
1153 self.pg2.config_ip4()
1154 self.assertTrue(find_route(self,
1155 self.pg2.remote_hosts[1].ip4,
1162 self.pg2.unconfig_ip4()
1163 self.pg2.set_table_ip4(0)
1165 def test_arp_incomplete(self):
1166 """ ARP Incomplete"""
1167 self.pg1.generate_remote_hosts(3)
1169 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1170 IP(src=self.pg0.remote_ip4,
1171 dst=self.pg1.remote_hosts[1].ip4) /
1172 UDP(sport=1234, dport=1234) /
1174 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1175 IP(src=self.pg0.remote_ip4,
1176 dst=self.pg1.remote_hosts[2].ip4) /
1177 UDP(sport=1234, dport=1234) /
1181 # a packet to an unresolved destination generates an ARP request
1183 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1184 self.verify_arp_req(rx[0],
1187 self.pg1._remote_hosts[1].ip4)
1190 # add a neighbour for remote host 1
1192 static_arp = VppNeighbor(self,
1193 self.pg1.sw_if_index,
1194 self.pg1.remote_hosts[1].mac,
1195 self.pg1.remote_hosts[1].ip4,
1197 static_arp.add_vpp_config()
1200 # change the interface's MAC
1202 mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1203 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1204 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1205 mac_string = ''.join(mac)
1207 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1211 # now ARP requests come from the new source mac
1213 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1214 self.verify_arp_req(rx[0],
1215 "00:00:00:33:33:33",
1217 self.pg1._remote_hosts[2].ip4)
1220 # packets to the resolved host also have the new source mac
1222 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1223 self.verify_ip(rx[0],
1224 "00:00:00:33:33:33",
1225 self.pg1.remote_hosts[1].mac,
1226 self.pg0.remote_ip4,
1227 self.pg1.remote_hosts[1].ip4)
1230 # set the mac address on the interface that does not have a
1231 # configured subnet and thus no glean
1233 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1236 def test_garp(self):
1240 # Generate some hosts on the LAN
1242 self.pg1.generate_remote_hosts(4)
1247 arp = VppNeighbor(self,
1248 self.pg1.sw_if_index,
1249 self.pg1.remote_hosts[1].mac,
1250 self.pg1.remote_hosts[1].ip4)
1251 arp.add_vpp_config()
1253 self.assertTrue(find_nbr(self,
1254 self.pg1.sw_if_index,
1255 self.pg1.remote_hosts[1].ip4,
1256 mac=self.pg1.remote_hosts[1].mac))
1259 # Send a GARP (request) to swap the host 1's address to that of host 2
1261 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1262 src=self.pg1.remote_hosts[2].mac) /
1264 hwdst=self.pg1.local_mac,
1265 hwsrc=self.pg1.remote_hosts[2].mac,
1266 pdst=self.pg1.remote_hosts[1].ip4,
1267 psrc=self.pg1.remote_hosts[1].ip4))
1269 self.pg1.add_stream(p1)
1270 self.pg_enable_capture(self.pg_interfaces)
1273 self.assertTrue(find_nbr(self,
1274 self.pg1.sw_if_index,
1275 self.pg1.remote_hosts[1].ip4,
1276 mac=self.pg1.remote_hosts[2].mac))
1279 # Send a GARP (reply) to swap the host 1's address to that of host 3
1281 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1282 src=self.pg1.remote_hosts[3].mac) /
1284 hwdst=self.pg1.local_mac,
1285 hwsrc=self.pg1.remote_hosts[3].mac,
1286 pdst=self.pg1.remote_hosts[1].ip4,
1287 psrc=self.pg1.remote_hosts[1].ip4))
1289 self.pg1.add_stream(p1)
1290 self.pg_enable_capture(self.pg_interfaces)
1293 self.assertTrue(find_nbr(self,
1294 self.pg1.sw_if_index,
1295 self.pg1.remote_hosts[1].ip4,
1296 mac=self.pg1.remote_hosts[3].mac))
1299 # GARPs (request nor replies) for host we don't know yet
1300 # don't result in new neighbour entries
1302 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1303 src=self.pg1.remote_hosts[3].mac) /
1305 hwdst=self.pg1.local_mac,
1306 hwsrc=self.pg1.remote_hosts[3].mac,
1307 pdst=self.pg1.remote_hosts[2].ip4,
1308 psrc=self.pg1.remote_hosts[2].ip4))
1310 self.pg1.add_stream(p1)
1311 self.pg_enable_capture(self.pg_interfaces)
1314 self.assertFalse(find_nbr(self,
1315 self.pg1.sw_if_index,
1316 self.pg1.remote_hosts[2].ip4))
1318 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1319 src=self.pg1.remote_hosts[3].mac) /
1321 hwdst=self.pg1.local_mac,
1322 hwsrc=self.pg1.remote_hosts[3].mac,
1323 pdst=self.pg1.remote_hosts[2].ip4,
1324 psrc=self.pg1.remote_hosts[2].ip4))
1326 self.pg1.add_stream(p1)
1327 self.pg_enable_capture(self.pg_interfaces)
1330 self.assertFalse(find_nbr(self,
1331 self.pg1.sw_if_index,
1332 self.pg1.remote_hosts[2].ip4))
1334 def test_arp_incomplete(self):
1335 """ Incomplete Entries """
1338 # ensure that we throttle the ARP and ND requests
1340 self.pg0.generate_remote_hosts(2)
1345 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1346 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1347 self.pg0.sw_if_index)])
1348 ip_10_0_0_1.add_vpp_config()
1350 p1 = (Ether(dst=self.pg1.local_mac,
1351 src=self.pg1.remote_mac) /
1352 IP(src=self.pg1.remote_ip4,
1354 UDP(sport=1234, dport=1234) /
1357 self.pg1.add_stream(p1 * 257)
1358 self.pg_enable_capture(self.pg_interfaces)
1360 rx = self.pg0._get_capture(1)
1363 # how many we get is going to be dependent on the time for packet
1364 # processing but it should be small
1366 self.assertLess(len(rx), 64)
1371 ip_10_1 = VppIpRoute(self, "10::1", 128,
1372 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1373 self.pg0.sw_if_index,
1374 proto=DpoProto.DPO_PROTO_IP6)])
1375 ip_10_1.add_vpp_config()
1377 p1 = (Ether(dst=self.pg1.local_mac,
1378 src=self.pg1.remote_mac) /
1379 IPv6(src=self.pg1.remote_ip6,
1381 UDP(sport=1234, dport=1234) /
1384 self.pg1.add_stream(p1 * 257)
1385 self.pg_enable_capture(self.pg_interfaces)
1387 rx = self.pg0._get_capture(1)
1390 # how many we get is going to be dependent on the time for packet
1391 # processing but it should be small
1393 self.assertLess(len(rx), 64)
1395 def test_arp_forus(self):
1396 """ ARP for for-us """
1399 # Test that VPP responds with ARP requests to addresses that
1400 # are connected and local routes.
1401 # Use one of the 'remote' addresses in the subnet as a local address
1402 # The intention of this route is that it then acts like a secondary
1403 # address added to an interface
1405 self.pg0.generate_remote_hosts(2)
1408 self, self.pg0.remote_hosts[1].ip4, 32,
1409 [VppRoutePath("0.0.0.0",
1410 self.pg0.sw_if_index,
1411 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1412 forus.add_vpp_config()
1414 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1415 src=self.pg0.remote_mac) /
1417 hwdst=self.pg0.local_mac,
1418 hwsrc=self.pg0.remote_mac,
1419 pdst=self.pg0.remote_hosts[1].ip4,
1420 psrc=self.pg0.remote_ip4))
1422 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1424 self.verify_arp_resp(rx[0],
1426 self.pg0.remote_mac,
1427 self.pg0.remote_hosts[1].ip4,
1428 self.pg0.remote_ip4)
1431 class NeighborStatsTestCase(VppTestCase):
1432 """ ARP/ND Counters """
1435 def setUpClass(cls):
1436 super(NeighborStatsTestCase, cls).setUpClass()
1439 def tearDownClass(cls):
1440 super(NeighborStatsTestCase, cls).tearDownClass()
1443 super(NeighborStatsTestCase, self).setUp()
1445 self.create_pg_interfaces(range(2))
1447 # pg0 configured with ip4 and 6 addresses used for input
1448 # pg1 configured with ip4 and 6 addresses used for output
1449 # pg2 is unnumbered to pg0
1450 for i in self.pg_interfaces:
1458 super(NeighborStatsTestCase, self).tearDown()
1460 for i in self.pg_interfaces:
1465 def test_arp_stats(self):
1466 """ ARP Counters """
1468 self.vapi.cli("adj counters enable")
1469 self.pg1.generate_remote_hosts(2)
1471 arp1 = VppNeighbor(self,
1472 self.pg1.sw_if_index,
1473 self.pg1.remote_hosts[0].mac,
1474 self.pg1.remote_hosts[0].ip4)
1475 arp1.add_vpp_config()
1476 arp2 = VppNeighbor(self,
1477 self.pg1.sw_if_index,
1478 self.pg1.remote_hosts[1].mac,
1479 self.pg1.remote_hosts[1].ip4)
1480 arp2.add_vpp_config()
1482 p1 = (Ether(dst=self.pg0.local_mac,
1483 src=self.pg0.remote_mac) /
1484 IP(src=self.pg0.remote_ip4,
1485 dst=self.pg1.remote_hosts[0].ip4) /
1486 UDP(sport=1234, dport=1234) /
1488 p2 = (Ether(dst=self.pg0.local_mac,
1489 src=self.pg0.remote_mac) /
1490 IP(src=self.pg0.remote_ip4,
1491 dst=self.pg1.remote_hosts[1].ip4) /
1492 UDP(sport=1234, dport=1234) /
1495 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1496 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1498 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1499 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1501 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1502 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1504 def test_nd_stats(self):
1507 self.vapi.cli("adj counters enable")
1508 self.pg0.generate_remote_hosts(3)
1510 nd1 = VppNeighbor(self,
1511 self.pg0.sw_if_index,
1512 self.pg0.remote_hosts[1].mac,
1513 self.pg0.remote_hosts[1].ip6)
1514 nd1.add_vpp_config()
1515 nd2 = VppNeighbor(self,
1516 self.pg0.sw_if_index,
1517 self.pg0.remote_hosts[2].mac,
1518 self.pg0.remote_hosts[2].ip6)
1519 nd2.add_vpp_config()
1521 p1 = (Ether(dst=self.pg1.local_mac,
1522 src=self.pg1.remote_mac) /
1523 IPv6(src=self.pg1.remote_ip6,
1524 dst=self.pg0.remote_hosts[1].ip6) /
1525 UDP(sport=1234, dport=1234) /
1527 p2 = (Ether(dst=self.pg1.local_mac,
1528 src=self.pg1.remote_mac) /
1529 IPv6(src=self.pg1.remote_ip6,
1530 dst=self.pg0.remote_hosts[2].ip6) /
1531 UDP(sport=1234, dport=1234) /
1534 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1535 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1537 self.assertEqual(16, nd1.get_stats()['packets'])
1538 self.assertEqual(16, nd2.get_stats()['packets'])
1540 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1541 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1544 if __name__ == '__main__':
1545 unittest.main(testRunner=VppTestRunner)