4 from socket import AF_INET, AF_INET6, inet_pton
6 from framework import VppTestCase, VppTestRunner
7 from vpp_neighbor import VppNeighbor, find_nbr
9 from scapy.packet import Raw
10 from scapy.layers.l2 import Ether, ARP
11 from scapy.layers.inet import IP, UDP
13 # not exported by scapy, so redefined here
14 arp_opts = {"who-has": 1, "is-at": 2}
17 class ARPTestCase(VppTestCase):
21 super(ARPTestCase, self).setUp()
23 # create 3 pg interfaces
24 self.create_pg_interfaces(range(4))
26 # pg0 configured with ip4 and 6 addresses used for input
27 # pg1 configured with ip4 and 6 addresses used for output
28 # pg2 is unnumbered to pg0
29 for i in self.pg_interfaces:
34 self.pg0.resolve_arp()
39 # pg3 in a different VRF
40 self.pg3.set_table_ip4(1)
44 super(ARPTestCase, self).tearDown()
45 for i in self.pg_interfaces:
50 def verify_arp_req(self, rx, smac, sip, dip):
52 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
53 self.assertEqual(ether.src, smac)
56 self.assertEqual(arp.hwtype, 1)
57 self.assertEqual(arp.ptype, 0x800)
58 self.assertEqual(arp.hwlen, 6)
59 self.assertEqual(arp.plen, 4)
60 self.assertEqual(arp.op, arp_opts["who-has"])
61 self.assertEqual(arp.hwsrc, smac)
62 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
63 self.assertEqual(arp.psrc, sip)
64 self.assertEqual(arp.pdst, dip)
66 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
68 self.assertEqual(ether.dst, dmac)
69 self.assertEqual(ether.src, smac)
72 self.assertEqual(arp.hwtype, 1)
73 self.assertEqual(arp.ptype, 0x800)
74 self.assertEqual(arp.hwlen, 6)
75 self.assertEqual(arp.plen, 4)
76 self.assertEqual(arp.op, arp_opts["is-at"])
77 self.assertEqual(arp.hwsrc, smac)
78 self.assertEqual(arp.hwdst, dmac)
79 self.assertEqual(arp.psrc, sip)
80 self.assertEqual(arp.pdst, dip)
82 def verify_ip(self, rx, smac, dmac, sip, dip):
84 self.assertEqual(ether.dst, dmac)
85 self.assertEqual(ether.src, smac)
88 self.assertEqual(ip.src, sip)
89 self.assertEqual(ip.dst, dip)
91 def send_and_assert_no_replies(self, intf, pkts, remark):
93 self.pg_enable_capture(self.pg_interfaces)
95 for i in self.pg_interfaces:
96 i.assert_nothing_captured(remark=remark)
102 # Generate some hosts on the LAN
104 self.pg1.generate_remote_hosts(4)
107 # Send IP traffic to one of these unresolved hosts.
108 # expect the generation of an ARP request
110 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
111 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
112 UDP(sport=1234, dport=1234) /
115 self.pg0.add_stream(p)
116 self.pg_enable_capture(self.pg_interfaces)
119 rx = self.pg1.get_capture(1)
121 self.verify_arp_req(rx[0],
124 self.pg1._remote_hosts[1].ip4)
127 # And a dynamic ARP entry for host 1
129 dyn_arp = VppNeighbor(self,
130 self.pg1.sw_if_index,
131 self.pg1.remote_hosts[1].mac,
132 self.pg1.remote_hosts[1].ip4)
133 dyn_arp.add_vpp_config()
136 # now we expect IP traffic forwarded
138 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
139 IP(src=self.pg0.remote_ip4,
140 dst=self.pg1._remote_hosts[1].ip4) /
141 UDP(sport=1234, dport=1234) /
144 self.pg0.add_stream(dyn_p)
145 self.pg_enable_capture(self.pg_interfaces)
148 rx = self.pg1.get_capture(1)
150 self.verify_ip(rx[0],
152 self.pg1.remote_hosts[1].mac,
154 self.pg1._remote_hosts[1].ip4)
157 # And a Static ARP entry for host 2
159 static_arp = VppNeighbor(self,
160 self.pg1.sw_if_index,
161 self.pg1.remote_hosts[2].mac,
162 self.pg1.remote_hosts[2].ip4,
164 static_arp.add_vpp_config()
166 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
167 IP(src=self.pg0.remote_ip4,
168 dst=self.pg1._remote_hosts[2].ip4) /
169 UDP(sport=1234, dport=1234) /
172 self.pg0.add_stream(static_p)
173 self.pg_enable_capture(self.pg_interfaces)
176 rx = self.pg1.get_capture(1)
178 self.verify_ip(rx[0],
180 self.pg1.remote_hosts[2].mac,
182 self.pg1._remote_hosts[2].ip4)
185 # flap the link. dynamic ARPs get flush, statics don't
187 self.pg1.admin_down()
190 self.pg0.add_stream(static_p)
191 self.pg_enable_capture(self.pg_interfaces)
193 rx = self.pg1.get_capture(1)
195 self.verify_ip(rx[0],
197 self.pg1.remote_hosts[2].mac,
199 self.pg1._remote_hosts[2].ip4)
201 self.pg0.add_stream(dyn_p)
202 self.pg_enable_capture(self.pg_interfaces)
205 rx = self.pg1.get_capture(1)
206 self.verify_arp_req(rx[0],
209 self.pg1._remote_hosts[1].ip4)
212 # Send an ARP request from one of the so-far unlearned remote hosts
214 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
215 src=self.pg1._remote_hosts[3].mac) /
217 hwsrc=self.pg1._remote_hosts[3].mac,
218 pdst=self.pg1.local_ip4,
219 psrc=self.pg1._remote_hosts[3].ip4))
221 self.pg1.add_stream(p)
222 self.pg_enable_capture(self.pg_interfaces)
225 rx = self.pg1.get_capture(1)
226 self.verify_arp_resp(rx[0],
228 self.pg1._remote_hosts[3].mac,
230 self.pg1._remote_hosts[3].ip4)
233 # VPP should have learned the mapping for the remote host
235 self.assertTrue(find_nbr(self,
236 self.pg1.sw_if_index,
237 self.pg1._remote_hosts[3].ip4))
241 # 1 - don't respond to ARP request for address not within the
242 # interface's sub-net
244 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
246 hwsrc=self.pg0.remote_mac,
248 psrc=self.pg0.remote_ip4))
249 self.send_and_assert_no_replies(self.pg0, p,
250 "ARP req for non-local destination")
253 # 2 - don't respond to ARP request from an address not within the
254 # interface's sub-net
256 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
258 hwsrc=self.pg0.remote_mac,
260 pdst=self.pg0.local_ip4))
261 self.send_and_assert_no_replies(self.pg0, p,
262 "ARP req for non-local source")
265 # 3 - don't respond to ARP request from an address that belongs to
268 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
270 hwsrc=self.pg0.remote_mac,
271 psrc=self.pg0.local_ip4,
272 pdst=self.pg0.local_ip4))
273 self.send_and_assert_no_replies(self.pg0, p,
274 "ARP req for non-local source")
277 # 4 - don't respond to ARP requests that has mac source different
278 # from ARP request HW source
281 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
283 hwsrc="00:00:00:DE:AD:BE",
284 psrc=self.pg0.remote_ip4,
285 pdst=self.pg0.local_ip4))
286 self.send_and_assert_no_replies(self.pg0, p,
287 "ARP req for non-local source")
292 dyn_arp.remove_vpp_config()
293 static_arp.remove_vpp_config()
295 def test_proxy_arp(self):
299 # Proxy ARP rewquest packets for each interface
301 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
302 dst="ff:ff:ff:ff:ff:ff") /
304 hwsrc=self.pg2.remote_mac,
306 psrc=self.pg1.remote_ip4))
307 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
308 dst="ff:ff:ff:ff:ff:ff") /
310 hwsrc=self.pg0.remote_mac,
312 psrc=self.pg0.remote_ip4))
313 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
314 dst="ff:ff:ff:ff:ff:ff") /
316 hwsrc=self.pg1.remote_mac,
318 psrc=self.pg1.remote_ip4))
319 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
320 dst="ff:ff:ff:ff:ff:ff") /
322 hwsrc=self.pg3.remote_mac,
324 psrc=self.pg3.remote_ip4))
327 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
329 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
330 inet_pton(AF_INET, "10.10.10.124"))
333 # No responses are sent when the interfaces are not enabled for proxy
336 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
337 "ARP req from unconfigured interface")
338 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
339 "ARP req from unconfigured interface")
342 # Make pg2 un-numbered to pg1
345 self.pg2.set_unnumbered(self.pg1.sw_if_index)
347 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
348 "ARP req from unnumbered interface")
351 # Enable each interface to reply to proxy ARPs
353 for i in self.pg_interfaces:
357 # Now each of the interfaces should reply to a request to a proxied
360 self.pg0.add_stream(arp_req_pg0)
361 self.pg_enable_capture(self.pg_interfaces)
364 rx = self.pg0.get_capture(1)
365 self.verify_arp_resp(rx[0],
371 self.pg1.add_stream(arp_req_pg1)
372 self.pg_enable_capture(self.pg_interfaces)
375 rx = self.pg1.get_capture(1)
376 self.verify_arp_resp(rx[0],
382 self.pg2.add_stream(arp_req_pg2)
383 self.pg_enable_capture(self.pg_interfaces)
386 rx = self.pg2.get_capture(1)
387 self.verify_arp_resp(rx[0],
394 # A request for an address out of the configured range
396 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
397 dst="ff:ff:ff:ff:ff:ff") /
399 hwsrc=self.pg1.remote_mac,
401 psrc=self.pg1.remote_ip4))
402 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
403 "ARP req out of range HI")
404 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
405 dst="ff:ff:ff:ff:ff:ff") /
407 hwsrc=self.pg1.remote_mac,
409 psrc=self.pg1.remote_ip4))
410 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
411 "ARP req out of range Low")
414 # Request for an address in the proxy range but from an interface
417 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
418 "ARP req from different VRF")
421 # Disable Each interface for proxy ARP
422 # - expect none to respond
424 for i in self.pg_interfaces:
427 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
428 "ARP req from disable")
429 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
430 "ARP req from disable")
431 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
432 "ARP req from disable")