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)
1442 arp = VppNeighbor(self,
1443 self.pg1.sw_if_index,
1444 self.pg1.remote_hosts[1].mac,
1445 self.pg1.remote_hosts[1].ip4)
1446 arp.add_vpp_config()
1448 self.assertTrue(find_nbr(self,
1449 self.pg1.sw_if_index,
1450 self.pg1.remote_hosts[1].ip4,
1451 mac=self.pg1.remote_hosts[1].mac))
1454 # Send a GARP (request) to swap the host 1's address to that of host 2
1456 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1457 src=self.pg1.remote_hosts[2].mac) /
1459 hwdst=self.pg1.local_mac,
1460 hwsrc=self.pg1.remote_hosts[2].mac,
1461 pdst=self.pg1.remote_hosts[1].ip4,
1462 psrc=self.pg1.remote_hosts[1].ip4))
1464 self.pg1.add_stream(p1)
1465 self.pg_enable_capture(self.pg_interfaces)
1468 self.assertTrue(find_nbr(self,
1469 self.pg1.sw_if_index,
1470 self.pg1.remote_hosts[1].ip4,
1471 mac=self.pg1.remote_hosts[2].mac))
1474 # Send a GARP (reply) to swap the host 1's address to that of host 3
1476 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1477 src=self.pg1.remote_hosts[3].mac) /
1479 hwdst=self.pg1.local_mac,
1480 hwsrc=self.pg1.remote_hosts[3].mac,
1481 pdst=self.pg1.remote_hosts[1].ip4,
1482 psrc=self.pg1.remote_hosts[1].ip4))
1484 self.pg1.add_stream(p1)
1485 self.pg_enable_capture(self.pg_interfaces)
1488 self.assertTrue(find_nbr(self,
1489 self.pg1.sw_if_index,
1490 self.pg1.remote_hosts[1].ip4,
1491 mac=self.pg1.remote_hosts[3].mac))
1494 # GARPs (request nor replies) for host we don't know yet
1495 # don't result in new neighbour entries
1497 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1498 src=self.pg1.remote_hosts[3].mac) /
1500 hwdst=self.pg1.local_mac,
1501 hwsrc=self.pg1.remote_hosts[3].mac,
1502 pdst=self.pg1.remote_hosts[2].ip4,
1503 psrc=self.pg1.remote_hosts[2].ip4))
1505 self.pg1.add_stream(p1)
1506 self.pg_enable_capture(self.pg_interfaces)
1509 self.assertFalse(find_nbr(self,
1510 self.pg1.sw_if_index,
1511 self.pg1.remote_hosts[2].ip4))
1513 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1514 src=self.pg1.remote_hosts[3].mac) /
1516 hwdst=self.pg1.local_mac,
1517 hwsrc=self.pg1.remote_hosts[3].mac,
1518 pdst=self.pg1.remote_hosts[2].ip4,
1519 psrc=self.pg1.remote_hosts[2].ip4))
1521 self.pg1.add_stream(p1)
1522 self.pg_enable_capture(self.pg_interfaces)
1525 self.assertFalse(find_nbr(self,
1526 self.pg1.sw_if_index,
1527 self.pg1.remote_hosts[2].ip4))
1529 def test_arp_incomplete(self):
1530 """ Incomplete Entries """
1533 # ensure that we throttle the ARP and ND requests
1535 self.pg0.generate_remote_hosts(2)
1540 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1541 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1542 self.pg0.sw_if_index)])
1543 ip_10_0_0_1.add_vpp_config()
1545 p1 = (Ether(dst=self.pg1.local_mac,
1546 src=self.pg1.remote_mac) /
1547 IP(src=self.pg1.remote_ip4,
1549 UDP(sport=1234, dport=1234) /
1552 self.pg1.add_stream(p1 * 257)
1553 self.pg_enable_capture(self.pg_interfaces)
1555 rx = self.pg0._get_capture(1)
1558 # how many we get is going to be dependent on the time for packet
1559 # processing but it should be small
1561 self.assertLess(len(rx), 64)
1566 ip_10_1 = VppIpRoute(self, "10::1", 128,
1567 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1568 self.pg0.sw_if_index,
1569 proto=DpoProto.DPO_PROTO_IP6)])
1570 ip_10_1.add_vpp_config()
1572 p1 = (Ether(dst=self.pg1.local_mac,
1573 src=self.pg1.remote_mac) /
1574 IPv6(src=self.pg1.remote_ip6,
1576 UDP(sport=1234, dport=1234) /
1579 self.pg1.add_stream(p1 * 257)
1580 self.pg_enable_capture(self.pg_interfaces)
1582 rx = self.pg0._get_capture(1)
1585 # how many we get is going to be dependent on the time for packet
1586 # processing but it should be small
1588 self.assertLess(len(rx), 64)
1590 def test_arp_forus(self):
1591 """ ARP for for-us """
1594 # Test that VPP responds with ARP requests to addresses that
1595 # are connected and local routes.
1596 # Use one of the 'remote' addresses in the subnet as a local address
1597 # The intention of this route is that it then acts like a secondary
1598 # address added to an interface
1600 self.pg0.generate_remote_hosts(2)
1603 self, self.pg0.remote_hosts[1].ip4, 32,
1604 [VppRoutePath("0.0.0.0",
1605 self.pg0.sw_if_index,
1606 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1607 forus.add_vpp_config()
1609 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1610 src=self.pg0.remote_mac) /
1612 hwdst=self.pg0.local_mac,
1613 hwsrc=self.pg0.remote_mac,
1614 pdst=self.pg0.remote_hosts[1].ip4,
1615 psrc=self.pg0.remote_ip4))
1617 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1619 self.verify_arp_resp(rx[0],
1621 self.pg0.remote_mac,
1622 self.pg0.remote_hosts[1].ip4,
1623 self.pg0.remote_ip4)
1625 def test_arp_table_swap(self):
1627 # Generate some hosts on the LAN
1630 self.pg1.generate_remote_hosts(N_NBRS)
1632 for n in range(N_NBRS):
1633 # a route thru each neighbour
1634 VppIpRoute(self, "10.0.0.%d" % n, 32,
1635 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1636 self.pg1.sw_if_index)]).add_vpp_config()
1638 # resolve each neighbour
1639 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1640 ARP(op="is-at", hwdst=self.pg1.local_mac,
1641 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1642 psrc=self.pg1.remote_hosts[n].ip4))
1644 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1646 self.logger.info(self.vapi.cli("sh ip neighbors"))
1649 # swap the table pg1 is in
1651 table = VppIpTable(self, 100).add_vpp_config()
1653 self.pg1.unconfig_ip4()
1654 self.pg1.set_table_ip4(100)
1655 self.pg1.config_ip4()
1658 # all neighbours are cleared
1660 for n in range(N_NBRS):
1661 self.assertFalse(find_nbr(self,
1662 self.pg1.sw_if_index,
1663 self.pg1.remote_hosts[n].ip4))
1666 # packets to all neighbours generate ARP requests
1668 for n in range(N_NBRS):
1669 # a route thru each neighbour
1670 VppIpRoute(self, "10.0.0.%d" % n, 32,
1671 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1672 self.pg1.sw_if_index)],
1673 table_id=100).add_vpp_config()
1675 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1676 dst=self.pg1.local_mac) /
1677 IP(src=self.pg1.remote_hosts[n].ip4,
1678 dst="10.0.0.%d" % n) /
1680 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1682 self.verify_arp_req(rx,
1685 self.pg1.remote_hosts[n].ip4)
1687 self.pg1.unconfig_ip4()
1688 self.pg1.set_table_ip4(0)
1691 class NeighborStatsTestCase(VppTestCase):
1692 """ ARP/ND Counters """
1695 def setUpClass(cls):
1696 super(NeighborStatsTestCase, cls).setUpClass()
1699 def tearDownClass(cls):
1700 super(NeighborStatsTestCase, cls).tearDownClass()
1703 super(NeighborStatsTestCase, self).setUp()
1705 self.create_pg_interfaces(range(2))
1707 # pg0 configured with ip4 and 6 addresses used for input
1708 # pg1 configured with ip4 and 6 addresses used for output
1709 # pg2 is unnumbered to pg0
1710 for i in self.pg_interfaces:
1718 super(NeighborStatsTestCase, self).tearDown()
1720 for i in self.pg_interfaces:
1725 def test_arp_stats(self):
1726 """ ARP Counters """
1728 self.vapi.cli("adj counters enable")
1729 self.pg1.generate_remote_hosts(2)
1731 arp1 = VppNeighbor(self,
1732 self.pg1.sw_if_index,
1733 self.pg1.remote_hosts[0].mac,
1734 self.pg1.remote_hosts[0].ip4)
1735 arp1.add_vpp_config()
1736 arp2 = VppNeighbor(self,
1737 self.pg1.sw_if_index,
1738 self.pg1.remote_hosts[1].mac,
1739 self.pg1.remote_hosts[1].ip4)
1740 arp2.add_vpp_config()
1742 p1 = (Ether(dst=self.pg0.local_mac,
1743 src=self.pg0.remote_mac) /
1744 IP(src=self.pg0.remote_ip4,
1745 dst=self.pg1.remote_hosts[0].ip4) /
1746 UDP(sport=1234, dport=1234) /
1748 p2 = (Ether(dst=self.pg0.local_mac,
1749 src=self.pg0.remote_mac) /
1750 IP(src=self.pg0.remote_ip4,
1751 dst=self.pg1.remote_hosts[1].ip4) /
1752 UDP(sport=1234, dport=1234) /
1755 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1756 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1758 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1759 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1761 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1762 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1764 def test_nd_stats(self):
1767 self.vapi.cli("adj counters enable")
1768 self.pg0.generate_remote_hosts(3)
1770 nd1 = VppNeighbor(self,
1771 self.pg0.sw_if_index,
1772 self.pg0.remote_hosts[1].mac,
1773 self.pg0.remote_hosts[1].ip6)
1774 nd1.add_vpp_config()
1775 nd2 = VppNeighbor(self,
1776 self.pg0.sw_if_index,
1777 self.pg0.remote_hosts[2].mac,
1778 self.pg0.remote_hosts[2].ip6)
1779 nd2.add_vpp_config()
1781 p1 = (Ether(dst=self.pg1.local_mac,
1782 src=self.pg1.remote_mac) /
1783 IPv6(src=self.pg1.remote_ip6,
1784 dst=self.pg0.remote_hosts[1].ip6) /
1785 UDP(sport=1234, dport=1234) /
1787 p2 = (Ether(dst=self.pg1.local_mac,
1788 src=self.pg1.remote_mac) /
1789 IPv6(src=self.pg1.remote_ip6,
1790 dst=self.pg0.remote_hosts[2].ip6) /
1791 UDP(sport=1234, dport=1234) /
1794 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1795 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1797 self.assertEqual(16, nd1.get_stats()['packets'])
1798 self.assertEqual(16, nd2.get_stats()['packets'])
1800 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1801 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1804 class NeighborAgeTestCase(VppTestCase):
1805 """ ARP/ND Aging """
1808 def setUpClass(cls):
1809 super(NeighborAgeTestCase, cls).setUpClass()
1812 def tearDownClass(cls):
1813 super(NeighborAgeTestCase, cls).tearDownClass()
1816 super(NeighborAgeTestCase, self).setUp()
1818 self.create_pg_interfaces(range(1))
1820 # pg0 configured with ip4 and 6 addresses used for input
1821 # pg1 configured with ip4 and 6 addresses used for output
1822 # pg2 is unnumbered to pg0
1823 for i in self.pg_interfaces:
1831 super(NeighborAgeTestCase, self).tearDown()
1833 for i in self.pg_interfaces:
1838 def wait_for_no_nbr(self, intf, address,
1839 n_tries=50, s_time=1):
1841 if not find_nbr(self, intf, address):
1843 n_tries = n_tries - 1
1848 def verify_arp_req(self, rx, smac, sip, dip):
1850 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1851 self.assertEqual(ether.src, smac)
1854 self.assertEqual(arp.hwtype, 1)
1855 self.assertEqual(arp.ptype, 0x800)
1856 self.assertEqual(arp.hwlen, 6)
1857 self.assertEqual(arp.plen, 4)
1858 self.assertEqual(arp.op, arp_opts["who-has"])
1859 self.assertEqual(arp.hwsrc, smac)
1860 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1861 self.assertEqual(arp.psrc, sip)
1862 self.assertEqual(arp.pdst, dip)
1865 """ Aging/Recycle """
1867 self.vapi.cli("set logging unthrottle 0")
1868 self.vapi.cli("set logging size %d" % 0xffff)
1870 self.pg0.generate_remote_hosts(201)
1872 vaf = VppEnum.vl_api_address_family_t
1875 # start listening on all interfaces
1877 self.pg_enable_capture(self.pg_interfaces)
1880 # Set the neighbor configuration:
1885 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1890 self.vapi.cli("sh ip neighbor-config")
1892 # add the 198 neighbours that should pass (-1 for one created in setup)
1893 for ii in range(200):
1895 self.pg0.sw_if_index,
1896 self.pg0.remote_hosts[ii].mac,
1897 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1899 # one more neighbor over the limit should fail
1900 with self.vapi.assert_negative_api_retval():
1902 self.pg0.sw_if_index,
1903 self.pg0.remote_hosts[200].mac,
1904 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1907 # change the config to allow recycling the old neighbors
1909 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1914 # now new additions are allowed
1916 self.pg0.sw_if_index,
1917 self.pg0.remote_hosts[200].mac,
1918 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1920 # add the first neighbor we configured has been re-used
1921 self.assertFalse(find_nbr(self,
1922 self.pg0.sw_if_index,
1923 self.pg0.remote_hosts[0].ip4))
1924 self.assertTrue(find_nbr(self,
1925 self.pg0.sw_if_index,
1926 self.pg0.remote_hosts[200].ip4))
1929 # change the config to age old neighbors
1931 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1936 self.vapi.cli("sh ip4 neighbor-sorted")
1939 # expect probes from all these ARP entries as they age
1940 # 3 probes for each neighbor 3*200 = 600
1941 rxs = self.pg0.get_capture(600, timeout=8)
1944 for jj in range(200):
1945 rx = rxs[ii*200 + jj]
1949 # 3 probes sent then 1 more second to see if a reply comes, before
1952 for jj in range(1, 201):
1953 self.wait_for_no_nbr(self.pg0.sw_if_index,
1954 self.pg0.remote_hosts[jj].ip4)
1956 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1957 af=vaf.ADDRESS_IP4))
1960 # load up some neighbours again with 2s aging enabled
1961 # they should be removed after 10s (2s age + 4s for probes + gap)
1963 for ii in range(10):
1965 self.pg0.sw_if_index,
1966 self.pg0.remote_hosts[ii].mac,
1967 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1969 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1970 af=vaf.ADDRESS_IP4))
1973 # check if we can set age and recycle with empty neighbor list
1975 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1981 # load up some neighbours again, then disable the aging
1982 # they should still be there in 10 seconds time
1984 for ii in range(10):
1986 self.pg0.sw_if_index,
1987 self.pg0.remote_hosts[ii].mac,
1988 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1989 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1995 self.assertTrue(find_nbr(self,
1996 self.pg0.sw_if_index,
1997 self.pg0.remote_hosts[0].ip4))
2000 class NeighborReplaceTestCase(VppTestCase):
2001 """ ARP/ND Replacement """
2004 def setUpClass(cls):
2005 super(NeighborReplaceTestCase, cls).setUpClass()
2008 def tearDownClass(cls):
2009 super(NeighborReplaceTestCase, cls).tearDownClass()
2012 super(NeighborReplaceTestCase, self).setUp()
2014 self.create_pg_interfaces(range(4))
2016 # pg0 configured with ip4 and 6 addresses used for input
2017 # pg1 configured with ip4 and 6 addresses used for output
2018 # pg2 is unnumbered to pg0
2019 for i in self.pg_interfaces:
2027 super(NeighborReplaceTestCase, self).tearDown()
2029 for i in self.pg_interfaces:
2034 def test_replace(self):
2039 for i in self.pg_interfaces:
2040 i.generate_remote_hosts(N_HOSTS)
2041 i.configure_ipv4_neighbors()
2042 i.configure_ipv6_neighbors()
2045 self.vapi.ip_neighbor_replace_begin()
2046 self.vapi.ip_neighbor_replace_end()
2048 for i in self.pg_interfaces:
2049 for h in range(N_HOSTS):
2050 self.assertFalse(find_nbr(self,
2051 self.pg0.sw_if_index,
2052 self.pg0.remote_hosts[h].ip4))
2053 self.assertFalse(find_nbr(self,
2054 self.pg0.sw_if_index,
2055 self.pg0.remote_hosts[h].ip6))
2058 # and them all back via the API
2060 for i in self.pg_interfaces:
2061 for h in range(N_HOSTS):
2064 i.remote_hosts[h].mac,
2065 i.remote_hosts[h].ip4).add_vpp_config()
2068 i.remote_hosts[h].mac,
2069 i.remote_hosts[h].ip6).add_vpp_config()
2072 # begin the replacement again, this time touch some
2073 # the neighbours on pg1 so they are not deleted
2075 self.vapi.ip_neighbor_replace_begin()
2077 # update from the API all neighbours on pg1
2078 for h in range(N_HOSTS):
2080 self.pg1.sw_if_index,
2081 self.pg1.remote_hosts[h].mac,
2082 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2084 self.pg1.sw_if_index,
2085 self.pg1.remote_hosts[h].mac,
2086 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2088 # update from the data-plane all neighbours on pg3
2089 self.pg3.configure_ipv4_neighbors()
2090 self.pg3.configure_ipv6_neighbors()
2092 # complete the replacement
2093 self.logger.info(self.vapi.cli("sh ip neighbors"))
2094 self.vapi.ip_neighbor_replace_end()
2096 for i in self.pg_interfaces:
2097 if i == self.pg1 or i == self.pg3:
2098 # neighbours on pg1 and pg3 are still present
2099 for h in range(N_HOSTS):
2100 self.assertTrue(find_nbr(self,
2102 i.remote_hosts[h].ip4))
2103 self.assertTrue(find_nbr(self,
2105 i.remote_hosts[h].ip6))
2107 # all other neighbours are toast
2108 for h in range(N_HOSTS):
2109 self.assertFalse(find_nbr(self,
2111 i.remote_hosts[h].ip4))
2112 self.assertFalse(find_nbr(self,
2114 i.remote_hosts[h].ip6))
2117 class NeighborFlush(VppTestCase):
2118 """ Neighbor Flush """
2121 def setUpClass(cls):
2122 super(NeighborFlush, cls).setUpClass()
2125 def tearDownClass(cls):
2126 super(NeighborFlush, cls).tearDownClass()
2129 super(NeighborFlush, self).setUp()
2131 self.create_pg_interfaces(range(2))
2133 for i in self.pg_interfaces:
2141 super(NeighborFlush, self).tearDown()
2143 for i in self.pg_interfaces:
2148 def test_flush(self):
2149 """ Neighbour Flush """
2152 nf = e.vl_api_ip_neighbor_flags_t
2153 af = e.vl_api_address_family_t
2155 static = [False, True]
2156 self.pg0.generate_remote_hosts(N_HOSTS)
2157 self.pg1.generate_remote_hosts(N_HOSTS)
2160 # a few v4 and v6 dynamic neoghbors
2161 for n in range(N_HOSTS):
2163 self.pg0.sw_if_index,
2164 self.pg0.remote_hosts[n].mac,
2165 self.pg0.remote_hosts[n].ip4,
2166 is_static=s).add_vpp_config()
2168 self.pg1.sw_if_index,
2169 self.pg1.remote_hosts[n].mac,
2170 self.pg1.remote_hosts[n].ip6,
2171 is_static=s).add_vpp_config()
2173 # flush the interfaces individually
2174 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2176 # check we haven't flushed that which we shouldn't
2177 for n in range(N_HOSTS):
2178 self.assertTrue(find_nbr(self,
2179 self.pg1.sw_if_index,
2180 self.pg1.remote_hosts[n].ip6,
2183 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2185 for n in range(N_HOSTS):
2186 self.assertFalse(find_nbr(self,
2187 self.pg0.sw_if_index,
2188 self.pg0.remote_hosts[n].ip4))
2189 self.assertFalse(find_nbr(self,
2190 self.pg1.sw_if_index,
2191 self.pg1.remote_hosts[n].ip6))
2193 # add the nieghbours back
2194 for n in range(N_HOSTS):
2196 self.pg0.sw_if_index,
2197 self.pg0.remote_hosts[n].mac,
2198 self.pg0.remote_hosts[n].ip4,
2199 is_static=s).add_vpp_config()
2201 self.pg1.sw_if_index,
2202 self.pg1.remote_hosts[n].mac,
2203 self.pg1.remote_hosts[n].ip6,
2204 is_static=s).add_vpp_config()
2206 self.logger.info(self.vapi.cli("sh ip neighbor"))
2208 # flush both interfaces at the same time
2209 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2211 # check we haven't flushed that which we shouldn't
2212 for n in range(N_HOSTS):
2213 self.assertTrue(find_nbr(self,
2214 self.pg0.sw_if_index,
2215 self.pg0.remote_hosts[n].ip4,
2218 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2220 for n in range(N_HOSTS):
2221 self.assertFalse(find_nbr(self,
2222 self.pg0.sw_if_index,
2223 self.pg0.remote_hosts[n].ip4))
2224 self.assertFalse(find_nbr(self,
2225 self.pg1.sw_if_index,
2226 self.pg1.remote_hosts[n].ip6))
2229 if __name__ == '__main__':
2230 unittest.main(testRunner=VppTestRunner)