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
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
20 # not exported by scapy, so redefined here
21 arp_opts = {"who-has": 1, "is-at": 2}
24 class ARPTestCase(VppTestCase):
29 super(ARPTestCase, cls).setUpClass()
32 def tearDownClass(cls):
33 super(ARPTestCase, cls).tearDownClass()
36 super(ARPTestCase, self).setUp()
38 # create 3 pg interfaces
39 self.create_pg_interfaces(range(4))
41 # pg0 configured with ip4 and 6 addresses used for input
42 # pg1 configured with ip4 and 6 addresses used for output
43 # pg2 is unnumbered to pg0
44 for i in self.pg_interfaces:
49 self.pg0.resolve_arp()
54 # pg3 in a different VRF
55 self.tbl = VppIpTable(self, 1)
56 self.tbl.add_vpp_config()
58 self.pg3.set_table_ip4(1)
62 self.pg0.unconfig_ip4()
63 self.pg0.unconfig_ip6()
65 self.pg1.unconfig_ip4()
66 self.pg1.unconfig_ip6()
68 self.pg3.unconfig_ip4()
69 self.pg3.set_table_ip4(0)
71 for i in self.pg_interfaces:
74 super(ARPTestCase, self).tearDown()
76 def verify_arp_req(self, rx, smac, sip, dip):
78 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
79 self.assertEqual(ether.src, smac)
82 self.assertEqual(arp.hwtype, 1)
83 self.assertEqual(arp.ptype, 0x800)
84 self.assertEqual(arp.hwlen, 6)
85 self.assertEqual(arp.plen, 4)
86 self.assertEqual(arp.op, arp_opts["who-has"])
87 self.assertEqual(arp.hwsrc, smac)
88 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
89 self.assertEqual(arp.psrc, sip)
90 self.assertEqual(arp.pdst, dip)
92 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
94 self.assertEqual(ether.dst, dmac)
95 self.assertEqual(ether.src, smac)
98 self.assertEqual(arp.hwtype, 1)
99 self.assertEqual(arp.ptype, 0x800)
100 self.assertEqual(arp.hwlen, 6)
101 self.assertEqual(arp.plen, 4)
102 self.assertEqual(arp.op, arp_opts["is-at"])
103 self.assertEqual(arp.hwsrc, smac)
104 self.assertEqual(arp.hwdst, dmac)
105 self.assertEqual(arp.psrc, sip)
106 self.assertEqual(arp.pdst, dip)
108 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
110 self.assertEqual(ether.dst, dmac)
111 self.assertEqual(ether.src, smac)
114 self.assertEqual(arp.hwtype, 1)
115 self.assertEqual(arp.ptype, 0x800)
116 self.assertEqual(arp.hwlen, 6)
117 self.assertEqual(arp.plen, 4)
118 self.assertEqual(arp.op, arp_opts["is-at"])
119 self.assertNotEqual(arp.hwsrc, smac)
120 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
121 "00:00:5E:00:01" in arp.hwsrc)
122 self.assertEqual(arp.hwdst, dmac)
123 self.assertEqual(arp.psrc, sip)
124 self.assertEqual(arp.pdst, dip)
126 def verify_ip(self, rx, smac, dmac, sip, dip):
128 self.assertEqual(ether.dst, dmac)
129 self.assertEqual(ether.src, smac)
132 self.assertEqual(ip.src, sip)
133 self.assertEqual(ip.dst, dip)
135 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
137 self.assertEqual(ether.dst, dmac)
138 self.assertEqual(ether.src, smac)
141 self.assertTrue(mpls.label, label)
144 self.assertEqual(ip.src, sip)
145 self.assertEqual(ip.dst, dip)
151 # Generate some hosts on the LAN
153 self.pg1.generate_remote_hosts(11)
156 # Send IP traffic to one of these unresolved hosts.
157 # expect the generation of an ARP request
159 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
160 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
161 UDP(sport=1234, dport=1234) /
164 self.pg0.add_stream(p)
165 self.pg_enable_capture(self.pg_interfaces)
168 rx = self.pg1.get_capture(1)
170 self.verify_arp_req(rx[0],
173 self.pg1._remote_hosts[1].ip4)
176 # And a dynamic ARP entry for host 1
178 dyn_arp = VppNeighbor(self,
179 self.pg1.sw_if_index,
180 self.pg1.remote_hosts[1].mac,
181 self.pg1.remote_hosts[1].ip4)
182 dyn_arp.add_vpp_config()
185 # now we expect IP traffic forwarded
187 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
188 IP(src=self.pg0.remote_ip4,
189 dst=self.pg1._remote_hosts[1].ip4) /
190 UDP(sport=1234, dport=1234) /
193 self.pg0.add_stream(dyn_p)
194 self.pg_enable_capture(self.pg_interfaces)
197 rx = self.pg1.get_capture(1)
199 self.verify_ip(rx[0],
201 self.pg1.remote_hosts[1].mac,
203 self.pg1._remote_hosts[1].ip4)
206 # And a Static ARP entry for host 2
208 static_arp = VppNeighbor(self,
209 self.pg1.sw_if_index,
210 self.pg1.remote_hosts[2].mac,
211 self.pg1.remote_hosts[2].ip4,
213 static_arp.add_vpp_config()
215 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
216 IP(src=self.pg0.remote_ip4,
217 dst=self.pg1._remote_hosts[2].ip4) /
218 UDP(sport=1234, dport=1234) /
221 self.pg0.add_stream(static_p)
222 self.pg_enable_capture(self.pg_interfaces)
225 rx = self.pg1.get_capture(1)
227 self.verify_ip(rx[0],
229 self.pg1.remote_hosts[2].mac,
231 self.pg1._remote_hosts[2].ip4)
234 # flap the link. dynamic ARPs get flush, statics don't
236 self.pg1.admin_down()
239 self.pg0.add_stream(static_p)
240 self.pg_enable_capture(self.pg_interfaces)
242 rx = self.pg1.get_capture(1)
244 self.verify_ip(rx[0],
246 self.pg1.remote_hosts[2].mac,
248 self.pg1._remote_hosts[2].ip4)
250 self.pg0.add_stream(dyn_p)
251 self.pg_enable_capture(self.pg_interfaces)
254 rx = self.pg1.get_capture(1)
255 self.verify_arp_req(rx[0],
258 self.pg1._remote_hosts[1].ip4)
261 # Send an ARP request from one of the so-far unlearned remote hosts
263 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
264 src=self.pg1._remote_hosts[3].mac) /
266 hwsrc=self.pg1._remote_hosts[3].mac,
267 pdst=self.pg1.local_ip4,
268 psrc=self.pg1._remote_hosts[3].ip4))
270 self.pg1.add_stream(p)
271 self.pg_enable_capture(self.pg_interfaces)
274 rx = self.pg1.get_capture(1)
275 self.verify_arp_resp(rx[0],
277 self.pg1._remote_hosts[3].mac,
279 self.pg1._remote_hosts[3].ip4)
282 # VPP should have learned the mapping for the remote host
284 self.assertTrue(find_nbr(self,
285 self.pg1.sw_if_index,
286 self.pg1._remote_hosts[3].ip4))
288 # Fire in an ARP request before the interface becomes IP enabled
290 self.pg2.generate_remote_hosts(4)
292 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
294 hwsrc=self.pg2.remote_mac,
295 pdst=self.pg1.local_ip4,
296 psrc=self.pg2.remote_hosts[3].ip4))
297 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
300 hwsrc=self.pg2.remote_mac,
301 pdst=self.pg1.local_ip4,
302 psrc=self.pg2.remote_hosts[3].ip4))
303 self.send_and_assert_no_replies(self.pg2, p,
304 "interface not IP enabled")
307 # Make pg2 un-numbered to pg1
309 self.pg2.set_unnumbered(self.pg1.sw_if_index)
311 unnum = self.vapi.ip_unnumbered_dump()
312 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
313 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
316 # We should respond to ARP requests for the unnumbered to address
317 # once an attached route to the source is known
319 self.send_and_assert_no_replies(
321 "ARP req for unnumbered address - no source")
323 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
324 [VppRoutePath("0.0.0.0",
325 self.pg2.sw_if_index)])
326 attached_host.add_vpp_config()
328 self.pg2.add_stream(p)
329 self.pg_enable_capture(self.pg_interfaces)
332 rx = self.pg2.get_capture(1)
333 self.verify_arp_resp(rx[0],
337 self.pg2.remote_hosts[3].ip4)
339 self.pg2.add_stream(pt)
340 self.pg_enable_capture(self.pg_interfaces)
343 rx = self.pg2.get_capture(1)
344 self.verify_arp_resp(rx[0],
348 self.pg2.remote_hosts[3].ip4)
351 # A neighbor entry that has no associated FIB-entry
353 arp_no_fib = VppNeighbor(self,
354 self.pg1.sw_if_index,
355 self.pg1.remote_hosts[4].mac,
356 self.pg1.remote_hosts[4].ip4,
358 arp_no_fib.add_vpp_config()
361 # check we have the neighbor, but no route
363 self.assertTrue(find_nbr(self,
364 self.pg1.sw_if_index,
365 self.pg1._remote_hosts[4].ip4))
366 self.assertFalse(find_route(self,
367 self.pg1._remote_hosts[4].ip4,
370 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
371 # from within pg1's subnet
373 arp_unnum = VppNeighbor(self,
374 self.pg2.sw_if_index,
375 self.pg1.remote_hosts[5].mac,
376 self.pg1.remote_hosts[5].ip4)
377 arp_unnum.add_vpp_config()
379 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
380 IP(src=self.pg0.remote_ip4,
381 dst=self.pg1._remote_hosts[5].ip4) /
382 UDP(sport=1234, dport=1234) /
385 self.pg0.add_stream(p)
386 self.pg_enable_capture(self.pg_interfaces)
389 rx = self.pg2.get_capture(1)
391 self.verify_ip(rx[0],
393 self.pg1.remote_hosts[5].mac,
395 self.pg1._remote_hosts[5].ip4)
398 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
399 # with the unnumbered interface's address as the source
401 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
403 hwsrc=self.pg2.remote_mac,
404 pdst=self.pg1.local_ip4,
405 psrc=self.pg1.remote_hosts[6].ip4))
407 self.pg2.add_stream(p)
408 self.pg_enable_capture(self.pg_interfaces)
411 rx = self.pg2.get_capture(1)
412 self.verify_arp_resp(rx[0],
416 self.pg1.remote_hosts[6].ip4)
419 # An attached host route out of pg2 for an undiscovered hosts generates
420 # an ARP request with the unnumbered address as the source
422 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
423 [VppRoutePath("0.0.0.0",
424 self.pg2.sw_if_index)])
425 att_unnum.add_vpp_config()
427 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
428 IP(src=self.pg0.remote_ip4,
429 dst=self.pg1._remote_hosts[7].ip4) /
430 UDP(sport=1234, dport=1234) /
433 self.pg0.add_stream(p)
434 self.pg_enable_capture(self.pg_interfaces)
437 rx = self.pg2.get_capture(1)
439 self.verify_arp_req(rx[0],
442 self.pg1._remote_hosts[7].ip4)
444 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
446 hwsrc=self.pg2.remote_mac,
447 pdst=self.pg1.local_ip4,
448 psrc=self.pg1.remote_hosts[7].ip4))
450 self.pg2.add_stream(p)
451 self.pg_enable_capture(self.pg_interfaces)
454 rx = self.pg2.get_capture(1)
455 self.verify_arp_resp(rx[0],
459 self.pg1.remote_hosts[7].ip4)
462 # An attached host route as yet unresolved out of pg2 for an
463 # undiscovered host, an ARP requests begets a response.
465 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
466 [VppRoutePath("0.0.0.0",
467 self.pg2.sw_if_index)])
468 att_unnum1.add_vpp_config()
470 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
472 hwsrc=self.pg2.remote_mac,
473 pdst=self.pg1.local_ip4,
474 psrc=self.pg1.remote_hosts[8].ip4))
476 self.pg2.add_stream(p)
477 self.pg_enable_capture(self.pg_interfaces)
480 rx = self.pg2.get_capture(1)
481 self.verify_arp_resp(rx[0],
485 self.pg1.remote_hosts[8].ip4)
488 # Send an ARP request from one of the so-far unlearned remote hosts
491 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
492 src=self.pg1._remote_hosts[9].mac) /
495 hwsrc=self.pg1._remote_hosts[9].mac,
496 pdst=self.pg1.local_ip4,
497 psrc=self.pg1._remote_hosts[9].ip4))
499 self.pg1.add_stream(p)
500 self.pg_enable_capture(self.pg_interfaces)
503 rx = self.pg1.get_capture(1)
504 self.verify_arp_resp(rx[0],
506 self.pg1._remote_hosts[9].mac,
508 self.pg1._remote_hosts[9].ip4)
511 # Add a hierarchy of routes for a host in the sub-net.
512 # Should still get an ARP resp since the cover is attached
514 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
516 hwsrc=self.pg1.remote_mac,
517 pdst=self.pg1.local_ip4,
518 psrc=self.pg1.remote_hosts[10].ip4))
520 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
521 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
522 self.pg1.sw_if_index)])
525 self.pg1.add_stream(p)
526 self.pg_enable_capture(self.pg_interfaces)
528 rx = self.pg1.get_capture(1)
529 self.verify_arp_resp(rx[0],
533 self.pg1.remote_hosts[10].ip4)
535 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
536 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
537 self.pg1.sw_if_index)])
540 self.pg1.add_stream(p)
541 self.pg_enable_capture(self.pg_interfaces)
543 rx = self.pg1.get_capture(1)
544 self.verify_arp_resp(rx[0],
548 self.pg1.remote_hosts[10].ip4)
551 # add an ARP entry that's not on the sub-net and so whose
552 # adj-fib fails the refinement check. then send an ARP request
555 a1 = VppNeighbor(self,
556 self.pg0.sw_if_index,
561 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
563 hwsrc=self.pg0.remote_mac,
564 psrc="100.100.100.50",
565 pdst=self.pg0.remote_ip4))
566 self.send_and_assert_no_replies(self.pg0, p,
567 "ARP req for from failed adj-fib")
571 # 1 - don't respond to ARP request for address not within the
572 # interface's sub-net
573 # 1b - nor within the unnumbered subnet
574 # 1c - nor within the subnet of a different interface
576 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
578 hwsrc=self.pg0.remote_mac,
580 psrc=self.pg0.remote_ip4))
581 self.send_and_assert_no_replies(self.pg0, p,
582 "ARP req for non-local destination")
583 self.assertFalse(find_nbr(self,
584 self.pg0.sw_if_index,
587 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
589 hwsrc=self.pg2.remote_mac,
591 psrc=self.pg1.remote_hosts[7].ip4))
592 self.send_and_assert_no_replies(
594 "ARP req for non-local destination - unnum")
596 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
598 hwsrc=self.pg0.remote_mac,
599 pdst=self.pg1.local_ip4,
600 psrc=self.pg1.remote_ip4))
601 self.send_and_assert_no_replies(self.pg0, p,
602 "ARP req diff sub-net")
603 self.assertFalse(find_nbr(self,
604 self.pg0.sw_if_index,
605 self.pg1.remote_ip4))
608 # 2 - don't respond to ARP request from an address not within the
609 # interface's sub-net
610 # 2b - to a proxied address
611 # 2c - not within a different interface's sub-net
612 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
614 hwsrc=self.pg0.remote_mac,
616 pdst=self.pg0.local_ip4))
617 self.send_and_assert_no_replies(self.pg0, p,
618 "ARP req for non-local source")
619 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
621 hwsrc=self.pg2.remote_mac,
623 pdst=self.pg0.local_ip4))
624 self.send_and_assert_no_replies(
626 "ARP req for non-local source - unnum")
627 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
629 hwsrc=self.pg0.remote_mac,
630 psrc=self.pg1.remote_ip4,
631 pdst=self.pg0.local_ip4))
632 self.send_and_assert_no_replies(self.pg0, p,
633 "ARP req for non-local source 2c")
636 # 3 - don't respond to ARP request from an address that belongs to
639 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
641 hwsrc=self.pg0.remote_mac,
642 psrc=self.pg0.local_ip4,
643 pdst=self.pg0.local_ip4))
644 self.send_and_assert_no_replies(self.pg0, p,
645 "ARP req for non-local source")
648 # 4 - don't respond to ARP requests that has mac source different
649 # from ARP request HW source
651 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
653 hwsrc="00:00:00:DE:AD:BE",
654 psrc=self.pg0.remote_ip4,
655 pdst=self.pg0.local_ip4))
656 self.send_and_assert_no_replies(self.pg0, p,
657 "ARP req for non-local source")
660 # 5 - don't respond to ARP requests for address within the
661 # interface's sub-net but not the interface's address
663 self.pg0.generate_remote_hosts(2)
664 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
666 hwsrc=self.pg0.remote_mac,
667 psrc=self.pg0.remote_hosts[0].ip4,
668 pdst=self.pg0.remote_hosts[1].ip4))
669 self.send_and_assert_no_replies(self.pg0, p,
670 "ARP req for non-local destination")
675 dyn_arp.remove_vpp_config()
676 static_arp.remove_vpp_config()
677 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
679 # need this to flush the adj-fibs
680 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
681 self.pg2.admin_down()
682 self.pg1.admin_down()
684 def test_proxy_mirror_arp(self):
685 """ Interface Mirror Proxy ARP """
688 # When VPP has an interface whose address is also applied to a TAP
689 # interface on the host, then VPP's TAP interface will be unnumbered
690 # to the 'real' interface and do proxy ARP from the host.
691 # the curious aspect of this setup is that ARP requests from the host
692 # will come from the VPP's own address.
694 self.pg0.generate_remote_hosts(2)
696 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
697 dst="ff:ff:ff:ff:ff:ff") /
699 hwsrc=self.pg2.remote_mac,
700 pdst=self.pg0.remote_hosts[1].ip4,
701 psrc=self.pg0.local_ip4))
704 # Configure Proxy ARP for the subnet on PG0addresses on pg0
706 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
707 self.pg0._local_ip4_bcast)
709 # Make pg2 un-numbered to pg0
711 self.pg2.set_unnumbered(self.pg0.sw_if_index)
714 # Enable pg2 for proxy ARP
716 self.pg2.set_proxy_arp()
719 # Send the ARP request with an originating address that
720 # is VPP's own address
722 self.pg2.add_stream(arp_req_from_me)
723 self.pg_enable_capture(self.pg_interfaces)
726 rx = self.pg2.get_capture(1)
727 self.verify_arp_resp(rx[0],
730 self.pg0.remote_hosts[1].ip4,
734 # validate we have not learned an ARP entry as a result of this
736 self.assertFalse(find_nbr(self,
737 self.pg2.sw_if_index,
743 self.pg2.set_proxy_arp(0)
744 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
745 self.pg0._local_ip4_bcast,
748 def test_proxy_arp(self):
751 self.pg1.generate_remote_hosts(2)
754 # Proxy ARP request packets for each interface
756 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
757 dst="ff:ff:ff:ff:ff:ff") /
759 hwsrc=self.pg0.remote_mac,
761 psrc=self.pg0.remote_ip4))
762 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
763 dst="ff:ff:ff:ff:ff:ff") /
766 hwsrc=self.pg0.remote_mac,
768 psrc=self.pg0.remote_ip4))
769 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
770 dst="ff:ff:ff:ff:ff:ff") /
772 hwsrc=self.pg1.remote_mac,
774 psrc=self.pg1.remote_ip4))
775 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
776 dst="ff:ff:ff:ff:ff:ff") /
778 hwsrc=self.pg2.remote_mac,
780 psrc=self.pg1.remote_hosts[1].ip4))
781 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
782 dst="ff:ff:ff:ff:ff:ff") /
784 hwsrc=self.pg3.remote_mac,
786 psrc=self.pg3.remote_ip4))
789 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
791 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
792 inet_pton(AF_INET, "10.10.10.124"))
795 # No responses are sent when the interfaces are not enabled for proxy
798 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
799 "ARP req from unconfigured interface")
800 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
801 "ARP req from unconfigured interface")
804 # Make pg2 un-numbered to pg1
807 self.pg2.set_unnumbered(self.pg1.sw_if_index)
809 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
810 "ARP req from unnumbered interface")
813 # Enable each interface to reply to proxy ARPs
815 for i in self.pg_interfaces:
819 # Now each of the interfaces should reply to a request to a proxied
822 self.pg0.add_stream(arp_req_pg0)
823 self.pg_enable_capture(self.pg_interfaces)
826 rx = self.pg0.get_capture(1)
827 self.verify_arp_resp(rx[0],
833 self.pg0.add_stream(arp_req_pg0_tagged)
834 self.pg_enable_capture(self.pg_interfaces)
837 rx = self.pg0.get_capture(1)
838 self.verify_arp_resp(rx[0],
844 self.pg1.add_stream(arp_req_pg1)
845 self.pg_enable_capture(self.pg_interfaces)
848 rx = self.pg1.get_capture(1)
849 self.verify_arp_resp(rx[0],
855 self.pg2.add_stream(arp_req_pg2)
856 self.pg_enable_capture(self.pg_interfaces)
859 rx = self.pg2.get_capture(1)
860 self.verify_arp_resp(rx[0],
864 self.pg1.remote_hosts[1].ip4)
867 # A request for an address out of the configured range
869 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
870 dst="ff:ff:ff:ff:ff:ff") /
872 hwsrc=self.pg1.remote_mac,
874 psrc=self.pg1.remote_ip4))
875 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
876 "ARP req out of range HI")
877 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
878 dst="ff:ff:ff:ff:ff:ff") /
880 hwsrc=self.pg1.remote_mac,
882 psrc=self.pg1.remote_ip4))
883 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
884 "ARP req out of range Low")
887 # Request for an address in the proxy range but from an interface
890 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
891 "ARP req from different VRF")
894 # Disable Each interface for proxy ARP
895 # - expect none to respond
897 for i in self.pg_interfaces:
900 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
901 "ARP req from disable")
902 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
903 "ARP req from disable")
904 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
905 "ARP req from disable")
908 # clean up on interface 2
910 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
916 # Interface 2 does not yet have ip4 config
918 self.pg2.config_ip4()
919 self.pg2.generate_remote_hosts(2)
922 # Add a route with out going label via an ARP unresolved next-hop
924 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
925 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
926 self.pg2.sw_if_index,
928 ip_10_0_0_1.add_vpp_config()
931 # packets should generate an ARP request
933 p = (Ether(src=self.pg0.remote_mac,
934 dst=self.pg0.local_mac) /
935 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
936 UDP(sport=1234, dport=1234) /
939 self.pg0.add_stream(p)
940 self.pg_enable_capture(self.pg_interfaces)
943 rx = self.pg2.get_capture(1)
944 self.verify_arp_req(rx[0],
947 self.pg2._remote_hosts[1].ip4)
950 # now resolve the neighbours
952 self.pg2.configure_ipv4_neighbors()
955 # Now packet should be properly MPLS encapped.
956 # This verifies that MPLS link-type adjacencies are completed
957 # when the ARP entry resolves
959 self.pg0.add_stream(p)
960 self.pg_enable_capture(self.pg_interfaces)
963 rx = self.pg2.get_capture(1)
964 self.verify_ip_o_mpls(rx[0],
966 self.pg2.remote_hosts[1].mac,
970 self.pg2.unconfig_ip4()
972 def test_arp_vrrp(self):
973 """ ARP reply with VRRP virtual src hw addr """
976 # IP packet destined for pg1 remote host arrives on pg0 resulting
977 # in an ARP request for the address of the remote host on pg1
979 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
980 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
981 UDP(sport=1234, dport=1234) /
984 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
986 self.verify_arp_req(rx1[0],
992 # ARP reply for address of pg1 remote host arrives on pg1 with
993 # the hw src addr set to a value in the VRRP IPv4 range of
996 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
997 ARP(op="is-at", hwdst=self.pg1.local_mac,
998 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
999 psrc=self.pg1.remote_ip4))
1001 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1004 # IP packet destined for pg1 remote host arrives on pg0 again.
1005 # VPP should have an ARP entry for that address now and the packet
1006 # should be sent out pg1.
1008 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
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 should 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 = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1191 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1192 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1193 mac_string = ''.join(mac)
1195 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1199 # now ARP requests come from the new source mac
1201 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1202 self.verify_arp_req(rx[0],
1203 "00:00:00:33:33:33",
1205 self.pg1._remote_hosts[2].ip4)
1208 # packets to the resolved host also have the new source mac
1210 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1211 self.verify_ip(rx[0],
1212 "00:00:00:33:33:33",
1213 self.pg1.remote_hosts[1].mac,
1214 self.pg0.remote_ip4,
1215 self.pg1.remote_hosts[1].ip4)
1218 # set the mac address on the interface that does not have a
1219 # configured subnet and thus no glean
1221 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1224 def test_garp(self):
1228 # Generate some hosts on the LAN
1230 self.pg1.generate_remote_hosts(4)
1235 arp = VppNeighbor(self,
1236 self.pg1.sw_if_index,
1237 self.pg1.remote_hosts[1].mac,
1238 self.pg1.remote_hosts[1].ip4)
1239 arp.add_vpp_config()
1241 self.assertTrue(find_nbr(self,
1242 self.pg1.sw_if_index,
1243 self.pg1.remote_hosts[1].ip4,
1244 mac=self.pg1.remote_hosts[1].mac))
1247 # Send a GARP (request) to swap the host 1's address to that of host 2
1249 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1250 src=self.pg1.remote_hosts[2].mac) /
1252 hwdst=self.pg1.local_mac,
1253 hwsrc=self.pg1.remote_hosts[2].mac,
1254 pdst=self.pg1.remote_hosts[1].ip4,
1255 psrc=self.pg1.remote_hosts[1].ip4))
1257 self.pg1.add_stream(p1)
1258 self.pg_enable_capture(self.pg_interfaces)
1261 self.assertTrue(find_nbr(self,
1262 self.pg1.sw_if_index,
1263 self.pg1.remote_hosts[1].ip4,
1264 mac=self.pg1.remote_hosts[2].mac))
1267 # Send a GARP (reply) to swap the host 1's address to that of host 3
1269 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1270 src=self.pg1.remote_hosts[3].mac) /
1272 hwdst=self.pg1.local_mac,
1273 hwsrc=self.pg1.remote_hosts[3].mac,
1274 pdst=self.pg1.remote_hosts[1].ip4,
1275 psrc=self.pg1.remote_hosts[1].ip4))
1277 self.pg1.add_stream(p1)
1278 self.pg_enable_capture(self.pg_interfaces)
1281 self.assertTrue(find_nbr(self,
1282 self.pg1.sw_if_index,
1283 self.pg1.remote_hosts[1].ip4,
1284 mac=self.pg1.remote_hosts[3].mac))
1287 # GARPs (request nor replies) for host we don't know yet
1288 # don't result in new neighbour entries
1290 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1291 src=self.pg1.remote_hosts[3].mac) /
1293 hwdst=self.pg1.local_mac,
1294 hwsrc=self.pg1.remote_hosts[3].mac,
1295 pdst=self.pg1.remote_hosts[2].ip4,
1296 psrc=self.pg1.remote_hosts[2].ip4))
1298 self.pg1.add_stream(p1)
1299 self.pg_enable_capture(self.pg_interfaces)
1302 self.assertFalse(find_nbr(self,
1303 self.pg1.sw_if_index,
1304 self.pg1.remote_hosts[2].ip4))
1306 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1307 src=self.pg1.remote_hosts[3].mac) /
1309 hwdst=self.pg1.local_mac,
1310 hwsrc=self.pg1.remote_hosts[3].mac,
1311 pdst=self.pg1.remote_hosts[2].ip4,
1312 psrc=self.pg1.remote_hosts[2].ip4))
1314 self.pg1.add_stream(p1)
1315 self.pg_enable_capture(self.pg_interfaces)
1318 self.assertFalse(find_nbr(self,
1319 self.pg1.sw_if_index,
1320 self.pg1.remote_hosts[2].ip4))
1322 def test_arp_incomplete(self):
1323 """ Incomplete Entries """
1326 # ensure that we throttle the ARP and ND requests
1328 self.pg0.generate_remote_hosts(2)
1333 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1334 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1335 self.pg0.sw_if_index)])
1336 ip_10_0_0_1.add_vpp_config()
1338 p1 = (Ether(dst=self.pg1.local_mac,
1339 src=self.pg1.remote_mac) /
1340 IP(src=self.pg1.remote_ip4,
1342 UDP(sport=1234, dport=1234) /
1345 self.pg1.add_stream(p1 * 257)
1346 self.pg_enable_capture(self.pg_interfaces)
1348 rx = self.pg0._get_capture(1)
1351 # how many we get is going to be dependent on the time for packet
1352 # processing but it should be small
1354 self.assertLess(len(rx), 64)
1359 ip_10_1 = VppIpRoute(self, "10::1", 128,
1360 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1361 self.pg0.sw_if_index,
1362 proto=DpoProto.DPO_PROTO_IP6)],
1364 ip_10_1.add_vpp_config()
1366 p1 = (Ether(dst=self.pg1.local_mac,
1367 src=self.pg1.remote_mac) /
1368 IPv6(src=self.pg1.remote_ip6,
1370 UDP(sport=1234, dport=1234) /
1373 self.pg1.add_stream(p1 * 257)
1374 self.pg_enable_capture(self.pg_interfaces)
1376 rx = self.pg0._get_capture(1)
1379 # how many we get is going to be dependent on the time for packet
1380 # processing but it should be small
1382 self.assertLess(len(rx), 64)
1384 def test_arp_forus(self):
1385 """ ARP for for-us """
1388 # Test that VPP responds with ARP requests to addresses that
1389 # are connected and local routes.
1390 # Use one of the 'remote' addresses in the subnet as a local address
1391 # The intention of this route is that it then acts like a secondary
1392 # address added to an interface
1394 self.pg0.generate_remote_hosts(2)
1396 forus = VppIpRoute(self, self.pg0.remote_hosts[1].ip4, 32,
1397 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1398 self.pg0.sw_if_index)],
1400 forus.add_vpp_config()
1402 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1403 src=self.pg0.remote_mac) /
1405 hwdst=self.pg0.local_mac,
1406 hwsrc=self.pg0.remote_mac,
1407 pdst=self.pg0.remote_hosts[1].ip4,
1408 psrc=self.pg0.remote_ip4))
1410 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1412 self.verify_arp_resp(rx[0],
1414 self.pg0.remote_mac,
1415 self.pg0.remote_hosts[1].ip4,
1416 self.pg0.remote_ip4)
1419 class NeighborStatsTestCase(VppTestCase):
1420 """ ARP/ND Counters """
1423 def setUpClass(cls):
1424 super(NeighborStatsTestCase, cls).setUpClass()
1427 def tearDownClass(cls):
1428 super(NeighborStatsTestCase, cls).tearDownClass()
1431 super(NeighborStatsTestCase, self).setUp()
1433 self.create_pg_interfaces(range(2))
1435 # pg0 configured with ip4 and 6 addresses used for input
1436 # pg1 configured with ip4 and 6 addresses used for output
1437 # pg2 is unnumbered to pg0
1438 for i in self.pg_interfaces:
1446 super(NeighborStatsTestCase, self).tearDown()
1448 for i in self.pg_interfaces:
1453 def test_arp_stats(self):
1454 """ ARP Counters """
1456 self.vapi.cli("adj counters enable")
1457 self.pg1.generate_remote_hosts(2)
1459 arp1 = VppNeighbor(self,
1460 self.pg1.sw_if_index,
1461 self.pg1.remote_hosts[0].mac,
1462 self.pg1.remote_hosts[0].ip4)
1463 arp1.add_vpp_config()
1464 arp2 = VppNeighbor(self,
1465 self.pg1.sw_if_index,
1466 self.pg1.remote_hosts[1].mac,
1467 self.pg1.remote_hosts[1].ip4)
1468 arp2.add_vpp_config()
1470 p1 = (Ether(dst=self.pg0.local_mac,
1471 src=self.pg0.remote_mac) /
1472 IP(src=self.pg0.remote_ip4,
1473 dst=self.pg1.remote_hosts[0].ip4) /
1474 UDP(sport=1234, dport=1234) /
1476 p2 = (Ether(dst=self.pg0.local_mac,
1477 src=self.pg0.remote_mac) /
1478 IP(src=self.pg0.remote_ip4,
1479 dst=self.pg1.remote_hosts[1].ip4) /
1480 UDP(sport=1234, dport=1234) /
1483 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1484 rx = self.send_and_expect(self.pg0, p2 * 65, self.pg1)
1486 self.assertEqual(65, arp1.get_stats()['packets'])
1487 self.assertEqual(65, arp2.get_stats()['packets'])
1489 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1490 self.assertEqual(130, arp1.get_stats()['packets'])
1492 def test_nd_stats(self):
1495 self.vapi.cli("adj counters enable")
1496 self.pg0.generate_remote_hosts(3)
1498 nd1 = VppNeighbor(self,
1499 self.pg0.sw_if_index,
1500 self.pg0.remote_hosts[1].mac,
1501 self.pg0.remote_hosts[1].ip6)
1502 nd1.add_vpp_config()
1503 nd2 = VppNeighbor(self,
1504 self.pg0.sw_if_index,
1505 self.pg0.remote_hosts[2].mac,
1506 self.pg0.remote_hosts[2].ip6)
1507 nd2.add_vpp_config()
1509 p1 = (Ether(dst=self.pg1.local_mac,
1510 src=self.pg1.remote_mac) /
1511 IPv6(src=self.pg1.remote_ip6,
1512 dst=self.pg0.remote_hosts[1].ip6) /
1513 UDP(sport=1234, dport=1234) /
1515 p2 = (Ether(dst=self.pg1.local_mac,
1516 src=self.pg1.remote_mac) /
1517 IPv6(src=self.pg1.remote_ip6,
1518 dst=self.pg0.remote_hosts[2].ip6) /
1519 UDP(sport=1234, dport=1234) /
1522 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1523 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1525 self.assertEqual(16, nd1.get_stats()['packets'])
1526 self.assertEqual(16, nd2.get_stats()['packets'])
1528 rx = self.send_and_expect(self.pg1, p1 * 65, self.pg0)
1529 self.assertEqual(81, nd1.get_stats()['packets'])
1532 if __name__ == '__main__':
1533 unittest.main(testRunner=VppTestRunner)