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, \
11 from scapy.packet import Raw
12 from scapy.layers.l2 import Ether, ARP, Dot1Q
13 from scapy.layers.inet import IP, UDP
14 from scapy.layers.inet6 import IPv6
15 from scapy.contrib.mpls import MPLS
16 from scapy.layers.inet6 import IPv6
18 # not exported by scapy, so redefined here
19 arp_opts = {"who-has": 1, "is-at": 2}
22 class ARPTestCase(VppTestCase):
26 super(ARPTestCase, self).setUp()
28 # create 3 pg interfaces
29 self.create_pg_interfaces(range(4))
31 # pg0 configured with ip4 and 6 addresses used for input
32 # pg1 configured with ip4 and 6 addresses used for output
33 # pg2 is unnumbered to pg0
34 for i in self.pg_interfaces:
39 self.pg0.resolve_arp()
44 # pg3 in a different VRF
45 self.tbl = VppIpTable(self, 1)
46 self.tbl.add_vpp_config()
48 self.pg3.set_table_ip4(1)
52 self.pg0.unconfig_ip4()
53 self.pg0.unconfig_ip6()
55 self.pg1.unconfig_ip4()
56 self.pg1.unconfig_ip6()
58 self.pg3.unconfig_ip4()
59 self.pg3.set_table_ip4(0)
61 for i in self.pg_interfaces:
64 super(ARPTestCase, self).tearDown()
66 def verify_arp_req(self, rx, smac, sip, dip):
68 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
69 self.assertEqual(ether.src, smac)
72 self.assertEqual(arp.hwtype, 1)
73 self.assertEqual(arp.ptype, 0x800)
74 self.assertEqual(arp.hwlen, 6)
75 self.assertEqual(arp.plen, 4)
76 self.assertEqual(arp.op, arp_opts["who-has"])
77 self.assertEqual(arp.hwsrc, smac)
78 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
79 self.assertEqual(arp.psrc, sip)
80 self.assertEqual(arp.pdst, dip)
82 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
84 self.assertEqual(ether.dst, dmac)
85 self.assertEqual(ether.src, smac)
88 self.assertEqual(arp.hwtype, 1)
89 self.assertEqual(arp.ptype, 0x800)
90 self.assertEqual(arp.hwlen, 6)
91 self.assertEqual(arp.plen, 4)
92 self.assertEqual(arp.op, arp_opts["is-at"])
93 self.assertEqual(arp.hwsrc, smac)
94 self.assertEqual(arp.hwdst, dmac)
95 self.assertEqual(arp.psrc, sip)
96 self.assertEqual(arp.pdst, dip)
98 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
100 self.assertEqual(ether.dst, dmac)
101 self.assertEqual(ether.src, smac)
104 self.assertEqual(arp.hwtype, 1)
105 self.assertEqual(arp.ptype, 0x800)
106 self.assertEqual(arp.hwlen, 6)
107 self.assertEqual(arp.plen, 4)
108 self.assertEqual(arp.op, arp_opts["is-at"])
109 self.assertNotEqual(arp.hwsrc, smac)
110 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
111 "00:00:5E:00:01" in arp.hwsrc)
112 self.assertEqual(arp.hwdst, dmac)
113 self.assertEqual(arp.psrc, sip)
114 self.assertEqual(arp.pdst, dip)
116 def verify_ip(self, rx, smac, dmac, sip, dip):
118 self.assertEqual(ether.dst, dmac)
119 self.assertEqual(ether.src, smac)
122 self.assertEqual(ip.src, sip)
123 self.assertEqual(ip.dst, dip)
125 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
127 self.assertEqual(ether.dst, dmac)
128 self.assertEqual(ether.src, smac)
131 self.assertTrue(mpls.label, label)
134 self.assertEqual(ip.src, sip)
135 self.assertEqual(ip.dst, dip)
141 # Generate some hosts on the LAN
143 self.pg1.generate_remote_hosts(11)
146 # Send IP traffic to one of these unresolved hosts.
147 # expect the generation of an ARP request
149 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
150 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
151 UDP(sport=1234, dport=1234) /
154 self.pg0.add_stream(p)
155 self.pg_enable_capture(self.pg_interfaces)
158 rx = self.pg1.get_capture(1)
160 self.verify_arp_req(rx[0],
163 self.pg1._remote_hosts[1].ip4)
166 # And a dynamic ARP entry for host 1
168 dyn_arp = VppNeighbor(self,
169 self.pg1.sw_if_index,
170 self.pg1.remote_hosts[1].mac,
171 self.pg1.remote_hosts[1].ip4)
172 dyn_arp.add_vpp_config()
175 # now we expect IP traffic forwarded
177 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
178 IP(src=self.pg0.remote_ip4,
179 dst=self.pg1._remote_hosts[1].ip4) /
180 UDP(sport=1234, dport=1234) /
183 self.pg0.add_stream(dyn_p)
184 self.pg_enable_capture(self.pg_interfaces)
187 rx = self.pg1.get_capture(1)
189 self.verify_ip(rx[0],
191 self.pg1.remote_hosts[1].mac,
193 self.pg1._remote_hosts[1].ip4)
196 # And a Static ARP entry for host 2
198 static_arp = VppNeighbor(self,
199 self.pg1.sw_if_index,
200 self.pg1.remote_hosts[2].mac,
201 self.pg1.remote_hosts[2].ip4,
203 static_arp.add_vpp_config()
205 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
206 IP(src=self.pg0.remote_ip4,
207 dst=self.pg1._remote_hosts[2].ip4) /
208 UDP(sport=1234, dport=1234) /
211 self.pg0.add_stream(static_p)
212 self.pg_enable_capture(self.pg_interfaces)
215 rx = self.pg1.get_capture(1)
217 self.verify_ip(rx[0],
219 self.pg1.remote_hosts[2].mac,
221 self.pg1._remote_hosts[2].ip4)
224 # flap the link. dynamic ARPs get flush, statics don't
226 self.pg1.admin_down()
229 self.pg0.add_stream(static_p)
230 self.pg_enable_capture(self.pg_interfaces)
232 rx = self.pg1.get_capture(1)
234 self.verify_ip(rx[0],
236 self.pg1.remote_hosts[2].mac,
238 self.pg1._remote_hosts[2].ip4)
240 self.pg0.add_stream(dyn_p)
241 self.pg_enable_capture(self.pg_interfaces)
244 rx = self.pg1.get_capture(1)
245 self.verify_arp_req(rx[0],
248 self.pg1._remote_hosts[1].ip4)
251 # Send an ARP request from one of the so-far unlearned remote hosts
253 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
254 src=self.pg1._remote_hosts[3].mac) /
256 hwsrc=self.pg1._remote_hosts[3].mac,
257 pdst=self.pg1.local_ip4,
258 psrc=self.pg1._remote_hosts[3].ip4))
260 self.pg1.add_stream(p)
261 self.pg_enable_capture(self.pg_interfaces)
264 rx = self.pg1.get_capture(1)
265 self.verify_arp_resp(rx[0],
267 self.pg1._remote_hosts[3].mac,
269 self.pg1._remote_hosts[3].ip4)
272 # VPP should have learned the mapping for the remote host
274 self.assertTrue(find_nbr(self,
275 self.pg1.sw_if_index,
276 self.pg1._remote_hosts[3].ip4))
278 # Fire in an ARP request before the interface becomes IP enabled
280 self.pg2.generate_remote_hosts(4)
282 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
284 hwsrc=self.pg2.remote_mac,
285 pdst=self.pg1.local_ip4,
286 psrc=self.pg2.remote_hosts[3].ip4))
287 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
290 hwsrc=self.pg2.remote_mac,
291 pdst=self.pg1.local_ip4,
292 psrc=self.pg2.remote_hosts[3].ip4))
293 self.send_and_assert_no_replies(self.pg2, p,
294 "interface not IP enabled")
297 # Make pg2 un-numbered to pg1
299 self.pg2.set_unnumbered(self.pg1.sw_if_index)
301 unnum = self.vapi.ip_unnumbered_dump()
302 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
303 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
306 # We should respond to ARP requests for the unnumbered to address
307 # once an attached route to the source is known
309 self.send_and_assert_no_replies(
311 "ARP req for unnumbered address - no source")
313 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
314 [VppRoutePath("0.0.0.0",
315 self.pg2.sw_if_index)])
316 attached_host.add_vpp_config()
318 self.pg2.add_stream(p)
319 self.pg_enable_capture(self.pg_interfaces)
322 rx = self.pg2.get_capture(1)
323 self.verify_arp_resp(rx[0],
327 self.pg2.remote_hosts[3].ip4)
329 self.pg2.add_stream(pt)
330 self.pg_enable_capture(self.pg_interfaces)
333 rx = self.pg2.get_capture(1)
334 self.verify_arp_resp(rx[0],
338 self.pg2.remote_hosts[3].ip4)
341 # A neighbor entry that has no associated FIB-entry
343 arp_no_fib = VppNeighbor(self,
344 self.pg1.sw_if_index,
345 self.pg1.remote_hosts[4].mac,
346 self.pg1.remote_hosts[4].ip4,
348 arp_no_fib.add_vpp_config()
351 # check we have the neighbor, but no route
353 self.assertTrue(find_nbr(self,
354 self.pg1.sw_if_index,
355 self.pg1._remote_hosts[4].ip4))
356 self.assertFalse(find_route(self,
357 self.pg1._remote_hosts[4].ip4,
360 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
361 # from within pg1's subnet
363 arp_unnum = VppNeighbor(self,
364 self.pg2.sw_if_index,
365 self.pg1.remote_hosts[5].mac,
366 self.pg1.remote_hosts[5].ip4)
367 arp_unnum.add_vpp_config()
369 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
370 IP(src=self.pg0.remote_ip4,
371 dst=self.pg1._remote_hosts[5].ip4) /
372 UDP(sport=1234, dport=1234) /
375 self.pg0.add_stream(p)
376 self.pg_enable_capture(self.pg_interfaces)
379 rx = self.pg2.get_capture(1)
381 self.verify_ip(rx[0],
383 self.pg1.remote_hosts[5].mac,
385 self.pg1._remote_hosts[5].ip4)
388 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
389 # with the unnumbered interface's address as the source
391 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
393 hwsrc=self.pg2.remote_mac,
394 pdst=self.pg1.local_ip4,
395 psrc=self.pg1.remote_hosts[6].ip4))
397 self.pg2.add_stream(p)
398 self.pg_enable_capture(self.pg_interfaces)
401 rx = self.pg2.get_capture(1)
402 self.verify_arp_resp(rx[0],
406 self.pg1.remote_hosts[6].ip4)
409 # An attached host route out of pg2 for an undiscovered hosts generates
410 # an ARP request with the unnumbered address as the source
412 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
413 [VppRoutePath("0.0.0.0",
414 self.pg2.sw_if_index)])
415 att_unnum.add_vpp_config()
417 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
418 IP(src=self.pg0.remote_ip4,
419 dst=self.pg1._remote_hosts[7].ip4) /
420 UDP(sport=1234, dport=1234) /
423 self.pg0.add_stream(p)
424 self.pg_enable_capture(self.pg_interfaces)
427 rx = self.pg2.get_capture(1)
429 self.verify_arp_req(rx[0],
432 self.pg1._remote_hosts[7].ip4)
434 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
436 hwsrc=self.pg2.remote_mac,
437 pdst=self.pg1.local_ip4,
438 psrc=self.pg1.remote_hosts[7].ip4))
440 self.pg2.add_stream(p)
441 self.pg_enable_capture(self.pg_interfaces)
444 rx = self.pg2.get_capture(1)
445 self.verify_arp_resp(rx[0],
449 self.pg1.remote_hosts[7].ip4)
452 # An attached host route as yet unresolved out of pg2 for an
453 # undiscovered host, an ARP requests begets a response.
455 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
456 [VppRoutePath("0.0.0.0",
457 self.pg2.sw_if_index)])
458 att_unnum1.add_vpp_config()
460 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
462 hwsrc=self.pg2.remote_mac,
463 pdst=self.pg1.local_ip4,
464 psrc=self.pg1.remote_hosts[8].ip4))
466 self.pg2.add_stream(p)
467 self.pg_enable_capture(self.pg_interfaces)
470 rx = self.pg2.get_capture(1)
471 self.verify_arp_resp(rx[0],
475 self.pg1.remote_hosts[8].ip4)
478 # Send an ARP request from one of the so-far unlearned remote hosts
481 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
482 src=self.pg1._remote_hosts[9].mac) /
485 hwsrc=self.pg1._remote_hosts[9].mac,
486 pdst=self.pg1.local_ip4,
487 psrc=self.pg1._remote_hosts[9].ip4))
489 self.pg1.add_stream(p)
490 self.pg_enable_capture(self.pg_interfaces)
493 rx = self.pg1.get_capture(1)
494 self.verify_arp_resp(rx[0],
496 self.pg1._remote_hosts[9].mac,
498 self.pg1._remote_hosts[9].ip4)
501 # Add a hierachy of routes for a host in the sub-net.
502 # Should still get an ARP resp since the cover is attached
504 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
506 hwsrc=self.pg1.remote_mac,
507 pdst=self.pg1.local_ip4,
508 psrc=self.pg1.remote_hosts[10].ip4))
510 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
511 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
512 self.pg1.sw_if_index)])
515 self.pg1.add_stream(p)
516 self.pg_enable_capture(self.pg_interfaces)
518 rx = self.pg1.get_capture(1)
519 self.verify_arp_resp(rx[0],
523 self.pg1.remote_hosts[10].ip4)
525 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
526 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
527 self.pg1.sw_if_index)])
530 self.pg1.add_stream(p)
531 self.pg_enable_capture(self.pg_interfaces)
533 rx = self.pg1.get_capture(1)
534 self.verify_arp_resp(rx[0],
538 self.pg1.remote_hosts[10].ip4)
541 # add an ARP entry that's not on the sub-net and so whose
542 # adj-fib fails the refinement check. then send an ARP request
545 a1 = VppNeighbor(self,
546 self.pg0.sw_if_index,
551 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
553 hwsrc=self.pg0.remote_mac,
554 psrc="100.100.100.50",
555 pdst=self.pg0.remote_ip4))
556 self.send_and_assert_no_replies(self.pg0, p,
557 "ARP req for from failed adj-fib")
561 # 1 - don't respond to ARP request for address not within the
562 # interface's sub-net
563 # 1b - nor within the unnumbered subnet
564 # 1c - nor within the subnet of a different interface
566 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
568 hwsrc=self.pg0.remote_mac,
570 psrc=self.pg0.remote_ip4))
571 self.send_and_assert_no_replies(self.pg0, p,
572 "ARP req for non-local destination")
573 self.assertFalse(find_nbr(self,
574 self.pg0.sw_if_index,
577 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
579 hwsrc=self.pg2.remote_mac,
581 psrc=self.pg1.remote_hosts[7].ip4))
582 self.send_and_assert_no_replies(
584 "ARP req for non-local destination - unnum")
586 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
588 hwsrc=self.pg0.remote_mac,
589 pdst=self.pg1.local_ip4,
590 psrc=self.pg1.remote_ip4))
591 self.send_and_assert_no_replies(self.pg0, p,
592 "ARP req diff sub-net")
593 self.assertFalse(find_nbr(self,
594 self.pg0.sw_if_index,
595 self.pg1.remote_ip4))
598 # 2 - don't respond to ARP request from an address not within the
599 # interface's sub-net
600 # 2b - to a prxied address
601 # 2c - not within a differents interface's sub-net
602 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
604 hwsrc=self.pg0.remote_mac,
606 pdst=self.pg0.local_ip4))
607 self.send_and_assert_no_replies(self.pg0, p,
608 "ARP req for non-local source")
609 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
611 hwsrc=self.pg2.remote_mac,
613 pdst=self.pg0.local_ip4))
614 self.send_and_assert_no_replies(
616 "ARP req for non-local source - unnum")
617 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
619 hwsrc=self.pg0.remote_mac,
620 psrc=self.pg1.remote_ip4,
621 pdst=self.pg0.local_ip4))
622 self.send_and_assert_no_replies(self.pg0, p,
623 "ARP req for non-local source 2c")
626 # 3 - don't respond to ARP request from an address that belongs to
629 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
631 hwsrc=self.pg0.remote_mac,
632 psrc=self.pg0.local_ip4,
633 pdst=self.pg0.local_ip4))
634 self.send_and_assert_no_replies(self.pg0, p,
635 "ARP req for non-local source")
638 # 4 - don't respond to ARP requests that has mac source different
639 # from ARP request HW source
641 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
643 hwsrc="00:00:00:DE:AD:BE",
644 psrc=self.pg0.remote_ip4,
645 pdst=self.pg0.local_ip4))
646 self.send_and_assert_no_replies(self.pg0, p,
647 "ARP req for non-local source")
650 # 5 - don't respond to ARP requests for address within the
651 # interface's sub-net but not the interface's address
653 self.pg0.generate_remote_hosts(2)
654 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
656 hwsrc=self.pg0.remote_mac,
657 psrc=self.pg0.remote_hosts[0].ip4,
658 pdst=self.pg0.remote_hosts[1].ip4))
659 self.send_and_assert_no_replies(self.pg0, p,
660 "ARP req for non-local destination")
665 dyn_arp.remove_vpp_config()
666 static_arp.remove_vpp_config()
667 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
669 # need this to flush the adj-fibs
670 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
671 self.pg2.admin_down()
672 self.pg1.admin_down()
674 def test_proxy_mirror_arp(self):
675 """ Interface Mirror Proxy ARP """
678 # When VPP has an interface whose address is also applied to a TAP
679 # interface on the host, then VPP's TAP interface will be unnumbered
680 # to the 'real' interface and do proxy ARP from the host.
681 # the curious aspect of this setup is that ARP requests from the host
682 # will come from the VPP's own address.
684 self.pg0.generate_remote_hosts(2)
686 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
687 dst="ff:ff:ff:ff:ff:ff") /
689 hwsrc=self.pg2.remote_mac,
690 pdst=self.pg0.remote_hosts[1].ip4,
691 psrc=self.pg0.local_ip4))
694 # Configure Proxy ARP for the subnet on PG0addresses on pg0
696 self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
697 self.pg0._local_ip4n_bcast)
699 # Make pg2 un-numbered to pg0
701 self.pg2.set_unnumbered(self.pg0.sw_if_index)
704 # Enable pg2 for proxy ARP
706 self.pg2.set_proxy_arp()
709 # Send the ARP request with an originating address that
710 # is VPP's own address
712 self.pg2.add_stream(arp_req_from_me)
713 self.pg_enable_capture(self.pg_interfaces)
716 rx = self.pg2.get_capture(1)
717 self.verify_arp_resp(rx[0],
720 self.pg0.remote_hosts[1].ip4,
724 # validate we have not learned an ARP entry as a result of this
726 self.assertFalse(find_nbr(self,
727 self.pg2.sw_if_index,
733 self.pg2.set_proxy_arp(0)
734 self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
735 self.pg0._local_ip4n_bcast,
738 def test_proxy_arp(self):
741 self.pg1.generate_remote_hosts(2)
744 # Proxy ARP rewquest packets for each interface
746 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
747 dst="ff:ff:ff:ff:ff:ff") /
749 hwsrc=self.pg0.remote_mac,
751 psrc=self.pg0.remote_ip4))
752 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
753 dst="ff:ff:ff:ff:ff:ff") /
756 hwsrc=self.pg0.remote_mac,
758 psrc=self.pg0.remote_ip4))
759 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
760 dst="ff:ff:ff:ff:ff:ff") /
762 hwsrc=self.pg1.remote_mac,
764 psrc=self.pg1.remote_ip4))
765 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
766 dst="ff:ff:ff:ff:ff:ff") /
768 hwsrc=self.pg2.remote_mac,
770 psrc=self.pg1.remote_hosts[1].ip4))
771 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
772 dst="ff:ff:ff:ff:ff:ff") /
774 hwsrc=self.pg3.remote_mac,
776 psrc=self.pg3.remote_ip4))
779 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
781 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
782 inet_pton(AF_INET, "10.10.10.124"))
785 # No responses are sent when the interfaces are not enabled for proxy
788 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
789 "ARP req from unconfigured interface")
790 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
791 "ARP req from unconfigured interface")
794 # Make pg2 un-numbered to pg1
797 self.pg2.set_unnumbered(self.pg1.sw_if_index)
799 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
800 "ARP req from unnumbered interface")
803 # Enable each interface to reply to proxy ARPs
805 for i in self.pg_interfaces:
809 # Now each of the interfaces should reply to a request to a proxied
812 self.pg0.add_stream(arp_req_pg0)
813 self.pg_enable_capture(self.pg_interfaces)
816 rx = self.pg0.get_capture(1)
817 self.verify_arp_resp(rx[0],
823 self.pg0.add_stream(arp_req_pg0_tagged)
824 self.pg_enable_capture(self.pg_interfaces)
827 rx = self.pg0.get_capture(1)
828 self.verify_arp_resp(rx[0],
834 self.pg1.add_stream(arp_req_pg1)
835 self.pg_enable_capture(self.pg_interfaces)
838 rx = self.pg1.get_capture(1)
839 self.verify_arp_resp(rx[0],
845 self.pg2.add_stream(arp_req_pg2)
846 self.pg_enable_capture(self.pg_interfaces)
849 rx = self.pg2.get_capture(1)
850 self.verify_arp_resp(rx[0],
854 self.pg1.remote_hosts[1].ip4)
857 # A request for an address out of the configured range
859 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
860 dst="ff:ff:ff:ff:ff:ff") /
862 hwsrc=self.pg1.remote_mac,
864 psrc=self.pg1.remote_ip4))
865 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
866 "ARP req out of range HI")
867 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
868 dst="ff:ff:ff:ff:ff:ff") /
870 hwsrc=self.pg1.remote_mac,
872 psrc=self.pg1.remote_ip4))
873 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
874 "ARP req out of range Low")
877 # Request for an address in the proxy range but from an interface
880 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
881 "ARP req from different VRF")
884 # Disable Each interface for proxy ARP
885 # - expect none to respond
887 for i in self.pg_interfaces:
890 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
891 "ARP req from disable")
892 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
893 "ARP req from disable")
894 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
895 "ARP req from disable")
898 # clean up on interface 2
900 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
906 # Interface 2 does not yet have ip4 config
908 self.pg2.config_ip4()
909 self.pg2.generate_remote_hosts(2)
912 # Add a reoute with out going label via an ARP unresolved next-hop
914 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
915 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
916 self.pg2.sw_if_index,
918 ip_10_0_0_1.add_vpp_config()
921 # packets should generate an ARP request
923 p = (Ether(src=self.pg0.remote_mac,
924 dst=self.pg0.local_mac) /
925 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
926 UDP(sport=1234, dport=1234) /
929 self.pg0.add_stream(p)
930 self.pg_enable_capture(self.pg_interfaces)
933 rx = self.pg2.get_capture(1)
934 self.verify_arp_req(rx[0],
937 self.pg2._remote_hosts[1].ip4)
940 # now resolve the neighbours
942 self.pg2.configure_ipv4_neighbors()
945 # Now packet should be properly MPLS encapped.
946 # This verifies that MPLS link-type adjacencies are completed
947 # when the ARP entry resolves
949 self.pg0.add_stream(p)
950 self.pg_enable_capture(self.pg_interfaces)
953 rx = self.pg2.get_capture(1)
954 self.verify_ip_o_mpls(rx[0],
956 self.pg2.remote_hosts[1].mac,
960 self.pg2.unconfig_ip4()
962 def test_arp_vrrp(self):
963 """ ARP reply with VRRP virtual src hw addr """
966 # IP packet destined for pg1 remote host arrives on pg0 resulting
967 # in an ARP request for the address of the remote host on pg1
969 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
970 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
971 UDP(sport=1234, dport=1234) /
974 self.pg0.add_stream(p0)
975 self.pg_enable_capture(self.pg_interfaces)
978 rx1 = self.pg1.get_capture(1)
980 self.verify_arp_req(rx1[0],
986 # ARP reply for address of pg1 remote host arrives on pg1 with
987 # the hw src addr set to a value in the VRRP IPv4 range of
990 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
991 ARP(op="is-at", hwdst=self.pg1.local_mac,
992 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
993 psrc=self.pg1.remote_ip4))
995 self.pg1.add_stream(p1)
996 self.pg_enable_capture(self.pg_interfaces)
1000 # IP packet destined for pg1 remote host arrives on pg0 again.
1001 # VPP should have an ARP entry for that address now and the packet
1002 # should be sent out pg1.
1004 self.pg0.add_stream(p0)
1005 self.pg_enable_capture(self.pg_interfaces)
1008 rx1 = self.pg1.get_capture(1)
1010 self.verify_ip(rx1[0],
1012 "00:00:5e:00:01:09",
1013 self.pg0.remote_ip4,
1014 self.pg1.remote_ip4)
1016 self.pg1.admin_down()
1019 def test_arp_duplicates(self):
1020 """ ARP Duplicates"""
1023 # Generate some hosts on the LAN
1025 self.pg1.generate_remote_hosts(3)
1028 # Add host 1 on pg1 and pg2
1030 arp_pg1 = VppNeighbor(self,
1031 self.pg1.sw_if_index,
1032 self.pg1.remote_hosts[1].mac,
1033 self.pg1.remote_hosts[1].ip4)
1034 arp_pg1.add_vpp_config()
1035 arp_pg2 = VppNeighbor(self,
1036 self.pg2.sw_if_index,
1037 self.pg2.remote_mac,
1038 self.pg1.remote_hosts[1].ip4)
1039 arp_pg2.add_vpp_config()
1042 # IP packet destined for pg1 remote host arrives on pg1 again.
1044 p = (Ether(dst=self.pg0.local_mac,
1045 src=self.pg0.remote_mac) /
1046 IP(src=self.pg0.remote_ip4,
1047 dst=self.pg1.remote_hosts[1].ip4) /
1048 UDP(sport=1234, dport=1234) /
1051 self.pg0.add_stream(p)
1052 self.pg_enable_capture(self.pg_interfaces)
1055 rx1 = self.pg1.get_capture(1)
1057 self.verify_ip(rx1[0],
1059 self.pg1.remote_hosts[1].mac,
1060 self.pg0.remote_ip4,
1061 self.pg1.remote_hosts[1].ip4)
1064 # remove the duplicate on pg1
1065 # packet stream shoud generate ARPs out of pg1
1067 arp_pg1.remove_vpp_config()
1069 self.pg0.add_stream(p)
1070 self.pg_enable_capture(self.pg_interfaces)
1073 rx1 = self.pg1.get_capture(1)
1075 self.verify_arp_req(rx1[0],
1078 self.pg1.remote_hosts[1].ip4)
1083 arp_pg1.add_vpp_config()
1085 self.pg0.add_stream(p)
1086 self.pg_enable_capture(self.pg_interfaces)
1089 rx1 = self.pg1.get_capture(1)
1091 self.verify_ip(rx1[0],
1093 self.pg1.remote_hosts[1].mac,
1094 self.pg0.remote_ip4,
1095 self.pg1.remote_hosts[1].ip4)
1097 def test_arp_static(self):
1099 self.pg2.generate_remote_hosts(3)
1102 # Add a static ARP entry
1104 static_arp = VppNeighbor(self,
1105 self.pg2.sw_if_index,
1106 self.pg2.remote_hosts[1].mac,
1107 self.pg2.remote_hosts[1].ip4,
1109 static_arp.add_vpp_config()
1112 # Add the connected prefix to the interface
1114 self.pg2.config_ip4()
1117 # We should now find the adj-fib
1119 self.assertTrue(find_nbr(self,
1120 self.pg2.sw_if_index,
1121 self.pg2.remote_hosts[1].ip4,
1123 self.assertTrue(find_route(self,
1124 self.pg2.remote_hosts[1].ip4,
1128 # remove the connected
1130 self.pg2.unconfig_ip4()
1133 # put the interface into table 1
1135 self.pg2.set_table_ip4(1)
1138 # configure the same connected and expect to find the
1139 # adj fib in the new table
1141 self.pg2.config_ip4()
1142 self.assertTrue(find_route(self,
1143 self.pg2.remote_hosts[1].ip4,
1150 self.pg2.unconfig_ip4()
1151 self.pg2.set_table_ip4(0)
1153 def test_arp_incomplete(self):
1154 """ ARP Incomplete"""
1155 self.pg1.generate_remote_hosts(3)
1157 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1158 IP(src=self.pg0.remote_ip4,
1159 dst=self.pg1.remote_hosts[1].ip4) /
1160 UDP(sport=1234, dport=1234) /
1162 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1163 IP(src=self.pg0.remote_ip4,
1164 dst=self.pg1.remote_hosts[2].ip4) /
1165 UDP(sport=1234, dport=1234) /
1169 # a packet to an unresolved destination generates an ARP request
1171 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1172 self.verify_arp_req(rx[0],
1175 self.pg1._remote_hosts[1].ip4)
1178 # add a neighbour for remote host 1
1180 static_arp = VppNeighbor(self,
1181 self.pg1.sw_if_index,
1182 self.pg1.remote_hosts[1].mac,
1183 self.pg1.remote_hosts[1].ip4,
1185 static_arp.add_vpp_config()
1188 # change the interface's MAC
1190 mac = [chr(0x00), chr(0x00), chr(0x00),
1191 chr(0x33), chr(0x33), chr(0x33)]
1192 mac_string = ''.join(mac)
1194 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1198 # now ARP requests come from the new source mac
1200 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1201 self.verify_arp_req(rx[0],
1202 "00:00:00:33:33:33",
1204 self.pg1._remote_hosts[2].ip4)
1207 # packets to the resolved host also have the new source mac
1209 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1210 self.verify_ip(rx[0],
1211 "00:00:00:33:33:33",
1212 self.pg1.remote_hosts[1].mac,
1213 self.pg0.remote_ip4,
1214 self.pg1.remote_hosts[1].ip4)
1217 # set the mac address on the inteface that does not have a
1218 # configured subnet and thus no glean
1220 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1223 def test_garp(self):
1227 # Generate some hosts on the LAN
1229 self.pg1.generate_remote_hosts(4)
1234 arp = VppNeighbor(self,
1235 self.pg1.sw_if_index,
1236 self.pg1.remote_hosts[1].mac,
1237 self.pg1.remote_hosts[1].ip4)
1238 arp.add_vpp_config()
1240 self.assertTrue(find_nbr(self,
1241 self.pg1.sw_if_index,
1242 self.pg1.remote_hosts[1].ip4,
1243 mac=self.pg1.remote_hosts[1].mac))
1246 # Send a GARP (request) to swap the host 1's address to that of host 2
1248 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1249 src=self.pg1.remote_hosts[2].mac) /
1251 hwdst=self.pg1.local_mac,
1252 hwsrc=self.pg1.remote_hosts[2].mac,
1253 pdst=self.pg1.remote_hosts[1].ip4,
1254 psrc=self.pg1.remote_hosts[1].ip4))
1256 self.pg1.add_stream(p1)
1257 self.pg_enable_capture(self.pg_interfaces)
1260 self.assertTrue(find_nbr(self,
1261 self.pg1.sw_if_index,
1262 self.pg1.remote_hosts[1].ip4,
1263 mac=self.pg1.remote_hosts[2].mac))
1266 # Send a GARP (reply) to swap the host 1's address to that of host 3
1268 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1269 src=self.pg1.remote_hosts[3].mac) /
1271 hwdst=self.pg1.local_mac,
1272 hwsrc=self.pg1.remote_hosts[3].mac,
1273 pdst=self.pg1.remote_hosts[1].ip4,
1274 psrc=self.pg1.remote_hosts[1].ip4))
1276 self.pg1.add_stream(p1)
1277 self.pg_enable_capture(self.pg_interfaces)
1280 self.assertTrue(find_nbr(self,
1281 self.pg1.sw_if_index,
1282 self.pg1.remote_hosts[1].ip4,
1283 mac=self.pg1.remote_hosts[3].mac))
1286 # GARPs (requets nor replies) for host we don't know yet
1287 # don't result in new neighbour entries
1289 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1290 src=self.pg1.remote_hosts[3].mac) /
1292 hwdst=self.pg1.local_mac,
1293 hwsrc=self.pg1.remote_hosts[3].mac,
1294 pdst=self.pg1.remote_hosts[2].ip4,
1295 psrc=self.pg1.remote_hosts[2].ip4))
1297 self.pg1.add_stream(p1)
1298 self.pg_enable_capture(self.pg_interfaces)
1301 self.assertFalse(find_nbr(self,
1302 self.pg1.sw_if_index,
1303 self.pg1.remote_hosts[2].ip4))
1305 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1306 src=self.pg1.remote_hosts[3].mac) /
1308 hwdst=self.pg1.local_mac,
1309 hwsrc=self.pg1.remote_hosts[3].mac,
1310 pdst=self.pg1.remote_hosts[2].ip4,
1311 psrc=self.pg1.remote_hosts[2].ip4))
1313 self.pg1.add_stream(p1)
1314 self.pg_enable_capture(self.pg_interfaces)
1317 self.assertFalse(find_nbr(self,
1318 self.pg1.sw_if_index,
1319 self.pg1.remote_hosts[2].ip4))
1321 def test_arp_incomplete(self):
1322 """ Incomplete Entries """
1325 # ensure that we throttle the ARP and ND requests
1327 self.pg0.generate_remote_hosts(2)
1332 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1333 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1334 self.pg0.sw_if_index)])
1335 ip_10_0_0_1.add_vpp_config()
1337 p1 = (Ether(dst=self.pg1.local_mac,
1338 src=self.pg1.remote_mac) /
1339 IP(src=self.pg1.remote_ip4,
1341 UDP(sport=1234, dport=1234) /
1344 self.pg1.add_stream(p1 * 257)
1345 self.pg_enable_capture(self.pg_interfaces)
1347 rx = self.pg0._get_capture(1)
1350 # how many we get is going to be dependent on the time for packet
1351 # processing but it should be small
1353 self.assertLess(len(rx), 64)
1358 ip_10_1 = VppIpRoute(self, "10::1", 128,
1359 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1360 self.pg0.sw_if_index,
1361 proto=DpoProto.DPO_PROTO_IP6)],
1363 ip_10_1.add_vpp_config()
1365 p1 = (Ether(dst=self.pg1.local_mac,
1366 src=self.pg1.remote_mac) /
1367 IPv6(src=self.pg1.remote_ip6,
1369 UDP(sport=1234, dport=1234) /
1372 self.pg1.add_stream(p1 * 257)
1373 self.pg_enable_capture(self.pg_interfaces)
1375 rx = self.pg0._get_capture(1)
1378 # how many we get is going to be dependent on the time for packet
1379 # processing but it should be small
1381 self.assertLess(len(rx), 64)
1384 class NeighborStatsTestCase(VppTestCase):
1385 """ ARP Test Case """
1388 super(NeighborStatsTestCase, self).setUp()
1390 self.create_pg_interfaces(range(2))
1392 # pg0 configured with ip4 and 6 addresses used for input
1393 # pg1 configured with ip4 and 6 addresses used for output
1394 # pg2 is unnumbered to pg0
1395 for i in self.pg_interfaces:
1403 super(NeighborStatsTestCase, self).tearDown()
1405 for i in self.pg_interfaces:
1410 def test_arp_stats(self):
1411 """ ARP Counters """
1413 self.vapi.cli("adj counters enable")
1414 self.pg1.generate_remote_hosts(2)
1416 arp1 = VppNeighbor(self,
1417 self.pg1.sw_if_index,
1418 self.pg1.remote_hosts[0].mac,
1419 self.pg1.remote_hosts[0].ip4)
1420 arp1.add_vpp_config()
1421 arp2 = VppNeighbor(self,
1422 self.pg1.sw_if_index,
1423 self.pg1.remote_hosts[1].mac,
1424 self.pg1.remote_hosts[1].ip4)
1425 arp2.add_vpp_config()
1427 p1 = (Ether(dst=self.pg0.local_mac,
1428 src=self.pg0.remote_mac) /
1429 IP(src=self.pg0.remote_ip4,
1430 dst=self.pg1.remote_hosts[0].ip4) /
1431 UDP(sport=1234, dport=1234) /
1433 p2 = (Ether(dst=self.pg0.local_mac,
1434 src=self.pg0.remote_mac) /
1435 IP(src=self.pg0.remote_ip4,
1436 dst=self.pg1.remote_hosts[1].ip4) /
1437 UDP(sport=1234, dport=1234) /
1440 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1441 rx = self.send_and_expect(self.pg0, p2 * 65, self.pg1)
1443 self.assertEqual(65, arp1.get_stats()['packets'])
1444 self.assertEqual(65, arp2.get_stats()['packets'])
1446 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1447 self.assertEqual(130, arp1.get_stats()['packets'])
1449 def test_nd_stats(self):
1452 self.vapi.cli("adj counters enable")
1453 self.pg0.generate_remote_hosts(3)
1455 nd1 = VppNeighbor(self,
1456 self.pg0.sw_if_index,
1457 self.pg0.remote_hosts[1].mac,
1458 self.pg0.remote_hosts[1].ip6,
1460 nd1.add_vpp_config()
1461 nd2 = VppNeighbor(self,
1462 self.pg0.sw_if_index,
1463 self.pg0.remote_hosts[2].mac,
1464 self.pg0.remote_hosts[2].ip6,
1466 nd2.add_vpp_config()
1468 p1 = (Ether(dst=self.pg1.local_mac,
1469 src=self.pg1.remote_mac) /
1470 IPv6(src=self.pg1.remote_ip6,
1471 dst=self.pg0.remote_hosts[1].ip6) /
1472 UDP(sport=1234, dport=1234) /
1474 p2 = (Ether(dst=self.pg1.local_mac,
1475 src=self.pg1.remote_mac) /
1476 IPv6(src=self.pg1.remote_ip6,
1477 dst=self.pg0.remote_hosts[2].ip6) /
1478 UDP(sport=1234, dport=1234) /
1481 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1482 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1484 self.assertEqual(16, nd1.get_stats()['packets'])
1485 self.assertEqual(16, nd2.get_stats()['packets'])
1487 rx = self.send_and_expect(self.pg1, p1 * 65, self.pg0)
1488 self.assertEqual(81, nd1.get_stats()['packets'])
1491 if __name__ == '__main__':
1492 unittest.main(testRunner=VppTestRunner)