blob: 68dde2fb840ddedf696bd5b8d4dff0ad2f08aa49 [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
Neale Ranns15002542017-09-10 04:39:11 -07008from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
9 VppIpTable
Neale Ranns39f9d8b2017-02-16 21:57:05 -080010
11from scapy.packet import Raw
Neale Ranns30d0fd42017-05-30 07:30:04 -070012from scapy.layers.l2 import Ether, ARP, Dot1Q
Neale Ranns39f9d8b2017-02-16 21:57:05 -080013from scapy.layers.inet import IP, UDP
Neale Ranns37be7362017-02-21 17:30:26 -080014from scapy.contrib.mpls import MPLS
Neale Ranns39f9d8b2017-02-16 21:57:05 -080015
16# not exported by scapy, so redefined here
17arp_opts = {"who-has": 1, "is-at": 2}
18
19
20class ARPTestCase(VppTestCase):
21 """ ARP Test Case """
22
23 def setUp(self):
24 super(ARPTestCase, self).setUp()
25
26 # create 3 pg interfaces
27 self.create_pg_interfaces(range(4))
28
29 # pg0 configured with ip4 and 6 addresses used for input
30 # pg1 configured with ip4 and 6 addresses used for output
31 # pg2 is unnumbered to pg0
32 for i in self.pg_interfaces:
33 i.admin_up()
34
35 self.pg0.config_ip4()
36 self.pg0.config_ip6()
37 self.pg0.resolve_arp()
38
39 self.pg1.config_ip4()
40 self.pg1.config_ip6()
41
42 # pg3 in a different VRF
Neale Ranns15002542017-09-10 04:39:11 -070043 self.tbl = VppIpTable(self, 1)
44 self.tbl.add_vpp_config()
45
Neale Ranns39f9d8b2017-02-16 21:57:05 -080046 self.pg3.set_table_ip4(1)
47 self.pg3.config_ip4()
48
Neale Ranns4008ac92017-02-13 23:20:04 -080049 def tearDown(self):
Neale Ranns4b919a52017-03-11 05:55:21 -080050 self.pg0.unconfig_ip4()
51 self.pg0.unconfig_ip6()
52
53 self.pg1.unconfig_ip4()
54 self.pg1.unconfig_ip6()
55
56 self.pg3.unconfig_ip4()
Neale Ranns15002542017-09-10 04:39:11 -070057 self.pg3.set_table_ip4(0)
Neale Ranns4b919a52017-03-11 05:55:21 -080058
Neale Ranns4008ac92017-02-13 23:20:04 -080059 for i in self.pg_interfaces:
Neale Ranns4008ac92017-02-13 23:20:04 -080060 i.admin_down()
61
Neale Ranns15002542017-09-10 04:39:11 -070062 super(ARPTestCase, self).tearDown()
63
Neale Ranns39f9d8b2017-02-16 21:57:05 -080064 def verify_arp_req(self, rx, smac, sip, dip):
65 ether = rx[Ether]
66 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
67 self.assertEqual(ether.src, smac)
68
69 arp = rx[ARP]
70 self.assertEqual(arp.hwtype, 1)
71 self.assertEqual(arp.ptype, 0x800)
72 self.assertEqual(arp.hwlen, 6)
73 self.assertEqual(arp.plen, 4)
74 self.assertEqual(arp.op, arp_opts["who-has"])
75 self.assertEqual(arp.hwsrc, smac)
76 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
77 self.assertEqual(arp.psrc, sip)
78 self.assertEqual(arp.pdst, dip)
79
80 def verify_arp_resp(self, rx, smac, dmac, sip, dip):
81 ether = rx[Ether]
82 self.assertEqual(ether.dst, dmac)
83 self.assertEqual(ether.src, smac)
84
85 arp = rx[ARP]
86 self.assertEqual(arp.hwtype, 1)
87 self.assertEqual(arp.ptype, 0x800)
88 self.assertEqual(arp.hwlen, 6)
89 self.assertEqual(arp.plen, 4)
90 self.assertEqual(arp.op, arp_opts["is-at"])
91 self.assertEqual(arp.hwsrc, smac)
92 self.assertEqual(arp.hwdst, dmac)
93 self.assertEqual(arp.psrc, sip)
94 self.assertEqual(arp.pdst, dip)
95
Matthew Smithcb9ab472017-05-16 21:35:56 -050096 def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
97 ether = rx[Ether]
98 self.assertEqual(ether.dst, dmac)
99 self.assertEqual(ether.src, smac)
100
101 arp = rx[ARP]
102 self.assertEqual(arp.hwtype, 1)
103 self.assertEqual(arp.ptype, 0x800)
104 self.assertEqual(arp.hwlen, 6)
105 self.assertEqual(arp.plen, 4)
106 self.assertEqual(arp.op, arp_opts["is-at"])
107 self.assertNotEqual(arp.hwsrc, smac)
108 self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
109 "00:00:5E:00:01" in arp.hwsrc)
110 self.assertEqual(arp.hwdst, dmac)
111 self.assertEqual(arp.psrc, sip)
112 self.assertEqual(arp.pdst, dip)
113
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800114 def verify_ip(self, rx, smac, dmac, sip, dip):
115 ether = rx[Ether]
116 self.assertEqual(ether.dst, dmac)
117 self.assertEqual(ether.src, smac)
118
119 ip = rx[IP]
120 self.assertEqual(ip.src, sip)
121 self.assertEqual(ip.dst, dip)
122
Neale Ranns37be7362017-02-21 17:30:26 -0800123 def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
124 ether = rx[Ether]
125 self.assertEqual(ether.dst, dmac)
126 self.assertEqual(ether.src, smac)
127
128 mpls = rx[MPLS]
129 self.assertTrue(mpls.label, label)
130
131 ip = rx[IP]
132 self.assertEqual(ip.src, sip)
133 self.assertEqual(ip.dst, dip)
134
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800135 def send_and_assert_no_replies(self, intf, pkts, remark):
136 intf.add_stream(pkts)
137 self.pg_enable_capture(self.pg_interfaces)
138 self.pg_start()
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700139 timeout = 1
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800140 for i in self.pg_interfaces:
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700141 i.get_capture(0, timeout=timeout)
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800142 i.assert_nothing_captured(remark=remark)
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700143 timeout = 0.1
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800144
145 def test_arp(self):
146 """ ARP """
147
148 #
149 # Generate some hosts on the LAN
150 #
Neale Rannsca193612017-06-14 06:50:08 -0700151 self.pg1.generate_remote_hosts(11)
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800152
153 #
154 # Send IP traffic to one of these unresolved hosts.
155 # expect the generation of an ARP request
156 #
157 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
158 IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
159 UDP(sport=1234, dport=1234) /
160 Raw())
161
162 self.pg0.add_stream(p)
163 self.pg_enable_capture(self.pg_interfaces)
164 self.pg_start()
165
166 rx = self.pg1.get_capture(1)
167
168 self.verify_arp_req(rx[0],
169 self.pg1.local_mac,
170 self.pg1.local_ip4,
171 self.pg1._remote_hosts[1].ip4)
172
173 #
174 # And a dynamic ARP entry for host 1
175 #
176 dyn_arp = VppNeighbor(self,
177 self.pg1.sw_if_index,
178 self.pg1.remote_hosts[1].mac,
179 self.pg1.remote_hosts[1].ip4)
180 dyn_arp.add_vpp_config()
181
182 #
183 # now we expect IP traffic forwarded
184 #
185 dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
186 IP(src=self.pg0.remote_ip4,
187 dst=self.pg1._remote_hosts[1].ip4) /
188 UDP(sport=1234, dport=1234) /
189 Raw())
190
191 self.pg0.add_stream(dyn_p)
192 self.pg_enable_capture(self.pg_interfaces)
193 self.pg_start()
194
195 rx = self.pg1.get_capture(1)
196
197 self.verify_ip(rx[0],
198 self.pg1.local_mac,
199 self.pg1.remote_hosts[1].mac,
200 self.pg0.remote_ip4,
201 self.pg1._remote_hosts[1].ip4)
202
203 #
204 # And a Static ARP entry for host 2
205 #
206 static_arp = VppNeighbor(self,
207 self.pg1.sw_if_index,
208 self.pg1.remote_hosts[2].mac,
209 self.pg1.remote_hosts[2].ip4,
210 is_static=1)
211 static_arp.add_vpp_config()
212
213 static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
214 IP(src=self.pg0.remote_ip4,
215 dst=self.pg1._remote_hosts[2].ip4) /
216 UDP(sport=1234, dport=1234) /
217 Raw())
218
219 self.pg0.add_stream(static_p)
220 self.pg_enable_capture(self.pg_interfaces)
221 self.pg_start()
222
223 rx = self.pg1.get_capture(1)
224
225 self.verify_ip(rx[0],
226 self.pg1.local_mac,
227 self.pg1.remote_hosts[2].mac,
228 self.pg0.remote_ip4,
229 self.pg1._remote_hosts[2].ip4)
230
231 #
232 # flap the link. dynamic ARPs get flush, statics don't
233 #
234 self.pg1.admin_down()
235 self.pg1.admin_up()
236
237 self.pg0.add_stream(static_p)
238 self.pg_enable_capture(self.pg_interfaces)
239 self.pg_start()
240 rx = self.pg1.get_capture(1)
241
242 self.verify_ip(rx[0],
243 self.pg1.local_mac,
244 self.pg1.remote_hosts[2].mac,
245 self.pg0.remote_ip4,
246 self.pg1._remote_hosts[2].ip4)
247
248 self.pg0.add_stream(dyn_p)
249 self.pg_enable_capture(self.pg_interfaces)
250 self.pg_start()
251
252 rx = self.pg1.get_capture(1)
253 self.verify_arp_req(rx[0],
254 self.pg1.local_mac,
255 self.pg1.local_ip4,
256 self.pg1._remote_hosts[1].ip4)
257
258 #
259 # Send an ARP request from one of the so-far unlearned remote hosts
260 #
261 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
262 src=self.pg1._remote_hosts[3].mac) /
263 ARP(op="who-has",
264 hwsrc=self.pg1._remote_hosts[3].mac,
265 pdst=self.pg1.local_ip4,
266 psrc=self.pg1._remote_hosts[3].ip4))
267
268 self.pg1.add_stream(p)
269 self.pg_enable_capture(self.pg_interfaces)
270 self.pg_start()
271
272 rx = self.pg1.get_capture(1)
273 self.verify_arp_resp(rx[0],
274 self.pg1.local_mac,
275 self.pg1._remote_hosts[3].mac,
276 self.pg1.local_ip4,
277 self.pg1._remote_hosts[3].ip4)
278
279 #
280 # VPP should have learned the mapping for the remote host
281 #
282 self.assertTrue(find_nbr(self,
283 self.pg1.sw_if_index,
284 self.pg1._remote_hosts[3].ip4))
Neale Ranns4b919a52017-03-11 05:55:21 -0800285 #
286 # Fire in an ARP request before the interface becomes IP enabled
287 #
288 self.pg2.generate_remote_hosts(4)
289
290 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
291 ARP(op="who-has",
292 hwsrc=self.pg2.remote_mac,
293 pdst=self.pg1.local_ip4,
294 psrc=self.pg2.remote_hosts[3].ip4))
Neale Ranns30d0fd42017-05-30 07:30:04 -0700295 pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
296 Dot1Q(vlan=0) /
297 ARP(op="who-has",
298 hwsrc=self.pg2.remote_mac,
299 pdst=self.pg1.local_ip4,
300 psrc=self.pg2.remote_hosts[3].ip4))
Neale Ranns4b919a52017-03-11 05:55:21 -0800301 self.send_and_assert_no_replies(self.pg2, p,
302 "interface not IP enabled")
303
304 #
305 # Make pg2 un-numbered to pg1
306 #
307 self.pg2.set_unnumbered(self.pg1.sw_if_index)
308
309 #
310 # We should respond to ARP requests for the unnumbered to address
311 # once an attached route to the source is known
312 #
313 self.send_and_assert_no_replies(
314 self.pg2, p,
315 "ARP req for unnumbered address - no source")
316
317 attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
318 [VppRoutePath("0.0.0.0",
319 self.pg2.sw_if_index)])
320 attached_host.add_vpp_config()
321
322 self.pg2.add_stream(p)
323 self.pg_enable_capture(self.pg_interfaces)
324 self.pg_start()
325
326 rx = self.pg2.get_capture(1)
327 self.verify_arp_resp(rx[0],
328 self.pg2.local_mac,
329 self.pg2.remote_mac,
330 self.pg1.local_ip4,
331 self.pg2.remote_hosts[3].ip4)
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800332
Neale Ranns30d0fd42017-05-30 07:30:04 -0700333 self.pg2.add_stream(pt)
334 self.pg_enable_capture(self.pg_interfaces)
335 self.pg_start()
336
337 rx = self.pg2.get_capture(1)
338 self.verify_arp_resp(rx[0],
339 self.pg2.local_mac,
340 self.pg2.remote_mac,
341 self.pg1.local_ip4,
342 self.pg2.remote_hosts[3].ip4)
343
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800344 #
Neale Ranns3983ac22017-03-10 11:53:27 -0800345 # A neighbor entry that has no associated FIB-entry
346 #
347 arp_no_fib = VppNeighbor(self,
348 self.pg1.sw_if_index,
349 self.pg1.remote_hosts[4].mac,
350 self.pg1.remote_hosts[4].ip4,
351 is_no_fib_entry=1)
352 arp_no_fib.add_vpp_config()
353
354 #
355 # check we have the neighbor, but no route
356 #
357 self.assertTrue(find_nbr(self,
358 self.pg1.sw_if_index,
359 self.pg1._remote_hosts[4].ip4))
360 self.assertFalse(find_route(self,
361 self.pg1._remote_hosts[4].ip4,
362 32))
363 #
Neale Ranns4b919a52017-03-11 05:55:21 -0800364 # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
365 # from within pg1's subnet
Neale Ranns3983ac22017-03-10 11:53:27 -0800366 #
367 arp_unnum = VppNeighbor(self,
368 self.pg2.sw_if_index,
369 self.pg1.remote_hosts[5].mac,
370 self.pg1.remote_hosts[5].ip4)
371 arp_unnum.add_vpp_config()
372
373 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
374 IP(src=self.pg0.remote_ip4,
375 dst=self.pg1._remote_hosts[5].ip4) /
376 UDP(sport=1234, dport=1234) /
377 Raw())
378
379 self.pg0.add_stream(p)
380 self.pg_enable_capture(self.pg_interfaces)
381 self.pg_start()
382
383 rx = self.pg2.get_capture(1)
384
385 self.verify_ip(rx[0],
386 self.pg2.local_mac,
387 self.pg1.remote_hosts[5].mac,
388 self.pg0.remote_ip4,
389 self.pg1._remote_hosts[5].ip4)
390
391 #
Neale Ranns4b919a52017-03-11 05:55:21 -0800392 # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
393 # with the unnumbered interface's address as the source
394 #
395 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
396 ARP(op="who-has",
397 hwsrc=self.pg2.remote_mac,
398 pdst=self.pg1.local_ip4,
399 psrc=self.pg1.remote_hosts[6].ip4))
400
401 self.pg2.add_stream(p)
402 self.pg_enable_capture(self.pg_interfaces)
403 self.pg_start()
404
405 rx = self.pg2.get_capture(1)
406 self.verify_arp_resp(rx[0],
407 self.pg2.local_mac,
408 self.pg2.remote_mac,
409 self.pg1.local_ip4,
410 self.pg1.remote_hosts[6].ip4)
411
412 #
413 # An attached host route out of pg2 for an undiscovered hosts generates
414 # an ARP request with the unnumbered address as the source
415 #
416 att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
417 [VppRoutePath("0.0.0.0",
418 self.pg2.sw_if_index)])
419 att_unnum.add_vpp_config()
420
421 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
422 IP(src=self.pg0.remote_ip4,
423 dst=self.pg1._remote_hosts[7].ip4) /
424 UDP(sport=1234, dport=1234) /
425 Raw())
426
427 self.pg0.add_stream(p)
428 self.pg_enable_capture(self.pg_interfaces)
429 self.pg_start()
430
431 rx = self.pg2.get_capture(1)
432
433 self.verify_arp_req(rx[0],
434 self.pg2.local_mac,
435 self.pg1.local_ip4,
436 self.pg1._remote_hosts[7].ip4)
437
438 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
439 ARP(op="who-has",
440 hwsrc=self.pg2.remote_mac,
441 pdst=self.pg1.local_ip4,
442 psrc=self.pg1.remote_hosts[7].ip4))
443
444 self.pg2.add_stream(p)
445 self.pg_enable_capture(self.pg_interfaces)
446 self.pg_start()
447
448 rx = self.pg2.get_capture(1)
449 self.verify_arp_resp(rx[0],
450 self.pg2.local_mac,
451 self.pg2.remote_mac,
452 self.pg1.local_ip4,
453 self.pg1.remote_hosts[7].ip4)
454
455 #
456 # An attached host route as yet unresolved out of pg2 for an
457 # undiscovered host, an ARP requests begets a response.
458 #
459 att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
460 [VppRoutePath("0.0.0.0",
461 self.pg2.sw_if_index)])
462 att_unnum1.add_vpp_config()
463
464 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
465 ARP(op="who-has",
466 hwsrc=self.pg2.remote_mac,
467 pdst=self.pg1.local_ip4,
468 psrc=self.pg1.remote_hosts[8].ip4))
469
470 self.pg2.add_stream(p)
471 self.pg_enable_capture(self.pg_interfaces)
472 self.pg_start()
473
474 rx = self.pg2.get_capture(1)
475 self.verify_arp_resp(rx[0],
476 self.pg2.local_mac,
477 self.pg2.remote_mac,
478 self.pg1.local_ip4,
479 self.pg1.remote_hosts[8].ip4)
480
481 #
Neale Ranns30d0fd42017-05-30 07:30:04 -0700482 # Send an ARP request from one of the so-far unlearned remote hosts
483 # with a VLAN0 tag
484 #
485 p = (Ether(dst="ff:ff:ff:ff:ff:ff",
486 src=self.pg1._remote_hosts[9].mac) /
487 Dot1Q(vlan=0) /
488 ARP(op="who-has",
489 hwsrc=self.pg1._remote_hosts[9].mac,
490 pdst=self.pg1.local_ip4,
491 psrc=self.pg1._remote_hosts[9].ip4))
492
493 self.pg1.add_stream(p)
494 self.pg_enable_capture(self.pg_interfaces)
495 self.pg_start()
496
497 rx = self.pg1.get_capture(1)
498 self.verify_arp_resp(rx[0],
499 self.pg1.local_mac,
500 self.pg1._remote_hosts[9].mac,
501 self.pg1.local_ip4,
502 self.pg1._remote_hosts[9].ip4)
503
504 #
Neale Rannsca193612017-06-14 06:50:08 -0700505 # Add a hierachy of routes for a host in the sub-net.
506 # Should still get an ARP resp since the cover is attached
507 #
508 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
509 ARP(op="who-has",
510 hwsrc=self.pg1.remote_mac,
511 pdst=self.pg1.local_ip4,
512 psrc=self.pg1.remote_hosts[10].ip4))
513
514 r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
515 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
516 self.pg1.sw_if_index)])
517 r1.add_vpp_config()
518
519 self.pg1.add_stream(p)
520 self.pg_enable_capture(self.pg_interfaces)
521 self.pg_start()
522 rx = self.pg1.get_capture(1)
523 self.verify_arp_resp(rx[0],
524 self.pg1.local_mac,
525 self.pg1.remote_mac,
526 self.pg1.local_ip4,
527 self.pg1.remote_hosts[10].ip4)
528
529 r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
530 [VppRoutePath(self.pg1.remote_hosts[10].ip4,
531 self.pg1.sw_if_index)])
532 r2.add_vpp_config()
533
534 self.pg1.add_stream(p)
535 self.pg_enable_capture(self.pg_interfaces)
536 self.pg_start()
537 rx = self.pg1.get_capture(1)
538 self.verify_arp_resp(rx[0],
539 self.pg1.local_mac,
540 self.pg1.remote_mac,
541 self.pg1.local_ip4,
542 self.pg1.remote_hosts[10].ip4)
543
544 #
545 # add an ARP entry that's not on the sub-net and so whose
546 # adj-fib fails the refinement check. then send an ARP request
547 # from that source
548 #
549 a1 = VppNeighbor(self,
550 self.pg0.sw_if_index,
551 self.pg0.remote_mac,
552 "100.100.100.50")
553 a1.add_vpp_config()
554
555 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
556 ARP(op="who-has",
557 hwsrc=self.pg0.remote_mac,
558 psrc="100.100.100.50",
559 pdst=self.pg0.remote_ip4))
560 self.send_and_assert_no_replies(self.pg0, p,
561 "ARP req for from failed adj-fib")
562
563 #
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800564 # ERROR Cases
565 # 1 - don't respond to ARP request for address not within the
566 # interface's sub-net
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700567 # 1b - nor within the unnumbered subnet
568 # 1c - nor within the subnet of a different interface
569 #
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800570 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
571 ARP(op="who-has",
572 hwsrc=self.pg0.remote_mac,
573 pdst="10.10.10.3",
574 psrc=self.pg0.remote_ip4))
575 self.send_and_assert_no_replies(self.pg0, p,
576 "ARP req for non-local destination")
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700577 self.assertFalse(find_nbr(self,
578 self.pg0.sw_if_index,
579 "10.10.10.3"))
580
Neale Ranns4b919a52017-03-11 05:55:21 -0800581 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
582 ARP(op="who-has",
583 hwsrc=self.pg2.remote_mac,
584 pdst="10.10.10.3",
585 psrc=self.pg1.remote_hosts[7].ip4))
586 self.send_and_assert_no_replies(
587 self.pg0, p,
588 "ARP req for non-local destination - unnum")
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800589
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700590 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
591 ARP(op="who-has",
592 hwsrc=self.pg0.remote_mac,
593 pdst=self.pg1.local_ip4,
594 psrc=self.pg1.remote_ip4))
595 self.send_and_assert_no_replies(self.pg0, p,
596 "ARP req diff sub-net")
597 self.assertFalse(find_nbr(self,
598 self.pg0.sw_if_index,
599 self.pg1.remote_ip4))
600
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800601 #
602 # 2 - don't respond to ARP request from an address not within the
603 # interface's sub-net
Neale Rannsca193612017-06-14 06:50:08 -0700604 # 2b - to a prxied address
605 # 2c - not within a differents interface's sub-net
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800606 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
607 ARP(op="who-has",
608 hwsrc=self.pg0.remote_mac,
609 psrc="10.10.10.3",
610 pdst=self.pg0.local_ip4))
611 self.send_and_assert_no_replies(self.pg0, p,
612 "ARP req for non-local source")
Neale Ranns4b919a52017-03-11 05:55:21 -0800613 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
614 ARP(op="who-has",
615 hwsrc=self.pg2.remote_mac,
616 psrc="10.10.10.3",
617 pdst=self.pg0.local_ip4))
618 self.send_and_assert_no_replies(
619 self.pg0, p,
620 "ARP req for non-local source - unnum")
Neale Rannsca193612017-06-14 06:50:08 -0700621 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
622 ARP(op="who-has",
623 hwsrc=self.pg0.remote_mac,
624 psrc=self.pg1.remote_ip4,
625 pdst=self.pg0.local_ip4))
626 self.send_and_assert_no_replies(self.pg0, p,
627 "ARP req for non-local source 2c")
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800628
629 #
630 # 3 - don't respond to ARP request from an address that belongs to
631 # the router
632 #
633 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
634 ARP(op="who-has",
635 hwsrc=self.pg0.remote_mac,
636 psrc=self.pg0.local_ip4,
637 pdst=self.pg0.local_ip4))
638 self.send_and_assert_no_replies(self.pg0, p,
639 "ARP req for non-local source")
640
641 #
642 # 4 - don't respond to ARP requests that has mac source different
643 # from ARP request HW source
644 # the router
645 #
646 p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
647 ARP(op="who-has",
648 hwsrc="00:00:00:DE:AD:BE",
649 psrc=self.pg0.remote_ip4,
650 pdst=self.pg0.local_ip4))
651 self.send_and_assert_no_replies(self.pg0, p,
652 "ARP req for non-local source")
653
654 #
655 # cleanup
656 #
657 dyn_arp.remove_vpp_config()
658 static_arp.remove_vpp_config()
Neale Ranns3983ac22017-03-10 11:53:27 -0800659 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800660
Neale Ranns4b919a52017-03-11 05:55:21 -0800661 # need this to flush the adj-fibs
662 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
663 self.pg2.admin_down()
Neale Rannsca193612017-06-14 06:50:08 -0700664 self.pg1.admin_down()
Neale Ranns4b919a52017-03-11 05:55:21 -0800665
Neale Ranns24b170a2017-08-15 05:33:11 -0700666 def test_proxy_mirror_arp(self):
667 """ Interface Mirror Proxy ARP """
668
669 #
670 # When VPP has an interface whose address is also applied to a TAP
671 # interface on the host, then VPP's TAP interface will be unnumbered
672 # to the 'real' interface and do proxy ARP from the host.
673 # the curious aspect of this setup is that ARP requests from the host
674 # will come from the VPP's own address.
675 #
676 self.pg0.generate_remote_hosts(2)
677
678 arp_req_from_me = (Ether(src=self.pg2.remote_mac,
679 dst="ff:ff:ff:ff:ff:ff") /
680 ARP(op="who-has",
681 hwsrc=self.pg2.remote_mac,
682 pdst=self.pg0.remote_hosts[1].ip4,
683 psrc=self.pg0.local_ip4))
684
685 #
686 # Configure Proxy ARP for the subnet on PG0addresses on pg0
687 #
688 self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
689 self.pg0._local_ip4n_bcast)
690
691 # Make pg2 un-numbered to pg0
692 #
693 self.pg2.set_unnumbered(self.pg0.sw_if_index)
694
695 #
696 # Enable pg2 for proxy ARP
697 #
698 self.pg2.set_proxy_arp()
699
700 #
701 # Send the ARP request with an originating address that
702 # is VPP's own address
703 #
704 self.pg2.add_stream(arp_req_from_me)
705 self.pg_enable_capture(self.pg_interfaces)
706 self.pg_start()
707
708 rx = self.pg2.get_capture(1)
709 self.verify_arp_resp(rx[0],
710 self.pg2.local_mac,
711 self.pg2.remote_mac,
712 self.pg0.remote_hosts[1].ip4,
713 self.pg0.local_ip4)
714
715 #
716 # validate we have not learned an ARP entry as a result of this
717 #
718 self.assertFalse(find_nbr(self,
719 self.pg2.sw_if_index,
720 self.pg0.local_ip4))
721
722 #
723 # cleanup
724 #
725 self.pg2.set_proxy_arp(0)
726 self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet,
727 self.pg0._local_ip4n_bcast,
728 is_add=0)
729
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800730 def test_proxy_arp(self):
731 """ Proxy ARP """
732
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700733 self.pg1.generate_remote_hosts(2)
734
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800735 #
736 # Proxy ARP rewquest packets for each interface
737 #
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800738 arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
739 dst="ff:ff:ff:ff:ff:ff") /
740 ARP(op="who-has",
741 hwsrc=self.pg0.remote_mac,
742 pdst="10.10.10.3",
743 psrc=self.pg0.remote_ip4))
Neale Ranns30d0fd42017-05-30 07:30:04 -0700744 arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
745 dst="ff:ff:ff:ff:ff:ff") /
746 Dot1Q(vlan=0) /
747 ARP(op="who-has",
748 hwsrc=self.pg0.remote_mac,
749 pdst="10.10.10.3",
750 psrc=self.pg0.remote_ip4))
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800751 arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
752 dst="ff:ff:ff:ff:ff:ff") /
753 ARP(op="who-has",
754 hwsrc=self.pg1.remote_mac,
755 pdst="10.10.10.3",
756 psrc=self.pg1.remote_ip4))
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700757 arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
758 dst="ff:ff:ff:ff:ff:ff") /
759 ARP(op="who-has",
760 hwsrc=self.pg2.remote_mac,
761 pdst="10.10.10.3",
762 psrc=self.pg1.remote_hosts[1].ip4))
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800763 arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
764 dst="ff:ff:ff:ff:ff:ff") /
765 ARP(op="who-has",
766 hwsrc=self.pg3.remote_mac,
767 pdst="10.10.10.3",
768 psrc=self.pg3.remote_ip4))
769
770 #
771 # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
772 #
773 self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
774 inet_pton(AF_INET, "10.10.10.124"))
775
776 #
777 # No responses are sent when the interfaces are not enabled for proxy
778 # ARP
779 #
780 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
781 "ARP req from unconfigured interface")
782 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
783 "ARP req from unconfigured interface")
784
785 #
786 # Make pg2 un-numbered to pg1
787 # still won't reply.
788 #
789 self.pg2.set_unnumbered(self.pg1.sw_if_index)
790
791 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
792 "ARP req from unnumbered interface")
793
794 #
795 # Enable each interface to reply to proxy ARPs
796 #
797 for i in self.pg_interfaces:
798 i.set_proxy_arp()
799
800 #
801 # Now each of the interfaces should reply to a request to a proxied
802 # address
803 #
804 self.pg0.add_stream(arp_req_pg0)
805 self.pg_enable_capture(self.pg_interfaces)
806 self.pg_start()
807
808 rx = self.pg0.get_capture(1)
809 self.verify_arp_resp(rx[0],
810 self.pg0.local_mac,
811 self.pg0.remote_mac,
812 "10.10.10.3",
813 self.pg0.remote_ip4)
814
Neale Ranns30d0fd42017-05-30 07:30:04 -0700815 self.pg0.add_stream(arp_req_pg0_tagged)
816 self.pg_enable_capture(self.pg_interfaces)
817 self.pg_start()
818
819 rx = self.pg0.get_capture(1)
820 self.verify_arp_resp(rx[0],
821 self.pg0.local_mac,
822 self.pg0.remote_mac,
823 "10.10.10.3",
824 self.pg0.remote_ip4)
825
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800826 self.pg1.add_stream(arp_req_pg1)
827 self.pg_enable_capture(self.pg_interfaces)
828 self.pg_start()
829
830 rx = self.pg1.get_capture(1)
831 self.verify_arp_resp(rx[0],
832 self.pg1.local_mac,
833 self.pg1.remote_mac,
834 "10.10.10.3",
835 self.pg1.remote_ip4)
836
837 self.pg2.add_stream(arp_req_pg2)
838 self.pg_enable_capture(self.pg_interfaces)
839 self.pg_start()
840
841 rx = self.pg2.get_capture(1)
842 self.verify_arp_resp(rx[0],
843 self.pg2.local_mac,
844 self.pg2.remote_mac,
845 "10.10.10.3",
Neale Rannsd5b6aa12017-05-16 08:46:45 -0700846 self.pg1.remote_hosts[1].ip4)
Neale Ranns39f9d8b2017-02-16 21:57:05 -0800847
848 #
849 # A request for an address out of the configured range
850 #
851 arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
852 dst="ff:ff:ff:ff:ff:ff") /
853 ARP(op="who-has",
854 hwsrc=self.pg1.remote_mac,
855 pdst="10.10.10.125",
856 psrc=self.pg1.remote_ip4))
857 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
858 "ARP req out of range HI")
859 arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
860 dst="ff:ff:ff:ff:ff:ff") /
861 ARP(op="who-has",
862 hwsrc=self.pg1.remote_mac,
863 pdst="10.10.10.1",
864 psrc=self.pg1.remote_ip4))
865 self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
866 "ARP req out of range Low")
867
868 #
869 # Request for an address in the proxy range but from an interface
870 # in a different VRF
871 #
872 self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
873 "ARP req from different VRF")
874
875 #
876 # Disable Each interface for proxy ARP
877 # - expect none to respond
878 #
879 for i in self.pg_interfaces:
880 i.set_proxy_arp(0)
881
882 self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
883 "ARP req from disable")
884 self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
885 "ARP req from disable")
886 self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
887 "ARP req from disable")
Neale Ranns37be7362017-02-21 17:30:26 -0800888
889 #
890 # clean up on interface 2
891 #
Neale Ranns4b919a52017-03-11 05:55:21 -0800892 self.pg2.unset_unnumbered(self.pg1.sw_if_index)
Neale Ranns37be7362017-02-21 17:30:26 -0800893
894 def test_mpls(self):
895 """ MPLS """
896
897 #
898 # Interface 2 does not yet have ip4 config
899 #
900 self.pg2.config_ip4()
901 self.pg2.generate_remote_hosts(2)
902
903 #
904 # Add a reoute with out going label via an ARP unresolved next-hop
905 #
906 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
907 [VppRoutePath(self.pg2.remote_hosts[1].ip4,
908 self.pg2.sw_if_index,
909 labels=[55])])
910 ip_10_0_0_1.add_vpp_config()
911
912 #
913 # packets should generate an ARP request
914 #
915 p = (Ether(src=self.pg0.remote_mac,
916 dst=self.pg0.local_mac) /
917 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
918 UDP(sport=1234, dport=1234) /
919 Raw('\xa5' * 100))
920
921 self.pg0.add_stream(p)
922 self.pg_enable_capture(self.pg_interfaces)
923 self.pg_start()
924
925 rx = self.pg2.get_capture(1)
926 self.verify_arp_req(rx[0],
927 self.pg2.local_mac,
928 self.pg2.local_ip4,
929 self.pg2._remote_hosts[1].ip4)
930
931 #
932 # now resolve the neighbours
933 #
934 self.pg2.configure_ipv4_neighbors()
935
936 #
937 # Now packet should be properly MPLS encapped.
938 # This verifies that MPLS link-type adjacencies are completed
939 # when the ARP entry resolves
940 #
941 self.pg0.add_stream(p)
942 self.pg_enable_capture(self.pg_interfaces)
943 self.pg_start()
944
945 rx = self.pg2.get_capture(1)
946 self.verify_ip_o_mpls(rx[0],
947 self.pg2.local_mac,
948 self.pg2.remote_hosts[1].mac,
949 55,
950 self.pg0.remote_ip4,
951 "10.0.0.1")
Neale Ranns4b919a52017-03-11 05:55:21 -0800952 self.pg2.unconfig_ip4()
Neale Ranns37be7362017-02-21 17:30:26 -0800953
Matthew Smithcb9ab472017-05-16 21:35:56 -0500954 def test_arp_vrrp(self):
955 """ ARP reply with VRRP virtual src hw addr """
956
957 #
958 # IP packet destined for pg1 remote host arrives on pg0 resulting
959 # in an ARP request for the address of the remote host on pg1
960 #
961 p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
962 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
963 UDP(sport=1234, dport=1234) /
964 Raw())
965
966 self.pg0.add_stream(p0)
967 self.pg_enable_capture(self.pg_interfaces)
968 self.pg_start()
969
970 rx1 = self.pg1.get_capture(1)
971
972 self.verify_arp_req(rx1[0],
973 self.pg1.local_mac,
974 self.pg1.local_ip4,
975 self.pg1.remote_ip4)
976
977 #
978 # ARP reply for address of pg1 remote host arrives on pg1 with
979 # the hw src addr set to a value in the VRRP IPv4 range of
980 # MAC addresses
981 #
982 p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
983 ARP(op="is-at", hwdst=self.pg1.local_mac,
984 hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
985 psrc=self.pg1.remote_ip4))
986
987 self.pg1.add_stream(p1)
988 self.pg_enable_capture(self.pg_interfaces)
989 self.pg_start()
990
991 #
992 # IP packet destined for pg1 remote host arrives on pg0 again.
993 # VPP should have an ARP entry for that address now and the packet
994 # should be sent out pg1.
995 #
996 self.pg0.add_stream(p0)
997 self.pg_enable_capture(self.pg_interfaces)
998 self.pg_start()
999
1000 rx1 = self.pg1.get_capture(1)
1001
1002 self.verify_ip(rx1[0],
1003 self.pg1.local_mac,
1004 "00:00:5e:00:01:09",
1005 self.pg0.remote_ip4,
1006 self.pg1.remote_ip4)
1007
1008 self.pg1.admin_down()
1009 self.pg1.admin_up()
1010
Neale Rannsdcd6d622017-05-26 02:59:16 -07001011 def test_arp_duplicates(self):
1012 """ ARP Duplicates"""
1013
1014 #
1015 # Generate some hosts on the LAN
1016 #
1017 self.pg1.generate_remote_hosts(3)
1018
1019 #
1020 # Add host 1 on pg1 and pg2
1021 #
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()
1032
1033 #
1034 # IP packet destined for pg1 remote host arrives on pg1 again.
1035 #
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) /
1041 Raw())
1042
1043 self.pg0.add_stream(p)
1044 self.pg_enable_capture(self.pg_interfaces)
1045 self.pg_start()
1046
1047 rx1 = self.pg1.get_capture(1)
1048
1049 self.verify_ip(rx1[0],
1050 self.pg1.local_mac,
1051 self.pg1.remote_hosts[1].mac,
1052 self.pg0.remote_ip4,
1053 self.pg1.remote_hosts[1].ip4)
1054
1055 #
1056 # remove the duplicate on pg1
1057 # packet stream shoud generate ARPs out of pg1
1058 #
1059 arp_pg1.remove_vpp_config()
1060
1061 self.pg0.add_stream(p)
1062 self.pg_enable_capture(self.pg_interfaces)
1063 self.pg_start()
1064
1065 rx1 = self.pg1.get_capture(1)
1066
1067 self.verify_arp_req(rx1[0],
1068 self.pg1.local_mac,
1069 self.pg1.local_ip4,
1070 self.pg1.remote_hosts[1].ip4)
1071
1072 #
1073 # Add it back
1074 #
1075 arp_pg1.add_vpp_config()
1076
1077 self.pg0.add_stream(p)
1078 self.pg_enable_capture(self.pg_interfaces)
1079 self.pg_start()
1080
1081 rx1 = self.pg1.get_capture(1)
1082
1083 self.verify_ip(rx1[0],
1084 self.pg1.local_mac,
1085 self.pg1.remote_hosts[1].mac,
1086 self.pg0.remote_ip4,
1087 self.pg1.remote_hosts[1].ip4)
1088
Neale Ranns15002542017-09-10 04:39:11 -07001089 def test_arp_static(self):
1090 """ ARP Static"""
1091 self.pg2.generate_remote_hosts(3)
1092
1093 #
1094 # Add a static ARP entry
1095 #
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,
1100 is_static=1)
1101 static_arp.add_vpp_config()
1102
1103 #
1104 # Add the connected prefix to the interface
1105 #
1106 self.pg2.config_ip4()
1107
1108 #
1109 # We should now find the adj-fib
1110 #
1111 self.assertTrue(find_nbr(self,
1112 self.pg2.sw_if_index,
1113 self.pg2.remote_hosts[1].ip4,
1114 is_static=1))
1115 self.assertTrue(find_route(self,
1116 self.pg2.remote_hosts[1].ip4,
1117 32))
1118
1119 #
1120 # remove the connected
1121 #
1122 self.pg2.unconfig_ip4()
1123
1124 #
1125 # put the interface into table 1
1126 #
1127 self.pg2.set_table_ip4(1)
1128
1129 #
1130 # configure the same connected and expect to find the
1131 # adj fib in the new table
1132 #
1133 self.pg2.config_ip4()
1134 self.assertTrue(find_route(self,
1135 self.pg2.remote_hosts[1].ip4,
1136 32,
1137 table_id=1))
1138
1139 #
1140 # clean-up
1141 #
1142 self.pg2.unconfig_ip4()
1143 self.pg2.set_table_ip4(0)
1144
Neale Rannsdcd6d622017-05-26 02:59:16 -07001145
Neale Ranns37be7362017-02-21 17:30:26 -08001146if __name__ == '__main__':
1147 unittest.main(testRunner=VppTestRunner)