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_incomplete(self):
1251 """ ARP Incomplete"""
1252 self.pg1.generate_remote_hosts(3)
1254 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1255 IP(src=self.pg0.remote_ip4,
1256 dst=self.pg1.remote_hosts[1].ip4) /
1257 UDP(sport=1234, dport=1234) /
1259 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1260 IP(src=self.pg0.remote_ip4,
1261 dst=self.pg1.remote_hosts[2].ip4) /
1262 UDP(sport=1234, dport=1234) /
1266 # a packet to an unresolved destination generates an ARP request
1268 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1269 self.verify_arp_req(rx[0],
1272 self.pg1._remote_hosts[1].ip4)
1275 # add a neighbour for remote host 1
1277 static_arp = VppNeighbor(self,
1278 self.pg1.sw_if_index,
1279 self.pg1.remote_hosts[1].mac,
1280 self.pg1.remote_hosts[1].ip4,
1282 static_arp.add_vpp_config()
1285 # change the interface's MAC
1287 mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1288 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1289 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1290 mac_string = ''.join(mac)
1292 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1296 # now ARP requests come from the new source mac
1298 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1299 self.verify_arp_req(rx[0],
1300 "00:00:00:33:33:33",
1302 self.pg1._remote_hosts[2].ip4)
1305 # packets to the resolved host also have the new source mac
1307 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1308 self.verify_ip(rx[0],
1309 "00:00:00:33:33:33",
1310 self.pg1.remote_hosts[1].mac,
1311 self.pg0.remote_ip4,
1312 self.pg1.remote_hosts[1].ip4)
1315 # set the mac address on the interface that does not have a
1316 # configured subnet and thus no glean
1318 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1321 def test_garp(self):
1325 # Generate some hosts on the LAN
1327 self.pg1.generate_remote_hosts(4)
1332 arp = VppNeighbor(self,
1333 self.pg1.sw_if_index,
1334 self.pg1.remote_hosts[1].mac,
1335 self.pg1.remote_hosts[1].ip4)
1336 arp.add_vpp_config()
1338 self.assertTrue(find_nbr(self,
1339 self.pg1.sw_if_index,
1340 self.pg1.remote_hosts[1].ip4,
1341 mac=self.pg1.remote_hosts[1].mac))
1344 # Send a GARP (request) to swap the host 1's address to that of host 2
1346 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1347 src=self.pg1.remote_hosts[2].mac) /
1349 hwdst=self.pg1.local_mac,
1350 hwsrc=self.pg1.remote_hosts[2].mac,
1351 pdst=self.pg1.remote_hosts[1].ip4,
1352 psrc=self.pg1.remote_hosts[1].ip4))
1354 self.pg1.add_stream(p1)
1355 self.pg_enable_capture(self.pg_interfaces)
1358 self.assertTrue(find_nbr(self,
1359 self.pg1.sw_if_index,
1360 self.pg1.remote_hosts[1].ip4,
1361 mac=self.pg1.remote_hosts[2].mac))
1364 # Send a GARP (reply) to swap the host 1's address to that of host 3
1366 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1367 src=self.pg1.remote_hosts[3].mac) /
1369 hwdst=self.pg1.local_mac,
1370 hwsrc=self.pg1.remote_hosts[3].mac,
1371 pdst=self.pg1.remote_hosts[1].ip4,
1372 psrc=self.pg1.remote_hosts[1].ip4))
1374 self.pg1.add_stream(p1)
1375 self.pg_enable_capture(self.pg_interfaces)
1378 self.assertTrue(find_nbr(self,
1379 self.pg1.sw_if_index,
1380 self.pg1.remote_hosts[1].ip4,
1381 mac=self.pg1.remote_hosts[3].mac))
1384 # GARPs (request nor replies) for host we don't know yet
1385 # don't result in new neighbour entries
1387 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1388 src=self.pg1.remote_hosts[3].mac) /
1390 hwdst=self.pg1.local_mac,
1391 hwsrc=self.pg1.remote_hosts[3].mac,
1392 pdst=self.pg1.remote_hosts[2].ip4,
1393 psrc=self.pg1.remote_hosts[2].ip4))
1395 self.pg1.add_stream(p1)
1396 self.pg_enable_capture(self.pg_interfaces)
1399 self.assertFalse(find_nbr(self,
1400 self.pg1.sw_if_index,
1401 self.pg1.remote_hosts[2].ip4))
1403 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1404 src=self.pg1.remote_hosts[3].mac) /
1406 hwdst=self.pg1.local_mac,
1407 hwsrc=self.pg1.remote_hosts[3].mac,
1408 pdst=self.pg1.remote_hosts[2].ip4,
1409 psrc=self.pg1.remote_hosts[2].ip4))
1411 self.pg1.add_stream(p1)
1412 self.pg_enable_capture(self.pg_interfaces)
1415 self.assertFalse(find_nbr(self,
1416 self.pg1.sw_if_index,
1417 self.pg1.remote_hosts[2].ip4))
1419 def test_arp_incomplete(self):
1420 """ Incomplete Entries """
1423 # ensure that we throttle the ARP and ND requests
1425 self.pg0.generate_remote_hosts(2)
1430 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1431 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1432 self.pg0.sw_if_index)])
1433 ip_10_0_0_1.add_vpp_config()
1435 p1 = (Ether(dst=self.pg1.local_mac,
1436 src=self.pg1.remote_mac) /
1437 IP(src=self.pg1.remote_ip4,
1439 UDP(sport=1234, dport=1234) /
1442 self.pg1.add_stream(p1 * 257)
1443 self.pg_enable_capture(self.pg_interfaces)
1445 rx = self.pg0._get_capture(1)
1448 # how many we get is going to be dependent on the time for packet
1449 # processing but it should be small
1451 self.assertLess(len(rx), 64)
1456 ip_10_1 = VppIpRoute(self, "10::1", 128,
1457 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1458 self.pg0.sw_if_index,
1459 proto=DpoProto.DPO_PROTO_IP6)])
1460 ip_10_1.add_vpp_config()
1462 p1 = (Ether(dst=self.pg1.local_mac,
1463 src=self.pg1.remote_mac) /
1464 IPv6(src=self.pg1.remote_ip6,
1466 UDP(sport=1234, dport=1234) /
1469 self.pg1.add_stream(p1 * 257)
1470 self.pg_enable_capture(self.pg_interfaces)
1472 rx = self.pg0._get_capture(1)
1475 # how many we get is going to be dependent on the time for packet
1476 # processing but it should be small
1478 self.assertLess(len(rx), 64)
1480 def test_arp_forus(self):
1481 """ ARP for for-us """
1484 # Test that VPP responds with ARP requests to addresses that
1485 # are connected and local routes.
1486 # Use one of the 'remote' addresses in the subnet as a local address
1487 # The intention of this route is that it then acts like a secondary
1488 # address added to an interface
1490 self.pg0.generate_remote_hosts(2)
1493 self, self.pg0.remote_hosts[1].ip4, 32,
1494 [VppRoutePath("0.0.0.0",
1495 self.pg0.sw_if_index,
1496 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1497 forus.add_vpp_config()
1499 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1500 src=self.pg0.remote_mac) /
1502 hwdst=self.pg0.local_mac,
1503 hwsrc=self.pg0.remote_mac,
1504 pdst=self.pg0.remote_hosts[1].ip4,
1505 psrc=self.pg0.remote_ip4))
1507 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1509 self.verify_arp_resp(rx[0],
1511 self.pg0.remote_mac,
1512 self.pg0.remote_hosts[1].ip4,
1513 self.pg0.remote_ip4)
1515 def test_arp_table_swap(self):
1517 # Generate some hosts on the LAN
1520 self.pg1.generate_remote_hosts(N_NBRS)
1522 for n in range(N_NBRS):
1523 # a route thru each neighbour
1524 VppIpRoute(self, "10.0.0.%d" % n, 32,
1525 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1526 self.pg1.sw_if_index)]).add_vpp_config()
1528 # resolve each neighbour
1529 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1530 ARP(op="is-at", hwdst=self.pg1.local_mac,
1531 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1532 psrc=self.pg1.remote_hosts[n].ip4))
1534 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1536 self.logger.info(self.vapi.cli("sh ip neighbors"))
1539 # swap the table pg1 is in
1541 table = VppIpTable(self, 100).add_vpp_config()
1543 self.pg1.unconfig_ip4()
1544 self.pg1.set_table_ip4(100)
1545 self.pg1.config_ip4()
1548 # all neighbours are cleared
1550 for n in range(N_NBRS):
1551 self.assertFalse(find_nbr(self,
1552 self.pg1.sw_if_index,
1553 self.pg1.remote_hosts[n].ip4))
1556 # packets to all neighbours generate ARP requests
1558 for n in range(N_NBRS):
1559 # a route thru each neighbour
1560 VppIpRoute(self, "10.0.0.%d" % n, 32,
1561 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1562 self.pg1.sw_if_index)],
1563 table_id=100).add_vpp_config()
1565 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1566 dst=self.pg1.local_mac) /
1567 IP(src=self.pg1.remote_hosts[n].ip4,
1568 dst="10.0.0.%d" % n) /
1570 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1572 self.verify_arp_req(rx,
1575 self.pg1.remote_hosts[n].ip4)
1577 self.pg1.unconfig_ip4()
1578 self.pg1.set_table_ip4(0)
1581 class NeighborStatsTestCase(VppTestCase):
1582 """ ARP/ND Counters """
1585 def setUpClass(cls):
1586 super(NeighborStatsTestCase, cls).setUpClass()
1589 def tearDownClass(cls):
1590 super(NeighborStatsTestCase, cls).tearDownClass()
1593 super(NeighborStatsTestCase, self).setUp()
1595 self.create_pg_interfaces(range(2))
1597 # pg0 configured with ip4 and 6 addresses used for input
1598 # pg1 configured with ip4 and 6 addresses used for output
1599 # pg2 is unnumbered to pg0
1600 for i in self.pg_interfaces:
1608 super(NeighborStatsTestCase, self).tearDown()
1610 for i in self.pg_interfaces:
1615 def test_arp_stats(self):
1616 """ ARP Counters """
1618 self.vapi.cli("adj counters enable")
1619 self.pg1.generate_remote_hosts(2)
1621 arp1 = VppNeighbor(self,
1622 self.pg1.sw_if_index,
1623 self.pg1.remote_hosts[0].mac,
1624 self.pg1.remote_hosts[0].ip4)
1625 arp1.add_vpp_config()
1626 arp2 = VppNeighbor(self,
1627 self.pg1.sw_if_index,
1628 self.pg1.remote_hosts[1].mac,
1629 self.pg1.remote_hosts[1].ip4)
1630 arp2.add_vpp_config()
1632 p1 = (Ether(dst=self.pg0.local_mac,
1633 src=self.pg0.remote_mac) /
1634 IP(src=self.pg0.remote_ip4,
1635 dst=self.pg1.remote_hosts[0].ip4) /
1636 UDP(sport=1234, dport=1234) /
1638 p2 = (Ether(dst=self.pg0.local_mac,
1639 src=self.pg0.remote_mac) /
1640 IP(src=self.pg0.remote_ip4,
1641 dst=self.pg1.remote_hosts[1].ip4) /
1642 UDP(sport=1234, dport=1234) /
1645 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1646 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1648 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1649 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1651 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1652 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1654 def test_nd_stats(self):
1657 self.vapi.cli("adj counters enable")
1658 self.pg0.generate_remote_hosts(3)
1660 nd1 = VppNeighbor(self,
1661 self.pg0.sw_if_index,
1662 self.pg0.remote_hosts[1].mac,
1663 self.pg0.remote_hosts[1].ip6)
1664 nd1.add_vpp_config()
1665 nd2 = VppNeighbor(self,
1666 self.pg0.sw_if_index,
1667 self.pg0.remote_hosts[2].mac,
1668 self.pg0.remote_hosts[2].ip6)
1669 nd2.add_vpp_config()
1671 p1 = (Ether(dst=self.pg1.local_mac,
1672 src=self.pg1.remote_mac) /
1673 IPv6(src=self.pg1.remote_ip6,
1674 dst=self.pg0.remote_hosts[1].ip6) /
1675 UDP(sport=1234, dport=1234) /
1677 p2 = (Ether(dst=self.pg1.local_mac,
1678 src=self.pg1.remote_mac) /
1679 IPv6(src=self.pg1.remote_ip6,
1680 dst=self.pg0.remote_hosts[2].ip6) /
1681 UDP(sport=1234, dport=1234) /
1684 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1685 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1687 self.assertEqual(16, nd1.get_stats()['packets'])
1688 self.assertEqual(16, nd2.get_stats()['packets'])
1690 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1691 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1694 class NeighborAgeTestCase(VppTestCase):
1695 """ ARP/ND Aging """
1698 def setUpClass(cls):
1699 super(NeighborAgeTestCase, cls).setUpClass()
1702 def tearDownClass(cls):
1703 super(NeighborAgeTestCase, cls).tearDownClass()
1706 super(NeighborAgeTestCase, self).setUp()
1708 self.create_pg_interfaces(range(1))
1710 # pg0 configured with ip4 and 6 addresses used for input
1711 # pg1 configured with ip4 and 6 addresses used for output
1712 # pg2 is unnumbered to pg0
1713 for i in self.pg_interfaces:
1721 super(NeighborAgeTestCase, self).tearDown()
1723 for i in self.pg_interfaces:
1728 def wait_for_no_nbr(self, intf, address,
1729 n_tries=50, s_time=1):
1731 if not find_nbr(self, intf, address):
1733 n_tries = n_tries - 1
1738 def verify_arp_req(self, rx, smac, sip, dip):
1740 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1741 self.assertEqual(ether.src, smac)
1744 self.assertEqual(arp.hwtype, 1)
1745 self.assertEqual(arp.ptype, 0x800)
1746 self.assertEqual(arp.hwlen, 6)
1747 self.assertEqual(arp.plen, 4)
1748 self.assertEqual(arp.op, arp_opts["who-has"])
1749 self.assertEqual(arp.hwsrc, smac)
1750 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1751 self.assertEqual(arp.psrc, sip)
1752 self.assertEqual(arp.pdst, dip)
1755 """ Aging/Recycle """
1757 self.vapi.cli("set logging unthrottle 0")
1758 self.vapi.cli("set logging size %d" % 0xffff)
1760 self.pg0.generate_remote_hosts(201)
1762 vaf = VppEnum.vl_api_address_family_t
1765 # start listening on all interfaces
1767 self.pg_enable_capture(self.pg_interfaces)
1770 # Set the neighbor configuration:
1775 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1780 self.vapi.cli("sh ip neighbor-config")
1782 # add the 198 neighbours that should pass (-1 for one created in setup)
1783 for ii in range(200):
1785 self.pg0.sw_if_index,
1786 self.pg0.remote_hosts[ii].mac,
1787 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1789 # one more neighbor over the limit should fail
1790 with self.vapi.assert_negative_api_retval():
1792 self.pg0.sw_if_index,
1793 self.pg0.remote_hosts[200].mac,
1794 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1797 # change the config to allow recycling the old neighbors
1799 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1804 # now new additions are allowed
1806 self.pg0.sw_if_index,
1807 self.pg0.remote_hosts[200].mac,
1808 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1810 # add the first neighbor we configured has been re-used
1811 self.assertFalse(find_nbr(self,
1812 self.pg0.sw_if_index,
1813 self.pg0.remote_hosts[0].ip4))
1814 self.assertTrue(find_nbr(self,
1815 self.pg0.sw_if_index,
1816 self.pg0.remote_hosts[200].ip4))
1819 # change the config to age old neighbors
1821 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1826 self.vapi.cli("sh ip4 neighbor-sorted")
1829 # expect probes from all these ARP entries as they age
1830 # 3 probes for each neighbor 3*200 = 600
1831 rxs = self.pg0.get_capture(600, timeout=8)
1834 for jj in range(200):
1835 rx = rxs[ii*200 + jj]
1839 # 3 probes sent then 1 more second to see if a reply comes, before
1842 for jj in range(1, 201):
1843 self.wait_for_no_nbr(self.pg0.sw_if_index,
1844 self.pg0.remote_hosts[jj].ip4)
1846 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1847 af=vaf.ADDRESS_IP4))
1850 # load up some neighbours again with 2s aging enabled
1851 # they should be removed after 10s (2s age + 4s for probes + gap)
1853 for ii in range(10):
1855 self.pg0.sw_if_index,
1856 self.pg0.remote_hosts[ii].mac,
1857 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1859 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1860 af=vaf.ADDRESS_IP4))
1863 # check if we can set age and recycle with empty neighbor list
1865 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1871 # load up some neighbours again, then disable the aging
1872 # they should still be there in 10 seconds time
1874 for ii in range(10):
1876 self.pg0.sw_if_index,
1877 self.pg0.remote_hosts[ii].mac,
1878 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1879 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1885 self.assertTrue(find_nbr(self,
1886 self.pg0.sw_if_index,
1887 self.pg0.remote_hosts[0].ip4))
1890 class NeighborReplaceTestCase(VppTestCase):
1891 """ ARP/ND Replacement """
1894 def setUpClass(cls):
1895 super(NeighborReplaceTestCase, cls).setUpClass()
1898 def tearDownClass(cls):
1899 super(NeighborReplaceTestCase, cls).tearDownClass()
1902 super(NeighborReplaceTestCase, self).setUp()
1904 self.create_pg_interfaces(range(4))
1906 # pg0 configured with ip4 and 6 addresses used for input
1907 # pg1 configured with ip4 and 6 addresses used for output
1908 # pg2 is unnumbered to pg0
1909 for i in self.pg_interfaces:
1917 super(NeighborReplaceTestCase, self).tearDown()
1919 for i in self.pg_interfaces:
1924 def test_replace(self):
1929 for i in self.pg_interfaces:
1930 i.generate_remote_hosts(N_HOSTS)
1931 i.configure_ipv4_neighbors()
1932 i.configure_ipv6_neighbors()
1935 self.vapi.ip_neighbor_replace_begin()
1936 self.vapi.ip_neighbor_replace_end()
1938 for i in self.pg_interfaces:
1939 for h in range(N_HOSTS):
1940 self.assertFalse(find_nbr(self,
1941 self.pg0.sw_if_index,
1942 self.pg0.remote_hosts[h].ip4))
1943 self.assertFalse(find_nbr(self,
1944 self.pg0.sw_if_index,
1945 self.pg0.remote_hosts[h].ip6))
1948 # and them all back via the API
1950 for i in self.pg_interfaces:
1951 for h in range(N_HOSTS):
1954 i.remote_hosts[h].mac,
1955 i.remote_hosts[h].ip4).add_vpp_config()
1958 i.remote_hosts[h].mac,
1959 i.remote_hosts[h].ip6).add_vpp_config()
1962 # begin the replacement again, this time touch some
1963 # the neighbours on pg1 so they are not deleted
1965 self.vapi.ip_neighbor_replace_begin()
1967 # update from the API all neighbours on pg1
1968 for h in range(N_HOSTS):
1970 self.pg1.sw_if_index,
1971 self.pg1.remote_hosts[h].mac,
1972 self.pg1.remote_hosts[h].ip4).add_vpp_config()
1974 self.pg1.sw_if_index,
1975 self.pg1.remote_hosts[h].mac,
1976 self.pg1.remote_hosts[h].ip6).add_vpp_config()
1978 # update from the data-plane all neighbours on pg3
1979 self.pg3.configure_ipv4_neighbors()
1980 self.pg3.configure_ipv6_neighbors()
1982 # complete the replacement
1983 self.logger.info(self.vapi.cli("sh ip neighbors"))
1984 self.vapi.ip_neighbor_replace_end()
1986 for i in self.pg_interfaces:
1987 if i == self.pg1 or i == self.pg3:
1988 # neighbours on pg1 and pg3 are still present
1989 for h in range(N_HOSTS):
1990 self.assertTrue(find_nbr(self,
1992 i.remote_hosts[h].ip4))
1993 self.assertTrue(find_nbr(self,
1995 i.remote_hosts[h].ip6))
1997 # all other neighbours are toast
1998 for h in range(N_HOSTS):
1999 self.assertFalse(find_nbr(self,
2001 i.remote_hosts[h].ip4))
2002 self.assertFalse(find_nbr(self,
2004 i.remote_hosts[h].ip6))
2007 class NeighborFlush(VppTestCase):
2008 """ Neighbor Flush """
2011 def setUpClass(cls):
2012 super(NeighborFlush, cls).setUpClass()
2015 def tearDownClass(cls):
2016 super(NeighborFlush, cls).tearDownClass()
2019 super(NeighborFlush, self).setUp()
2021 self.create_pg_interfaces(range(2))
2023 for i in self.pg_interfaces:
2031 super(NeighborFlush, self).tearDown()
2033 for i in self.pg_interfaces:
2038 def test_flush(self):
2039 """ Neighbour Flush """
2042 nf = e.vl_api_ip_neighbor_flags_t
2043 af = e.vl_api_address_family_t
2045 static = [False, True]
2046 self.pg0.generate_remote_hosts(N_HOSTS)
2047 self.pg1.generate_remote_hosts(N_HOSTS)
2050 # a few v4 and v6 dynamic neoghbors
2051 for n in range(N_HOSTS):
2053 self.pg0.sw_if_index,
2054 self.pg0.remote_hosts[n].mac,
2055 self.pg0.remote_hosts[n].ip4,
2056 is_static=s).add_vpp_config()
2058 self.pg1.sw_if_index,
2059 self.pg1.remote_hosts[n].mac,
2060 self.pg1.remote_hosts[n].ip6,
2061 is_static=s).add_vpp_config()
2063 # flush the interfaces individually
2064 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2066 # check we haven't flushed that which we shouldn't
2067 for n in range(N_HOSTS):
2068 self.assertTrue(find_nbr(self,
2069 self.pg1.sw_if_index,
2070 self.pg1.remote_hosts[n].ip6,
2073 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2075 for n in range(N_HOSTS):
2076 self.assertFalse(find_nbr(self,
2077 self.pg0.sw_if_index,
2078 self.pg0.remote_hosts[n].ip4))
2079 self.assertFalse(find_nbr(self,
2080 self.pg1.sw_if_index,
2081 self.pg1.remote_hosts[n].ip6))
2083 # add the nieghbours back
2084 for n in range(N_HOSTS):
2086 self.pg0.sw_if_index,
2087 self.pg0.remote_hosts[n].mac,
2088 self.pg0.remote_hosts[n].ip4,
2089 is_static=s).add_vpp_config()
2091 self.pg1.sw_if_index,
2092 self.pg1.remote_hosts[n].mac,
2093 self.pg1.remote_hosts[n].ip6,
2094 is_static=s).add_vpp_config()
2096 self.logger.info(self.vapi.cli("sh ip neighbor"))
2098 # flush both interfaces at the same time
2099 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2101 # check we haven't flushed that which we shouldn't
2102 for n in range(N_HOSTS):
2103 self.assertTrue(find_nbr(self,
2104 self.pg0.sw_if_index,
2105 self.pg0.remote_hosts[n].ip4,
2108 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2110 for n in range(N_HOSTS):
2111 self.assertFalse(find_nbr(self,
2112 self.pg0.sw_if_index,
2113 self.pg0.remote_hosts[n].ip4))
2114 self.assertFalse(find_nbr(self,
2115 self.pg1.sw_if_index,
2116 self.pg1.remote_hosts[n].ip6))
2119 if __name__ == '__main__':
2120 unittest.main(testRunner=VppTestRunner)