5 from socket import AF_INET, AF_INET6, inet_pton
7 from framework import VppTestCase, VppTestRunner
8 from vpp_neighbor import VppNeighbor, find_nbr
9 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
10 VppIpTable, DpoProto, FibPathType, VppIpInterfaceAddress
11 from vpp_papi import VppEnum
12 from vpp_ip import VppIpPuntRedirect
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether, ARP, Dot1Q
17 from scapy.layers.inet import IP, UDP, TCP
18 from scapy.layers.inet6 import IPv6
19 from scapy.contrib.mpls import MPLS
20 from scapy.layers.inet6 import IPv6
25 # not exported by scapy, so redefined here
26 arp_opts = {"who-has": 1, "is-at": 2}
29 class ARPTestCase(VppTestCase):
34 super(ARPTestCase, cls).setUpClass()
37 def tearDownClass(cls):
38 super(ARPTestCase, cls).tearDownClass()
41 super(ARPTestCase, self).setUp()
43 # create 3 pg interfaces
44 self.create_pg_interfaces(range(4))
46 # pg0 configured with ip4 and 6 addresses used for input
47 # pg1 configured with ip4 and 6 addresses used for output
48 # pg2 is unnumbered to pg0
49 for i in self.pg_interfaces:
54 self.pg0.resolve_arp()
59 # pg3 in a different VRF
60 self.tbl = VppIpTable(self, 1)
61 self.tbl.add_vpp_config()
63 self.pg3.set_table_ip4(1)
67 self.pg0.unconfig_ip4()
68 self.pg0.unconfig_ip6()
70 self.pg1.unconfig_ip4()
71 self.pg1.unconfig_ip6()
73 self.pg3.unconfig_ip4()
74 self.pg3.set_table_ip4(0)
76 for i in self.pg_interfaces:
79 super(ARPTestCase, self).tearDown()
81 def verify_arp_req(self, rx, smac, sip, dip):
83 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
84 self.assertEqual(ether.src, smac)
85 self.assertEqual(ether.type, 0x0806)
88 self.assertEqual(arp.hwtype, 1)
89 self.assertEqual(arp.ptype, 0x800)
90 self.assertEqual(arp.hwlen, 6)
91 self.assertEqual(arp.plen, 4)
92 self.assertEqual(arp.op, arp_opts["who-has"])
93 self.assertEqual(arp.hwsrc, smac)
94 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
95 self.assertEqual(arp.psrc, sip)
96 self.assertEqual(arp.pdst, dip)
98 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
100 self.assertEqual(ether.dst, dmac)
101 self.assertEqual(ether.src, smac)
102 self.assertEqual(ether.type, 0x0806)
105 self.assertEqual(arp.hwtype, 1)
106 self.assertEqual(arp.ptype, 0x800)
107 self.assertEqual(arp.hwlen, 6)
108 self.assertEqual(arp.plen, 4)
109 self.assertEqual(arp.op, arp_opts["is-at"])
110 self.assertEqual(arp.hwsrc, smac)
111 self.assertEqual(arp.hwdst, dmac)
112 self.assertEqual(arp.psrc, sip)
113 self.assertEqual(arp.pdst, dip)
115 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
117 self.assertEqual(ether.dst, dmac)
118 self.assertEqual(ether.src, smac)
121 self.assertEqual(arp.hwtype, 1)
122 self.assertEqual(arp.ptype, 0x800)
123 self.assertEqual(arp.hwlen, 6)
124 self.assertEqual(arp.plen, 4)
125 self.assertEqual(arp.op, arp_opts["is-at"])
126 self.assertNotEqual(arp.hwsrc, smac)
127 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
128 "00:00:5E:00:01" in arp.hwsrc)
129 self.assertEqual(arp.hwdst, dmac)
130 self.assertEqual(arp.psrc, sip)
131 self.assertEqual(arp.pdst, dip)
133 def verify_ip(self, rx, smac, dmac, sip, dip):
135 self.assertEqual(ether.dst, dmac)
136 self.assertEqual(ether.src, smac)
137 self.assertEqual(ether.type, 0x0800)
140 self.assertEqual(ip.src, sip)
141 self.assertEqual(ip.dst, dip)
143 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
145 self.assertEqual(ether.dst, dmac)
146 self.assertEqual(ether.src, smac)
147 self.assertEqual(ether.type, 0x8847)
150 self.assertTrue(mpls.label, label)
153 self.assertEqual(ip.src, sip)
154 self.assertEqual(ip.dst, dip)
160 # Generate some hosts on the LAN
162 self.pg1.generate_remote_hosts(11)
166 # - all neighbour events
167 # - all neighbor events on pg1
168 # - neighbor events for host[1] on pg1
170 self.vapi.want_ip_neighbor_events(enable=1,
172 self.vapi.want_ip_neighbor_events(enable=1,
174 sw_if_index=self.pg1.sw_if_index)
175 self.vapi.want_ip_neighbor_events(enable=1,
177 sw_if_index=self.pg1.sw_if_index,
178 ip=self.pg1.remote_hosts[1].ip4)
180 self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
183 # Send IP traffic to one of these unresolved hosts.
184 # expect the generation of an ARP request
186 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
187 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
188 UDP(sport=1234, dport=1234) /
191 self.pg0.add_stream(p)
192 self.pg_enable_capture(self.pg_interfaces)
195 rx = self.pg1.get_capture(1)
197 self.verify_arp_req(rx[0],
200 self.pg1._remote_hosts[1].ip4)
203 # And a dynamic ARP entry for host 1
205 dyn_arp = VppNeighbor(self,
206 self.pg1.sw_if_index,
207 self.pg1.remote_hosts[1].mac,
208 self.pg1.remote_hosts[1].ip4)
209 dyn_arp.add_vpp_config()
210 self.assertTrue(dyn_arp.query_vpp_config())
212 self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
214 # this matches all of the listnerers
215 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
218 self.assertEqual(str(e.neighbor.ip_address),
219 self.pg1.remote_hosts[1].ip4)
222 # now we expect IP traffic forwarded
224 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
225 IP(src=self.pg0.remote_ip4,
226 dst=self.pg1._remote_hosts[1].ip4) /
227 UDP(sport=1234, dport=1234) /
230 self.pg0.add_stream(dyn_p)
231 self.pg_enable_capture(self.pg_interfaces)
234 rx = self.pg1.get_capture(1)
236 self.verify_ip(rx[0],
238 self.pg1.remote_hosts[1].mac,
240 self.pg1._remote_hosts[1].ip4)
243 # And a Static ARP entry for host 2
245 static_arp = VppNeighbor(self,
246 self.pg1.sw_if_index,
247 self.pg1.remote_hosts[2].mac,
248 self.pg1.remote_hosts[2].ip4,
250 static_arp.add_vpp_config()
251 es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
254 self.assertEqual(str(e.neighbor.ip_address),
255 self.pg1.remote_hosts[2].ip4)
257 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
258 IP(src=self.pg0.remote_ip4,
259 dst=self.pg1._remote_hosts[2].ip4) /
260 UDP(sport=1234, dport=1234) /
263 self.pg0.add_stream(static_p)
264 self.pg_enable_capture(self.pg_interfaces)
267 rx = self.pg1.get_capture(1)
269 self.verify_ip(rx[0],
271 self.pg1.remote_hosts[2].mac,
273 self.pg1._remote_hosts[2].ip4)
276 # remove all the listeners
278 self.vapi.want_ip_neighbor_events(enable=0,
280 self.vapi.want_ip_neighbor_events(enable=0,
282 sw_if_index=self.pg1.sw_if_index)
283 self.vapi.want_ip_neighbor_events(enable=0,
285 sw_if_index=self.pg1.sw_if_index,
286 ip=self.pg1.remote_hosts[1].ip4)
289 # flap the link. dynamic ARPs get flush, statics don't
291 self.pg1.admin_down()
294 self.pg0.add_stream(static_p)
295 self.pg_enable_capture(self.pg_interfaces)
297 rx = self.pg1.get_capture(1)
299 self.verify_ip(rx[0],
301 self.pg1.remote_hosts[2].mac,
303 self.pg1._remote_hosts[2].ip4)
305 self.pg0.add_stream(dyn_p)
306 self.pg_enable_capture(self.pg_interfaces)
309 rx = self.pg1.get_capture(1)
310 self.verify_arp_req(rx[0],
313 self.pg1._remote_hosts[1].ip4)
315 self.assertFalse(dyn_arp.query_vpp_config())
316 self.assertTrue(static_arp.query_vpp_config())
318 # Send an ARP request from one of the so-far unlearned remote hosts
320 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
321 src=self.pg1._remote_hosts[3].mac) /
323 hwsrc=self.pg1._remote_hosts[3].mac,
324 pdst=self.pg1.local_ip4,
325 psrc=self.pg1._remote_hosts[3].ip4))
327 self.pg1.add_stream(p)
328 self.pg_enable_capture(self.pg_interfaces)
331 rx = self.pg1.get_capture(1)
332 self.verify_arp_resp(rx[0],
334 self.pg1._remote_hosts[3].mac,
336 self.pg1._remote_hosts[3].ip4)
339 # VPP should have learned the mapping for the remote host
341 self.assertTrue(find_nbr(self,
342 self.pg1.sw_if_index,
343 self.pg1._remote_hosts[3].ip4))
345 # Fire in an ARP request before the interface becomes IP enabled
347 self.pg2.generate_remote_hosts(4)
349 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
351 hwsrc=self.pg2.remote_mac,
352 pdst=self.pg1.local_ip4,
353 psrc=self.pg2.remote_hosts[3].ip4))
354 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
357 hwsrc=self.pg2.remote_mac,
358 pdst=self.pg1.local_ip4,
359 psrc=self.pg2.remote_hosts[3].ip4))
360 self.send_and_assert_no_replies(self.pg2, p,
361 "interface not IP enabled")
364 # Make pg2 un-numbered to pg1
366 self.pg2.set_unnumbered(self.pg1.sw_if_index)
369 # test the unnumbered dump both by all interfaces and just the enabled
372 unnum = self.vapi.ip_unnumbered_dump()
373 self.assertTrue(len(unnum))
374 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
375 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
376 unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
377 self.assertTrue(len(unnum))
378 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
379 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
382 # We should respond to ARP requests for the unnumbered to address
383 # once an attached route to the source is known
385 self.send_and_assert_no_replies(
387 "ARP req for unnumbered address - no source")
389 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
390 [VppRoutePath("0.0.0.0",
391 self.pg2.sw_if_index)])
392 attached_host.add_vpp_config()
394 self.pg2.add_stream(p)
395 self.pg_enable_capture(self.pg_interfaces)
398 rx = self.pg2.get_capture(1)
399 self.verify_arp_resp(rx[0],
403 self.pg2.remote_hosts[3].ip4)
405 self.pg2.add_stream(pt)
406 self.pg_enable_capture(self.pg_interfaces)
409 rx = self.pg2.get_capture(1)
410 self.verify_arp_resp(rx[0],
414 self.pg2.remote_hosts[3].ip4)
417 # A neighbor entry that has no associated FIB-entry
419 arp_no_fib = VppNeighbor(self,
420 self.pg1.sw_if_index,
421 self.pg1.remote_hosts[4].mac,
422 self.pg1.remote_hosts[4].ip4,
424 arp_no_fib.add_vpp_config()
427 # check we have the neighbor, but no route
429 self.assertTrue(find_nbr(self,
430 self.pg1.sw_if_index,
431 self.pg1._remote_hosts[4].ip4))
432 self.assertFalse(find_route(self,
433 self.pg1._remote_hosts[4].ip4,
436 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
437 # from within pg1's subnet
439 arp_unnum = VppNeighbor(self,
440 self.pg2.sw_if_index,
441 self.pg1.remote_hosts[5].mac,
442 self.pg1.remote_hosts[5].ip4)
443 arp_unnum.add_vpp_config()
445 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
446 IP(src=self.pg0.remote_ip4,
447 dst=self.pg1._remote_hosts[5].ip4) /
448 UDP(sport=1234, dport=1234) /
451 self.pg0.add_stream(p)
452 self.pg_enable_capture(self.pg_interfaces)
455 rx = self.pg2.get_capture(1)
457 self.verify_ip(rx[0],
459 self.pg1.remote_hosts[5].mac,
461 self.pg1._remote_hosts[5].ip4)
464 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
465 # with the unnumbered interface's address as the source
467 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
469 hwsrc=self.pg2.remote_mac,
470 pdst=self.pg1.local_ip4,
471 psrc=self.pg1.remote_hosts[6].ip4))
473 self.pg2.add_stream(p)
474 self.pg_enable_capture(self.pg_interfaces)
477 rx = self.pg2.get_capture(1)
478 self.verify_arp_resp(rx[0],
482 self.pg1.remote_hosts[6].ip4)
485 # An attached host route out of pg2 for an undiscovered hosts generates
486 # an ARP request with the unnumbered address as the source
488 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
489 [VppRoutePath("0.0.0.0",
490 self.pg2.sw_if_index)])
491 att_unnum.add_vpp_config()
493 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
494 IP(src=self.pg0.remote_ip4,
495 dst=self.pg1._remote_hosts[7].ip4) /
496 UDP(sport=1234, dport=1234) /
499 self.pg0.add_stream(p)
500 self.pg_enable_capture(self.pg_interfaces)
503 rx = self.pg2.get_capture(1)
505 self.verify_arp_req(rx[0],
508 self.pg1._remote_hosts[7].ip4)
510 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
512 hwsrc=self.pg2.remote_mac,
513 pdst=self.pg1.local_ip4,
514 psrc=self.pg1.remote_hosts[7].ip4))
516 self.pg2.add_stream(p)
517 self.pg_enable_capture(self.pg_interfaces)
520 rx = self.pg2.get_capture(1)
521 self.verify_arp_resp(rx[0],
525 self.pg1.remote_hosts[7].ip4)
528 # An attached host route as yet unresolved out of pg2 for an
529 # undiscovered host, an ARP requests begets a response.
531 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
532 [VppRoutePath("0.0.0.0",
533 self.pg2.sw_if_index)])
534 att_unnum1.add_vpp_config()
536 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
538 hwsrc=self.pg2.remote_mac,
539 pdst=self.pg1.local_ip4,
540 psrc=self.pg1.remote_hosts[8].ip4))
542 self.pg2.add_stream(p)
543 self.pg_enable_capture(self.pg_interfaces)
546 rx = self.pg2.get_capture(1)
547 self.verify_arp_resp(rx[0],
551 self.pg1.remote_hosts[8].ip4)
554 # Send an ARP request from one of the so-far unlearned remote hosts
557 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
558 src=self.pg1._remote_hosts[9].mac) /
561 hwsrc=self.pg1._remote_hosts[9].mac,
562 pdst=self.pg1.local_ip4,
563 psrc=self.pg1._remote_hosts[9].ip4))
565 self.pg1.add_stream(p)
566 self.pg_enable_capture(self.pg_interfaces)
569 rx = self.pg1.get_capture(1)
570 self.verify_arp_resp(rx[0],
572 self.pg1._remote_hosts[9].mac,
574 self.pg1._remote_hosts[9].ip4)
577 # Add a hierarchy of routes for a host in the sub-net.
578 # Should still get an ARP resp since the cover is attached
580 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
582 hwsrc=self.pg1.remote_mac,
583 pdst=self.pg1.local_ip4,
584 psrc=self.pg1.remote_hosts[10].ip4))
586 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
587 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
588 self.pg1.sw_if_index)])
591 self.pg1.add_stream(p)
592 self.pg_enable_capture(self.pg_interfaces)
594 rx = self.pg1.get_capture(1)
595 self.verify_arp_resp(rx[0],
599 self.pg1.remote_hosts[10].ip4)
601 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
602 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
603 self.pg1.sw_if_index)])
606 self.pg1.add_stream(p)
607 self.pg_enable_capture(self.pg_interfaces)
609 rx = self.pg1.get_capture(1)
610 self.verify_arp_resp(rx[0],
614 self.pg1.remote_hosts[10].ip4)
617 # add an ARP entry that's not on the sub-net and so whose
618 # adj-fib fails the refinement check. then send an ARP request
621 a1 = VppNeighbor(self,
622 self.pg0.sw_if_index,
627 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
629 hwsrc=self.pg0.remote_mac,
630 psrc="100.100.100.50",
631 pdst=self.pg0.remote_ip4))
632 self.send_and_assert_no_replies(self.pg0, p,
633 "ARP req for from failed adj-fib")
637 # 1 - don't respond to ARP request for address not within the
638 # interface's sub-net
639 # 1b - nor within the unnumbered subnet
640 # 1c - nor within the subnet of a different interface
642 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
644 hwsrc=self.pg0.remote_mac,
646 psrc=self.pg0.remote_ip4))
647 self.send_and_assert_no_replies(self.pg0, p,
648 "ARP req for non-local destination")
649 self.assertFalse(find_nbr(self,
650 self.pg0.sw_if_index,
653 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
655 hwsrc=self.pg2.remote_mac,
657 psrc=self.pg1.remote_hosts[7].ip4))
658 self.send_and_assert_no_replies(
660 "ARP req for non-local destination - unnum")
662 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
664 hwsrc=self.pg0.remote_mac,
665 pdst=self.pg1.local_ip4,
666 psrc=self.pg1.remote_ip4))
667 self.send_and_assert_no_replies(self.pg0, p,
668 "ARP req diff sub-net")
669 self.assertFalse(find_nbr(self,
670 self.pg0.sw_if_index,
671 self.pg1.remote_ip4))
674 # 2 - don't respond to ARP request from an address not within the
675 # interface's sub-net
676 # 2b - to a proxied address
677 # 2c - not within a different interface's sub-net
678 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
680 hwsrc=self.pg0.remote_mac,
682 pdst=self.pg0.local_ip4))
683 self.send_and_assert_no_replies(self.pg0, p,
684 "ARP req for non-local source")
685 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
687 hwsrc=self.pg2.remote_mac,
689 pdst=self.pg0.local_ip4))
690 self.send_and_assert_no_replies(
692 "ARP req for non-local source - unnum")
693 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
695 hwsrc=self.pg0.remote_mac,
696 psrc=self.pg1.remote_ip4,
697 pdst=self.pg0.local_ip4))
698 self.send_and_assert_no_replies(self.pg0, p,
699 "ARP req for non-local source 2c")
702 # 3 - don't respond to ARP request from an address that belongs to
705 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
707 hwsrc=self.pg0.remote_mac,
708 psrc=self.pg0.local_ip4,
709 pdst=self.pg0.local_ip4))
710 self.send_and_assert_no_replies(self.pg0, p,
711 "ARP req for non-local source")
714 # 4 - don't respond to ARP requests that has mac source different
715 # from ARP request HW source
717 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
719 hwsrc="00:00:00:DE:AD:BE",
720 psrc=self.pg0.remote_ip4,
721 pdst=self.pg0.local_ip4))
722 self.send_and_assert_no_replies(self.pg0, p,
723 "ARP req for non-local source")
726 # 5 - don't respond to ARP requests for address within the
727 # interface's sub-net but not the interface's address
729 self.pg0.generate_remote_hosts(2)
730 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
732 hwsrc=self.pg0.remote_mac,
733 psrc=self.pg0.remote_hosts[0].ip4,
734 pdst=self.pg0.remote_hosts[1].ip4))
735 self.send_and_assert_no_replies(self.pg0, p,
736 "ARP req for non-local destination")
741 static_arp.remove_vpp_config()
742 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
744 # need this to flush the adj-fibs
745 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
746 self.pg2.admin_down()
747 self.pg1.admin_down()
749 def test_proxy_mirror_arp(self):
750 """ Interface Mirror Proxy ARP """
753 # When VPP has an interface whose address is also applied to a TAP
754 # interface on the host, then VPP's TAP interface will be unnumbered
755 # to the 'real' interface and do proxy ARP from the host.
756 # the curious aspect of this setup is that ARP requests from the host
757 # will come from the VPP's own address.
759 self.pg0.generate_remote_hosts(2)
761 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
762 dst="ff:ff:ff:ff:ff:ff") /
764 hwsrc=self.pg2.remote_mac,
765 pdst=self.pg0.remote_hosts[1].ip4,
766 psrc=self.pg0.local_ip4))
769 # Configure Proxy ARP for the subnet on PG0addresses on pg0
771 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
772 'low': self.pg0._local_ip4_subnet,
773 'hi': self.pg0._local_ip4_bcast},
776 # Make pg2 un-numbered to pg0
778 self.pg2.set_unnumbered(self.pg0.sw_if_index)
781 # Enable pg2 for proxy ARP
783 self.pg2.set_proxy_arp()
786 # Send the ARP request with an originating address that
787 # is VPP's own address
789 rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
790 self.verify_arp_resp(rx[0],
793 self.pg0.remote_hosts[1].ip4,
797 # validate we have not learned an ARP entry as a result of this
799 self.assertFalse(find_nbr(self,
800 self.pg2.sw_if_index,
804 # setup a punt redirect so packets from the uplink go to the tap
806 redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index,
807 self.pg2.sw_if_index, self.pg0.local_ip4)
808 redirect.add_vpp_config()
810 p_tcp = (Ether(src=self.pg0.remote_mac,
811 dst=self.pg0.local_mac,) /
812 IP(src=self.pg0.remote_ip4,
813 dst=self.pg0.local_ip4) /
814 TCP(sport=80, dport=80) /
816 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
818 # there's no ARP entry so this is an ARP req
819 self.assertTrue(rx[0].haslayer(ARP))
821 # and ARP entry for VPP's pg0 address on the host interface
822 n1 = VppNeighbor(self,
823 self.pg2.sw_if_index,
826 is_no_fib_entry=True).add_vpp_config()
827 # now the packets shold forward
828 rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
829 self.assertFalse(rx[0].haslayer(ARP))
830 self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
833 # flush the neighbor cache on the uplink
835 af = VppEnum.vl_api_address_family_t
836 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
838 # ensure we can still resolve the ARPs on the uplink
839 self.pg0.resolve_arp()
841 self.assertTrue(find_nbr(self,
842 self.pg0.sw_if_index,
843 self.pg0.remote_ip4))
848 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
849 'low': self.pg0._local_ip4_subnet,
850 'hi': self.pg0._local_ip4_bcast},
852 redirect.remove_vpp_config()
854 def test_proxy_arp(self):
857 self.pg1.generate_remote_hosts(2)
860 # Proxy ARP request packets for each interface
862 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
863 dst="ff:ff:ff:ff:ff:ff") /
865 hwsrc=self.pg0.remote_mac,
867 psrc=self.pg0.remote_ip4))
868 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
869 dst="ff:ff:ff:ff:ff:ff") /
872 hwsrc=self.pg0.remote_mac,
874 psrc=self.pg0.remote_ip4))
875 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
876 dst="ff:ff:ff:ff:ff:ff") /
878 hwsrc=self.pg1.remote_mac,
880 psrc=self.pg1.remote_ip4))
881 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
882 dst="ff:ff:ff:ff:ff:ff") /
884 hwsrc=self.pg2.remote_mac,
886 psrc=self.pg1.remote_hosts[1].ip4))
887 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
888 dst="ff:ff:ff:ff:ff:ff") /
890 hwsrc=self.pg3.remote_mac,
892 psrc=self.pg3.remote_ip4))
895 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
897 self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
899 'hi': "10.10.10.124"},
903 # No responses are sent when the interfaces are not enabled for proxy
906 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
907 "ARP req from unconfigured interface")
908 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
909 "ARP req from unconfigured interface")
912 # Make pg2 un-numbered to pg1
915 self.pg2.set_unnumbered(self.pg1.sw_if_index)
917 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
918 "ARP req from unnumbered interface")
921 # Enable each interface to reply to proxy ARPs
923 for i in self.pg_interfaces:
927 # Now each of the interfaces should reply to a request to a proxied
930 self.pg0.add_stream(arp_req_pg0)
931 self.pg_enable_capture(self.pg_interfaces)
934 rx = self.pg0.get_capture(1)
935 self.verify_arp_resp(rx[0],
941 self.pg0.add_stream(arp_req_pg0_tagged)
942 self.pg_enable_capture(self.pg_interfaces)
945 rx = self.pg0.get_capture(1)
946 self.verify_arp_resp(rx[0],
952 self.pg1.add_stream(arp_req_pg1)
953 self.pg_enable_capture(self.pg_interfaces)
956 rx = self.pg1.get_capture(1)
957 self.verify_arp_resp(rx[0],
963 self.pg2.add_stream(arp_req_pg2)
964 self.pg_enable_capture(self.pg_interfaces)
967 rx = self.pg2.get_capture(1)
968 self.verify_arp_resp(rx[0],
972 self.pg1.remote_hosts[1].ip4)
975 # A request for an address out of the configured range
977 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
978 dst="ff:ff:ff:ff:ff:ff") /
980 hwsrc=self.pg1.remote_mac,
982 psrc=self.pg1.remote_ip4))
983 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
984 "ARP req out of range HI")
985 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
986 dst="ff:ff:ff:ff:ff:ff") /
988 hwsrc=self.pg1.remote_mac,
990 psrc=self.pg1.remote_ip4))
991 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
992 "ARP req out of range Low")
995 # Request for an address in the proxy range but from an interface
998 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
999 "ARP req from different VRF")
1002 # Disable Each interface for proxy ARP
1003 # - expect none to respond
1005 for i in self.pg_interfaces:
1008 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
1009 "ARP req from disable")
1010 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1011 "ARP req from disable")
1012 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1013 "ARP req from disable")
1016 # clean up on interface 2
1018 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1020 def test_mpls(self):
1024 # Interface 2 does not yet have ip4 config
1026 self.pg2.config_ip4()
1027 self.pg2.generate_remote_hosts(2)
1030 # Add a route with out going label via an ARP unresolved next-hop
1032 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1033 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1034 self.pg2.sw_if_index,
1036 ip_10_0_0_1.add_vpp_config()
1039 # packets should generate an ARP request
1041 p = (Ether(src=self.pg0.remote_mac,
1042 dst=self.pg0.local_mac) /
1043 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1044 UDP(sport=1234, dport=1234) /
1047 self.pg0.add_stream(p)
1048 self.pg_enable_capture(self.pg_interfaces)
1051 rx = self.pg2.get_capture(1)
1052 self.verify_arp_req(rx[0],
1055 self.pg2._remote_hosts[1].ip4)
1058 # now resolve the neighbours
1060 self.pg2.configure_ipv4_neighbors()
1063 # Now packet should be properly MPLS encapped.
1064 # This verifies that MPLS link-type adjacencies are completed
1065 # when the ARP entry resolves
1067 self.pg0.add_stream(p)
1068 self.pg_enable_capture(self.pg_interfaces)
1071 rx = self.pg2.get_capture(1)
1072 self.verify_ip_o_mpls(rx[0],
1074 self.pg2.remote_hosts[1].mac,
1076 self.pg0.remote_ip4,
1078 self.pg2.unconfig_ip4()
1080 def test_arp_vrrp(self):
1081 """ ARP reply with VRRP virtual src hw addr """
1084 # IP packet destined for pg1 remote host arrives on pg0 resulting
1085 # in an ARP request for the address of the remote host on pg1
1087 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1088 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1089 UDP(sport=1234, dport=1234) /
1092 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1094 self.verify_arp_req(rx1[0],
1097 self.pg1.remote_ip4)
1100 # ARP reply for address of pg1 remote host arrives on pg1 with
1101 # the hw src addr set to a value in the VRRP IPv4 range of
1104 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1105 ARP(op="is-at", hwdst=self.pg1.local_mac,
1106 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1107 psrc=self.pg1.remote_ip4))
1109 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1112 # IP packet destined for pg1 remote host arrives on pg0 again.
1113 # VPP should have an ARP entry for that address now and the packet
1114 # should be sent out pg1.
1116 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1118 self.verify_ip(rx1[0],
1120 "00:00:5e:00:01:09",
1121 self.pg0.remote_ip4,
1122 self.pg1.remote_ip4)
1124 self.pg1.admin_down()
1127 def test_arp_duplicates(self):
1128 """ ARP Duplicates"""
1131 # Generate some hosts on the LAN
1133 self.pg1.generate_remote_hosts(3)
1136 # Add host 1 on pg1 and pg2
1138 arp_pg1 = VppNeighbor(self,
1139 self.pg1.sw_if_index,
1140 self.pg1.remote_hosts[1].mac,
1141 self.pg1.remote_hosts[1].ip4)
1142 arp_pg1.add_vpp_config()
1143 arp_pg2 = VppNeighbor(self,
1144 self.pg2.sw_if_index,
1145 self.pg2.remote_mac,
1146 self.pg1.remote_hosts[1].ip4)
1147 arp_pg2.add_vpp_config()
1150 # IP packet destined for pg1 remote host arrives on pg1 again.
1152 p = (Ether(dst=self.pg0.local_mac,
1153 src=self.pg0.remote_mac) /
1154 IP(src=self.pg0.remote_ip4,
1155 dst=self.pg1.remote_hosts[1].ip4) /
1156 UDP(sport=1234, dport=1234) /
1159 self.pg0.add_stream(p)
1160 self.pg_enable_capture(self.pg_interfaces)
1163 rx1 = self.pg1.get_capture(1)
1165 self.verify_ip(rx1[0],
1167 self.pg1.remote_hosts[1].mac,
1168 self.pg0.remote_ip4,
1169 self.pg1.remote_hosts[1].ip4)
1172 # remove the duplicate on pg1
1173 # packet stream should generate ARPs out of pg1
1175 arp_pg1.remove_vpp_config()
1177 self.pg0.add_stream(p)
1178 self.pg_enable_capture(self.pg_interfaces)
1181 rx1 = self.pg1.get_capture(1)
1183 self.verify_arp_req(rx1[0],
1186 self.pg1.remote_hosts[1].ip4)
1191 arp_pg1.add_vpp_config()
1193 self.pg0.add_stream(p)
1194 self.pg_enable_capture(self.pg_interfaces)
1197 rx1 = self.pg1.get_capture(1)
1199 self.verify_ip(rx1[0],
1201 self.pg1.remote_hosts[1].mac,
1202 self.pg0.remote_ip4,
1203 self.pg1.remote_hosts[1].ip4)
1205 def test_arp_static(self):
1207 self.pg2.generate_remote_hosts(3)
1210 # Add a static ARP entry
1212 static_arp = VppNeighbor(self,
1213 self.pg2.sw_if_index,
1214 self.pg2.remote_hosts[1].mac,
1215 self.pg2.remote_hosts[1].ip4,
1217 static_arp.add_vpp_config()
1220 # Add the connected prefix to the interface
1222 self.pg2.config_ip4()
1225 # We should now find the adj-fib
1227 self.assertTrue(find_nbr(self,
1228 self.pg2.sw_if_index,
1229 self.pg2.remote_hosts[1].ip4,
1231 self.assertTrue(find_route(self,
1232 self.pg2.remote_hosts[1].ip4,
1236 # remove the connected
1238 self.pg2.unconfig_ip4()
1241 # put the interface into table 1
1243 self.pg2.set_table_ip4(1)
1246 # configure the same connected and expect to find the
1247 # adj fib in the new table
1249 self.pg2.config_ip4()
1250 self.assertTrue(find_route(self,
1251 self.pg2.remote_hosts[1].ip4,
1258 self.pg2.unconfig_ip4()
1259 static_arp.remove_vpp_config()
1260 self.pg2.set_table_ip4(0)
1262 def test_arp_static_replace_dynamic_same_mac(self):
1263 """ ARP Static can replace Dynamic (same mac) """
1264 self.pg2.generate_remote_hosts(1)
1266 dyn_arp = VppNeighbor(self,
1267 self.pg2.sw_if_index,
1268 self.pg2.remote_hosts[0].mac,
1269 self.pg2.remote_hosts[0].ip4)
1270 static_arp = VppNeighbor(self,
1271 self.pg2.sw_if_index,
1272 self.pg2.remote_hosts[0].mac,
1273 self.pg2.remote_hosts[0].ip4,
1277 # Add a dynamic ARP entry
1279 dyn_arp.add_vpp_config()
1282 # We should find the dynamic nbr
1284 self.assertFalse(find_nbr(self,
1285 self.pg2.sw_if_index,
1286 self.pg2.remote_hosts[0].ip4,
1288 self.assertTrue(find_nbr(self,
1289 self.pg2.sw_if_index,
1290 self.pg2.remote_hosts[0].ip4,
1292 mac=self.pg2.remote_hosts[0].mac))
1295 # Add a static ARP entry with the same mac
1297 static_arp.add_vpp_config()
1300 # We should now find the static nbr with the same mac
1302 self.assertFalse(find_nbr(self,
1303 self.pg2.sw_if_index,
1304 self.pg2.remote_hosts[0].ip4,
1306 self.assertTrue(find_nbr(self,
1307 self.pg2.sw_if_index,
1308 self.pg2.remote_hosts[0].ip4,
1310 mac=self.pg2.remote_hosts[0].mac))
1315 static_arp.remove_vpp_config()
1317 def test_arp_static_replace_dynamic_diff_mac(self):
1318 """ ARP Static can replace Dynamic (diff mac) """
1319 self.pg2.generate_remote_hosts(2)
1321 dyn_arp = VppNeighbor(self,
1322 self.pg2.sw_if_index,
1323 self.pg2.remote_hosts[0].mac,
1324 self.pg2.remote_hosts[0].ip4)
1325 static_arp = VppNeighbor(self,
1326 self.pg2.sw_if_index,
1327 self.pg2.remote_hosts[1].mac,
1328 self.pg2.remote_hosts[0].ip4,
1332 # Add a dynamic ARP entry
1334 dyn_arp.add_vpp_config()
1337 # We should find the dynamic nbr
1339 self.assertFalse(find_nbr(self,
1340 self.pg2.sw_if_index,
1341 self.pg2.remote_hosts[0].ip4,
1343 self.assertTrue(find_nbr(self,
1344 self.pg2.sw_if_index,
1345 self.pg2.remote_hosts[0].ip4,
1347 mac=self.pg2.remote_hosts[0].mac))
1350 # Add a static ARP entry with a changed mac
1352 static_arp.add_vpp_config()
1355 # We should now find the static nbr with a changed mac
1357 self.assertFalse(find_nbr(self,
1358 self.pg2.sw_if_index,
1359 self.pg2.remote_hosts[0].ip4,
1361 self.assertTrue(find_nbr(self,
1362 self.pg2.sw_if_index,
1363 self.pg2.remote_hosts[0].ip4,
1365 mac=self.pg2.remote_hosts[1].mac))
1370 static_arp.remove_vpp_config()
1372 def test_arp_incomplete(self):
1373 """ ARP Incomplete"""
1374 self.pg1.generate_remote_hosts(3)
1376 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1377 IP(src=self.pg0.remote_ip4,
1378 dst=self.pg1.remote_hosts[1].ip4) /
1379 UDP(sport=1234, dport=1234) /
1381 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1382 IP(src=self.pg0.remote_ip4,
1383 dst=self.pg1.remote_hosts[2].ip4) /
1384 UDP(sport=1234, dport=1234) /
1388 # a packet to an unresolved destination generates an ARP request
1390 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1391 self.verify_arp_req(rx[0],
1394 self.pg1._remote_hosts[1].ip4)
1397 # add a neighbour for remote host 1
1399 static_arp = VppNeighbor(self,
1400 self.pg1.sw_if_index,
1401 self.pg1.remote_hosts[1].mac,
1402 self.pg1.remote_hosts[1].ip4,
1404 static_arp.add_vpp_config()
1407 # change the interface's MAC
1409 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1410 "00:00:00:33:33:33")
1413 # now ARP requests come from the new source mac
1415 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1416 self.verify_arp_req(rx[0],
1417 "00:00:00:33:33:33",
1419 self.pg1._remote_hosts[2].ip4)
1422 # packets to the resolved host also have the new source mac
1424 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1425 self.verify_ip(rx[0],
1426 "00:00:00:33:33:33",
1427 self.pg1.remote_hosts[1].mac,
1428 self.pg0.remote_ip4,
1429 self.pg1.remote_hosts[1].ip4)
1432 # set the mac address on the interface that does not have a
1433 # configured subnet and thus no glean
1435 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1436 "00:00:00:33:33:33")
1438 def test_garp(self):
1442 # Generate some hosts on the LAN
1444 self.pg1.generate_remote_hosts(4)
1445 self.pg2.generate_remote_hosts(4)
1450 arp = VppNeighbor(self,
1451 self.pg1.sw_if_index,
1452 self.pg1.remote_hosts[1].mac,
1453 self.pg1.remote_hosts[1].ip4)
1454 arp.add_vpp_config()
1456 self.assertTrue(find_nbr(self,
1457 self.pg1.sw_if_index,
1458 self.pg1.remote_hosts[1].ip4,
1459 mac=self.pg1.remote_hosts[1].mac))
1462 # Send a GARP (request) to swap the host 1's address to that of host 2
1464 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1465 src=self.pg1.remote_hosts[2].mac) /
1467 hwdst=self.pg1.local_mac,
1468 hwsrc=self.pg1.remote_hosts[2].mac,
1469 pdst=self.pg1.remote_hosts[1].ip4,
1470 psrc=self.pg1.remote_hosts[1].ip4))
1472 self.pg1.add_stream(p1)
1473 self.pg_enable_capture(self.pg_interfaces)
1476 self.assertTrue(find_nbr(self,
1477 self.pg1.sw_if_index,
1478 self.pg1.remote_hosts[1].ip4,
1479 mac=self.pg1.remote_hosts[2].mac))
1482 # Send a GARP (reply) to swap the host 1's address to that of host 3
1484 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1485 src=self.pg1.remote_hosts[3].mac) /
1487 hwdst=self.pg1.local_mac,
1488 hwsrc=self.pg1.remote_hosts[3].mac,
1489 pdst=self.pg1.remote_hosts[1].ip4,
1490 psrc=self.pg1.remote_hosts[1].ip4))
1492 self.pg1.add_stream(p1)
1493 self.pg_enable_capture(self.pg_interfaces)
1496 self.assertTrue(find_nbr(self,
1497 self.pg1.sw_if_index,
1498 self.pg1.remote_hosts[1].ip4,
1499 mac=self.pg1.remote_hosts[3].mac))
1502 # GARPs (request nor replies) for host we don't know yet
1503 # don't result in new neighbour entries
1505 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1506 src=self.pg1.remote_hosts[3].mac) /
1508 hwdst=self.pg1.local_mac,
1509 hwsrc=self.pg1.remote_hosts[3].mac,
1510 pdst=self.pg1.remote_hosts[2].ip4,
1511 psrc=self.pg1.remote_hosts[2].ip4))
1513 self.pg1.add_stream(p1)
1514 self.pg_enable_capture(self.pg_interfaces)
1517 self.assertFalse(find_nbr(self,
1518 self.pg1.sw_if_index,
1519 self.pg1.remote_hosts[2].ip4))
1521 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1522 src=self.pg1.remote_hosts[3].mac) /
1524 hwdst=self.pg1.local_mac,
1525 hwsrc=self.pg1.remote_hosts[3].mac,
1526 pdst=self.pg1.remote_hosts[2].ip4,
1527 psrc=self.pg1.remote_hosts[2].ip4))
1529 self.pg1.add_stream(p1)
1530 self.pg_enable_capture(self.pg_interfaces)
1533 self.assertFalse(find_nbr(self,
1534 self.pg1.sw_if_index,
1535 self.pg1.remote_hosts[2].ip4))
1538 # IP address in different subnets are not learnt
1540 self.pg2.configure_ipv4_neighbors()
1542 for op in ["is-at", "who-has"]:
1543 p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1544 src=self.pg2.remote_hosts[1].mac) /
1546 hwdst=self.pg2.local_mac,
1547 hwsrc=self.pg2.remote_hosts[1].mac,
1548 pdst=self.pg2.remote_hosts[1].ip4,
1549 psrc=self.pg2.remote_hosts[1].ip4)),
1550 (Ether(dst="ff:ff:ff:ff:ff:ff",
1551 src=self.pg2.remote_hosts[1].mac) /
1553 hwdst="ff:ff:ff:ff:ff:ff",
1554 hwsrc=self.pg2.remote_hosts[1].mac,
1555 pdst=self.pg2.remote_hosts[1].ip4,
1556 psrc=self.pg2.remote_hosts[1].ip4))]
1558 self.send_and_assert_no_replies(self.pg1, p1)
1559 self.assertFalse(find_nbr(self,
1560 self.pg1.sw_if_index,
1561 self.pg2.remote_hosts[1].ip4))
1563 # they are all dropped because the subnet's don't match
1564 self.assertEqual(4, self.statistics.get_err_counter(
1565 "/err/arp-reply/IP4 destination address not local to subnet"))
1567 def test_arp_incomplete2(self):
1568 """ Incomplete Entries """
1571 # ensure that we throttle the ARP and ND requests
1573 self.pg0.generate_remote_hosts(2)
1578 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1579 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1580 self.pg0.sw_if_index)])
1581 ip_10_0_0_1.add_vpp_config()
1583 p1 = (Ether(dst=self.pg1.local_mac,
1584 src=self.pg1.remote_mac) /
1585 IP(src=self.pg1.remote_ip4,
1587 UDP(sport=1234, dport=1234) /
1590 self.pg1.add_stream(p1 * 257)
1591 self.pg_enable_capture(self.pg_interfaces)
1593 rx = self.pg0._get_capture(1)
1596 # how many we get is going to be dependent on the time for packet
1597 # processing but it should be small
1599 self.assertLess(len(rx), 64)
1604 ip_10_1 = VppIpRoute(self, "10::1", 128,
1605 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1606 self.pg0.sw_if_index,
1607 proto=DpoProto.DPO_PROTO_IP6)])
1608 ip_10_1.add_vpp_config()
1610 p1 = (Ether(dst=self.pg1.local_mac,
1611 src=self.pg1.remote_mac) /
1612 IPv6(src=self.pg1.remote_ip6,
1614 UDP(sport=1234, dport=1234) /
1617 self.pg1.add_stream(p1 * 257)
1618 self.pg_enable_capture(self.pg_interfaces)
1620 rx = self.pg0._get_capture(1)
1623 # how many we get is going to be dependent on the time for packet
1624 # processing but it should be small
1626 self.assertLess(len(rx), 64)
1628 def test_arp_forus(self):
1629 """ ARP for for-us """
1632 # Test that VPP responds with ARP requests to addresses that
1633 # are connected and local routes.
1634 # Use one of the 'remote' addresses in the subnet as a local address
1635 # The intention of this route is that it then acts like a secondary
1636 # address added to an interface
1638 self.pg0.generate_remote_hosts(2)
1641 self, self.pg0.remote_hosts[1].ip4, 32,
1642 [VppRoutePath("0.0.0.0",
1643 self.pg0.sw_if_index,
1644 type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1645 forus.add_vpp_config()
1647 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1648 src=self.pg0.remote_mac) /
1650 hwdst=self.pg0.local_mac,
1651 hwsrc=self.pg0.remote_mac,
1652 pdst=self.pg0.remote_hosts[1].ip4,
1653 psrc=self.pg0.remote_ip4))
1655 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1657 self.verify_arp_resp(rx[0],
1659 self.pg0.remote_mac,
1660 self.pg0.remote_hosts[1].ip4,
1661 self.pg0.remote_ip4)
1663 def test_arp_table_swap(self):
1665 # Generate some hosts on the LAN
1668 self.pg1.generate_remote_hosts(N_NBRS)
1670 for n in range(N_NBRS):
1671 # a route thru each neighbour
1672 VppIpRoute(self, "10.0.0.%d" % n, 32,
1673 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1674 self.pg1.sw_if_index)]).add_vpp_config()
1676 # resolve each neighbour
1677 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1678 ARP(op="is-at", hwdst=self.pg1.local_mac,
1679 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1680 psrc=self.pg1.remote_hosts[n].ip4))
1682 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1684 self.logger.info(self.vapi.cli("sh ip neighbors"))
1687 # swap the table pg1 is in
1689 table = VppIpTable(self, 100).add_vpp_config()
1691 self.pg1.unconfig_ip4()
1692 self.pg1.set_table_ip4(100)
1693 self.pg1.config_ip4()
1696 # all neighbours are cleared
1698 for n in range(N_NBRS):
1699 self.assertFalse(find_nbr(self,
1700 self.pg1.sw_if_index,
1701 self.pg1.remote_hosts[n].ip4))
1704 # packets to all neighbours generate ARP requests
1706 for n in range(N_NBRS):
1707 # a route thru each neighbour
1708 VppIpRoute(self, "10.0.0.%d" % n, 32,
1709 [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1710 self.pg1.sw_if_index)],
1711 table_id=100).add_vpp_config()
1713 p = (Ether(src=self.pg1.remote_hosts[n].mac,
1714 dst=self.pg1.local_mac) /
1715 IP(src=self.pg1.remote_hosts[n].ip4,
1716 dst="10.0.0.%d" % n) /
1718 rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1720 self.verify_arp_req(rx,
1723 self.pg1.remote_hosts[n].ip4)
1725 self.pg1.unconfig_ip4()
1726 self.pg1.set_table_ip4(0)
1728 def test_glean_src_select(self):
1729 """ Multi Connecteds """
1732 # configure multiple connected subnets on an interface
1733 # and ensure that ARP requests for hosts on those subnets
1734 # pick up the correct source address
1736 conn1 = VppIpInterfaceAddress(self, self.pg1,
1737 "10.0.0.1", 24).add_vpp_config()
1738 conn2 = VppIpInterfaceAddress(self, self.pg1,
1739 "10.0.1.1", 24).add_vpp_config()
1741 p1 = (Ether(src=self.pg0.remote_mac,
1742 dst=self.pg0.local_mac) /
1743 IP(src=self.pg1.remote_ip4,
1747 rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
1749 self.verify_arp_req(rx,
1754 p2 = (Ether(src=self.pg0.remote_mac,
1755 dst=self.pg0.local_mac) /
1756 IP(src=self.pg1.remote_ip4,
1760 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1762 self.verify_arp_req(rx,
1768 # add a local address in the same subnet
1769 # the source addresses are equivalent. VPP happens to
1770 # choose the last one that was added
1771 conn3 = VppIpInterfaceAddress(self, self.pg1,
1772 "10.0.1.2", 24).add_vpp_config()
1774 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1776 self.verify_arp_req(rx,
1784 conn3.remove_vpp_config()
1785 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1787 self.verify_arp_req(rx,
1793 # add back, this time remove the first one
1795 conn3 = VppIpInterfaceAddress(self, self.pg1,
1796 "10.0.1.2", 24).add_vpp_config()
1798 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1800 self.verify_arp_req(rx,
1805 conn1.remove_vpp_config()
1806 rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
1808 self.verify_arp_req(rx,
1814 conn3.remove_vpp_config()
1815 conn2.remove_vpp_config()
1818 class NeighborStatsTestCase(VppTestCase):
1819 """ ARP/ND Counters """
1822 def setUpClass(cls):
1823 super(NeighborStatsTestCase, cls).setUpClass()
1826 def tearDownClass(cls):
1827 super(NeighborStatsTestCase, cls).tearDownClass()
1830 super(NeighborStatsTestCase, self).setUp()
1832 self.create_pg_interfaces(range(2))
1834 # pg0 configured with ip4 and 6 addresses used for input
1835 # pg1 configured with ip4 and 6 addresses used for output
1836 # pg2 is unnumbered to pg0
1837 for i in self.pg_interfaces:
1845 super(NeighborStatsTestCase, self).tearDown()
1847 for i in self.pg_interfaces:
1852 def test_arp_stats(self):
1853 """ ARP Counters """
1855 self.vapi.cli("adj counters enable")
1856 self.pg1.generate_remote_hosts(2)
1858 arp1 = VppNeighbor(self,
1859 self.pg1.sw_if_index,
1860 self.pg1.remote_hosts[0].mac,
1861 self.pg1.remote_hosts[0].ip4)
1862 arp1.add_vpp_config()
1863 arp2 = VppNeighbor(self,
1864 self.pg1.sw_if_index,
1865 self.pg1.remote_hosts[1].mac,
1866 self.pg1.remote_hosts[1].ip4)
1867 arp2.add_vpp_config()
1869 p1 = (Ether(dst=self.pg0.local_mac,
1870 src=self.pg0.remote_mac) /
1871 IP(src=self.pg0.remote_ip4,
1872 dst=self.pg1.remote_hosts[0].ip4) /
1873 UDP(sport=1234, dport=1234) /
1875 p2 = (Ether(dst=self.pg0.local_mac,
1876 src=self.pg0.remote_mac) /
1877 IP(src=self.pg0.remote_ip4,
1878 dst=self.pg1.remote_hosts[1].ip4) /
1879 UDP(sport=1234, dport=1234) /
1882 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1883 rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1885 self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1886 self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1888 rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1889 self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1891 def test_nd_stats(self):
1894 self.vapi.cli("adj counters enable")
1895 self.pg0.generate_remote_hosts(3)
1897 nd1 = VppNeighbor(self,
1898 self.pg0.sw_if_index,
1899 self.pg0.remote_hosts[1].mac,
1900 self.pg0.remote_hosts[1].ip6)
1901 nd1.add_vpp_config()
1902 nd2 = VppNeighbor(self,
1903 self.pg0.sw_if_index,
1904 self.pg0.remote_hosts[2].mac,
1905 self.pg0.remote_hosts[2].ip6)
1906 nd2.add_vpp_config()
1908 p1 = (Ether(dst=self.pg1.local_mac,
1909 src=self.pg1.remote_mac) /
1910 IPv6(src=self.pg1.remote_ip6,
1911 dst=self.pg0.remote_hosts[1].ip6) /
1912 UDP(sport=1234, dport=1234) /
1914 p2 = (Ether(dst=self.pg1.local_mac,
1915 src=self.pg1.remote_mac) /
1916 IPv6(src=self.pg1.remote_ip6,
1917 dst=self.pg0.remote_hosts[2].ip6) /
1918 UDP(sport=1234, dport=1234) /
1921 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1922 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1924 self.assertEqual(16, nd1.get_stats()['packets'])
1925 self.assertEqual(16, nd2.get_stats()['packets'])
1927 rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1928 self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1931 class NeighborAgeTestCase(VppTestCase):
1932 """ ARP/ND Aging """
1935 def setUpClass(cls):
1936 super(NeighborAgeTestCase, cls).setUpClass()
1939 def tearDownClass(cls):
1940 super(NeighborAgeTestCase, cls).tearDownClass()
1943 super(NeighborAgeTestCase, self).setUp()
1945 self.create_pg_interfaces(range(1))
1947 # pg0 configured with ip4 and 6 addresses used for input
1948 # pg1 configured with ip4 and 6 addresses used for output
1949 # pg2 is unnumbered to pg0
1950 for i in self.pg_interfaces:
1958 super(NeighborAgeTestCase, self).tearDown()
1960 for i in self.pg_interfaces:
1965 def wait_for_no_nbr(self, intf, address,
1966 n_tries=50, s_time=1):
1968 if not find_nbr(self, intf, address):
1970 n_tries = n_tries - 1
1975 def verify_arp_req(self, rx, smac, sip, dip):
1977 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1978 self.assertEqual(ether.src, smac)
1981 self.assertEqual(arp.hwtype, 1)
1982 self.assertEqual(arp.ptype, 0x800)
1983 self.assertEqual(arp.hwlen, 6)
1984 self.assertEqual(arp.plen, 4)
1985 self.assertEqual(arp.op, arp_opts["who-has"])
1986 self.assertEqual(arp.hwsrc, smac)
1987 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1988 self.assertEqual(arp.psrc, sip)
1989 self.assertEqual(arp.pdst, dip)
1992 """ Aging/Recycle """
1994 self.vapi.cli("set logging unthrottle 0")
1995 self.vapi.cli("set logging size %d" % 0xffff)
1997 self.pg0.generate_remote_hosts(201)
1999 vaf = VppEnum.vl_api_address_family_t
2002 # start listening on all interfaces
2004 self.pg_enable_capture(self.pg_interfaces)
2007 # Set the neighbor configuration:
2012 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2017 self.vapi.cli("sh ip neighbor-config")
2019 # add the 198 neighbours that should pass (-1 for one created in setup)
2020 for ii in range(200):
2022 self.pg0.sw_if_index,
2023 self.pg0.remote_hosts[ii].mac,
2024 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2026 # one more neighbor over the limit should fail
2027 with self.vapi.assert_negative_api_retval():
2029 self.pg0.sw_if_index,
2030 self.pg0.remote_hosts[200].mac,
2031 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2034 # change the config to allow recycling the old neighbors
2036 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2041 # now new additions are allowed
2043 self.pg0.sw_if_index,
2044 self.pg0.remote_hosts[200].mac,
2045 self.pg0.remote_hosts[200].ip4).add_vpp_config()
2047 # add the first neighbor we configured has been re-used
2048 self.assertFalse(find_nbr(self,
2049 self.pg0.sw_if_index,
2050 self.pg0.remote_hosts[0].ip4))
2051 self.assertTrue(find_nbr(self,
2052 self.pg0.sw_if_index,
2053 self.pg0.remote_hosts[200].ip4))
2056 # change the config to age old neighbors
2058 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2063 self.vapi.cli("sh ip4 neighbor-sorted")
2066 # expect probes from all these ARP entries as they age
2067 # 3 probes for each neighbor 3*200 = 600
2068 rxs = self.pg0.get_capture(600, timeout=8)
2071 for jj in range(200):
2072 rx = rxs[ii*200 + jj]
2076 # 3 probes sent then 1 more second to see if a reply comes, before
2079 for jj in range(1, 201):
2080 self.wait_for_no_nbr(self.pg0.sw_if_index,
2081 self.pg0.remote_hosts[jj].ip4)
2083 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2084 af=vaf.ADDRESS_IP4))
2087 # load up some neighbours again with 2s aging enabled
2088 # they should be removed after 10s (2s age + 4s for probes + gap)
2089 # check for the add and remove events
2091 enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2093 self.vapi.want_ip_neighbor_events_v2(enable=1)
2094 for ii in range(10):
2096 self.pg0.sw_if_index,
2097 self.pg0.remote_hosts[ii].mac,
2098 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2100 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2101 self.assertEqual(e.flags,
2102 enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2103 self.assertEqual(str(e.neighbor.ip_address),
2104 self.pg0.remote_hosts[ii].ip4)
2105 self.assertEqual(e.neighbor.mac_address,
2106 self.pg0.remote_hosts[ii].mac)
2109 self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2110 af=vaf.ADDRESS_IP4))
2113 for ii in range(10):
2114 e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2115 self.assertEqual(e.flags,
2116 enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2119 # check we got the correct mac/ip pairs - done separately
2120 # because we don't care about the order the remove notifications
2122 for ii in range(10):
2124 mac = self.pg0.remote_hosts[ii].mac
2125 ip = self.pg0.remote_hosts[ii].ip4
2128 if (e.neighbor.mac_address == mac and
2129 str(e.neighbor.ip_address) == ip):
2132 self.assertTrue(found)
2135 # check if we can set age and recycle with empty neighbor list
2137 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2143 # load up some neighbours again, then disable the aging
2144 # they should still be there in 10 seconds time
2146 for ii in range(10):
2148 self.pg0.sw_if_index,
2149 self.pg0.remote_hosts[ii].mac,
2150 self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2151 self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2157 self.assertTrue(find_nbr(self,
2158 self.pg0.sw_if_index,
2159 self.pg0.remote_hosts[0].ip4))
2162 class NeighborReplaceTestCase(VppTestCase):
2163 """ ARP/ND Replacement """
2166 def setUpClass(cls):
2167 super(NeighborReplaceTestCase, cls).setUpClass()
2170 def tearDownClass(cls):
2171 super(NeighborReplaceTestCase, cls).tearDownClass()
2174 super(NeighborReplaceTestCase, self).setUp()
2176 self.create_pg_interfaces(range(4))
2178 # pg0 configured with ip4 and 6 addresses used for input
2179 # pg1 configured with ip4 and 6 addresses used for output
2180 # pg2 is unnumbered to pg0
2181 for i in self.pg_interfaces:
2189 super(NeighborReplaceTestCase, self).tearDown()
2191 for i in self.pg_interfaces:
2196 def test_replace(self):
2201 for i in self.pg_interfaces:
2202 i.generate_remote_hosts(N_HOSTS)
2203 i.configure_ipv4_neighbors()
2204 i.configure_ipv6_neighbors()
2207 self.vapi.ip_neighbor_replace_begin()
2208 self.vapi.ip_neighbor_replace_end()
2210 for i in self.pg_interfaces:
2211 for h in range(N_HOSTS):
2212 self.assertFalse(find_nbr(self,
2213 self.pg0.sw_if_index,
2214 self.pg0.remote_hosts[h].ip4))
2215 self.assertFalse(find_nbr(self,
2216 self.pg0.sw_if_index,
2217 self.pg0.remote_hosts[h].ip6))
2220 # and them all back via the API
2222 for i in self.pg_interfaces:
2223 for h in range(N_HOSTS):
2226 i.remote_hosts[h].mac,
2227 i.remote_hosts[h].ip4).add_vpp_config()
2230 i.remote_hosts[h].mac,
2231 i.remote_hosts[h].ip6).add_vpp_config()
2234 # begin the replacement again, this time touch some
2235 # the neighbours on pg1 so they are not deleted
2237 self.vapi.ip_neighbor_replace_begin()
2239 # update from the API all neighbours on pg1
2240 for h in range(N_HOSTS):
2242 self.pg1.sw_if_index,
2243 self.pg1.remote_hosts[h].mac,
2244 self.pg1.remote_hosts[h].ip4).add_vpp_config()
2246 self.pg1.sw_if_index,
2247 self.pg1.remote_hosts[h].mac,
2248 self.pg1.remote_hosts[h].ip6).add_vpp_config()
2250 # update from the data-plane all neighbours on pg3
2251 self.pg3.configure_ipv4_neighbors()
2252 self.pg3.configure_ipv6_neighbors()
2254 # complete the replacement
2255 self.logger.info(self.vapi.cli("sh ip neighbors"))
2256 self.vapi.ip_neighbor_replace_end()
2258 for i in self.pg_interfaces:
2259 if i == self.pg1 or i == self.pg3:
2260 # neighbours on pg1 and pg3 are still present
2261 for h in range(N_HOSTS):
2262 self.assertTrue(find_nbr(self,
2264 i.remote_hosts[h].ip4))
2265 self.assertTrue(find_nbr(self,
2267 i.remote_hosts[h].ip6))
2269 # all other neighbours are toast
2270 for h in range(N_HOSTS):
2271 self.assertFalse(find_nbr(self,
2273 i.remote_hosts[h].ip4))
2274 self.assertFalse(find_nbr(self,
2276 i.remote_hosts[h].ip6))
2279 class NeighborFlush(VppTestCase):
2280 """ Neighbor Flush """
2283 def setUpClass(cls):
2284 super(NeighborFlush, cls).setUpClass()
2287 def tearDownClass(cls):
2288 super(NeighborFlush, cls).tearDownClass()
2291 super(NeighborFlush, self).setUp()
2293 self.create_pg_interfaces(range(2))
2295 for i in self.pg_interfaces:
2303 super(NeighborFlush, self).tearDown()
2305 for i in self.pg_interfaces:
2310 def test_flush(self):
2311 """ Neighbour Flush """
2314 nf = e.vl_api_ip_neighbor_flags_t
2315 af = e.vl_api_address_family_t
2317 static = [False, True]
2318 self.pg0.generate_remote_hosts(N_HOSTS)
2319 self.pg1.generate_remote_hosts(N_HOSTS)
2322 # a few v4 and v6 dynamic neoghbors
2323 for n in range(N_HOSTS):
2325 self.pg0.sw_if_index,
2326 self.pg0.remote_hosts[n].mac,
2327 self.pg0.remote_hosts[n].ip4,
2328 is_static=s).add_vpp_config()
2330 self.pg1.sw_if_index,
2331 self.pg1.remote_hosts[n].mac,
2332 self.pg1.remote_hosts[n].ip6,
2333 is_static=s).add_vpp_config()
2335 # flush the interfaces individually
2336 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2338 # check we haven't flushed that which we shouldn't
2339 for n in range(N_HOSTS):
2340 self.assertTrue(find_nbr(self,
2341 self.pg1.sw_if_index,
2342 self.pg1.remote_hosts[n].ip6,
2345 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2347 for n in range(N_HOSTS):
2348 self.assertFalse(find_nbr(self,
2349 self.pg0.sw_if_index,
2350 self.pg0.remote_hosts[n].ip4))
2351 self.assertFalse(find_nbr(self,
2352 self.pg1.sw_if_index,
2353 self.pg1.remote_hosts[n].ip6))
2355 # add the nieghbours back
2356 for n in range(N_HOSTS):
2358 self.pg0.sw_if_index,
2359 self.pg0.remote_hosts[n].mac,
2360 self.pg0.remote_hosts[n].ip4,
2361 is_static=s).add_vpp_config()
2363 self.pg1.sw_if_index,
2364 self.pg1.remote_hosts[n].mac,
2365 self.pg1.remote_hosts[n].ip6,
2366 is_static=s).add_vpp_config()
2368 self.logger.info(self.vapi.cli("sh ip neighbor"))
2370 # flush both interfaces at the same time
2371 self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2373 # check we haven't flushed that which we shouldn't
2374 for n in range(N_HOSTS):
2375 self.assertTrue(find_nbr(self,
2376 self.pg0.sw_if_index,
2377 self.pg0.remote_hosts[n].ip4,
2380 self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2382 for n in range(N_HOSTS):
2383 self.assertFalse(find_nbr(self,
2384 self.pg0.sw_if_index,
2385 self.pg0.remote_hosts[n].ip4))
2386 self.assertFalse(find_nbr(self,
2387 self.pg1.sw_if_index,
2388 self.pg1.remote_hosts[n].ip6))
2391 if __name__ == '__main__':
2392 unittest.main(testRunner=VppTestRunner)