blob: 6a60809160b5d48d4fccd4b12b1d49d123279026 [file] [log] [blame]
Neale Ranns39f9d8b2017-02-16 21:57:05 -08001#!/usr/bin/env python
2
3import unittest
4from socket import AF_INET, AF_INET6, inet_pton
5
6from framework import VppTestCase, VppTestRunner
7from vpp_neighbor import VppNeighbor, find_nbr
8
9from scapy.packet import Raw
10from scapy.layers.l2 import Ether, ARP
11from scapy.layers.inet import IP, UDP
12
13# not exported by scapy, so redefined here
14arp_opts = {"who-has": 1, "is-at": 2}
15
16
17class ARPTestCase(VppTestCase):
18 """ ARP Test Case """
19
20 def setUp(self):
21 super(ARPTestCase, self).setUp()
22
23 # create 3 pg interfaces
24 self.create_pg_interfaces(range(4))
25
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:
30 i.admin_up()
31
32 self.pg0.config_ip4()
33 self.pg0.config_ip6()
34 self.pg0.resolve_arp()
35
36 self.pg1.config_ip4()
37 self.pg1.config_ip6()
38
39 # pg3 in a different VRF
40 self.pg3.set_table_ip4(1)
41 self.pg3.config_ip4()
42
43 def verify_arp_req(self, rx, smac, sip, dip):
44 ether = rx[Ether]
45 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
46 self.assertEqual(ether.src, smac)
47
48 arp = rx[ARP]
49 self.assertEqual(arp.hwtype, 1)
50 self.assertEqual(arp.ptype, 0x800)
51 self.assertEqual(arp.hwlen, 6)
52 self.assertEqual(arp.plen, 4)
53 self.assertEqual(arp.op, arp_opts["who-has"])
54 self.assertEqual(arp.hwsrc, smac)
55 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
56 self.assertEqual(arp.psrc, sip)
57 self.assertEqual(arp.pdst, dip)
58
59 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
60 ether = rx[Ether]
61 self.assertEqual(ether.dst, dmac)
62 self.assertEqual(ether.src, smac)
63
64 arp = rx[ARP]
65 self.assertEqual(arp.hwtype, 1)
66 self.assertEqual(arp.ptype, 0x800)
67 self.assertEqual(arp.hwlen, 6)
68 self.assertEqual(arp.plen, 4)
69 self.assertEqual(arp.op, arp_opts["is-at"])
70 self.assertEqual(arp.hwsrc, smac)
71 self.assertEqual(arp.hwdst, dmac)
72 self.assertEqual(arp.psrc, sip)
73 self.assertEqual(arp.pdst, dip)
74
75 def verify_ip(self, rx, smac, dmac, sip, dip):
76 ether = rx[Ether]
77 self.assertEqual(ether.dst, dmac)
78 self.assertEqual(ether.src, smac)
79
80 ip = rx[IP]
81 self.assertEqual(ip.src, sip)
82 self.assertEqual(ip.dst, dip)
83
84 def send_and_assert_no_replies(self, intf, pkts, remark):
85 intf.add_stream(pkts)
86 self.pg_enable_capture(self.pg_interfaces)
87 self.pg_start()
88 for i in self.pg_interfaces:
89 i.assert_nothing_captured(remark=remark)
90
91 def test_arp(self):
92 """ ARP """
93
94 #
95 # Generate some hosts on the LAN
96 #
97 self.pg1.generate_remote_hosts(4)
98
99 #
100 # Send IP traffic to one of these unresolved hosts.
101 # expect the generation of an ARP request
102 #
103 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
104 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
105 UDP(sport=1234, dport=1234) /
106 Raw())
107
108 self.pg0.add_stream(p)
109 self.pg_enable_capture(self.pg_interfaces)
110 self.pg_start()
111
112 rx = self.pg1.get_capture(1)
113
114 self.verify_arp_req(rx[0],
115 self.pg1.local_mac,
116 self.pg1.local_ip4,
117 self.pg1._remote_hosts[1].ip4)
118
119 #
120 # And a dynamic ARP entry for host 1
121 #
122 dyn_arp = VppNeighbor(self,
123 self.pg1.sw_if_index,
124 self.pg1.remote_hosts[1].mac,
125 self.pg1.remote_hosts[1].ip4)
126 dyn_arp.add_vpp_config()
127
128 #
129 # now we expect IP traffic forwarded
130 #
131 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
132 IP(src=self.pg0.remote_ip4,
133 dst=self.pg1._remote_hosts[1].ip4) /
134 UDP(sport=1234, dport=1234) /
135 Raw())
136
137 self.pg0.add_stream(dyn_p)
138 self.pg_enable_capture(self.pg_interfaces)
139 self.pg_start()
140
141 rx = self.pg1.get_capture(1)
142
143 self.verify_ip(rx[0],
144 self.pg1.local_mac,
145 self.pg1.remote_hosts[1].mac,
146 self.pg0.remote_ip4,
147 self.pg1._remote_hosts[1].ip4)
148
149 #
150 # And a Static ARP entry for host 2
151 #
152 static_arp = VppNeighbor(self,
153 self.pg1.sw_if_index,
154 self.pg1.remote_hosts[2].mac,
155 self.pg1.remote_hosts[2].ip4,
156 is_static=1)
157 static_arp.add_vpp_config()
158
159 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
160 IP(src=self.pg0.remote_ip4,
161 dst=self.pg1._remote_hosts[2].ip4) /
162 UDP(sport=1234, dport=1234) /
163 Raw())
164
165 self.pg0.add_stream(static_p)
166 self.pg_enable_capture(self.pg_interfaces)
167 self.pg_start()
168
169 rx = self.pg1.get_capture(1)
170
171 self.verify_ip(rx[0],
172 self.pg1.local_mac,
173 self.pg1.remote_hosts[2].mac,
174 self.pg0.remote_ip4,
175 self.pg1._remote_hosts[2].ip4)
176
177 #
178 # flap the link. dynamic ARPs get flush, statics don't
179 #
180 self.pg1.admin_down()
181 self.pg1.admin_up()
182
183 self.pg0.add_stream(static_p)
184 self.pg_enable_capture(self.pg_interfaces)
185 self.pg_start()
186 rx = self.pg1.get_capture(1)
187
188 self.verify_ip(rx[0],
189 self.pg1.local_mac,
190 self.pg1.remote_hosts[2].mac,
191 self.pg0.remote_ip4,
192 self.pg1._remote_hosts[2].ip4)
193
194 self.pg0.add_stream(dyn_p)
195 self.pg_enable_capture(self.pg_interfaces)
196 self.pg_start()
197
198 rx = self.pg1.get_capture(1)
199 self.verify_arp_req(rx[0],
200 self.pg1.local_mac,
201 self.pg1.local_ip4,
202 self.pg1._remote_hosts[1].ip4)
203
204 #
205 # Send an ARP request from one of the so-far unlearned remote hosts
206 #
207 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
208 src=self.pg1._remote_hosts[3].mac) /
209 ARP(op="who-has",
210 hwsrc=self.pg1._remote_hosts[3].mac,
211 pdst=self.pg1.local_ip4,
212 psrc=self.pg1._remote_hosts[3].ip4))
213
214 self.pg1.add_stream(p)
215 self.pg_enable_capture(self.pg_interfaces)
216 self.pg_start()
217
218 rx = self.pg1.get_capture(1)
219 self.verify_arp_resp(rx[0],
220 self.pg1.local_mac,
221 self.pg1._remote_hosts[3].mac,
222 self.pg1.local_ip4,
223 self.pg1._remote_hosts[3].ip4)
224
225 #
226 # VPP should have learned the mapping for the remote host
227 #
228 self.assertTrue(find_nbr(self,
229 self.pg1.sw_if_index,
230 self.pg1._remote_hosts[3].ip4))
231
232 #
233 # ERROR Cases
234 # 1 - don't respond to ARP request for address not within the
235 # interface's sub-net
236 #
237 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
238 ARP(op="who-has",
239 hwsrc=self.pg0.remote_mac,
240 pdst="10.10.10.3",
241 psrc=self.pg0.remote_ip4))
242 self.send_and_assert_no_replies(self.pg0, p,
243 "ARP req for non-local destination")
244
245 #
246 # 2 - don't respond to ARP request from an address not within the
247 # interface's sub-net
248 #
249 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
250 ARP(op="who-has",
251 hwsrc=self.pg0.remote_mac,
252 psrc="10.10.10.3",
253 pdst=self.pg0.local_ip4))
254 self.send_and_assert_no_replies(self.pg0, p,
255 "ARP req for non-local source")
256
257 #
258 # 3 - don't respond to ARP request from an address that belongs to
259 # the router
260 #
261 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
262 ARP(op="who-has",
263 hwsrc=self.pg0.remote_mac,
264 psrc=self.pg0.local_ip4,
265 pdst=self.pg0.local_ip4))
266 self.send_and_assert_no_replies(self.pg0, p,
267 "ARP req for non-local source")
268
269 #
270 # 4 - don't respond to ARP requests that has mac source different
271 # from ARP request HW source
272 # the router
273 #
274 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
275 ARP(op="who-has",
276 hwsrc="00:00:00:DE:AD:BE",
277 psrc=self.pg0.remote_ip4,
278 pdst=self.pg0.local_ip4))
279 self.send_and_assert_no_replies(self.pg0, p,
280 "ARP req for non-local source")
281
282 #
283 # cleanup
284 #
285 dyn_arp.remove_vpp_config()
286 static_arp.remove_vpp_config()
287
288 def test_proxy_arp(self):
289 """ Proxy ARP """
290
291 #
292 # Proxy ARP rewquest packets for each interface
293 #
294 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
295 dst="ff:ff:ff:ff:ff:ff") /
296 ARP(op="who-has",
297 hwsrc=self.pg2.remote_mac,
298 pdst="10.10.10.3",
299 psrc=self.pg1.remote_ip4))
300 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
301 dst="ff:ff:ff:ff:ff:ff") /
302 ARP(op="who-has",
303 hwsrc=self.pg0.remote_mac,
304 pdst="10.10.10.3",
305 psrc=self.pg0.remote_ip4))
306 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
307 dst="ff:ff:ff:ff:ff:ff") /
308 ARP(op="who-has",
309 hwsrc=self.pg1.remote_mac,
310 pdst="10.10.10.3",
311 psrc=self.pg1.remote_ip4))
312 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
313 dst="ff:ff:ff:ff:ff:ff") /
314 ARP(op="who-has",
315 hwsrc=self.pg3.remote_mac,
316 pdst="10.10.10.3",
317 psrc=self.pg3.remote_ip4))
318
319 #
320 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
321 #
322 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
323 inet_pton(AF_INET, "10.10.10.124"))
324
325 #
326 # No responses are sent when the interfaces are not enabled for proxy
327 # ARP
328 #
329 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
330 "ARP req from unconfigured interface")
331 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
332 "ARP req from unconfigured interface")
333
334 #
335 # Make pg2 un-numbered to pg1
336 # still won't reply.
337 #
338 self.pg2.set_unnumbered(self.pg1.sw_if_index)
339
340 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
341 "ARP req from unnumbered interface")
342
343 #
344 # Enable each interface to reply to proxy ARPs
345 #
346 for i in self.pg_interfaces:
347 i.set_proxy_arp()
348
349 #
350 # Now each of the interfaces should reply to a request to a proxied
351 # address
352 #
353 self.pg0.add_stream(arp_req_pg0)
354 self.pg_enable_capture(self.pg_interfaces)
355 self.pg_start()
356
357 rx = self.pg0.get_capture(1)
358 self.verify_arp_resp(rx[0],
359 self.pg0.local_mac,
360 self.pg0.remote_mac,
361 "10.10.10.3",
362 self.pg0.remote_ip4)
363
364 self.pg1.add_stream(arp_req_pg1)
365 self.pg_enable_capture(self.pg_interfaces)
366 self.pg_start()
367
368 rx = self.pg1.get_capture(1)
369 self.verify_arp_resp(rx[0],
370 self.pg1.local_mac,
371 self.pg1.remote_mac,
372 "10.10.10.3",
373 self.pg1.remote_ip4)
374
375 self.pg2.add_stream(arp_req_pg2)
376 self.pg_enable_capture(self.pg_interfaces)
377 self.pg_start()
378
379 rx = self.pg2.get_capture(1)
380 self.verify_arp_resp(rx[0],
381 self.pg2.local_mac,
382 self.pg2.remote_mac,
383 "10.10.10.3",
384 self.pg1.remote_ip4)
385
386 #
387 # A request for an address out of the configured range
388 #
389 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
390 dst="ff:ff:ff:ff:ff:ff") /
391 ARP(op="who-has",
392 hwsrc=self.pg1.remote_mac,
393 pdst="10.10.10.125",
394 psrc=self.pg1.remote_ip4))
395 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
396 "ARP req out of range HI")
397 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
398 dst="ff:ff:ff:ff:ff:ff") /
399 ARP(op="who-has",
400 hwsrc=self.pg1.remote_mac,
401 pdst="10.10.10.1",
402 psrc=self.pg1.remote_ip4))
403 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
404 "ARP req out of range Low")
405
406 #
407 # Request for an address in the proxy range but from an interface
408 # in a different VRF
409 #
410 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
411 "ARP req from different VRF")
412
413 #
414 # Disable Each interface for proxy ARP
415 # - expect none to respond
416 #
417 for i in self.pg_interfaces:
418 i.set_proxy_arp(0)
419
420 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
421 "ARP req from disable")
422 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
423 "ARP req from disable")
424 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
425 "ARP req from disable")