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,
1814 # apply a connected prefix to an interface in a different table
1815 VppIpRoute(self, "10.0.1.0", 24,
1816 [VppRoutePath("0.0.0.0",
1817 self.pg1.sw_if_index)],
1818 table_id=1).add_vpp_config()
1820 rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
1822 self.verify_arp_req(rx,
1828 conn3.remove_vpp_config()
1829 conn2.remove_vpp_config()
1832 @tag_fixme_vpp_workers
1833 class NeighborStatsTestCase(VppTestCase):
1834 """ ARP/ND Counters """
1837 def setUpClass(cls):
1838 super(NeighborStatsTestCase, cls).setUpClass()
1841 def tearDownClass(cls):
1842 super(NeighborStatsTestCase, cls).tearDownClass()
1845 super(NeighborStatsTestCase, self).setUp()
1847 self.create_pg_interfaces(range(2))
1849 # pg0 configured with ip4 and 6 addresses used for input
1850 # pg1 configured with ip4 and 6 addresses used for output
1851 # pg2 is unnumbered to pg0
1852 for i in self.pg_interfaces:
1860 super(NeighborStatsTestCase, self).tearDown()
1862 for i in self.pg_interfaces:
1867 def test_arp_stats(self):
1868 """ ARP Counters """
1870 self.vapi.cli("adj counters enable")
1871 self.pg1.generate_remote_hosts(2)
1873 arp1 = VppNeighbor(self,
1874 self.pg1.sw_if_index,
1875 self.pg1.remote_hosts[0].mac,
1876 self.pg1.remote_hosts[0].ip4)
1877 arp1.add_vpp_config()
1878 arp2 = VppNeighbor(self,
1879 self.pg1.sw_if_index,
1880 self.pg1.remote_hosts[1].mac,
1881 self.pg1.remote_hosts[1].ip4)
1882 arp2.add_vpp_config()
1884 p1 = (Ether(dst=self.pg0.local_mac,
1885 src=self.pg0.remote_mac) /
1886 IP(src=self.pg0.remote_ip4,
1887 dst=self.pg1.remote_hosts[0].ip4) /
1888 UDP(sport=1234, dport=1234) /
1890 p2 = (Ether(dst=self.pg0.local_mac,
1891 src=self.pg0.remote_mac) /
1892 IP(src=self.pg0.remote_ip4,
1893 dst=self.pg1.remote_hosts[1].ip4) /
1894 UDP(sport=1234, dport=1234) /
1897 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1898 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1900 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1901 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1903 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1904 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1906 def test_nd_stats(self):
1909 self.vapi.cli("adj counters enable")
1910 self.pg0.generate_remote_hosts(3)
1912 nd1 = VppNeighbor(self,
1913 self.pg0.sw_if_index,
1914 self.pg0.remote_hosts[1].mac,
1915 self.pg0.remote_hosts[1].ip6)
1916 nd1.add_vpp_config()
1917 nd2 = VppNeighbor(self,
1918 self.pg0.sw_if_index,
1919 self.pg0.remote_hosts[2].mac,
1920 self.pg0.remote_hosts[2].ip6)
1921 nd2.add_vpp_config()
1923 p1 = (Ether(dst=self.pg1.local_mac,
1924 src=self.pg1.remote_mac) /
1925 IPv6(src=self.pg1.remote_ip6,
1926 dst=self.pg0.remote_hosts[1].ip6) /
1927 UDP(sport=1234, dport=1234) /
1929 p2 = (Ether(dst=self.pg1.local_mac,
1930 src=self.pg1.remote_mac) /
1931 IPv6(src=self.pg1.remote_ip6,
1932 dst=self.pg0.remote_hosts[2].ip6) /
1933 UDP(sport=1234, dport=1234) /
1936 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1937 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1939 self.assertEqual(16, nd1.get_stats()['packets'])
1940 self.assertEqual(16, nd2.get_stats()['packets'])
1942 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1943 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1946 class NeighborAgeTestCase(VppTestCase):
1947 """ ARP/ND Aging """
1950 def setUpClass(cls):
1951 super(NeighborAgeTestCase, cls).setUpClass()
1954 def tearDownClass(cls):
1955 super(NeighborAgeTestCase, cls).tearDownClass()
1958 super(NeighborAgeTestCase, self).setUp()
1960 self.create_pg_interfaces(range(1))
1962 # pg0 configured with ip4 and 6 addresses used for input
1963 # pg1 configured with ip4 and 6 addresses used for output
1964 # pg2 is unnumbered to pg0
1965 for i in self.pg_interfaces:
1973 super(NeighborAgeTestCase, self).tearDown()
1975 for i in self.pg_interfaces:
1980 def wait_for_no_nbr(self, intf, address,
1981 n_tries=50, s_time=1):
1983 if not find_nbr(self, intf, address):
1985 n_tries = n_tries - 1
1990 def verify_arp_req(self, rx, smac, sip, dip):
1992 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1993 self.assertEqual(ether.src, smac)
1996 self.assertEqual(arp.hwtype, 1)
1997 self.assertEqual(arp.ptype, 0x800)
1998 self.assertEqual(arp.hwlen, 6)
1999 self.assertEqual(arp.plen, 4)
2000 self.assertEqual(arp.op, arp_opts["who-has"])
2001 self.assertEqual(arp.hwsrc, smac)
2002 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2003 self.assertEqual(arp.psrc, sip)
2004 self.assertEqual(arp.pdst, dip)
2007 """ Aging/Recycle """
2009 self.vapi.cli("set logging unthrottle 0")
2010 self.vapi.cli("set logging size %d" % 0xffff)
2012 self.pg0.generate_remote_hosts(201)
2014 vaf = VppEnum.vl_api_address_family_t
2017 # start listening on all interfaces
2019 self.pg_enable_capture(self.pg_interfaces)
2022 # Set the neighbor configuration:
2027 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2032 self.vapi.cli("sh ip neighbor-config")
2034 # add the 198 neighbours that should pass (-1 for one created in setup)
2035 for ii in range(200):
2037 self.pg0.sw_if_index,
2038 self.pg0.remote_hosts[ii].mac,
2039 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2041 # one more neighbor over the limit should fail
2042 with self.vapi.assert_negative_api_retval():
2044 self.pg0.sw_if_index,
2045 self.pg0.remote_hosts[200].mac,
2046 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2049 # change the config to allow recycling the old neighbors
2051 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2056 # now new additions are allowed
2058 self.pg0.sw_if_index,
2059 self.pg0.remote_hosts[200].mac,
2060 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2062 # add the first neighbor we configured has been re-used
2063 self.assertFalse(find_nbr(self,
2064 self.pg0.sw_if_index,
2065 self.pg0.remote_hosts[0].ip4))
2066 self.assertTrue(find_nbr(self,
2067 self.pg0.sw_if_index,
2068 self.pg0.remote_hosts[200].ip4))
2071 # change the config to age old neighbors
2073 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2078 self.vapi.cli("sh ip4 neighbor-sorted")
2081 # expect probes from all these ARP entries as they age
2082 # 3 probes for each neighbor 3*200 = 600
2083 rxs = self.pg0.get_capture(600, timeout=8)
2086 for jj in range(200):
2087 rx = rxs[ii*200 + jj]
2091 # 3 probes sent then 1 more second to see if a reply comes, before
2094 for jj in range(1, 201):
2095 self.wait_for_no_nbr(self.pg0.sw_if_index,
2096 self.pg0.remote_hosts[jj].ip4)
2098 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2099 af=vaf.ADDRESS_IP4))
2102 # load up some neighbours again with 2s aging enabled
2103 # they should be removed after 10s (2s age + 4s for probes + gap)
2104 # check for the add and remove events
2106 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2108 self.vapi.want_ip_neighbor_events_v2(enable=1)
2109 for ii in range(10):
2111 self.pg0.sw_if_index,
2112 self.pg0.remote_hosts[ii].mac,
2113 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2115 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2116 self.assertEqual(e.flags,
2117 enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2118 self.assertEqual(str(e.neighbor.ip_address),
2119 self.pg0.remote_hosts[ii].ip4)
2120 self.assertEqual(e.neighbor.mac_address,
2121 self.pg0.remote_hosts[ii].mac)
2124 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2125 af=vaf.ADDRESS_IP4))
2128 for ii in range(10):
2129 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2130 self.assertEqual(e.flags,
2131 enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2134 # check we got the correct mac/ip pairs - done separately
2135 # because we don't care about the order the remove notifications
2137 for ii in range(10):
2139 mac = self.pg0.remote_hosts[ii].mac
2140 ip = self.pg0.remote_hosts[ii].ip4
2143 if (e.neighbor.mac_address == mac and
2144 str(e.neighbor.ip_address) == ip):
2147 self.assertTrue(found)
2150 # check if we can set age and recycle with empty neighbor list
2152 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2158 # load up some neighbours again, then disable the aging
2159 # they should still be there in 10 seconds time
2161 for ii in range(10):
2163 self.pg0.sw_if_index,
2164 self.pg0.remote_hosts[ii].mac,
2165 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2166 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2172 self.assertTrue(find_nbr(self,
2173 self.pg0.sw_if_index,
2174 self.pg0.remote_hosts[0].ip4))
2177 class NeighborReplaceTestCase(VppTestCase):
2178 """ ARP/ND Replacement """
2181 def setUpClass(cls):
2182 super(NeighborReplaceTestCase, cls).setUpClass()
2185 def tearDownClass(cls):
2186 super(NeighborReplaceTestCase, cls).tearDownClass()
2189 super(NeighborReplaceTestCase, self).setUp()
2191 self.create_pg_interfaces(range(4))
2193 # pg0 configured with ip4 and 6 addresses used for input
2194 # pg1 configured with ip4 and 6 addresses used for output
2195 # pg2 is unnumbered to pg0
2196 for i in self.pg_interfaces:
2204 super(NeighborReplaceTestCase, self).tearDown()
2206 for i in self.pg_interfaces:
2211 def test_replace(self):
2216 for i in self.pg_interfaces:
2217 i.generate_remote_hosts(N_HOSTS)
2218 i.configure_ipv4_neighbors()
2219 i.configure_ipv6_neighbors()
2222 self.vapi.ip_neighbor_replace_begin()
2223 self.vapi.ip_neighbor_replace_end()
2225 for i in self.pg_interfaces:
2226 for h in range(N_HOSTS):
2227 self.assertFalse(find_nbr(self,
2228 self.pg0.sw_if_index,
2229 self.pg0.remote_hosts[h].ip4))
2230 self.assertFalse(find_nbr(self,
2231 self.pg0.sw_if_index,
2232 self.pg0.remote_hosts[h].ip6))
2235 # and them all back via the API
2237 for i in self.pg_interfaces:
2238 for h in range(N_HOSTS):
2241 i.remote_hosts[h].mac,
2242 i.remote_hosts[h].ip4).add_vpp_config()
2245 i.remote_hosts[h].mac,
2246 i.remote_hosts[h].ip6).add_vpp_config()
2249 # begin the replacement again, this time touch some
2250 # the neighbours on pg1 so they are not deleted
2252 self.vapi.ip_neighbor_replace_begin()
2254 # update from the API all neighbours on pg1
2255 for h in range(N_HOSTS):
2257 self.pg1.sw_if_index,
2258 self.pg1.remote_hosts[h].mac,
2259 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2261 self.pg1.sw_if_index,
2262 self.pg1.remote_hosts[h].mac,
2263 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2265 # update from the data-plane all neighbours on pg3
2266 self.pg3.configure_ipv4_neighbors()
2267 self.pg3.configure_ipv6_neighbors()
2269 # complete the replacement
2270 self.logger.info(self.vapi.cli("sh ip neighbors"))
2271 self.vapi.ip_neighbor_replace_end()
2273 for i in self.pg_interfaces:
2274 if i == self.pg1 or i == self.pg3:
2275 # neighbours on pg1 and pg3 are still present
2276 for h in range(N_HOSTS):
2277 self.assertTrue(find_nbr(self,
2279 i.remote_hosts[h].ip4))
2280 self.assertTrue(find_nbr(self,
2282 i.remote_hosts[h].ip6))
2284 # all other neighbours are toast
2285 for h in range(N_HOSTS):
2286 self.assertFalse(find_nbr(self,
2288 i.remote_hosts[h].ip4))
2289 self.assertFalse(find_nbr(self,
2291 i.remote_hosts[h].ip6))
2294 class NeighborFlush(VppTestCase):
2295 """ Neighbor Flush """
2298 def setUpClass(cls):
2299 super(NeighborFlush, cls).setUpClass()
2302 def tearDownClass(cls):
2303 super(NeighborFlush, cls).tearDownClass()
2306 super(NeighborFlush, self).setUp()
2308 self.create_pg_interfaces(range(2))
2310 for i in self.pg_interfaces:
2318 super(NeighborFlush, self).tearDown()
2320 for i in self.pg_interfaces:
2325 def test_flush(self):
2326 """ Neighbour Flush """
2329 nf = e.vl_api_ip_neighbor_flags_t
2330 af = e.vl_api_address_family_t
2332 static = [False, True]
2333 self.pg0.generate_remote_hosts(N_HOSTS)
2334 self.pg1.generate_remote_hosts(N_HOSTS)
2337 # a few v4 and v6 dynamic neoghbors
2338 for n in range(N_HOSTS):
2340 self.pg0.sw_if_index,
2341 self.pg0.remote_hosts[n].mac,
2342 self.pg0.remote_hosts[n].ip4,
2343 is_static=s).add_vpp_config()
2345 self.pg1.sw_if_index,
2346 self.pg1.remote_hosts[n].mac,
2347 self.pg1.remote_hosts[n].ip6,
2348 is_static=s).add_vpp_config()
2350 # flush the interfaces individually
2351 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2353 # check we haven't flushed that which we shouldn't
2354 for n in range(N_HOSTS):
2355 self.assertTrue(find_nbr(self,
2356 self.pg1.sw_if_index,
2357 self.pg1.remote_hosts[n].ip6,
2360 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2362 for n in range(N_HOSTS):
2363 self.assertFalse(find_nbr(self,
2364 self.pg0.sw_if_index,
2365 self.pg0.remote_hosts[n].ip4))
2366 self.assertFalse(find_nbr(self,
2367 self.pg1.sw_if_index,
2368 self.pg1.remote_hosts[n].ip6))
2370 # add the nieghbours back
2371 for n in range(N_HOSTS):
2373 self.pg0.sw_if_index,
2374 self.pg0.remote_hosts[n].mac,
2375 self.pg0.remote_hosts[n].ip4,
2376 is_static=s).add_vpp_config()
2378 self.pg1.sw_if_index,
2379 self.pg1.remote_hosts[n].mac,
2380 self.pg1.remote_hosts[n].ip6,
2381 is_static=s).add_vpp_config()
2383 self.logger.info(self.vapi.cli("sh ip neighbor"))
2385 # flush both interfaces at the same time
2386 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2388 # check we haven't flushed that which we shouldn't
2389 for n in range(N_HOSTS):
2390 self.assertTrue(find_nbr(self,
2391 self.pg0.sw_if_index,
2392 self.pg0.remote_hosts[n].ip4,
2395 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2397 for n in range(N_HOSTS):
2398 self.assertFalse(find_nbr(self,
2399 self.pg0.sw_if_index,
2400 self.pg0.remote_hosts[n].ip4))
2401 self.assertFalse(find_nbr(self,
2402 self.pg1.sw_if_index,
2403 self.pg1.remote_hosts[n].ip6))
2406 if __name__ == '__main__':
2407 unittest.main(testRunner=VppTestRunner)