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
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)
1725 class NeighborStatsTestCase(VppTestCase):
1726 """ ARP/ND Counters """
1729 def setUpClass(cls):
1730 super(NeighborStatsTestCase, cls).setUpClass()
1733 def tearDownClass(cls):
1734 super(NeighborStatsTestCase, cls).tearDownClass()
1737 super(NeighborStatsTestCase, self).setUp()
1739 self.create_pg_interfaces(range(2))
1741 # pg0 configured with ip4 and 6 addresses used for input
1742 # pg1 configured with ip4 and 6 addresses used for output
1743 # pg2 is unnumbered to pg0
1744 for i in self.pg_interfaces:
1752 super(NeighborStatsTestCase, self).tearDown()
1754 for i in self.pg_interfaces:
1759 def test_arp_stats(self):
1760 """ ARP Counters """
1762 self.vapi.cli("adj counters enable")
1763 self.pg1.generate_remote_hosts(2)
1765 arp1 = VppNeighbor(self,
1766 self.pg1.sw_if_index,
1767 self.pg1.remote_hosts[0].mac,
1768 self.pg1.remote_hosts[0].ip4)
1769 arp1.add_vpp_config()
1770 arp2 = VppNeighbor(self,
1771 self.pg1.sw_if_index,
1772 self.pg1.remote_hosts[1].mac,
1773 self.pg1.remote_hosts[1].ip4)
1774 arp2.add_vpp_config()
1776 p1 = (Ether(dst=self.pg0.local_mac,
1777 src=self.pg0.remote_mac) /
1778 IP(src=self.pg0.remote_ip4,
1779 dst=self.pg1.remote_hosts[0].ip4) /
1780 UDP(sport=1234, dport=1234) /
1782 p2 = (Ether(dst=self.pg0.local_mac,
1783 src=self.pg0.remote_mac) /
1784 IP(src=self.pg0.remote_ip4,
1785 dst=self.pg1.remote_hosts[1].ip4) /
1786 UDP(sport=1234, dport=1234) /
1789 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1790 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1792 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1793 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1795 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1796 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1798 def test_nd_stats(self):
1801 self.vapi.cli("adj counters enable")
1802 self.pg0.generate_remote_hosts(3)
1804 nd1 = VppNeighbor(self,
1805 self.pg0.sw_if_index,
1806 self.pg0.remote_hosts[1].mac,
1807 self.pg0.remote_hosts[1].ip6)
1808 nd1.add_vpp_config()
1809 nd2 = VppNeighbor(self,
1810 self.pg0.sw_if_index,
1811 self.pg0.remote_hosts[2].mac,
1812 self.pg0.remote_hosts[2].ip6)
1813 nd2.add_vpp_config()
1815 p1 = (Ether(dst=self.pg1.local_mac,
1816 src=self.pg1.remote_mac) /
1817 IPv6(src=self.pg1.remote_ip6,
1818 dst=self.pg0.remote_hosts[1].ip6) /
1819 UDP(sport=1234, dport=1234) /
1821 p2 = (Ether(dst=self.pg1.local_mac,
1822 src=self.pg1.remote_mac) /
1823 IPv6(src=self.pg1.remote_ip6,
1824 dst=self.pg0.remote_hosts[2].ip6) /
1825 UDP(sport=1234, dport=1234) /
1828 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1829 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1831 self.assertEqual(16, nd1.get_stats()['packets'])
1832 self.assertEqual(16, nd2.get_stats()['packets'])
1834 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1835 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1838 class NeighborAgeTestCase(VppTestCase):
1839 """ ARP/ND Aging """
1842 def setUpClass(cls):
1843 super(NeighborAgeTestCase, cls).setUpClass()
1846 def tearDownClass(cls):
1847 super(NeighborAgeTestCase, cls).tearDownClass()
1850 super(NeighborAgeTestCase, self).setUp()
1852 self.create_pg_interfaces(range(1))
1854 # pg0 configured with ip4 and 6 addresses used for input
1855 # pg1 configured with ip4 and 6 addresses used for output
1856 # pg2 is unnumbered to pg0
1857 for i in self.pg_interfaces:
1865 super(NeighborAgeTestCase, self).tearDown()
1867 for i in self.pg_interfaces:
1872 def wait_for_no_nbr(self, intf, address,
1873 n_tries=50, s_time=1):
1875 if not find_nbr(self, intf, address):
1877 n_tries = n_tries - 1
1882 def verify_arp_req(self, rx, smac, sip, dip):
1884 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1885 self.assertEqual(ether.src, smac)
1888 self.assertEqual(arp.hwtype, 1)
1889 self.assertEqual(arp.ptype, 0x800)
1890 self.assertEqual(arp.hwlen, 6)
1891 self.assertEqual(arp.plen, 4)
1892 self.assertEqual(arp.op, arp_opts["who-has"])
1893 self.assertEqual(arp.hwsrc, smac)
1894 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1895 self.assertEqual(arp.psrc, sip)
1896 self.assertEqual(arp.pdst, dip)
1899 """ Aging/Recycle """
1901 self.vapi.cli("set logging unthrottle 0")
1902 self.vapi.cli("set logging size %d" % 0xffff)
1904 self.pg0.generate_remote_hosts(201)
1906 vaf = VppEnum.vl_api_address_family_t
1909 # start listening on all interfaces
1911 self.pg_enable_capture(self.pg_interfaces)
1914 # Set the neighbor configuration:
1919 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1924 self.vapi.cli("sh ip neighbor-config")
1926 # add the 198 neighbours that should pass (-1 for one created in setup)
1927 for ii in range(200):
1929 self.pg0.sw_if_index,
1930 self.pg0.remote_hosts[ii].mac,
1931 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1933 # one more neighbor over the limit should fail
1934 with self.vapi.assert_negative_api_retval():
1936 self.pg0.sw_if_index,
1937 self.pg0.remote_hosts[200].mac,
1938 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1941 # change the config to allow recycling the old neighbors
1943 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1948 # now new additions are allowed
1950 self.pg0.sw_if_index,
1951 self.pg0.remote_hosts[200].mac,
1952 self.pg0.remote_hosts[200].ip4).add_vpp_config()
1954 # add the first neighbor we configured has been re-used
1955 self.assertFalse(find_nbr(self,
1956 self.pg0.sw_if_index,
1957 self.pg0.remote_hosts[0].ip4))
1958 self.assertTrue(find_nbr(self,
1959 self.pg0.sw_if_index,
1960 self.pg0.remote_hosts[200].ip4))
1963 # change the config to age old neighbors
1965 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1970 self.vapi.cli("sh ip4 neighbor-sorted")
1973 # expect probes from all these ARP entries as they age
1974 # 3 probes for each neighbor 3*200 = 600
1975 rxs = self.pg0.get_capture(600, timeout=8)
1978 for jj in range(200):
1979 rx = rxs[ii*200 + jj]
1983 # 3 probes sent then 1 more second to see if a reply comes, before
1986 for jj in range(1, 201):
1987 self.wait_for_no_nbr(self.pg0.sw_if_index,
1988 self.pg0.remote_hosts[jj].ip4)
1990 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1991 af=vaf.ADDRESS_IP4))
1994 # load up some neighbours again with 2s aging enabled
1995 # they should be removed after 10s (2s age + 4s for probes + gap)
1996 # check for the add and remove events
1998 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2000 self.vapi.want_ip_neighbor_events_v2(enable=1)
2001 for ii in range(10):
2003 self.pg0.sw_if_index,
2004 self.pg0.remote_hosts[ii].mac,
2005 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2007 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2008 self.assertEqual(e.flags,
2009 enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2010 self.assertEqual(str(e.neighbor.ip_address),
2011 self.pg0.remote_hosts[ii].ip4)
2012 self.assertEqual(e.neighbor.mac_address,
2013 self.pg0.remote_hosts[ii].mac)
2016 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2017 af=vaf.ADDRESS_IP4))
2020 for ii in range(10):
2021 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2022 self.assertEqual(e.flags,
2023 enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2026 # check we got the correct mac/ip pairs - done separately
2027 # because we don't care about the order the remove notifications
2029 for ii in range(10):
2031 mac = self.pg0.remote_hosts[ii].mac
2032 ip = self.pg0.remote_hosts[ii].ip4
2035 if (e.neighbor.mac_address == mac and
2036 str(e.neighbor.ip_address) == ip):
2039 self.assertTrue(found)
2042 # check if we can set age and recycle with empty neighbor list
2044 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2050 # load up some neighbours again, then disable the aging
2051 # they should still be there in 10 seconds time
2053 for ii in range(10):
2055 self.pg0.sw_if_index,
2056 self.pg0.remote_hosts[ii].mac,
2057 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2058 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2064 self.assertTrue(find_nbr(self,
2065 self.pg0.sw_if_index,
2066 self.pg0.remote_hosts[0].ip4))
2069 class NeighborReplaceTestCase(VppTestCase):
2070 """ ARP/ND Replacement """
2073 def setUpClass(cls):
2074 super(NeighborReplaceTestCase, cls).setUpClass()
2077 def tearDownClass(cls):
2078 super(NeighborReplaceTestCase, cls).tearDownClass()
2081 super(NeighborReplaceTestCase, self).setUp()
2083 self.create_pg_interfaces(range(4))
2085 # pg0 configured with ip4 and 6 addresses used for input
2086 # pg1 configured with ip4 and 6 addresses used for output
2087 # pg2 is unnumbered to pg0
2088 for i in self.pg_interfaces:
2096 super(NeighborReplaceTestCase, self).tearDown()
2098 for i in self.pg_interfaces:
2103 def test_replace(self):
2108 for i in self.pg_interfaces:
2109 i.generate_remote_hosts(N_HOSTS)
2110 i.configure_ipv4_neighbors()
2111 i.configure_ipv6_neighbors()
2114 self.vapi.ip_neighbor_replace_begin()
2115 self.vapi.ip_neighbor_replace_end()
2117 for i in self.pg_interfaces:
2118 for h in range(N_HOSTS):
2119 self.assertFalse(find_nbr(self,
2120 self.pg0.sw_if_index,
2121 self.pg0.remote_hosts[h].ip4))
2122 self.assertFalse(find_nbr(self,
2123 self.pg0.sw_if_index,
2124 self.pg0.remote_hosts[h].ip6))
2127 # and them all back via the API
2129 for i in self.pg_interfaces:
2130 for h in range(N_HOSTS):
2133 i.remote_hosts[h].mac,
2134 i.remote_hosts[h].ip4).add_vpp_config()
2137 i.remote_hosts[h].mac,
2138 i.remote_hosts[h].ip6).add_vpp_config()
2141 # begin the replacement again, this time touch some
2142 # the neighbours on pg1 so they are not deleted
2144 self.vapi.ip_neighbor_replace_begin()
2146 # update from the API all neighbours on pg1
2147 for h in range(N_HOSTS):
2149 self.pg1.sw_if_index,
2150 self.pg1.remote_hosts[h].mac,
2151 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2153 self.pg1.sw_if_index,
2154 self.pg1.remote_hosts[h].mac,
2155 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2157 # update from the data-plane all neighbours on pg3
2158 self.pg3.configure_ipv4_neighbors()
2159 self.pg3.configure_ipv6_neighbors()
2161 # complete the replacement
2162 self.logger.info(self.vapi.cli("sh ip neighbors"))
2163 self.vapi.ip_neighbor_replace_end()
2165 for i in self.pg_interfaces:
2166 if i == self.pg1 or i == self.pg3:
2167 # neighbours on pg1 and pg3 are still present
2168 for h in range(N_HOSTS):
2169 self.assertTrue(find_nbr(self,
2171 i.remote_hosts[h].ip4))
2172 self.assertTrue(find_nbr(self,
2174 i.remote_hosts[h].ip6))
2176 # all other neighbours are toast
2177 for h in range(N_HOSTS):
2178 self.assertFalse(find_nbr(self,
2180 i.remote_hosts[h].ip4))
2181 self.assertFalse(find_nbr(self,
2183 i.remote_hosts[h].ip6))
2186 class NeighborFlush(VppTestCase):
2187 """ Neighbor Flush """
2190 def setUpClass(cls):
2191 super(NeighborFlush, cls).setUpClass()
2194 def tearDownClass(cls):
2195 super(NeighborFlush, cls).tearDownClass()
2198 super(NeighborFlush, self).setUp()
2200 self.create_pg_interfaces(range(2))
2202 for i in self.pg_interfaces:
2210 super(NeighborFlush, self).tearDown()
2212 for i in self.pg_interfaces:
2217 def test_flush(self):
2218 """ Neighbour Flush """
2221 nf = e.vl_api_ip_neighbor_flags_t
2222 af = e.vl_api_address_family_t
2224 static = [False, True]
2225 self.pg0.generate_remote_hosts(N_HOSTS)
2226 self.pg1.generate_remote_hosts(N_HOSTS)
2229 # a few v4 and v6 dynamic neoghbors
2230 for n in range(N_HOSTS):
2232 self.pg0.sw_if_index,
2233 self.pg0.remote_hosts[n].mac,
2234 self.pg0.remote_hosts[n].ip4,
2235 is_static=s).add_vpp_config()
2237 self.pg1.sw_if_index,
2238 self.pg1.remote_hosts[n].mac,
2239 self.pg1.remote_hosts[n].ip6,
2240 is_static=s).add_vpp_config()
2242 # flush the interfaces individually
2243 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2245 # check we haven't flushed that which we shouldn't
2246 for n in range(N_HOSTS):
2247 self.assertTrue(find_nbr(self,
2248 self.pg1.sw_if_index,
2249 self.pg1.remote_hosts[n].ip6,
2252 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2254 for n in range(N_HOSTS):
2255 self.assertFalse(find_nbr(self,
2256 self.pg0.sw_if_index,
2257 self.pg0.remote_hosts[n].ip4))
2258 self.assertFalse(find_nbr(self,
2259 self.pg1.sw_if_index,
2260 self.pg1.remote_hosts[n].ip6))
2262 # add the nieghbours back
2263 for n in range(N_HOSTS):
2265 self.pg0.sw_if_index,
2266 self.pg0.remote_hosts[n].mac,
2267 self.pg0.remote_hosts[n].ip4,
2268 is_static=s).add_vpp_config()
2270 self.pg1.sw_if_index,
2271 self.pg1.remote_hosts[n].mac,
2272 self.pg1.remote_hosts[n].ip6,
2273 is_static=s).add_vpp_config()
2275 self.logger.info(self.vapi.cli("sh ip neighbor"))
2277 # flush both interfaces at the same time
2278 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2280 # check we haven't flushed that which we shouldn't
2281 for n in range(N_HOSTS):
2282 self.assertTrue(find_nbr(self,
2283 self.pg0.sw_if_index,
2284 self.pg0.remote_hosts[n].ip4,
2287 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2289 for n in range(N_HOSTS):
2290 self.assertFalse(find_nbr(self,
2291 self.pg0.sw_if_index,
2292 self.pg0.remote_hosts[n].ip4))
2293 self.assertFalse(find_nbr(self,
2294 self.pg1.sw_if_index,
2295 self.pg1.remote_hosts[n].ip6))
2298 if __name__ == '__main__':
2299 unittest.main(testRunner=VppTestRunner)