4 from socket import AF_INET, AF_INET6, inet_pton
6 from framework import VppTestCase, VppTestRunner
7 from vpp_neighbor import VppNeighbor, find_nbr
8 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
10 from vpp_papi import VppEnum
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, ARP, Dot1Q
15 from scapy.layers.inet import IP, UDP
16 from scapy.layers.inet6 import IPv6
17 from scapy.contrib.mpls import MPLS
18 from scapy.layers.inet6 import IPv6
20 # not exported by scapy, so redefined here
21 arp_opts = {"who-has": 1, "is-at": 2}
24 class ARPTestCase(VppTestCase):
28 super(ARPTestCase, self).setUp()
30 # create 3 pg interfaces
31 self.create_pg_interfaces(range(4))
33 # pg0 configured with ip4 and 6 addresses used for input
34 # pg1 configured with ip4 and 6 addresses used for output
35 # pg2 is unnumbered to pg0
36 for i in self.pg_interfaces:
41 self.pg0.resolve_arp()
46 # pg3 in a different VRF
47 self.tbl = VppIpTable(self, 1)
48 self.tbl.add_vpp_config()
50 self.pg3.set_table_ip4(1)
54 self.pg0.unconfig_ip4()
55 self.pg0.unconfig_ip6()
57 self.pg1.unconfig_ip4()
58 self.pg1.unconfig_ip6()
60 self.pg3.unconfig_ip4()
61 self.pg3.set_table_ip4(0)
63 for i in self.pg_interfaces:
66 super(ARPTestCase, self).tearDown()
68 def verify_arp_req(self, rx, smac, sip, dip):
70 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
71 self.assertEqual(ether.src, smac)
74 self.assertEqual(arp.hwtype, 1)
75 self.assertEqual(arp.ptype, 0x800)
76 self.assertEqual(arp.hwlen, 6)
77 self.assertEqual(arp.plen, 4)
78 self.assertEqual(arp.op, arp_opts["who-has"])
79 self.assertEqual(arp.hwsrc, smac)
80 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
81 self.assertEqual(arp.psrc, sip)
82 self.assertEqual(arp.pdst, dip)
84 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
86 self.assertEqual(ether.dst, dmac)
87 self.assertEqual(ether.src, smac)
90 self.assertEqual(arp.hwtype, 1)
91 self.assertEqual(arp.ptype, 0x800)
92 self.assertEqual(arp.hwlen, 6)
93 self.assertEqual(arp.plen, 4)
94 self.assertEqual(arp.op, arp_opts["is-at"])
95 self.assertEqual(arp.hwsrc, smac)
96 self.assertEqual(arp.hwdst, dmac)
97 self.assertEqual(arp.psrc, sip)
98 self.assertEqual(arp.pdst, dip)
100 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
102 self.assertEqual(ether.dst, dmac)
103 self.assertEqual(ether.src, smac)
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.assertNotEqual(arp.hwsrc, smac)
112 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
113 "00:00:5E:00:01" in arp.hwsrc)
114 self.assertEqual(arp.hwdst, dmac)
115 self.assertEqual(arp.psrc, sip)
116 self.assertEqual(arp.pdst, dip)
118 def verify_ip(self, rx, smac, dmac, sip, dip):
120 self.assertEqual(ether.dst, dmac)
121 self.assertEqual(ether.src, smac)
124 self.assertEqual(ip.src, sip)
125 self.assertEqual(ip.dst, dip)
127 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
129 self.assertEqual(ether.dst, dmac)
130 self.assertEqual(ether.src, smac)
133 self.assertTrue(mpls.label, label)
136 self.assertEqual(ip.src, sip)
137 self.assertEqual(ip.dst, dip)
143 # Generate some hosts on the LAN
145 self.pg1.generate_remote_hosts(11)
148 # Send IP traffic to one of these unresolved hosts.
149 # expect the generation of an ARP request
151 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
152 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
153 UDP(sport=1234, dport=1234) /
156 self.pg0.add_stream(p)
157 self.pg_enable_capture(self.pg_interfaces)
160 rx = self.pg1.get_capture(1)
162 self.verify_arp_req(rx[0],
165 self.pg1._remote_hosts[1].ip4)
168 # And a dynamic ARP entry for host 1
170 dyn_arp = VppNeighbor(self,
171 self.pg1.sw_if_index,
172 self.pg1.remote_hosts[1].mac,
173 self.pg1.remote_hosts[1].ip4)
174 dyn_arp.add_vpp_config()
177 # now we expect IP traffic forwarded
179 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
180 IP(src=self.pg0.remote_ip4,
181 dst=self.pg1._remote_hosts[1].ip4) /
182 UDP(sport=1234, dport=1234) /
185 self.pg0.add_stream(dyn_p)
186 self.pg_enable_capture(self.pg_interfaces)
189 rx = self.pg1.get_capture(1)
191 self.verify_ip(rx[0],
193 self.pg1.remote_hosts[1].mac,
195 self.pg1._remote_hosts[1].ip4)
198 # And a Static ARP entry for host 2
200 static_arp = VppNeighbor(self,
201 self.pg1.sw_if_index,
202 self.pg1.remote_hosts[2].mac,
203 self.pg1.remote_hosts[2].ip4,
205 static_arp.add_vpp_config()
207 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
208 IP(src=self.pg0.remote_ip4,
209 dst=self.pg1._remote_hosts[2].ip4) /
210 UDP(sport=1234, dport=1234) /
213 self.pg0.add_stream(static_p)
214 self.pg_enable_capture(self.pg_interfaces)
217 rx = self.pg1.get_capture(1)
219 self.verify_ip(rx[0],
221 self.pg1.remote_hosts[2].mac,
223 self.pg1._remote_hosts[2].ip4)
226 # flap the link. dynamic ARPs get flush, statics don't
228 self.pg1.admin_down()
231 self.pg0.add_stream(static_p)
232 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[2].mac,
240 self.pg1._remote_hosts[2].ip4)
242 self.pg0.add_stream(dyn_p)
243 self.pg_enable_capture(self.pg_interfaces)
246 rx = self.pg1.get_capture(1)
247 self.verify_arp_req(rx[0],
250 self.pg1._remote_hosts[1].ip4)
253 # Send an ARP request from one of the so-far unlearned remote hosts
255 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
256 src=self.pg1._remote_hosts[3].mac) /
258 hwsrc=self.pg1._remote_hosts[3].mac,
259 pdst=self.pg1.local_ip4,
260 psrc=self.pg1._remote_hosts[3].ip4))
262 self.pg1.add_stream(p)
263 self.pg_enable_capture(self.pg_interfaces)
266 rx = self.pg1.get_capture(1)
267 self.verify_arp_resp(rx[0],
269 self.pg1._remote_hosts[3].mac,
271 self.pg1._remote_hosts[3].ip4)
274 # VPP should have learned the mapping for the remote host
276 self.assertTrue(find_nbr(self,
277 self.pg1.sw_if_index,
278 self.pg1._remote_hosts[3].ip4))
280 # Fire in an ARP request before the interface becomes IP enabled
282 self.pg2.generate_remote_hosts(4)
284 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
286 hwsrc=self.pg2.remote_mac,
287 pdst=self.pg1.local_ip4,
288 psrc=self.pg2.remote_hosts[3].ip4))
289 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
292 hwsrc=self.pg2.remote_mac,
293 pdst=self.pg1.local_ip4,
294 psrc=self.pg2.remote_hosts[3].ip4))
295 self.send_and_assert_no_replies(self.pg2, p,
296 "interface not IP enabled")
299 # Make pg2 un-numbered to pg1
301 self.pg2.set_unnumbered(self.pg1.sw_if_index)
303 unnum = self.vapi.ip_unnumbered_dump()
304 self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
305 self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
308 # We should respond to ARP requests for the unnumbered to address
309 # once an attached route to the source is known
311 self.send_and_assert_no_replies(
313 "ARP req for unnumbered address - no source")
315 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
316 [VppRoutePath("0.0.0.0",
317 self.pg2.sw_if_index)])
318 attached_host.add_vpp_config()
320 self.pg2.add_stream(p)
321 self.pg_enable_capture(self.pg_interfaces)
324 rx = self.pg2.get_capture(1)
325 self.verify_arp_resp(rx[0],
329 self.pg2.remote_hosts[3].ip4)
331 self.pg2.add_stream(pt)
332 self.pg_enable_capture(self.pg_interfaces)
335 rx = self.pg2.get_capture(1)
336 self.verify_arp_resp(rx[0],
340 self.pg2.remote_hosts[3].ip4)
343 # A neighbor entry that has no associated FIB-entry
345 arp_no_fib = VppNeighbor(self,
346 self.pg1.sw_if_index,
347 self.pg1.remote_hosts[4].mac,
348 self.pg1.remote_hosts[4].ip4,
350 arp_no_fib.add_vpp_config()
353 # check we have the neighbor, but no route
355 self.assertTrue(find_nbr(self,
356 self.pg1.sw_if_index,
357 self.pg1._remote_hosts[4].ip4))
358 self.assertFalse(find_route(self,
359 self.pg1._remote_hosts[4].ip4,
362 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
363 # from within pg1's subnet
365 arp_unnum = VppNeighbor(self,
366 self.pg2.sw_if_index,
367 self.pg1.remote_hosts[5].mac,
368 self.pg1.remote_hosts[5].ip4)
369 arp_unnum.add_vpp_config()
371 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
372 IP(src=self.pg0.remote_ip4,
373 dst=self.pg1._remote_hosts[5].ip4) /
374 UDP(sport=1234, dport=1234) /
377 self.pg0.add_stream(p)
378 self.pg_enable_capture(self.pg_interfaces)
381 rx = self.pg2.get_capture(1)
383 self.verify_ip(rx[0],
385 self.pg1.remote_hosts[5].mac,
387 self.pg1._remote_hosts[5].ip4)
390 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
391 # with the unnumbered interface's address as the source
393 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
395 hwsrc=self.pg2.remote_mac,
396 pdst=self.pg1.local_ip4,
397 psrc=self.pg1.remote_hosts[6].ip4))
399 self.pg2.add_stream(p)
400 self.pg_enable_capture(self.pg_interfaces)
403 rx = self.pg2.get_capture(1)
404 self.verify_arp_resp(rx[0],
408 self.pg1.remote_hosts[6].ip4)
411 # An attached host route out of pg2 for an undiscovered hosts generates
412 # an ARP request with the unnumbered address as the source
414 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
415 [VppRoutePath("0.0.0.0",
416 self.pg2.sw_if_index)])
417 att_unnum.add_vpp_config()
419 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
420 IP(src=self.pg0.remote_ip4,
421 dst=self.pg1._remote_hosts[7].ip4) /
422 UDP(sport=1234, dport=1234) /
425 self.pg0.add_stream(p)
426 self.pg_enable_capture(self.pg_interfaces)
429 rx = self.pg2.get_capture(1)
431 self.verify_arp_req(rx[0],
434 self.pg1._remote_hosts[7].ip4)
436 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
438 hwsrc=self.pg2.remote_mac,
439 pdst=self.pg1.local_ip4,
440 psrc=self.pg1.remote_hosts[7].ip4))
442 self.pg2.add_stream(p)
443 self.pg_enable_capture(self.pg_interfaces)
446 rx = self.pg2.get_capture(1)
447 self.verify_arp_resp(rx[0],
451 self.pg1.remote_hosts[7].ip4)
454 # An attached host route as yet unresolved out of pg2 for an
455 # undiscovered host, an ARP requests begets a response.
457 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
458 [VppRoutePath("0.0.0.0",
459 self.pg2.sw_if_index)])
460 att_unnum1.add_vpp_config()
462 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
464 hwsrc=self.pg2.remote_mac,
465 pdst=self.pg1.local_ip4,
466 psrc=self.pg1.remote_hosts[8].ip4))
468 self.pg2.add_stream(p)
469 self.pg_enable_capture(self.pg_interfaces)
472 rx = self.pg2.get_capture(1)
473 self.verify_arp_resp(rx[0],
477 self.pg1.remote_hosts[8].ip4)
480 # Send an ARP request from one of the so-far unlearned remote hosts
483 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
484 src=self.pg1._remote_hosts[9].mac) /
487 hwsrc=self.pg1._remote_hosts[9].mac,
488 pdst=self.pg1.local_ip4,
489 psrc=self.pg1._remote_hosts[9].ip4))
491 self.pg1.add_stream(p)
492 self.pg_enable_capture(self.pg_interfaces)
495 rx = self.pg1.get_capture(1)
496 self.verify_arp_resp(rx[0],
498 self.pg1._remote_hosts[9].mac,
500 self.pg1._remote_hosts[9].ip4)
503 # Add a hierarchy of routes for a host in the sub-net.
504 # Should still get an ARP resp since the cover is attached
506 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
508 hwsrc=self.pg1.remote_mac,
509 pdst=self.pg1.local_ip4,
510 psrc=self.pg1.remote_hosts[10].ip4))
512 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
513 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
514 self.pg1.sw_if_index)])
517 self.pg1.add_stream(p)
518 self.pg_enable_capture(self.pg_interfaces)
520 rx = self.pg1.get_capture(1)
521 self.verify_arp_resp(rx[0],
525 self.pg1.remote_hosts[10].ip4)
527 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
528 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
529 self.pg1.sw_if_index)])
532 self.pg1.add_stream(p)
533 self.pg_enable_capture(self.pg_interfaces)
535 rx = self.pg1.get_capture(1)
536 self.verify_arp_resp(rx[0],
540 self.pg1.remote_hosts[10].ip4)
543 # add an ARP entry that's not on the sub-net and so whose
544 # adj-fib fails the refinement check. then send an ARP request
547 a1 = VppNeighbor(self,
548 self.pg0.sw_if_index,
553 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
555 hwsrc=self.pg0.remote_mac,
556 psrc="100.100.100.50",
557 pdst=self.pg0.remote_ip4))
558 self.send_and_assert_no_replies(self.pg0, p,
559 "ARP req for from failed adj-fib")
563 # 1 - don't respond to ARP request for address not within the
564 # interface's sub-net
565 # 1b - nor within the unnumbered subnet
566 # 1c - nor within the subnet of a different interface
568 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
570 hwsrc=self.pg0.remote_mac,
572 psrc=self.pg0.remote_ip4))
573 self.send_and_assert_no_replies(self.pg0, p,
574 "ARP req for non-local destination")
575 self.assertFalse(find_nbr(self,
576 self.pg0.sw_if_index,
579 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
581 hwsrc=self.pg2.remote_mac,
583 psrc=self.pg1.remote_hosts[7].ip4))
584 self.send_and_assert_no_replies(
586 "ARP req for non-local destination - unnum")
588 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
590 hwsrc=self.pg0.remote_mac,
591 pdst=self.pg1.local_ip4,
592 psrc=self.pg1.remote_ip4))
593 self.send_and_assert_no_replies(self.pg0, p,
594 "ARP req diff sub-net")
595 self.assertFalse(find_nbr(self,
596 self.pg0.sw_if_index,
597 self.pg1.remote_ip4))
600 # 2 - don't respond to ARP request from an address not within the
601 # interface's sub-net
602 # 2b - to a proxied address
603 # 2c - not within a different interface's sub-net
604 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
606 hwsrc=self.pg0.remote_mac,
608 pdst=self.pg0.local_ip4))
609 self.send_and_assert_no_replies(self.pg0, p,
610 "ARP req for non-local source")
611 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
613 hwsrc=self.pg2.remote_mac,
615 pdst=self.pg0.local_ip4))
616 self.send_and_assert_no_replies(
618 "ARP req for non-local source - unnum")
619 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
621 hwsrc=self.pg0.remote_mac,
622 psrc=self.pg1.remote_ip4,
623 pdst=self.pg0.local_ip4))
624 self.send_and_assert_no_replies(self.pg0, p,
625 "ARP req for non-local source 2c")
628 # 3 - don't respond to ARP request from an address that belongs to
631 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
633 hwsrc=self.pg0.remote_mac,
634 psrc=self.pg0.local_ip4,
635 pdst=self.pg0.local_ip4))
636 self.send_and_assert_no_replies(self.pg0, p,
637 "ARP req for non-local source")
640 # 4 - don't respond to ARP requests that has mac source different
641 # from ARP request HW source
643 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
645 hwsrc="00:00:00:DE:AD:BE",
646 psrc=self.pg0.remote_ip4,
647 pdst=self.pg0.local_ip4))
648 self.send_and_assert_no_replies(self.pg0, p,
649 "ARP req for non-local source")
652 # 5 - don't respond to ARP requests for address within the
653 # interface's sub-net but not the interface's address
655 self.pg0.generate_remote_hosts(2)
656 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
658 hwsrc=self.pg0.remote_mac,
659 psrc=self.pg0.remote_hosts[0].ip4,
660 pdst=self.pg0.remote_hosts[1].ip4))
661 self.send_and_assert_no_replies(self.pg0, p,
662 "ARP req for non-local destination")
667 dyn_arp.remove_vpp_config()
668 static_arp.remove_vpp_config()
669 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
671 # need this to flush the adj-fibs
672 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
673 self.pg2.admin_down()
674 self.pg1.admin_down()
676 def test_proxy_mirror_arp(self):
677 """ Interface Mirror Proxy ARP """
680 # When VPP has an interface whose address is also applied to a TAP
681 # interface on the host, then VPP's TAP interface will be unnumbered
682 # to the 'real' interface and do proxy ARP from the host.
683 # the curious aspect of this setup is that ARP requests from the host
684 # will come from the VPP's own address.
686 self.pg0.generate_remote_hosts(2)
688 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
689 dst="ff:ff:ff:ff:ff:ff") /
691 hwsrc=self.pg2.remote_mac,
692 pdst=self.pg0.remote_hosts[1].ip4,
693 psrc=self.pg0.local_ip4))
696 # Configure Proxy ARP for the subnet on PG0addresses on pg0
698 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
699 self.pg0._local_ip4_bcast)
701 # Make pg2 un-numbered to pg0
703 self.pg2.set_unnumbered(self.pg0.sw_if_index)
706 # Enable pg2 for proxy ARP
708 self.pg2.set_proxy_arp()
711 # Send the ARP request with an originating address that
712 # is VPP's own address
714 self.pg2.add_stream(arp_req_from_me)
715 self.pg_enable_capture(self.pg_interfaces)
718 rx = self.pg2.get_capture(1)
719 self.verify_arp_resp(rx[0],
722 self.pg0.remote_hosts[1].ip4,
726 # validate we have not learned an ARP entry as a result of this
728 self.assertFalse(find_nbr(self,
729 self.pg2.sw_if_index,
735 self.pg2.set_proxy_arp(0)
736 self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
737 self.pg0._local_ip4_bcast,
740 def test_proxy_arp(self):
743 self.pg1.generate_remote_hosts(2)
746 # Proxy ARP request packets for each interface
748 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
749 dst="ff:ff:ff:ff:ff:ff") /
751 hwsrc=self.pg0.remote_mac,
753 psrc=self.pg0.remote_ip4))
754 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
755 dst="ff:ff:ff:ff:ff:ff") /
758 hwsrc=self.pg0.remote_mac,
760 psrc=self.pg0.remote_ip4))
761 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
762 dst="ff:ff:ff:ff:ff:ff") /
764 hwsrc=self.pg1.remote_mac,
766 psrc=self.pg1.remote_ip4))
767 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
768 dst="ff:ff:ff:ff:ff:ff") /
770 hwsrc=self.pg2.remote_mac,
772 psrc=self.pg1.remote_hosts[1].ip4))
773 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
774 dst="ff:ff:ff:ff:ff:ff") /
776 hwsrc=self.pg3.remote_mac,
778 psrc=self.pg3.remote_ip4))
781 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
783 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
784 inet_pton(AF_INET, "10.10.10.124"))
787 # No responses are sent when the interfaces are not enabled for proxy
790 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
791 "ARP req from unconfigured interface")
792 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
793 "ARP req from unconfigured interface")
796 # Make pg2 un-numbered to pg1
799 self.pg2.set_unnumbered(self.pg1.sw_if_index)
801 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
802 "ARP req from unnumbered interface")
805 # Enable each interface to reply to proxy ARPs
807 for i in self.pg_interfaces:
811 # Now each of the interfaces should reply to a request to a proxied
814 self.pg0.add_stream(arp_req_pg0)
815 self.pg_enable_capture(self.pg_interfaces)
818 rx = self.pg0.get_capture(1)
819 self.verify_arp_resp(rx[0],
825 self.pg0.add_stream(arp_req_pg0_tagged)
826 self.pg_enable_capture(self.pg_interfaces)
829 rx = self.pg0.get_capture(1)
830 self.verify_arp_resp(rx[0],
836 self.pg1.add_stream(arp_req_pg1)
837 self.pg_enable_capture(self.pg_interfaces)
840 rx = self.pg1.get_capture(1)
841 self.verify_arp_resp(rx[0],
847 self.pg2.add_stream(arp_req_pg2)
848 self.pg_enable_capture(self.pg_interfaces)
851 rx = self.pg2.get_capture(1)
852 self.verify_arp_resp(rx[0],
856 self.pg1.remote_hosts[1].ip4)
859 # A request for an address out of the configured range
861 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
862 dst="ff:ff:ff:ff:ff:ff") /
864 hwsrc=self.pg1.remote_mac,
866 psrc=self.pg1.remote_ip4))
867 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
868 "ARP req out of range HI")
869 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
870 dst="ff:ff:ff:ff:ff:ff") /
872 hwsrc=self.pg1.remote_mac,
874 psrc=self.pg1.remote_ip4))
875 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
876 "ARP req out of range Low")
879 # Request for an address in the proxy range but from an interface
882 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
883 "ARP req from different VRF")
886 # Disable Each interface for proxy ARP
887 # - expect none to respond
889 for i in self.pg_interfaces:
892 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
893 "ARP req from disable")
894 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
895 "ARP req from disable")
896 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
897 "ARP req from disable")
900 # clean up on interface 2
902 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
908 # Interface 2 does not yet have ip4 config
910 self.pg2.config_ip4()
911 self.pg2.generate_remote_hosts(2)
914 # Add a route with out going label via an ARP unresolved next-hop
916 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
917 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
918 self.pg2.sw_if_index,
920 ip_10_0_0_1.add_vpp_config()
923 # packets should generate an ARP request
925 p = (Ether(src=self.pg0.remote_mac,
926 dst=self.pg0.local_mac) /
927 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
928 UDP(sport=1234, dport=1234) /
931 self.pg0.add_stream(p)
932 self.pg_enable_capture(self.pg_interfaces)
935 rx = self.pg2.get_capture(1)
936 self.verify_arp_req(rx[0],
939 self.pg2._remote_hosts[1].ip4)
942 # now resolve the neighbours
944 self.pg2.configure_ipv4_neighbors()
947 # Now packet should be properly MPLS encapped.
948 # This verifies that MPLS link-type adjacencies are completed
949 # when the ARP entry resolves
951 self.pg0.add_stream(p)
952 self.pg_enable_capture(self.pg_interfaces)
955 rx = self.pg2.get_capture(1)
956 self.verify_ip_o_mpls(rx[0],
958 self.pg2.remote_hosts[1].mac,
962 self.pg2.unconfig_ip4()
964 def test_arp_vrrp(self):
965 """ ARP reply with VRRP virtual src hw addr """
968 # IP packet destined for pg1 remote host arrives on pg0 resulting
969 # in an ARP request for the address of the remote host on pg1
971 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
972 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
973 UDP(sport=1234, dport=1234) /
976 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
978 self.verify_arp_req(rx1[0],
984 # ARP reply for address of pg1 remote host arrives on pg1 with
985 # the hw src addr set to a value in the VRRP IPv4 range of
988 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
989 ARP(op="is-at", hwdst=self.pg1.local_mac,
990 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
991 psrc=self.pg1.remote_ip4))
993 self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
996 # IP packet destined for pg1 remote host arrives on pg0 again.
997 # VPP should have an ARP entry for that address now and the packet
998 # should be sent out pg1.
1000 rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1002 self.verify_ip(rx1[0],
1004 "00:00:5e:00:01:09",
1005 self.pg0.remote_ip4,
1006 self.pg1.remote_ip4)
1008 self.pg1.admin_down()
1011 def test_arp_duplicates(self):
1012 """ ARP Duplicates"""
1015 # Generate some hosts on the LAN
1017 self.pg1.generate_remote_hosts(3)
1020 # Add host 1 on pg1 and pg2
1022 arp_pg1 = VppNeighbor(self,
1023 self.pg1.sw_if_index,
1024 self.pg1.remote_hosts[1].mac,
1025 self.pg1.remote_hosts[1].ip4)
1026 arp_pg1.add_vpp_config()
1027 arp_pg2 = VppNeighbor(self,
1028 self.pg2.sw_if_index,
1029 self.pg2.remote_mac,
1030 self.pg1.remote_hosts[1].ip4)
1031 arp_pg2.add_vpp_config()
1034 # IP packet destined for pg1 remote host arrives on pg1 again.
1036 p = (Ether(dst=self.pg0.local_mac,
1037 src=self.pg0.remote_mac) /
1038 IP(src=self.pg0.remote_ip4,
1039 dst=self.pg1.remote_hosts[1].ip4) /
1040 UDP(sport=1234, dport=1234) /
1043 self.pg0.add_stream(p)
1044 self.pg_enable_capture(self.pg_interfaces)
1047 rx1 = self.pg1.get_capture(1)
1049 self.verify_ip(rx1[0],
1051 self.pg1.remote_hosts[1].mac,
1052 self.pg0.remote_ip4,
1053 self.pg1.remote_hosts[1].ip4)
1056 # remove the duplicate on pg1
1057 # packet stream should generate ARPs out of pg1
1059 arp_pg1.remove_vpp_config()
1061 self.pg0.add_stream(p)
1062 self.pg_enable_capture(self.pg_interfaces)
1065 rx1 = self.pg1.get_capture(1)
1067 self.verify_arp_req(rx1[0],
1070 self.pg1.remote_hosts[1].ip4)
1075 arp_pg1.add_vpp_config()
1077 self.pg0.add_stream(p)
1078 self.pg_enable_capture(self.pg_interfaces)
1081 rx1 = self.pg1.get_capture(1)
1083 self.verify_ip(rx1[0],
1085 self.pg1.remote_hosts[1].mac,
1086 self.pg0.remote_ip4,
1087 self.pg1.remote_hosts[1].ip4)
1089 def test_arp_static(self):
1091 self.pg2.generate_remote_hosts(3)
1094 # Add a static ARP entry
1096 static_arp = VppNeighbor(self,
1097 self.pg2.sw_if_index,
1098 self.pg2.remote_hosts[1].mac,
1099 self.pg2.remote_hosts[1].ip4,
1101 static_arp.add_vpp_config()
1104 # Add the connected prefix to the interface
1106 self.pg2.config_ip4()
1109 # We should now find the adj-fib
1111 self.assertTrue(find_nbr(self,
1112 self.pg2.sw_if_index,
1113 self.pg2.remote_hosts[1].ip4,
1115 self.assertTrue(find_route(self,
1116 self.pg2.remote_hosts[1].ip4,
1120 # remove the connected
1122 self.pg2.unconfig_ip4()
1125 # put the interface into table 1
1127 self.pg2.set_table_ip4(1)
1130 # configure the same connected and expect to find the
1131 # adj fib in the new table
1133 self.pg2.config_ip4()
1134 self.assertTrue(find_route(self,
1135 self.pg2.remote_hosts[1].ip4,
1142 self.pg2.unconfig_ip4()
1143 self.pg2.set_table_ip4(0)
1145 def test_arp_incomplete(self):
1146 """ ARP Incomplete"""
1147 self.pg1.generate_remote_hosts(3)
1149 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1150 IP(src=self.pg0.remote_ip4,
1151 dst=self.pg1.remote_hosts[1].ip4) /
1152 UDP(sport=1234, dport=1234) /
1154 p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1155 IP(src=self.pg0.remote_ip4,
1156 dst=self.pg1.remote_hosts[2].ip4) /
1157 UDP(sport=1234, dport=1234) /
1161 # a packet to an unresolved destination generates an ARP request
1163 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1164 self.verify_arp_req(rx[0],
1167 self.pg1._remote_hosts[1].ip4)
1170 # add a neighbour for remote host 1
1172 static_arp = VppNeighbor(self,
1173 self.pg1.sw_if_index,
1174 self.pg1.remote_hosts[1].mac,
1175 self.pg1.remote_hosts[1].ip4,
1177 static_arp.add_vpp_config()
1180 # change the interface's MAC
1182 mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1183 scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1184 scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1185 mac_string = ''.join(mac)
1187 self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1191 # now ARP requests come from the new source mac
1193 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1194 self.verify_arp_req(rx[0],
1195 "00:00:00:33:33:33",
1197 self.pg1._remote_hosts[2].ip4)
1200 # packets to the resolved host also have the new source mac
1202 rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1203 self.verify_ip(rx[0],
1204 "00:00:00:33:33:33",
1205 self.pg1.remote_hosts[1].mac,
1206 self.pg0.remote_ip4,
1207 self.pg1.remote_hosts[1].ip4)
1210 # set the mac address on the interface that does not have a
1211 # configured subnet and thus no glean
1213 self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1216 def test_garp(self):
1220 # Generate some hosts on the LAN
1222 self.pg1.generate_remote_hosts(4)
1227 arp = VppNeighbor(self,
1228 self.pg1.sw_if_index,
1229 self.pg1.remote_hosts[1].mac,
1230 self.pg1.remote_hosts[1].ip4)
1231 arp.add_vpp_config()
1233 self.assertTrue(find_nbr(self,
1234 self.pg1.sw_if_index,
1235 self.pg1.remote_hosts[1].ip4,
1236 mac=self.pg1.remote_hosts[1].mac))
1239 # Send a GARP (request) to swap the host 1's address to that of host 2
1241 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1242 src=self.pg1.remote_hosts[2].mac) /
1244 hwdst=self.pg1.local_mac,
1245 hwsrc=self.pg1.remote_hosts[2].mac,
1246 pdst=self.pg1.remote_hosts[1].ip4,
1247 psrc=self.pg1.remote_hosts[1].ip4))
1249 self.pg1.add_stream(p1)
1250 self.pg_enable_capture(self.pg_interfaces)
1253 self.assertTrue(find_nbr(self,
1254 self.pg1.sw_if_index,
1255 self.pg1.remote_hosts[1].ip4,
1256 mac=self.pg1.remote_hosts[2].mac))
1259 # Send a GARP (reply) to swap the host 1's address to that of host 3
1261 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1262 src=self.pg1.remote_hosts[3].mac) /
1264 hwdst=self.pg1.local_mac,
1265 hwsrc=self.pg1.remote_hosts[3].mac,
1266 pdst=self.pg1.remote_hosts[1].ip4,
1267 psrc=self.pg1.remote_hosts[1].ip4))
1269 self.pg1.add_stream(p1)
1270 self.pg_enable_capture(self.pg_interfaces)
1273 self.assertTrue(find_nbr(self,
1274 self.pg1.sw_if_index,
1275 self.pg1.remote_hosts[1].ip4,
1276 mac=self.pg1.remote_hosts[3].mac))
1279 # GARPs (request nor replies) for host we don't know yet
1280 # don't result in new neighbour entries
1282 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1283 src=self.pg1.remote_hosts[3].mac) /
1285 hwdst=self.pg1.local_mac,
1286 hwsrc=self.pg1.remote_hosts[3].mac,
1287 pdst=self.pg1.remote_hosts[2].ip4,
1288 psrc=self.pg1.remote_hosts[2].ip4))
1290 self.pg1.add_stream(p1)
1291 self.pg_enable_capture(self.pg_interfaces)
1294 self.assertFalse(find_nbr(self,
1295 self.pg1.sw_if_index,
1296 self.pg1.remote_hosts[2].ip4))
1298 p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1299 src=self.pg1.remote_hosts[3].mac) /
1301 hwdst=self.pg1.local_mac,
1302 hwsrc=self.pg1.remote_hosts[3].mac,
1303 pdst=self.pg1.remote_hosts[2].ip4,
1304 psrc=self.pg1.remote_hosts[2].ip4))
1306 self.pg1.add_stream(p1)
1307 self.pg_enable_capture(self.pg_interfaces)
1310 self.assertFalse(find_nbr(self,
1311 self.pg1.sw_if_index,
1312 self.pg1.remote_hosts[2].ip4))
1314 def test_arp_incomplete(self):
1315 """ Incomplete Entries """
1318 # ensure that we throttle the ARP and ND requests
1320 self.pg0.generate_remote_hosts(2)
1325 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1326 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1327 self.pg0.sw_if_index)])
1328 ip_10_0_0_1.add_vpp_config()
1330 p1 = (Ether(dst=self.pg1.local_mac,
1331 src=self.pg1.remote_mac) /
1332 IP(src=self.pg1.remote_ip4,
1334 UDP(sport=1234, dport=1234) /
1337 self.pg1.add_stream(p1 * 257)
1338 self.pg_enable_capture(self.pg_interfaces)
1340 rx = self.pg0._get_capture(1)
1343 # how many we get is going to be dependent on the time for packet
1344 # processing but it should be small
1346 self.assertLess(len(rx), 64)
1351 ip_10_1 = VppIpRoute(self, "10::1", 128,
1352 [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1353 self.pg0.sw_if_index,
1354 proto=DpoProto.DPO_PROTO_IP6)],
1356 ip_10_1.add_vpp_config()
1358 p1 = (Ether(dst=self.pg1.local_mac,
1359 src=self.pg1.remote_mac) /
1360 IPv6(src=self.pg1.remote_ip6,
1362 UDP(sport=1234, dport=1234) /
1365 self.pg1.add_stream(p1 * 257)
1366 self.pg_enable_capture(self.pg_interfaces)
1368 rx = self.pg0._get_capture(1)
1371 # how many we get is going to be dependent on the time for packet
1372 # processing but it should be small
1374 self.assertLess(len(rx), 64)
1376 def test_arp_forus(self):
1377 """ ARP for for-us """
1380 # Test that VPP responds with ARP requests to addresses that
1381 # are connected and local routes.
1382 # Use one of the 'remote' addresses in the subnet as a local address
1383 # The intention of this route is that it then acts like a secondary
1384 # address added to an interface
1386 self.pg0.generate_remote_hosts(2)
1388 forus = VppIpRoute(self, self.pg0.remote_hosts[1].ip4, 32,
1389 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1390 self.pg0.sw_if_index)],
1392 forus.add_vpp_config()
1394 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1395 src=self.pg0.remote_mac) /
1397 hwdst=self.pg0.local_mac,
1398 hwsrc=self.pg0.remote_mac,
1399 pdst=self.pg0.remote_hosts[1].ip4,
1400 psrc=self.pg0.remote_ip4))
1402 rx = self.send_and_expect(self.pg0, [p], self.pg0)
1404 self.verify_arp_resp(rx[0],
1406 self.pg0.remote_mac,
1407 self.pg0.remote_hosts[1].ip4,
1408 self.pg0.remote_ip4)
1411 class NeighborStatsTestCase(VppTestCase):
1412 """ ARP/ND Counters """
1415 super(NeighborStatsTestCase, self).setUp()
1417 self.create_pg_interfaces(range(2))
1419 # pg0 configured with ip4 and 6 addresses used for input
1420 # pg1 configured with ip4 and 6 addresses used for output
1421 # pg2 is unnumbered to pg0
1422 for i in self.pg_interfaces:
1430 super(NeighborStatsTestCase, self).tearDown()
1432 for i in self.pg_interfaces:
1437 def test_arp_stats(self):
1438 """ ARP Counters """
1440 self.vapi.cli("adj counters enable")
1441 self.pg1.generate_remote_hosts(2)
1443 arp1 = VppNeighbor(self,
1444 self.pg1.sw_if_index,
1445 self.pg1.remote_hosts[0].mac,
1446 self.pg1.remote_hosts[0].ip4)
1447 arp1.add_vpp_config()
1448 arp2 = VppNeighbor(self,
1449 self.pg1.sw_if_index,
1450 self.pg1.remote_hosts[1].mac,
1451 self.pg1.remote_hosts[1].ip4)
1452 arp2.add_vpp_config()
1454 p1 = (Ether(dst=self.pg0.local_mac,
1455 src=self.pg0.remote_mac) /
1456 IP(src=self.pg0.remote_ip4,
1457 dst=self.pg1.remote_hosts[0].ip4) /
1458 UDP(sport=1234, dport=1234) /
1460 p2 = (Ether(dst=self.pg0.local_mac,
1461 src=self.pg0.remote_mac) /
1462 IP(src=self.pg0.remote_ip4,
1463 dst=self.pg1.remote_hosts[1].ip4) /
1464 UDP(sport=1234, dport=1234) /
1467 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1468 rx = self.send_and_expect(self.pg0, p2 * 65, self.pg1)
1470 self.assertEqual(65, arp1.get_stats()['packets'])
1471 self.assertEqual(65, arp2.get_stats()['packets'])
1473 rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
1474 self.assertEqual(130, arp1.get_stats()['packets'])
1476 def test_nd_stats(self):
1479 self.vapi.cli("adj counters enable")
1480 self.pg0.generate_remote_hosts(3)
1482 nd1 = VppNeighbor(self,
1483 self.pg0.sw_if_index,
1484 self.pg0.remote_hosts[1].mac,
1485 self.pg0.remote_hosts[1].ip6)
1486 nd1.add_vpp_config()
1487 nd2 = VppNeighbor(self,
1488 self.pg0.sw_if_index,
1489 self.pg0.remote_hosts[2].mac,
1490 self.pg0.remote_hosts[2].ip6)
1491 nd2.add_vpp_config()
1493 p1 = (Ether(dst=self.pg1.local_mac,
1494 src=self.pg1.remote_mac) /
1495 IPv6(src=self.pg1.remote_ip6,
1496 dst=self.pg0.remote_hosts[1].ip6) /
1497 UDP(sport=1234, dport=1234) /
1499 p2 = (Ether(dst=self.pg1.local_mac,
1500 src=self.pg1.remote_mac) /
1501 IPv6(src=self.pg1.remote_ip6,
1502 dst=self.pg0.remote_hosts[2].ip6) /
1503 UDP(sport=1234, dport=1234) /
1506 rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1507 rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1509 self.assertEqual(16, nd1.get_stats()['packets'])
1510 self.assertEqual(16, nd2.get_stats()['packets'])
1512 rx = self.send_and_expect(self.pg1, p1 * 65, self.pg0)
1513 self.assertEqual(81, nd1.get_stats()['packets'])
1516 if __name__ == '__main__':
1517 unittest.main(testRunner=VppTestRunner)