5 from socket import AF_INET, AF_INET6, inet_pton
7 from framework import tag_fixme_vpp_workers
8 from framework import VppTestCase, VppTestRunner
9 from vpp_neighbor import VppNeighbor, find_nbr
10 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
11 VppIpTable, DpoProto, FibPathType, VppIpInterfaceAddress
12 from vpp_papi import VppEnum
13 from vpp_ip import VppIpPuntRedirect
16 from scapy.packet import Raw
17 from scapy.layers.l2 import Ether, ARP, Dot1Q
18 from scapy.layers.inet import IP, UDP, TCP
19 from scapy.layers.inet6 import IPv6
20 from scapy.contrib.mpls import MPLS
21 from scapy.layers.inet6 import IPv6
26 # not exported by scapy, so redefined here
27 arp_opts = {"who-has": 1, "is-at": 2}
30 class ARPTestCase(VppTestCase):
35 super(ARPTestCase, cls).setUpClass()
38 def tearDownClass(cls):
39 super(ARPTestCase, cls).tearDownClass()
42 super(ARPTestCase, self).setUp()
44 # create 3 pg interfaces
45 self.create_pg_interfaces(range(4))
47 # pg0 configured with ip4 and 6 addresses used for input
48 # pg1 configured with ip4 and 6 addresses used for output
49 # pg2 is unnumbered to pg0
50 for i in self.pg_interfaces:
55 self.pg0.resolve_arp()
60 # pg3 in a different VRF
61 self.tbl = VppIpTable(self, 1)
62 self.tbl.add_vpp_config()
64 self.pg3.set_table_ip4(1)
68 self.pg0.unconfig_ip4()
69 self.pg0.unconfig_ip6()
71 self.pg1.unconfig_ip4()
72 self.pg1.unconfig_ip6()
74 self.pg3.unconfig_ip4()
75 self.pg3.set_table_ip4(0)
77 for i in self.pg_interfaces:
80 super(ARPTestCase, self).tearDown()
82 def verify_arp_req(self, rx, smac, sip, dip):
84 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
85 self.assertEqual(ether.src, smac)
86 self.assertEqual(ether.type, 0x0806)
89 self.assertEqual(arp.hwtype, 1)
90 self.assertEqual(arp.ptype, 0x800)
91 self.assertEqual(arp.hwlen, 6)
92 self.assertEqual(arp.plen, 4)
93 self.assertEqual(arp.op, arp_opts["who-has"])
94 self.assertEqual(arp.hwsrc, smac)
95 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
96 self.assertEqual(arp.psrc, sip)
97 self.assertEqual(arp.pdst, dip)
99 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
101 self.assertEqual(ether.dst, dmac)
102 self.assertEqual(ether.src, smac)
103 self.assertEqual(ether.type, 0x0806)
106 self.assertEqual(arp.hwtype, 1)
107 self.assertEqual(arp.ptype, 0x800)
108 self.assertEqual(arp.hwlen, 6)
109 self.assertEqual(arp.plen, 4)
110 self.assertEqual(arp.op, arp_opts["is-at"])
111 self.assertEqual(arp.hwsrc, smac)
112 self.assertEqual(arp.hwdst, dmac)
113 self.assertEqual(arp.psrc, sip)
114 self.assertEqual(arp.pdst, dip)
116 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
118 self.assertEqual(ether.dst, dmac)
119 self.assertEqual(ether.src, smac)
122 self.assertEqual(arp.hwtype, 1)
123 self.assertEqual(arp.ptype, 0x800)
124 self.assertEqual(arp.hwlen, 6)
125 self.assertEqual(arp.plen, 4)
126 self.assertEqual(arp.op, arp_opts["is-at"])
127 self.assertNotEqual(arp.hwsrc, smac)
128 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
129 "00:00:5E:00:01" in arp.hwsrc)
130 self.assertEqual(arp.hwdst, dmac)
131 self.assertEqual(arp.psrc, sip)
132 self.assertEqual(arp.pdst, dip)
134 def verify_ip(self, rx, smac, dmac, sip, dip):
136 self.assertEqual(ether.dst, dmac)
137 self.assertEqual(ether.src, smac)
138 self.assertEqual(ether.type, 0x0800)
141 self.assertEqual(ip.src, sip)
142 self.assertEqual(ip.dst, dip)
144 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
146 self.assertEqual(ether.dst, dmac)
147 self.assertEqual(ether.src, smac)
148 self.assertEqual(ether.type, 0x8847)
151 self.assertTrue(mpls.label, label)
154 self.assertEqual(ip.src, sip)
155 self.assertEqual(ip.dst, dip)
161 # Generate some hosts on the LAN
163 self.pg1.generate_remote_hosts(11)
167 # - all neighbour events
168 # - all neighbor events on pg1
169 # - neighbor events for host[1] on pg1
171 self.vapi.want_ip_neighbor_events(enable=1,
173 self.vapi.want_ip_neighbor_events(enable=1,
175 sw_if_index=self.pg1.sw_if_index)
176 self.vapi.want_ip_neighbor_events(enable=1,
178 sw_if_index=self.pg1.sw_if_index,
179 ip=self.pg1.remote_hosts[1].ip4)
181 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
184 # Send IP traffic to one of these unresolved hosts.
185 # expect the generation of an ARP request
187 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
188 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
189 UDP(sport=1234, dport=1234) /
192 self.pg0.add_stream(p)
193 self.pg_enable_capture(self.pg_interfaces)
196 rx = self.pg1.get_capture(1)
198 self.verify_arp_req(rx[0],
201 self.pg1._remote_hosts[1].ip4)
204 # And a dynamic ARP entry for host 1
206 dyn_arp = VppNeighbor(self,
207 self.pg1.sw_if_index,
208 self.pg1.remote_hosts[1].mac,
209 self.pg1.remote_hosts[1].ip4)
210 dyn_arp.add_vpp_config()
211 self.assertTrue(dyn_arp.query_vpp_config())
213 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
215 # this matches all of the listnerers
216 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
219 self.assertEqual(str(e.neighbor.ip_address),
220 self.pg1.remote_hosts[1].ip4)
223 # now we expect IP traffic forwarded
225 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
226 IP(src=self.pg0.remote_ip4,
227 dst=self.pg1._remote_hosts[1].ip4) /
228 UDP(sport=1234, dport=1234) /
231 self.pg0.add_stream(dyn_p)
232 self.pg_enable_capture(self.pg_interfaces)
235 rx = self.pg1.get_capture(1)
237 self.verify_ip(rx[0],
239 self.pg1.remote_hosts[1].mac,
241 self.pg1._remote_hosts[1].ip4)
244 # And a Static ARP entry for host 2
246 static_arp = VppNeighbor(self,
247 self.pg1.sw_if_index,
248 self.pg1.remote_hosts[2].mac,
249 self.pg1.remote_hosts[2].ip4,
251 static_arp.add_vpp_config()
252 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
255 self.assertEqual(str(e.neighbor.ip_address),
256 self.pg1.remote_hosts[2].ip4)
258 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
259 IP(src=self.pg0.remote_ip4,
260 dst=self.pg1._remote_hosts[2].ip4) /
261 UDP(sport=1234, dport=1234) /
264 self.pg0.add_stream(static_p)
265 self.pg_enable_capture(self.pg_interfaces)
268 rx = self.pg1.get_capture(1)
270 self.verify_ip(rx[0],
272 self.pg1.remote_hosts[2].mac,
274 self.pg1._remote_hosts[2].ip4)
277 # remove all the listeners
279 self.vapi.want_ip_neighbor_events(enable=0,
281 self.vapi.want_ip_neighbor_events(enable=0,
283 sw_if_index=self.pg1.sw_if_index)
284 self.vapi.want_ip_neighbor_events(enable=0,
286 sw_if_index=self.pg1.sw_if_index,
287 ip=self.pg1.remote_hosts[1].ip4)
290 # flap the link. dynamic ARPs get flush, statics don't
292 self.pg1.admin_down()
295 self.pg0.add_stream(static_p)
296 self.pg_enable_capture(self.pg_interfaces)
298 rx = self.pg1.get_capture(1)
300 self.verify_ip(rx[0],
302 self.pg1.remote_hosts[2].mac,
304 self.pg1._remote_hosts[2].ip4)
306 self.pg0.add_stream(dyn_p)
307 self.pg_enable_capture(self.pg_interfaces)
310 rx = self.pg1.get_capture(1)
311 self.verify_arp_req(rx[0],
314 self.pg1._remote_hosts[1].ip4)
316 self.assertFalse(dyn_arp.query_vpp_config())
317 self.assertTrue(static_arp.query_vpp_config())
319 # Send an ARP request from one of the so-far unlearned remote hosts
321 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
322 src=self.pg1._remote_hosts[3].mac) /
324 hwsrc=self.pg1._remote_hosts[3].mac,
325 pdst=self.pg1.local_ip4,
326 psrc=self.pg1._remote_hosts[3].ip4))
328 self.pg1.add_stream(p)
329 self.pg_enable_capture(self.pg_interfaces)
332 rx = self.pg1.get_capture(1)
333 self.verify_arp_resp(rx[0],
335 self.pg1._remote_hosts[3].mac,
337 self.pg1._remote_hosts[3].ip4)
340 # VPP should have learned the mapping for the remote host
342 self.assertTrue(find_nbr(self,
343 self.pg1.sw_if_index,
344 self.pg1._remote_hosts[3].ip4))
346 # Fire in an ARP request before the interface becomes IP enabled
348 self.pg2.generate_remote_hosts(4)
350 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
352 hwsrc=self.pg2.remote_mac,
353 pdst=self.pg1.local_ip4,
354 psrc=self.pg2.remote_hosts[3].ip4))
355 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
358 hwsrc=self.pg2.remote_mac,
359 pdst=self.pg1.local_ip4,
360 psrc=self.pg2.remote_hosts[3].ip4))
361 self.send_and_assert_no_replies(self.pg2, p,
362 "interface not IP enabled")
365 # Make pg2 un-numbered to pg1
367 self.pg2.set_unnumbered(self.pg1.sw_if_index)
370 # test the unnumbered dump both by all interfaces and just the enabled
373 unnum = self.vapi.ip_unnumbered_dump()
374 self.assertTrue(len(unnum))
375 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
376 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
377 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
378 self.assertTrue(len(unnum))
379 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
380 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
383 # We should respond to ARP requests for the unnumbered to address
384 # once an attached route to the source is known
386 self.send_and_assert_no_replies(
388 "ARP req for unnumbered address - no source")
390 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
391 [VppRoutePath("0.0.0.0",
392 self.pg2.sw_if_index)])
393 attached_host.add_vpp_config()
395 self.pg2.add_stream(p)
396 self.pg_enable_capture(self.pg_interfaces)
399 rx = self.pg2.get_capture(1)
400 self.verify_arp_resp(rx[0],
404 self.pg2.remote_hosts[3].ip4)
406 self.pg2.add_stream(pt)
407 self.pg_enable_capture(self.pg_interfaces)
410 rx = self.pg2.get_capture(1)
411 self.verify_arp_resp(rx[0],
415 self.pg2.remote_hosts[3].ip4)
418 # A neighbor entry that has no associated FIB-entry
420 arp_no_fib = VppNeighbor(self,
421 self.pg1.sw_if_index,
422 self.pg1.remote_hosts[4].mac,
423 self.pg1.remote_hosts[4].ip4,
425 arp_no_fib.add_vpp_config()
428 # check we have the neighbor, but no route
430 self.assertTrue(find_nbr(self,
431 self.pg1.sw_if_index,
432 self.pg1._remote_hosts[4].ip4))
433 self.assertFalse(find_route(self,
434 self.pg1._remote_hosts[4].ip4,
437 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
438 # from within pg1's subnet
440 arp_unnum = VppNeighbor(self,
441 self.pg2.sw_if_index,
442 self.pg1.remote_hosts[5].mac,
443 self.pg1.remote_hosts[5].ip4)
444 arp_unnum.add_vpp_config()
446 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
447 IP(src=self.pg0.remote_ip4,
448 dst=self.pg1._remote_hosts[5].ip4) /
449 UDP(sport=1234, dport=1234) /
452 self.pg0.add_stream(p)
453 self.pg_enable_capture(self.pg_interfaces)
456 rx = self.pg2.get_capture(1)
458 self.verify_ip(rx[0],
460 self.pg1.remote_hosts[5].mac,
462 self.pg1._remote_hosts[5].ip4)
465 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
466 # with the unnumbered interface's address as the source
468 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
470 hwsrc=self.pg2.remote_mac,
471 pdst=self.pg1.local_ip4,
472 psrc=self.pg1.remote_hosts[6].ip4))
474 self.pg2.add_stream(p)
475 self.pg_enable_capture(self.pg_interfaces)
478 rx = self.pg2.get_capture(1)
479 self.verify_arp_resp(rx[0],
483 self.pg1.remote_hosts[6].ip4)
486 # An attached host route out of pg2 for an undiscovered hosts generates
487 # an ARP request with the unnumbered address as the source
489 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
490 [VppRoutePath("0.0.0.0",
491 self.pg2.sw_if_index)])
492 att_unnum.add_vpp_config()
494 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
495 IP(src=self.pg0.remote_ip4,
496 dst=self.pg1._remote_hosts[7].ip4) /
497 UDP(sport=1234, dport=1234) /
500 self.pg0.add_stream(p)
501 self.pg_enable_capture(self.pg_interfaces)
504 rx = self.pg2.get_capture(1)
506 self.verify_arp_req(rx[0],
509 self.pg1._remote_hosts[7].ip4)
511 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
513 hwsrc=self.pg2.remote_mac,
514 pdst=self.pg1.local_ip4,
515 psrc=self.pg1.remote_hosts[7].ip4))
517 self.pg2.add_stream(p)
518 self.pg_enable_capture(self.pg_interfaces)
521 rx = self.pg2.get_capture(1)
522 self.verify_arp_resp(rx[0],
526 self.pg1.remote_hosts[7].ip4)
529 # An attached host route as yet unresolved out of pg2 for an
530 # undiscovered host, an ARP requests begets a response.
532 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
533 [VppRoutePath("0.0.0.0",
534 self.pg2.sw_if_index)])
535 att_unnum1.add_vpp_config()
537 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
539 hwsrc=self.pg2.remote_mac,
540 pdst=self.pg1.local_ip4,
541 psrc=self.pg1.remote_hosts[8].ip4))
543 self.pg2.add_stream(p)
544 self.pg_enable_capture(self.pg_interfaces)
547 rx = self.pg2.get_capture(1)
548 self.verify_arp_resp(rx[0],
552 self.pg1.remote_hosts[8].ip4)
555 # Send an ARP request from one of the so-far unlearned remote hosts
558 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
559 src=self.pg1._remote_hosts[9].mac) /
562 hwsrc=self.pg1._remote_hosts[9].mac,
563 pdst=self.pg1.local_ip4,
564 psrc=self.pg1._remote_hosts[9].ip4))
566 self.pg1.add_stream(p)
567 self.pg_enable_capture(self.pg_interfaces)
570 rx = self.pg1.get_capture(1)
571 self.verify_arp_resp(rx[0],
573 self.pg1._remote_hosts[9].mac,
575 self.pg1._remote_hosts[9].ip4)
578 # Add a hierarchy of routes for a host in the sub-net.
579 # Should still get an ARP resp since the cover is attached
581 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
583 hwsrc=self.pg1.remote_mac,
584 pdst=self.pg1.local_ip4,
585 psrc=self.pg1.remote_hosts[10].ip4))
587 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
588 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
589 self.pg1.sw_if_index)])
592 self.pg1.add_stream(p)
593 self.pg_enable_capture(self.pg_interfaces)
595 rx = self.pg1.get_capture(1)
596 self.verify_arp_resp(rx[0],
600 self.pg1.remote_hosts[10].ip4)
602 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
603 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
604 self.pg1.sw_if_index)])
607 self.pg1.add_stream(p)
608 self.pg_enable_capture(self.pg_interfaces)
610 rx = self.pg1.get_capture(1)
611 self.verify_arp_resp(rx[0],
615 self.pg1.remote_hosts[10].ip4)
618 # add an ARP entry that's not on the sub-net and so whose
619 # adj-fib fails the refinement check. then send an ARP request
622 a1 = VppNeighbor(self,
623 self.pg0.sw_if_index,
628 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
630 hwsrc=self.pg0.remote_mac,
631 psrc="100.100.100.50",
632 pdst=self.pg0.remote_ip4))
633 self.send_and_assert_no_replies(self.pg0, p,
634 "ARP req for from failed adj-fib")
638 # 1 - don't respond to ARP request for address not within the
639 # interface's sub-net
640 # 1b - nor within the unnumbered subnet
641 # 1c - nor within the subnet of a different interface
643 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
645 hwsrc=self.pg0.remote_mac,
647 psrc=self.pg0.remote_ip4))
648 self.send_and_assert_no_replies(self.pg0, p,
649 "ARP req for non-local destination")
650 self.assertFalse(find_nbr(self,
651 self.pg0.sw_if_index,
654 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
656 hwsrc=self.pg2.remote_mac,
658 psrc=self.pg1.remote_hosts[7].ip4))
659 self.send_and_assert_no_replies(
661 "ARP req for non-local destination - unnum")
663 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
665 hwsrc=self.pg0.remote_mac,
666 pdst=self.pg1.local_ip4,
667 psrc=self.pg1.remote_ip4))
668 self.send_and_assert_no_replies(self.pg0, p,
669 "ARP req diff sub-net")
670 self.assertFalse(find_nbr(self,
671 self.pg0.sw_if_index,
672 self.pg1.remote_ip4))
675 # 2 - don't respond to ARP request from an address not within the
676 # interface's sub-net
677 # 2b - to a proxied address
678 # 2c - not within a different interface's sub-net
679 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
681 hwsrc=self.pg0.remote_mac,
683 pdst=self.pg0.local_ip4))
684 self.send_and_assert_no_replies(self.pg0, p,
685 "ARP req for non-local source")
686 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
688 hwsrc=self.pg2.remote_mac,
690 pdst=self.pg0.local_ip4))
691 self.send_and_assert_no_replies(
693 "ARP req for non-local source - unnum")
694 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
696 hwsrc=self.pg0.remote_mac,
697 psrc=self.pg1.remote_ip4,
698 pdst=self.pg0.local_ip4))
699 self.send_and_assert_no_replies(self.pg0, p,
700 "ARP req for non-local source 2c")
703 # 3 - don't respond to ARP request from an address that belongs to
706 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
708 hwsrc=self.pg0.remote_mac,
709 psrc=self.pg0.local_ip4,
710 pdst=self.pg0.local_ip4))
711 self.send_and_assert_no_replies(self.pg0, p,
712 "ARP req for non-local source")
715 # 4 - don't respond to ARP requests that has mac source different
716 # from ARP request HW source
718 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
720 hwsrc="00:00:00:DE:AD:BE",
721 psrc=self.pg0.remote_ip4,
722 pdst=self.pg0.local_ip4))
723 self.send_and_assert_no_replies(self.pg0, p,
724 "ARP req for non-local source")
727 # 5 - don't respond to ARP requests for address within the
728 # interface's sub-net but not the interface's address
730 self.pg0.generate_remote_hosts(2)
731 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
733 hwsrc=self.pg0.remote_mac,
734 psrc=self.pg0.remote_hosts[0].ip4,
735 pdst=self.pg0.remote_hosts[1].ip4))
736 self.send_and_assert_no_replies(self.pg0, p,
737 "ARP req for non-local destination")
742 static_arp.remove_vpp_config()
743 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
745 # need this to flush the adj-fibs
746 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
747 self.pg2.admin_down()
748 self.pg1.admin_down()
750 def test_proxy_mirror_arp(self):
751 """ Interface Mirror Proxy ARP """
754 # When VPP has an interface whose address is also applied to a TAP
755 # interface on the host, then VPP's TAP interface will be unnumbered
756 # to the 'real' interface and do proxy ARP from the host.
757 # the curious aspect of this setup is that ARP requests from the host
758 # will come from the VPP's own address.
760 self.pg0.generate_remote_hosts(2)
762 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
763 dst="ff:ff:ff:ff:ff:ff") /
765 hwsrc=self.pg2.remote_mac,
766 pdst=self.pg0.remote_hosts[1].ip4,
767 psrc=self.pg0.local_ip4))
770 # Configure Proxy ARP for the subnet on PG0addresses on pg0
772 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
773 'low': self.pg0._local_ip4_subnet,
774 'hi': self.pg0._local_ip4_bcast},
777 # Make pg2 un-numbered to pg0
779 self.pg2.set_unnumbered(self.pg0.sw_if_index)
782 # Enable pg2 for proxy ARP
784 self.pg2.set_proxy_arp()
787 # Send the ARP request with an originating address that
788 # is VPP's own address
790 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
791 self.verify_arp_resp(rx[0],
794 self.pg0.remote_hosts[1].ip4,
798 # validate we have not learned an ARP entry as a result of this
800 self.assertFalse(find_nbr(self,
801 self.pg2.sw_if_index,
805 # setup a punt redirect so packets from the uplink go to the tap
807 redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index,
808 self.pg2.sw_if_index, self.pg0.local_ip4)
809 redirect.add_vpp_config()
811 p_tcp = (Ether(src=self.pg0.remote_mac,
812 dst=self.pg0.local_mac,) /
813 IP(src=self.pg0.remote_ip4,
814 dst=self.pg0.local_ip4) /
815 TCP(sport=80, dport=80) /
817 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
819 # there's no ARP entry so this is an ARP req
820 self.assertTrue(rx[0].haslayer(ARP))
822 # and ARP entry for VPP's pg0 address on the host interface
823 n1 = VppNeighbor(self,
824 self.pg2.sw_if_index,
827 is_no_fib_entry=True).add_vpp_config()
828 # now the packets shold forward
829 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
830 self.assertFalse(rx[0].haslayer(ARP))
831 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
834 # flush the neighbor cache on the uplink
836 af = VppEnum.vl_api_address_family_t
837 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
839 # ensure we can still resolve the ARPs on the uplink
840 self.pg0.resolve_arp()
842 self.assertTrue(find_nbr(self,
843 self.pg0.sw_if_index,
844 self.pg0.remote_ip4))
849 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
850 'low': self.pg0._local_ip4_subnet,
851 'hi': self.pg0._local_ip4_bcast},
853 redirect.remove_vpp_config()
855 def test_proxy_arp(self):
858 self.pg1.generate_remote_hosts(2)
861 # Proxy ARP request packets for each interface
863 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
864 dst="ff:ff:ff:ff:ff:ff") /
866 hwsrc=self.pg0.remote_mac,
868 psrc=self.pg0.remote_ip4))
869 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
870 dst="ff:ff:ff:ff:ff:ff") /
873 hwsrc=self.pg0.remote_mac,
875 psrc=self.pg0.remote_ip4))
876 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
877 dst="ff:ff:ff:ff:ff:ff") /
879 hwsrc=self.pg1.remote_mac,
881 psrc=self.pg1.remote_ip4))
882 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
883 dst="ff:ff:ff:ff:ff:ff") /
885 hwsrc=self.pg2.remote_mac,
887 psrc=self.pg1.remote_hosts[1].ip4))
888 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
889 dst="ff:ff:ff:ff:ff:ff") /
891 hwsrc=self.pg3.remote_mac,
893 psrc=self.pg3.remote_ip4))
896 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
898 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
900 'hi': "10.10.10.124"},
904 # No responses are sent when the interfaces are not enabled for proxy
907 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
908 "ARP req from unconfigured interface")
909 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
910 "ARP req from unconfigured interface")
913 # Make pg2 un-numbered to pg1
916 self.pg2.set_unnumbered(self.pg1.sw_if_index)
918 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
919 "ARP req from unnumbered interface")
922 # Enable each interface to reply to proxy ARPs
924 for i in self.pg_interfaces:
928 # Now each of the interfaces should reply to a request to a proxied
931 self.pg0.add_stream(arp_req_pg0)
932 self.pg_enable_capture(self.pg_interfaces)
935 rx = self.pg0.get_capture(1)
936 self.verify_arp_resp(rx[0],
942 self.pg0.add_stream(arp_req_pg0_tagged)
943 self.pg_enable_capture(self.pg_interfaces)
946 rx = self.pg0.get_capture(1)
947 self.verify_arp_resp(rx[0],
953 self.pg1.add_stream(arp_req_pg1)
954 self.pg_enable_capture(self.pg_interfaces)
957 rx = self.pg1.get_capture(1)
958 self.verify_arp_resp(rx[0],
964 self.pg2.add_stream(arp_req_pg2)
965 self.pg_enable_capture(self.pg_interfaces)
968 rx = self.pg2.get_capture(1)
969 self.verify_arp_resp(rx[0],
973 self.pg1.remote_hosts[1].ip4)
976 # A request for an address out of the configured range
978 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
979 dst="ff:ff:ff:ff:ff:ff") /
981 hwsrc=self.pg1.remote_mac,
983 psrc=self.pg1.remote_ip4))
984 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
985 "ARP req out of range HI")
986 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
987 dst="ff:ff:ff:ff:ff:ff") /
989 hwsrc=self.pg1.remote_mac,
991 psrc=self.pg1.remote_ip4))
992 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
993 "ARP req out of range Low")
996 # Request for an address in the proxy range but from an interface
999 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
1000 "ARP req from different VRF")
1003 # Disable Each interface for proxy ARP
1004 # - expect none to respond
1006 for i in self.pg_interfaces:
1009 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
1010 "ARP req from disable")
1011 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1012 "ARP req from disable")
1013 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1014 "ARP req from disable")
1017 # clean up on interface 2
1019 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1021 def test_mpls(self):
1025 # Interface 2 does not yet have ip4 config
1027 self.pg2.config_ip4()
1028 self.pg2.generate_remote_hosts(2)
1031 # Add a route with out going label via an ARP unresolved next-hop
1033 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1034 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1035 self.pg2.sw_if_index,
1037 ip_10_0_0_1.add_vpp_config()
1040 # packets should generate an ARP request
1042 p = (Ether(src=self.pg0.remote_mac,
1043 dst=self.pg0.local_mac) /
1044 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1045 UDP(sport=1234, dport=1234) /
1048 self.pg0.add_stream(p)
1049 self.pg_enable_capture(self.pg_interfaces)
1052 rx = self.pg2.get_capture(1)
1053 self.verify_arp_req(rx[0],
1056 self.pg2._remote_hosts[1].ip4)
1059 # now resolve the neighbours
1061 self.pg2.configure_ipv4_neighbors()
1064 # Now packet should be properly MPLS encapped.
1065 # This verifies that MPLS link-type adjacencies are completed
1066 # when the ARP entry resolves
1068 self.pg0.add_stream(p)
1069 self.pg_enable_capture(self.pg_interfaces)
1072 rx = self.pg2.get_capture(1)
1073 self.verify_ip_o_mpls(rx[0],
1075 self.pg2.remote_hosts[1].mac,
1077 self.pg0.remote_ip4,
1079 self.pg2.unconfig_ip4()
1081 def test_arp_vrrp(self):
1082 """ ARP reply with VRRP virtual src hw addr """
1085 # IP packet destined for pg1 remote host arrives on pg0 resulting
1086 # in an ARP request for the address of the remote host on pg1
1088 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1089 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1090 UDP(sport=1234, dport=1234) /
1093 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1095 self.verify_arp_req(rx1[0],
1098 self.pg1.remote_ip4)
1101 # ARP reply for address of pg1 remote host arrives on pg1 with
1102 # the hw src addr set to a value in the VRRP IPv4 range of
1105 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1106 ARP(op="is-at", hwdst=self.pg1.local_mac,
1107 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1108 psrc=self.pg1.remote_ip4))
1110 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1113 # IP packet destined for pg1 remote host arrives on pg0 again.
1114 # VPP should have an ARP entry for that address now and the packet
1115 # should be sent out pg1.
1117 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1119 self.verify_ip(rx1[0],
1121 "00:00:5e:00:01:09",
1122 self.pg0.remote_ip4,
1123 self.pg1.remote_ip4)
1125 self.pg1.admin_down()
1128 def test_arp_duplicates(self):
1129 """ ARP Duplicates"""
1132 # Generate some hosts on the LAN
1134 self.pg1.generate_remote_hosts(3)
1137 # Add host 1 on pg1 and pg2
1139 arp_pg1 = VppNeighbor(self,
1140 self.pg1.sw_if_index,
1141 self.pg1.remote_hosts[1].mac,
1142 self.pg1.remote_hosts[1].ip4)
1143 arp_pg1.add_vpp_config()
1144 arp_pg2 = VppNeighbor(self,
1145 self.pg2.sw_if_index,
1146 self.pg2.remote_mac,
1147 self.pg1.remote_hosts[1].ip4)
1148 arp_pg2.add_vpp_config()
1151 # IP packet destined for pg1 remote host arrives on pg1 again.
1153 p = (Ether(dst=self.pg0.local_mac,
1154 src=self.pg0.remote_mac) /
1155 IP(src=self.pg0.remote_ip4,
1156 dst=self.pg1.remote_hosts[1].ip4) /
1157 UDP(sport=1234, dport=1234) /
1160 self.pg0.add_stream(p)
1161 self.pg_enable_capture(self.pg_interfaces)
1164 rx1 = self.pg1.get_capture(1)
1166 self.verify_ip(rx1[0],
1168 self.pg1.remote_hosts[1].mac,
1169 self.pg0.remote_ip4,
1170 self.pg1.remote_hosts[1].ip4)
1173 # remove the duplicate on pg1
1174 # packet stream should generate ARPs out of pg1
1176 arp_pg1.remove_vpp_config()
1178 self.pg0.add_stream(p)
1179 self.pg_enable_capture(self.pg_interfaces)
1182 rx1 = self.pg1.get_capture(1)
1184 self.verify_arp_req(rx1[0],
1187 self.pg1.remote_hosts[1].ip4)
1192 arp_pg1.add_vpp_config()
1194 self.pg0.add_stream(p)
1195 self.pg_enable_capture(self.pg_interfaces)
1198 rx1 = self.pg1.get_capture(1)
1200 self.verify_ip(rx1[0],
1202 self.pg1.remote_hosts[1].mac,
1203 self.pg0.remote_ip4,
1204 self.pg1.remote_hosts[1].ip4)
1206 def test_arp_static(self):
1208 self.pg2.generate_remote_hosts(3)
1211 # Add a static ARP entry
1213 static_arp = VppNeighbor(self,
1214 self.pg2.sw_if_index,
1215 self.pg2.remote_hosts[1].mac,
1216 self.pg2.remote_hosts[1].ip4,
1218 static_arp.add_vpp_config()
1221 # Add the connected prefix to the interface
1223 self.pg2.config_ip4()
1226 # We should now find the adj-fib
1228 self.assertTrue(find_nbr(self,
1229 self.pg2.sw_if_index,
1230 self.pg2.remote_hosts[1].ip4,
1232 self.assertTrue(find_route(self,
1233 self.pg2.remote_hosts[1].ip4,
1237 # remove the connected
1239 self.pg2.unconfig_ip4()
1242 # put the interface into table 1
1244 self.pg2.set_table_ip4(1)
1247 # configure the same connected and expect to find the
1248 # adj fib in the new table
1250 self.pg2.config_ip4()
1251 self.assertTrue(find_route(self,
1252 self.pg2.remote_hosts[1].ip4,
1259 self.pg2.unconfig_ip4()
1260 static_arp.remove_vpp_config()
1261 self.pg2.set_table_ip4(0)
1263 def test_arp_static_replace_dynamic_same_mac(self):
1264 """ ARP Static can replace Dynamic (same mac) """
1265 self.pg2.generate_remote_hosts(1)
1267 dyn_arp = VppNeighbor(self,
1268 self.pg2.sw_if_index,
1269 self.pg2.remote_hosts[0].mac,
1270 self.pg2.remote_hosts[0].ip4)
1271 static_arp = VppNeighbor(self,
1272 self.pg2.sw_if_index,
1273 self.pg2.remote_hosts[0].mac,
1274 self.pg2.remote_hosts[0].ip4,
1278 # Add a dynamic ARP entry
1280 dyn_arp.add_vpp_config()
1283 # We should find the dynamic nbr
1285 self.assertFalse(find_nbr(self,
1286 self.pg2.sw_if_index,
1287 self.pg2.remote_hosts[0].ip4,
1289 self.assertTrue(find_nbr(self,
1290 self.pg2.sw_if_index,
1291 self.pg2.remote_hosts[0].ip4,
1293 mac=self.pg2.remote_hosts[0].mac))
1296 # Add a static ARP entry with the same mac
1298 static_arp.add_vpp_config()
1301 # We should now find the static nbr with the same mac
1303 self.assertFalse(find_nbr(self,
1304 self.pg2.sw_if_index,
1305 self.pg2.remote_hosts[0].ip4,
1307 self.assertTrue(find_nbr(self,
1308 self.pg2.sw_if_index,
1309 self.pg2.remote_hosts[0].ip4,
1311 mac=self.pg2.remote_hosts[0].mac))
1316 static_arp.remove_vpp_config()
1318 def test_arp_static_replace_dynamic_diff_mac(self):
1319 """ ARP Static can replace Dynamic (diff mac) """
1320 self.pg2.generate_remote_hosts(2)
1322 dyn_arp = VppNeighbor(self,
1323 self.pg2.sw_if_index,
1324 self.pg2.remote_hosts[0].mac,
1325 self.pg2.remote_hosts[0].ip4)
1326 static_arp = VppNeighbor(self,
1327 self.pg2.sw_if_index,
1328 self.pg2.remote_hosts[1].mac,
1329 self.pg2.remote_hosts[0].ip4,
1333 # Add a dynamic ARP entry
1335 dyn_arp.add_vpp_config()
1338 # We should find the dynamic nbr
1340 self.assertFalse(find_nbr(self,
1341 self.pg2.sw_if_index,
1342 self.pg2.remote_hosts[0].ip4,
1344 self.assertTrue(find_nbr(self,
1345 self.pg2.sw_if_index,
1346 self.pg2.remote_hosts[0].ip4,
1348 mac=self.pg2.remote_hosts[0].mac))
1351 # Add a static ARP entry with a changed mac
1353 static_arp.add_vpp_config()
1356 # We should now find the static nbr with a changed mac
1358 self.assertFalse(find_nbr(self,
1359 self.pg2.sw_if_index,
1360 self.pg2.remote_hosts[0].ip4,
1362 self.assertTrue(find_nbr(self,
1363 self.pg2.sw_if_index,
1364 self.pg2.remote_hosts[0].ip4,
1366 mac=self.pg2.remote_hosts[1].mac))
1371 static_arp.remove_vpp_config()
1373 def test_arp_incomplete(self):
1374 """ ARP Incomplete"""
1375 self.pg1.generate_remote_hosts(3)
1377 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1378 IP(src=self.pg0.remote_ip4,
1379 dst=self.pg1.remote_hosts[1].ip4) /
1380 UDP(sport=1234, dport=1234) /
1382 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1383 IP(src=self.pg0.remote_ip4,
1384 dst=self.pg1.remote_hosts[2].ip4) /
1385 UDP(sport=1234, dport=1234) /
1389 # a packet to an unresolved destination generates an ARP request
1391 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1392 self.verify_arp_req(rx[0],
1395 self.pg1._remote_hosts[1].ip4)
1398 # add a neighbour for remote host 1
1400 static_arp = VppNeighbor(self,
1401 self.pg1.sw_if_index,
1402 self.pg1.remote_hosts[1].mac,
1403 self.pg1.remote_hosts[1].ip4,
1405 static_arp.add_vpp_config()
1408 # change the interface's MAC
1410 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1411 "00:00:00:33:33:33")
1414 # now ARP requests come from the new source mac
1416 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1417 self.verify_arp_req(rx[0],
1418 "00:00:00:33:33:33",
1420 self.pg1._remote_hosts[2].ip4)
1423 # packets to the resolved host also have the new source mac
1425 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1426 self.verify_ip(rx[0],
1427 "00:00:00:33:33:33",
1428 self.pg1.remote_hosts[1].mac,
1429 self.pg0.remote_ip4,
1430 self.pg1.remote_hosts[1].ip4)
1433 # set the mac address on the interface that does not have a
1434 # configured subnet and thus no glean
1436 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1437 "00:00:00:33:33:33")
1439 def test_garp(self):
1443 # Generate some hosts on the LAN
1445 self.pg1.generate_remote_hosts(4)
1446 self.pg2.generate_remote_hosts(4)
1451 arp = VppNeighbor(self,
1452 self.pg1.sw_if_index,
1453 self.pg1.remote_hosts[1].mac,
1454 self.pg1.remote_hosts[1].ip4)
1455 arp.add_vpp_config()
1457 self.assertTrue(find_nbr(self,
1458 self.pg1.sw_if_index,
1459 self.pg1.remote_hosts[1].ip4,
1460 mac=self.pg1.remote_hosts[1].mac))
1463 # Send a GARP (request) to swap the host 1's address to that of host 2
1465 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1466 src=self.pg1.remote_hosts[2].mac) /
1468 hwdst=self.pg1.local_mac,
1469 hwsrc=self.pg1.remote_hosts[2].mac,
1470 pdst=self.pg1.remote_hosts[1].ip4,
1471 psrc=self.pg1.remote_hosts[1].ip4))
1473 self.pg1.add_stream(p1)
1474 self.pg_enable_capture(self.pg_interfaces)
1477 self.assertTrue(find_nbr(self,
1478 self.pg1.sw_if_index,
1479 self.pg1.remote_hosts[1].ip4,
1480 mac=self.pg1.remote_hosts[2].mac))
1483 # Send a GARP (reply) to swap the host 1's address to that of host 3
1485 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1486 src=self.pg1.remote_hosts[3].mac) /
1488 hwdst=self.pg1.local_mac,
1489 hwsrc=self.pg1.remote_hosts[3].mac,
1490 pdst=self.pg1.remote_hosts[1].ip4,
1491 psrc=self.pg1.remote_hosts[1].ip4))
1493 self.pg1.add_stream(p1)
1494 self.pg_enable_capture(self.pg_interfaces)
1497 self.assertTrue(find_nbr(self,
1498 self.pg1.sw_if_index,
1499 self.pg1.remote_hosts[1].ip4,
1500 mac=self.pg1.remote_hosts[3].mac))
1503 # GARPs (request nor replies) for host we don't know yet
1504 # don't result in new neighbour entries
1506 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1507 src=self.pg1.remote_hosts[3].mac) /
1509 hwdst=self.pg1.local_mac,
1510 hwsrc=self.pg1.remote_hosts[3].mac,
1511 pdst=self.pg1.remote_hosts[2].ip4,
1512 psrc=self.pg1.remote_hosts[2].ip4))
1514 self.pg1.add_stream(p1)
1515 self.pg_enable_capture(self.pg_interfaces)
1518 self.assertFalse(find_nbr(self,
1519 self.pg1.sw_if_index,
1520 self.pg1.remote_hosts[2].ip4))
1522 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1523 src=self.pg1.remote_hosts[3].mac) /
1525 hwdst=self.pg1.local_mac,
1526 hwsrc=self.pg1.remote_hosts[3].mac,
1527 pdst=self.pg1.remote_hosts[2].ip4,
1528 psrc=self.pg1.remote_hosts[2].ip4))
1530 self.pg1.add_stream(p1)
1531 self.pg_enable_capture(self.pg_interfaces)
1534 self.assertFalse(find_nbr(self,
1535 self.pg1.sw_if_index,
1536 self.pg1.remote_hosts[2].ip4))
1539 # IP address in different subnets are not learnt
1541 self.pg2.configure_ipv4_neighbors()
1543 for op in ["is-at", "who-has"]:
1544 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1545 src=self.pg2.remote_hosts[1].mac) /
1547 hwdst=self.pg2.local_mac,
1548 hwsrc=self.pg2.remote_hosts[1].mac,
1549 pdst=self.pg2.remote_hosts[1].ip4,
1550 psrc=self.pg2.remote_hosts[1].ip4)),
1551 (Ether(dst="ff:ff:ff:ff:ff:ff",
1552 src=self.pg2.remote_hosts[1].mac) /
1554 hwdst="ff:ff:ff:ff:ff:ff",
1555 hwsrc=self.pg2.remote_hosts[1].mac,
1556 pdst=self.pg2.remote_hosts[1].ip4,
1557 psrc=self.pg2.remote_hosts[1].ip4))]
1559 self.send_and_assert_no_replies(self.pg1, p1)
1560 self.assertFalse(find_nbr(self,
1561 self.pg1.sw_if_index,
1562 self.pg2.remote_hosts[1].ip4))
1564 # they are all dropped because the subnet's don't match
1565 self.assertEqual(4, self.statistics.get_err_counter(
1566 "/err/arp-reply/IP4 destination address not local to subnet"))
1568 def test_arp_incomplete2(self):
1569 """ Incomplete Entries """
1572 # ensure that we throttle the ARP and ND requests
1574 self.pg0.generate_remote_hosts(2)
1579 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1580 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1581 self.pg0.sw_if_index)])
1582 ip_10_0_0_1.add_vpp_config()
1584 p1 = (Ether(dst=self.pg1.local_mac,
1585 src=self.pg1.remote_mac) /
1586 IP(src=self.pg1.remote_ip4,
1588 UDP(sport=1234, dport=1234) /
1591 self.pg1.add_stream(p1 * 257)
1592 self.pg_enable_capture(self.pg_interfaces)
1594 rx = self.pg0._get_capture(1)
1597 # how many we get is going to be dependent on the time for packet
1598 # processing but it should be small
1600 self.assertLess(len(rx), 64)
1605 ip_10_1 = VppIpRoute(self, "10::1", 128,
1606 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1607 self.pg0.sw_if_index,
1608 proto=DpoProto.DPO_PROTO_IP6)])
1609 ip_10_1.add_vpp_config()
1611 p1 = (Ether(dst=self.pg1.local_mac,
1612 src=self.pg1.remote_mac) /
1613 IPv6(src=self.pg1.remote_ip6,
1615 UDP(sport=1234, dport=1234) /
1618 self.pg1.add_stream(p1 * 257)
1619 self.pg_enable_capture(self.pg_interfaces)
1621 rx = self.pg0._get_capture(1)
1624 # how many we get is going to be dependent on the time for packet
1625 # processing but it should be small
1627 self.assertLess(len(rx), 64)
1629 def test_arp_forus(self):
1630 """ ARP for for-us """
1633 # Test that VPP responds with ARP requests to addresses that
1634 # are connected and local routes.
1635 # Use one of the 'remote' addresses in the subnet as a local address
1636 # The intention of this route is that it then acts like a secondary
1637 # address added to an interface
1639 self.pg0.generate_remote_hosts(2)
1642 self, self.pg0.remote_hosts[1].ip4, 32,
1643 [VppRoutePath("0.0.0.0",
1644 self.pg0.sw_if_index,
1645 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1646 forus.add_vpp_config()
1648 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1649 src=self.pg0.remote_mac) /
1651 hwdst=self.pg0.local_mac,
1652 hwsrc=self.pg0.remote_mac,
1653 pdst=self.pg0.remote_hosts[1].ip4,
1654 psrc=self.pg0.remote_ip4))
1656 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1658 self.verify_arp_resp(rx[0],
1660 self.pg0.remote_mac,
1661 self.pg0.remote_hosts[1].ip4,
1662 self.pg0.remote_ip4)
1664 def test_arp_table_swap(self):
1666 # Generate some hosts on the LAN
1669 self.pg1.generate_remote_hosts(N_NBRS)
1671 for n in range(N_NBRS):
1672 # a route thru each neighbour
1673 VppIpRoute(self, "10.0.0.%d" % n, 32,
1674 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1675 self.pg1.sw_if_index)]).add_vpp_config()
1677 # resolve each neighbour
1678 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1679 ARP(op="is-at", hwdst=self.pg1.local_mac,
1680 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1681 psrc=self.pg1.remote_hosts[n].ip4))
1683 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1685 self.logger.info(self.vapi.cli("sh ip neighbors"))
1688 # swap the table pg1 is in
1690 table = VppIpTable(self, 100).add_vpp_config()
1692 self.pg1.unconfig_ip4()
1693 self.pg1.set_table_ip4(100)
1694 self.pg1.config_ip4()
1697 # all neighbours are cleared
1699 for n in range(N_NBRS):
1700 self.assertFalse(find_nbr(self,
1701 self.pg1.sw_if_index,
1702 self.pg1.remote_hosts[n].ip4))
1705 # packets to all neighbours generate ARP requests
1707 for n in range(N_NBRS):
1708 # a route thru each neighbour
1709 VppIpRoute(self, "10.0.0.%d" % n, 32,
1710 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1711 self.pg1.sw_if_index)],
1712 table_id=100).add_vpp_config()
1714 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1715 dst=self.pg1.local_mac) /
1716 IP(src=self.pg1.remote_hosts[n].ip4,
1717 dst="10.0.0.%d" % n) /
1719 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1721 self.verify_arp_req(rx,
1724 self.pg1.remote_hosts[n].ip4)
1726 self.pg1.unconfig_ip4()
1727 self.pg1.set_table_ip4(0)
1729 def test_glean_src_select(self):
1730 """ Multi Connecteds """
1733 # configure multiple connected subnets on an interface
1734 # and ensure that ARP requests for hosts on those subnets
1735 # pick up the correct source address
1737 conn1 = VppIpInterfaceAddress(self, self.pg1,
1738 "10.0.0.1", 24).add_vpp_config()
1739 conn2 = VppIpInterfaceAddress(self, self.pg1,
1740 "10.0.1.1", 24).add_vpp_config()
1742 p1 = (Ether(src=self.pg0.remote_mac,
1743 dst=self.pg0.local_mac) /
1744 IP(src=self.pg1.remote_ip4,
1748 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
1750 self.verify_arp_req(rx,
1755 p2 = (Ether(src=self.pg0.remote_mac,
1756 dst=self.pg0.local_mac) /
1757 IP(src=self.pg1.remote_ip4,
1761 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1763 self.verify_arp_req(rx,
1769 # add a local address in the same subnet
1770 # the source addresses are equivalent. VPP happens to
1771 # choose the last one that was added
1772 conn3 = VppIpInterfaceAddress(self, self.pg1,
1773 "10.0.1.2", 24).add_vpp_config()
1775 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1777 self.verify_arp_req(rx,
1785 conn3.remove_vpp_config()
1786 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1788 self.verify_arp_req(rx,
1794 # add back, this time remove the first one
1796 conn3 = VppIpInterfaceAddress(self, self.pg1,
1797 "10.0.1.2", 24).add_vpp_config()
1799 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1801 self.verify_arp_req(rx,
1806 conn1.remove_vpp_config()
1807 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1809 self.verify_arp_req(rx,
1815 conn3.remove_vpp_config()
1816 conn2.remove_vpp_config()
1819 @tag_fixme_vpp_workers
1820 class NeighborStatsTestCase(VppTestCase):
1821 """ ARP/ND Counters """
1824 def setUpClass(cls):
1825 super(NeighborStatsTestCase, cls).setUpClass()
1828 def tearDownClass(cls):
1829 super(NeighborStatsTestCase, cls).tearDownClass()
1832 super(NeighborStatsTestCase, self).setUp()
1834 self.create_pg_interfaces(range(2))
1836 # pg0 configured with ip4 and 6 addresses used for input
1837 # pg1 configured with ip4 and 6 addresses used for output
1838 # pg2 is unnumbered to pg0
1839 for i in self.pg_interfaces:
1847 super(NeighborStatsTestCase, self).tearDown()
1849 for i in self.pg_interfaces:
1854 def test_arp_stats(self):
1855 """ ARP Counters """
1857 self.vapi.cli("adj counters enable")
1858 self.pg1.generate_remote_hosts(2)
1860 arp1 = VppNeighbor(self,
1861 self.pg1.sw_if_index,
1862 self.pg1.remote_hosts[0].mac,
1863 self.pg1.remote_hosts[0].ip4)
1864 arp1.add_vpp_config()
1865 arp2 = VppNeighbor(self,
1866 self.pg1.sw_if_index,
1867 self.pg1.remote_hosts[1].mac,
1868 self.pg1.remote_hosts[1].ip4)
1869 arp2.add_vpp_config()
1871 p1 = (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[0].ip4) /
1875 UDP(sport=1234, dport=1234) /
1877 p2 = (Ether(dst=self.pg0.local_mac,
1878 src=self.pg0.remote_mac) /
1879 IP(src=self.pg0.remote_ip4,
1880 dst=self.pg1.remote_hosts[1].ip4) /
1881 UDP(sport=1234, dport=1234) /
1884 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1885 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1887 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1888 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1890 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1891 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1893 def test_nd_stats(self):
1896 self.vapi.cli("adj counters enable")
1897 self.pg0.generate_remote_hosts(3)
1899 nd1 = VppNeighbor(self,
1900 self.pg0.sw_if_index,
1901 self.pg0.remote_hosts[1].mac,
1902 self.pg0.remote_hosts[1].ip6)
1903 nd1.add_vpp_config()
1904 nd2 = VppNeighbor(self,
1905 self.pg0.sw_if_index,
1906 self.pg0.remote_hosts[2].mac,
1907 self.pg0.remote_hosts[2].ip6)
1908 nd2.add_vpp_config()
1910 p1 = (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[1].ip6) /
1914 UDP(sport=1234, dport=1234) /
1916 p2 = (Ether(dst=self.pg1.local_mac,
1917 src=self.pg1.remote_mac) /
1918 IPv6(src=self.pg1.remote_ip6,
1919 dst=self.pg0.remote_hosts[2].ip6) /
1920 UDP(sport=1234, dport=1234) /
1923 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1924 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1926 self.assertEqual(16, nd1.get_stats()['packets'])
1927 self.assertEqual(16, nd2.get_stats()['packets'])
1929 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1930 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1933 class NeighborAgeTestCase(VppTestCase):
1934 """ ARP/ND Aging """
1937 def setUpClass(cls):
1938 super(NeighborAgeTestCase, cls).setUpClass()
1941 def tearDownClass(cls):
1942 super(NeighborAgeTestCase, cls).tearDownClass()
1945 super(NeighborAgeTestCase, self).setUp()
1947 self.create_pg_interfaces(range(1))
1949 # pg0 configured with ip4 and 6 addresses used for input
1950 # pg1 configured with ip4 and 6 addresses used for output
1951 # pg2 is unnumbered to pg0
1952 for i in self.pg_interfaces:
1960 super(NeighborAgeTestCase, self).tearDown()
1962 for i in self.pg_interfaces:
1967 def wait_for_no_nbr(self, intf, address,
1968 n_tries=50, s_time=1):
1970 if not find_nbr(self, intf, address):
1972 n_tries = n_tries - 1
1977 def verify_arp_req(self, rx, smac, sip, dip):
1979 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1980 self.assertEqual(ether.src, smac)
1983 self.assertEqual(arp.hwtype, 1)
1984 self.assertEqual(arp.ptype, 0x800)
1985 self.assertEqual(arp.hwlen, 6)
1986 self.assertEqual(arp.plen, 4)
1987 self.assertEqual(arp.op, arp_opts["who-has"])
1988 self.assertEqual(arp.hwsrc, smac)
1989 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1990 self.assertEqual(arp.psrc, sip)
1991 self.assertEqual(arp.pdst, dip)
1994 """ Aging/Recycle """
1996 self.vapi.cli("set logging unthrottle 0")
1997 self.vapi.cli("set logging size %d" % 0xffff)
1999 self.pg0.generate_remote_hosts(201)
2001 vaf = VppEnum.vl_api_address_family_t
2004 # start listening on all interfaces
2006 self.pg_enable_capture(self.pg_interfaces)
2009 # Set the neighbor configuration:
2014 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2019 self.vapi.cli("sh ip neighbor-config")
2021 # add the 198 neighbours that should pass (-1 for one created in setup)
2022 for ii in range(200):
2024 self.pg0.sw_if_index,
2025 self.pg0.remote_hosts[ii].mac,
2026 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2028 # one more neighbor over the limit should fail
2029 with self.vapi.assert_negative_api_retval():
2031 self.pg0.sw_if_index,
2032 self.pg0.remote_hosts[200].mac,
2033 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2036 # change the config to allow recycling the old neighbors
2038 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2043 # now new additions are allowed
2045 self.pg0.sw_if_index,
2046 self.pg0.remote_hosts[200].mac,
2047 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2049 # add the first neighbor we configured has been re-used
2050 self.assertFalse(find_nbr(self,
2051 self.pg0.sw_if_index,
2052 self.pg0.remote_hosts[0].ip4))
2053 self.assertTrue(find_nbr(self,
2054 self.pg0.sw_if_index,
2055 self.pg0.remote_hosts[200].ip4))
2058 # change the config to age old neighbors
2060 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2065 self.vapi.cli("sh ip4 neighbor-sorted")
2068 # expect probes from all these ARP entries as they age
2069 # 3 probes for each neighbor 3*200 = 600
2070 rxs = self.pg0.get_capture(600, timeout=8)
2073 for jj in range(200):
2074 rx = rxs[ii*200 + jj]
2078 # 3 probes sent then 1 more second to see if a reply comes, before
2081 for jj in range(1, 201):
2082 self.wait_for_no_nbr(self.pg0.sw_if_index,
2083 self.pg0.remote_hosts[jj].ip4)
2085 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2086 af=vaf.ADDRESS_IP4))
2089 # load up some neighbours again with 2s aging enabled
2090 # they should be removed after 10s (2s age + 4s for probes + gap)
2091 # check for the add and remove events
2093 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2095 self.vapi.want_ip_neighbor_events_v2(enable=1)
2096 for ii in range(10):
2098 self.pg0.sw_if_index,
2099 self.pg0.remote_hosts[ii].mac,
2100 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2102 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2103 self.assertEqual(e.flags,
2104 enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2105 self.assertEqual(str(e.neighbor.ip_address),
2106 self.pg0.remote_hosts[ii].ip4)
2107 self.assertEqual(e.neighbor.mac_address,
2108 self.pg0.remote_hosts[ii].mac)
2111 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2112 af=vaf.ADDRESS_IP4))
2115 for ii in range(10):
2116 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2117 self.assertEqual(e.flags,
2118 enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2121 # check we got the correct mac/ip pairs - done separately
2122 # because we don't care about the order the remove notifications
2124 for ii in range(10):
2126 mac = self.pg0.remote_hosts[ii].mac
2127 ip = self.pg0.remote_hosts[ii].ip4
2130 if (e.neighbor.mac_address == mac and
2131 str(e.neighbor.ip_address) == ip):
2134 self.assertTrue(found)
2137 # check if we can set age and recycle with empty neighbor list
2139 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2145 # load up some neighbours again, then disable the aging
2146 # they should still be there in 10 seconds time
2148 for ii in range(10):
2150 self.pg0.sw_if_index,
2151 self.pg0.remote_hosts[ii].mac,
2152 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2153 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2159 self.assertTrue(find_nbr(self,
2160 self.pg0.sw_if_index,
2161 self.pg0.remote_hosts[0].ip4))
2164 class NeighborReplaceTestCase(VppTestCase):
2165 """ ARP/ND Replacement """
2168 def setUpClass(cls):
2169 super(NeighborReplaceTestCase, cls).setUpClass()
2172 def tearDownClass(cls):
2173 super(NeighborReplaceTestCase, cls).tearDownClass()
2176 super(NeighborReplaceTestCase, self).setUp()
2178 self.create_pg_interfaces(range(4))
2180 # pg0 configured with ip4 and 6 addresses used for input
2181 # pg1 configured with ip4 and 6 addresses used for output
2182 # pg2 is unnumbered to pg0
2183 for i in self.pg_interfaces:
2191 super(NeighborReplaceTestCase, self).tearDown()
2193 for i in self.pg_interfaces:
2198 def test_replace(self):
2203 for i in self.pg_interfaces:
2204 i.generate_remote_hosts(N_HOSTS)
2205 i.configure_ipv4_neighbors()
2206 i.configure_ipv6_neighbors()
2209 self.vapi.ip_neighbor_replace_begin()
2210 self.vapi.ip_neighbor_replace_end()
2212 for i in self.pg_interfaces:
2213 for h in range(N_HOSTS):
2214 self.assertFalse(find_nbr(self,
2215 self.pg0.sw_if_index,
2216 self.pg0.remote_hosts[h].ip4))
2217 self.assertFalse(find_nbr(self,
2218 self.pg0.sw_if_index,
2219 self.pg0.remote_hosts[h].ip6))
2222 # and them all back via the API
2224 for i in self.pg_interfaces:
2225 for h in range(N_HOSTS):
2228 i.remote_hosts[h].mac,
2229 i.remote_hosts[h].ip4).add_vpp_config()
2232 i.remote_hosts[h].mac,
2233 i.remote_hosts[h].ip6).add_vpp_config()
2236 # begin the replacement again, this time touch some
2237 # the neighbours on pg1 so they are not deleted
2239 self.vapi.ip_neighbor_replace_begin()
2241 # update from the API all neighbours on pg1
2242 for h in range(N_HOSTS):
2244 self.pg1.sw_if_index,
2245 self.pg1.remote_hosts[h].mac,
2246 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2248 self.pg1.sw_if_index,
2249 self.pg1.remote_hosts[h].mac,
2250 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2252 # update from the data-plane all neighbours on pg3
2253 self.pg3.configure_ipv4_neighbors()
2254 self.pg3.configure_ipv6_neighbors()
2256 # complete the replacement
2257 self.logger.info(self.vapi.cli("sh ip neighbors"))
2258 self.vapi.ip_neighbor_replace_end()
2260 for i in self.pg_interfaces:
2261 if i == self.pg1 or i == self.pg3:
2262 # neighbours on pg1 and pg3 are still present
2263 for h in range(N_HOSTS):
2264 self.assertTrue(find_nbr(self,
2266 i.remote_hosts[h].ip4))
2267 self.assertTrue(find_nbr(self,
2269 i.remote_hosts[h].ip6))
2271 # all other neighbours are toast
2272 for h in range(N_HOSTS):
2273 self.assertFalse(find_nbr(self,
2275 i.remote_hosts[h].ip4))
2276 self.assertFalse(find_nbr(self,
2278 i.remote_hosts[h].ip6))
2281 class NeighborFlush(VppTestCase):
2282 """ Neighbor Flush """
2285 def setUpClass(cls):
2286 super(NeighborFlush, cls).setUpClass()
2289 def tearDownClass(cls):
2290 super(NeighborFlush, cls).tearDownClass()
2293 super(NeighborFlush, self).setUp()
2295 self.create_pg_interfaces(range(2))
2297 for i in self.pg_interfaces:
2305 super(NeighborFlush, self).tearDown()
2307 for i in self.pg_interfaces:
2312 def test_flush(self):
2313 """ Neighbour Flush """
2316 nf = e.vl_api_ip_neighbor_flags_t
2317 af = e.vl_api_address_family_t
2319 static = [False, True]
2320 self.pg0.generate_remote_hosts(N_HOSTS)
2321 self.pg1.generate_remote_hosts(N_HOSTS)
2324 # a few v4 and v6 dynamic neoghbors
2325 for n in range(N_HOSTS):
2327 self.pg0.sw_if_index,
2328 self.pg0.remote_hosts[n].mac,
2329 self.pg0.remote_hosts[n].ip4,
2330 is_static=s).add_vpp_config()
2332 self.pg1.sw_if_index,
2333 self.pg1.remote_hosts[n].mac,
2334 self.pg1.remote_hosts[n].ip6,
2335 is_static=s).add_vpp_config()
2337 # flush the interfaces individually
2338 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2340 # check we haven't flushed that which we shouldn't
2341 for n in range(N_HOSTS):
2342 self.assertTrue(find_nbr(self,
2343 self.pg1.sw_if_index,
2344 self.pg1.remote_hosts[n].ip6,
2347 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2349 for n in range(N_HOSTS):
2350 self.assertFalse(find_nbr(self,
2351 self.pg0.sw_if_index,
2352 self.pg0.remote_hosts[n].ip4))
2353 self.assertFalse(find_nbr(self,
2354 self.pg1.sw_if_index,
2355 self.pg1.remote_hosts[n].ip6))
2357 # add the nieghbours back
2358 for n in range(N_HOSTS):
2360 self.pg0.sw_if_index,
2361 self.pg0.remote_hosts[n].mac,
2362 self.pg0.remote_hosts[n].ip4,
2363 is_static=s).add_vpp_config()
2365 self.pg1.sw_if_index,
2366 self.pg1.remote_hosts[n].mac,
2367 self.pg1.remote_hosts[n].ip6,
2368 is_static=s).add_vpp_config()
2370 self.logger.info(self.vapi.cli("sh ip neighbor"))
2372 # flush both interfaces at the same time
2373 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2375 # check we haven't flushed that which we shouldn't
2376 for n in range(N_HOSTS):
2377 self.assertTrue(find_nbr(self,
2378 self.pg0.sw_if_index,
2379 self.pg0.remote_hosts[n].ip4,
2382 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2384 for n in range(N_HOSTS):
2385 self.assertFalse(find_nbr(self,
2386 self.pg0.sw_if_index,
2387 self.pg0.remote_hosts[n].ip4))
2388 self.assertFalse(find_nbr(self,
2389 self.pg1.sw_if_index,
2390 self.pg1.remote_hosts[n].ip6))
2393 if __name__ == '__main__':
2394 unittest.main(testRunner=VppTestRunner)