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, \
10 from vpp_papi import VppEnum
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether, ARP, Dot1Q
14 from scapy.layers.inet import IP, UDP
15 from scapy.layers.inet6 import IPv6
16 from scapy.contrib.mpls import MPLS
17 from scapy.layers.inet6 import IPv6
19 # not exported by scapy, so redefined here
20 arp_opts = {"who-has": 1, "is-at": 2}
23 class ARPTestCase(VppTestCase):
27 super(ARPTestCase, self).setUp()
29 # create 3 pg interfaces
30 self.create_pg_interfaces(range(4))
32 # pg0 configured with ip4 and 6 addresses used for input
33 # pg1 configured with ip4 and 6 addresses used for output
34 # pg2 is unnumbered to pg0
35 for i in self.pg_interfaces:
40 self.pg0.resolve_arp()
45 # pg3 in a different VRF
46 self.tbl = VppIpTable(self, 1)
47 self.tbl.add_vpp_config()
49 self.pg3.set_table_ip4(1)
53 self.pg0.unconfig_ip4()
54 self.pg0.unconfig_ip6()
56 self.pg1.unconfig_ip4()
57 self.pg1.unconfig_ip6()
59 self.pg3.unconfig_ip4()
60 self.pg3.set_table_ip4(0)
62 for i in self.pg_interfaces:
65 super(ARPTestCase, self).tearDown()
67 def verify_arp_req(self, rx, smac, sip, dip):
69 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
70 self.assertEqual(ether.src, smac)
73 self.assertEqual(arp.hwtype, 1)
74 self.assertEqual(arp.ptype, 0x800)
75 self.assertEqual(arp.hwlen, 6)
76 self.assertEqual(arp.plen, 4)
77 self.assertEqual(arp.op, arp_opts["who-has"])
78 self.assertEqual(arp.hwsrc, smac)
79 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
80 self.assertEqual(arp.psrc, sip)
81 self.assertEqual(arp.pdst, dip)
83 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
85 self.assertEqual(ether.dst, dmac)
86 self.assertEqual(ether.src, smac)
89 self.assertEqual(arp.hwtype, 1)
90 self.assertEqual(arp.ptype, 0x800)
91 self.assertEqual(arp.hwlen, 6)
92 self.assertEqual(arp.plen, 4)
93 self.assertEqual(arp.op, arp_opts["is-at"])
94 self.assertEqual(arp.hwsrc, smac)
95 self.assertEqual(arp.hwdst, dmac)
96 self.assertEqual(arp.psrc, sip)
97 self.assertEqual(arp.pdst, dip)
99 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
101 self.assertEqual(ether.dst, dmac)
102 self.assertEqual(ether.src, smac)
105 self.assertEqual(arp.hwtype, 1)
106 self.assertEqual(arp.ptype, 0x800)
107 self.assertEqual(arp.hwlen, 6)
108 self.assertEqual(arp.plen, 4)
109 self.assertEqual(arp.op, arp_opts["is-at"])
110 self.assertNotEqual(arp.hwsrc, smac)
111 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
112 "00:00:5E:00:01" in arp.hwsrc)
113 self.assertEqual(arp.hwdst, dmac)
114 self.assertEqual(arp.psrc, sip)
115 self.assertEqual(arp.pdst, dip)
117 def verify_ip(self, rx, smac, dmac, sip, dip):
119 self.assertEqual(ether.dst, dmac)
120 self.assertEqual(ether.src, smac)
123 self.assertEqual(ip.src, sip)
124 self.assertEqual(ip.dst, dip)
126 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
128 self.assertEqual(ether.dst, dmac)
129 self.assertEqual(ether.src, smac)
132 self.assertTrue(mpls.label, label)
135 self.assertEqual(ip.src, sip)
136 self.assertEqual(ip.dst, dip)
142 # Generate some hosts on the LAN
144 self.pg1.generate_remote_hosts(11)
147 # Send IP traffic to one of these unresolved hosts.
148 # expect the generation of an ARP request
150 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
151 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
152 UDP(sport=1234, dport=1234) /
155 self.pg0.add_stream(p)
156 self.pg_enable_capture(self.pg_interfaces)
159 rx = self.pg1.get_capture(1)
161 self.verify_arp_req(rx[0],
164 self.pg1._remote_hosts[1].ip4)
167 # And a dynamic ARP entry for host 1
169 dyn_arp = VppNeighbor(self,
170 self.pg1.sw_if_index,
171 self.pg1.remote_hosts[1].mac,
172 self.pg1.remote_hosts[1].ip4)
173 dyn_arp.add_vpp_config()
176 # now we expect IP traffic forwarded
178 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
179 IP(src=self.pg0.remote_ip4,
180 dst=self.pg1._remote_hosts[1].ip4) /
181 UDP(sport=1234, dport=1234) /
184 self.pg0.add_stream(dyn_p)
185 self.pg_enable_capture(self.pg_interfaces)
188 rx = self.pg1.get_capture(1)
190 self.verify_ip(rx[0],
192 self.pg1.remote_hosts[1].mac,
194 self.pg1._remote_hosts[1].ip4)
197 # And a Static ARP entry for host 2
199 static_arp = VppNeighbor(self,
200 self.pg1.sw_if_index,
201 self.pg1.remote_hosts[2].mac,
202 self.pg1.remote_hosts[2].ip4,
204 static_arp.add_vpp_config()
206 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
207 IP(src=self.pg0.remote_ip4,
208 dst=self.pg1._remote_hosts[2].ip4) /
209 UDP(sport=1234, dport=1234) /
212 self.pg0.add_stream(static_p)
213 self.pg_enable_capture(self.pg_interfaces)
216 rx = self.pg1.get_capture(1)
218 self.verify_ip(rx[0],
220 self.pg1.remote_hosts[2].mac,
222 self.pg1._remote_hosts[2].ip4)
225 # flap the link. dynamic ARPs get flush, statics don't
227 self.pg1.admin_down()
230 self.pg0.add_stream(static_p)
231 self.pg_enable_capture(self.pg_interfaces)
233 rx = self.pg1.get_capture(1)
235 self.verify_ip(rx[0],
237 self.pg1.remote_hosts[2].mac,
239 self.pg1._remote_hosts[2].ip4)
241 self.pg0.add_stream(dyn_p)
242 self.pg_enable_capture(self.pg_interfaces)
245 rx = self.pg1.get_capture(1)
246 self.verify_arp_req(rx[0],
249 self.pg1._remote_hosts[1].ip4)
252 # Send an ARP request from one of the so-far unlearned remote hosts
254 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
255 src=self.pg1._remote_hosts[3].mac) /
257 hwsrc=self.pg1._remote_hosts[3].mac,
258 pdst=self.pg1.local_ip4,
259 psrc=self.pg1._remote_hosts[3].ip4))
261 self.pg1.add_stream(p)
262 self.pg_enable_capture(self.pg_interfaces)
265 rx = self.pg1.get_capture(1)
266 self.verify_arp_resp(rx[0],
268 self.pg1._remote_hosts[3].mac,
270 self.pg1._remote_hosts[3].ip4)
273 # VPP should have learned the mapping for the remote host
275 self.assertTrue(find_nbr(self,
276 self.pg1.sw_if_index,
277 self.pg1._remote_hosts[3].ip4))
279 # Fire in an ARP request before the interface becomes IP enabled
281 self.pg2.generate_remote_hosts(4)
283 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
285 hwsrc=self.pg2.remote_mac,
286 pdst=self.pg1.local_ip4,
287 psrc=self.pg2.remote_hosts[3].ip4))
288 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
291 hwsrc=self.pg2.remote_mac,
292 pdst=self.pg1.local_ip4,
293 psrc=self.pg2.remote_hosts[3].ip4))
294 self.send_and_assert_no_replies(self.pg2, p,
295 "interface not IP enabled")
298 # Make pg2 un-numbered to pg1
300 self.pg2.set_unnumbered(self.pg1.sw_if_index)
302 unnum = self.vapi.ip_unnumbered_dump()
303 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
304 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
307 # We should respond to ARP requests for the unnumbered to address
308 # once an attached route to the source is known
310 self.send_and_assert_no_replies(
312 "ARP req for unnumbered address - no source")
314 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
315 [VppRoutePath("0.0.0.0",
316 self.pg2.sw_if_index)])
317 attached_host.add_vpp_config()
319 self.pg2.add_stream(p)
320 self.pg_enable_capture(self.pg_interfaces)
323 rx = self.pg2.get_capture(1)
324 self.verify_arp_resp(rx[0],
328 self.pg2.remote_hosts[3].ip4)
330 self.pg2.add_stream(pt)
331 self.pg_enable_capture(self.pg_interfaces)
334 rx = self.pg2.get_capture(1)
335 self.verify_arp_resp(rx[0],
339 self.pg2.remote_hosts[3].ip4)
342 # A neighbor entry that has no associated FIB-entry
344 arp_no_fib = VppNeighbor(self,
345 self.pg1.sw_if_index,
346 self.pg1.remote_hosts[4].mac,
347 self.pg1.remote_hosts[4].ip4,
349 arp_no_fib.add_vpp_config()
352 # check we have the neighbor, but no route
354 self.assertTrue(find_nbr(self,
355 self.pg1.sw_if_index,
356 self.pg1._remote_hosts[4].ip4))
357 self.assertFalse(find_route(self,
358 self.pg1._remote_hosts[4].ip4,
361 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
362 # from within pg1's subnet
364 arp_unnum = VppNeighbor(self,
365 self.pg2.sw_if_index,
366 self.pg1.remote_hosts[5].mac,
367 self.pg1.remote_hosts[5].ip4)
368 arp_unnum.add_vpp_config()
370 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
371 IP(src=self.pg0.remote_ip4,
372 dst=self.pg1._remote_hosts[5].ip4) /
373 UDP(sport=1234, dport=1234) /
376 self.pg0.add_stream(p)
377 self.pg_enable_capture(self.pg_interfaces)
380 rx = self.pg2.get_capture(1)
382 self.verify_ip(rx[0],
384 self.pg1.remote_hosts[5].mac,
386 self.pg1._remote_hosts[5].ip4)
389 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
390 # with the unnumbered interface's address as the source
392 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
394 hwsrc=self.pg2.remote_mac,
395 pdst=self.pg1.local_ip4,
396 psrc=self.pg1.remote_hosts[6].ip4))
398 self.pg2.add_stream(p)
399 self.pg_enable_capture(self.pg_interfaces)
402 rx = self.pg2.get_capture(1)
403 self.verify_arp_resp(rx[0],
407 self.pg1.remote_hosts[6].ip4)
410 # An attached host route out of pg2 for an undiscovered hosts generates
411 # an ARP request with the unnumbered address as the source
413 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
414 [VppRoutePath("0.0.0.0",
415 self.pg2.sw_if_index)])
416 att_unnum.add_vpp_config()
418 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
419 IP(src=self.pg0.remote_ip4,
420 dst=self.pg1._remote_hosts[7].ip4) /
421 UDP(sport=1234, dport=1234) /
424 self.pg0.add_stream(p)
425 self.pg_enable_capture(self.pg_interfaces)
428 rx = self.pg2.get_capture(1)
430 self.verify_arp_req(rx[0],
433 self.pg1._remote_hosts[7].ip4)
435 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
437 hwsrc=self.pg2.remote_mac,
438 pdst=self.pg1.local_ip4,
439 psrc=self.pg1.remote_hosts[7].ip4))
441 self.pg2.add_stream(p)
442 self.pg_enable_capture(self.pg_interfaces)
445 rx = self.pg2.get_capture(1)
446 self.verify_arp_resp(rx[0],
450 self.pg1.remote_hosts[7].ip4)
453 # An attached host route as yet unresolved out of pg2 for an
454 # undiscovered host, an ARP requests begets a response.
456 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
457 [VppRoutePath("0.0.0.0",
458 self.pg2.sw_if_index)])
459 att_unnum1.add_vpp_config()
461 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
463 hwsrc=self.pg2.remote_mac,
464 pdst=self.pg1.local_ip4,
465 psrc=self.pg1.remote_hosts[8].ip4))
467 self.pg2.add_stream(p)
468 self.pg_enable_capture(self.pg_interfaces)
471 rx = self.pg2.get_capture(1)
472 self.verify_arp_resp(rx[0],
476 self.pg1.remote_hosts[8].ip4)
479 # Send an ARP request from one of the so-far unlearned remote hosts
482 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
483 src=self.pg1._remote_hosts[9].mac) /
486 hwsrc=self.pg1._remote_hosts[9].mac,
487 pdst=self.pg1.local_ip4,
488 psrc=self.pg1._remote_hosts[9].ip4))
490 self.pg1.add_stream(p)
491 self.pg_enable_capture(self.pg_interfaces)
494 rx = self.pg1.get_capture(1)
495 self.verify_arp_resp(rx[0],
497 self.pg1._remote_hosts[9].mac,
499 self.pg1._remote_hosts[9].ip4)
502 # Add a hierachy of routes for a host in the sub-net.
503 # Should still get an ARP resp since the cover is attached
505 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
507 hwsrc=self.pg1.remote_mac,
508 pdst=self.pg1.local_ip4,
509 psrc=self.pg1.remote_hosts[10].ip4))
511 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
512 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
513 self.pg1.sw_if_index)])
516 self.pg1.add_stream(p)
517 self.pg_enable_capture(self.pg_interfaces)
519 rx = self.pg1.get_capture(1)
520 self.verify_arp_resp(rx[0],
524 self.pg1.remote_hosts[10].ip4)
526 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
527 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
528 self.pg1.sw_if_index)])
531 self.pg1.add_stream(p)
532 self.pg_enable_capture(self.pg_interfaces)
534 rx = self.pg1.get_capture(1)
535 self.verify_arp_resp(rx[0],
539 self.pg1.remote_hosts[10].ip4)
542 # add an ARP entry that's not on the sub-net and so whose
543 # adj-fib fails the refinement check. then send an ARP request
546 a1 = VppNeighbor(self,
547 self.pg0.sw_if_index,
552 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
554 hwsrc=self.pg0.remote_mac,
555 psrc="100.100.100.50",
556 pdst=self.pg0.remote_ip4))
557 self.send_and_assert_no_replies(self.pg0, p,
558 "ARP req for from failed adj-fib")
562 # 1 - don't respond to ARP request for address not within the
563 # interface's sub-net
564 # 1b - nor within the unnumbered subnet
565 # 1c - nor within the subnet of a different interface
567 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
569 hwsrc=self.pg0.remote_mac,
571 psrc=self.pg0.remote_ip4))
572 self.send_and_assert_no_replies(self.pg0, p,
573 "ARP req for non-local destination")
574 self.assertFalse(find_nbr(self,
575 self.pg0.sw_if_index,
578 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
580 hwsrc=self.pg2.remote_mac,
582 psrc=self.pg1.remote_hosts[7].ip4))
583 self.send_and_assert_no_replies(
585 "ARP req for non-local destination - unnum")
587 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
589 hwsrc=self.pg0.remote_mac,
590 pdst=self.pg1.local_ip4,
591 psrc=self.pg1.remote_ip4))
592 self.send_and_assert_no_replies(self.pg0, p,
593 "ARP req diff sub-net")
594 self.assertFalse(find_nbr(self,
595 self.pg0.sw_if_index,
596 self.pg1.remote_ip4))
599 # 2 - don't respond to ARP request from an address not within the
600 # interface's sub-net
601 # 2b - to a prxied address
602 # 2c - not within a differents interface's sub-net
603 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
605 hwsrc=self.pg0.remote_mac,
607 pdst=self.pg0.local_ip4))
608 self.send_and_assert_no_replies(self.pg0, p,
609 "ARP req for non-local source")
610 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
612 hwsrc=self.pg2.remote_mac,
614 pdst=self.pg0.local_ip4))
615 self.send_and_assert_no_replies(
617 "ARP req for non-local source - unnum")
618 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
620 hwsrc=self.pg0.remote_mac,
621 psrc=self.pg1.remote_ip4,
622 pdst=self.pg0.local_ip4))
623 self.send_and_assert_no_replies(self.pg0, p,
624 "ARP req for non-local source 2c")
627 # 3 - don't respond to ARP request from an address that belongs to
630 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
632 hwsrc=self.pg0.remote_mac,
633 psrc=self.pg0.local_ip4,
634 pdst=self.pg0.local_ip4))
635 self.send_and_assert_no_replies(self.pg0, p,
636 "ARP req for non-local source")
639 # 4 - don't respond to ARP requests that has mac source different
640 # from ARP request HW source
642 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
644 hwsrc="00:00:00:DE:AD:BE",
645 psrc=self.pg0.remote_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 # 5 - don't respond to ARP requests for address within the
652 # interface's sub-net but not the interface's address
654 self.pg0.generate_remote_hosts(2)
655 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
657 hwsrc=self.pg0.remote_mac,
658 psrc=self.pg0.remote_hosts[0].ip4,
659 pdst=self.pg0.remote_hosts[1].ip4))
660 self.send_and_assert_no_replies(self.pg0, p,
661 "ARP req for non-local destination")
666 dyn_arp.remove_vpp_config()
667 static_arp.remove_vpp_config()
668 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
670 # need this to flush the adj-fibs
671 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
672 self.pg2.admin_down()
673 self.pg1.admin_down()
675 def test_proxy_mirror_arp(self):
676 """ Interface Mirror Proxy ARP """
679 # When VPP has an interface whose address is also applied to a TAP
680 # interface on the host, then VPP's TAP interface will be unnumbered
681 # to the 'real' interface and do proxy ARP from the host.
682 # the curious aspect of this setup is that ARP requests from the host
683 # will come from the VPP's own address.
685 self.pg0.generate_remote_hosts(2)
687 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
688 dst="ff:ff:ff:ff:ff:ff") /
690 hwsrc=self.pg2.remote_mac,
691 pdst=self.pg0.remote_hosts[1].ip4,
692 psrc=self.pg0.local_ip4))
695 # Configure Proxy ARP for the subnet on PG0addresses on pg0
697 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
698 self.pg0._local_ip4_bcast)
700 # Make pg2 un-numbered to pg0
702 self.pg2.set_unnumbered(self.pg0.sw_if_index)
705 # Enable pg2 for proxy ARP
707 self.pg2.set_proxy_arp()
710 # Send the ARP request with an originating address that
711 # is VPP's own address
713 self.pg2.add_stream(arp_req_from_me)
714 self.pg_enable_capture(self.pg_interfaces)
717 rx = self.pg2.get_capture(1)
718 self.verify_arp_resp(rx[0],
721 self.pg0.remote_hosts[1].ip4,
725 # validate we have not learned an ARP entry as a result of this
727 self.assertFalse(find_nbr(self,
728 self.pg2.sw_if_index,
734 self.pg2.set_proxy_arp(0)
735 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
736 self.pg0._local_ip4_bcast,
739 def test_proxy_arp(self):
742 self.pg1.generate_remote_hosts(2)
745 # Proxy ARP rewquest packets for each interface
747 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
748 dst="ff:ff:ff:ff:ff:ff") /
750 hwsrc=self.pg0.remote_mac,
752 psrc=self.pg0.remote_ip4))
753 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
754 dst="ff:ff:ff:ff:ff:ff") /
757 hwsrc=self.pg0.remote_mac,
759 psrc=self.pg0.remote_ip4))
760 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
761 dst="ff:ff:ff:ff:ff:ff") /
763 hwsrc=self.pg1.remote_mac,
765 psrc=self.pg1.remote_ip4))
766 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
767 dst="ff:ff:ff:ff:ff:ff") /
769 hwsrc=self.pg2.remote_mac,
771 psrc=self.pg1.remote_hosts[1].ip4))
772 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
773 dst="ff:ff:ff:ff:ff:ff") /
775 hwsrc=self.pg3.remote_mac,
777 psrc=self.pg3.remote_ip4))
780 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
782 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
783 inet_pton(AF_INET, "10.10.10.124"))
786 # No responses are sent when the interfaces are not enabled for proxy
789 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
790 "ARP req from unconfigured interface")
791 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
792 "ARP req from unconfigured interface")
795 # Make pg2 un-numbered to pg1
798 self.pg2.set_unnumbered(self.pg1.sw_if_index)
800 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
801 "ARP req from unnumbered interface")
804 # Enable each interface to reply to proxy ARPs
806 for i in self.pg_interfaces:
810 # Now each of the interfaces should reply to a request to a proxied
813 self.pg0.add_stream(arp_req_pg0)
814 self.pg_enable_capture(self.pg_interfaces)
817 rx = self.pg0.get_capture(1)
818 self.verify_arp_resp(rx[0],
824 self.pg0.add_stream(arp_req_pg0_tagged)
825 self.pg_enable_capture(self.pg_interfaces)
828 rx = self.pg0.get_capture(1)
829 self.verify_arp_resp(rx[0],
835 self.pg1.add_stream(arp_req_pg1)
836 self.pg_enable_capture(self.pg_interfaces)
839 rx = self.pg1.get_capture(1)
840 self.verify_arp_resp(rx[0],
846 self.pg2.add_stream(arp_req_pg2)
847 self.pg_enable_capture(self.pg_interfaces)
850 rx = self.pg2.get_capture(1)
851 self.verify_arp_resp(rx[0],
855 self.pg1.remote_hosts[1].ip4)
858 # A request for an address out of the configured range
860 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
861 dst="ff:ff:ff:ff:ff:ff") /
863 hwsrc=self.pg1.remote_mac,
865 psrc=self.pg1.remote_ip4))
866 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
867 "ARP req out of range HI")
868 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
869 dst="ff:ff:ff:ff:ff:ff") /
871 hwsrc=self.pg1.remote_mac,
873 psrc=self.pg1.remote_ip4))
874 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
875 "ARP req out of range Low")
878 # Request for an address in the proxy range but from an interface
881 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
882 "ARP req from different VRF")
885 # Disable Each interface for proxy ARP
886 # - expect none to respond
888 for i in self.pg_interfaces:
891 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
892 "ARP req from disable")
893 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
894 "ARP req from disable")
895 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
896 "ARP req from disable")
899 # clean up on interface 2
901 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
907 # Interface 2 does not yet have ip4 config
909 self.pg2.config_ip4()
910 self.pg2.generate_remote_hosts(2)
913 # Add a reoute with out going label via an ARP unresolved next-hop
915 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
916 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
917 self.pg2.sw_if_index,
919 ip_10_0_0_1.add_vpp_config()
922 # packets should generate an ARP request
924 p = (Ether(src=self.pg0.remote_mac,
925 dst=self.pg0.local_mac) /
926 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
927 UDP(sport=1234, dport=1234) /
930 self.pg0.add_stream(p)
931 self.pg_enable_capture(self.pg_interfaces)
934 rx = self.pg2.get_capture(1)
935 self.verify_arp_req(rx[0],
938 self.pg2._remote_hosts[1].ip4)
941 # now resolve the neighbours
943 self.pg2.configure_ipv4_neighbors()
946 # Now packet should be properly MPLS encapped.
947 # This verifies that MPLS link-type adjacencies are completed
948 # when the ARP entry resolves
950 self.pg0.add_stream(p)
951 self.pg_enable_capture(self.pg_interfaces)
954 rx = self.pg2.get_capture(1)
955 self.verify_ip_o_mpls(rx[0],
957 self.pg2.remote_hosts[1].mac,
961 self.pg2.unconfig_ip4()
963 def test_arp_vrrp(self):
964 """ ARP reply with VRRP virtual src hw addr """
967 # IP packet destined for pg1 remote host arrives on pg0 resulting
968 # in an ARP request for the address of the remote host on pg1
970 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
971 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
972 UDP(sport=1234, dport=1234) /
975 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
977 self.verify_arp_req(rx1[0],
983 # ARP reply for address of pg1 remote host arrives on pg1 with
984 # the hw src addr set to a value in the VRRP IPv4 range of
987 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
988 ARP(op="is-at", hwdst=self.pg1.local_mac,
989 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
990 psrc=self.pg1.remote_ip4))
992 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
995 # IP packet destined for pg1 remote host arrives on pg0 again.
996 # VPP should have an ARP entry for that address now and the packet
997 # should be sent out pg1.
999 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1001 self.verify_ip(rx1[0],
1003 "00:00:5e:00:01:09",
1004 self.pg0.remote_ip4,
1005 self.pg1.remote_ip4)
1007 self.pg1.admin_down()
1010 def test_arp_duplicates(self):
1011 """ ARP Duplicates"""
1014 # Generate some hosts on the LAN
1016 self.pg1.generate_remote_hosts(3)
1019 # Add host 1 on pg1 and pg2
1021 arp_pg1 = VppNeighbor(self,
1022 self.pg1.sw_if_index,
1023 self.pg1.remote_hosts[1].mac,
1024 self.pg1.remote_hosts[1].ip4)
1025 arp_pg1.add_vpp_config()
1026 arp_pg2 = VppNeighbor(self,
1027 self.pg2.sw_if_index,
1028 self.pg2.remote_mac,
1029 self.pg1.remote_hosts[1].ip4)
1030 arp_pg2.add_vpp_config()
1033 # IP packet destined for pg1 remote host arrives on pg1 again.
1035 p = (Ether(dst=self.pg0.local_mac,
1036 src=self.pg0.remote_mac) /
1037 IP(src=self.pg0.remote_ip4,
1038 dst=self.pg1.remote_hosts[1].ip4) /
1039 UDP(sport=1234, dport=1234) /
1042 self.pg0.add_stream(p)
1043 self.pg_enable_capture(self.pg_interfaces)
1046 rx1 = self.pg1.get_capture(1)
1048 self.verify_ip(rx1[0],
1050 self.pg1.remote_hosts[1].mac,
1051 self.pg0.remote_ip4,
1052 self.pg1.remote_hosts[1].ip4)
1055 # remove the duplicate on pg1
1056 # packet stream shoud generate ARPs out of pg1
1058 arp_pg1.remove_vpp_config()
1060 self.pg0.add_stream(p)
1061 self.pg_enable_capture(self.pg_interfaces)
1064 rx1 = self.pg1.get_capture(1)
1066 self.verify_arp_req(rx1[0],
1069 self.pg1.remote_hosts[1].ip4)
1074 arp_pg1.add_vpp_config()
1076 self.pg0.add_stream(p)
1077 self.pg_enable_capture(self.pg_interfaces)
1080 rx1 = self.pg1.get_capture(1)
1082 self.verify_ip(rx1[0],
1084 self.pg1.remote_hosts[1].mac,
1085 self.pg0.remote_ip4,
1086 self.pg1.remote_hosts[1].ip4)
1088 def test_arp_static(self):
1090 self.pg2.generate_remote_hosts(3)
1093 # Add a static ARP entry
1095 static_arp = VppNeighbor(self,
1096 self.pg2.sw_if_index,
1097 self.pg2.remote_hosts[1].mac,
1098 self.pg2.remote_hosts[1].ip4,
1100 static_arp.add_vpp_config()
1103 # Add the connected prefix to the interface
1105 self.pg2.config_ip4()
1108 # We should now find the adj-fib
1110 self.assertTrue(find_nbr(self,
1111 self.pg2.sw_if_index,
1112 self.pg2.remote_hosts[1].ip4,
1114 self.assertTrue(find_route(self,
1115 self.pg2.remote_hosts[1].ip4,
1119 # remove the connected
1121 self.pg2.unconfig_ip4()
1124 # put the interface into table 1
1126 self.pg2.set_table_ip4(1)
1129 # configure the same connected and expect to find the
1130 # adj fib in the new table
1132 self.pg2.config_ip4()
1133 self.assertTrue(find_route(self,
1134 self.pg2.remote_hosts[1].ip4,
1141 self.pg2.unconfig_ip4()
1142 self.pg2.set_table_ip4(0)
1144 def test_arp_incomplete(self):
1145 """ ARP Incomplete"""
1146 self.pg1.generate_remote_hosts(3)
1148 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1149 IP(src=self.pg0.remote_ip4,
1150 dst=self.pg1.remote_hosts[1].ip4) /
1151 UDP(sport=1234, dport=1234) /
1153 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1154 IP(src=self.pg0.remote_ip4,
1155 dst=self.pg1.remote_hosts[2].ip4) /
1156 UDP(sport=1234, dport=1234) /
1160 # a packet to an unresolved destination generates an ARP request
1162 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1163 self.verify_arp_req(rx[0],
1166 self.pg1._remote_hosts[1].ip4)
1169 # add a neighbour for remote host 1
1171 static_arp = VppNeighbor(self,
1172 self.pg1.sw_if_index,
1173 self.pg1.remote_hosts[1].mac,
1174 self.pg1.remote_hosts[1].ip4,
1176 static_arp.add_vpp_config()
1179 # change the interface's MAC
1181 mac = [chr(0x00), chr(0x00), chr(0x00),
1182 chr(0x33), chr(0x33), chr(0x33)]
1183 mac_string = ''.join(mac)
1185 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1189 # now ARP requests come from the new source mac
1191 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1192 self.verify_arp_req(rx[0],
1193 "00:00:00:33:33:33",
1195 self.pg1._remote_hosts[2].ip4)
1198 # packets to the resolved host also have the new source mac
1200 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1201 self.verify_ip(rx[0],
1202 "00:00:00:33:33:33",
1203 self.pg1.remote_hosts[1].mac,
1204 self.pg0.remote_ip4,
1205 self.pg1.remote_hosts[1].ip4)
1208 # set the mac address on the inteface that does not have a
1209 # configured subnet and thus no glean
1211 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1214 def test_garp(self):
1218 # Generate some hosts on the LAN
1220 self.pg1.generate_remote_hosts(4)
1225 arp = VppNeighbor(self,
1226 self.pg1.sw_if_index,
1227 self.pg1.remote_hosts[1].mac,
1228 self.pg1.remote_hosts[1].ip4)
1229 arp.add_vpp_config()
1231 self.assertTrue(find_nbr(self,
1232 self.pg1.sw_if_index,
1233 self.pg1.remote_hosts[1].ip4,
1234 mac=self.pg1.remote_hosts[1].mac))
1237 # Send a GARP (request) to swap the host 1's address to that of host 2
1239 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1240 src=self.pg1.remote_hosts[2].mac) /
1242 hwdst=self.pg1.local_mac,
1243 hwsrc=self.pg1.remote_hosts[2].mac,
1244 pdst=self.pg1.remote_hosts[1].ip4,
1245 psrc=self.pg1.remote_hosts[1].ip4))
1247 self.pg1.add_stream(p1)
1248 self.pg_enable_capture(self.pg_interfaces)
1251 self.assertTrue(find_nbr(self,
1252 self.pg1.sw_if_index,
1253 self.pg1.remote_hosts[1].ip4,
1254 mac=self.pg1.remote_hosts[2].mac))
1257 # Send a GARP (reply) to swap the host 1's address to that of host 3
1259 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1260 src=self.pg1.remote_hosts[3].mac) /
1262 hwdst=self.pg1.local_mac,
1263 hwsrc=self.pg1.remote_hosts[3].mac,
1264 pdst=self.pg1.remote_hosts[1].ip4,
1265 psrc=self.pg1.remote_hosts[1].ip4))
1267 self.pg1.add_stream(p1)
1268 self.pg_enable_capture(self.pg_interfaces)
1271 self.assertTrue(find_nbr(self,
1272 self.pg1.sw_if_index,
1273 self.pg1.remote_hosts[1].ip4,
1274 mac=self.pg1.remote_hosts[3].mac))
1277 # GARPs (requets nor replies) for host we don't know yet
1278 # don't result in new neighbour entries
1280 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1281 src=self.pg1.remote_hosts[3].mac) /
1283 hwdst=self.pg1.local_mac,
1284 hwsrc=self.pg1.remote_hosts[3].mac,
1285 pdst=self.pg1.remote_hosts[2].ip4,
1286 psrc=self.pg1.remote_hosts[2].ip4))
1288 self.pg1.add_stream(p1)
1289 self.pg_enable_capture(self.pg_interfaces)
1292 self.assertFalse(find_nbr(self,
1293 self.pg1.sw_if_index,
1294 self.pg1.remote_hosts[2].ip4))
1296 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1297 src=self.pg1.remote_hosts[3].mac) /
1299 hwdst=self.pg1.local_mac,
1300 hwsrc=self.pg1.remote_hosts[3].mac,
1301 pdst=self.pg1.remote_hosts[2].ip4,
1302 psrc=self.pg1.remote_hosts[2].ip4))
1304 self.pg1.add_stream(p1)
1305 self.pg_enable_capture(self.pg_interfaces)
1308 self.assertFalse(find_nbr(self,
1309 self.pg1.sw_if_index,
1310 self.pg1.remote_hosts[2].ip4))
1312 def test_arp_incomplete(self):
1313 """ Incomplete Entries """
1316 # ensure that we throttle the ARP and ND requests
1318 self.pg0.generate_remote_hosts(2)
1323 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1324 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1325 self.pg0.sw_if_index)])
1326 ip_10_0_0_1.add_vpp_config()
1328 p1 = (Ether(dst=self.pg1.local_mac,
1329 src=self.pg1.remote_mac) /
1330 IP(src=self.pg1.remote_ip4,
1332 UDP(sport=1234, dport=1234) /
1335 self.pg1.add_stream(p1 * 257)
1336 self.pg_enable_capture(self.pg_interfaces)
1338 rx = self.pg0._get_capture(1)
1341 # how many we get is going to be dependent on the time for packet
1342 # processing but it should be small
1344 self.assertLess(len(rx), 64)
1349 ip_10_1 = VppIpRoute(self, "10::1", 128,
1350 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1351 self.pg0.sw_if_index,
1352 proto=DpoProto.DPO_PROTO_IP6)],
1354 ip_10_1.add_vpp_config()
1356 p1 = (Ether(dst=self.pg1.local_mac,
1357 src=self.pg1.remote_mac) /
1358 IPv6(src=self.pg1.remote_ip6,
1360 UDP(sport=1234, dport=1234) /
1363 self.pg1.add_stream(p1 * 257)
1364 self.pg_enable_capture(self.pg_interfaces)
1366 rx = self.pg0._get_capture(1)
1369 # how many we get is going to be dependent on the time for packet
1370 # processing but it should be small
1372 self.assertLess(len(rx), 64)
1374 def test_arp_forus(self):
1375 """ ARP for for-us """
1378 # Test that VPP responds with ARP requests to addresses that
1379 # are connected and local routes.
1380 # Use one of the 'remote' addresses in the subnet as a local address
1381 # The intention of this route is that it then acts like a secondardy
1382 # address added to an interface
1384 self.pg0.generate_remote_hosts(2)
1386 forus = VppIpRoute(self, self.pg0.remote_hosts[1].ip4, 32,
1387 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1388 self.pg0.sw_if_index)],
1390 forus.add_vpp_config()
1392 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1393 src=self.pg0.remote_mac) /
1395 hwdst=self.pg0.local_mac,
1396 hwsrc=self.pg0.remote_mac,
1397 pdst=self.pg0.remote_hosts[1].ip4,
1398 psrc=self.pg0.remote_ip4))
1400 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1402 self.verify_arp_resp(rx[0],
1404 self.pg0.remote_mac,
1405 self.pg0.remote_hosts[1].ip4,
1406 self.pg0.remote_ip4)
1409 class NeighborStatsTestCase(VppTestCase):
1410 """ ARP/ND Counters """
1413 super(NeighborStatsTestCase, self).setUp()
1415 self.create_pg_interfaces(range(2))
1417 # pg0 configured with ip4 and 6 addresses used for input
1418 # pg1 configured with ip4 and 6 addresses used for output
1419 # pg2 is unnumbered to pg0
1420 for i in self.pg_interfaces:
1428 super(NeighborStatsTestCase, self).tearDown()
1430 for i in self.pg_interfaces:
1435 def test_arp_stats(self):
1436 """ ARP Counters """
1438 self.vapi.cli("adj counters enable")
1439 self.pg1.generate_remote_hosts(2)
1441 arp1 = VppNeighbor(self,
1442 self.pg1.sw_if_index,
1443 self.pg1.remote_hosts[0].mac,
1444 self.pg1.remote_hosts[0].ip4)
1445 arp1.add_vpp_config()
1446 arp2 = VppNeighbor(self,
1447 self.pg1.sw_if_index,
1448 self.pg1.remote_hosts[1].mac,
1449 self.pg1.remote_hosts[1].ip4)
1450 arp2.add_vpp_config()
1452 p1 = (Ether(dst=self.pg0.local_mac,
1453 src=self.pg0.remote_mac) /
1454 IP(src=self.pg0.remote_ip4,
1455 dst=self.pg1.remote_hosts[0].ip4) /
1456 UDP(sport=1234, dport=1234) /
1458 p2 = (Ether(dst=self.pg0.local_mac,
1459 src=self.pg0.remote_mac) /
1460 IP(src=self.pg0.remote_ip4,
1461 dst=self.pg1.remote_hosts[1].ip4) /
1462 UDP(sport=1234, dport=1234) /
1465 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1466 rx = self.send_and_expect(self.pg0, p2 * 65, self.pg1)
1468 self.assertEqual(65, arp1.get_stats()['packets'])
1469 self.assertEqual(65, arp2.get_stats()['packets'])
1471 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1472 self.assertEqual(130, arp1.get_stats()['packets'])
1474 def test_nd_stats(self):
1477 self.vapi.cli("adj counters enable")
1478 self.pg0.generate_remote_hosts(3)
1480 nd1 = VppNeighbor(self,
1481 self.pg0.sw_if_index,
1482 self.pg0.remote_hosts[1].mac,
1483 self.pg0.remote_hosts[1].ip6)
1484 nd1.add_vpp_config()
1485 nd2 = VppNeighbor(self,
1486 self.pg0.sw_if_index,
1487 self.pg0.remote_hosts[2].mac,
1488 self.pg0.remote_hosts[2].ip6)
1489 nd2.add_vpp_config()
1491 p1 = (Ether(dst=self.pg1.local_mac,
1492 src=self.pg1.remote_mac) /
1493 IPv6(src=self.pg1.remote_ip6,
1494 dst=self.pg0.remote_hosts[1].ip6) /
1495 UDP(sport=1234, dport=1234) /
1497 p2 = (Ether(dst=self.pg1.local_mac,
1498 src=self.pg1.remote_mac) /
1499 IPv6(src=self.pg1.remote_ip6,
1500 dst=self.pg0.remote_hosts[2].ip6) /
1501 UDP(sport=1234, dport=1234) /
1504 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1505 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1507 self.assertEqual(16, nd1.get_stats()['packets'])
1508 self.assertEqual(16, nd2.get_stats()['packets'])
1510 rx = self.send_and_expect(self.pg1, p1 * 65, self.pg0)
1511 self.assertEqual(81, nd1.get_stats()['packets'])
1514 if __name__ == '__main__':
1515 unittest.main(testRunner=VppTestRunner)