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 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
209 # this matches all of the listnerers
210 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
213 self.assertEqual(str(e.neighbor.ip_address),
214 self.pg1.remote_hosts[1].ip4)
217 # now we expect IP traffic forwarded
219 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
220 IP(src=self.pg0.remote_ip4,
221 dst=self.pg1._remote_hosts[1].ip4) /
222 UDP(sport=1234, dport=1234) /
225 self.pg0.add_stream(dyn_p)
226 self.pg_enable_capture(self.pg_interfaces)
229 rx = self.pg1.get_capture(1)
231 self.verify_ip(rx[0],
233 self.pg1.remote_hosts[1].mac,
235 self.pg1._remote_hosts[1].ip4)
238 # And a Static ARP entry for host 2
240 static_arp = VppNeighbor(self,
241 self.pg1.sw_if_index,
242 self.pg1.remote_hosts[2].mac,
243 self.pg1.remote_hosts[2].ip4,
245 static_arp.add_vpp_config()
246 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
249 self.assertEqual(str(e.neighbor.ip_address),
250 self.pg1.remote_hosts[2].ip4)
252 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
253 IP(src=self.pg0.remote_ip4,
254 dst=self.pg1._remote_hosts[2].ip4) /
255 UDP(sport=1234, dport=1234) /
258 self.pg0.add_stream(static_p)
259 self.pg_enable_capture(self.pg_interfaces)
262 rx = self.pg1.get_capture(1)
264 self.verify_ip(rx[0],
266 self.pg1.remote_hosts[2].mac,
268 self.pg1._remote_hosts[2].ip4)
271 # remove all the listeners
273 self.vapi.want_ip_neighbor_events(enable=0,
275 self.vapi.want_ip_neighbor_events(enable=0,
277 sw_if_index=self.pg1.sw_if_index)
278 self.vapi.want_ip_neighbor_events(enable=0,
280 sw_if_index=self.pg1.sw_if_index,
281 ip=self.pg1.remote_hosts[1].ip4)
284 # flap the link. dynamic ARPs get flush, statics don't
286 self.pg1.admin_down()
289 self.pg0.add_stream(static_p)
290 self.pg_enable_capture(self.pg_interfaces)
292 rx = self.pg1.get_capture(1)
294 self.verify_ip(rx[0],
296 self.pg1.remote_hosts[2].mac,
298 self.pg1._remote_hosts[2].ip4)
300 self.pg0.add_stream(dyn_p)
301 self.pg_enable_capture(self.pg_interfaces)
304 rx = self.pg1.get_capture(1)
305 self.verify_arp_req(rx[0],
308 self.pg1._remote_hosts[1].ip4)
310 self.assertFalse(dyn_arp.query_vpp_config())
311 self.assertTrue(static_arp.query_vpp_config())
313 # Send an ARP request from one of the so-far unlearned remote hosts
315 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
316 src=self.pg1._remote_hosts[3].mac) /
318 hwsrc=self.pg1._remote_hosts[3].mac,
319 pdst=self.pg1.local_ip4,
320 psrc=self.pg1._remote_hosts[3].ip4))
322 self.pg1.add_stream(p)
323 self.pg_enable_capture(self.pg_interfaces)
326 rx = self.pg1.get_capture(1)
327 self.verify_arp_resp(rx[0],
329 self.pg1._remote_hosts[3].mac,
331 self.pg1._remote_hosts[3].ip4)
334 # VPP should have learned the mapping for the remote host
336 self.assertTrue(find_nbr(self,
337 self.pg1.sw_if_index,
338 self.pg1._remote_hosts[3].ip4))
340 # Fire in an ARP request before the interface becomes IP enabled
342 self.pg2.generate_remote_hosts(4)
344 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
346 hwsrc=self.pg2.remote_mac,
347 pdst=self.pg1.local_ip4,
348 psrc=self.pg2.remote_hosts[3].ip4))
349 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
352 hwsrc=self.pg2.remote_mac,
353 pdst=self.pg1.local_ip4,
354 psrc=self.pg2.remote_hosts[3].ip4))
355 self.send_and_assert_no_replies(self.pg2, p,
356 "interface not IP enabled")
359 # Make pg2 un-numbered to pg1
361 self.pg2.set_unnumbered(self.pg1.sw_if_index)
364 # test the unnumbered dump both by all interfaces and just the enabled
367 unnum = self.vapi.ip_unnumbered_dump()
368 self.assertTrue(len(unnum))
369 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
370 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
371 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
372 self.assertTrue(len(unnum))
373 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
374 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
377 # We should respond to ARP requests for the unnumbered to address
378 # once an attached route to the source is known
380 self.send_and_assert_no_replies(
382 "ARP req for unnumbered address - no source")
384 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
385 [VppRoutePath("0.0.0.0",
386 self.pg2.sw_if_index)])
387 attached_host.add_vpp_config()
389 self.pg2.add_stream(p)
390 self.pg_enable_capture(self.pg_interfaces)
393 rx = self.pg2.get_capture(1)
394 self.verify_arp_resp(rx[0],
398 self.pg2.remote_hosts[3].ip4)
400 self.pg2.add_stream(pt)
401 self.pg_enable_capture(self.pg_interfaces)
404 rx = self.pg2.get_capture(1)
405 self.verify_arp_resp(rx[0],
409 self.pg2.remote_hosts[3].ip4)
412 # A neighbor entry that has no associated FIB-entry
414 arp_no_fib = VppNeighbor(self,
415 self.pg1.sw_if_index,
416 self.pg1.remote_hosts[4].mac,
417 self.pg1.remote_hosts[4].ip4,
419 arp_no_fib.add_vpp_config()
422 # check we have the neighbor, but no route
424 self.assertTrue(find_nbr(self,
425 self.pg1.sw_if_index,
426 self.pg1._remote_hosts[4].ip4))
427 self.assertFalse(find_route(self,
428 self.pg1._remote_hosts[4].ip4,
431 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
432 # from within pg1's subnet
434 arp_unnum = VppNeighbor(self,
435 self.pg2.sw_if_index,
436 self.pg1.remote_hosts[5].mac,
437 self.pg1.remote_hosts[5].ip4)
438 arp_unnum.add_vpp_config()
440 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
441 IP(src=self.pg0.remote_ip4,
442 dst=self.pg1._remote_hosts[5].ip4) /
443 UDP(sport=1234, dport=1234) /
446 self.pg0.add_stream(p)
447 self.pg_enable_capture(self.pg_interfaces)
450 rx = self.pg2.get_capture(1)
452 self.verify_ip(rx[0],
454 self.pg1.remote_hosts[5].mac,
456 self.pg1._remote_hosts[5].ip4)
459 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
460 # with the unnumbered interface's address as the source
462 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
464 hwsrc=self.pg2.remote_mac,
465 pdst=self.pg1.local_ip4,
466 psrc=self.pg1.remote_hosts[6].ip4))
468 self.pg2.add_stream(p)
469 self.pg_enable_capture(self.pg_interfaces)
472 rx = self.pg2.get_capture(1)
473 self.verify_arp_resp(rx[0],
477 self.pg1.remote_hosts[6].ip4)
480 # An attached host route out of pg2 for an undiscovered hosts generates
481 # an ARP request with the unnumbered address as the source
483 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
484 [VppRoutePath("0.0.0.0",
485 self.pg2.sw_if_index)])
486 att_unnum.add_vpp_config()
488 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
489 IP(src=self.pg0.remote_ip4,
490 dst=self.pg1._remote_hosts[7].ip4) /
491 UDP(sport=1234, dport=1234) /
494 self.pg0.add_stream(p)
495 self.pg_enable_capture(self.pg_interfaces)
498 rx = self.pg2.get_capture(1)
500 self.verify_arp_req(rx[0],
503 self.pg1._remote_hosts[7].ip4)
505 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
507 hwsrc=self.pg2.remote_mac,
508 pdst=self.pg1.local_ip4,
509 psrc=self.pg1.remote_hosts[7].ip4))
511 self.pg2.add_stream(p)
512 self.pg_enable_capture(self.pg_interfaces)
515 rx = self.pg2.get_capture(1)
516 self.verify_arp_resp(rx[0],
520 self.pg1.remote_hosts[7].ip4)
523 # An attached host route as yet unresolved out of pg2 for an
524 # undiscovered host, an ARP requests begets a response.
526 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
527 [VppRoutePath("0.0.0.0",
528 self.pg2.sw_if_index)])
529 att_unnum1.add_vpp_config()
531 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
533 hwsrc=self.pg2.remote_mac,
534 pdst=self.pg1.local_ip4,
535 psrc=self.pg1.remote_hosts[8].ip4))
537 self.pg2.add_stream(p)
538 self.pg_enable_capture(self.pg_interfaces)
541 rx = self.pg2.get_capture(1)
542 self.verify_arp_resp(rx[0],
546 self.pg1.remote_hosts[8].ip4)
549 # Send an ARP request from one of the so-far unlearned remote hosts
552 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
553 src=self.pg1._remote_hosts[9].mac) /
556 hwsrc=self.pg1._remote_hosts[9].mac,
557 pdst=self.pg1.local_ip4,
558 psrc=self.pg1._remote_hosts[9].ip4))
560 self.pg1.add_stream(p)
561 self.pg_enable_capture(self.pg_interfaces)
564 rx = self.pg1.get_capture(1)
565 self.verify_arp_resp(rx[0],
567 self.pg1._remote_hosts[9].mac,
569 self.pg1._remote_hosts[9].ip4)
572 # Add a hierarchy of routes for a host in the sub-net.
573 # Should still get an ARP resp since the cover is attached
575 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
577 hwsrc=self.pg1.remote_mac,
578 pdst=self.pg1.local_ip4,
579 psrc=self.pg1.remote_hosts[10].ip4))
581 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
582 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
583 self.pg1.sw_if_index)])
586 self.pg1.add_stream(p)
587 self.pg_enable_capture(self.pg_interfaces)
589 rx = self.pg1.get_capture(1)
590 self.verify_arp_resp(rx[0],
594 self.pg1.remote_hosts[10].ip4)
596 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
597 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
598 self.pg1.sw_if_index)])
601 self.pg1.add_stream(p)
602 self.pg_enable_capture(self.pg_interfaces)
604 rx = self.pg1.get_capture(1)
605 self.verify_arp_resp(rx[0],
609 self.pg1.remote_hosts[10].ip4)
612 # add an ARP entry that's not on the sub-net and so whose
613 # adj-fib fails the refinement check. then send an ARP request
616 a1 = VppNeighbor(self,
617 self.pg0.sw_if_index,
622 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
624 hwsrc=self.pg0.remote_mac,
625 psrc="100.100.100.50",
626 pdst=self.pg0.remote_ip4))
627 self.send_and_assert_no_replies(self.pg0, p,
628 "ARP req for from failed adj-fib")
632 # 1 - don't respond to ARP request for address not within the
633 # interface's sub-net
634 # 1b - nor within the unnumbered subnet
635 # 1c - nor within the subnet of a different interface
637 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
639 hwsrc=self.pg0.remote_mac,
641 psrc=self.pg0.remote_ip4))
642 self.send_and_assert_no_replies(self.pg0, p,
643 "ARP req for non-local destination")
644 self.assertFalse(find_nbr(self,
645 self.pg0.sw_if_index,
648 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
650 hwsrc=self.pg2.remote_mac,
652 psrc=self.pg1.remote_hosts[7].ip4))
653 self.send_and_assert_no_replies(
655 "ARP req for non-local destination - unnum")
657 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
659 hwsrc=self.pg0.remote_mac,
660 pdst=self.pg1.local_ip4,
661 psrc=self.pg1.remote_ip4))
662 self.send_and_assert_no_replies(self.pg0, p,
663 "ARP req diff sub-net")
664 self.assertFalse(find_nbr(self,
665 self.pg0.sw_if_index,
666 self.pg1.remote_ip4))
669 # 2 - don't respond to ARP request from an address not within the
670 # interface's sub-net
671 # 2b - to a proxied address
672 # 2c - not within a different interface's sub-net
673 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
675 hwsrc=self.pg0.remote_mac,
677 pdst=self.pg0.local_ip4))
678 self.send_and_assert_no_replies(self.pg0, p,
679 "ARP req for non-local source")
680 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
682 hwsrc=self.pg2.remote_mac,
684 pdst=self.pg0.local_ip4))
685 self.send_and_assert_no_replies(
687 "ARP req for non-local source - unnum")
688 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
690 hwsrc=self.pg0.remote_mac,
691 psrc=self.pg1.remote_ip4,
692 pdst=self.pg0.local_ip4))
693 self.send_and_assert_no_replies(self.pg0, p,
694 "ARP req for non-local source 2c")
697 # 3 - don't respond to ARP request from an address that belongs to
700 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
702 hwsrc=self.pg0.remote_mac,
703 psrc=self.pg0.local_ip4,
704 pdst=self.pg0.local_ip4))
705 self.send_and_assert_no_replies(self.pg0, p,
706 "ARP req for non-local source")
709 # 4 - don't respond to ARP requests that has mac source different
710 # from ARP request HW source
712 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
714 hwsrc="00:00:00:DE:AD:BE",
715 psrc=self.pg0.remote_ip4,
716 pdst=self.pg0.local_ip4))
717 self.send_and_assert_no_replies(self.pg0, p,
718 "ARP req for non-local source")
721 # 5 - don't respond to ARP requests for address within the
722 # interface's sub-net but not the interface's address
724 self.pg0.generate_remote_hosts(2)
725 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
727 hwsrc=self.pg0.remote_mac,
728 psrc=self.pg0.remote_hosts[0].ip4,
729 pdst=self.pg0.remote_hosts[1].ip4))
730 self.send_and_assert_no_replies(self.pg0, p,
731 "ARP req for non-local destination")
736 static_arp.remove_vpp_config()
737 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
739 # need this to flush the adj-fibs
740 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
741 self.pg2.admin_down()
742 self.pg1.admin_down()
744 def test_proxy_mirror_arp(self):
745 """ Interface Mirror Proxy ARP """
748 # When VPP has an interface whose address is also applied to a TAP
749 # interface on the host, then VPP's TAP interface will be unnumbered
750 # to the 'real' interface and do proxy ARP from the host.
751 # the curious aspect of this setup is that ARP requests from the host
752 # will come from the VPP's own address.
754 self.pg0.generate_remote_hosts(2)
756 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
757 dst="ff:ff:ff:ff:ff:ff") /
759 hwsrc=self.pg2.remote_mac,
760 pdst=self.pg0.remote_hosts[1].ip4,
761 psrc=self.pg0.local_ip4))
764 # Configure Proxy ARP for the subnet on PG0addresses on pg0
766 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
767 self.pg0._local_ip4_bcast)
769 # Make pg2 un-numbered to pg0
771 self.pg2.set_unnumbered(self.pg0.sw_if_index)
774 # Enable pg2 for proxy ARP
776 self.pg2.set_proxy_arp()
779 # Send the ARP request with an originating address that
780 # is VPP's own address
782 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
783 self.verify_arp_resp(rx[0],
786 self.pg0.remote_hosts[1].ip4,
790 # validate we have not learned an ARP entry as a result of this
792 self.assertFalse(find_nbr(self,
793 self.pg2.sw_if_index,
797 # setup a punt redirect so packets from the uplink go to the tap
799 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
800 self.pg2.sw_if_index,
803 p_tcp = (Ether(src=self.pg0.remote_mac,
804 dst=self.pg0.local_mac,) /
805 IP(src=self.pg0.remote_ip4,
806 dst=self.pg0.local_ip4) /
807 TCP(sport=80, dport=80) /
809 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
811 # there's no ARP entry so this is an ARP req
812 self.assertTrue(rx[0].haslayer(ARP))
814 # and ARP entry for VPP's pg0 address on the host interface
815 n1 = VppNeighbor(self,
816 self.pg2.sw_if_index,
819 is_no_fib_entry=True).add_vpp_config()
820 # now the packets shold forward
821 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
822 self.assertFalse(rx[0].haslayer(ARP))
823 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
826 # flush the neighbor cache on the uplink
828 af = VppEnum.vl_api_address_family_t
829 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
831 # ensure we can still resolve the ARPs on the uplink
832 self.pg0.resolve_arp()
834 self.assertTrue(find_nbr(self,
835 self.pg0.sw_if_index,
836 self.pg0.remote_ip4))
841 self.pg2.set_proxy_arp(0)
842 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
843 self.pg0._local_ip4_bcast,
846 def test_proxy_arp(self):
849 self.pg1.generate_remote_hosts(2)
852 # Proxy ARP request packets for each interface
854 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
855 dst="ff:ff:ff:ff:ff:ff") /
857 hwsrc=self.pg0.remote_mac,
859 psrc=self.pg0.remote_ip4))
860 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
861 dst="ff:ff:ff:ff:ff:ff") /
864 hwsrc=self.pg0.remote_mac,
866 psrc=self.pg0.remote_ip4))
867 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
868 dst="ff:ff:ff:ff:ff:ff") /
870 hwsrc=self.pg1.remote_mac,
872 psrc=self.pg1.remote_ip4))
873 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
874 dst="ff:ff:ff:ff:ff:ff") /
876 hwsrc=self.pg2.remote_mac,
878 psrc=self.pg1.remote_hosts[1].ip4))
879 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
880 dst="ff:ff:ff:ff:ff:ff") /
882 hwsrc=self.pg3.remote_mac,
884 psrc=self.pg3.remote_ip4))
887 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
889 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
890 inet_pton(AF_INET, "10.10.10.124"))
893 # No responses are sent when the interfaces are not enabled for proxy
896 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
897 "ARP req from unconfigured interface")
898 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
899 "ARP req from unconfigured interface")
902 # Make pg2 un-numbered to pg1
905 self.pg2.set_unnumbered(self.pg1.sw_if_index)
907 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
908 "ARP req from unnumbered interface")
911 # Enable each interface to reply to proxy ARPs
913 for i in self.pg_interfaces:
917 # Now each of the interfaces should reply to a request to a proxied
920 self.pg0.add_stream(arp_req_pg0)
921 self.pg_enable_capture(self.pg_interfaces)
924 rx = self.pg0.get_capture(1)
925 self.verify_arp_resp(rx[0],
931 self.pg0.add_stream(arp_req_pg0_tagged)
932 self.pg_enable_capture(self.pg_interfaces)
935 rx = self.pg0.get_capture(1)
936 self.verify_arp_resp(rx[0],
942 self.pg1.add_stream(arp_req_pg1)
943 self.pg_enable_capture(self.pg_interfaces)
946 rx = self.pg1.get_capture(1)
947 self.verify_arp_resp(rx[0],
953 self.pg2.add_stream(arp_req_pg2)
954 self.pg_enable_capture(self.pg_interfaces)
957 rx = self.pg2.get_capture(1)
958 self.verify_arp_resp(rx[0],
962 self.pg1.remote_hosts[1].ip4)
965 # A request for an address out of the configured range
967 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
968 dst="ff:ff:ff:ff:ff:ff") /
970 hwsrc=self.pg1.remote_mac,
972 psrc=self.pg1.remote_ip4))
973 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
974 "ARP req out of range HI")
975 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
976 dst="ff:ff:ff:ff:ff:ff") /
978 hwsrc=self.pg1.remote_mac,
980 psrc=self.pg1.remote_ip4))
981 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
982 "ARP req out of range Low")
985 # Request for an address in the proxy range but from an interface
988 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
989 "ARP req from different VRF")
992 # Disable Each interface for proxy ARP
993 # - expect none to respond
995 for i in self.pg_interfaces:
998 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
999 "ARP req from disable")
1000 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1001 "ARP req from disable")
1002 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1003 "ARP req from disable")
1006 # clean up on interface 2
1008 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1010 def test_mpls(self):
1014 # Interface 2 does not yet have ip4 config
1016 self.pg2.config_ip4()
1017 self.pg2.generate_remote_hosts(2)
1020 # Add a route with out going label via an ARP unresolved next-hop
1022 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1023 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1024 self.pg2.sw_if_index,
1026 ip_10_0_0_1.add_vpp_config()
1029 # packets should generate an ARP request
1031 p = (Ether(src=self.pg0.remote_mac,
1032 dst=self.pg0.local_mac) /
1033 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1034 UDP(sport=1234, dport=1234) /
1037 self.pg0.add_stream(p)
1038 self.pg_enable_capture(self.pg_interfaces)
1041 rx = self.pg2.get_capture(1)
1042 self.verify_arp_req(rx[0],
1045 self.pg2._remote_hosts[1].ip4)
1048 # now resolve the neighbours
1050 self.pg2.configure_ipv4_neighbors()
1053 # Now packet should be properly MPLS encapped.
1054 # This verifies that MPLS link-type adjacencies are completed
1055 # when the ARP entry resolves
1057 self.pg0.add_stream(p)
1058 self.pg_enable_capture(self.pg_interfaces)
1061 rx = self.pg2.get_capture(1)
1062 self.verify_ip_o_mpls(rx[0],
1064 self.pg2.remote_hosts[1].mac,
1066 self.pg0.remote_ip4,
1068 self.pg2.unconfig_ip4()
1070 def test_arp_vrrp(self):
1071 """ ARP reply with VRRP virtual src hw addr """
1074 # IP packet destined for pg1 remote host arrives on pg0 resulting
1075 # in an ARP request for the address of the remote host on pg1
1077 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1078 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1079 UDP(sport=1234, dport=1234) /
1082 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1084 self.verify_arp_req(rx1[0],
1087 self.pg1.remote_ip4)
1090 # ARP reply for address of pg1 remote host arrives on pg1 with
1091 # the hw src addr set to a value in the VRRP IPv4 range of
1094 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1095 ARP(op="is-at", hwdst=self.pg1.local_mac,
1096 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1097 psrc=self.pg1.remote_ip4))
1099 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1102 # IP packet destined for pg1 remote host arrives on pg0 again.
1103 # VPP should have an ARP entry for that address now and the packet
1104 # should be sent out pg1.
1106 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1108 self.verify_ip(rx1[0],
1110 "00:00:5e:00:01:09",
1111 self.pg0.remote_ip4,
1112 self.pg1.remote_ip4)
1114 self.pg1.admin_down()
1117 def test_arp_duplicates(self):
1118 """ ARP Duplicates"""
1121 # Generate some hosts on the LAN
1123 self.pg1.generate_remote_hosts(3)
1126 # Add host 1 on pg1 and pg2
1128 arp_pg1 = VppNeighbor(self,
1129 self.pg1.sw_if_index,
1130 self.pg1.remote_hosts[1].mac,
1131 self.pg1.remote_hosts[1].ip4)
1132 arp_pg1.add_vpp_config()
1133 arp_pg2 = VppNeighbor(self,
1134 self.pg2.sw_if_index,
1135 self.pg2.remote_mac,
1136 self.pg1.remote_hosts[1].ip4)
1137 arp_pg2.add_vpp_config()
1140 # IP packet destined for pg1 remote host arrives on pg1 again.
1142 p = (Ether(dst=self.pg0.local_mac,
1143 src=self.pg0.remote_mac) /
1144 IP(src=self.pg0.remote_ip4,
1145 dst=self.pg1.remote_hosts[1].ip4) /
1146 UDP(sport=1234, dport=1234) /
1149 self.pg0.add_stream(p)
1150 self.pg_enable_capture(self.pg_interfaces)
1153 rx1 = self.pg1.get_capture(1)
1155 self.verify_ip(rx1[0],
1157 self.pg1.remote_hosts[1].mac,
1158 self.pg0.remote_ip4,
1159 self.pg1.remote_hosts[1].ip4)
1162 # remove the duplicate on pg1
1163 # packet stream should generate ARPs out of pg1
1165 arp_pg1.remove_vpp_config()
1167 self.pg0.add_stream(p)
1168 self.pg_enable_capture(self.pg_interfaces)
1171 rx1 = self.pg1.get_capture(1)
1173 self.verify_arp_req(rx1[0],
1176 self.pg1.remote_hosts[1].ip4)
1181 arp_pg1.add_vpp_config()
1183 self.pg0.add_stream(p)
1184 self.pg_enable_capture(self.pg_interfaces)
1187 rx1 = self.pg1.get_capture(1)
1189 self.verify_ip(rx1[0],
1191 self.pg1.remote_hosts[1].mac,
1192 self.pg0.remote_ip4,
1193 self.pg1.remote_hosts[1].ip4)
1195 def test_arp_static(self):
1197 self.pg2.generate_remote_hosts(3)
1200 # Add a static ARP entry
1202 static_arp = VppNeighbor(self,
1203 self.pg2.sw_if_index,
1204 self.pg2.remote_hosts[1].mac,
1205 self.pg2.remote_hosts[1].ip4,
1207 static_arp.add_vpp_config()
1210 # Add the connected prefix to the interface
1212 self.pg2.config_ip4()
1215 # We should now find the adj-fib
1217 self.assertTrue(find_nbr(self,
1218 self.pg2.sw_if_index,
1219 self.pg2.remote_hosts[1].ip4,
1221 self.assertTrue(find_route(self,
1222 self.pg2.remote_hosts[1].ip4,
1226 # remove the connected
1228 self.pg2.unconfig_ip4()
1231 # put the interface into table 1
1233 self.pg2.set_table_ip4(1)
1236 # configure the same connected and expect to find the
1237 # adj fib in the new table
1239 self.pg2.config_ip4()
1240 self.assertTrue(find_route(self,
1241 self.pg2.remote_hosts[1].ip4,
1248 self.pg2.unconfig_ip4()
1249 static_arp.remove_vpp_config()
1250 self.pg2.set_table_ip4(0)
1252 def test_arp_static_replace_dynamic_same_mac(self):
1253 """ ARP Static can replace Dynamic (same mac) """
1254 self.pg2.generate_remote_hosts(1)
1256 dyn_arp = VppNeighbor(self,
1257 self.pg2.sw_if_index,
1258 self.pg2.remote_hosts[0].mac,
1259 self.pg2.remote_hosts[0].ip4)
1260 static_arp = VppNeighbor(self,
1261 self.pg2.sw_if_index,
1262 self.pg2.remote_hosts[0].mac,
1263 self.pg2.remote_hosts[0].ip4,
1267 # Add a dynamic ARP entry
1269 dyn_arp.add_vpp_config()
1272 # We should find the dynamic nbr
1274 self.assertFalse(find_nbr(self,
1275 self.pg2.sw_if_index,
1276 self.pg2.remote_hosts[0].ip4,
1278 self.assertTrue(find_nbr(self,
1279 self.pg2.sw_if_index,
1280 self.pg2.remote_hosts[0].ip4,
1282 mac=self.pg2.remote_hosts[0].mac))
1285 # Add a static ARP entry with the same mac
1287 static_arp.add_vpp_config()
1290 # We should now find the static nbr with the same mac
1292 self.assertFalse(find_nbr(self,
1293 self.pg2.sw_if_index,
1294 self.pg2.remote_hosts[0].ip4,
1296 self.assertTrue(find_nbr(self,
1297 self.pg2.sw_if_index,
1298 self.pg2.remote_hosts[0].ip4,
1300 mac=self.pg2.remote_hosts[0].mac))
1305 static_arp.remove_vpp_config()
1307 def test_arp_static_replace_dynamic_diff_mac(self):
1308 """ ARP Static can replace Dynamic (diff mac) """
1309 self.pg2.generate_remote_hosts(2)
1311 dyn_arp = VppNeighbor(self,
1312 self.pg2.sw_if_index,
1313 self.pg2.remote_hosts[0].mac,
1314 self.pg2.remote_hosts[0].ip4)
1315 static_arp = VppNeighbor(self,
1316 self.pg2.sw_if_index,
1317 self.pg2.remote_hosts[1].mac,
1318 self.pg2.remote_hosts[0].ip4,
1322 # Add a dynamic ARP entry
1324 dyn_arp.add_vpp_config()
1327 # We should find the dynamic nbr
1329 self.assertFalse(find_nbr(self,
1330 self.pg2.sw_if_index,
1331 self.pg2.remote_hosts[0].ip4,
1333 self.assertTrue(find_nbr(self,
1334 self.pg2.sw_if_index,
1335 self.pg2.remote_hosts[0].ip4,
1337 mac=self.pg2.remote_hosts[0].mac))
1340 # Add a static ARP entry with a changed mac
1342 static_arp.add_vpp_config()
1345 # We should now find the static nbr with a changed mac
1347 self.assertFalse(find_nbr(self,
1348 self.pg2.sw_if_index,
1349 self.pg2.remote_hosts[0].ip4,
1351 self.assertTrue(find_nbr(self,
1352 self.pg2.sw_if_index,
1353 self.pg2.remote_hosts[0].ip4,
1355 mac=self.pg2.remote_hosts[1].mac))
1360 static_arp.remove_vpp_config()
1362 def test_arp_incomplete(self):
1363 """ ARP Incomplete"""
1364 self.pg1.generate_remote_hosts(3)
1366 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1367 IP(src=self.pg0.remote_ip4,
1368 dst=self.pg1.remote_hosts[1].ip4) /
1369 UDP(sport=1234, dport=1234) /
1371 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1372 IP(src=self.pg0.remote_ip4,
1373 dst=self.pg1.remote_hosts[2].ip4) /
1374 UDP(sport=1234, dport=1234) /
1378 # a packet to an unresolved destination generates an ARP request
1380 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1381 self.verify_arp_req(rx[0],
1384 self.pg1._remote_hosts[1].ip4)
1387 # add a neighbour for remote host 1
1389 static_arp = VppNeighbor(self,
1390 self.pg1.sw_if_index,
1391 self.pg1.remote_hosts[1].mac,
1392 self.pg1.remote_hosts[1].ip4,
1394 static_arp.add_vpp_config()
1397 # change the interface's MAC
1399 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1400 "00:00:00:33:33:33")
1403 # now ARP requests come from the new source mac
1405 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1406 self.verify_arp_req(rx[0],
1407 "00:00:00:33:33:33",
1409 self.pg1._remote_hosts[2].ip4)
1412 # packets to the resolved host also have the new source mac
1414 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1415 self.verify_ip(rx[0],
1416 "00:00:00:33:33:33",
1417 self.pg1.remote_hosts[1].mac,
1418 self.pg0.remote_ip4,
1419 self.pg1.remote_hosts[1].ip4)
1422 # set the mac address on the interface that does not have a
1423 # configured subnet and thus no glean
1425 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1426 "00:00:00:33:33:33")
1428 def test_garp(self):
1432 # Generate some hosts on the LAN
1434 self.pg1.generate_remote_hosts(4)
1435 self.pg2.generate_remote_hosts(4)
1440 arp = VppNeighbor(self,
1441 self.pg1.sw_if_index,
1442 self.pg1.remote_hosts[1].mac,
1443 self.pg1.remote_hosts[1].ip4)
1444 arp.add_vpp_config()
1446 self.assertTrue(find_nbr(self,
1447 self.pg1.sw_if_index,
1448 self.pg1.remote_hosts[1].ip4,
1449 mac=self.pg1.remote_hosts[1].mac))
1452 # Send a GARP (request) to swap the host 1's address to that of host 2
1454 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1455 src=self.pg1.remote_hosts[2].mac) /
1457 hwdst=self.pg1.local_mac,
1458 hwsrc=self.pg1.remote_hosts[2].mac,
1459 pdst=self.pg1.remote_hosts[1].ip4,
1460 psrc=self.pg1.remote_hosts[1].ip4))
1462 self.pg1.add_stream(p1)
1463 self.pg_enable_capture(self.pg_interfaces)
1466 self.assertTrue(find_nbr(self,
1467 self.pg1.sw_if_index,
1468 self.pg1.remote_hosts[1].ip4,
1469 mac=self.pg1.remote_hosts[2].mac))
1472 # Send a GARP (reply) to swap the host 1's address to that of host 3
1474 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1475 src=self.pg1.remote_hosts[3].mac) /
1477 hwdst=self.pg1.local_mac,
1478 hwsrc=self.pg1.remote_hosts[3].mac,
1479 pdst=self.pg1.remote_hosts[1].ip4,
1480 psrc=self.pg1.remote_hosts[1].ip4))
1482 self.pg1.add_stream(p1)
1483 self.pg_enable_capture(self.pg_interfaces)
1486 self.assertTrue(find_nbr(self,
1487 self.pg1.sw_if_index,
1488 self.pg1.remote_hosts[1].ip4,
1489 mac=self.pg1.remote_hosts[3].mac))
1492 # GARPs (request nor replies) for host we don't know yet
1493 # don't result in new neighbour entries
1495 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1496 src=self.pg1.remote_hosts[3].mac) /
1498 hwdst=self.pg1.local_mac,
1499 hwsrc=self.pg1.remote_hosts[3].mac,
1500 pdst=self.pg1.remote_hosts[2].ip4,
1501 psrc=self.pg1.remote_hosts[2].ip4))
1503 self.pg1.add_stream(p1)
1504 self.pg_enable_capture(self.pg_interfaces)
1507 self.assertFalse(find_nbr(self,
1508 self.pg1.sw_if_index,
1509 self.pg1.remote_hosts[2].ip4))
1511 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1512 src=self.pg1.remote_hosts[3].mac) /
1514 hwdst=self.pg1.local_mac,
1515 hwsrc=self.pg1.remote_hosts[3].mac,
1516 pdst=self.pg1.remote_hosts[2].ip4,
1517 psrc=self.pg1.remote_hosts[2].ip4))
1519 self.pg1.add_stream(p1)
1520 self.pg_enable_capture(self.pg_interfaces)
1523 self.assertFalse(find_nbr(self,
1524 self.pg1.sw_if_index,
1525 self.pg1.remote_hosts[2].ip4))
1528 # IP address in different subnets are not learnt
1530 self.pg2.configure_ipv4_neighbors()
1532 for op in ["is-at", "who-has"]:
1533 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1534 src=self.pg2.remote_hosts[1].mac) /
1536 hwdst=self.pg2.local_mac,
1537 hwsrc=self.pg2.remote_hosts[1].mac,
1538 pdst=self.pg2.remote_hosts[1].ip4,
1539 psrc=self.pg2.remote_hosts[1].ip4)),
1540 (Ether(dst="ff:ff:ff:ff:ff:ff",
1541 src=self.pg2.remote_hosts[1].mac) /
1543 hwdst="ff:ff:ff:ff:ff:ff",
1544 hwsrc=self.pg2.remote_hosts[1].mac,
1545 pdst=self.pg2.remote_hosts[1].ip4,
1546 psrc=self.pg2.remote_hosts[1].ip4))]
1548 self.send_and_assert_no_replies(self.pg1, p1)
1549 self.assertFalse(find_nbr(self,
1550 self.pg1.sw_if_index,
1551 self.pg2.remote_hosts[1].ip4))
1553 # they are all dropped because the subnet's don't match
1554 self.assertEqual(4, self.statistics.get_err_counter(
1555 "/err/arp-reply/IP4 destination address not local to subnet"))
1557 def test_arp_incomplete2(self):
1558 """ Incomplete Entries """
1561 # ensure that we throttle the ARP and ND requests
1563 self.pg0.generate_remote_hosts(2)
1568 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1569 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1570 self.pg0.sw_if_index)])
1571 ip_10_0_0_1.add_vpp_config()
1573 p1 = (Ether(dst=self.pg1.local_mac,
1574 src=self.pg1.remote_mac) /
1575 IP(src=self.pg1.remote_ip4,
1577 UDP(sport=1234, dport=1234) /
1580 self.pg1.add_stream(p1 * 257)
1581 self.pg_enable_capture(self.pg_interfaces)
1583 rx = self.pg0._get_capture(1)
1586 # how many we get is going to be dependent on the time for packet
1587 # processing but it should be small
1589 self.assertLess(len(rx), 64)
1594 ip_10_1 = VppIpRoute(self, "10::1", 128,
1595 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1596 self.pg0.sw_if_index,
1597 proto=DpoProto.DPO_PROTO_IP6)])
1598 ip_10_1.add_vpp_config()
1600 p1 = (Ether(dst=self.pg1.local_mac,
1601 src=self.pg1.remote_mac) /
1602 IPv6(src=self.pg1.remote_ip6,
1604 UDP(sport=1234, dport=1234) /
1607 self.pg1.add_stream(p1 * 257)
1608 self.pg_enable_capture(self.pg_interfaces)
1610 rx = self.pg0._get_capture(1)
1613 # how many we get is going to be dependent on the time for packet
1614 # processing but it should be small
1616 self.assertLess(len(rx), 64)
1618 def test_arp_forus(self):
1619 """ ARP for for-us """
1622 # Test that VPP responds with ARP requests to addresses that
1623 # are connected and local routes.
1624 # Use one of the 'remote' addresses in the subnet as a local address
1625 # The intention of this route is that it then acts like a secondary
1626 # address added to an interface
1628 self.pg0.generate_remote_hosts(2)
1631 self, self.pg0.remote_hosts[1].ip4, 32,
1632 [VppRoutePath("0.0.0.0",
1633 self.pg0.sw_if_index,
1634 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1635 forus.add_vpp_config()
1637 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1638 src=self.pg0.remote_mac) /
1640 hwdst=self.pg0.local_mac,
1641 hwsrc=self.pg0.remote_mac,
1642 pdst=self.pg0.remote_hosts[1].ip4,
1643 psrc=self.pg0.remote_ip4))
1645 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1647 self.verify_arp_resp(rx[0],
1649 self.pg0.remote_mac,
1650 self.pg0.remote_hosts[1].ip4,
1651 self.pg0.remote_ip4)
1653 def test_arp_table_swap(self):
1655 # Generate some hosts on the LAN
1658 self.pg1.generate_remote_hosts(N_NBRS)
1660 for n in range(N_NBRS):
1661 # a route thru each neighbour
1662 VppIpRoute(self, "10.0.0.%d" % n, 32,
1663 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1664 self.pg1.sw_if_index)]).add_vpp_config()
1666 # resolve each neighbour
1667 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1668 ARP(op="is-at", hwdst=self.pg1.local_mac,
1669 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1670 psrc=self.pg1.remote_hosts[n].ip4))
1672 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1674 self.logger.info(self.vapi.cli("sh ip neighbors"))
1677 # swap the table pg1 is in
1679 table = VppIpTable(self, 100).add_vpp_config()
1681 self.pg1.unconfig_ip4()
1682 self.pg1.set_table_ip4(100)
1683 self.pg1.config_ip4()
1686 # all neighbours are cleared
1688 for n in range(N_NBRS):
1689 self.assertFalse(find_nbr(self,
1690 self.pg1.sw_if_index,
1691 self.pg1.remote_hosts[n].ip4))
1694 # packets to all neighbours generate ARP requests
1696 for n in range(N_NBRS):
1697 # a route thru each neighbour
1698 VppIpRoute(self, "10.0.0.%d" % n, 32,
1699 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1700 self.pg1.sw_if_index)],
1701 table_id=100).add_vpp_config()
1703 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1704 dst=self.pg1.local_mac) /
1705 IP(src=self.pg1.remote_hosts[n].ip4,
1706 dst="10.0.0.%d" % n) /
1708 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1710 self.verify_arp_req(rx,
1713 self.pg1.remote_hosts[n].ip4)
1715 self.pg1.unconfig_ip4()
1716 self.pg1.set_table_ip4(0)
1719 class NeighborStatsTestCase(VppTestCase):
1720 """ ARP/ND Counters """
1723 def setUpClass(cls):
1724 super(NeighborStatsTestCase, cls).setUpClass()
1727 def tearDownClass(cls):
1728 super(NeighborStatsTestCase, cls).tearDownClass()
1731 super(NeighborStatsTestCase, self).setUp()
1733 self.create_pg_interfaces(range(2))
1735 # pg0 configured with ip4 and 6 addresses used for input
1736 # pg1 configured with ip4 and 6 addresses used for output
1737 # pg2 is unnumbered to pg0
1738 for i in self.pg_interfaces:
1746 super(NeighborStatsTestCase, self).tearDown()
1748 for i in self.pg_interfaces:
1753 def test_arp_stats(self):
1754 """ ARP Counters """
1756 self.vapi.cli("adj counters enable")
1757 self.pg1.generate_remote_hosts(2)
1759 arp1 = VppNeighbor(self,
1760 self.pg1.sw_if_index,
1761 self.pg1.remote_hosts[0].mac,
1762 self.pg1.remote_hosts[0].ip4)
1763 arp1.add_vpp_config()
1764 arp2 = VppNeighbor(self,
1765 self.pg1.sw_if_index,
1766 self.pg1.remote_hosts[1].mac,
1767 self.pg1.remote_hosts[1].ip4)
1768 arp2.add_vpp_config()
1770 p1 = (Ether(dst=self.pg0.local_mac,
1771 src=self.pg0.remote_mac) /
1772 IP(src=self.pg0.remote_ip4,
1773 dst=self.pg1.remote_hosts[0].ip4) /
1774 UDP(sport=1234, dport=1234) /
1776 p2 = (Ether(dst=self.pg0.local_mac,
1777 src=self.pg0.remote_mac) /
1778 IP(src=self.pg0.remote_ip4,
1779 dst=self.pg1.remote_hosts[1].ip4) /
1780 UDP(sport=1234, dport=1234) /
1783 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1784 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1786 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1787 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1789 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1790 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1792 def test_nd_stats(self):
1795 self.vapi.cli("adj counters enable")
1796 self.pg0.generate_remote_hosts(3)
1798 nd1 = VppNeighbor(self,
1799 self.pg0.sw_if_index,
1800 self.pg0.remote_hosts[1].mac,
1801 self.pg0.remote_hosts[1].ip6)
1802 nd1.add_vpp_config()
1803 nd2 = VppNeighbor(self,
1804 self.pg0.sw_if_index,
1805 self.pg0.remote_hosts[2].mac,
1806 self.pg0.remote_hosts[2].ip6)
1807 nd2.add_vpp_config()
1809 p1 = (Ether(dst=self.pg1.local_mac,
1810 src=self.pg1.remote_mac) /
1811 IPv6(src=self.pg1.remote_ip6,
1812 dst=self.pg0.remote_hosts[1].ip6) /
1813 UDP(sport=1234, dport=1234) /
1815 p2 = (Ether(dst=self.pg1.local_mac,
1816 src=self.pg1.remote_mac) /
1817 IPv6(src=self.pg1.remote_ip6,
1818 dst=self.pg0.remote_hosts[2].ip6) /
1819 UDP(sport=1234, dport=1234) /
1822 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1823 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1825 self.assertEqual(16, nd1.get_stats()['packets'])
1826 self.assertEqual(16, nd2.get_stats()['packets'])
1828 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1829 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1832 class NeighborAgeTestCase(VppTestCase):
1833 """ ARP/ND Aging """
1836 def setUpClass(cls):
1837 super(NeighborAgeTestCase, cls).setUpClass()
1840 def tearDownClass(cls):
1841 super(NeighborAgeTestCase, cls).tearDownClass()
1844 super(NeighborAgeTestCase, self).setUp()
1846 self.create_pg_interfaces(range(1))
1848 # pg0 configured with ip4 and 6 addresses used for input
1849 # pg1 configured with ip4 and 6 addresses used for output
1850 # pg2 is unnumbered to pg0
1851 for i in self.pg_interfaces:
1859 super(NeighborAgeTestCase, self).tearDown()
1861 for i in self.pg_interfaces:
1866 def wait_for_no_nbr(self, intf, address,
1867 n_tries=50, s_time=1):
1869 if not find_nbr(self, intf, address):
1871 n_tries = n_tries - 1
1876 def verify_arp_req(self, rx, smac, sip, dip):
1878 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1879 self.assertEqual(ether.src, smac)
1882 self.assertEqual(arp.hwtype, 1)
1883 self.assertEqual(arp.ptype, 0x800)
1884 self.assertEqual(arp.hwlen, 6)
1885 self.assertEqual(arp.plen, 4)
1886 self.assertEqual(arp.op, arp_opts["who-has"])
1887 self.assertEqual(arp.hwsrc, smac)
1888 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1889 self.assertEqual(arp.psrc, sip)
1890 self.assertEqual(arp.pdst, dip)
1893 """ Aging/Recycle """
1895 self.vapi.cli("set logging unthrottle 0")
1896 self.vapi.cli("set logging size %d" % 0xffff)
1898 self.pg0.generate_remote_hosts(201)
1900 vaf = VppEnum.vl_api_address_family_t
1903 # start listening on all interfaces
1905 self.pg_enable_capture(self.pg_interfaces)
1908 # Set the neighbor configuration:
1913 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1918 self.vapi.cli("sh ip neighbor-config")
1920 # add the 198 neighbours that should pass (-1 for one created in setup)
1921 for ii in range(200):
1923 self.pg0.sw_if_index,
1924 self.pg0.remote_hosts[ii].mac,
1925 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1927 # one more neighbor over the limit should fail
1928 with self.vapi.assert_negative_api_retval():
1930 self.pg0.sw_if_index,
1931 self.pg0.remote_hosts[200].mac,
1932 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1935 # change the config to allow recycling the old neighbors
1937 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1942 # now new additions are allowed
1944 self.pg0.sw_if_index,
1945 self.pg0.remote_hosts[200].mac,
1946 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1948 # add the first neighbor we configured has been re-used
1949 self.assertFalse(find_nbr(self,
1950 self.pg0.sw_if_index,
1951 self.pg0.remote_hosts[0].ip4))
1952 self.assertTrue(find_nbr(self,
1953 self.pg0.sw_if_index,
1954 self.pg0.remote_hosts[200].ip4))
1957 # change the config to age old neighbors
1959 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1964 self.vapi.cli("sh ip4 neighbor-sorted")
1967 # expect probes from all these ARP entries as they age
1968 # 3 probes for each neighbor 3*200 = 600
1969 rxs = self.pg0.get_capture(600, timeout=8)
1972 for jj in range(200):
1973 rx = rxs[ii*200 + jj]
1977 # 3 probes sent then 1 more second to see if a reply comes, before
1980 for jj in range(1, 201):
1981 self.wait_for_no_nbr(self.pg0.sw_if_index,
1982 self.pg0.remote_hosts[jj].ip4)
1984 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1985 af=vaf.ADDRESS_IP4))
1988 # load up some neighbours again with 2s aging enabled
1989 # they should be removed after 10s (2s age + 4s for probes + gap)
1991 for ii in range(10):
1993 self.pg0.sw_if_index,
1994 self.pg0.remote_hosts[ii].mac,
1995 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1997 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1998 af=vaf.ADDRESS_IP4))
2001 # check if we can set age and recycle with empty neighbor list
2003 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2009 # load up some neighbours again, then disable the aging
2010 # they should still be there in 10 seconds time
2012 for ii in range(10):
2014 self.pg0.sw_if_index,
2015 self.pg0.remote_hosts[ii].mac,
2016 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2017 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2023 self.assertTrue(find_nbr(self,
2024 self.pg0.sw_if_index,
2025 self.pg0.remote_hosts[0].ip4))
2028 class NeighborReplaceTestCase(VppTestCase):
2029 """ ARP/ND Replacement """
2032 def setUpClass(cls):
2033 super(NeighborReplaceTestCase, cls).setUpClass()
2036 def tearDownClass(cls):
2037 super(NeighborReplaceTestCase, cls).tearDownClass()
2040 super(NeighborReplaceTestCase, self).setUp()
2042 self.create_pg_interfaces(range(4))
2044 # pg0 configured with ip4 and 6 addresses used for input
2045 # pg1 configured with ip4 and 6 addresses used for output
2046 # pg2 is unnumbered to pg0
2047 for i in self.pg_interfaces:
2055 super(NeighborReplaceTestCase, self).tearDown()
2057 for i in self.pg_interfaces:
2062 def test_replace(self):
2067 for i in self.pg_interfaces:
2068 i.generate_remote_hosts(N_HOSTS)
2069 i.configure_ipv4_neighbors()
2070 i.configure_ipv6_neighbors()
2073 self.vapi.ip_neighbor_replace_begin()
2074 self.vapi.ip_neighbor_replace_end()
2076 for i in self.pg_interfaces:
2077 for h in range(N_HOSTS):
2078 self.assertFalse(find_nbr(self,
2079 self.pg0.sw_if_index,
2080 self.pg0.remote_hosts[h].ip4))
2081 self.assertFalse(find_nbr(self,
2082 self.pg0.sw_if_index,
2083 self.pg0.remote_hosts[h].ip6))
2086 # and them all back via the API
2088 for i in self.pg_interfaces:
2089 for h in range(N_HOSTS):
2092 i.remote_hosts[h].mac,
2093 i.remote_hosts[h].ip4).add_vpp_config()
2096 i.remote_hosts[h].mac,
2097 i.remote_hosts[h].ip6).add_vpp_config()
2100 # begin the replacement again, this time touch some
2101 # the neighbours on pg1 so they are not deleted
2103 self.vapi.ip_neighbor_replace_begin()
2105 # update from the API all neighbours on pg1
2106 for h in range(N_HOSTS):
2108 self.pg1.sw_if_index,
2109 self.pg1.remote_hosts[h].mac,
2110 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2112 self.pg1.sw_if_index,
2113 self.pg1.remote_hosts[h].mac,
2114 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2116 # update from the data-plane all neighbours on pg3
2117 self.pg3.configure_ipv4_neighbors()
2118 self.pg3.configure_ipv6_neighbors()
2120 # complete the replacement
2121 self.logger.info(self.vapi.cli("sh ip neighbors"))
2122 self.vapi.ip_neighbor_replace_end()
2124 for i in self.pg_interfaces:
2125 if i == self.pg1 or i == self.pg3:
2126 # neighbours on pg1 and pg3 are still present
2127 for h in range(N_HOSTS):
2128 self.assertTrue(find_nbr(self,
2130 i.remote_hosts[h].ip4))
2131 self.assertTrue(find_nbr(self,
2133 i.remote_hosts[h].ip6))
2135 # all other neighbours are toast
2136 for h in range(N_HOSTS):
2137 self.assertFalse(find_nbr(self,
2139 i.remote_hosts[h].ip4))
2140 self.assertFalse(find_nbr(self,
2142 i.remote_hosts[h].ip6))
2145 class NeighborFlush(VppTestCase):
2146 """ Neighbor Flush """
2149 def setUpClass(cls):
2150 super(NeighborFlush, cls).setUpClass()
2153 def tearDownClass(cls):
2154 super(NeighborFlush, cls).tearDownClass()
2157 super(NeighborFlush, self).setUp()
2159 self.create_pg_interfaces(range(2))
2161 for i in self.pg_interfaces:
2169 super(NeighborFlush, self).tearDown()
2171 for i in self.pg_interfaces:
2176 def test_flush(self):
2177 """ Neighbour Flush """
2180 nf = e.vl_api_ip_neighbor_flags_t
2181 af = e.vl_api_address_family_t
2183 static = [False, True]
2184 self.pg0.generate_remote_hosts(N_HOSTS)
2185 self.pg1.generate_remote_hosts(N_HOSTS)
2188 # a few v4 and v6 dynamic neoghbors
2189 for n in range(N_HOSTS):
2191 self.pg0.sw_if_index,
2192 self.pg0.remote_hosts[n].mac,
2193 self.pg0.remote_hosts[n].ip4,
2194 is_static=s).add_vpp_config()
2196 self.pg1.sw_if_index,
2197 self.pg1.remote_hosts[n].mac,
2198 self.pg1.remote_hosts[n].ip6,
2199 is_static=s).add_vpp_config()
2201 # flush the interfaces individually
2202 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2204 # check we haven't flushed that which we shouldn't
2205 for n in range(N_HOSTS):
2206 self.assertTrue(find_nbr(self,
2207 self.pg1.sw_if_index,
2208 self.pg1.remote_hosts[n].ip6,
2211 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2213 for n in range(N_HOSTS):
2214 self.assertFalse(find_nbr(self,
2215 self.pg0.sw_if_index,
2216 self.pg0.remote_hosts[n].ip4))
2217 self.assertFalse(find_nbr(self,
2218 self.pg1.sw_if_index,
2219 self.pg1.remote_hosts[n].ip6))
2221 # add the nieghbours back
2222 for n in range(N_HOSTS):
2224 self.pg0.sw_if_index,
2225 self.pg0.remote_hosts[n].mac,
2226 self.pg0.remote_hosts[n].ip4,
2227 is_static=s).add_vpp_config()
2229 self.pg1.sw_if_index,
2230 self.pg1.remote_hosts[n].mac,
2231 self.pg1.remote_hosts[n].ip6,
2232 is_static=s).add_vpp_config()
2234 self.logger.info(self.vapi.cli("sh ip neighbor"))
2236 # flush both interfaces at the same time
2237 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2239 # check we haven't flushed that which we shouldn't
2240 for n in range(N_HOSTS):
2241 self.assertTrue(find_nbr(self,
2242 self.pg0.sw_if_index,
2243 self.pg0.remote_hosts[n].ip4,
2246 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2248 for n in range(N_HOSTS):
2249 self.assertFalse(find_nbr(self,
2250 self.pg0.sw_if_index,
2251 self.pg0.remote_hosts[n].ip4))
2252 self.assertFalse(find_nbr(self,
2253 self.pg1.sw_if_index,
2254 self.pg1.remote_hosts[n].ip6))
2257 if __name__ == '__main__':
2258 unittest.main(testRunner=VppTestRunner)