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)
314 unnum = self.vapi.ip_unnumbered_dump()
315 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
316 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
319 # We should respond to ARP requests for the unnumbered to address
320 # once an attached route to the source is known
322 self.send_and_assert_no_replies(
324 "ARP req for unnumbered address - no source")
326 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
327 [VppRoutePath("0.0.0.0",
328 self.pg2.sw_if_index)])
329 attached_host.add_vpp_config()
331 self.pg2.add_stream(p)
332 self.pg_enable_capture(self.pg_interfaces)
335 rx = self.pg2.get_capture(1)
336 self.verify_arp_resp(rx[0],
340 self.pg2.remote_hosts[3].ip4)
342 self.pg2.add_stream(pt)
343 self.pg_enable_capture(self.pg_interfaces)
346 rx = self.pg2.get_capture(1)
347 self.verify_arp_resp(rx[0],
351 self.pg2.remote_hosts[3].ip4)
354 # A neighbor entry that has no associated FIB-entry
356 arp_no_fib = VppNeighbor(self,
357 self.pg1.sw_if_index,
358 self.pg1.remote_hosts[4].mac,
359 self.pg1.remote_hosts[4].ip4,
361 arp_no_fib.add_vpp_config()
364 # check we have the neighbor, but no route
366 self.assertTrue(find_nbr(self,
367 self.pg1.sw_if_index,
368 self.pg1._remote_hosts[4].ip4))
369 self.assertFalse(find_route(self,
370 self.pg1._remote_hosts[4].ip4,
373 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
374 # from within pg1's subnet
376 arp_unnum = VppNeighbor(self,
377 self.pg2.sw_if_index,
378 self.pg1.remote_hosts[5].mac,
379 self.pg1.remote_hosts[5].ip4)
380 arp_unnum.add_vpp_config()
382 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
383 IP(src=self.pg0.remote_ip4,
384 dst=self.pg1._remote_hosts[5].ip4) /
385 UDP(sport=1234, dport=1234) /
388 self.pg0.add_stream(p)
389 self.pg_enable_capture(self.pg_interfaces)
392 rx = self.pg2.get_capture(1)
394 self.verify_ip(rx[0],
396 self.pg1.remote_hosts[5].mac,
398 self.pg1._remote_hosts[5].ip4)
401 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
402 # with the unnumbered interface's address as the source
404 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
406 hwsrc=self.pg2.remote_mac,
407 pdst=self.pg1.local_ip4,
408 psrc=self.pg1.remote_hosts[6].ip4))
410 self.pg2.add_stream(p)
411 self.pg_enable_capture(self.pg_interfaces)
414 rx = self.pg2.get_capture(1)
415 self.verify_arp_resp(rx[0],
419 self.pg1.remote_hosts[6].ip4)
422 # An attached host route out of pg2 for an undiscovered hosts generates
423 # an ARP request with the unnumbered address as the source
425 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
426 [VppRoutePath("0.0.0.0",
427 self.pg2.sw_if_index)])
428 att_unnum.add_vpp_config()
430 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
431 IP(src=self.pg0.remote_ip4,
432 dst=self.pg1._remote_hosts[7].ip4) /
433 UDP(sport=1234, dport=1234) /
436 self.pg0.add_stream(p)
437 self.pg_enable_capture(self.pg_interfaces)
440 rx = self.pg2.get_capture(1)
442 self.verify_arp_req(rx[0],
445 self.pg1._remote_hosts[7].ip4)
447 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
449 hwsrc=self.pg2.remote_mac,
450 pdst=self.pg1.local_ip4,
451 psrc=self.pg1.remote_hosts[7].ip4))
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(rx[0],
462 self.pg1.remote_hosts[7].ip4)
465 # An attached host route as yet unresolved out of pg2 for an
466 # undiscovered host, an ARP requests begets a response.
468 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
469 [VppRoutePath("0.0.0.0",
470 self.pg2.sw_if_index)])
471 att_unnum1.add_vpp_config()
473 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
475 hwsrc=self.pg2.remote_mac,
476 pdst=self.pg1.local_ip4,
477 psrc=self.pg1.remote_hosts[8].ip4))
479 self.pg2.add_stream(p)
480 self.pg_enable_capture(self.pg_interfaces)
483 rx = self.pg2.get_capture(1)
484 self.verify_arp_resp(rx[0],
488 self.pg1.remote_hosts[8].ip4)
491 # Send an ARP request from one of the so-far unlearned remote hosts
494 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
495 src=self.pg1._remote_hosts[9].mac) /
498 hwsrc=self.pg1._remote_hosts[9].mac,
499 pdst=self.pg1.local_ip4,
500 psrc=self.pg1._remote_hosts[9].ip4))
502 self.pg1.add_stream(p)
503 self.pg_enable_capture(self.pg_interfaces)
506 rx = self.pg1.get_capture(1)
507 self.verify_arp_resp(rx[0],
509 self.pg1._remote_hosts[9].mac,
511 self.pg1._remote_hosts[9].ip4)
514 # Add a hierarchy of routes for a host in the sub-net.
515 # Should still get an ARP resp since the cover is attached
517 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
519 hwsrc=self.pg1.remote_mac,
520 pdst=self.pg1.local_ip4,
521 psrc=self.pg1.remote_hosts[10].ip4))
523 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
524 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
525 self.pg1.sw_if_index)])
528 self.pg1.add_stream(p)
529 self.pg_enable_capture(self.pg_interfaces)
531 rx = self.pg1.get_capture(1)
532 self.verify_arp_resp(rx[0],
536 self.pg1.remote_hosts[10].ip4)
538 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
539 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
540 self.pg1.sw_if_index)])
543 self.pg1.add_stream(p)
544 self.pg_enable_capture(self.pg_interfaces)
546 rx = self.pg1.get_capture(1)
547 self.verify_arp_resp(rx[0],
551 self.pg1.remote_hosts[10].ip4)
554 # add an ARP entry that's not on the sub-net and so whose
555 # adj-fib fails the refinement check. then send an ARP request
558 a1 = VppNeighbor(self,
559 self.pg0.sw_if_index,
564 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
566 hwsrc=self.pg0.remote_mac,
567 psrc="100.100.100.50",
568 pdst=self.pg0.remote_ip4))
569 self.send_and_assert_no_replies(self.pg0, p,
570 "ARP req for from failed adj-fib")
574 # 1 - don't respond to ARP request for address not within the
575 # interface's sub-net
576 # 1b - nor within the unnumbered subnet
577 # 1c - nor within the subnet of a different interface
579 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
581 hwsrc=self.pg0.remote_mac,
583 psrc=self.pg0.remote_ip4))
584 self.send_and_assert_no_replies(self.pg0, p,
585 "ARP req for non-local destination")
586 self.assertFalse(find_nbr(self,
587 self.pg0.sw_if_index,
590 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
592 hwsrc=self.pg2.remote_mac,
594 psrc=self.pg1.remote_hosts[7].ip4))
595 self.send_and_assert_no_replies(
597 "ARP req for non-local destination - unnum")
599 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
601 hwsrc=self.pg0.remote_mac,
602 pdst=self.pg1.local_ip4,
603 psrc=self.pg1.remote_ip4))
604 self.send_and_assert_no_replies(self.pg0, p,
605 "ARP req diff sub-net")
606 self.assertFalse(find_nbr(self,
607 self.pg0.sw_if_index,
608 self.pg1.remote_ip4))
611 # 2 - don't respond to ARP request from an address not within the
612 # interface's sub-net
613 # 2b - to a proxied address
614 # 2c - not within a different interface's sub-net
615 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
617 hwsrc=self.pg0.remote_mac,
619 pdst=self.pg0.local_ip4))
620 self.send_and_assert_no_replies(self.pg0, p,
621 "ARP req for non-local source")
622 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
624 hwsrc=self.pg2.remote_mac,
626 pdst=self.pg0.local_ip4))
627 self.send_and_assert_no_replies(
629 "ARP req for non-local source - unnum")
630 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
632 hwsrc=self.pg0.remote_mac,
633 psrc=self.pg1.remote_ip4,
634 pdst=self.pg0.local_ip4))
635 self.send_and_assert_no_replies(self.pg0, p,
636 "ARP req for non-local source 2c")
639 # 3 - don't respond to ARP request from an address that belongs to
642 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
644 hwsrc=self.pg0.remote_mac,
645 psrc=self.pg0.local_ip4,
646 pdst=self.pg0.local_ip4))
647 self.send_and_assert_no_replies(self.pg0, p,
648 "ARP req for non-local source")
651 # 4 - don't respond to ARP requests that has mac source different
652 # from ARP request HW source
654 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
656 hwsrc="00:00:00:DE:AD:BE",
657 psrc=self.pg0.remote_ip4,
658 pdst=self.pg0.local_ip4))
659 self.send_and_assert_no_replies(self.pg0, p,
660 "ARP req for non-local source")
663 # 5 - don't respond to ARP requests for address within the
664 # interface's sub-net but not the interface's address
666 self.pg0.generate_remote_hosts(2)
667 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
669 hwsrc=self.pg0.remote_mac,
670 psrc=self.pg0.remote_hosts[0].ip4,
671 pdst=self.pg0.remote_hosts[1].ip4))
672 self.send_and_assert_no_replies(self.pg0, p,
673 "ARP req for non-local destination")
678 dyn_arp.remove_vpp_config()
679 static_arp.remove_vpp_config()
680 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
682 # need this to flush the adj-fibs
683 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
684 self.pg2.admin_down()
685 self.pg1.admin_down()
687 def test_proxy_mirror_arp(self):
688 """ Interface Mirror Proxy ARP """
691 # When VPP has an interface whose address is also applied to a TAP
692 # interface on the host, then VPP's TAP interface will be unnumbered
693 # to the 'real' interface and do proxy ARP from the host.
694 # the curious aspect of this setup is that ARP requests from the host
695 # will come from the VPP's own address.
697 self.pg0.generate_remote_hosts(2)
699 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
700 dst="ff:ff:ff:ff:ff:ff") /
702 hwsrc=self.pg2.remote_mac,
703 pdst=self.pg0.remote_hosts[1].ip4,
704 psrc=self.pg0.local_ip4))
707 # Configure Proxy ARP for the subnet on PG0addresses on pg0
709 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
710 self.pg0._local_ip4_bcast)
712 # Make pg2 un-numbered to pg0
714 self.pg2.set_unnumbered(self.pg0.sw_if_index)
717 # Enable pg2 for proxy ARP
719 self.pg2.set_proxy_arp()
722 # Send the ARP request with an originating address that
723 # is VPP's own address
725 self.pg2.add_stream(arp_req_from_me)
726 self.pg_enable_capture(self.pg_interfaces)
729 rx = self.pg2.get_capture(1)
730 self.verify_arp_resp(rx[0],
733 self.pg0.remote_hosts[1].ip4,
737 # validate we have not learned an ARP entry as a result of this
739 self.assertFalse(find_nbr(self,
740 self.pg2.sw_if_index,
746 self.pg2.set_proxy_arp(0)
747 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
748 self.pg0._local_ip4_bcast,
751 def test_proxy_arp(self):
754 self.pg1.generate_remote_hosts(2)
757 # Proxy ARP request packets for each interface
759 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
760 dst="ff:ff:ff:ff:ff:ff") /
762 hwsrc=self.pg0.remote_mac,
764 psrc=self.pg0.remote_ip4))
765 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
766 dst="ff:ff:ff:ff:ff:ff") /
769 hwsrc=self.pg0.remote_mac,
771 psrc=self.pg0.remote_ip4))
772 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
773 dst="ff:ff:ff:ff:ff:ff") /
775 hwsrc=self.pg1.remote_mac,
777 psrc=self.pg1.remote_ip4))
778 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
779 dst="ff:ff:ff:ff:ff:ff") /
781 hwsrc=self.pg2.remote_mac,
783 psrc=self.pg1.remote_hosts[1].ip4))
784 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
785 dst="ff:ff:ff:ff:ff:ff") /
787 hwsrc=self.pg3.remote_mac,
789 psrc=self.pg3.remote_ip4))
792 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
794 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
795 inet_pton(AF_INET, "10.10.10.124"))
798 # No responses are sent when the interfaces are not enabled for proxy
801 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
802 "ARP req from unconfigured interface")
803 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
804 "ARP req from unconfigured interface")
807 # Make pg2 un-numbered to pg1
810 self.pg2.set_unnumbered(self.pg1.sw_if_index)
812 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
813 "ARP req from unnumbered interface")
816 # Enable each interface to reply to proxy ARPs
818 for i in self.pg_interfaces:
822 # Now each of the interfaces should reply to a request to a proxied
825 self.pg0.add_stream(arp_req_pg0)
826 self.pg_enable_capture(self.pg_interfaces)
829 rx = self.pg0.get_capture(1)
830 self.verify_arp_resp(rx[0],
836 self.pg0.add_stream(arp_req_pg0_tagged)
837 self.pg_enable_capture(self.pg_interfaces)
840 rx = self.pg0.get_capture(1)
841 self.verify_arp_resp(rx[0],
847 self.pg1.add_stream(arp_req_pg1)
848 self.pg_enable_capture(self.pg_interfaces)
851 rx = self.pg1.get_capture(1)
852 self.verify_arp_resp(rx[0],
858 self.pg2.add_stream(arp_req_pg2)
859 self.pg_enable_capture(self.pg_interfaces)
862 rx = self.pg2.get_capture(1)
863 self.verify_arp_resp(rx[0],
867 self.pg1.remote_hosts[1].ip4)
870 # A request for an address out of the configured range
872 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
873 dst="ff:ff:ff:ff:ff:ff") /
875 hwsrc=self.pg1.remote_mac,
877 psrc=self.pg1.remote_ip4))
878 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
879 "ARP req out of range HI")
880 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
881 dst="ff:ff:ff:ff:ff:ff") /
883 hwsrc=self.pg1.remote_mac,
885 psrc=self.pg1.remote_ip4))
886 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
887 "ARP req out of range Low")
890 # Request for an address in the proxy range but from an interface
893 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
894 "ARP req from different VRF")
897 # Disable Each interface for proxy ARP
898 # - expect none to respond
900 for i in self.pg_interfaces:
903 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
904 "ARP req from disable")
905 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
906 "ARP req from disable")
907 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
908 "ARP req from disable")
911 # clean up on interface 2
913 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
919 # Interface 2 does not yet have ip4 config
921 self.pg2.config_ip4()
922 self.pg2.generate_remote_hosts(2)
925 # Add a route with out going label via an ARP unresolved next-hop
927 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
928 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
929 self.pg2.sw_if_index,
931 ip_10_0_0_1.add_vpp_config()
934 # packets should generate an ARP request
936 p = (Ether(src=self.pg0.remote_mac,
937 dst=self.pg0.local_mac) /
938 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
939 UDP(sport=1234, dport=1234) /
942 self.pg0.add_stream(p)
943 self.pg_enable_capture(self.pg_interfaces)
946 rx = self.pg2.get_capture(1)
947 self.verify_arp_req(rx[0],
950 self.pg2._remote_hosts[1].ip4)
953 # now resolve the neighbours
955 self.pg2.configure_ipv4_neighbors()
958 # Now packet should be properly MPLS encapped.
959 # This verifies that MPLS link-type adjacencies are completed
960 # when the ARP entry resolves
962 self.pg0.add_stream(p)
963 self.pg_enable_capture(self.pg_interfaces)
966 rx = self.pg2.get_capture(1)
967 self.verify_ip_o_mpls(rx[0],
969 self.pg2.remote_hosts[1].mac,
973 self.pg2.unconfig_ip4()
975 def test_arp_vrrp(self):
976 """ ARP reply with VRRP virtual src hw addr """
979 # IP packet destined for pg1 remote host arrives on pg0 resulting
980 # in an ARP request for the address of the remote host on pg1
982 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
983 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
984 UDP(sport=1234, dport=1234) /
987 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
989 self.verify_arp_req(rx1[0],
995 # ARP reply for address of pg1 remote host arrives on pg1 with
996 # the hw src addr set to a value in the VRRP IPv4 range of
999 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1000 ARP(op="is-at", hwdst=self.pg1.local_mac,
1001 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1002 psrc=self.pg1.remote_ip4))
1004 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1007 # IP packet destined for pg1 remote host arrives on pg0 again.
1008 # VPP should have an ARP entry for that address now and the packet
1009 # should be sent out pg1.
1011 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1013 self.verify_ip(rx1[0],
1015 "00:00:5e:00:01:09",
1016 self.pg0.remote_ip4,
1017 self.pg1.remote_ip4)
1019 self.pg1.admin_down()
1022 def test_arp_duplicates(self):
1023 """ ARP Duplicates"""
1026 # Generate some hosts on the LAN
1028 self.pg1.generate_remote_hosts(3)
1031 # Add host 1 on pg1 and pg2
1033 arp_pg1 = VppNeighbor(self,
1034 self.pg1.sw_if_index,
1035 self.pg1.remote_hosts[1].mac,
1036 self.pg1.remote_hosts[1].ip4)
1037 arp_pg1.add_vpp_config()
1038 arp_pg2 = VppNeighbor(self,
1039 self.pg2.sw_if_index,
1040 self.pg2.remote_mac,
1041 self.pg1.remote_hosts[1].ip4)
1042 arp_pg2.add_vpp_config()
1045 # IP packet destined for pg1 remote host arrives on pg1 again.
1047 p = (Ether(dst=self.pg0.local_mac,
1048 src=self.pg0.remote_mac) /
1049 IP(src=self.pg0.remote_ip4,
1050 dst=self.pg1.remote_hosts[1].ip4) /
1051 UDP(sport=1234, dport=1234) /
1054 self.pg0.add_stream(p)
1055 self.pg_enable_capture(self.pg_interfaces)
1058 rx1 = self.pg1.get_capture(1)
1060 self.verify_ip(rx1[0],
1062 self.pg1.remote_hosts[1].mac,
1063 self.pg0.remote_ip4,
1064 self.pg1.remote_hosts[1].ip4)
1067 # remove the duplicate on pg1
1068 # packet stream should generate ARPs out of pg1
1070 arp_pg1.remove_vpp_config()
1072 self.pg0.add_stream(p)
1073 self.pg_enable_capture(self.pg_interfaces)
1076 rx1 = self.pg1.get_capture(1)
1078 self.verify_arp_req(rx1[0],
1081 self.pg1.remote_hosts[1].ip4)
1086 arp_pg1.add_vpp_config()
1088 self.pg0.add_stream(p)
1089 self.pg_enable_capture(self.pg_interfaces)
1092 rx1 = self.pg1.get_capture(1)
1094 self.verify_ip(rx1[0],
1096 self.pg1.remote_hosts[1].mac,
1097 self.pg0.remote_ip4,
1098 self.pg1.remote_hosts[1].ip4)
1100 def test_arp_static(self):
1102 self.pg2.generate_remote_hosts(3)
1105 # Add a static ARP entry
1107 static_arp = VppNeighbor(self,
1108 self.pg2.sw_if_index,
1109 self.pg2.remote_hosts[1].mac,
1110 self.pg2.remote_hosts[1].ip4,
1112 static_arp.add_vpp_config()
1115 # Add the connected prefix to the interface
1117 self.pg2.config_ip4()
1120 # We should now find the adj-fib
1122 self.assertTrue(find_nbr(self,
1123 self.pg2.sw_if_index,
1124 self.pg2.remote_hosts[1].ip4,
1126 self.assertTrue(find_route(self,
1127 self.pg2.remote_hosts[1].ip4,
1131 # remove the connected
1133 self.pg2.unconfig_ip4()
1136 # put the interface into table 1
1138 self.pg2.set_table_ip4(1)
1141 # configure the same connected and expect to find the
1142 # adj fib in the new table
1144 self.pg2.config_ip4()
1145 self.assertTrue(find_route(self,
1146 self.pg2.remote_hosts[1].ip4,
1153 self.pg2.unconfig_ip4()
1154 self.pg2.set_table_ip4(0)
1156 def test_arp_incomplete(self):
1157 """ ARP Incomplete"""
1158 self.pg1.generate_remote_hosts(3)
1160 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1161 IP(src=self.pg0.remote_ip4,
1162 dst=self.pg1.remote_hosts[1].ip4) /
1163 UDP(sport=1234, dport=1234) /
1165 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1166 IP(src=self.pg0.remote_ip4,
1167 dst=self.pg1.remote_hosts[2].ip4) /
1168 UDP(sport=1234, dport=1234) /
1172 # a packet to an unresolved destination generates an ARP request
1174 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1175 self.verify_arp_req(rx[0],
1178 self.pg1._remote_hosts[1].ip4)
1181 # add a neighbour for remote host 1
1183 static_arp = VppNeighbor(self,
1184 self.pg1.sw_if_index,
1185 self.pg1.remote_hosts[1].mac,
1186 self.pg1.remote_hosts[1].ip4,
1188 static_arp.add_vpp_config()
1191 # change the interface's MAC
1193 mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1194 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1195 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1196 mac_string = ''.join(mac)
1198 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1202 # now ARP requests come from the new source mac
1204 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1205 self.verify_arp_req(rx[0],
1206 "00:00:00:33:33:33",
1208 self.pg1._remote_hosts[2].ip4)
1211 # packets to the resolved host also have the new source mac
1213 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1214 self.verify_ip(rx[0],
1215 "00:00:00:33:33:33",
1216 self.pg1.remote_hosts[1].mac,
1217 self.pg0.remote_ip4,
1218 self.pg1.remote_hosts[1].ip4)
1221 # set the mac address on the interface that does not have a
1222 # configured subnet and thus no glean
1224 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1227 def test_garp(self):
1231 # Generate some hosts on the LAN
1233 self.pg1.generate_remote_hosts(4)
1238 arp = VppNeighbor(self,
1239 self.pg1.sw_if_index,
1240 self.pg1.remote_hosts[1].mac,
1241 self.pg1.remote_hosts[1].ip4)
1242 arp.add_vpp_config()
1244 self.assertTrue(find_nbr(self,
1245 self.pg1.sw_if_index,
1246 self.pg1.remote_hosts[1].ip4,
1247 mac=self.pg1.remote_hosts[1].mac))
1250 # Send a GARP (request) to swap the host 1's address to that of host 2
1252 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1253 src=self.pg1.remote_hosts[2].mac) /
1255 hwdst=self.pg1.local_mac,
1256 hwsrc=self.pg1.remote_hosts[2].mac,
1257 pdst=self.pg1.remote_hosts[1].ip4,
1258 psrc=self.pg1.remote_hosts[1].ip4))
1260 self.pg1.add_stream(p1)
1261 self.pg_enable_capture(self.pg_interfaces)
1264 self.assertTrue(find_nbr(self,
1265 self.pg1.sw_if_index,
1266 self.pg1.remote_hosts[1].ip4,
1267 mac=self.pg1.remote_hosts[2].mac))
1270 # Send a GARP (reply) to swap the host 1's address to that of host 3
1272 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1273 src=self.pg1.remote_hosts[3].mac) /
1275 hwdst=self.pg1.local_mac,
1276 hwsrc=self.pg1.remote_hosts[3].mac,
1277 pdst=self.pg1.remote_hosts[1].ip4,
1278 psrc=self.pg1.remote_hosts[1].ip4))
1280 self.pg1.add_stream(p1)
1281 self.pg_enable_capture(self.pg_interfaces)
1284 self.assertTrue(find_nbr(self,
1285 self.pg1.sw_if_index,
1286 self.pg1.remote_hosts[1].ip4,
1287 mac=self.pg1.remote_hosts[3].mac))
1290 # GARPs (request nor replies) for host we don't know yet
1291 # don't result in new neighbour entries
1293 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1294 src=self.pg1.remote_hosts[3].mac) /
1296 hwdst=self.pg1.local_mac,
1297 hwsrc=self.pg1.remote_hosts[3].mac,
1298 pdst=self.pg1.remote_hosts[2].ip4,
1299 psrc=self.pg1.remote_hosts[2].ip4))
1301 self.pg1.add_stream(p1)
1302 self.pg_enable_capture(self.pg_interfaces)
1305 self.assertFalse(find_nbr(self,
1306 self.pg1.sw_if_index,
1307 self.pg1.remote_hosts[2].ip4))
1309 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1310 src=self.pg1.remote_hosts[3].mac) /
1312 hwdst=self.pg1.local_mac,
1313 hwsrc=self.pg1.remote_hosts[3].mac,
1314 pdst=self.pg1.remote_hosts[2].ip4,
1315 psrc=self.pg1.remote_hosts[2].ip4))
1317 self.pg1.add_stream(p1)
1318 self.pg_enable_capture(self.pg_interfaces)
1321 self.assertFalse(find_nbr(self,
1322 self.pg1.sw_if_index,
1323 self.pg1.remote_hosts[2].ip4))
1325 def test_arp_incomplete(self):
1326 """ Incomplete Entries """
1329 # ensure that we throttle the ARP and ND requests
1331 self.pg0.generate_remote_hosts(2)
1336 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1337 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1338 self.pg0.sw_if_index)])
1339 ip_10_0_0_1.add_vpp_config()
1341 p1 = (Ether(dst=self.pg1.local_mac,
1342 src=self.pg1.remote_mac) /
1343 IP(src=self.pg1.remote_ip4,
1345 UDP(sport=1234, dport=1234) /
1348 self.pg1.add_stream(p1 * 257)
1349 self.pg_enable_capture(self.pg_interfaces)
1351 rx = self.pg0._get_capture(1)
1354 # how many we get is going to be dependent on the time for packet
1355 # processing but it should be small
1357 self.assertLess(len(rx), 64)
1362 ip_10_1 = VppIpRoute(self, "10::1", 128,
1363 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1364 self.pg0.sw_if_index,
1365 proto=DpoProto.DPO_PROTO_IP6)])
1366 ip_10_1.add_vpp_config()
1368 p1 = (Ether(dst=self.pg1.local_mac,
1369 src=self.pg1.remote_mac) /
1370 IPv6(src=self.pg1.remote_ip6,
1372 UDP(sport=1234, dport=1234) /
1375 self.pg1.add_stream(p1 * 257)
1376 self.pg_enable_capture(self.pg_interfaces)
1378 rx = self.pg0._get_capture(1)
1381 # how many we get is going to be dependent on the time for packet
1382 # processing but it should be small
1384 self.assertLess(len(rx), 64)
1386 def test_arp_forus(self):
1387 """ ARP for for-us """
1390 # Test that VPP responds with ARP requests to addresses that
1391 # are connected and local routes.
1392 # Use one of the 'remote' addresses in the subnet as a local address
1393 # The intention of this route is that it then acts like a secondary
1394 # address added to an interface
1396 self.pg0.generate_remote_hosts(2)
1399 self, self.pg0.remote_hosts[1].ip4, 32,
1400 [VppRoutePath("0.0.0.0",
1401 self.pg0.sw_if_index,
1402 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1403 forus.add_vpp_config()
1405 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1406 src=self.pg0.remote_mac) /
1408 hwdst=self.pg0.local_mac,
1409 hwsrc=self.pg0.remote_mac,
1410 pdst=self.pg0.remote_hosts[1].ip4,
1411 psrc=self.pg0.remote_ip4))
1413 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1415 self.verify_arp_resp(rx[0],
1417 self.pg0.remote_mac,
1418 self.pg0.remote_hosts[1].ip4,
1419 self.pg0.remote_ip4)
1422 class NeighborStatsTestCase(VppTestCase):
1423 """ ARP/ND Counters """
1426 def setUpClass(cls):
1427 super(NeighborStatsTestCase, cls).setUpClass()
1430 def tearDownClass(cls):
1431 super(NeighborStatsTestCase, cls).tearDownClass()
1434 super(NeighborStatsTestCase, self).setUp()
1436 self.create_pg_interfaces(range(2))
1438 # pg0 configured with ip4 and 6 addresses used for input
1439 # pg1 configured with ip4 and 6 addresses used for output
1440 # pg2 is unnumbered to pg0
1441 for i in self.pg_interfaces:
1449 super(NeighborStatsTestCase, self).tearDown()
1451 for i in self.pg_interfaces:
1456 def test_arp_stats(self):
1457 """ ARP Counters """
1459 self.vapi.cli("adj counters enable")
1460 self.pg1.generate_remote_hosts(2)
1462 arp1 = VppNeighbor(self,
1463 self.pg1.sw_if_index,
1464 self.pg1.remote_hosts[0].mac,
1465 self.pg1.remote_hosts[0].ip4)
1466 arp1.add_vpp_config()
1467 arp2 = VppNeighbor(self,
1468 self.pg1.sw_if_index,
1469 self.pg1.remote_hosts[1].mac,
1470 self.pg1.remote_hosts[1].ip4)
1471 arp2.add_vpp_config()
1473 p1 = (Ether(dst=self.pg0.local_mac,
1474 src=self.pg0.remote_mac) /
1475 IP(src=self.pg0.remote_ip4,
1476 dst=self.pg1.remote_hosts[0].ip4) /
1477 UDP(sport=1234, dport=1234) /
1479 p2 = (Ether(dst=self.pg0.local_mac,
1480 src=self.pg0.remote_mac) /
1481 IP(src=self.pg0.remote_ip4,
1482 dst=self.pg1.remote_hosts[1].ip4) /
1483 UDP(sport=1234, dport=1234) /
1486 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1487 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1489 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1490 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1492 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1493 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1495 def test_nd_stats(self):
1498 self.vapi.cli("adj counters enable")
1499 self.pg0.generate_remote_hosts(3)
1501 nd1 = VppNeighbor(self,
1502 self.pg0.sw_if_index,
1503 self.pg0.remote_hosts[1].mac,
1504 self.pg0.remote_hosts[1].ip6)
1505 nd1.add_vpp_config()
1506 nd2 = VppNeighbor(self,
1507 self.pg0.sw_if_index,
1508 self.pg0.remote_hosts[2].mac,
1509 self.pg0.remote_hosts[2].ip6)
1510 nd2.add_vpp_config()
1512 p1 = (Ether(dst=self.pg1.local_mac,
1513 src=self.pg1.remote_mac) /
1514 IPv6(src=self.pg1.remote_ip6,
1515 dst=self.pg0.remote_hosts[1].ip6) /
1516 UDP(sport=1234, dport=1234) /
1518 p2 = (Ether(dst=self.pg1.local_mac,
1519 src=self.pg1.remote_mac) /
1520 IPv6(src=self.pg1.remote_ip6,
1521 dst=self.pg0.remote_hosts[2].ip6) /
1522 UDP(sport=1234, dport=1234) /
1525 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1526 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1528 self.assertEqual(16, nd1.get_stats()['packets'])
1529 self.assertEqual(16, nd2.get_stats()['packets'])
1531 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1532 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1535 if __name__ == '__main__':
1536 unittest.main(testRunner=VppTestRunner)