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(proxy={'table_id': 0,
767 'low': self.pg0._local_ip4_subnet,
768 'hi': self.pg0._local_ip4_bcast},
771 # Make pg2 un-numbered to pg0
773 self.pg2.set_unnumbered(self.pg0.sw_if_index)
776 # Enable pg2 for proxy ARP
778 self.pg2.set_proxy_arp()
781 # Send the ARP request with an originating address that
782 # is VPP's own address
784 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
785 self.verify_arp_resp(rx[0],
788 self.pg0.remote_hosts[1].ip4,
792 # validate we have not learned an ARP entry as a result of this
794 self.assertFalse(find_nbr(self,
795 self.pg2.sw_if_index,
799 # setup a punt redirect so packets from the uplink go to the tap
801 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
802 self.pg2.sw_if_index,
805 p_tcp = (Ether(src=self.pg0.remote_mac,
806 dst=self.pg0.local_mac,) /
807 IP(src=self.pg0.remote_ip4,
808 dst=self.pg0.local_ip4) /
809 TCP(sport=80, dport=80) /
811 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
813 # there's no ARP entry so this is an ARP req
814 self.assertTrue(rx[0].haslayer(ARP))
816 # and ARP entry for VPP's pg0 address on the host interface
817 n1 = VppNeighbor(self,
818 self.pg2.sw_if_index,
821 is_no_fib_entry=True).add_vpp_config()
822 # now the packets shold forward
823 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
824 self.assertFalse(rx[0].haslayer(ARP))
825 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
828 # flush the neighbor cache on the uplink
830 af = VppEnum.vl_api_address_family_t
831 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
833 # ensure we can still resolve the ARPs on the uplink
834 self.pg0.resolve_arp()
836 self.assertTrue(find_nbr(self,
837 self.pg0.sw_if_index,
838 self.pg0.remote_ip4))
843 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
844 'low': self.pg0._local_ip4_subnet,
845 'hi': self.pg0._local_ip4_bcast},
848 def test_proxy_arp(self):
851 self.pg1.generate_remote_hosts(2)
854 # Proxy ARP request packets for each interface
856 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
857 dst="ff:ff:ff:ff:ff:ff") /
859 hwsrc=self.pg0.remote_mac,
861 psrc=self.pg0.remote_ip4))
862 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
863 dst="ff:ff:ff:ff:ff:ff") /
866 hwsrc=self.pg0.remote_mac,
868 psrc=self.pg0.remote_ip4))
869 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
870 dst="ff:ff:ff:ff:ff:ff") /
872 hwsrc=self.pg1.remote_mac,
874 psrc=self.pg1.remote_ip4))
875 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
876 dst="ff:ff:ff:ff:ff:ff") /
878 hwsrc=self.pg2.remote_mac,
880 psrc=self.pg1.remote_hosts[1].ip4))
881 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
882 dst="ff:ff:ff:ff:ff:ff") /
884 hwsrc=self.pg3.remote_mac,
886 psrc=self.pg3.remote_ip4))
889 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
891 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
893 'hi': "10.10.10.124"},
897 # No responses are sent when the interfaces are not enabled for proxy
900 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
901 "ARP req from unconfigured interface")
902 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
903 "ARP req from unconfigured interface")
906 # Make pg2 un-numbered to pg1
909 self.pg2.set_unnumbered(self.pg1.sw_if_index)
911 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
912 "ARP req from unnumbered interface")
915 # Enable each interface to reply to proxy ARPs
917 for i in self.pg_interfaces:
921 # Now each of the interfaces should reply to a request to a proxied
924 self.pg0.add_stream(arp_req_pg0)
925 self.pg_enable_capture(self.pg_interfaces)
928 rx = self.pg0.get_capture(1)
929 self.verify_arp_resp(rx[0],
935 self.pg0.add_stream(arp_req_pg0_tagged)
936 self.pg_enable_capture(self.pg_interfaces)
939 rx = self.pg0.get_capture(1)
940 self.verify_arp_resp(rx[0],
946 self.pg1.add_stream(arp_req_pg1)
947 self.pg_enable_capture(self.pg_interfaces)
950 rx = self.pg1.get_capture(1)
951 self.verify_arp_resp(rx[0],
957 self.pg2.add_stream(arp_req_pg2)
958 self.pg_enable_capture(self.pg_interfaces)
961 rx = self.pg2.get_capture(1)
962 self.verify_arp_resp(rx[0],
966 self.pg1.remote_hosts[1].ip4)
969 # A request for an address out of the configured range
971 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
972 dst="ff:ff:ff:ff:ff:ff") /
974 hwsrc=self.pg1.remote_mac,
976 psrc=self.pg1.remote_ip4))
977 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
978 "ARP req out of range HI")
979 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
980 dst="ff:ff:ff:ff:ff:ff") /
982 hwsrc=self.pg1.remote_mac,
984 psrc=self.pg1.remote_ip4))
985 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
986 "ARP req out of range Low")
989 # Request for an address in the proxy range but from an interface
992 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
993 "ARP req from different VRF")
996 # Disable Each interface for proxy ARP
997 # - expect none to respond
999 for i in self.pg_interfaces:
1002 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
1003 "ARP req from disable")
1004 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1005 "ARP req from disable")
1006 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1007 "ARP req from disable")
1010 # clean up on interface 2
1012 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1014 def test_mpls(self):
1018 # Interface 2 does not yet have ip4 config
1020 self.pg2.config_ip4()
1021 self.pg2.generate_remote_hosts(2)
1024 # Add a route with out going label via an ARP unresolved next-hop
1026 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1027 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1028 self.pg2.sw_if_index,
1030 ip_10_0_0_1.add_vpp_config()
1033 # packets should generate an ARP request
1035 p = (Ether(src=self.pg0.remote_mac,
1036 dst=self.pg0.local_mac) /
1037 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1038 UDP(sport=1234, dport=1234) /
1041 self.pg0.add_stream(p)
1042 self.pg_enable_capture(self.pg_interfaces)
1045 rx = self.pg2.get_capture(1)
1046 self.verify_arp_req(rx[0],
1049 self.pg2._remote_hosts[1].ip4)
1052 # now resolve the neighbours
1054 self.pg2.configure_ipv4_neighbors()
1057 # Now packet should be properly MPLS encapped.
1058 # This verifies that MPLS link-type adjacencies are completed
1059 # when the ARP entry resolves
1061 self.pg0.add_stream(p)
1062 self.pg_enable_capture(self.pg_interfaces)
1065 rx = self.pg2.get_capture(1)
1066 self.verify_ip_o_mpls(rx[0],
1068 self.pg2.remote_hosts[1].mac,
1070 self.pg0.remote_ip4,
1072 self.pg2.unconfig_ip4()
1074 def test_arp_vrrp(self):
1075 """ ARP reply with VRRP virtual src hw addr """
1078 # IP packet destined for pg1 remote host arrives on pg0 resulting
1079 # in an ARP request for the address of the remote host on pg1
1081 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1082 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1083 UDP(sport=1234, dport=1234) /
1086 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1088 self.verify_arp_req(rx1[0],
1091 self.pg1.remote_ip4)
1094 # ARP reply for address of pg1 remote host arrives on pg1 with
1095 # the hw src addr set to a value in the VRRP IPv4 range of
1098 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1099 ARP(op="is-at", hwdst=self.pg1.local_mac,
1100 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1101 psrc=self.pg1.remote_ip4))
1103 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1106 # IP packet destined for pg1 remote host arrives on pg0 again.
1107 # VPP should have an ARP entry for that address now and the packet
1108 # should be sent out pg1.
1110 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1112 self.verify_ip(rx1[0],
1114 "00:00:5e:00:01:09",
1115 self.pg0.remote_ip4,
1116 self.pg1.remote_ip4)
1118 self.pg1.admin_down()
1121 def test_arp_duplicates(self):
1122 """ ARP Duplicates"""
1125 # Generate some hosts on the LAN
1127 self.pg1.generate_remote_hosts(3)
1130 # Add host 1 on pg1 and pg2
1132 arp_pg1 = VppNeighbor(self,
1133 self.pg1.sw_if_index,
1134 self.pg1.remote_hosts[1].mac,
1135 self.pg1.remote_hosts[1].ip4)
1136 arp_pg1.add_vpp_config()
1137 arp_pg2 = VppNeighbor(self,
1138 self.pg2.sw_if_index,
1139 self.pg2.remote_mac,
1140 self.pg1.remote_hosts[1].ip4)
1141 arp_pg2.add_vpp_config()
1144 # IP packet destined for pg1 remote host arrives on pg1 again.
1146 p = (Ether(dst=self.pg0.local_mac,
1147 src=self.pg0.remote_mac) /
1148 IP(src=self.pg0.remote_ip4,
1149 dst=self.pg1.remote_hosts[1].ip4) /
1150 UDP(sport=1234, dport=1234) /
1153 self.pg0.add_stream(p)
1154 self.pg_enable_capture(self.pg_interfaces)
1157 rx1 = self.pg1.get_capture(1)
1159 self.verify_ip(rx1[0],
1161 self.pg1.remote_hosts[1].mac,
1162 self.pg0.remote_ip4,
1163 self.pg1.remote_hosts[1].ip4)
1166 # remove the duplicate on pg1
1167 # packet stream should generate ARPs out of pg1
1169 arp_pg1.remove_vpp_config()
1171 self.pg0.add_stream(p)
1172 self.pg_enable_capture(self.pg_interfaces)
1175 rx1 = self.pg1.get_capture(1)
1177 self.verify_arp_req(rx1[0],
1180 self.pg1.remote_hosts[1].ip4)
1185 arp_pg1.add_vpp_config()
1187 self.pg0.add_stream(p)
1188 self.pg_enable_capture(self.pg_interfaces)
1191 rx1 = self.pg1.get_capture(1)
1193 self.verify_ip(rx1[0],
1195 self.pg1.remote_hosts[1].mac,
1196 self.pg0.remote_ip4,
1197 self.pg1.remote_hosts[1].ip4)
1199 def test_arp_static(self):
1201 self.pg2.generate_remote_hosts(3)
1204 # Add a static ARP entry
1206 static_arp = VppNeighbor(self,
1207 self.pg2.sw_if_index,
1208 self.pg2.remote_hosts[1].mac,
1209 self.pg2.remote_hosts[1].ip4,
1211 static_arp.add_vpp_config()
1214 # Add the connected prefix to the interface
1216 self.pg2.config_ip4()
1219 # We should now find the adj-fib
1221 self.assertTrue(find_nbr(self,
1222 self.pg2.sw_if_index,
1223 self.pg2.remote_hosts[1].ip4,
1225 self.assertTrue(find_route(self,
1226 self.pg2.remote_hosts[1].ip4,
1230 # remove the connected
1232 self.pg2.unconfig_ip4()
1235 # put the interface into table 1
1237 self.pg2.set_table_ip4(1)
1240 # configure the same connected and expect to find the
1241 # adj fib in the new table
1243 self.pg2.config_ip4()
1244 self.assertTrue(find_route(self,
1245 self.pg2.remote_hosts[1].ip4,
1252 self.pg2.unconfig_ip4()
1253 static_arp.remove_vpp_config()
1254 self.pg2.set_table_ip4(0)
1256 def test_arp_static_replace_dynamic_same_mac(self):
1257 """ ARP Static can replace Dynamic (same mac) """
1258 self.pg2.generate_remote_hosts(1)
1260 dyn_arp = VppNeighbor(self,
1261 self.pg2.sw_if_index,
1262 self.pg2.remote_hosts[0].mac,
1263 self.pg2.remote_hosts[0].ip4)
1264 static_arp = VppNeighbor(self,
1265 self.pg2.sw_if_index,
1266 self.pg2.remote_hosts[0].mac,
1267 self.pg2.remote_hosts[0].ip4,
1271 # Add a dynamic ARP entry
1273 dyn_arp.add_vpp_config()
1276 # We should find the dynamic nbr
1278 self.assertFalse(find_nbr(self,
1279 self.pg2.sw_if_index,
1280 self.pg2.remote_hosts[0].ip4,
1282 self.assertTrue(find_nbr(self,
1283 self.pg2.sw_if_index,
1284 self.pg2.remote_hosts[0].ip4,
1286 mac=self.pg2.remote_hosts[0].mac))
1289 # Add a static ARP entry with the same mac
1291 static_arp.add_vpp_config()
1294 # We should now find the static nbr with the same mac
1296 self.assertFalse(find_nbr(self,
1297 self.pg2.sw_if_index,
1298 self.pg2.remote_hosts[0].ip4,
1300 self.assertTrue(find_nbr(self,
1301 self.pg2.sw_if_index,
1302 self.pg2.remote_hosts[0].ip4,
1304 mac=self.pg2.remote_hosts[0].mac))
1309 static_arp.remove_vpp_config()
1311 def test_arp_static_replace_dynamic_diff_mac(self):
1312 """ ARP Static can replace Dynamic (diff mac) """
1313 self.pg2.generate_remote_hosts(2)
1315 dyn_arp = VppNeighbor(self,
1316 self.pg2.sw_if_index,
1317 self.pg2.remote_hosts[0].mac,
1318 self.pg2.remote_hosts[0].ip4)
1319 static_arp = VppNeighbor(self,
1320 self.pg2.sw_if_index,
1321 self.pg2.remote_hosts[1].mac,
1322 self.pg2.remote_hosts[0].ip4,
1326 # Add a dynamic ARP entry
1328 dyn_arp.add_vpp_config()
1331 # We should find the dynamic nbr
1333 self.assertFalse(find_nbr(self,
1334 self.pg2.sw_if_index,
1335 self.pg2.remote_hosts[0].ip4,
1337 self.assertTrue(find_nbr(self,
1338 self.pg2.sw_if_index,
1339 self.pg2.remote_hosts[0].ip4,
1341 mac=self.pg2.remote_hosts[0].mac))
1344 # Add a static ARP entry with a changed mac
1346 static_arp.add_vpp_config()
1349 # We should now find the static nbr with a changed mac
1351 self.assertFalse(find_nbr(self,
1352 self.pg2.sw_if_index,
1353 self.pg2.remote_hosts[0].ip4,
1355 self.assertTrue(find_nbr(self,
1356 self.pg2.sw_if_index,
1357 self.pg2.remote_hosts[0].ip4,
1359 mac=self.pg2.remote_hosts[1].mac))
1364 static_arp.remove_vpp_config()
1366 def test_arp_incomplete(self):
1367 """ ARP Incomplete"""
1368 self.pg1.generate_remote_hosts(3)
1370 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1371 IP(src=self.pg0.remote_ip4,
1372 dst=self.pg1.remote_hosts[1].ip4) /
1373 UDP(sport=1234, dport=1234) /
1375 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1376 IP(src=self.pg0.remote_ip4,
1377 dst=self.pg1.remote_hosts[2].ip4) /
1378 UDP(sport=1234, dport=1234) /
1382 # a packet to an unresolved destination generates an ARP request
1384 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1385 self.verify_arp_req(rx[0],
1388 self.pg1._remote_hosts[1].ip4)
1391 # add a neighbour for remote host 1
1393 static_arp = VppNeighbor(self,
1394 self.pg1.sw_if_index,
1395 self.pg1.remote_hosts[1].mac,
1396 self.pg1.remote_hosts[1].ip4,
1398 static_arp.add_vpp_config()
1401 # change the interface's MAC
1403 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1404 "00:00:00:33:33:33")
1407 # now ARP requests come from the new source mac
1409 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1410 self.verify_arp_req(rx[0],
1411 "00:00:00:33:33:33",
1413 self.pg1._remote_hosts[2].ip4)
1416 # packets to the resolved host also have the new source mac
1418 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1419 self.verify_ip(rx[0],
1420 "00:00:00:33:33:33",
1421 self.pg1.remote_hosts[1].mac,
1422 self.pg0.remote_ip4,
1423 self.pg1.remote_hosts[1].ip4)
1426 # set the mac address on the interface that does not have a
1427 # configured subnet and thus no glean
1429 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1430 "00:00:00:33:33:33")
1432 def test_garp(self):
1436 # Generate some hosts on the LAN
1438 self.pg1.generate_remote_hosts(4)
1439 self.pg2.generate_remote_hosts(4)
1444 arp = VppNeighbor(self,
1445 self.pg1.sw_if_index,
1446 self.pg1.remote_hosts[1].mac,
1447 self.pg1.remote_hosts[1].ip4)
1448 arp.add_vpp_config()
1450 self.assertTrue(find_nbr(self,
1451 self.pg1.sw_if_index,
1452 self.pg1.remote_hosts[1].ip4,
1453 mac=self.pg1.remote_hosts[1].mac))
1456 # Send a GARP (request) to swap the host 1's address to that of host 2
1458 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1459 src=self.pg1.remote_hosts[2].mac) /
1461 hwdst=self.pg1.local_mac,
1462 hwsrc=self.pg1.remote_hosts[2].mac,
1463 pdst=self.pg1.remote_hosts[1].ip4,
1464 psrc=self.pg1.remote_hosts[1].ip4))
1466 self.pg1.add_stream(p1)
1467 self.pg_enable_capture(self.pg_interfaces)
1470 self.assertTrue(find_nbr(self,
1471 self.pg1.sw_if_index,
1472 self.pg1.remote_hosts[1].ip4,
1473 mac=self.pg1.remote_hosts[2].mac))
1476 # Send a GARP (reply) to swap the host 1's address to that of host 3
1478 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1479 src=self.pg1.remote_hosts[3].mac) /
1481 hwdst=self.pg1.local_mac,
1482 hwsrc=self.pg1.remote_hosts[3].mac,
1483 pdst=self.pg1.remote_hosts[1].ip4,
1484 psrc=self.pg1.remote_hosts[1].ip4))
1486 self.pg1.add_stream(p1)
1487 self.pg_enable_capture(self.pg_interfaces)
1490 self.assertTrue(find_nbr(self,
1491 self.pg1.sw_if_index,
1492 self.pg1.remote_hosts[1].ip4,
1493 mac=self.pg1.remote_hosts[3].mac))
1496 # GARPs (request nor replies) for host we don't know yet
1497 # don't result in new neighbour entries
1499 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1500 src=self.pg1.remote_hosts[3].mac) /
1502 hwdst=self.pg1.local_mac,
1503 hwsrc=self.pg1.remote_hosts[3].mac,
1504 pdst=self.pg1.remote_hosts[2].ip4,
1505 psrc=self.pg1.remote_hosts[2].ip4))
1507 self.pg1.add_stream(p1)
1508 self.pg_enable_capture(self.pg_interfaces)
1511 self.assertFalse(find_nbr(self,
1512 self.pg1.sw_if_index,
1513 self.pg1.remote_hosts[2].ip4))
1515 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1516 src=self.pg1.remote_hosts[3].mac) /
1518 hwdst=self.pg1.local_mac,
1519 hwsrc=self.pg1.remote_hosts[3].mac,
1520 pdst=self.pg1.remote_hosts[2].ip4,
1521 psrc=self.pg1.remote_hosts[2].ip4))
1523 self.pg1.add_stream(p1)
1524 self.pg_enable_capture(self.pg_interfaces)
1527 self.assertFalse(find_nbr(self,
1528 self.pg1.sw_if_index,
1529 self.pg1.remote_hosts[2].ip4))
1532 # IP address in different subnets are not learnt
1534 self.pg2.configure_ipv4_neighbors()
1536 for op in ["is-at", "who-has"]:
1537 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1538 src=self.pg2.remote_hosts[1].mac) /
1540 hwdst=self.pg2.local_mac,
1541 hwsrc=self.pg2.remote_hosts[1].mac,
1542 pdst=self.pg2.remote_hosts[1].ip4,
1543 psrc=self.pg2.remote_hosts[1].ip4)),
1544 (Ether(dst="ff:ff:ff:ff:ff:ff",
1545 src=self.pg2.remote_hosts[1].mac) /
1547 hwdst="ff:ff:ff:ff:ff:ff",
1548 hwsrc=self.pg2.remote_hosts[1].mac,
1549 pdst=self.pg2.remote_hosts[1].ip4,
1550 psrc=self.pg2.remote_hosts[1].ip4))]
1552 self.send_and_assert_no_replies(self.pg1, p1)
1553 self.assertFalse(find_nbr(self,
1554 self.pg1.sw_if_index,
1555 self.pg2.remote_hosts[1].ip4))
1557 # they are all dropped because the subnet's don't match
1558 self.assertEqual(4, self.statistics.get_err_counter(
1559 "/err/arp-reply/IP4 destination address not local to subnet"))
1561 def test_arp_incomplete2(self):
1562 """ Incomplete Entries """
1565 # ensure that we throttle the ARP and ND requests
1567 self.pg0.generate_remote_hosts(2)
1572 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1573 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1574 self.pg0.sw_if_index)])
1575 ip_10_0_0_1.add_vpp_config()
1577 p1 = (Ether(dst=self.pg1.local_mac,
1578 src=self.pg1.remote_mac) /
1579 IP(src=self.pg1.remote_ip4,
1581 UDP(sport=1234, dport=1234) /
1584 self.pg1.add_stream(p1 * 257)
1585 self.pg_enable_capture(self.pg_interfaces)
1587 rx = self.pg0._get_capture(1)
1590 # how many we get is going to be dependent on the time for packet
1591 # processing but it should be small
1593 self.assertLess(len(rx), 64)
1598 ip_10_1 = VppIpRoute(self, "10::1", 128,
1599 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1600 self.pg0.sw_if_index,
1601 proto=DpoProto.DPO_PROTO_IP6)])
1602 ip_10_1.add_vpp_config()
1604 p1 = (Ether(dst=self.pg1.local_mac,
1605 src=self.pg1.remote_mac) /
1606 IPv6(src=self.pg1.remote_ip6,
1608 UDP(sport=1234, dport=1234) /
1611 self.pg1.add_stream(p1 * 257)
1612 self.pg_enable_capture(self.pg_interfaces)
1614 rx = self.pg0._get_capture(1)
1617 # how many we get is going to be dependent on the time for packet
1618 # processing but it should be small
1620 self.assertLess(len(rx), 64)
1622 def test_arp_forus(self):
1623 """ ARP for for-us """
1626 # Test that VPP responds with ARP requests to addresses that
1627 # are connected and local routes.
1628 # Use one of the 'remote' addresses in the subnet as a local address
1629 # The intention of this route is that it then acts like a secondary
1630 # address added to an interface
1632 self.pg0.generate_remote_hosts(2)
1635 self, self.pg0.remote_hosts[1].ip4, 32,
1636 [VppRoutePath("0.0.0.0",
1637 self.pg0.sw_if_index,
1638 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1639 forus.add_vpp_config()
1641 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1642 src=self.pg0.remote_mac) /
1644 hwdst=self.pg0.local_mac,
1645 hwsrc=self.pg0.remote_mac,
1646 pdst=self.pg0.remote_hosts[1].ip4,
1647 psrc=self.pg0.remote_ip4))
1649 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1651 self.verify_arp_resp(rx[0],
1653 self.pg0.remote_mac,
1654 self.pg0.remote_hosts[1].ip4,
1655 self.pg0.remote_ip4)
1657 def test_arp_table_swap(self):
1659 # Generate some hosts on the LAN
1662 self.pg1.generate_remote_hosts(N_NBRS)
1664 for n in range(N_NBRS):
1665 # a route thru each neighbour
1666 VppIpRoute(self, "10.0.0.%d" % n, 32,
1667 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1668 self.pg1.sw_if_index)]).add_vpp_config()
1670 # resolve each neighbour
1671 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1672 ARP(op="is-at", hwdst=self.pg1.local_mac,
1673 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1674 psrc=self.pg1.remote_hosts[n].ip4))
1676 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1678 self.logger.info(self.vapi.cli("sh ip neighbors"))
1681 # swap the table pg1 is in
1683 table = VppIpTable(self, 100).add_vpp_config()
1685 self.pg1.unconfig_ip4()
1686 self.pg1.set_table_ip4(100)
1687 self.pg1.config_ip4()
1690 # all neighbours are cleared
1692 for n in range(N_NBRS):
1693 self.assertFalse(find_nbr(self,
1694 self.pg1.sw_if_index,
1695 self.pg1.remote_hosts[n].ip4))
1698 # packets to all neighbours generate ARP requests
1700 for n in range(N_NBRS):
1701 # a route thru each neighbour
1702 VppIpRoute(self, "10.0.0.%d" % n, 32,
1703 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1704 self.pg1.sw_if_index)],
1705 table_id=100).add_vpp_config()
1707 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1708 dst=self.pg1.local_mac) /
1709 IP(src=self.pg1.remote_hosts[n].ip4,
1710 dst="10.0.0.%d" % n) /
1712 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1714 self.verify_arp_req(rx,
1717 self.pg1.remote_hosts[n].ip4)
1719 self.pg1.unconfig_ip4()
1720 self.pg1.set_table_ip4(0)
1723 class NeighborStatsTestCase(VppTestCase):
1724 """ ARP/ND Counters """
1727 def setUpClass(cls):
1728 super(NeighborStatsTestCase, cls).setUpClass()
1731 def tearDownClass(cls):
1732 super(NeighborStatsTestCase, cls).tearDownClass()
1735 super(NeighborStatsTestCase, self).setUp()
1737 self.create_pg_interfaces(range(2))
1739 # pg0 configured with ip4 and 6 addresses used for input
1740 # pg1 configured with ip4 and 6 addresses used for output
1741 # pg2 is unnumbered to pg0
1742 for i in self.pg_interfaces:
1750 super(NeighborStatsTestCase, self).tearDown()
1752 for i in self.pg_interfaces:
1757 def test_arp_stats(self):
1758 """ ARP Counters """
1760 self.vapi.cli("adj counters enable")
1761 self.pg1.generate_remote_hosts(2)
1763 arp1 = VppNeighbor(self,
1764 self.pg1.sw_if_index,
1765 self.pg1.remote_hosts[0].mac,
1766 self.pg1.remote_hosts[0].ip4)
1767 arp1.add_vpp_config()
1768 arp2 = VppNeighbor(self,
1769 self.pg1.sw_if_index,
1770 self.pg1.remote_hosts[1].mac,
1771 self.pg1.remote_hosts[1].ip4)
1772 arp2.add_vpp_config()
1774 p1 = (Ether(dst=self.pg0.local_mac,
1775 src=self.pg0.remote_mac) /
1776 IP(src=self.pg0.remote_ip4,
1777 dst=self.pg1.remote_hosts[0].ip4) /
1778 UDP(sport=1234, dport=1234) /
1780 p2 = (Ether(dst=self.pg0.local_mac,
1781 src=self.pg0.remote_mac) /
1782 IP(src=self.pg0.remote_ip4,
1783 dst=self.pg1.remote_hosts[1].ip4) /
1784 UDP(sport=1234, dport=1234) /
1787 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1788 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1790 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1791 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1793 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1794 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1796 def test_nd_stats(self):
1799 self.vapi.cli("adj counters enable")
1800 self.pg0.generate_remote_hosts(3)
1802 nd1 = VppNeighbor(self,
1803 self.pg0.sw_if_index,
1804 self.pg0.remote_hosts[1].mac,
1805 self.pg0.remote_hosts[1].ip6)
1806 nd1.add_vpp_config()
1807 nd2 = VppNeighbor(self,
1808 self.pg0.sw_if_index,
1809 self.pg0.remote_hosts[2].mac,
1810 self.pg0.remote_hosts[2].ip6)
1811 nd2.add_vpp_config()
1813 p1 = (Ether(dst=self.pg1.local_mac,
1814 src=self.pg1.remote_mac) /
1815 IPv6(src=self.pg1.remote_ip6,
1816 dst=self.pg0.remote_hosts[1].ip6) /
1817 UDP(sport=1234, dport=1234) /
1819 p2 = (Ether(dst=self.pg1.local_mac,
1820 src=self.pg1.remote_mac) /
1821 IPv6(src=self.pg1.remote_ip6,
1822 dst=self.pg0.remote_hosts[2].ip6) /
1823 UDP(sport=1234, dport=1234) /
1826 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1827 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1829 self.assertEqual(16, nd1.get_stats()['packets'])
1830 self.assertEqual(16, nd2.get_stats()['packets'])
1832 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1833 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1836 class NeighborAgeTestCase(VppTestCase):
1837 """ ARP/ND Aging """
1840 def setUpClass(cls):
1841 super(NeighborAgeTestCase, cls).setUpClass()
1844 def tearDownClass(cls):
1845 super(NeighborAgeTestCase, cls).tearDownClass()
1848 super(NeighborAgeTestCase, self).setUp()
1850 self.create_pg_interfaces(range(1))
1852 # pg0 configured with ip4 and 6 addresses used for input
1853 # pg1 configured with ip4 and 6 addresses used for output
1854 # pg2 is unnumbered to pg0
1855 for i in self.pg_interfaces:
1863 super(NeighborAgeTestCase, self).tearDown()
1865 for i in self.pg_interfaces:
1870 def wait_for_no_nbr(self, intf, address,
1871 n_tries=50, s_time=1):
1873 if not find_nbr(self, intf, address):
1875 n_tries = n_tries - 1
1880 def verify_arp_req(self, rx, smac, sip, dip):
1882 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1883 self.assertEqual(ether.src, smac)
1886 self.assertEqual(arp.hwtype, 1)
1887 self.assertEqual(arp.ptype, 0x800)
1888 self.assertEqual(arp.hwlen, 6)
1889 self.assertEqual(arp.plen, 4)
1890 self.assertEqual(arp.op, arp_opts["who-has"])
1891 self.assertEqual(arp.hwsrc, smac)
1892 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1893 self.assertEqual(arp.psrc, sip)
1894 self.assertEqual(arp.pdst, dip)
1897 """ Aging/Recycle """
1899 self.vapi.cli("set logging unthrottle 0")
1900 self.vapi.cli("set logging size %d" % 0xffff)
1902 self.pg0.generate_remote_hosts(201)
1904 vaf = VppEnum.vl_api_address_family_t
1907 # start listening on all interfaces
1909 self.pg_enable_capture(self.pg_interfaces)
1912 # Set the neighbor configuration:
1917 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1922 self.vapi.cli("sh ip neighbor-config")
1924 # add the 198 neighbours that should pass (-1 for one created in setup)
1925 for ii in range(200):
1927 self.pg0.sw_if_index,
1928 self.pg0.remote_hosts[ii].mac,
1929 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1931 # one more neighbor over the limit should fail
1932 with self.vapi.assert_negative_api_retval():
1934 self.pg0.sw_if_index,
1935 self.pg0.remote_hosts[200].mac,
1936 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1939 # change the config to allow recycling the old neighbors
1941 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1946 # now new additions are allowed
1948 self.pg0.sw_if_index,
1949 self.pg0.remote_hosts[200].mac,
1950 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1952 # add the first neighbor we configured has been re-used
1953 self.assertFalse(find_nbr(self,
1954 self.pg0.sw_if_index,
1955 self.pg0.remote_hosts[0].ip4))
1956 self.assertTrue(find_nbr(self,
1957 self.pg0.sw_if_index,
1958 self.pg0.remote_hosts[200].ip4))
1961 # change the config to age old neighbors
1963 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1968 self.vapi.cli("sh ip4 neighbor-sorted")
1971 # expect probes from all these ARP entries as they age
1972 # 3 probes for each neighbor 3*200 = 600
1973 rxs = self.pg0.get_capture(600, timeout=8)
1976 for jj in range(200):
1977 rx = rxs[ii*200 + jj]
1981 # 3 probes sent then 1 more second to see if a reply comes, before
1984 for jj in range(1, 201):
1985 self.wait_for_no_nbr(self.pg0.sw_if_index,
1986 self.pg0.remote_hosts[jj].ip4)
1988 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1989 af=vaf.ADDRESS_IP4))
1992 # load up some neighbours again with 2s aging enabled
1993 # they should be removed after 10s (2s age + 4s for probes + gap)
1995 for ii in range(10):
1997 self.pg0.sw_if_index,
1998 self.pg0.remote_hosts[ii].mac,
1999 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2001 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2002 af=vaf.ADDRESS_IP4))
2005 # check if we can set age and recycle with empty neighbor list
2007 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2013 # load up some neighbours again, then disable the aging
2014 # they should still be there in 10 seconds time
2016 for ii in range(10):
2018 self.pg0.sw_if_index,
2019 self.pg0.remote_hosts[ii].mac,
2020 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2021 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2027 self.assertTrue(find_nbr(self,
2028 self.pg0.sw_if_index,
2029 self.pg0.remote_hosts[0].ip4))
2032 class NeighborReplaceTestCase(VppTestCase):
2033 """ ARP/ND Replacement """
2036 def setUpClass(cls):
2037 super(NeighborReplaceTestCase, cls).setUpClass()
2040 def tearDownClass(cls):
2041 super(NeighborReplaceTestCase, cls).tearDownClass()
2044 super(NeighborReplaceTestCase, self).setUp()
2046 self.create_pg_interfaces(range(4))
2048 # pg0 configured with ip4 and 6 addresses used for input
2049 # pg1 configured with ip4 and 6 addresses used for output
2050 # pg2 is unnumbered to pg0
2051 for i in self.pg_interfaces:
2059 super(NeighborReplaceTestCase, self).tearDown()
2061 for i in self.pg_interfaces:
2066 def test_replace(self):
2071 for i in self.pg_interfaces:
2072 i.generate_remote_hosts(N_HOSTS)
2073 i.configure_ipv4_neighbors()
2074 i.configure_ipv6_neighbors()
2077 self.vapi.ip_neighbor_replace_begin()
2078 self.vapi.ip_neighbor_replace_end()
2080 for i in self.pg_interfaces:
2081 for h in range(N_HOSTS):
2082 self.assertFalse(find_nbr(self,
2083 self.pg0.sw_if_index,
2084 self.pg0.remote_hosts[h].ip4))
2085 self.assertFalse(find_nbr(self,
2086 self.pg0.sw_if_index,
2087 self.pg0.remote_hosts[h].ip6))
2090 # and them all back via the API
2092 for i in self.pg_interfaces:
2093 for h in range(N_HOSTS):
2096 i.remote_hosts[h].mac,
2097 i.remote_hosts[h].ip4).add_vpp_config()
2100 i.remote_hosts[h].mac,
2101 i.remote_hosts[h].ip6).add_vpp_config()
2104 # begin the replacement again, this time touch some
2105 # the neighbours on pg1 so they are not deleted
2107 self.vapi.ip_neighbor_replace_begin()
2109 # update from the API all neighbours on pg1
2110 for h in range(N_HOSTS):
2112 self.pg1.sw_if_index,
2113 self.pg1.remote_hosts[h].mac,
2114 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2116 self.pg1.sw_if_index,
2117 self.pg1.remote_hosts[h].mac,
2118 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2120 # update from the data-plane all neighbours on pg3
2121 self.pg3.configure_ipv4_neighbors()
2122 self.pg3.configure_ipv6_neighbors()
2124 # complete the replacement
2125 self.logger.info(self.vapi.cli("sh ip neighbors"))
2126 self.vapi.ip_neighbor_replace_end()
2128 for i in self.pg_interfaces:
2129 if i == self.pg1 or i == self.pg3:
2130 # neighbours on pg1 and pg3 are still present
2131 for h in range(N_HOSTS):
2132 self.assertTrue(find_nbr(self,
2134 i.remote_hosts[h].ip4))
2135 self.assertTrue(find_nbr(self,
2137 i.remote_hosts[h].ip6))
2139 # all other neighbours are toast
2140 for h in range(N_HOSTS):
2141 self.assertFalse(find_nbr(self,
2143 i.remote_hosts[h].ip4))
2144 self.assertFalse(find_nbr(self,
2146 i.remote_hosts[h].ip6))
2149 class NeighborFlush(VppTestCase):
2150 """ Neighbor Flush """
2153 def setUpClass(cls):
2154 super(NeighborFlush, cls).setUpClass()
2157 def tearDownClass(cls):
2158 super(NeighborFlush, cls).tearDownClass()
2161 super(NeighborFlush, self).setUp()
2163 self.create_pg_interfaces(range(2))
2165 for i in self.pg_interfaces:
2173 super(NeighborFlush, self).tearDown()
2175 for i in self.pg_interfaces:
2180 def test_flush(self):
2181 """ Neighbour Flush """
2184 nf = e.vl_api_ip_neighbor_flags_t
2185 af = e.vl_api_address_family_t
2187 static = [False, True]
2188 self.pg0.generate_remote_hosts(N_HOSTS)
2189 self.pg1.generate_remote_hosts(N_HOSTS)
2192 # a few v4 and v6 dynamic neoghbors
2193 for n in range(N_HOSTS):
2195 self.pg0.sw_if_index,
2196 self.pg0.remote_hosts[n].mac,
2197 self.pg0.remote_hosts[n].ip4,
2198 is_static=s).add_vpp_config()
2200 self.pg1.sw_if_index,
2201 self.pg1.remote_hosts[n].mac,
2202 self.pg1.remote_hosts[n].ip6,
2203 is_static=s).add_vpp_config()
2205 # flush the interfaces individually
2206 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2208 # check we haven't flushed that which we shouldn't
2209 for n in range(N_HOSTS):
2210 self.assertTrue(find_nbr(self,
2211 self.pg1.sw_if_index,
2212 self.pg1.remote_hosts[n].ip6,
2215 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2217 for n in range(N_HOSTS):
2218 self.assertFalse(find_nbr(self,
2219 self.pg0.sw_if_index,
2220 self.pg0.remote_hosts[n].ip4))
2221 self.assertFalse(find_nbr(self,
2222 self.pg1.sw_if_index,
2223 self.pg1.remote_hosts[n].ip6))
2225 # add the nieghbours back
2226 for n in range(N_HOSTS):
2228 self.pg0.sw_if_index,
2229 self.pg0.remote_hosts[n].mac,
2230 self.pg0.remote_hosts[n].ip4,
2231 is_static=s).add_vpp_config()
2233 self.pg1.sw_if_index,
2234 self.pg1.remote_hosts[n].mac,
2235 self.pg1.remote_hosts[n].ip6,
2236 is_static=s).add_vpp_config()
2238 self.logger.info(self.vapi.cli("sh ip neighbor"))
2240 # flush both interfaces at the same time
2241 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2243 # check we haven't flushed that which we shouldn't
2244 for n in range(N_HOSTS):
2245 self.assertTrue(find_nbr(self,
2246 self.pg0.sw_if_index,
2247 self.pg0.remote_hosts[n].ip4,
2250 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2252 for n in range(N_HOSTS):
2253 self.assertFalse(find_nbr(self,
2254 self.pg0.sw_if_index,
2255 self.pg0.remote_hosts[n].ip4))
2256 self.assertFalse(find_nbr(self,
2257 self.pg1.sw_if_index,
2258 self.pg1.remote_hosts[n].ip6))
2261 if __name__ == '__main__':
2262 unittest.main(testRunner=VppTestRunner)