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, VppIpInterfaceAddress
11 from vpp_papi import VppEnum
12 from vpp_ip import VppIpPuntRedirect
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether, ARP, Dot1Q
17 from scapy.layers.inet import IP, UDP, TCP
18 from scapy.layers.inet6 import IPv6
19 from scapy.contrib.mpls import MPLS
20 from scapy.layers.inet6 import IPv6
25 # not exported by scapy, so redefined here
26 arp_opts = {"who-has": 1, "is-at": 2}
29 class ARPTestCase(VppTestCase):
34 super(ARPTestCase, cls).setUpClass()
37 def tearDownClass(cls):
38 super(ARPTestCase, cls).tearDownClass()
41 super(ARPTestCase, self).setUp()
43 # create 3 pg interfaces
44 self.create_pg_interfaces(range(4))
46 # pg0 configured with ip4 and 6 addresses used for input
47 # pg1 configured with ip4 and 6 addresses used for output
48 # pg2 is unnumbered to pg0
49 for i in self.pg_interfaces:
54 self.pg0.resolve_arp()
59 # pg3 in a different VRF
60 self.tbl = VppIpTable(self, 1)
61 self.tbl.add_vpp_config()
63 self.pg3.set_table_ip4(1)
67 self.pg0.unconfig_ip4()
68 self.pg0.unconfig_ip6()
70 self.pg1.unconfig_ip4()
71 self.pg1.unconfig_ip6()
73 self.pg3.unconfig_ip4()
74 self.pg3.set_table_ip4(0)
76 for i in self.pg_interfaces:
79 super(ARPTestCase, self).tearDown()
81 def verify_arp_req(self, rx, smac, sip, dip):
83 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
84 self.assertEqual(ether.src, smac)
87 self.assertEqual(arp.hwtype, 1)
88 self.assertEqual(arp.ptype, 0x800)
89 self.assertEqual(arp.hwlen, 6)
90 self.assertEqual(arp.plen, 4)
91 self.assertEqual(arp.op, arp_opts["who-has"])
92 self.assertEqual(arp.hwsrc, smac)
93 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
94 self.assertEqual(arp.psrc, sip)
95 self.assertEqual(arp.pdst, dip)
97 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
99 self.assertEqual(ether.dst, dmac)
100 self.assertEqual(ether.src, smac)
103 self.assertEqual(arp.hwtype, 1)
104 self.assertEqual(arp.ptype, 0x800)
105 self.assertEqual(arp.hwlen, 6)
106 self.assertEqual(arp.plen, 4)
107 self.assertEqual(arp.op, arp_opts["is-at"])
108 self.assertEqual(arp.hwsrc, smac)
109 self.assertEqual(arp.hwdst, dmac)
110 self.assertEqual(arp.psrc, sip)
111 self.assertEqual(arp.pdst, dip)
113 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
115 self.assertEqual(ether.dst, dmac)
116 self.assertEqual(ether.src, smac)
119 self.assertEqual(arp.hwtype, 1)
120 self.assertEqual(arp.ptype, 0x800)
121 self.assertEqual(arp.hwlen, 6)
122 self.assertEqual(arp.plen, 4)
123 self.assertEqual(arp.op, arp_opts["is-at"])
124 self.assertNotEqual(arp.hwsrc, smac)
125 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
126 "00:00:5E:00:01" in arp.hwsrc)
127 self.assertEqual(arp.hwdst, dmac)
128 self.assertEqual(arp.psrc, sip)
129 self.assertEqual(arp.pdst, dip)
131 def verify_ip(self, rx, smac, dmac, sip, dip):
133 self.assertEqual(ether.dst, dmac)
134 self.assertEqual(ether.src, smac)
137 self.assertEqual(ip.src, sip)
138 self.assertEqual(ip.dst, dip)
140 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
142 self.assertEqual(ether.dst, dmac)
143 self.assertEqual(ether.src, smac)
146 self.assertTrue(mpls.label, label)
149 self.assertEqual(ip.src, sip)
150 self.assertEqual(ip.dst, dip)
156 # Generate some hosts on the LAN
158 self.pg1.generate_remote_hosts(11)
162 # - all neighbour events
163 # - all neighbor events on pg1
164 # - neighbor events for host[1] on pg1
166 self.vapi.want_ip_neighbor_events(enable=1,
168 self.vapi.want_ip_neighbor_events(enable=1,
170 sw_if_index=self.pg1.sw_if_index)
171 self.vapi.want_ip_neighbor_events(enable=1,
173 sw_if_index=self.pg1.sw_if_index,
174 ip=self.pg1.remote_hosts[1].ip4)
176 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
179 # Send IP traffic to one of these unresolved hosts.
180 # expect the generation of an ARP request
182 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
183 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
184 UDP(sport=1234, dport=1234) /
187 self.pg0.add_stream(p)
188 self.pg_enable_capture(self.pg_interfaces)
191 rx = self.pg1.get_capture(1)
193 self.verify_arp_req(rx[0],
196 self.pg1._remote_hosts[1].ip4)
199 # And a dynamic ARP entry for host 1
201 dyn_arp = VppNeighbor(self,
202 self.pg1.sw_if_index,
203 self.pg1.remote_hosts[1].mac,
204 self.pg1.remote_hosts[1].ip4)
205 dyn_arp.add_vpp_config()
206 self.assertTrue(dyn_arp.query_vpp_config())
208 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
210 # this matches all of the listnerers
211 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
214 self.assertEqual(str(e.neighbor.ip_address),
215 self.pg1.remote_hosts[1].ip4)
218 # now we expect IP traffic forwarded
220 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
221 IP(src=self.pg0.remote_ip4,
222 dst=self.pg1._remote_hosts[1].ip4) /
223 UDP(sport=1234, dport=1234) /
226 self.pg0.add_stream(dyn_p)
227 self.pg_enable_capture(self.pg_interfaces)
230 rx = self.pg1.get_capture(1)
232 self.verify_ip(rx[0],
234 self.pg1.remote_hosts[1].mac,
236 self.pg1._remote_hosts[1].ip4)
239 # And a Static ARP entry for host 2
241 static_arp = VppNeighbor(self,
242 self.pg1.sw_if_index,
243 self.pg1.remote_hosts[2].mac,
244 self.pg1.remote_hosts[2].ip4,
246 static_arp.add_vpp_config()
247 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
250 self.assertEqual(str(e.neighbor.ip_address),
251 self.pg1.remote_hosts[2].ip4)
253 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
254 IP(src=self.pg0.remote_ip4,
255 dst=self.pg1._remote_hosts[2].ip4) /
256 UDP(sport=1234, dport=1234) /
259 self.pg0.add_stream(static_p)
260 self.pg_enable_capture(self.pg_interfaces)
263 rx = self.pg1.get_capture(1)
265 self.verify_ip(rx[0],
267 self.pg1.remote_hosts[2].mac,
269 self.pg1._remote_hosts[2].ip4)
272 # remove all the listeners
274 self.vapi.want_ip_neighbor_events(enable=0,
276 self.vapi.want_ip_neighbor_events(enable=0,
278 sw_if_index=self.pg1.sw_if_index)
279 self.vapi.want_ip_neighbor_events(enable=0,
281 sw_if_index=self.pg1.sw_if_index,
282 ip=self.pg1.remote_hosts[1].ip4)
285 # flap the link. dynamic ARPs get flush, statics don't
287 self.pg1.admin_down()
290 self.pg0.add_stream(static_p)
291 self.pg_enable_capture(self.pg_interfaces)
293 rx = self.pg1.get_capture(1)
295 self.verify_ip(rx[0],
297 self.pg1.remote_hosts[2].mac,
299 self.pg1._remote_hosts[2].ip4)
301 self.pg0.add_stream(dyn_p)
302 self.pg_enable_capture(self.pg_interfaces)
305 rx = self.pg1.get_capture(1)
306 self.verify_arp_req(rx[0],
309 self.pg1._remote_hosts[1].ip4)
311 self.assertFalse(dyn_arp.query_vpp_config())
312 self.assertTrue(static_arp.query_vpp_config())
314 # Send an ARP request from one of the so-far unlearned remote hosts
316 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
317 src=self.pg1._remote_hosts[3].mac) /
319 hwsrc=self.pg1._remote_hosts[3].mac,
320 pdst=self.pg1.local_ip4,
321 psrc=self.pg1._remote_hosts[3].ip4))
323 self.pg1.add_stream(p)
324 self.pg_enable_capture(self.pg_interfaces)
327 rx = self.pg1.get_capture(1)
328 self.verify_arp_resp(rx[0],
330 self.pg1._remote_hosts[3].mac,
332 self.pg1._remote_hosts[3].ip4)
335 # VPP should have learned the mapping for the remote host
337 self.assertTrue(find_nbr(self,
338 self.pg1.sw_if_index,
339 self.pg1._remote_hosts[3].ip4))
341 # Fire in an ARP request before the interface becomes IP enabled
343 self.pg2.generate_remote_hosts(4)
345 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
347 hwsrc=self.pg2.remote_mac,
348 pdst=self.pg1.local_ip4,
349 psrc=self.pg2.remote_hosts[3].ip4))
350 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
353 hwsrc=self.pg2.remote_mac,
354 pdst=self.pg1.local_ip4,
355 psrc=self.pg2.remote_hosts[3].ip4))
356 self.send_and_assert_no_replies(self.pg2, p,
357 "interface not IP enabled")
360 # Make pg2 un-numbered to pg1
362 self.pg2.set_unnumbered(self.pg1.sw_if_index)
365 # test the unnumbered dump both by all interfaces and just the enabled
368 unnum = self.vapi.ip_unnumbered_dump()
369 self.assertTrue(len(unnum))
370 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
371 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
372 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
373 self.assertTrue(len(unnum))
374 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
375 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
378 # We should respond to ARP requests for the unnumbered to address
379 # once an attached route to the source is known
381 self.send_and_assert_no_replies(
383 "ARP req for unnumbered address - no source")
385 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
386 [VppRoutePath("0.0.0.0",
387 self.pg2.sw_if_index)])
388 attached_host.add_vpp_config()
390 self.pg2.add_stream(p)
391 self.pg_enable_capture(self.pg_interfaces)
394 rx = self.pg2.get_capture(1)
395 self.verify_arp_resp(rx[0],
399 self.pg2.remote_hosts[3].ip4)
401 self.pg2.add_stream(pt)
402 self.pg_enable_capture(self.pg_interfaces)
405 rx = self.pg2.get_capture(1)
406 self.verify_arp_resp(rx[0],
410 self.pg2.remote_hosts[3].ip4)
413 # A neighbor entry that has no associated FIB-entry
415 arp_no_fib = VppNeighbor(self,
416 self.pg1.sw_if_index,
417 self.pg1.remote_hosts[4].mac,
418 self.pg1.remote_hosts[4].ip4,
420 arp_no_fib.add_vpp_config()
423 # check we have the neighbor, but no route
425 self.assertTrue(find_nbr(self,
426 self.pg1.sw_if_index,
427 self.pg1._remote_hosts[4].ip4))
428 self.assertFalse(find_route(self,
429 self.pg1._remote_hosts[4].ip4,
432 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
433 # from within pg1's subnet
435 arp_unnum = VppNeighbor(self,
436 self.pg2.sw_if_index,
437 self.pg1.remote_hosts[5].mac,
438 self.pg1.remote_hosts[5].ip4)
439 arp_unnum.add_vpp_config()
441 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
442 IP(src=self.pg0.remote_ip4,
443 dst=self.pg1._remote_hosts[5].ip4) /
444 UDP(sport=1234, dport=1234) /
447 self.pg0.add_stream(p)
448 self.pg_enable_capture(self.pg_interfaces)
451 rx = self.pg2.get_capture(1)
453 self.verify_ip(rx[0],
455 self.pg1.remote_hosts[5].mac,
457 self.pg1._remote_hosts[5].ip4)
460 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
461 # with the unnumbered interface's address as the source
463 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
465 hwsrc=self.pg2.remote_mac,
466 pdst=self.pg1.local_ip4,
467 psrc=self.pg1.remote_hosts[6].ip4))
469 self.pg2.add_stream(p)
470 self.pg_enable_capture(self.pg_interfaces)
473 rx = self.pg2.get_capture(1)
474 self.verify_arp_resp(rx[0],
478 self.pg1.remote_hosts[6].ip4)
481 # An attached host route out of pg2 for an undiscovered hosts generates
482 # an ARP request with the unnumbered address as the source
484 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
485 [VppRoutePath("0.0.0.0",
486 self.pg2.sw_if_index)])
487 att_unnum.add_vpp_config()
489 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
490 IP(src=self.pg0.remote_ip4,
491 dst=self.pg1._remote_hosts[7].ip4) /
492 UDP(sport=1234, dport=1234) /
495 self.pg0.add_stream(p)
496 self.pg_enable_capture(self.pg_interfaces)
499 rx = self.pg2.get_capture(1)
501 self.verify_arp_req(rx[0],
504 self.pg1._remote_hosts[7].ip4)
506 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
508 hwsrc=self.pg2.remote_mac,
509 pdst=self.pg1.local_ip4,
510 psrc=self.pg1.remote_hosts[7].ip4))
512 self.pg2.add_stream(p)
513 self.pg_enable_capture(self.pg_interfaces)
516 rx = self.pg2.get_capture(1)
517 self.verify_arp_resp(rx[0],
521 self.pg1.remote_hosts[7].ip4)
524 # An attached host route as yet unresolved out of pg2 for an
525 # undiscovered host, an ARP requests begets a response.
527 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
528 [VppRoutePath("0.0.0.0",
529 self.pg2.sw_if_index)])
530 att_unnum1.add_vpp_config()
532 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
534 hwsrc=self.pg2.remote_mac,
535 pdst=self.pg1.local_ip4,
536 psrc=self.pg1.remote_hosts[8].ip4))
538 self.pg2.add_stream(p)
539 self.pg_enable_capture(self.pg_interfaces)
542 rx = self.pg2.get_capture(1)
543 self.verify_arp_resp(rx[0],
547 self.pg1.remote_hosts[8].ip4)
550 # Send an ARP request from one of the so-far unlearned remote hosts
553 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
554 src=self.pg1._remote_hosts[9].mac) /
557 hwsrc=self.pg1._remote_hosts[9].mac,
558 pdst=self.pg1.local_ip4,
559 psrc=self.pg1._remote_hosts[9].ip4))
561 self.pg1.add_stream(p)
562 self.pg_enable_capture(self.pg_interfaces)
565 rx = self.pg1.get_capture(1)
566 self.verify_arp_resp(rx[0],
568 self.pg1._remote_hosts[9].mac,
570 self.pg1._remote_hosts[9].ip4)
573 # Add a hierarchy of routes for a host in the sub-net.
574 # Should still get an ARP resp since the cover is attached
576 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
578 hwsrc=self.pg1.remote_mac,
579 pdst=self.pg1.local_ip4,
580 psrc=self.pg1.remote_hosts[10].ip4))
582 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
583 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
584 self.pg1.sw_if_index)])
587 self.pg1.add_stream(p)
588 self.pg_enable_capture(self.pg_interfaces)
590 rx = self.pg1.get_capture(1)
591 self.verify_arp_resp(rx[0],
595 self.pg1.remote_hosts[10].ip4)
597 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
598 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
599 self.pg1.sw_if_index)])
602 self.pg1.add_stream(p)
603 self.pg_enable_capture(self.pg_interfaces)
605 rx = self.pg1.get_capture(1)
606 self.verify_arp_resp(rx[0],
610 self.pg1.remote_hosts[10].ip4)
613 # add an ARP entry that's not on the sub-net and so whose
614 # adj-fib fails the refinement check. then send an ARP request
617 a1 = VppNeighbor(self,
618 self.pg0.sw_if_index,
623 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
625 hwsrc=self.pg0.remote_mac,
626 psrc="100.100.100.50",
627 pdst=self.pg0.remote_ip4))
628 self.send_and_assert_no_replies(self.pg0, p,
629 "ARP req for from failed adj-fib")
633 # 1 - don't respond to ARP request for address not within the
634 # interface's sub-net
635 # 1b - nor within the unnumbered subnet
636 # 1c - nor within the subnet of a different interface
638 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
640 hwsrc=self.pg0.remote_mac,
642 psrc=self.pg0.remote_ip4))
643 self.send_and_assert_no_replies(self.pg0, p,
644 "ARP req for non-local destination")
645 self.assertFalse(find_nbr(self,
646 self.pg0.sw_if_index,
649 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
651 hwsrc=self.pg2.remote_mac,
653 psrc=self.pg1.remote_hosts[7].ip4))
654 self.send_and_assert_no_replies(
656 "ARP req for non-local destination - unnum")
658 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
660 hwsrc=self.pg0.remote_mac,
661 pdst=self.pg1.local_ip4,
662 psrc=self.pg1.remote_ip4))
663 self.send_and_assert_no_replies(self.pg0, p,
664 "ARP req diff sub-net")
665 self.assertFalse(find_nbr(self,
666 self.pg0.sw_if_index,
667 self.pg1.remote_ip4))
670 # 2 - don't respond to ARP request from an address not within the
671 # interface's sub-net
672 # 2b - to a proxied address
673 # 2c - not within a different interface's sub-net
674 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
676 hwsrc=self.pg0.remote_mac,
678 pdst=self.pg0.local_ip4))
679 self.send_and_assert_no_replies(self.pg0, p,
680 "ARP req for non-local source")
681 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
683 hwsrc=self.pg2.remote_mac,
685 pdst=self.pg0.local_ip4))
686 self.send_and_assert_no_replies(
688 "ARP req for non-local source - unnum")
689 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
691 hwsrc=self.pg0.remote_mac,
692 psrc=self.pg1.remote_ip4,
693 pdst=self.pg0.local_ip4))
694 self.send_and_assert_no_replies(self.pg0, p,
695 "ARP req for non-local source 2c")
698 # 3 - don't respond to ARP request from an address that belongs to
701 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
703 hwsrc=self.pg0.remote_mac,
704 psrc=self.pg0.local_ip4,
705 pdst=self.pg0.local_ip4))
706 self.send_and_assert_no_replies(self.pg0, p,
707 "ARP req for non-local source")
710 # 4 - don't respond to ARP requests that has mac source different
711 # from ARP request HW source
713 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
715 hwsrc="00:00:00:DE:AD:BE",
716 psrc=self.pg0.remote_ip4,
717 pdst=self.pg0.local_ip4))
718 self.send_and_assert_no_replies(self.pg0, p,
719 "ARP req for non-local source")
722 # 5 - don't respond to ARP requests for address within the
723 # interface's sub-net but not the interface's address
725 self.pg0.generate_remote_hosts(2)
726 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
728 hwsrc=self.pg0.remote_mac,
729 psrc=self.pg0.remote_hosts[0].ip4,
730 pdst=self.pg0.remote_hosts[1].ip4))
731 self.send_and_assert_no_replies(self.pg0, p,
732 "ARP req for non-local destination")
737 static_arp.remove_vpp_config()
738 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
740 # need this to flush the adj-fibs
741 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
742 self.pg2.admin_down()
743 self.pg1.admin_down()
745 def test_proxy_mirror_arp(self):
746 """ Interface Mirror Proxy ARP """
749 # When VPP has an interface whose address is also applied to a TAP
750 # interface on the host, then VPP's TAP interface will be unnumbered
751 # to the 'real' interface and do proxy ARP from the host.
752 # the curious aspect of this setup is that ARP requests from the host
753 # will come from the VPP's own address.
755 self.pg0.generate_remote_hosts(2)
757 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
758 dst="ff:ff:ff:ff:ff:ff") /
760 hwsrc=self.pg2.remote_mac,
761 pdst=self.pg0.remote_hosts[1].ip4,
762 psrc=self.pg0.local_ip4))
765 # Configure Proxy ARP for the subnet on PG0addresses on pg0
767 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
768 'low': self.pg0._local_ip4_subnet,
769 'hi': self.pg0._local_ip4_bcast},
772 # Make pg2 un-numbered to pg0
774 self.pg2.set_unnumbered(self.pg0.sw_if_index)
777 # Enable pg2 for proxy ARP
779 self.pg2.set_proxy_arp()
782 # Send the ARP request with an originating address that
783 # is VPP's own address
785 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
786 self.verify_arp_resp(rx[0],
789 self.pg0.remote_hosts[1].ip4,
793 # validate we have not learned an ARP entry as a result of this
795 self.assertFalse(find_nbr(self,
796 self.pg2.sw_if_index,
800 # setup a punt redirect so packets from the uplink go to the tap
802 redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index,
803 self.pg2.sw_if_index, self.pg0.local_ip4)
804 redirect.add_vpp_config()
806 p_tcp = (Ether(src=self.pg0.remote_mac,
807 dst=self.pg0.local_mac,) /
808 IP(src=self.pg0.remote_ip4,
809 dst=self.pg0.local_ip4) /
810 TCP(sport=80, dport=80) /
812 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
814 # there's no ARP entry so this is an ARP req
815 self.assertTrue(rx[0].haslayer(ARP))
817 # and ARP entry for VPP's pg0 address on the host interface
818 n1 = VppNeighbor(self,
819 self.pg2.sw_if_index,
822 is_no_fib_entry=True).add_vpp_config()
823 # now the packets shold forward
824 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
825 self.assertFalse(rx[0].haslayer(ARP))
826 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
829 # flush the neighbor cache on the uplink
831 af = VppEnum.vl_api_address_family_t
832 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
834 # ensure we can still resolve the ARPs on the uplink
835 self.pg0.resolve_arp()
837 self.assertTrue(find_nbr(self,
838 self.pg0.sw_if_index,
839 self.pg0.remote_ip4))
844 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
845 'low': self.pg0._local_ip4_subnet,
846 'hi': self.pg0._local_ip4_bcast},
848 redirect.remove_vpp_config()
850 def test_proxy_arp(self):
853 self.pg1.generate_remote_hosts(2)
856 # Proxy ARP request packets for each interface
858 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
859 dst="ff:ff:ff:ff:ff:ff") /
861 hwsrc=self.pg0.remote_mac,
863 psrc=self.pg0.remote_ip4))
864 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
865 dst="ff:ff:ff:ff:ff:ff") /
868 hwsrc=self.pg0.remote_mac,
870 psrc=self.pg0.remote_ip4))
871 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
872 dst="ff:ff:ff:ff:ff:ff") /
874 hwsrc=self.pg1.remote_mac,
876 psrc=self.pg1.remote_ip4))
877 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
878 dst="ff:ff:ff:ff:ff:ff") /
880 hwsrc=self.pg2.remote_mac,
882 psrc=self.pg1.remote_hosts[1].ip4))
883 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
884 dst="ff:ff:ff:ff:ff:ff") /
886 hwsrc=self.pg3.remote_mac,
888 psrc=self.pg3.remote_ip4))
891 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
893 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
895 'hi': "10.10.10.124"},
899 # No responses are sent when the interfaces are not enabled for proxy
902 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
903 "ARP req from unconfigured interface")
904 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
905 "ARP req from unconfigured interface")
908 # Make pg2 un-numbered to pg1
911 self.pg2.set_unnumbered(self.pg1.sw_if_index)
913 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
914 "ARP req from unnumbered interface")
917 # Enable each interface to reply to proxy ARPs
919 for i in self.pg_interfaces:
923 # Now each of the interfaces should reply to a request to a proxied
926 self.pg0.add_stream(arp_req_pg0)
927 self.pg_enable_capture(self.pg_interfaces)
930 rx = self.pg0.get_capture(1)
931 self.verify_arp_resp(rx[0],
937 self.pg0.add_stream(arp_req_pg0_tagged)
938 self.pg_enable_capture(self.pg_interfaces)
941 rx = self.pg0.get_capture(1)
942 self.verify_arp_resp(rx[0],
948 self.pg1.add_stream(arp_req_pg1)
949 self.pg_enable_capture(self.pg_interfaces)
952 rx = self.pg1.get_capture(1)
953 self.verify_arp_resp(rx[0],
959 self.pg2.add_stream(arp_req_pg2)
960 self.pg_enable_capture(self.pg_interfaces)
963 rx = self.pg2.get_capture(1)
964 self.verify_arp_resp(rx[0],
968 self.pg1.remote_hosts[1].ip4)
971 # A request for an address out of the configured range
973 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
974 dst="ff:ff:ff:ff:ff:ff") /
976 hwsrc=self.pg1.remote_mac,
978 psrc=self.pg1.remote_ip4))
979 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
980 "ARP req out of range HI")
981 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
982 dst="ff:ff:ff:ff:ff:ff") /
984 hwsrc=self.pg1.remote_mac,
986 psrc=self.pg1.remote_ip4))
987 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
988 "ARP req out of range Low")
991 # Request for an address in the proxy range but from an interface
994 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
995 "ARP req from different VRF")
998 # Disable Each interface for proxy ARP
999 # - expect none to respond
1001 for i in self.pg_interfaces:
1004 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
1005 "ARP req from disable")
1006 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1007 "ARP req from disable")
1008 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1009 "ARP req from disable")
1012 # clean up on interface 2
1014 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1016 def test_mpls(self):
1020 # Interface 2 does not yet have ip4 config
1022 self.pg2.config_ip4()
1023 self.pg2.generate_remote_hosts(2)
1026 # Add a route with out going label via an ARP unresolved next-hop
1028 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1029 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1030 self.pg2.sw_if_index,
1032 ip_10_0_0_1.add_vpp_config()
1035 # packets should generate an ARP request
1037 p = (Ether(src=self.pg0.remote_mac,
1038 dst=self.pg0.local_mac) /
1039 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1040 UDP(sport=1234, dport=1234) /
1043 self.pg0.add_stream(p)
1044 self.pg_enable_capture(self.pg_interfaces)
1047 rx = self.pg2.get_capture(1)
1048 self.verify_arp_req(rx[0],
1051 self.pg2._remote_hosts[1].ip4)
1054 # now resolve the neighbours
1056 self.pg2.configure_ipv4_neighbors()
1059 # Now packet should be properly MPLS encapped.
1060 # This verifies that MPLS link-type adjacencies are completed
1061 # when the ARP entry resolves
1063 self.pg0.add_stream(p)
1064 self.pg_enable_capture(self.pg_interfaces)
1067 rx = self.pg2.get_capture(1)
1068 self.verify_ip_o_mpls(rx[0],
1070 self.pg2.remote_hosts[1].mac,
1072 self.pg0.remote_ip4,
1074 self.pg2.unconfig_ip4()
1076 def test_arp_vrrp(self):
1077 """ ARP reply with VRRP virtual src hw addr """
1080 # IP packet destined for pg1 remote host arrives on pg0 resulting
1081 # in an ARP request for the address of the remote host on pg1
1083 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1084 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1085 UDP(sport=1234, dport=1234) /
1088 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1090 self.verify_arp_req(rx1[0],
1093 self.pg1.remote_ip4)
1096 # ARP reply for address of pg1 remote host arrives on pg1 with
1097 # the hw src addr set to a value in the VRRP IPv4 range of
1100 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1101 ARP(op="is-at", hwdst=self.pg1.local_mac,
1102 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1103 psrc=self.pg1.remote_ip4))
1105 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1108 # IP packet destined for pg1 remote host arrives on pg0 again.
1109 # VPP should have an ARP entry for that address now and the packet
1110 # should be sent out pg1.
1112 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1114 self.verify_ip(rx1[0],
1116 "00:00:5e:00:01:09",
1117 self.pg0.remote_ip4,
1118 self.pg1.remote_ip4)
1120 self.pg1.admin_down()
1123 def test_arp_duplicates(self):
1124 """ ARP Duplicates"""
1127 # Generate some hosts on the LAN
1129 self.pg1.generate_remote_hosts(3)
1132 # Add host 1 on pg1 and pg2
1134 arp_pg1 = VppNeighbor(self,
1135 self.pg1.sw_if_index,
1136 self.pg1.remote_hosts[1].mac,
1137 self.pg1.remote_hosts[1].ip4)
1138 arp_pg1.add_vpp_config()
1139 arp_pg2 = VppNeighbor(self,
1140 self.pg2.sw_if_index,
1141 self.pg2.remote_mac,
1142 self.pg1.remote_hosts[1].ip4)
1143 arp_pg2.add_vpp_config()
1146 # IP packet destined for pg1 remote host arrives on pg1 again.
1148 p = (Ether(dst=self.pg0.local_mac,
1149 src=self.pg0.remote_mac) /
1150 IP(src=self.pg0.remote_ip4,
1151 dst=self.pg1.remote_hosts[1].ip4) /
1152 UDP(sport=1234, dport=1234) /
1155 self.pg0.add_stream(p)
1156 self.pg_enable_capture(self.pg_interfaces)
1159 rx1 = self.pg1.get_capture(1)
1161 self.verify_ip(rx1[0],
1163 self.pg1.remote_hosts[1].mac,
1164 self.pg0.remote_ip4,
1165 self.pg1.remote_hosts[1].ip4)
1168 # remove the duplicate on pg1
1169 # packet stream should generate ARPs out of pg1
1171 arp_pg1.remove_vpp_config()
1173 self.pg0.add_stream(p)
1174 self.pg_enable_capture(self.pg_interfaces)
1177 rx1 = self.pg1.get_capture(1)
1179 self.verify_arp_req(rx1[0],
1182 self.pg1.remote_hosts[1].ip4)
1187 arp_pg1.add_vpp_config()
1189 self.pg0.add_stream(p)
1190 self.pg_enable_capture(self.pg_interfaces)
1193 rx1 = self.pg1.get_capture(1)
1195 self.verify_ip(rx1[0],
1197 self.pg1.remote_hosts[1].mac,
1198 self.pg0.remote_ip4,
1199 self.pg1.remote_hosts[1].ip4)
1201 def test_arp_static(self):
1203 self.pg2.generate_remote_hosts(3)
1206 # Add a static ARP entry
1208 static_arp = VppNeighbor(self,
1209 self.pg2.sw_if_index,
1210 self.pg2.remote_hosts[1].mac,
1211 self.pg2.remote_hosts[1].ip4,
1213 static_arp.add_vpp_config()
1216 # Add the connected prefix to the interface
1218 self.pg2.config_ip4()
1221 # We should now find the adj-fib
1223 self.assertTrue(find_nbr(self,
1224 self.pg2.sw_if_index,
1225 self.pg2.remote_hosts[1].ip4,
1227 self.assertTrue(find_route(self,
1228 self.pg2.remote_hosts[1].ip4,
1232 # remove the connected
1234 self.pg2.unconfig_ip4()
1237 # put the interface into table 1
1239 self.pg2.set_table_ip4(1)
1242 # configure the same connected and expect to find the
1243 # adj fib in the new table
1245 self.pg2.config_ip4()
1246 self.assertTrue(find_route(self,
1247 self.pg2.remote_hosts[1].ip4,
1254 self.pg2.unconfig_ip4()
1255 static_arp.remove_vpp_config()
1256 self.pg2.set_table_ip4(0)
1258 def test_arp_static_replace_dynamic_same_mac(self):
1259 """ ARP Static can replace Dynamic (same mac) """
1260 self.pg2.generate_remote_hosts(1)
1262 dyn_arp = VppNeighbor(self,
1263 self.pg2.sw_if_index,
1264 self.pg2.remote_hosts[0].mac,
1265 self.pg2.remote_hosts[0].ip4)
1266 static_arp = VppNeighbor(self,
1267 self.pg2.sw_if_index,
1268 self.pg2.remote_hosts[0].mac,
1269 self.pg2.remote_hosts[0].ip4,
1273 # Add a dynamic ARP entry
1275 dyn_arp.add_vpp_config()
1278 # We should find the dynamic nbr
1280 self.assertFalse(find_nbr(self,
1281 self.pg2.sw_if_index,
1282 self.pg2.remote_hosts[0].ip4,
1284 self.assertTrue(find_nbr(self,
1285 self.pg2.sw_if_index,
1286 self.pg2.remote_hosts[0].ip4,
1288 mac=self.pg2.remote_hosts[0].mac))
1291 # Add a static ARP entry with the same mac
1293 static_arp.add_vpp_config()
1296 # We should now find the static nbr with the same mac
1298 self.assertFalse(find_nbr(self,
1299 self.pg2.sw_if_index,
1300 self.pg2.remote_hosts[0].ip4,
1302 self.assertTrue(find_nbr(self,
1303 self.pg2.sw_if_index,
1304 self.pg2.remote_hosts[0].ip4,
1306 mac=self.pg2.remote_hosts[0].mac))
1311 static_arp.remove_vpp_config()
1313 def test_arp_static_replace_dynamic_diff_mac(self):
1314 """ ARP Static can replace Dynamic (diff mac) """
1315 self.pg2.generate_remote_hosts(2)
1317 dyn_arp = VppNeighbor(self,
1318 self.pg2.sw_if_index,
1319 self.pg2.remote_hosts[0].mac,
1320 self.pg2.remote_hosts[0].ip4)
1321 static_arp = VppNeighbor(self,
1322 self.pg2.sw_if_index,
1323 self.pg2.remote_hosts[1].mac,
1324 self.pg2.remote_hosts[0].ip4,
1328 # Add a dynamic ARP entry
1330 dyn_arp.add_vpp_config()
1333 # We should find the dynamic nbr
1335 self.assertFalse(find_nbr(self,
1336 self.pg2.sw_if_index,
1337 self.pg2.remote_hosts[0].ip4,
1339 self.assertTrue(find_nbr(self,
1340 self.pg2.sw_if_index,
1341 self.pg2.remote_hosts[0].ip4,
1343 mac=self.pg2.remote_hosts[0].mac))
1346 # Add a static ARP entry with a changed mac
1348 static_arp.add_vpp_config()
1351 # We should now find the static nbr with a changed mac
1353 self.assertFalse(find_nbr(self,
1354 self.pg2.sw_if_index,
1355 self.pg2.remote_hosts[0].ip4,
1357 self.assertTrue(find_nbr(self,
1358 self.pg2.sw_if_index,
1359 self.pg2.remote_hosts[0].ip4,
1361 mac=self.pg2.remote_hosts[1].mac))
1366 static_arp.remove_vpp_config()
1368 def test_arp_incomplete(self):
1369 """ ARP Incomplete"""
1370 self.pg1.generate_remote_hosts(3)
1372 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1373 IP(src=self.pg0.remote_ip4,
1374 dst=self.pg1.remote_hosts[1].ip4) /
1375 UDP(sport=1234, dport=1234) /
1377 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1378 IP(src=self.pg0.remote_ip4,
1379 dst=self.pg1.remote_hosts[2].ip4) /
1380 UDP(sport=1234, dport=1234) /
1384 # a packet to an unresolved destination generates an ARP request
1386 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1387 self.verify_arp_req(rx[0],
1390 self.pg1._remote_hosts[1].ip4)
1393 # add a neighbour for remote host 1
1395 static_arp = VppNeighbor(self,
1396 self.pg1.sw_if_index,
1397 self.pg1.remote_hosts[1].mac,
1398 self.pg1.remote_hosts[1].ip4,
1400 static_arp.add_vpp_config()
1403 # change the interface's MAC
1405 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1406 "00:00:00:33:33:33")
1409 # now ARP requests come from the new source mac
1411 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1412 self.verify_arp_req(rx[0],
1413 "00:00:00:33:33:33",
1415 self.pg1._remote_hosts[2].ip4)
1418 # packets to the resolved host also have the new source mac
1420 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1421 self.verify_ip(rx[0],
1422 "00:00:00:33:33:33",
1423 self.pg1.remote_hosts[1].mac,
1424 self.pg0.remote_ip4,
1425 self.pg1.remote_hosts[1].ip4)
1428 # set the mac address on the interface that does not have a
1429 # configured subnet and thus no glean
1431 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1432 "00:00:00:33:33:33")
1434 def test_garp(self):
1438 # Generate some hosts on the LAN
1440 self.pg1.generate_remote_hosts(4)
1441 self.pg2.generate_remote_hosts(4)
1446 arp = VppNeighbor(self,
1447 self.pg1.sw_if_index,
1448 self.pg1.remote_hosts[1].mac,
1449 self.pg1.remote_hosts[1].ip4)
1450 arp.add_vpp_config()
1452 self.assertTrue(find_nbr(self,
1453 self.pg1.sw_if_index,
1454 self.pg1.remote_hosts[1].ip4,
1455 mac=self.pg1.remote_hosts[1].mac))
1458 # Send a GARP (request) to swap the host 1's address to that of host 2
1460 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1461 src=self.pg1.remote_hosts[2].mac) /
1463 hwdst=self.pg1.local_mac,
1464 hwsrc=self.pg1.remote_hosts[2].mac,
1465 pdst=self.pg1.remote_hosts[1].ip4,
1466 psrc=self.pg1.remote_hosts[1].ip4))
1468 self.pg1.add_stream(p1)
1469 self.pg_enable_capture(self.pg_interfaces)
1472 self.assertTrue(find_nbr(self,
1473 self.pg1.sw_if_index,
1474 self.pg1.remote_hosts[1].ip4,
1475 mac=self.pg1.remote_hosts[2].mac))
1478 # Send a GARP (reply) to swap the host 1's address to that of host 3
1480 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1481 src=self.pg1.remote_hosts[3].mac) /
1483 hwdst=self.pg1.local_mac,
1484 hwsrc=self.pg1.remote_hosts[3].mac,
1485 pdst=self.pg1.remote_hosts[1].ip4,
1486 psrc=self.pg1.remote_hosts[1].ip4))
1488 self.pg1.add_stream(p1)
1489 self.pg_enable_capture(self.pg_interfaces)
1492 self.assertTrue(find_nbr(self,
1493 self.pg1.sw_if_index,
1494 self.pg1.remote_hosts[1].ip4,
1495 mac=self.pg1.remote_hosts[3].mac))
1498 # GARPs (request nor replies) for host we don't know yet
1499 # don't result in new neighbour entries
1501 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1502 src=self.pg1.remote_hosts[3].mac) /
1504 hwdst=self.pg1.local_mac,
1505 hwsrc=self.pg1.remote_hosts[3].mac,
1506 pdst=self.pg1.remote_hosts[2].ip4,
1507 psrc=self.pg1.remote_hosts[2].ip4))
1509 self.pg1.add_stream(p1)
1510 self.pg_enable_capture(self.pg_interfaces)
1513 self.assertFalse(find_nbr(self,
1514 self.pg1.sw_if_index,
1515 self.pg1.remote_hosts[2].ip4))
1517 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1518 src=self.pg1.remote_hosts[3].mac) /
1520 hwdst=self.pg1.local_mac,
1521 hwsrc=self.pg1.remote_hosts[3].mac,
1522 pdst=self.pg1.remote_hosts[2].ip4,
1523 psrc=self.pg1.remote_hosts[2].ip4))
1525 self.pg1.add_stream(p1)
1526 self.pg_enable_capture(self.pg_interfaces)
1529 self.assertFalse(find_nbr(self,
1530 self.pg1.sw_if_index,
1531 self.pg1.remote_hosts[2].ip4))
1534 # IP address in different subnets are not learnt
1536 self.pg2.configure_ipv4_neighbors()
1538 for op in ["is-at", "who-has"]:
1539 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1540 src=self.pg2.remote_hosts[1].mac) /
1542 hwdst=self.pg2.local_mac,
1543 hwsrc=self.pg2.remote_hosts[1].mac,
1544 pdst=self.pg2.remote_hosts[1].ip4,
1545 psrc=self.pg2.remote_hosts[1].ip4)),
1546 (Ether(dst="ff:ff:ff:ff:ff:ff",
1547 src=self.pg2.remote_hosts[1].mac) /
1549 hwdst="ff:ff:ff:ff:ff:ff",
1550 hwsrc=self.pg2.remote_hosts[1].mac,
1551 pdst=self.pg2.remote_hosts[1].ip4,
1552 psrc=self.pg2.remote_hosts[1].ip4))]
1554 self.send_and_assert_no_replies(self.pg1, p1)
1555 self.assertFalse(find_nbr(self,
1556 self.pg1.sw_if_index,
1557 self.pg2.remote_hosts[1].ip4))
1559 # they are all dropped because the subnet's don't match
1560 self.assertEqual(4, self.statistics.get_err_counter(
1561 "/err/arp-reply/IP4 destination address not local to subnet"))
1563 def test_arp_incomplete2(self):
1564 """ Incomplete Entries """
1567 # ensure that we throttle the ARP and ND requests
1569 self.pg0.generate_remote_hosts(2)
1574 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1575 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1576 self.pg0.sw_if_index)])
1577 ip_10_0_0_1.add_vpp_config()
1579 p1 = (Ether(dst=self.pg1.local_mac,
1580 src=self.pg1.remote_mac) /
1581 IP(src=self.pg1.remote_ip4,
1583 UDP(sport=1234, dport=1234) /
1586 self.pg1.add_stream(p1 * 257)
1587 self.pg_enable_capture(self.pg_interfaces)
1589 rx = self.pg0._get_capture(1)
1592 # how many we get is going to be dependent on the time for packet
1593 # processing but it should be small
1595 self.assertLess(len(rx), 64)
1600 ip_10_1 = VppIpRoute(self, "10::1", 128,
1601 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1602 self.pg0.sw_if_index,
1603 proto=DpoProto.DPO_PROTO_IP6)])
1604 ip_10_1.add_vpp_config()
1606 p1 = (Ether(dst=self.pg1.local_mac,
1607 src=self.pg1.remote_mac) /
1608 IPv6(src=self.pg1.remote_ip6,
1610 UDP(sport=1234, dport=1234) /
1613 self.pg1.add_stream(p1 * 257)
1614 self.pg_enable_capture(self.pg_interfaces)
1616 rx = self.pg0._get_capture(1)
1619 # how many we get is going to be dependent on the time for packet
1620 # processing but it should be small
1622 self.assertLess(len(rx), 64)
1624 def test_arp_forus(self):
1625 """ ARP for for-us """
1628 # Test that VPP responds with ARP requests to addresses that
1629 # are connected and local routes.
1630 # Use one of the 'remote' addresses in the subnet as a local address
1631 # The intention of this route is that it then acts like a secondary
1632 # address added to an interface
1634 self.pg0.generate_remote_hosts(2)
1637 self, self.pg0.remote_hosts[1].ip4, 32,
1638 [VppRoutePath("0.0.0.0",
1639 self.pg0.sw_if_index,
1640 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1641 forus.add_vpp_config()
1643 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1644 src=self.pg0.remote_mac) /
1646 hwdst=self.pg0.local_mac,
1647 hwsrc=self.pg0.remote_mac,
1648 pdst=self.pg0.remote_hosts[1].ip4,
1649 psrc=self.pg0.remote_ip4))
1651 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1653 self.verify_arp_resp(rx[0],
1655 self.pg0.remote_mac,
1656 self.pg0.remote_hosts[1].ip4,
1657 self.pg0.remote_ip4)
1659 def test_arp_table_swap(self):
1661 # Generate some hosts on the LAN
1664 self.pg1.generate_remote_hosts(N_NBRS)
1666 for n in range(N_NBRS):
1667 # a route thru each neighbour
1668 VppIpRoute(self, "10.0.0.%d" % n, 32,
1669 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1670 self.pg1.sw_if_index)]).add_vpp_config()
1672 # resolve each neighbour
1673 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1674 ARP(op="is-at", hwdst=self.pg1.local_mac,
1675 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1676 psrc=self.pg1.remote_hosts[n].ip4))
1678 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1680 self.logger.info(self.vapi.cli("sh ip neighbors"))
1683 # swap the table pg1 is in
1685 table = VppIpTable(self, 100).add_vpp_config()
1687 self.pg1.unconfig_ip4()
1688 self.pg1.set_table_ip4(100)
1689 self.pg1.config_ip4()
1692 # all neighbours are cleared
1694 for n in range(N_NBRS):
1695 self.assertFalse(find_nbr(self,
1696 self.pg1.sw_if_index,
1697 self.pg1.remote_hosts[n].ip4))
1700 # packets to all neighbours generate ARP requests
1702 for n in range(N_NBRS):
1703 # a route thru each neighbour
1704 VppIpRoute(self, "10.0.0.%d" % n, 32,
1705 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1706 self.pg1.sw_if_index)],
1707 table_id=100).add_vpp_config()
1709 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1710 dst=self.pg1.local_mac) /
1711 IP(src=self.pg1.remote_hosts[n].ip4,
1712 dst="10.0.0.%d" % n) /
1714 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1716 self.verify_arp_req(rx,
1719 self.pg1.remote_hosts[n].ip4)
1721 self.pg1.unconfig_ip4()
1722 self.pg1.set_table_ip4(0)
1724 def test_glean_src_select(self):
1725 """ Multi Connecteds """
1728 # configure multiple connected subnets on an interface
1729 # and ensure that ARP requests for hosts on those subnets
1730 # pick up the correct source address
1732 conn1 = VppIpInterfaceAddress(self, self.pg1,
1733 "10.0.0.1", 24).add_vpp_config()
1734 conn2 = VppIpInterfaceAddress(self, self.pg1,
1735 "10.0.1.1", 24).add_vpp_config()
1737 p1 = (Ether(src=self.pg0.remote_mac,
1738 dst=self.pg0.local_mac) /
1739 IP(src=self.pg1.remote_ip4,
1743 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
1745 self.verify_arp_req(rx,
1750 p2 = (Ether(src=self.pg0.remote_mac,
1751 dst=self.pg0.local_mac) /
1752 IP(src=self.pg1.remote_ip4,
1756 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1758 self.verify_arp_req(rx,
1764 # add a local address in the same subnet
1765 # the source addresses are equivalent. VPP happens to
1766 # choose the last one that was added
1767 conn3 = VppIpInterfaceAddress(self, self.pg1,
1768 "10.0.1.2", 24).add_vpp_config()
1770 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1772 self.verify_arp_req(rx,
1780 conn3.remove_vpp_config()
1781 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1783 self.verify_arp_req(rx,
1789 # add back, this time remove the first one
1791 conn3 = VppIpInterfaceAddress(self, self.pg1,
1792 "10.0.1.2", 24).add_vpp_config()
1794 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1796 self.verify_arp_req(rx,
1801 conn1.remove_vpp_config()
1802 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1804 self.verify_arp_req(rx,
1810 conn3.remove_vpp_config()
1811 conn2.remove_vpp_config()
1814 class NeighborStatsTestCase(VppTestCase):
1815 """ ARP/ND Counters """
1818 def setUpClass(cls):
1819 super(NeighborStatsTestCase, cls).setUpClass()
1822 def tearDownClass(cls):
1823 super(NeighborStatsTestCase, cls).tearDownClass()
1826 super(NeighborStatsTestCase, self).setUp()
1828 self.create_pg_interfaces(range(2))
1830 # pg0 configured with ip4 and 6 addresses used for input
1831 # pg1 configured with ip4 and 6 addresses used for output
1832 # pg2 is unnumbered to pg0
1833 for i in self.pg_interfaces:
1841 super(NeighborStatsTestCase, self).tearDown()
1843 for i in self.pg_interfaces:
1848 def test_arp_stats(self):
1849 """ ARP Counters """
1851 self.vapi.cli("adj counters enable")
1852 self.pg1.generate_remote_hosts(2)
1854 arp1 = VppNeighbor(self,
1855 self.pg1.sw_if_index,
1856 self.pg1.remote_hosts[0].mac,
1857 self.pg1.remote_hosts[0].ip4)
1858 arp1.add_vpp_config()
1859 arp2 = VppNeighbor(self,
1860 self.pg1.sw_if_index,
1861 self.pg1.remote_hosts[1].mac,
1862 self.pg1.remote_hosts[1].ip4)
1863 arp2.add_vpp_config()
1865 p1 = (Ether(dst=self.pg0.local_mac,
1866 src=self.pg0.remote_mac) /
1867 IP(src=self.pg0.remote_ip4,
1868 dst=self.pg1.remote_hosts[0].ip4) /
1869 UDP(sport=1234, dport=1234) /
1871 p2 = (Ether(dst=self.pg0.local_mac,
1872 src=self.pg0.remote_mac) /
1873 IP(src=self.pg0.remote_ip4,
1874 dst=self.pg1.remote_hosts[1].ip4) /
1875 UDP(sport=1234, dport=1234) /
1878 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1879 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1881 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1882 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1884 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1885 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1887 def test_nd_stats(self):
1890 self.vapi.cli("adj counters enable")
1891 self.pg0.generate_remote_hosts(3)
1893 nd1 = VppNeighbor(self,
1894 self.pg0.sw_if_index,
1895 self.pg0.remote_hosts[1].mac,
1896 self.pg0.remote_hosts[1].ip6)
1897 nd1.add_vpp_config()
1898 nd2 = VppNeighbor(self,
1899 self.pg0.sw_if_index,
1900 self.pg0.remote_hosts[2].mac,
1901 self.pg0.remote_hosts[2].ip6)
1902 nd2.add_vpp_config()
1904 p1 = (Ether(dst=self.pg1.local_mac,
1905 src=self.pg1.remote_mac) /
1906 IPv6(src=self.pg1.remote_ip6,
1907 dst=self.pg0.remote_hosts[1].ip6) /
1908 UDP(sport=1234, dport=1234) /
1910 p2 = (Ether(dst=self.pg1.local_mac,
1911 src=self.pg1.remote_mac) /
1912 IPv6(src=self.pg1.remote_ip6,
1913 dst=self.pg0.remote_hosts[2].ip6) /
1914 UDP(sport=1234, dport=1234) /
1917 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1918 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1920 self.assertEqual(16, nd1.get_stats()['packets'])
1921 self.assertEqual(16, nd2.get_stats()['packets'])
1923 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1924 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1927 class NeighborAgeTestCase(VppTestCase):
1928 """ ARP/ND Aging """
1931 def setUpClass(cls):
1932 super(NeighborAgeTestCase, cls).setUpClass()
1935 def tearDownClass(cls):
1936 super(NeighborAgeTestCase, cls).tearDownClass()
1939 super(NeighborAgeTestCase, self).setUp()
1941 self.create_pg_interfaces(range(1))
1943 # pg0 configured with ip4 and 6 addresses used for input
1944 # pg1 configured with ip4 and 6 addresses used for output
1945 # pg2 is unnumbered to pg0
1946 for i in self.pg_interfaces:
1954 super(NeighborAgeTestCase, self).tearDown()
1956 for i in self.pg_interfaces:
1961 def wait_for_no_nbr(self, intf, address,
1962 n_tries=50, s_time=1):
1964 if not find_nbr(self, intf, address):
1966 n_tries = n_tries - 1
1971 def verify_arp_req(self, rx, smac, sip, dip):
1973 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1974 self.assertEqual(ether.src, smac)
1977 self.assertEqual(arp.hwtype, 1)
1978 self.assertEqual(arp.ptype, 0x800)
1979 self.assertEqual(arp.hwlen, 6)
1980 self.assertEqual(arp.plen, 4)
1981 self.assertEqual(arp.op, arp_opts["who-has"])
1982 self.assertEqual(arp.hwsrc, smac)
1983 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1984 self.assertEqual(arp.psrc, sip)
1985 self.assertEqual(arp.pdst, dip)
1988 """ Aging/Recycle """
1990 self.vapi.cli("set logging unthrottle 0")
1991 self.vapi.cli("set logging size %d" % 0xffff)
1993 self.pg0.generate_remote_hosts(201)
1995 vaf = VppEnum.vl_api_address_family_t
1998 # start listening on all interfaces
2000 self.pg_enable_capture(self.pg_interfaces)
2003 # Set the neighbor configuration:
2008 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2013 self.vapi.cli("sh ip neighbor-config")
2015 # add the 198 neighbours that should pass (-1 for one created in setup)
2016 for ii in range(200):
2018 self.pg0.sw_if_index,
2019 self.pg0.remote_hosts[ii].mac,
2020 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2022 # one more neighbor over the limit should fail
2023 with self.vapi.assert_negative_api_retval():
2025 self.pg0.sw_if_index,
2026 self.pg0.remote_hosts[200].mac,
2027 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2030 # change the config to allow recycling the old neighbors
2032 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2037 # now new additions are allowed
2039 self.pg0.sw_if_index,
2040 self.pg0.remote_hosts[200].mac,
2041 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2043 # add the first neighbor we configured has been re-used
2044 self.assertFalse(find_nbr(self,
2045 self.pg0.sw_if_index,
2046 self.pg0.remote_hosts[0].ip4))
2047 self.assertTrue(find_nbr(self,
2048 self.pg0.sw_if_index,
2049 self.pg0.remote_hosts[200].ip4))
2052 # change the config to age old neighbors
2054 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2059 self.vapi.cli("sh ip4 neighbor-sorted")
2062 # expect probes from all these ARP entries as they age
2063 # 3 probes for each neighbor 3*200 = 600
2064 rxs = self.pg0.get_capture(600, timeout=8)
2067 for jj in range(200):
2068 rx = rxs[ii*200 + jj]
2072 # 3 probes sent then 1 more second to see if a reply comes, before
2075 for jj in range(1, 201):
2076 self.wait_for_no_nbr(self.pg0.sw_if_index,
2077 self.pg0.remote_hosts[jj].ip4)
2079 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2080 af=vaf.ADDRESS_IP4))
2083 # load up some neighbours again with 2s aging enabled
2084 # they should be removed after 10s (2s age + 4s for probes + gap)
2085 # check for the add and remove events
2087 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2089 self.vapi.want_ip_neighbor_events_v2(enable=1)
2090 for ii in range(10):
2092 self.pg0.sw_if_index,
2093 self.pg0.remote_hosts[ii].mac,
2094 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2096 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2097 self.assertEqual(e.flags,
2098 enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2099 self.assertEqual(str(e.neighbor.ip_address),
2100 self.pg0.remote_hosts[ii].ip4)
2101 self.assertEqual(e.neighbor.mac_address,
2102 self.pg0.remote_hosts[ii].mac)
2105 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2106 af=vaf.ADDRESS_IP4))
2109 for ii in range(10):
2110 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2111 self.assertEqual(e.flags,
2112 enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2115 # check we got the correct mac/ip pairs - done separately
2116 # because we don't care about the order the remove notifications
2118 for ii in range(10):
2120 mac = self.pg0.remote_hosts[ii].mac
2121 ip = self.pg0.remote_hosts[ii].ip4
2124 if (e.neighbor.mac_address == mac and
2125 str(e.neighbor.ip_address) == ip):
2128 self.assertTrue(found)
2131 # check if we can set age and recycle with empty neighbor list
2133 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2139 # load up some neighbours again, then disable the aging
2140 # they should still be there in 10 seconds time
2142 for ii in range(10):
2144 self.pg0.sw_if_index,
2145 self.pg0.remote_hosts[ii].mac,
2146 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2147 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2153 self.assertTrue(find_nbr(self,
2154 self.pg0.sw_if_index,
2155 self.pg0.remote_hosts[0].ip4))
2158 class NeighborReplaceTestCase(VppTestCase):
2159 """ ARP/ND Replacement """
2162 def setUpClass(cls):
2163 super(NeighborReplaceTestCase, cls).setUpClass()
2166 def tearDownClass(cls):
2167 super(NeighborReplaceTestCase, cls).tearDownClass()
2170 super(NeighborReplaceTestCase, self).setUp()
2172 self.create_pg_interfaces(range(4))
2174 # pg0 configured with ip4 and 6 addresses used for input
2175 # pg1 configured with ip4 and 6 addresses used for output
2176 # pg2 is unnumbered to pg0
2177 for i in self.pg_interfaces:
2185 super(NeighborReplaceTestCase, self).tearDown()
2187 for i in self.pg_interfaces:
2192 def test_replace(self):
2197 for i in self.pg_interfaces:
2198 i.generate_remote_hosts(N_HOSTS)
2199 i.configure_ipv4_neighbors()
2200 i.configure_ipv6_neighbors()
2203 self.vapi.ip_neighbor_replace_begin()
2204 self.vapi.ip_neighbor_replace_end()
2206 for i in self.pg_interfaces:
2207 for h in range(N_HOSTS):
2208 self.assertFalse(find_nbr(self,
2209 self.pg0.sw_if_index,
2210 self.pg0.remote_hosts[h].ip4))
2211 self.assertFalse(find_nbr(self,
2212 self.pg0.sw_if_index,
2213 self.pg0.remote_hosts[h].ip6))
2216 # and them all back via the API
2218 for i in self.pg_interfaces:
2219 for h in range(N_HOSTS):
2222 i.remote_hosts[h].mac,
2223 i.remote_hosts[h].ip4).add_vpp_config()
2226 i.remote_hosts[h].mac,
2227 i.remote_hosts[h].ip6).add_vpp_config()
2230 # begin the replacement again, this time touch some
2231 # the neighbours on pg1 so they are not deleted
2233 self.vapi.ip_neighbor_replace_begin()
2235 # update from the API all neighbours on pg1
2236 for h in range(N_HOSTS):
2238 self.pg1.sw_if_index,
2239 self.pg1.remote_hosts[h].mac,
2240 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2242 self.pg1.sw_if_index,
2243 self.pg1.remote_hosts[h].mac,
2244 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2246 # update from the data-plane all neighbours on pg3
2247 self.pg3.configure_ipv4_neighbors()
2248 self.pg3.configure_ipv6_neighbors()
2250 # complete the replacement
2251 self.logger.info(self.vapi.cli("sh ip neighbors"))
2252 self.vapi.ip_neighbor_replace_end()
2254 for i in self.pg_interfaces:
2255 if i == self.pg1 or i == self.pg3:
2256 # neighbours on pg1 and pg3 are still present
2257 for h in range(N_HOSTS):
2258 self.assertTrue(find_nbr(self,
2260 i.remote_hosts[h].ip4))
2261 self.assertTrue(find_nbr(self,
2263 i.remote_hosts[h].ip6))
2265 # all other neighbours are toast
2266 for h in range(N_HOSTS):
2267 self.assertFalse(find_nbr(self,
2269 i.remote_hosts[h].ip4))
2270 self.assertFalse(find_nbr(self,
2272 i.remote_hosts[h].ip6))
2275 class NeighborFlush(VppTestCase):
2276 """ Neighbor Flush """
2279 def setUpClass(cls):
2280 super(NeighborFlush, cls).setUpClass()
2283 def tearDownClass(cls):
2284 super(NeighborFlush, cls).tearDownClass()
2287 super(NeighborFlush, self).setUp()
2289 self.create_pg_interfaces(range(2))
2291 for i in self.pg_interfaces:
2299 super(NeighborFlush, self).tearDown()
2301 for i in self.pg_interfaces:
2306 def test_flush(self):
2307 """ Neighbour Flush """
2310 nf = e.vl_api_ip_neighbor_flags_t
2311 af = e.vl_api_address_family_t
2313 static = [False, True]
2314 self.pg0.generate_remote_hosts(N_HOSTS)
2315 self.pg1.generate_remote_hosts(N_HOSTS)
2318 # a few v4 and v6 dynamic neoghbors
2319 for n in range(N_HOSTS):
2321 self.pg0.sw_if_index,
2322 self.pg0.remote_hosts[n].mac,
2323 self.pg0.remote_hosts[n].ip4,
2324 is_static=s).add_vpp_config()
2326 self.pg1.sw_if_index,
2327 self.pg1.remote_hosts[n].mac,
2328 self.pg1.remote_hosts[n].ip6,
2329 is_static=s).add_vpp_config()
2331 # flush the interfaces individually
2332 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2334 # check we haven't flushed that which we shouldn't
2335 for n in range(N_HOSTS):
2336 self.assertTrue(find_nbr(self,
2337 self.pg1.sw_if_index,
2338 self.pg1.remote_hosts[n].ip6,
2341 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2343 for n in range(N_HOSTS):
2344 self.assertFalse(find_nbr(self,
2345 self.pg0.sw_if_index,
2346 self.pg0.remote_hosts[n].ip4))
2347 self.assertFalse(find_nbr(self,
2348 self.pg1.sw_if_index,
2349 self.pg1.remote_hosts[n].ip6))
2351 # add the nieghbours back
2352 for n in range(N_HOSTS):
2354 self.pg0.sw_if_index,
2355 self.pg0.remote_hosts[n].mac,
2356 self.pg0.remote_hosts[n].ip4,
2357 is_static=s).add_vpp_config()
2359 self.pg1.sw_if_index,
2360 self.pg1.remote_hosts[n].mac,
2361 self.pg1.remote_hosts[n].ip6,
2362 is_static=s).add_vpp_config()
2364 self.logger.info(self.vapi.cli("sh ip neighbor"))
2366 # flush both interfaces at the same time
2367 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2369 # check we haven't flushed that which we shouldn't
2370 for n in range(N_HOSTS):
2371 self.assertTrue(find_nbr(self,
2372 self.pg0.sw_if_index,
2373 self.pg0.remote_hosts[n].ip4,
2376 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2378 for n in range(N_HOSTS):
2379 self.assertFalse(find_nbr(self,
2380 self.pg0.sw_if_index,
2381 self.pg0.remote_hosts[n].ip4))
2382 self.assertFalse(find_nbr(self,
2383 self.pg1.sw_if_index,
2384 self.pg1.remote_hosts[n].ip6))
2387 if __name__ == '__main__':
2388 unittest.main(testRunner=VppTestRunner)