5 from socket import AF_INET, AF_INET6, inet_pton
7 from framework import VppTestCase, VppTestRunner
8 from vpp_neighbor import VppNeighbor, find_nbr
9 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
10 VppIpTable, DpoProto, FibPathType
11 from vpp_papi import VppEnum
14 from scapy.packet import Raw
15 from scapy.layers.l2 import Ether, ARP, Dot1Q
16 from scapy.layers.inet import IP, UDP, TCP
17 from scapy.layers.inet6 import IPv6
18 from scapy.contrib.mpls import MPLS
19 from scapy.layers.inet6 import IPv6
24 # not exported by scapy, so redefined here
25 arp_opts = {"who-has": 1, "is-at": 2}
28 class ARPTestCase(VppTestCase):
33 super(ARPTestCase, cls).setUpClass()
36 def tearDownClass(cls):
37 super(ARPTestCase, cls).tearDownClass()
40 super(ARPTestCase, self).setUp()
42 # create 3 pg interfaces
43 self.create_pg_interfaces(range(4))
45 # pg0 configured with ip4 and 6 addresses used for input
46 # pg1 configured with ip4 and 6 addresses used for output
47 # pg2 is unnumbered to pg0
48 for i in self.pg_interfaces:
53 self.pg0.resolve_arp()
58 # pg3 in a different VRF
59 self.tbl = VppIpTable(self, 1)
60 self.tbl.add_vpp_config()
62 self.pg3.set_table_ip4(1)
66 self.pg0.unconfig_ip4()
67 self.pg0.unconfig_ip6()
69 self.pg1.unconfig_ip4()
70 self.pg1.unconfig_ip6()
72 self.pg3.unconfig_ip4()
73 self.pg3.set_table_ip4(0)
75 for i in self.pg_interfaces:
78 super(ARPTestCase, self).tearDown()
80 def verify_arp_req(self, rx, smac, sip, dip):
82 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
83 self.assertEqual(ether.src, smac)
86 self.assertEqual(arp.hwtype, 1)
87 self.assertEqual(arp.ptype, 0x800)
88 self.assertEqual(arp.hwlen, 6)
89 self.assertEqual(arp.plen, 4)
90 self.assertEqual(arp.op, arp_opts["who-has"])
91 self.assertEqual(arp.hwsrc, smac)
92 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
93 self.assertEqual(arp.psrc, sip)
94 self.assertEqual(arp.pdst, dip)
96 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
98 self.assertEqual(ether.dst, dmac)
99 self.assertEqual(ether.src, smac)
102 self.assertEqual(arp.hwtype, 1)
103 self.assertEqual(arp.ptype, 0x800)
104 self.assertEqual(arp.hwlen, 6)
105 self.assertEqual(arp.plen, 4)
106 self.assertEqual(arp.op, arp_opts["is-at"])
107 self.assertEqual(arp.hwsrc, smac)
108 self.assertEqual(arp.hwdst, dmac)
109 self.assertEqual(arp.psrc, sip)
110 self.assertEqual(arp.pdst, dip)
112 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
114 self.assertEqual(ether.dst, dmac)
115 self.assertEqual(ether.src, smac)
118 self.assertEqual(arp.hwtype, 1)
119 self.assertEqual(arp.ptype, 0x800)
120 self.assertEqual(arp.hwlen, 6)
121 self.assertEqual(arp.plen, 4)
122 self.assertEqual(arp.op, arp_opts["is-at"])
123 self.assertNotEqual(arp.hwsrc, smac)
124 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
125 "00:00:5E:00:01" in arp.hwsrc)
126 self.assertEqual(arp.hwdst, dmac)
127 self.assertEqual(arp.psrc, sip)
128 self.assertEqual(arp.pdst, dip)
130 def verify_ip(self, rx, smac, dmac, sip, dip):
132 self.assertEqual(ether.dst, dmac)
133 self.assertEqual(ether.src, smac)
136 self.assertEqual(ip.src, sip)
137 self.assertEqual(ip.dst, dip)
139 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
141 self.assertEqual(ether.dst, dmac)
142 self.assertEqual(ether.src, smac)
145 self.assertTrue(mpls.label, label)
148 self.assertEqual(ip.src, sip)
149 self.assertEqual(ip.dst, dip)
155 # Generate some hosts on the LAN
157 self.pg1.generate_remote_hosts(11)
161 # - all neighbour events
162 # - all neighbor events on pg1
163 # - neighbor events for host[1] on pg1
165 self.vapi.want_ip_neighbor_events(enable=1,
167 self.vapi.want_ip_neighbor_events(enable=1,
169 sw_if_index=self.pg1.sw_if_index)
170 self.vapi.want_ip_neighbor_events(enable=1,
172 sw_if_index=self.pg1.sw_if_index,
173 ip=self.pg1.remote_hosts[1].ip4)
175 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
178 # Send IP traffic to one of these unresolved hosts.
179 # expect the generation of an ARP request
181 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
182 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
183 UDP(sport=1234, dport=1234) /
186 self.pg0.add_stream(p)
187 self.pg_enable_capture(self.pg_interfaces)
190 rx = self.pg1.get_capture(1)
192 self.verify_arp_req(rx[0],
195 self.pg1._remote_hosts[1].ip4)
198 # And a dynamic ARP entry for host 1
200 dyn_arp = VppNeighbor(self,
201 self.pg1.sw_if_index,
202 self.pg1.remote_hosts[1].mac,
203 self.pg1.remote_hosts[1].ip4)
204 dyn_arp.add_vpp_config()
205 self.assertTrue(dyn_arp.query_vpp_config())
207 # this matches all of the listnerers
208 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
211 self.assertEqual(str(e.neighbor.ip_address),
212 self.pg1.remote_hosts[1].ip4)
215 # now we expect IP traffic forwarded
217 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
218 IP(src=self.pg0.remote_ip4,
219 dst=self.pg1._remote_hosts[1].ip4) /
220 UDP(sport=1234, dport=1234) /
223 self.pg0.add_stream(dyn_p)
224 self.pg_enable_capture(self.pg_interfaces)
227 rx = self.pg1.get_capture(1)
229 self.verify_ip(rx[0],
231 self.pg1.remote_hosts[1].mac,
233 self.pg1._remote_hosts[1].ip4)
236 # And a Static ARP entry for host 2
238 static_arp = VppNeighbor(self,
239 self.pg1.sw_if_index,
240 self.pg1.remote_hosts[2].mac,
241 self.pg1.remote_hosts[2].ip4,
243 static_arp.add_vpp_config()
244 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
247 self.assertEqual(str(e.neighbor.ip_address),
248 self.pg1.remote_hosts[2].ip4)
250 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
251 IP(src=self.pg0.remote_ip4,
252 dst=self.pg1._remote_hosts[2].ip4) /
253 UDP(sport=1234, dport=1234) /
256 self.pg0.add_stream(static_p)
257 self.pg_enable_capture(self.pg_interfaces)
260 rx = self.pg1.get_capture(1)
262 self.verify_ip(rx[0],
264 self.pg1.remote_hosts[2].mac,
266 self.pg1._remote_hosts[2].ip4)
269 # remove all the listeners
271 self.vapi.want_ip_neighbor_events(enable=0,
273 self.vapi.want_ip_neighbor_events(enable=0,
275 sw_if_index=self.pg1.sw_if_index)
276 self.vapi.want_ip_neighbor_events(enable=0,
278 sw_if_index=self.pg1.sw_if_index,
279 ip=self.pg1.remote_hosts[1].ip4)
282 # flap the link. dynamic ARPs get flush, statics don't
284 self.pg1.admin_down()
287 self.pg0.add_stream(static_p)
288 self.pg_enable_capture(self.pg_interfaces)
290 rx = self.pg1.get_capture(1)
292 self.verify_ip(rx[0],
294 self.pg1.remote_hosts[2].mac,
296 self.pg1._remote_hosts[2].ip4)
298 self.pg0.add_stream(dyn_p)
299 self.pg_enable_capture(self.pg_interfaces)
302 rx = self.pg1.get_capture(1)
303 self.verify_arp_req(rx[0],
306 self.pg1._remote_hosts[1].ip4)
308 self.assertFalse(dyn_arp.query_vpp_config())
309 self.assertTrue(static_arp.query_vpp_config())
311 # Send an ARP request from one of the so-far unlearned remote hosts
313 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
314 src=self.pg1._remote_hosts[3].mac) /
316 hwsrc=self.pg1._remote_hosts[3].mac,
317 pdst=self.pg1.local_ip4,
318 psrc=self.pg1._remote_hosts[3].ip4))
320 self.pg1.add_stream(p)
321 self.pg_enable_capture(self.pg_interfaces)
324 rx = self.pg1.get_capture(1)
325 self.verify_arp_resp(rx[0],
327 self.pg1._remote_hosts[3].mac,
329 self.pg1._remote_hosts[3].ip4)
332 # VPP should have learned the mapping for the remote host
334 self.assertTrue(find_nbr(self,
335 self.pg1.sw_if_index,
336 self.pg1._remote_hosts[3].ip4))
338 # Fire in an ARP request before the interface becomes IP enabled
340 self.pg2.generate_remote_hosts(4)
342 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
344 hwsrc=self.pg2.remote_mac,
345 pdst=self.pg1.local_ip4,
346 psrc=self.pg2.remote_hosts[3].ip4))
347 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
350 hwsrc=self.pg2.remote_mac,
351 pdst=self.pg1.local_ip4,
352 psrc=self.pg2.remote_hosts[3].ip4))
353 self.send_and_assert_no_replies(self.pg2, p,
354 "interface not IP enabled")
357 # Make pg2 un-numbered to pg1
359 self.pg2.set_unnumbered(self.pg1.sw_if_index)
362 # test the unnumbered dump both by all interfaces and just the enabled
365 unnum = self.vapi.ip_unnumbered_dump()
366 self.assertTrue(len(unnum))
367 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
368 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
369 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
370 self.assertTrue(len(unnum))
371 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
372 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
375 # We should respond to ARP requests for the unnumbered to address
376 # once an attached route to the source is known
378 self.send_and_assert_no_replies(
380 "ARP req for unnumbered address - no source")
382 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
383 [VppRoutePath("0.0.0.0",
384 self.pg2.sw_if_index)])
385 attached_host.add_vpp_config()
387 self.pg2.add_stream(p)
388 self.pg_enable_capture(self.pg_interfaces)
391 rx = self.pg2.get_capture(1)
392 self.verify_arp_resp(rx[0],
396 self.pg2.remote_hosts[3].ip4)
398 self.pg2.add_stream(pt)
399 self.pg_enable_capture(self.pg_interfaces)
402 rx = self.pg2.get_capture(1)
403 self.verify_arp_resp(rx[0],
407 self.pg2.remote_hosts[3].ip4)
410 # A neighbor entry that has no associated FIB-entry
412 arp_no_fib = VppNeighbor(self,
413 self.pg1.sw_if_index,
414 self.pg1.remote_hosts[4].mac,
415 self.pg1.remote_hosts[4].ip4,
417 arp_no_fib.add_vpp_config()
420 # check we have the neighbor, but no route
422 self.assertTrue(find_nbr(self,
423 self.pg1.sw_if_index,
424 self.pg1._remote_hosts[4].ip4))
425 self.assertFalse(find_route(self,
426 self.pg1._remote_hosts[4].ip4,
429 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
430 # from within pg1's subnet
432 arp_unnum = VppNeighbor(self,
433 self.pg2.sw_if_index,
434 self.pg1.remote_hosts[5].mac,
435 self.pg1.remote_hosts[5].ip4)
436 arp_unnum.add_vpp_config()
438 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
439 IP(src=self.pg0.remote_ip4,
440 dst=self.pg1._remote_hosts[5].ip4) /
441 UDP(sport=1234, dport=1234) /
444 self.pg0.add_stream(p)
445 self.pg_enable_capture(self.pg_interfaces)
448 rx = self.pg2.get_capture(1)
450 self.verify_ip(rx[0],
452 self.pg1.remote_hosts[5].mac,
454 self.pg1._remote_hosts[5].ip4)
457 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
458 # with the unnumbered interface's address as the source
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[6].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[6].ip4)
478 # An attached host route out of pg2 for an undiscovered hosts generates
479 # an ARP request with the unnumbered address as the source
481 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
482 [VppRoutePath("0.0.0.0",
483 self.pg2.sw_if_index)])
484 att_unnum.add_vpp_config()
486 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
487 IP(src=self.pg0.remote_ip4,
488 dst=self.pg1._remote_hosts[7].ip4) /
489 UDP(sport=1234, dport=1234) /
492 self.pg0.add_stream(p)
493 self.pg_enable_capture(self.pg_interfaces)
496 rx = self.pg2.get_capture(1)
498 self.verify_arp_req(rx[0],
501 self.pg1._remote_hosts[7].ip4)
503 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
505 hwsrc=self.pg2.remote_mac,
506 pdst=self.pg1.local_ip4,
507 psrc=self.pg1.remote_hosts[7].ip4))
509 self.pg2.add_stream(p)
510 self.pg_enable_capture(self.pg_interfaces)
513 rx = self.pg2.get_capture(1)
514 self.verify_arp_resp(rx[0],
518 self.pg1.remote_hosts[7].ip4)
521 # An attached host route as yet unresolved out of pg2 for an
522 # undiscovered host, an ARP requests begets a response.
524 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
525 [VppRoutePath("0.0.0.0",
526 self.pg2.sw_if_index)])
527 att_unnum1.add_vpp_config()
529 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
531 hwsrc=self.pg2.remote_mac,
532 pdst=self.pg1.local_ip4,
533 psrc=self.pg1.remote_hosts[8].ip4))
535 self.pg2.add_stream(p)
536 self.pg_enable_capture(self.pg_interfaces)
539 rx = self.pg2.get_capture(1)
540 self.verify_arp_resp(rx[0],
544 self.pg1.remote_hosts[8].ip4)
547 # Send an ARP request from one of the so-far unlearned remote hosts
550 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
551 src=self.pg1._remote_hosts[9].mac) /
554 hwsrc=self.pg1._remote_hosts[9].mac,
555 pdst=self.pg1.local_ip4,
556 psrc=self.pg1._remote_hosts[9].ip4))
558 self.pg1.add_stream(p)
559 self.pg_enable_capture(self.pg_interfaces)
562 rx = self.pg1.get_capture(1)
563 self.verify_arp_resp(rx[0],
565 self.pg1._remote_hosts[9].mac,
567 self.pg1._remote_hosts[9].ip4)
570 # Add a hierarchy of routes for a host in the sub-net.
571 # Should still get an ARP resp since the cover is attached
573 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
575 hwsrc=self.pg1.remote_mac,
576 pdst=self.pg1.local_ip4,
577 psrc=self.pg1.remote_hosts[10].ip4))
579 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
580 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
581 self.pg1.sw_if_index)])
584 self.pg1.add_stream(p)
585 self.pg_enable_capture(self.pg_interfaces)
587 rx = self.pg1.get_capture(1)
588 self.verify_arp_resp(rx[0],
592 self.pg1.remote_hosts[10].ip4)
594 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
595 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
596 self.pg1.sw_if_index)])
599 self.pg1.add_stream(p)
600 self.pg_enable_capture(self.pg_interfaces)
602 rx = self.pg1.get_capture(1)
603 self.verify_arp_resp(rx[0],
607 self.pg1.remote_hosts[10].ip4)
610 # add an ARP entry that's not on the sub-net and so whose
611 # adj-fib fails the refinement check. then send an ARP request
614 a1 = VppNeighbor(self,
615 self.pg0.sw_if_index,
620 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
622 hwsrc=self.pg0.remote_mac,
623 psrc="100.100.100.50",
624 pdst=self.pg0.remote_ip4))
625 self.send_and_assert_no_replies(self.pg0, p,
626 "ARP req for from failed adj-fib")
630 # 1 - don't respond to ARP request for address not within the
631 # interface's sub-net
632 # 1b - nor within the unnumbered subnet
633 # 1c - nor within the subnet of a different interface
635 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
637 hwsrc=self.pg0.remote_mac,
639 psrc=self.pg0.remote_ip4))
640 self.send_and_assert_no_replies(self.pg0, p,
641 "ARP req for non-local destination")
642 self.assertFalse(find_nbr(self,
643 self.pg0.sw_if_index,
646 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
648 hwsrc=self.pg2.remote_mac,
650 psrc=self.pg1.remote_hosts[7].ip4))
651 self.send_and_assert_no_replies(
653 "ARP req for non-local destination - unnum")
655 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
657 hwsrc=self.pg0.remote_mac,
658 pdst=self.pg1.local_ip4,
659 psrc=self.pg1.remote_ip4))
660 self.send_and_assert_no_replies(self.pg0, p,
661 "ARP req diff sub-net")
662 self.assertFalse(find_nbr(self,
663 self.pg0.sw_if_index,
664 self.pg1.remote_ip4))
667 # 2 - don't respond to ARP request from an address not within the
668 # interface's sub-net
669 # 2b - to a proxied address
670 # 2c - not within a different interface's sub-net
671 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
673 hwsrc=self.pg0.remote_mac,
675 pdst=self.pg0.local_ip4))
676 self.send_and_assert_no_replies(self.pg0, p,
677 "ARP req for non-local source")
678 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
680 hwsrc=self.pg2.remote_mac,
682 pdst=self.pg0.local_ip4))
683 self.send_and_assert_no_replies(
685 "ARP req for non-local source - unnum")
686 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
688 hwsrc=self.pg0.remote_mac,
689 psrc=self.pg1.remote_ip4,
690 pdst=self.pg0.local_ip4))
691 self.send_and_assert_no_replies(self.pg0, p,
692 "ARP req for non-local source 2c")
695 # 3 - don't respond to ARP request from an address that belongs to
698 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
700 hwsrc=self.pg0.remote_mac,
701 psrc=self.pg0.local_ip4,
702 pdst=self.pg0.local_ip4))
703 self.send_and_assert_no_replies(self.pg0, p,
704 "ARP req for non-local source")
707 # 4 - don't respond to ARP requests that has mac source different
708 # from ARP request HW source
710 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
712 hwsrc="00:00:00:DE:AD:BE",
713 psrc=self.pg0.remote_ip4,
714 pdst=self.pg0.local_ip4))
715 self.send_and_assert_no_replies(self.pg0, p,
716 "ARP req for non-local source")
719 # 5 - don't respond to ARP requests for address within the
720 # interface's sub-net but not the interface's address
722 self.pg0.generate_remote_hosts(2)
723 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
725 hwsrc=self.pg0.remote_mac,
726 psrc=self.pg0.remote_hosts[0].ip4,
727 pdst=self.pg0.remote_hosts[1].ip4))
728 self.send_and_assert_no_replies(self.pg0, p,
729 "ARP req for non-local destination")
734 static_arp.remove_vpp_config()
735 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
737 # need this to flush the adj-fibs
738 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
739 self.pg2.admin_down()
740 self.pg1.admin_down()
742 def test_proxy_mirror_arp(self):
743 """ Interface Mirror Proxy ARP """
746 # When VPP has an interface whose address is also applied to a TAP
747 # interface on the host, then VPP's TAP interface will be unnumbered
748 # to the 'real' interface and do proxy ARP from the host.
749 # the curious aspect of this setup is that ARP requests from the host
750 # will come from the VPP's own address.
752 self.pg0.generate_remote_hosts(2)
754 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
755 dst="ff:ff:ff:ff:ff:ff") /
757 hwsrc=self.pg2.remote_mac,
758 pdst=self.pg0.remote_hosts[1].ip4,
759 psrc=self.pg0.local_ip4))
762 # Configure Proxy ARP for the subnet on PG0addresses on pg0
764 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
765 self.pg0._local_ip4_bcast)
767 # Make pg2 un-numbered to pg0
769 self.pg2.set_unnumbered(self.pg0.sw_if_index)
772 # Enable pg2 for proxy ARP
774 self.pg2.set_proxy_arp()
777 # Send the ARP request with an originating address that
778 # is VPP's own address
780 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
781 self.verify_arp_resp(rx[0],
784 self.pg0.remote_hosts[1].ip4,
788 # validate we have not learned an ARP entry as a result of this
790 self.assertFalse(find_nbr(self,
791 self.pg2.sw_if_index,
795 # setup a punt redirect so packets from the uplink go to the tap
797 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
798 self.pg2.sw_if_index,
801 p_tcp = (Ether(src=self.pg0.remote_mac,
802 dst=self.pg0.local_mac,) /
803 IP(src=self.pg0.remote_ip4,
804 dst=self.pg0.local_ip4) /
805 TCP(sport=80, dport=80) /
807 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
809 # there's no ARP entry so this is an ARP req
810 self.assertTrue(rx[0].haslayer(ARP))
812 # and ARP entry for VPP's pg0 address on the host interface
813 n1 = VppNeighbor(self,
814 self.pg2.sw_if_index,
817 is_no_fib_entry=True).add_vpp_config()
818 # now the packets shold forward
819 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
820 self.assertFalse(rx[0].haslayer(ARP))
821 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
824 # flush the neighbor cache on the uplink
826 af = VppEnum.vl_api_address_family_t
827 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
829 # ensure we can still resolve the ARPs on the uplink
830 self.pg0.resolve_arp()
832 self.assertTrue(find_nbr(self,
833 self.pg0.sw_if_index,
834 self.pg0.remote_ip4))
839 self.pg2.set_proxy_arp(0)
840 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
841 self.pg0._local_ip4_bcast,
844 def test_proxy_arp(self):
847 self.pg1.generate_remote_hosts(2)
850 # Proxy ARP request packets for each interface
852 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
853 dst="ff:ff:ff:ff:ff:ff") /
855 hwsrc=self.pg0.remote_mac,
857 psrc=self.pg0.remote_ip4))
858 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
859 dst="ff:ff:ff:ff:ff:ff") /
862 hwsrc=self.pg0.remote_mac,
864 psrc=self.pg0.remote_ip4))
865 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
866 dst="ff:ff:ff:ff:ff:ff") /
868 hwsrc=self.pg1.remote_mac,
870 psrc=self.pg1.remote_ip4))
871 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
872 dst="ff:ff:ff:ff:ff:ff") /
874 hwsrc=self.pg2.remote_mac,
876 psrc=self.pg1.remote_hosts[1].ip4))
877 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
878 dst="ff:ff:ff:ff:ff:ff") /
880 hwsrc=self.pg3.remote_mac,
882 psrc=self.pg3.remote_ip4))
885 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
887 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
888 inet_pton(AF_INET, "10.10.10.124"))
891 # No responses are sent when the interfaces are not enabled for proxy
894 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
895 "ARP req from unconfigured interface")
896 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
897 "ARP req from unconfigured interface")
900 # Make pg2 un-numbered to pg1
903 self.pg2.set_unnumbered(self.pg1.sw_if_index)
905 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
906 "ARP req from unnumbered interface")
909 # Enable each interface to reply to proxy ARPs
911 for i in self.pg_interfaces:
915 # Now each of the interfaces should reply to a request to a proxied
918 self.pg0.add_stream(arp_req_pg0)
919 self.pg_enable_capture(self.pg_interfaces)
922 rx = self.pg0.get_capture(1)
923 self.verify_arp_resp(rx[0],
929 self.pg0.add_stream(arp_req_pg0_tagged)
930 self.pg_enable_capture(self.pg_interfaces)
933 rx = self.pg0.get_capture(1)
934 self.verify_arp_resp(rx[0],
940 self.pg1.add_stream(arp_req_pg1)
941 self.pg_enable_capture(self.pg_interfaces)
944 rx = self.pg1.get_capture(1)
945 self.verify_arp_resp(rx[0],
951 self.pg2.add_stream(arp_req_pg2)
952 self.pg_enable_capture(self.pg_interfaces)
955 rx = self.pg2.get_capture(1)
956 self.verify_arp_resp(rx[0],
960 self.pg1.remote_hosts[1].ip4)
963 # A request for an address out of the configured range
965 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
966 dst="ff:ff:ff:ff:ff:ff") /
968 hwsrc=self.pg1.remote_mac,
970 psrc=self.pg1.remote_ip4))
971 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
972 "ARP req out of range HI")
973 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
974 dst="ff:ff:ff:ff:ff:ff") /
976 hwsrc=self.pg1.remote_mac,
978 psrc=self.pg1.remote_ip4))
979 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
980 "ARP req out of range Low")
983 # Request for an address in the proxy range but from an interface
986 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
987 "ARP req from different VRF")
990 # Disable Each interface for proxy ARP
991 # - expect none to respond
993 for i in self.pg_interfaces:
996 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
997 "ARP req from disable")
998 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
999 "ARP req from disable")
1000 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1001 "ARP req from disable")
1004 # clean up on interface 2
1006 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1008 def test_mpls(self):
1012 # Interface 2 does not yet have ip4 config
1014 self.pg2.config_ip4()
1015 self.pg2.generate_remote_hosts(2)
1018 # Add a route with out going label via an ARP unresolved next-hop
1020 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1021 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1022 self.pg2.sw_if_index,
1024 ip_10_0_0_1.add_vpp_config()
1027 # packets should generate an ARP request
1029 p = (Ether(src=self.pg0.remote_mac,
1030 dst=self.pg0.local_mac) /
1031 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1032 UDP(sport=1234, dport=1234) /
1035 self.pg0.add_stream(p)
1036 self.pg_enable_capture(self.pg_interfaces)
1039 rx = self.pg2.get_capture(1)
1040 self.verify_arp_req(rx[0],
1043 self.pg2._remote_hosts[1].ip4)
1046 # now resolve the neighbours
1048 self.pg2.configure_ipv4_neighbors()
1051 # Now packet should be properly MPLS encapped.
1052 # This verifies that MPLS link-type adjacencies are completed
1053 # when the ARP entry resolves
1055 self.pg0.add_stream(p)
1056 self.pg_enable_capture(self.pg_interfaces)
1059 rx = self.pg2.get_capture(1)
1060 self.verify_ip_o_mpls(rx[0],
1062 self.pg2.remote_hosts[1].mac,
1064 self.pg0.remote_ip4,
1066 self.pg2.unconfig_ip4()
1068 def test_arp_vrrp(self):
1069 """ ARP reply with VRRP virtual src hw addr """
1072 # IP packet destined for pg1 remote host arrives on pg0 resulting
1073 # in an ARP request for the address of the remote host on pg1
1075 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1076 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1077 UDP(sport=1234, dport=1234) /
1080 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1082 self.verify_arp_req(rx1[0],
1085 self.pg1.remote_ip4)
1088 # ARP reply for address of pg1 remote host arrives on pg1 with
1089 # the hw src addr set to a value in the VRRP IPv4 range of
1092 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1093 ARP(op="is-at", hwdst=self.pg1.local_mac,
1094 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1095 psrc=self.pg1.remote_ip4))
1097 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1100 # IP packet destined for pg1 remote host arrives on pg0 again.
1101 # VPP should have an ARP entry for that address now and the packet
1102 # should be sent out pg1.
1104 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1106 self.verify_ip(rx1[0],
1108 "00:00:5e:00:01:09",
1109 self.pg0.remote_ip4,
1110 self.pg1.remote_ip4)
1112 self.pg1.admin_down()
1115 def test_arp_duplicates(self):
1116 """ ARP Duplicates"""
1119 # Generate some hosts on the LAN
1121 self.pg1.generate_remote_hosts(3)
1124 # Add host 1 on pg1 and pg2
1126 arp_pg1 = VppNeighbor(self,
1127 self.pg1.sw_if_index,
1128 self.pg1.remote_hosts[1].mac,
1129 self.pg1.remote_hosts[1].ip4)
1130 arp_pg1.add_vpp_config()
1131 arp_pg2 = VppNeighbor(self,
1132 self.pg2.sw_if_index,
1133 self.pg2.remote_mac,
1134 self.pg1.remote_hosts[1].ip4)
1135 arp_pg2.add_vpp_config()
1138 # IP packet destined for pg1 remote host arrives on pg1 again.
1140 p = (Ether(dst=self.pg0.local_mac,
1141 src=self.pg0.remote_mac) /
1142 IP(src=self.pg0.remote_ip4,
1143 dst=self.pg1.remote_hosts[1].ip4) /
1144 UDP(sport=1234, dport=1234) /
1147 self.pg0.add_stream(p)
1148 self.pg_enable_capture(self.pg_interfaces)
1151 rx1 = self.pg1.get_capture(1)
1153 self.verify_ip(rx1[0],
1155 self.pg1.remote_hosts[1].mac,
1156 self.pg0.remote_ip4,
1157 self.pg1.remote_hosts[1].ip4)
1160 # remove the duplicate on pg1
1161 # packet stream should generate ARPs out of pg1
1163 arp_pg1.remove_vpp_config()
1165 self.pg0.add_stream(p)
1166 self.pg_enable_capture(self.pg_interfaces)
1169 rx1 = self.pg1.get_capture(1)
1171 self.verify_arp_req(rx1[0],
1174 self.pg1.remote_hosts[1].ip4)
1179 arp_pg1.add_vpp_config()
1181 self.pg0.add_stream(p)
1182 self.pg_enable_capture(self.pg_interfaces)
1185 rx1 = self.pg1.get_capture(1)
1187 self.verify_ip(rx1[0],
1189 self.pg1.remote_hosts[1].mac,
1190 self.pg0.remote_ip4,
1191 self.pg1.remote_hosts[1].ip4)
1193 def test_arp_static(self):
1195 self.pg2.generate_remote_hosts(3)
1198 # Add a static ARP entry
1200 static_arp = VppNeighbor(self,
1201 self.pg2.sw_if_index,
1202 self.pg2.remote_hosts[1].mac,
1203 self.pg2.remote_hosts[1].ip4,
1205 static_arp.add_vpp_config()
1208 # Add the connected prefix to the interface
1210 self.pg2.config_ip4()
1213 # We should now find the adj-fib
1215 self.assertTrue(find_nbr(self,
1216 self.pg2.sw_if_index,
1217 self.pg2.remote_hosts[1].ip4,
1219 self.assertTrue(find_route(self,
1220 self.pg2.remote_hosts[1].ip4,
1224 # remove the connected
1226 self.pg2.unconfig_ip4()
1229 # put the interface into table 1
1231 self.pg2.set_table_ip4(1)
1234 # configure the same connected and expect to find the
1235 # adj fib in the new table
1237 self.pg2.config_ip4()
1238 self.assertTrue(find_route(self,
1239 self.pg2.remote_hosts[1].ip4,
1246 self.pg2.unconfig_ip4()
1247 static_arp.remove_vpp_config()
1248 self.pg2.set_table_ip4(0)
1250 def test_arp_static_replace_dynamic_same_mac(self):
1251 """ ARP Static can replace Dynamic (same mac) """
1252 self.pg2.generate_remote_hosts(1)
1254 dyn_arp = VppNeighbor(self,
1255 self.pg2.sw_if_index,
1256 self.pg2.remote_hosts[0].mac,
1257 self.pg2.remote_hosts[0].ip4)
1258 static_arp = VppNeighbor(self,
1259 self.pg2.sw_if_index,
1260 self.pg2.remote_hosts[0].mac,
1261 self.pg2.remote_hosts[0].ip4,
1265 # Add a dynamic ARP entry
1267 dyn_arp.add_vpp_config()
1270 # We should find the dynamic nbr
1272 self.assertFalse(find_nbr(self,
1273 self.pg2.sw_if_index,
1274 self.pg2.remote_hosts[0].ip4,
1276 self.assertTrue(find_nbr(self,
1277 self.pg2.sw_if_index,
1278 self.pg2.remote_hosts[0].ip4,
1280 mac=self.pg2.remote_hosts[0].mac))
1283 # Add a static ARP entry with the same mac
1285 static_arp.add_vpp_config()
1288 # We should now find the static nbr with the same mac
1290 self.assertFalse(find_nbr(self,
1291 self.pg2.sw_if_index,
1292 self.pg2.remote_hosts[0].ip4,
1294 self.assertTrue(find_nbr(self,
1295 self.pg2.sw_if_index,
1296 self.pg2.remote_hosts[0].ip4,
1298 mac=self.pg2.remote_hosts[0].mac))
1303 static_arp.remove_vpp_config()
1305 def test_arp_static_replace_dynamic_diff_mac(self):
1306 """ ARP Static can replace Dynamic (diff mac) """
1307 self.pg2.generate_remote_hosts(2)
1309 dyn_arp = VppNeighbor(self,
1310 self.pg2.sw_if_index,
1311 self.pg2.remote_hosts[0].mac,
1312 self.pg2.remote_hosts[0].ip4)
1313 static_arp = VppNeighbor(self,
1314 self.pg2.sw_if_index,
1315 self.pg2.remote_hosts[1].mac,
1316 self.pg2.remote_hosts[0].ip4,
1320 # Add a dynamic ARP entry
1322 dyn_arp.add_vpp_config()
1325 # We should find the dynamic nbr
1327 self.assertFalse(find_nbr(self,
1328 self.pg2.sw_if_index,
1329 self.pg2.remote_hosts[0].ip4,
1331 self.assertTrue(find_nbr(self,
1332 self.pg2.sw_if_index,
1333 self.pg2.remote_hosts[0].ip4,
1335 mac=self.pg2.remote_hosts[0].mac))
1338 # Add a static ARP entry with a changed mac
1340 static_arp.add_vpp_config()
1343 # We should now find the static nbr with a changed mac
1345 self.assertFalse(find_nbr(self,
1346 self.pg2.sw_if_index,
1347 self.pg2.remote_hosts[0].ip4,
1349 self.assertTrue(find_nbr(self,
1350 self.pg2.sw_if_index,
1351 self.pg2.remote_hosts[0].ip4,
1353 mac=self.pg2.remote_hosts[1].mac))
1358 static_arp.remove_vpp_config()
1360 def test_arp_incomplete(self):
1361 """ ARP Incomplete"""
1362 self.pg1.generate_remote_hosts(3)
1364 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1365 IP(src=self.pg0.remote_ip4,
1366 dst=self.pg1.remote_hosts[1].ip4) /
1367 UDP(sport=1234, dport=1234) /
1369 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1370 IP(src=self.pg0.remote_ip4,
1371 dst=self.pg1.remote_hosts[2].ip4) /
1372 UDP(sport=1234, dport=1234) /
1376 # a packet to an unresolved destination generates an ARP request
1378 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1379 self.verify_arp_req(rx[0],
1382 self.pg1._remote_hosts[1].ip4)
1385 # add a neighbour for remote host 1
1387 static_arp = VppNeighbor(self,
1388 self.pg1.sw_if_index,
1389 self.pg1.remote_hosts[1].mac,
1390 self.pg1.remote_hosts[1].ip4,
1392 static_arp.add_vpp_config()
1395 # change the interface's MAC
1397 mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1398 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1399 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1400 mac_string = ''.join(mac)
1402 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1406 # now ARP requests come from the new source mac
1408 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1409 self.verify_arp_req(rx[0],
1410 "00:00:00:33:33:33",
1412 self.pg1._remote_hosts[2].ip4)
1415 # packets to the resolved host also have the new source mac
1417 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1418 self.verify_ip(rx[0],
1419 "00:00:00:33:33:33",
1420 self.pg1.remote_hosts[1].mac,
1421 self.pg0.remote_ip4,
1422 self.pg1.remote_hosts[1].ip4)
1425 # set the mac address on the interface that does not have a
1426 # configured subnet and thus no glean
1428 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1431 def test_garp(self):
1435 # Generate some hosts on the LAN
1437 self.pg1.generate_remote_hosts(4)
1438 self.pg2.generate_remote_hosts(4)
1443 arp = VppNeighbor(self,
1444 self.pg1.sw_if_index,
1445 self.pg1.remote_hosts[1].mac,
1446 self.pg1.remote_hosts[1].ip4)
1447 arp.add_vpp_config()
1449 self.assertTrue(find_nbr(self,
1450 self.pg1.sw_if_index,
1451 self.pg1.remote_hosts[1].ip4,
1452 mac=self.pg1.remote_hosts[1].mac))
1455 # Send a GARP (request) to swap the host 1's address to that of host 2
1457 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1458 src=self.pg1.remote_hosts[2].mac) /
1460 hwdst=self.pg1.local_mac,
1461 hwsrc=self.pg1.remote_hosts[2].mac,
1462 pdst=self.pg1.remote_hosts[1].ip4,
1463 psrc=self.pg1.remote_hosts[1].ip4))
1465 self.pg1.add_stream(p1)
1466 self.pg_enable_capture(self.pg_interfaces)
1469 self.assertTrue(find_nbr(self,
1470 self.pg1.sw_if_index,
1471 self.pg1.remote_hosts[1].ip4,
1472 mac=self.pg1.remote_hosts[2].mac))
1475 # Send a GARP (reply) to swap the host 1's address to that of host 3
1477 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1478 src=self.pg1.remote_hosts[3].mac) /
1480 hwdst=self.pg1.local_mac,
1481 hwsrc=self.pg1.remote_hosts[3].mac,
1482 pdst=self.pg1.remote_hosts[1].ip4,
1483 psrc=self.pg1.remote_hosts[1].ip4))
1485 self.pg1.add_stream(p1)
1486 self.pg_enable_capture(self.pg_interfaces)
1489 self.assertTrue(find_nbr(self,
1490 self.pg1.sw_if_index,
1491 self.pg1.remote_hosts[1].ip4,
1492 mac=self.pg1.remote_hosts[3].mac))
1495 # GARPs (request nor replies) for host we don't know yet
1496 # don't result in new neighbour entries
1498 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1499 src=self.pg1.remote_hosts[3].mac) /
1501 hwdst=self.pg1.local_mac,
1502 hwsrc=self.pg1.remote_hosts[3].mac,
1503 pdst=self.pg1.remote_hosts[2].ip4,
1504 psrc=self.pg1.remote_hosts[2].ip4))
1506 self.pg1.add_stream(p1)
1507 self.pg_enable_capture(self.pg_interfaces)
1510 self.assertFalse(find_nbr(self,
1511 self.pg1.sw_if_index,
1512 self.pg1.remote_hosts[2].ip4))
1514 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1515 src=self.pg1.remote_hosts[3].mac) /
1517 hwdst=self.pg1.local_mac,
1518 hwsrc=self.pg1.remote_hosts[3].mac,
1519 pdst=self.pg1.remote_hosts[2].ip4,
1520 psrc=self.pg1.remote_hosts[2].ip4))
1522 self.pg1.add_stream(p1)
1523 self.pg_enable_capture(self.pg_interfaces)
1526 self.assertFalse(find_nbr(self,
1527 self.pg1.sw_if_index,
1528 self.pg1.remote_hosts[2].ip4))
1531 # IP address in different subnets are not learnt
1533 self.pg2.configure_ipv4_neighbors()
1535 for op in ["is-at", "who-has"]:
1536 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1537 src=self.pg2.remote_hosts[1].mac) /
1539 hwdst=self.pg2.local_mac,
1540 hwsrc=self.pg2.remote_hosts[1].mac,
1541 pdst=self.pg2.remote_hosts[1].ip4,
1542 psrc=self.pg2.remote_hosts[1].ip4)),
1543 (Ether(dst="ff:ff:ff:ff:ff:ff",
1544 src=self.pg2.remote_hosts[1].mac) /
1546 hwdst="ff:ff:ff:ff:ff:ff",
1547 hwsrc=self.pg2.remote_hosts[1].mac,
1548 pdst=self.pg2.remote_hosts[1].ip4,
1549 psrc=self.pg2.remote_hosts[1].ip4))]
1551 self.send_and_assert_no_replies(self.pg1, p1)
1552 self.assertFalse(find_nbr(self,
1553 self.pg1.sw_if_index,
1554 self.pg2.remote_hosts[1].ip4))
1556 # they are all dropped because the subnet's don't match
1557 self.assertEqual(4, self.statistics.get_err_counter(
1558 "/err/arp-reply/IP4 destination address not local to subnet"))
1560 def test_arp_incomplete(self):
1561 """ Incomplete Entries """
1564 # ensure that we throttle the ARP and ND requests
1566 self.pg0.generate_remote_hosts(2)
1571 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1572 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1573 self.pg0.sw_if_index)])
1574 ip_10_0_0_1.add_vpp_config()
1576 p1 = (Ether(dst=self.pg1.local_mac,
1577 src=self.pg1.remote_mac) /
1578 IP(src=self.pg1.remote_ip4,
1580 UDP(sport=1234, dport=1234) /
1583 self.pg1.add_stream(p1 * 257)
1584 self.pg_enable_capture(self.pg_interfaces)
1586 rx = self.pg0._get_capture(1)
1589 # how many we get is going to be dependent on the time for packet
1590 # processing but it should be small
1592 self.assertLess(len(rx), 64)
1597 ip_10_1 = VppIpRoute(self, "10::1", 128,
1598 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1599 self.pg0.sw_if_index,
1600 proto=DpoProto.DPO_PROTO_IP6)])
1601 ip_10_1.add_vpp_config()
1603 p1 = (Ether(dst=self.pg1.local_mac,
1604 src=self.pg1.remote_mac) /
1605 IPv6(src=self.pg1.remote_ip6,
1607 UDP(sport=1234, dport=1234) /
1610 self.pg1.add_stream(p1 * 257)
1611 self.pg_enable_capture(self.pg_interfaces)
1613 rx = self.pg0._get_capture(1)
1616 # how many we get is going to be dependent on the time for packet
1617 # processing but it should be small
1619 self.assertLess(len(rx), 64)
1621 def test_arp_forus(self):
1622 """ ARP for for-us """
1625 # Test that VPP responds with ARP requests to addresses that
1626 # are connected and local routes.
1627 # Use one of the 'remote' addresses in the subnet as a local address
1628 # The intention of this route is that it then acts like a secondary
1629 # address added to an interface
1631 self.pg0.generate_remote_hosts(2)
1634 self, self.pg0.remote_hosts[1].ip4, 32,
1635 [VppRoutePath("0.0.0.0",
1636 self.pg0.sw_if_index,
1637 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1638 forus.add_vpp_config()
1640 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1641 src=self.pg0.remote_mac) /
1643 hwdst=self.pg0.local_mac,
1644 hwsrc=self.pg0.remote_mac,
1645 pdst=self.pg0.remote_hosts[1].ip4,
1646 psrc=self.pg0.remote_ip4))
1648 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1650 self.verify_arp_resp(rx[0],
1652 self.pg0.remote_mac,
1653 self.pg0.remote_hosts[1].ip4,
1654 self.pg0.remote_ip4)
1656 def test_arp_table_swap(self):
1658 # Generate some hosts on the LAN
1661 self.pg1.generate_remote_hosts(N_NBRS)
1663 for n in range(N_NBRS):
1664 # a route thru each neighbour
1665 VppIpRoute(self, "10.0.0.%d" % n, 32,
1666 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1667 self.pg1.sw_if_index)]).add_vpp_config()
1669 # resolve each neighbour
1670 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1671 ARP(op="is-at", hwdst=self.pg1.local_mac,
1672 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1673 psrc=self.pg1.remote_hosts[n].ip4))
1675 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1677 self.logger.info(self.vapi.cli("sh ip neighbors"))
1680 # swap the table pg1 is in
1682 table = VppIpTable(self, 100).add_vpp_config()
1684 self.pg1.unconfig_ip4()
1685 self.pg1.set_table_ip4(100)
1686 self.pg1.config_ip4()
1689 # all neighbours are cleared
1691 for n in range(N_NBRS):
1692 self.assertFalse(find_nbr(self,
1693 self.pg1.sw_if_index,
1694 self.pg1.remote_hosts[n].ip4))
1697 # packets to all neighbours generate ARP requests
1699 for n in range(N_NBRS):
1700 # a route thru each neighbour
1701 VppIpRoute(self, "10.0.0.%d" % n, 32,
1702 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1703 self.pg1.sw_if_index)],
1704 table_id=100).add_vpp_config()
1706 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1707 dst=self.pg1.local_mac) /
1708 IP(src=self.pg1.remote_hosts[n].ip4,
1709 dst="10.0.0.%d" % n) /
1711 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1713 self.verify_arp_req(rx,
1716 self.pg1.remote_hosts[n].ip4)
1718 self.pg1.unconfig_ip4()
1719 self.pg1.set_table_ip4(0)
1722 class NeighborStatsTestCase(VppTestCase):
1723 """ ARP/ND Counters """
1726 def setUpClass(cls):
1727 super(NeighborStatsTestCase, cls).setUpClass()
1730 def tearDownClass(cls):
1731 super(NeighborStatsTestCase, cls).tearDownClass()
1734 super(NeighborStatsTestCase, self).setUp()
1736 self.create_pg_interfaces(range(2))
1738 # pg0 configured with ip4 and 6 addresses used for input
1739 # pg1 configured with ip4 and 6 addresses used for output
1740 # pg2 is unnumbered to pg0
1741 for i in self.pg_interfaces:
1749 super(NeighborStatsTestCase, self).tearDown()
1751 for i in self.pg_interfaces:
1756 def test_arp_stats(self):
1757 """ ARP Counters """
1759 self.vapi.cli("adj counters enable")
1760 self.pg1.generate_remote_hosts(2)
1762 arp1 = VppNeighbor(self,
1763 self.pg1.sw_if_index,
1764 self.pg1.remote_hosts[0].mac,
1765 self.pg1.remote_hosts[0].ip4)
1766 arp1.add_vpp_config()
1767 arp2 = VppNeighbor(self,
1768 self.pg1.sw_if_index,
1769 self.pg1.remote_hosts[1].mac,
1770 self.pg1.remote_hosts[1].ip4)
1771 arp2.add_vpp_config()
1773 p1 = (Ether(dst=self.pg0.local_mac,
1774 src=self.pg0.remote_mac) /
1775 IP(src=self.pg0.remote_ip4,
1776 dst=self.pg1.remote_hosts[0].ip4) /
1777 UDP(sport=1234, dport=1234) /
1779 p2 = (Ether(dst=self.pg0.local_mac,
1780 src=self.pg0.remote_mac) /
1781 IP(src=self.pg0.remote_ip4,
1782 dst=self.pg1.remote_hosts[1].ip4) /
1783 UDP(sport=1234, dport=1234) /
1786 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1787 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1789 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1790 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1792 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1793 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1795 def test_nd_stats(self):
1798 self.vapi.cli("adj counters enable")
1799 self.pg0.generate_remote_hosts(3)
1801 nd1 = VppNeighbor(self,
1802 self.pg0.sw_if_index,
1803 self.pg0.remote_hosts[1].mac,
1804 self.pg0.remote_hosts[1].ip6)
1805 nd1.add_vpp_config()
1806 nd2 = VppNeighbor(self,
1807 self.pg0.sw_if_index,
1808 self.pg0.remote_hosts[2].mac,
1809 self.pg0.remote_hosts[2].ip6)
1810 nd2.add_vpp_config()
1812 p1 = (Ether(dst=self.pg1.local_mac,
1813 src=self.pg1.remote_mac) /
1814 IPv6(src=self.pg1.remote_ip6,
1815 dst=self.pg0.remote_hosts[1].ip6) /
1816 UDP(sport=1234, dport=1234) /
1818 p2 = (Ether(dst=self.pg1.local_mac,
1819 src=self.pg1.remote_mac) /
1820 IPv6(src=self.pg1.remote_ip6,
1821 dst=self.pg0.remote_hosts[2].ip6) /
1822 UDP(sport=1234, dport=1234) /
1825 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1826 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1828 self.assertEqual(16, nd1.get_stats()['packets'])
1829 self.assertEqual(16, nd2.get_stats()['packets'])
1831 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1832 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1835 class NeighborAgeTestCase(VppTestCase):
1836 """ ARP/ND Aging """
1839 def setUpClass(cls):
1840 super(NeighborAgeTestCase, cls).setUpClass()
1843 def tearDownClass(cls):
1844 super(NeighborAgeTestCase, cls).tearDownClass()
1847 super(NeighborAgeTestCase, self).setUp()
1849 self.create_pg_interfaces(range(1))
1851 # pg0 configured with ip4 and 6 addresses used for input
1852 # pg1 configured with ip4 and 6 addresses used for output
1853 # pg2 is unnumbered to pg0
1854 for i in self.pg_interfaces:
1862 super(NeighborAgeTestCase, self).tearDown()
1864 for i in self.pg_interfaces:
1869 def wait_for_no_nbr(self, intf, address,
1870 n_tries=50, s_time=1):
1872 if not find_nbr(self, intf, address):
1874 n_tries = n_tries - 1
1879 def verify_arp_req(self, rx, smac, sip, dip):
1881 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1882 self.assertEqual(ether.src, smac)
1885 self.assertEqual(arp.hwtype, 1)
1886 self.assertEqual(arp.ptype, 0x800)
1887 self.assertEqual(arp.hwlen, 6)
1888 self.assertEqual(arp.plen, 4)
1889 self.assertEqual(arp.op, arp_opts["who-has"])
1890 self.assertEqual(arp.hwsrc, smac)
1891 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1892 self.assertEqual(arp.psrc, sip)
1893 self.assertEqual(arp.pdst, dip)
1896 """ Aging/Recycle """
1898 self.vapi.cli("set logging unthrottle 0")
1899 self.vapi.cli("set logging size %d" % 0xffff)
1901 self.pg0.generate_remote_hosts(201)
1903 vaf = VppEnum.vl_api_address_family_t
1906 # start listening on all interfaces
1908 self.pg_enable_capture(self.pg_interfaces)
1911 # Set the neighbor configuration:
1916 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1921 self.vapi.cli("sh ip neighbor-config")
1923 # add the 198 neighbours that should pass (-1 for one created in setup)
1924 for ii in range(200):
1926 self.pg0.sw_if_index,
1927 self.pg0.remote_hosts[ii].mac,
1928 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1930 # one more neighbor over the limit should fail
1931 with self.vapi.assert_negative_api_retval():
1933 self.pg0.sw_if_index,
1934 self.pg0.remote_hosts[200].mac,
1935 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1938 # change the config to allow recycling the old neighbors
1940 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1945 # now new additions are allowed
1947 self.pg0.sw_if_index,
1948 self.pg0.remote_hosts[200].mac,
1949 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1951 # add the first neighbor we configured has been re-used
1952 self.assertFalse(find_nbr(self,
1953 self.pg0.sw_if_index,
1954 self.pg0.remote_hosts[0].ip4))
1955 self.assertTrue(find_nbr(self,
1956 self.pg0.sw_if_index,
1957 self.pg0.remote_hosts[200].ip4))
1960 # change the config to age old neighbors
1962 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1967 self.vapi.cli("sh ip4 neighbor-sorted")
1970 # expect probes from all these ARP entries as they age
1971 # 3 probes for each neighbor 3*200 = 600
1972 rxs = self.pg0.get_capture(600, timeout=8)
1975 for jj in range(200):
1976 rx = rxs[ii*200 + jj]
1980 # 3 probes sent then 1 more second to see if a reply comes, before
1983 for jj in range(1, 201):
1984 self.wait_for_no_nbr(self.pg0.sw_if_index,
1985 self.pg0.remote_hosts[jj].ip4)
1987 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1988 af=vaf.ADDRESS_IP4))
1991 # load up some neighbours again with 2s aging enabled
1992 # they should be removed after 10s (2s age + 4s for probes + gap)
1994 for ii in range(10):
1996 self.pg0.sw_if_index,
1997 self.pg0.remote_hosts[ii].mac,
1998 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2000 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2001 af=vaf.ADDRESS_IP4))
2004 # check if we can set age and recycle with empty neighbor list
2006 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2012 # load up some neighbours again, then disable the aging
2013 # they should still be there in 10 seconds time
2015 for ii in range(10):
2017 self.pg0.sw_if_index,
2018 self.pg0.remote_hosts[ii].mac,
2019 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2020 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2026 self.assertTrue(find_nbr(self,
2027 self.pg0.sw_if_index,
2028 self.pg0.remote_hosts[0].ip4))
2031 class NeighborReplaceTestCase(VppTestCase):
2032 """ ARP/ND Replacement """
2035 def setUpClass(cls):
2036 super(NeighborReplaceTestCase, cls).setUpClass()
2039 def tearDownClass(cls):
2040 super(NeighborReplaceTestCase, cls).tearDownClass()
2043 super(NeighborReplaceTestCase, self).setUp()
2045 self.create_pg_interfaces(range(4))
2047 # pg0 configured with ip4 and 6 addresses used for input
2048 # pg1 configured with ip4 and 6 addresses used for output
2049 # pg2 is unnumbered to pg0
2050 for i in self.pg_interfaces:
2058 super(NeighborReplaceTestCase, self).tearDown()
2060 for i in self.pg_interfaces:
2065 def test_replace(self):
2070 for i in self.pg_interfaces:
2071 i.generate_remote_hosts(N_HOSTS)
2072 i.configure_ipv4_neighbors()
2073 i.configure_ipv6_neighbors()
2076 self.vapi.ip_neighbor_replace_begin()
2077 self.vapi.ip_neighbor_replace_end()
2079 for i in self.pg_interfaces:
2080 for h in range(N_HOSTS):
2081 self.assertFalse(find_nbr(self,
2082 self.pg0.sw_if_index,
2083 self.pg0.remote_hosts[h].ip4))
2084 self.assertFalse(find_nbr(self,
2085 self.pg0.sw_if_index,
2086 self.pg0.remote_hosts[h].ip6))
2089 # and them all back via the API
2091 for i in self.pg_interfaces:
2092 for h in range(N_HOSTS):
2095 i.remote_hosts[h].mac,
2096 i.remote_hosts[h].ip4).add_vpp_config()
2099 i.remote_hosts[h].mac,
2100 i.remote_hosts[h].ip6).add_vpp_config()
2103 # begin the replacement again, this time touch some
2104 # the neighbours on pg1 so they are not deleted
2106 self.vapi.ip_neighbor_replace_begin()
2108 # update from the API all neighbours on pg1
2109 for h in range(N_HOSTS):
2111 self.pg1.sw_if_index,
2112 self.pg1.remote_hosts[h].mac,
2113 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2115 self.pg1.sw_if_index,
2116 self.pg1.remote_hosts[h].mac,
2117 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2119 # update from the data-plane all neighbours on pg3
2120 self.pg3.configure_ipv4_neighbors()
2121 self.pg3.configure_ipv6_neighbors()
2123 # complete the replacement
2124 self.logger.info(self.vapi.cli("sh ip neighbors"))
2125 self.vapi.ip_neighbor_replace_end()
2127 for i in self.pg_interfaces:
2128 if i == self.pg1 or i == self.pg3:
2129 # neighbours on pg1 and pg3 are still present
2130 for h in range(N_HOSTS):
2131 self.assertTrue(find_nbr(self,
2133 i.remote_hosts[h].ip4))
2134 self.assertTrue(find_nbr(self,
2136 i.remote_hosts[h].ip6))
2138 # all other neighbours are toast
2139 for h in range(N_HOSTS):
2140 self.assertFalse(find_nbr(self,
2142 i.remote_hosts[h].ip4))
2143 self.assertFalse(find_nbr(self,
2145 i.remote_hosts[h].ip6))
2148 class NeighborFlush(VppTestCase):
2149 """ Neighbor Flush """
2152 def setUpClass(cls):
2153 super(NeighborFlush, cls).setUpClass()
2156 def tearDownClass(cls):
2157 super(NeighborFlush, cls).tearDownClass()
2160 super(NeighborFlush, self).setUp()
2162 self.create_pg_interfaces(range(2))
2164 for i in self.pg_interfaces:
2172 super(NeighborFlush, self).tearDown()
2174 for i in self.pg_interfaces:
2179 def test_flush(self):
2180 """ Neighbour Flush """
2183 nf = e.vl_api_ip_neighbor_flags_t
2184 af = e.vl_api_address_family_t
2186 static = [False, True]
2187 self.pg0.generate_remote_hosts(N_HOSTS)
2188 self.pg1.generate_remote_hosts(N_HOSTS)
2191 # a few v4 and v6 dynamic neoghbors
2192 for n in range(N_HOSTS):
2194 self.pg0.sw_if_index,
2195 self.pg0.remote_hosts[n].mac,
2196 self.pg0.remote_hosts[n].ip4,
2197 is_static=s).add_vpp_config()
2199 self.pg1.sw_if_index,
2200 self.pg1.remote_hosts[n].mac,
2201 self.pg1.remote_hosts[n].ip6,
2202 is_static=s).add_vpp_config()
2204 # flush the interfaces individually
2205 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2207 # check we haven't flushed that which we shouldn't
2208 for n in range(N_HOSTS):
2209 self.assertTrue(find_nbr(self,
2210 self.pg1.sw_if_index,
2211 self.pg1.remote_hosts[n].ip6,
2214 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2216 for n in range(N_HOSTS):
2217 self.assertFalse(find_nbr(self,
2218 self.pg0.sw_if_index,
2219 self.pg0.remote_hosts[n].ip4))
2220 self.assertFalse(find_nbr(self,
2221 self.pg1.sw_if_index,
2222 self.pg1.remote_hosts[n].ip6))
2224 # add the nieghbours back
2225 for n in range(N_HOSTS):
2227 self.pg0.sw_if_index,
2228 self.pg0.remote_hosts[n].mac,
2229 self.pg0.remote_hosts[n].ip4,
2230 is_static=s).add_vpp_config()
2232 self.pg1.sw_if_index,
2233 self.pg1.remote_hosts[n].mac,
2234 self.pg1.remote_hosts[n].ip6,
2235 is_static=s).add_vpp_config()
2237 self.logger.info(self.vapi.cli("sh ip neighbor"))
2239 # flush both interfaces at the same time
2240 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2242 # check we haven't flushed that which we shouldn't
2243 for n in range(N_HOSTS):
2244 self.assertTrue(find_nbr(self,
2245 self.pg0.sw_if_index,
2246 self.pg0.remote_hosts[n].ip4,
2249 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2251 for n in range(N_HOSTS):
2252 self.assertFalse(find_nbr(self,
2253 self.pg0.sw_if_index,
2254 self.pg0.remote_hosts[n].ip4))
2255 self.assertFalse(find_nbr(self,
2256 self.pg1.sw_if_index,
2257 self.pg1.remote_hosts[n].ip6))
2260 if __name__ == '__main__':
2261 unittest.main(testRunner=VppTestRunner)