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 scapy.packet import Raw
11 from scapy.layers.l2 import Ether, ARP
12 from scapy.layers.inet import IP, UDP
13 from scapy.contrib.mpls import MPLS
15 # not exported by scapy, so redefined here
16 arp_opts = {"who-has": 1, "is-at": 2}
19 class ARPTestCase(VppTestCase):
23 super(ARPTestCase, self).setUp()
25 # create 3 pg interfaces
26 self.create_pg_interfaces(range(4))
28 # pg0 configured with ip4 and 6 addresses used for input
29 # pg1 configured with ip4 and 6 addresses used for output
30 # pg2 is unnumbered to pg0
31 for i in self.pg_interfaces:
36 self.pg0.resolve_arp()
41 # pg3 in a different VRF
42 self.pg3.set_table_ip4(1)
46 super(ARPTestCase, self).tearDown()
47 for i in self.pg_interfaces:
52 def verify_arp_req(self, rx, smac, sip, dip):
54 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
55 self.assertEqual(ether.src, smac)
58 self.assertEqual(arp.hwtype, 1)
59 self.assertEqual(arp.ptype, 0x800)
60 self.assertEqual(arp.hwlen, 6)
61 self.assertEqual(arp.plen, 4)
62 self.assertEqual(arp.op, arp_opts["who-has"])
63 self.assertEqual(arp.hwsrc, smac)
64 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
65 self.assertEqual(arp.psrc, sip)
66 self.assertEqual(arp.pdst, dip)
68 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
70 self.assertEqual(ether.dst, dmac)
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["is-at"])
79 self.assertEqual(arp.hwsrc, smac)
80 self.assertEqual(arp.hwdst, dmac)
81 self.assertEqual(arp.psrc, sip)
82 self.assertEqual(arp.pdst, dip)
84 def verify_ip(self, rx, smac, dmac, sip, dip):
86 self.assertEqual(ether.dst, dmac)
87 self.assertEqual(ether.src, smac)
90 self.assertEqual(ip.src, sip)
91 self.assertEqual(ip.dst, dip)
93 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
95 self.assertEqual(ether.dst, dmac)
96 self.assertEqual(ether.src, smac)
99 self.assertTrue(mpls.label, label)
102 self.assertEqual(ip.src, sip)
103 self.assertEqual(ip.dst, dip)
105 def send_and_assert_no_replies(self, intf, pkts, remark):
106 intf.add_stream(pkts)
107 self.pg_enable_capture(self.pg_interfaces)
109 for i in self.pg_interfaces:
110 i.assert_nothing_captured(remark=remark)
116 # Generate some hosts on the LAN
118 self.pg1.generate_remote_hosts(6)
121 # Send IP traffic to one of these unresolved hosts.
122 # expect the generation of an ARP request
124 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
125 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
126 UDP(sport=1234, dport=1234) /
129 self.pg0.add_stream(p)
130 self.pg_enable_capture(self.pg_interfaces)
133 rx = self.pg1.get_capture(1)
135 self.verify_arp_req(rx[0],
138 self.pg1._remote_hosts[1].ip4)
141 # And a dynamic ARP entry for host 1
143 dyn_arp = VppNeighbor(self,
144 self.pg1.sw_if_index,
145 self.pg1.remote_hosts[1].mac,
146 self.pg1.remote_hosts[1].ip4)
147 dyn_arp.add_vpp_config()
150 # now we expect IP traffic forwarded
152 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
153 IP(src=self.pg0.remote_ip4,
154 dst=self.pg1._remote_hosts[1].ip4) /
155 UDP(sport=1234, dport=1234) /
158 self.pg0.add_stream(dyn_p)
159 self.pg_enable_capture(self.pg_interfaces)
162 rx = self.pg1.get_capture(1)
164 self.verify_ip(rx[0],
166 self.pg1.remote_hosts[1].mac,
168 self.pg1._remote_hosts[1].ip4)
171 # And a Static ARP entry for host 2
173 static_arp = VppNeighbor(self,
174 self.pg1.sw_if_index,
175 self.pg1.remote_hosts[2].mac,
176 self.pg1.remote_hosts[2].ip4,
178 static_arp.add_vpp_config()
180 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
181 IP(src=self.pg0.remote_ip4,
182 dst=self.pg1._remote_hosts[2].ip4) /
183 UDP(sport=1234, dport=1234) /
186 self.pg0.add_stream(static_p)
187 self.pg_enable_capture(self.pg_interfaces)
190 rx = self.pg1.get_capture(1)
192 self.verify_ip(rx[0],
194 self.pg1.remote_hosts[2].mac,
196 self.pg1._remote_hosts[2].ip4)
199 # flap the link. dynamic ARPs get flush, statics don't
201 self.pg1.admin_down()
204 self.pg0.add_stream(static_p)
205 self.pg_enable_capture(self.pg_interfaces)
207 rx = self.pg1.get_capture(1)
209 self.verify_ip(rx[0],
211 self.pg1.remote_hosts[2].mac,
213 self.pg1._remote_hosts[2].ip4)
215 self.pg0.add_stream(dyn_p)
216 self.pg_enable_capture(self.pg_interfaces)
219 rx = self.pg1.get_capture(1)
220 self.verify_arp_req(rx[0],
223 self.pg1._remote_hosts[1].ip4)
226 # Send an ARP request from one of the so-far unlearned remote hosts
228 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
229 src=self.pg1._remote_hosts[3].mac) /
231 hwsrc=self.pg1._remote_hosts[3].mac,
232 pdst=self.pg1.local_ip4,
233 psrc=self.pg1._remote_hosts[3].ip4))
235 self.pg1.add_stream(p)
236 self.pg_enable_capture(self.pg_interfaces)
239 rx = self.pg1.get_capture(1)
240 self.verify_arp_resp(rx[0],
242 self.pg1._remote_hosts[3].mac,
244 self.pg1._remote_hosts[3].ip4)
247 # VPP should have learned the mapping for the remote host
249 self.assertTrue(find_nbr(self,
250 self.pg1.sw_if_index,
251 self.pg1._remote_hosts[3].ip4))
254 # A neighbor entry that has no associated FIB-entry
256 arp_no_fib = VppNeighbor(self,
257 self.pg1.sw_if_index,
258 self.pg1.remote_hosts[4].mac,
259 self.pg1.remote_hosts[4].ip4,
261 arp_no_fib.add_vpp_config()
264 # check we have the neighbor, but no route
266 self.assertTrue(find_nbr(self,
267 self.pg1.sw_if_index,
268 self.pg1._remote_hosts[4].ip4))
269 self.assertFalse(find_route(self,
270 self.pg1._remote_hosts[4].ip4,
273 # Unnumbered pg2 to pg1
275 self.pg2.set_unnumbered(self.pg1.sw_if_index)
278 # now we can form adjacencies out of pg2 from within pg1's subnet
280 arp_unnum = VppNeighbor(self,
281 self.pg2.sw_if_index,
282 self.pg1.remote_hosts[5].mac,
283 self.pg1.remote_hosts[5].ip4)
284 arp_unnum.add_vpp_config()
286 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
287 IP(src=self.pg0.remote_ip4,
288 dst=self.pg1._remote_hosts[5].ip4) /
289 UDP(sport=1234, dport=1234) /
292 self.pg0.add_stream(p)
293 self.pg_enable_capture(self.pg_interfaces)
296 rx = self.pg2.get_capture(1)
298 self.verify_ip(rx[0],
300 self.pg1.remote_hosts[5].mac,
302 self.pg1._remote_hosts[5].ip4)
306 # 1 - don't respond to ARP request for address not within the
307 # interface's sub-net
309 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
311 hwsrc=self.pg0.remote_mac,
313 psrc=self.pg0.remote_ip4))
314 self.send_and_assert_no_replies(self.pg0, p,
315 "ARP req for non-local destination")
318 # 2 - don't respond to ARP request from an address not within the
319 # interface's sub-net
321 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
323 hwsrc=self.pg0.remote_mac,
325 pdst=self.pg0.local_ip4))
326 self.send_and_assert_no_replies(self.pg0, p,
327 "ARP req for non-local source")
330 # 3 - don't respond to ARP request from an address that belongs to
333 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
335 hwsrc=self.pg0.remote_mac,
336 psrc=self.pg0.local_ip4,
337 pdst=self.pg0.local_ip4))
338 self.send_and_assert_no_replies(self.pg0, p,
339 "ARP req for non-local source")
342 # 4 - don't respond to ARP requests that has mac source different
343 # from ARP request HW source
346 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
348 hwsrc="00:00:00:DE:AD:BE",
349 psrc=self.pg0.remote_ip4,
350 pdst=self.pg0.local_ip4))
351 self.send_and_assert_no_replies(self.pg0, p,
352 "ARP req for non-local source")
357 dyn_arp.remove_vpp_config()
358 static_arp.remove_vpp_config()
359 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
361 def test_proxy_arp(self):
365 # Proxy ARP rewquest packets for each interface
367 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
368 dst="ff:ff:ff:ff:ff:ff") /
370 hwsrc=self.pg2.remote_mac,
372 psrc=self.pg1.remote_ip4))
373 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
374 dst="ff:ff:ff:ff:ff:ff") /
376 hwsrc=self.pg0.remote_mac,
378 psrc=self.pg0.remote_ip4))
379 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
380 dst="ff:ff:ff:ff:ff:ff") /
382 hwsrc=self.pg1.remote_mac,
384 psrc=self.pg1.remote_ip4))
385 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
386 dst="ff:ff:ff:ff:ff:ff") /
388 hwsrc=self.pg3.remote_mac,
390 psrc=self.pg3.remote_ip4))
393 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
395 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
396 inet_pton(AF_INET, "10.10.10.124"))
399 # No responses are sent when the interfaces are not enabled for proxy
402 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
403 "ARP req from unconfigured interface")
404 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
405 "ARP req from unconfigured interface")
408 # Make pg2 un-numbered to pg1
411 self.pg2.set_unnumbered(self.pg1.sw_if_index)
413 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
414 "ARP req from unnumbered interface")
417 # Enable each interface to reply to proxy ARPs
419 for i in self.pg_interfaces:
423 # Now each of the interfaces should reply to a request to a proxied
426 self.pg0.add_stream(arp_req_pg0)
427 self.pg_enable_capture(self.pg_interfaces)
430 rx = self.pg0.get_capture(1)
431 self.verify_arp_resp(rx[0],
437 self.pg1.add_stream(arp_req_pg1)
438 self.pg_enable_capture(self.pg_interfaces)
441 rx = self.pg1.get_capture(1)
442 self.verify_arp_resp(rx[0],
448 self.pg2.add_stream(arp_req_pg2)
449 self.pg_enable_capture(self.pg_interfaces)
452 rx = self.pg2.get_capture(1)
453 self.verify_arp_resp(rx[0],
460 # A request for an address out of the configured range
462 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
463 dst="ff:ff:ff:ff:ff:ff") /
465 hwsrc=self.pg1.remote_mac,
467 psrc=self.pg1.remote_ip4))
468 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
469 "ARP req out of range HI")
470 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
471 dst="ff:ff:ff:ff:ff:ff") /
473 hwsrc=self.pg1.remote_mac,
475 psrc=self.pg1.remote_ip4))
476 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
477 "ARP req out of range Low")
480 # Request for an address in the proxy range but from an interface
483 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
484 "ARP req from different VRF")
487 # Disable Each interface for proxy ARP
488 # - expect none to respond
490 for i in self.pg_interfaces:
493 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
494 "ARP req from disable")
495 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
496 "ARP req from disable")
497 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
498 "ARP req from disable")
501 # clean up on interface 2
503 self.pg2.set_unnumbered(self.pg1.sw_if_index)
509 # Interface 2 does not yet have ip4 config
511 self.pg2.config_ip4()
512 self.pg2.generate_remote_hosts(2)
515 # Add a reoute with out going label via an ARP unresolved next-hop
517 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
518 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
519 self.pg2.sw_if_index,
521 ip_10_0_0_1.add_vpp_config()
524 # packets should generate an ARP request
526 p = (Ether(src=self.pg0.remote_mac,
527 dst=self.pg0.local_mac) /
528 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
529 UDP(sport=1234, dport=1234) /
532 self.pg0.add_stream(p)
533 self.pg_enable_capture(self.pg_interfaces)
536 rx = self.pg2.get_capture(1)
537 self.verify_arp_req(rx[0],
540 self.pg2._remote_hosts[1].ip4)
543 # now resolve the neighbours
545 self.pg2.configure_ipv4_neighbors()
548 # Now packet should be properly MPLS encapped.
549 # This verifies that MPLS link-type adjacencies are completed
550 # when the ARP entry resolves
552 self.pg0.add_stream(p)
553 self.pg_enable_capture(self.pg_interfaces)
556 rx = self.pg2.get_capture(1)
557 self.verify_ip_o_mpls(rx[0],
559 self.pg2.remote_hosts[1].mac,
564 if __name__ == '__main__':
565 unittest.main(testRunner=VppTestRunner)