FIB table add/delete API
[vpp.git] / test / test_neighbor.py
1 #!/usr/bin/env python
2
3 import unittest
4 from socket import AF_INET, AF_INET6, inet_pton
5
6 from framework import VppTestCase, VppTestRunner
7 from vpp_neighbor import VppNeighbor, find_nbr
8 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
9     VppIpTable
10
11 from scapy.packet import Raw
12 from scapy.layers.l2 import Ether, ARP, Dot1Q
13 from scapy.layers.inet import IP, UDP
14 from scapy.contrib.mpls import MPLS
15
16 # not exported by scapy, so redefined here
17 arp_opts = {"who-has": 1, "is-at": 2}
18
19
20 class 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
43         self.tbl = VppIpTable(self, 1)
44         self.tbl.add_vpp_config()
45
46         self.pg3.set_table_ip4(1)
47         self.pg3.config_ip4()
48
49     def tearDown(self):
50         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()
57         self.pg3.set_table_ip4(0)
58
59         for i in self.pg_interfaces:
60             i.admin_down()
61
62         super(ARPTestCase, self).tearDown()
63
64     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
96     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
114     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
123     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
135     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()
139         timeout = 1
140         for i in self.pg_interfaces:
141             i.get_capture(0, timeout=timeout)
142             i.assert_nothing_captured(remark=remark)
143             timeout = 0.1
144
145     def test_arp(self):
146         """ ARP """
147
148         #
149         # Generate some hosts on the LAN
150         #
151         self.pg1.generate_remote_hosts(11)
152
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))
285         #
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))
295         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))
301         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)
332
333         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
344         #
345         # 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         #
364         # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
365         # from within pg1's subnet
366         #
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         #
392         # 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         #
482         # 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         #
505         # 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         #
564         # ERROR Cases
565         #  1 - don't respond to ARP request for address not within the
566         #      interface's sub-net
567         #  1b - nor within the unnumbered subnet
568         #  1c - nor within the subnet of a different interface
569         #
570         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")
577         self.assertFalse(find_nbr(self,
578                                   self.pg0.sw_if_index,
579                                   "10.10.10.3"))
580
581         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")
589
590         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
601         #
602         #  2 - don't respond to ARP request from an address not within the
603         #      interface's sub-net
604         #   2b - to a prxied address
605         #   2c - not within a differents interface's sub-net
606         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")
613         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")
621         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")
628
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()
659         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
660
661         # need this to flush the adj-fibs
662         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
663         self.pg2.admin_down()
664         self.pg1.admin_down()
665
666     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
730     def test_proxy_arp(self):
731         """ Proxy ARP """
732
733         self.pg1.generate_remote_hosts(2)
734
735         #
736         # Proxy ARP rewquest packets for each interface
737         #
738         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))
744         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))
751         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))
757         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))
763         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
815         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
826         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",
846                              self.pg1.remote_hosts[1].ip4)
847
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")
888
889         #
890         # clean up on interface 2
891         #
892         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
893
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")
952         self.pg2.unconfig_ip4()
953
954     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
1011     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
1089     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
1145
1146 if __name__ == '__main__':
1147     unittest.main(testRunner=VppTestRunner)