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 mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1400 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1401 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1402 mac_string = ''.join(mac)
1404 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1408 # now ARP requests come from the new source mac
1410 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1411 self.verify_arp_req(rx[0],
1412 "00:00:00:33:33:33",
1414 self.pg1._remote_hosts[2].ip4)
1417 # packets to the resolved host also have the new source mac
1419 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1420 self.verify_ip(rx[0],
1421 "00:00:00:33:33:33",
1422 self.pg1.remote_hosts[1].mac,
1423 self.pg0.remote_ip4,
1424 self.pg1.remote_hosts[1].ip4)
1427 # set the mac address on the interface that does not have a
1428 # configured subnet and thus no glean
1430 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1433 def test_garp(self):
1437 # Generate some hosts on the LAN
1439 self.pg1.generate_remote_hosts(4)
1440 self.pg2.generate_remote_hosts(4)
1445 arp = VppNeighbor(self,
1446 self.pg1.sw_if_index,
1447 self.pg1.remote_hosts[1].mac,
1448 self.pg1.remote_hosts[1].ip4)
1449 arp.add_vpp_config()
1451 self.assertTrue(find_nbr(self,
1452 self.pg1.sw_if_index,
1453 self.pg1.remote_hosts[1].ip4,
1454 mac=self.pg1.remote_hosts[1].mac))
1457 # Send a GARP (request) to swap the host 1's address to that of host 2
1459 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1460 src=self.pg1.remote_hosts[2].mac) /
1462 hwdst=self.pg1.local_mac,
1463 hwsrc=self.pg1.remote_hosts[2].mac,
1464 pdst=self.pg1.remote_hosts[1].ip4,
1465 psrc=self.pg1.remote_hosts[1].ip4))
1467 self.pg1.add_stream(p1)
1468 self.pg_enable_capture(self.pg_interfaces)
1471 self.assertTrue(find_nbr(self,
1472 self.pg1.sw_if_index,
1473 self.pg1.remote_hosts[1].ip4,
1474 mac=self.pg1.remote_hosts[2].mac))
1477 # Send a GARP (reply) to swap the host 1's address to that of host 3
1479 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1480 src=self.pg1.remote_hosts[3].mac) /
1482 hwdst=self.pg1.local_mac,
1483 hwsrc=self.pg1.remote_hosts[3].mac,
1484 pdst=self.pg1.remote_hosts[1].ip4,
1485 psrc=self.pg1.remote_hosts[1].ip4))
1487 self.pg1.add_stream(p1)
1488 self.pg_enable_capture(self.pg_interfaces)
1491 self.assertTrue(find_nbr(self,
1492 self.pg1.sw_if_index,
1493 self.pg1.remote_hosts[1].ip4,
1494 mac=self.pg1.remote_hosts[3].mac))
1497 # GARPs (request nor replies) for host we don't know yet
1498 # don't result in new neighbour entries
1500 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1501 src=self.pg1.remote_hosts[3].mac) /
1503 hwdst=self.pg1.local_mac,
1504 hwsrc=self.pg1.remote_hosts[3].mac,
1505 pdst=self.pg1.remote_hosts[2].ip4,
1506 psrc=self.pg1.remote_hosts[2].ip4))
1508 self.pg1.add_stream(p1)
1509 self.pg_enable_capture(self.pg_interfaces)
1512 self.assertFalse(find_nbr(self,
1513 self.pg1.sw_if_index,
1514 self.pg1.remote_hosts[2].ip4))
1516 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1517 src=self.pg1.remote_hosts[3].mac) /
1519 hwdst=self.pg1.local_mac,
1520 hwsrc=self.pg1.remote_hosts[3].mac,
1521 pdst=self.pg1.remote_hosts[2].ip4,
1522 psrc=self.pg1.remote_hosts[2].ip4))
1524 self.pg1.add_stream(p1)
1525 self.pg_enable_capture(self.pg_interfaces)
1528 self.assertFalse(find_nbr(self,
1529 self.pg1.sw_if_index,
1530 self.pg1.remote_hosts[2].ip4))
1533 # IP address in different subnets are not learnt
1535 self.pg2.configure_ipv4_neighbors()
1537 for op in ["is-at", "who-has"]:
1538 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1539 src=self.pg2.remote_hosts[1].mac) /
1541 hwdst=self.pg2.local_mac,
1542 hwsrc=self.pg2.remote_hosts[1].mac,
1543 pdst=self.pg2.remote_hosts[1].ip4,
1544 psrc=self.pg2.remote_hosts[1].ip4)),
1545 (Ether(dst="ff:ff:ff:ff:ff:ff",
1546 src=self.pg2.remote_hosts[1].mac) /
1548 hwdst="ff:ff:ff:ff:ff:ff",
1549 hwsrc=self.pg2.remote_hosts[1].mac,
1550 pdst=self.pg2.remote_hosts[1].ip4,
1551 psrc=self.pg2.remote_hosts[1].ip4))]
1553 self.send_and_assert_no_replies(self.pg1, p1)
1554 self.assertFalse(find_nbr(self,
1555 self.pg1.sw_if_index,
1556 self.pg2.remote_hosts[1].ip4))
1558 # they are all dropped because the subnet's don't match
1559 self.assertEqual(4, self.statistics.get_err_counter(
1560 "/err/arp-reply/IP4 destination address not local to subnet"))
1562 def test_arp_incomplete(self):
1563 """ Incomplete Entries """
1566 # ensure that we throttle the ARP and ND requests
1568 self.pg0.generate_remote_hosts(2)
1573 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1574 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1575 self.pg0.sw_if_index)])
1576 ip_10_0_0_1.add_vpp_config()
1578 p1 = (Ether(dst=self.pg1.local_mac,
1579 src=self.pg1.remote_mac) /
1580 IP(src=self.pg1.remote_ip4,
1582 UDP(sport=1234, dport=1234) /
1585 self.pg1.add_stream(p1 * 257)
1586 self.pg_enable_capture(self.pg_interfaces)
1588 rx = self.pg0._get_capture(1)
1591 # how many we get is going to be dependent on the time for packet
1592 # processing but it should be small
1594 self.assertLess(len(rx), 64)
1599 ip_10_1 = VppIpRoute(self, "10::1", 128,
1600 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1601 self.pg0.sw_if_index,
1602 proto=DpoProto.DPO_PROTO_IP6)])
1603 ip_10_1.add_vpp_config()
1605 p1 = (Ether(dst=self.pg1.local_mac,
1606 src=self.pg1.remote_mac) /
1607 IPv6(src=self.pg1.remote_ip6,
1609 UDP(sport=1234, dport=1234) /
1612 self.pg1.add_stream(p1 * 257)
1613 self.pg_enable_capture(self.pg_interfaces)
1615 rx = self.pg0._get_capture(1)
1618 # how many we get is going to be dependent on the time for packet
1619 # processing but it should be small
1621 self.assertLess(len(rx), 64)
1623 def test_arp_forus(self):
1624 """ ARP for for-us """
1627 # Test that VPP responds with ARP requests to addresses that
1628 # are connected and local routes.
1629 # Use one of the 'remote' addresses in the subnet as a local address
1630 # The intention of this route is that it then acts like a secondary
1631 # address added to an interface
1633 self.pg0.generate_remote_hosts(2)
1636 self, self.pg0.remote_hosts[1].ip4, 32,
1637 [VppRoutePath("0.0.0.0",
1638 self.pg0.sw_if_index,
1639 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1640 forus.add_vpp_config()
1642 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1643 src=self.pg0.remote_mac) /
1645 hwdst=self.pg0.local_mac,
1646 hwsrc=self.pg0.remote_mac,
1647 pdst=self.pg0.remote_hosts[1].ip4,
1648 psrc=self.pg0.remote_ip4))
1650 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1652 self.verify_arp_resp(rx[0],
1654 self.pg0.remote_mac,
1655 self.pg0.remote_hosts[1].ip4,
1656 self.pg0.remote_ip4)
1658 def test_arp_table_swap(self):
1660 # Generate some hosts on the LAN
1663 self.pg1.generate_remote_hosts(N_NBRS)
1665 for n in range(N_NBRS):
1666 # a route thru each neighbour
1667 VppIpRoute(self, "10.0.0.%d" % n, 32,
1668 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1669 self.pg1.sw_if_index)]).add_vpp_config()
1671 # resolve each neighbour
1672 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1673 ARP(op="is-at", hwdst=self.pg1.local_mac,
1674 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1675 psrc=self.pg1.remote_hosts[n].ip4))
1677 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1679 self.logger.info(self.vapi.cli("sh ip neighbors"))
1682 # swap the table pg1 is in
1684 table = VppIpTable(self, 100).add_vpp_config()
1686 self.pg1.unconfig_ip4()
1687 self.pg1.set_table_ip4(100)
1688 self.pg1.config_ip4()
1691 # all neighbours are cleared
1693 for n in range(N_NBRS):
1694 self.assertFalse(find_nbr(self,
1695 self.pg1.sw_if_index,
1696 self.pg1.remote_hosts[n].ip4))
1699 # packets to all neighbours generate ARP requests
1701 for n in range(N_NBRS):
1702 # a route thru each neighbour
1703 VppIpRoute(self, "10.0.0.%d" % n, 32,
1704 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1705 self.pg1.sw_if_index)],
1706 table_id=100).add_vpp_config()
1708 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1709 dst=self.pg1.local_mac) /
1710 IP(src=self.pg1.remote_hosts[n].ip4,
1711 dst="10.0.0.%d" % n) /
1713 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1715 self.verify_arp_req(rx,
1718 self.pg1.remote_hosts[n].ip4)
1720 self.pg1.unconfig_ip4()
1721 self.pg1.set_table_ip4(0)
1724 class NeighborStatsTestCase(VppTestCase):
1725 """ ARP/ND Counters """
1728 def setUpClass(cls):
1729 super(NeighborStatsTestCase, cls).setUpClass()
1732 def tearDownClass(cls):
1733 super(NeighborStatsTestCase, cls).tearDownClass()
1736 super(NeighborStatsTestCase, self).setUp()
1738 self.create_pg_interfaces(range(2))
1740 # pg0 configured with ip4 and 6 addresses used for input
1741 # pg1 configured with ip4 and 6 addresses used for output
1742 # pg2 is unnumbered to pg0
1743 for i in self.pg_interfaces:
1751 super(NeighborStatsTestCase, self).tearDown()
1753 for i in self.pg_interfaces:
1758 def test_arp_stats(self):
1759 """ ARP Counters """
1761 self.vapi.cli("adj counters enable")
1762 self.pg1.generate_remote_hosts(2)
1764 arp1 = VppNeighbor(self,
1765 self.pg1.sw_if_index,
1766 self.pg1.remote_hosts[0].mac,
1767 self.pg1.remote_hosts[0].ip4)
1768 arp1.add_vpp_config()
1769 arp2 = VppNeighbor(self,
1770 self.pg1.sw_if_index,
1771 self.pg1.remote_hosts[1].mac,
1772 self.pg1.remote_hosts[1].ip4)
1773 arp2.add_vpp_config()
1775 p1 = (Ether(dst=self.pg0.local_mac,
1776 src=self.pg0.remote_mac) /
1777 IP(src=self.pg0.remote_ip4,
1778 dst=self.pg1.remote_hosts[0].ip4) /
1779 UDP(sport=1234, dport=1234) /
1781 p2 = (Ether(dst=self.pg0.local_mac,
1782 src=self.pg0.remote_mac) /
1783 IP(src=self.pg0.remote_ip4,
1784 dst=self.pg1.remote_hosts[1].ip4) /
1785 UDP(sport=1234, dport=1234) /
1788 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1789 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1791 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1792 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1794 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1795 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1797 def test_nd_stats(self):
1800 self.vapi.cli("adj counters enable")
1801 self.pg0.generate_remote_hosts(3)
1803 nd1 = VppNeighbor(self,
1804 self.pg0.sw_if_index,
1805 self.pg0.remote_hosts[1].mac,
1806 self.pg0.remote_hosts[1].ip6)
1807 nd1.add_vpp_config()
1808 nd2 = VppNeighbor(self,
1809 self.pg0.sw_if_index,
1810 self.pg0.remote_hosts[2].mac,
1811 self.pg0.remote_hosts[2].ip6)
1812 nd2.add_vpp_config()
1814 p1 = (Ether(dst=self.pg1.local_mac,
1815 src=self.pg1.remote_mac) /
1816 IPv6(src=self.pg1.remote_ip6,
1817 dst=self.pg0.remote_hosts[1].ip6) /
1818 UDP(sport=1234, dport=1234) /
1820 p2 = (Ether(dst=self.pg1.local_mac,
1821 src=self.pg1.remote_mac) /
1822 IPv6(src=self.pg1.remote_ip6,
1823 dst=self.pg0.remote_hosts[2].ip6) /
1824 UDP(sport=1234, dport=1234) /
1827 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1828 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1830 self.assertEqual(16, nd1.get_stats()['packets'])
1831 self.assertEqual(16, nd2.get_stats()['packets'])
1833 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1834 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1837 class NeighborAgeTestCase(VppTestCase):
1838 """ ARP/ND Aging """
1841 def setUpClass(cls):
1842 super(NeighborAgeTestCase, cls).setUpClass()
1845 def tearDownClass(cls):
1846 super(NeighborAgeTestCase, cls).tearDownClass()
1849 super(NeighborAgeTestCase, self).setUp()
1851 self.create_pg_interfaces(range(1))
1853 # pg0 configured with ip4 and 6 addresses used for input
1854 # pg1 configured with ip4 and 6 addresses used for output
1855 # pg2 is unnumbered to pg0
1856 for i in self.pg_interfaces:
1864 super(NeighborAgeTestCase, self).tearDown()
1866 for i in self.pg_interfaces:
1871 def wait_for_no_nbr(self, intf, address,
1872 n_tries=50, s_time=1):
1874 if not find_nbr(self, intf, address):
1876 n_tries = n_tries - 1
1881 def verify_arp_req(self, rx, smac, sip, dip):
1883 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1884 self.assertEqual(ether.src, smac)
1887 self.assertEqual(arp.hwtype, 1)
1888 self.assertEqual(arp.ptype, 0x800)
1889 self.assertEqual(arp.hwlen, 6)
1890 self.assertEqual(arp.plen, 4)
1891 self.assertEqual(arp.op, arp_opts["who-has"])
1892 self.assertEqual(arp.hwsrc, smac)
1893 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1894 self.assertEqual(arp.psrc, sip)
1895 self.assertEqual(arp.pdst, dip)
1898 """ Aging/Recycle """
1900 self.vapi.cli("set logging unthrottle 0")
1901 self.vapi.cli("set logging size %d" % 0xffff)
1903 self.pg0.generate_remote_hosts(201)
1905 vaf = VppEnum.vl_api_address_family_t
1908 # start listening on all interfaces
1910 self.pg_enable_capture(self.pg_interfaces)
1913 # Set the neighbor configuration:
1918 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1923 self.vapi.cli("sh ip neighbor-config")
1925 # add the 198 neighbours that should pass (-1 for one created in setup)
1926 for ii in range(200):
1928 self.pg0.sw_if_index,
1929 self.pg0.remote_hosts[ii].mac,
1930 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1932 # one more neighbor over the limit should fail
1933 with self.vapi.assert_negative_api_retval():
1935 self.pg0.sw_if_index,
1936 self.pg0.remote_hosts[200].mac,
1937 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1940 # change the config to allow recycling the old neighbors
1942 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1947 # now new additions are allowed
1949 self.pg0.sw_if_index,
1950 self.pg0.remote_hosts[200].mac,
1951 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1953 # add the first neighbor we configured has been re-used
1954 self.assertFalse(find_nbr(self,
1955 self.pg0.sw_if_index,
1956 self.pg0.remote_hosts[0].ip4))
1957 self.assertTrue(find_nbr(self,
1958 self.pg0.sw_if_index,
1959 self.pg0.remote_hosts[200].ip4))
1962 # change the config to age old neighbors
1964 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1969 self.vapi.cli("sh ip4 neighbor-sorted")
1972 # expect probes from all these ARP entries as they age
1973 # 3 probes for each neighbor 3*200 = 600
1974 rxs = self.pg0.get_capture(600, timeout=8)
1977 for jj in range(200):
1978 rx = rxs[ii*200 + jj]
1982 # 3 probes sent then 1 more second to see if a reply comes, before
1985 for jj in range(1, 201):
1986 self.wait_for_no_nbr(self.pg0.sw_if_index,
1987 self.pg0.remote_hosts[jj].ip4)
1989 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1990 af=vaf.ADDRESS_IP4))
1993 # load up some neighbours again with 2s aging enabled
1994 # they should be removed after 10s (2s age + 4s for probes + gap)
1996 for ii in range(10):
1998 self.pg0.sw_if_index,
1999 self.pg0.remote_hosts[ii].mac,
2000 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2002 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2003 af=vaf.ADDRESS_IP4))
2006 # check if we can set age and recycle with empty neighbor list
2008 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2014 # load up some neighbours again, then disable the aging
2015 # they should still be there in 10 seconds time
2017 for ii in range(10):
2019 self.pg0.sw_if_index,
2020 self.pg0.remote_hosts[ii].mac,
2021 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2022 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2028 self.assertTrue(find_nbr(self,
2029 self.pg0.sw_if_index,
2030 self.pg0.remote_hosts[0].ip4))
2033 class NeighborReplaceTestCase(VppTestCase):
2034 """ ARP/ND Replacement """
2037 def setUpClass(cls):
2038 super(NeighborReplaceTestCase, cls).setUpClass()
2041 def tearDownClass(cls):
2042 super(NeighborReplaceTestCase, cls).tearDownClass()
2045 super(NeighborReplaceTestCase, self).setUp()
2047 self.create_pg_interfaces(range(4))
2049 # pg0 configured with ip4 and 6 addresses used for input
2050 # pg1 configured with ip4 and 6 addresses used for output
2051 # pg2 is unnumbered to pg0
2052 for i in self.pg_interfaces:
2060 super(NeighborReplaceTestCase, self).tearDown()
2062 for i in self.pg_interfaces:
2067 def test_replace(self):
2072 for i in self.pg_interfaces:
2073 i.generate_remote_hosts(N_HOSTS)
2074 i.configure_ipv4_neighbors()
2075 i.configure_ipv6_neighbors()
2078 self.vapi.ip_neighbor_replace_begin()
2079 self.vapi.ip_neighbor_replace_end()
2081 for i in self.pg_interfaces:
2082 for h in range(N_HOSTS):
2083 self.assertFalse(find_nbr(self,
2084 self.pg0.sw_if_index,
2085 self.pg0.remote_hosts[h].ip4))
2086 self.assertFalse(find_nbr(self,
2087 self.pg0.sw_if_index,
2088 self.pg0.remote_hosts[h].ip6))
2091 # and them all back via the API
2093 for i in self.pg_interfaces:
2094 for h in range(N_HOSTS):
2097 i.remote_hosts[h].mac,
2098 i.remote_hosts[h].ip4).add_vpp_config()
2101 i.remote_hosts[h].mac,
2102 i.remote_hosts[h].ip6).add_vpp_config()
2105 # begin the replacement again, this time touch some
2106 # the neighbours on pg1 so they are not deleted
2108 self.vapi.ip_neighbor_replace_begin()
2110 # update from the API all neighbours on pg1
2111 for h in range(N_HOSTS):
2113 self.pg1.sw_if_index,
2114 self.pg1.remote_hosts[h].mac,
2115 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2117 self.pg1.sw_if_index,
2118 self.pg1.remote_hosts[h].mac,
2119 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2121 # update from the data-plane all neighbours on pg3
2122 self.pg3.configure_ipv4_neighbors()
2123 self.pg3.configure_ipv6_neighbors()
2125 # complete the replacement
2126 self.logger.info(self.vapi.cli("sh ip neighbors"))
2127 self.vapi.ip_neighbor_replace_end()
2129 for i in self.pg_interfaces:
2130 if i == self.pg1 or i == self.pg3:
2131 # neighbours on pg1 and pg3 are still present
2132 for h in range(N_HOSTS):
2133 self.assertTrue(find_nbr(self,
2135 i.remote_hosts[h].ip4))
2136 self.assertTrue(find_nbr(self,
2138 i.remote_hosts[h].ip6))
2140 # all other neighbours are toast
2141 for h in range(N_HOSTS):
2142 self.assertFalse(find_nbr(self,
2144 i.remote_hosts[h].ip4))
2145 self.assertFalse(find_nbr(self,
2147 i.remote_hosts[h].ip6))
2150 class NeighborFlush(VppTestCase):
2151 """ Neighbor Flush """
2154 def setUpClass(cls):
2155 super(NeighborFlush, cls).setUpClass()
2158 def tearDownClass(cls):
2159 super(NeighborFlush, cls).tearDownClass()
2162 super(NeighborFlush, self).setUp()
2164 self.create_pg_interfaces(range(2))
2166 for i in self.pg_interfaces:
2174 super(NeighborFlush, self).tearDown()
2176 for i in self.pg_interfaces:
2181 def test_flush(self):
2182 """ Neighbour Flush """
2185 nf = e.vl_api_ip_neighbor_flags_t
2186 af = e.vl_api_address_family_t
2188 static = [False, True]
2189 self.pg0.generate_remote_hosts(N_HOSTS)
2190 self.pg1.generate_remote_hosts(N_HOSTS)
2193 # a few v4 and v6 dynamic neoghbors
2194 for n in range(N_HOSTS):
2196 self.pg0.sw_if_index,
2197 self.pg0.remote_hosts[n].mac,
2198 self.pg0.remote_hosts[n].ip4,
2199 is_static=s).add_vpp_config()
2201 self.pg1.sw_if_index,
2202 self.pg1.remote_hosts[n].mac,
2203 self.pg1.remote_hosts[n].ip6,
2204 is_static=s).add_vpp_config()
2206 # flush the interfaces individually
2207 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2209 # check we haven't flushed that which we shouldn't
2210 for n in range(N_HOSTS):
2211 self.assertTrue(find_nbr(self,
2212 self.pg1.sw_if_index,
2213 self.pg1.remote_hosts[n].ip6,
2216 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2218 for n in range(N_HOSTS):
2219 self.assertFalse(find_nbr(self,
2220 self.pg0.sw_if_index,
2221 self.pg0.remote_hosts[n].ip4))
2222 self.assertFalse(find_nbr(self,
2223 self.pg1.sw_if_index,
2224 self.pg1.remote_hosts[n].ip6))
2226 # add the nieghbours back
2227 for n in range(N_HOSTS):
2229 self.pg0.sw_if_index,
2230 self.pg0.remote_hosts[n].mac,
2231 self.pg0.remote_hosts[n].ip4,
2232 is_static=s).add_vpp_config()
2234 self.pg1.sw_if_index,
2235 self.pg1.remote_hosts[n].mac,
2236 self.pg1.remote_hosts[n].ip6,
2237 is_static=s).add_vpp_config()
2239 self.logger.info(self.vapi.cli("sh ip neighbor"))
2241 # flush both interfaces at the same time
2242 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2244 # check we haven't flushed that which we shouldn't
2245 for n in range(N_HOSTS):
2246 self.assertTrue(find_nbr(self,
2247 self.pg0.sw_if_index,
2248 self.pg0.remote_hosts[n].ip4,
2251 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2253 for n in range(N_HOSTS):
2254 self.assertFalse(find_nbr(self,
2255 self.pg0.sw_if_index,
2256 self.pg0.remote_hosts[n].ip4))
2257 self.assertFalse(find_nbr(self,
2258 self.pg1.sw_if_index,
2259 self.pg1.remote_hosts[n].ip6))
2262 if __name__ == '__main__':
2263 unittest.main(testRunner=VppTestRunner)