7c13f9ffb0a116d120227e7b0ef86b129afe06af
[vpp.git] / test / test_neighbor.py
1 #!/usr/bin/env python3
2
3 import unittest
4 import os
5 from socket import AF_INET, AF_INET6, inet_pton
6
7 from framework import VppTestCase, VppTestRunner
8 from vpp_neighbor import VppNeighbor, find_nbr
9 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
10     VppIpTable, DpoProto, FibPathType
11 from vpp_papi import VppEnum
12 from vpp_ip import VppIpPuntRedirect
13
14 import scapy.compat
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether, ARP, Dot1Q
17 from scapy.layers.inet import IP, UDP, TCP
18 from scapy.layers.inet6 import IPv6
19 from scapy.contrib.mpls import MPLS
20 from scapy.layers.inet6 import IPv6
21
22
23 NUM_PKTS = 67
24
25 # not exported by scapy, so redefined here
26 arp_opts = {"who-has": 1, "is-at": 2}
27
28
29 class ARPTestCase(VppTestCase):
30     """ ARP Test Case """
31
32     @classmethod
33     def setUpClass(cls):
34         super(ARPTestCase, cls).setUpClass()
35
36     @classmethod
37     def tearDownClass(cls):
38         super(ARPTestCase, cls).tearDownClass()
39
40     def setUp(self):
41         super(ARPTestCase, self).setUp()
42
43         # create 3 pg interfaces
44         self.create_pg_interfaces(range(4))
45
46         # pg0 configured with ip4 and 6 addresses used for input
47         # pg1 configured with ip4 and 6 addresses used for output
48         # pg2 is unnumbered to pg0
49         for i in self.pg_interfaces:
50             i.admin_up()
51
52         self.pg0.config_ip4()
53         self.pg0.config_ip6()
54         self.pg0.resolve_arp()
55
56         self.pg1.config_ip4()
57         self.pg1.config_ip6()
58
59         # pg3 in a different VRF
60         self.tbl = VppIpTable(self, 1)
61         self.tbl.add_vpp_config()
62
63         self.pg3.set_table_ip4(1)
64         self.pg3.config_ip4()
65
66     def tearDown(self):
67         self.pg0.unconfig_ip4()
68         self.pg0.unconfig_ip6()
69
70         self.pg1.unconfig_ip4()
71         self.pg1.unconfig_ip6()
72
73         self.pg3.unconfig_ip4()
74         self.pg3.set_table_ip4(0)
75
76         for i in self.pg_interfaces:
77             i.admin_down()
78
79         super(ARPTestCase, self).tearDown()
80
81     def verify_arp_req(self, rx, smac, sip, dip):
82         ether = rx[Ether]
83         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
84         self.assertEqual(ether.src, smac)
85
86         arp = rx[ARP]
87         self.assertEqual(arp.hwtype, 1)
88         self.assertEqual(arp.ptype, 0x800)
89         self.assertEqual(arp.hwlen, 6)
90         self.assertEqual(arp.plen, 4)
91         self.assertEqual(arp.op, arp_opts["who-has"])
92         self.assertEqual(arp.hwsrc, smac)
93         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
94         self.assertEqual(arp.psrc, sip)
95         self.assertEqual(arp.pdst, dip)
96
97     def verify_arp_resp(self, rx, smac, dmac, sip, dip):
98         ether = rx[Ether]
99         self.assertEqual(ether.dst, dmac)
100         self.assertEqual(ether.src, smac)
101
102         arp = rx[ARP]
103         self.assertEqual(arp.hwtype, 1)
104         self.assertEqual(arp.ptype, 0x800)
105         self.assertEqual(arp.hwlen, 6)
106         self.assertEqual(arp.plen, 4)
107         self.assertEqual(arp.op, arp_opts["is-at"])
108         self.assertEqual(arp.hwsrc, smac)
109         self.assertEqual(arp.hwdst, dmac)
110         self.assertEqual(arp.psrc, sip)
111         self.assertEqual(arp.pdst, dip)
112
113     def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
114         ether = rx[Ether]
115         self.assertEqual(ether.dst, dmac)
116         self.assertEqual(ether.src, smac)
117
118         arp = rx[ARP]
119         self.assertEqual(arp.hwtype, 1)
120         self.assertEqual(arp.ptype, 0x800)
121         self.assertEqual(arp.hwlen, 6)
122         self.assertEqual(arp.plen, 4)
123         self.assertEqual(arp.op, arp_opts["is-at"])
124         self.assertNotEqual(arp.hwsrc, smac)
125         self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
126                         "00:00:5E:00:01" in arp.hwsrc)
127         self.assertEqual(arp.hwdst, dmac)
128         self.assertEqual(arp.psrc, sip)
129         self.assertEqual(arp.pdst, dip)
130
131     def verify_ip(self, rx, smac, dmac, sip, dip):
132         ether = rx[Ether]
133         self.assertEqual(ether.dst, dmac)
134         self.assertEqual(ether.src, smac)
135
136         ip = rx[IP]
137         self.assertEqual(ip.src, sip)
138         self.assertEqual(ip.dst, dip)
139
140     def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
141         ether = rx[Ether]
142         self.assertEqual(ether.dst, dmac)
143         self.assertEqual(ether.src, smac)
144
145         mpls = rx[MPLS]
146         self.assertTrue(mpls.label, label)
147
148         ip = rx[IP]
149         self.assertEqual(ip.src, sip)
150         self.assertEqual(ip.dst, dip)
151
152     def test_arp(self):
153         """ ARP """
154
155         #
156         # Generate some hosts on the LAN
157         #
158         self.pg1.generate_remote_hosts(11)
159
160         #
161         # watch for:
162         #  - all neighbour events
163         #  - all neighbor events on pg1
164         #  - neighbor events for host[1] on pg1
165         #
166         self.vapi.want_ip_neighbor_events(enable=1,
167                                           pid=os.getpid())
168         self.vapi.want_ip_neighbor_events(enable=1,
169                                           pid=os.getpid(),
170                                           sw_if_index=self.pg1.sw_if_index)
171         self.vapi.want_ip_neighbor_events(enable=1,
172                                           pid=os.getpid(),
173                                           sw_if_index=self.pg1.sw_if_index,
174                                           ip=self.pg1.remote_hosts[1].ip4)
175
176         self.logger.info(self.vapi.cli("sh ip neighbor-watcher"))
177
178         #
179         # Send IP traffic to one of these unresolved hosts.
180         #  expect the generation of an ARP request
181         #
182         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
183              IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
184              UDP(sport=1234, dport=1234) /
185              Raw())
186
187         self.pg0.add_stream(p)
188         self.pg_enable_capture(self.pg_interfaces)
189         self.pg_start()
190
191         rx = self.pg1.get_capture(1)
192
193         self.verify_arp_req(rx[0],
194                             self.pg1.local_mac,
195                             self.pg1.local_ip4,
196                             self.pg1._remote_hosts[1].ip4)
197
198         #
199         # And a dynamic ARP entry for host 1
200         #
201         dyn_arp = VppNeighbor(self,
202                               self.pg1.sw_if_index,
203                               self.pg1.remote_hosts[1].mac,
204                               self.pg1.remote_hosts[1].ip4)
205         dyn_arp.add_vpp_config()
206         self.assertTrue(dyn_arp.query_vpp_config())
207
208         self.logger.info(self.vapi.cli("show ip neighbor-watcher"))
209
210         # this matches all of the listnerers
211         es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
212               for i in range(3)]
213         for e in es:
214             self.assertEqual(str(e.neighbor.ip_address),
215                              self.pg1.remote_hosts[1].ip4)
216
217         #
218         # now we expect IP traffic forwarded
219         #
220         dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
221                  IP(src=self.pg0.remote_ip4,
222                     dst=self.pg1._remote_hosts[1].ip4) /
223                  UDP(sport=1234, dport=1234) /
224                  Raw())
225
226         self.pg0.add_stream(dyn_p)
227         self.pg_enable_capture(self.pg_interfaces)
228         self.pg_start()
229
230         rx = self.pg1.get_capture(1)
231
232         self.verify_ip(rx[0],
233                        self.pg1.local_mac,
234                        self.pg1.remote_hosts[1].mac,
235                        self.pg0.remote_ip4,
236                        self.pg1._remote_hosts[1].ip4)
237
238         #
239         # And a Static ARP entry for host 2
240         #
241         static_arp = VppNeighbor(self,
242                                  self.pg1.sw_if_index,
243                                  self.pg1.remote_hosts[2].mac,
244                                  self.pg1.remote_hosts[2].ip4,
245                                  is_static=1)
246         static_arp.add_vpp_config()
247         es = [self.vapi.wait_for_event(1, "ip_neighbor_event")
248               for i in range(2)]
249         for e in es:
250             self.assertEqual(str(e.neighbor.ip_address),
251                              self.pg1.remote_hosts[2].ip4)
252
253         static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
254                     IP(src=self.pg0.remote_ip4,
255                        dst=self.pg1._remote_hosts[2].ip4) /
256                     UDP(sport=1234, dport=1234) /
257                     Raw())
258
259         self.pg0.add_stream(static_p)
260         self.pg_enable_capture(self.pg_interfaces)
261         self.pg_start()
262
263         rx = self.pg1.get_capture(1)
264
265         self.verify_ip(rx[0],
266                        self.pg1.local_mac,
267                        self.pg1.remote_hosts[2].mac,
268                        self.pg0.remote_ip4,
269                        self.pg1._remote_hosts[2].ip4)
270
271         #
272         # remove all the listeners
273         #
274         self.vapi.want_ip_neighbor_events(enable=0,
275                                           pid=os.getpid())
276         self.vapi.want_ip_neighbor_events(enable=0,
277                                           pid=os.getpid(),
278                                           sw_if_index=self.pg1.sw_if_index)
279         self.vapi.want_ip_neighbor_events(enable=0,
280                                           pid=os.getpid(),
281                                           sw_if_index=self.pg1.sw_if_index,
282                                           ip=self.pg1.remote_hosts[1].ip4)
283
284         #
285         # flap the link. dynamic ARPs get flush, statics don't
286         #
287         self.pg1.admin_down()
288         self.pg1.admin_up()
289
290         self.pg0.add_stream(static_p)
291         self.pg_enable_capture(self.pg_interfaces)
292         self.pg_start()
293         rx = self.pg1.get_capture(1)
294
295         self.verify_ip(rx[0],
296                        self.pg1.local_mac,
297                        self.pg1.remote_hosts[2].mac,
298                        self.pg0.remote_ip4,
299                        self.pg1._remote_hosts[2].ip4)
300
301         self.pg0.add_stream(dyn_p)
302         self.pg_enable_capture(self.pg_interfaces)
303         self.pg_start()
304
305         rx = self.pg1.get_capture(1)
306         self.verify_arp_req(rx[0],
307                             self.pg1.local_mac,
308                             self.pg1.local_ip4,
309                             self.pg1._remote_hosts[1].ip4)
310
311         self.assertFalse(dyn_arp.query_vpp_config())
312         self.assertTrue(static_arp.query_vpp_config())
313         #
314         # Send an ARP request from one of the so-far unlearned remote hosts
315         #
316         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
317                    src=self.pg1._remote_hosts[3].mac) /
318              ARP(op="who-has",
319                  hwsrc=self.pg1._remote_hosts[3].mac,
320                  pdst=self.pg1.local_ip4,
321                  psrc=self.pg1._remote_hosts[3].ip4))
322
323         self.pg1.add_stream(p)
324         self.pg_enable_capture(self.pg_interfaces)
325         self.pg_start()
326
327         rx = self.pg1.get_capture(1)
328         self.verify_arp_resp(rx[0],
329                              self.pg1.local_mac,
330                              self.pg1._remote_hosts[3].mac,
331                              self.pg1.local_ip4,
332                              self.pg1._remote_hosts[3].ip4)
333
334         #
335         # VPP should have learned the mapping for the remote host
336         #
337         self.assertTrue(find_nbr(self,
338                                  self.pg1.sw_if_index,
339                                  self.pg1._remote_hosts[3].ip4))
340         #
341         # Fire in an ARP request before the interface becomes IP enabled
342         #
343         self.pg2.generate_remote_hosts(4)
344
345         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
346              ARP(op="who-has",
347                  hwsrc=self.pg2.remote_mac,
348                  pdst=self.pg1.local_ip4,
349                  psrc=self.pg2.remote_hosts[3].ip4))
350         pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
351               Dot1Q(vlan=0) /
352               ARP(op="who-has",
353                   hwsrc=self.pg2.remote_mac,
354                   pdst=self.pg1.local_ip4,
355                   psrc=self.pg2.remote_hosts[3].ip4))
356         self.send_and_assert_no_replies(self.pg2, p,
357                                         "interface not IP enabled")
358
359         #
360         # Make pg2 un-numbered to pg1
361         #
362         self.pg2.set_unnumbered(self.pg1.sw_if_index)
363
364         #
365         # test the unnumbered dump both by all interfaces and just the enabled
366         # one
367         #
368         unnum = self.vapi.ip_unnumbered_dump()
369         self.assertTrue(len(unnum))
370         self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
371         self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
372         unnum = self.vapi.ip_unnumbered_dump(self.pg2.sw_if_index)
373         self.assertTrue(len(unnum))
374         self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
375         self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
376
377         #
378         # We should respond to ARP requests for the unnumbered to address
379         # once an attached route to the source is known
380         #
381         self.send_and_assert_no_replies(
382             self.pg2, p,
383             "ARP req for unnumbered address - no source")
384
385         attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
386                                    [VppRoutePath("0.0.0.0",
387                                                  self.pg2.sw_if_index)])
388         attached_host.add_vpp_config()
389
390         self.pg2.add_stream(p)
391         self.pg_enable_capture(self.pg_interfaces)
392         self.pg_start()
393
394         rx = self.pg2.get_capture(1)
395         self.verify_arp_resp(rx[0],
396                              self.pg2.local_mac,
397                              self.pg2.remote_mac,
398                              self.pg1.local_ip4,
399                              self.pg2.remote_hosts[3].ip4)
400
401         self.pg2.add_stream(pt)
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.pg2.remote_hosts[3].ip4)
411
412         #
413         # A neighbor entry that has no associated FIB-entry
414         #
415         arp_no_fib = VppNeighbor(self,
416                                  self.pg1.sw_if_index,
417                                  self.pg1.remote_hosts[4].mac,
418                                  self.pg1.remote_hosts[4].ip4,
419                                  is_no_fib_entry=1)
420         arp_no_fib.add_vpp_config()
421
422         #
423         # check we have the neighbor, but no route
424         #
425         self.assertTrue(find_nbr(self,
426                                  self.pg1.sw_if_index,
427                                  self.pg1._remote_hosts[4].ip4))
428         self.assertFalse(find_route(self,
429                                     self.pg1._remote_hosts[4].ip4,
430                                     32))
431         #
432         # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
433         # from within pg1's subnet
434         #
435         arp_unnum = VppNeighbor(self,
436                                 self.pg2.sw_if_index,
437                                 self.pg1.remote_hosts[5].mac,
438                                 self.pg1.remote_hosts[5].ip4)
439         arp_unnum.add_vpp_config()
440
441         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
442              IP(src=self.pg0.remote_ip4,
443                 dst=self.pg1._remote_hosts[5].ip4) /
444              UDP(sport=1234, dport=1234) /
445              Raw())
446
447         self.pg0.add_stream(p)
448         self.pg_enable_capture(self.pg_interfaces)
449         self.pg_start()
450
451         rx = self.pg2.get_capture(1)
452
453         self.verify_ip(rx[0],
454                        self.pg2.local_mac,
455                        self.pg1.remote_hosts[5].mac,
456                        self.pg0.remote_ip4,
457                        self.pg1._remote_hosts[5].ip4)
458
459         #
460         # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
461         # with the unnumbered interface's address as the source
462         #
463         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
464              ARP(op="who-has",
465                  hwsrc=self.pg2.remote_mac,
466                  pdst=self.pg1.local_ip4,
467                  psrc=self.pg1.remote_hosts[6].ip4))
468
469         self.pg2.add_stream(p)
470         self.pg_enable_capture(self.pg_interfaces)
471         self.pg_start()
472
473         rx = self.pg2.get_capture(1)
474         self.verify_arp_resp(rx[0],
475                              self.pg2.local_mac,
476                              self.pg2.remote_mac,
477                              self.pg1.local_ip4,
478                              self.pg1.remote_hosts[6].ip4)
479
480         #
481         # An attached host route out of pg2 for an undiscovered hosts generates
482         # an ARP request with the unnumbered address as the source
483         #
484         att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
485                                [VppRoutePath("0.0.0.0",
486                                              self.pg2.sw_if_index)])
487         att_unnum.add_vpp_config()
488
489         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
490              IP(src=self.pg0.remote_ip4,
491                 dst=self.pg1._remote_hosts[7].ip4) /
492              UDP(sport=1234, dport=1234) /
493              Raw())
494
495         self.pg0.add_stream(p)
496         self.pg_enable_capture(self.pg_interfaces)
497         self.pg_start()
498
499         rx = self.pg2.get_capture(1)
500
501         self.verify_arp_req(rx[0],
502                             self.pg2.local_mac,
503                             self.pg1.local_ip4,
504                             self.pg1._remote_hosts[7].ip4)
505
506         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
507              ARP(op="who-has",
508                  hwsrc=self.pg2.remote_mac,
509                  pdst=self.pg1.local_ip4,
510                  psrc=self.pg1.remote_hosts[7].ip4))
511
512         self.pg2.add_stream(p)
513         self.pg_enable_capture(self.pg_interfaces)
514         self.pg_start()
515
516         rx = self.pg2.get_capture(1)
517         self.verify_arp_resp(rx[0],
518                              self.pg2.local_mac,
519                              self.pg2.remote_mac,
520                              self.pg1.local_ip4,
521                              self.pg1.remote_hosts[7].ip4)
522
523         #
524         # An attached host route as yet unresolved out of pg2 for an
525         # undiscovered host, an ARP requests begets a response.
526         #
527         att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
528                                 [VppRoutePath("0.0.0.0",
529                                               self.pg2.sw_if_index)])
530         att_unnum1.add_vpp_config()
531
532         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
533              ARP(op="who-has",
534                  hwsrc=self.pg2.remote_mac,
535                  pdst=self.pg1.local_ip4,
536                  psrc=self.pg1.remote_hosts[8].ip4))
537
538         self.pg2.add_stream(p)
539         self.pg_enable_capture(self.pg_interfaces)
540         self.pg_start()
541
542         rx = self.pg2.get_capture(1)
543         self.verify_arp_resp(rx[0],
544                              self.pg2.local_mac,
545                              self.pg2.remote_mac,
546                              self.pg1.local_ip4,
547                              self.pg1.remote_hosts[8].ip4)
548
549         #
550         # Send an ARP request from one of the so-far unlearned remote hosts
551         # with a VLAN0 tag
552         #
553         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
554                    src=self.pg1._remote_hosts[9].mac) /
555              Dot1Q(vlan=0) /
556              ARP(op="who-has",
557                  hwsrc=self.pg1._remote_hosts[9].mac,
558                  pdst=self.pg1.local_ip4,
559                  psrc=self.pg1._remote_hosts[9].ip4))
560
561         self.pg1.add_stream(p)
562         self.pg_enable_capture(self.pg_interfaces)
563         self.pg_start()
564
565         rx = self.pg1.get_capture(1)
566         self.verify_arp_resp(rx[0],
567                              self.pg1.local_mac,
568                              self.pg1._remote_hosts[9].mac,
569                              self.pg1.local_ip4,
570                              self.pg1._remote_hosts[9].ip4)
571
572         #
573         # Add a hierarchy of routes for a host in the sub-net.
574         # Should still get an ARP resp since the cover is attached
575         #
576         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
577              ARP(op="who-has",
578                  hwsrc=self.pg1.remote_mac,
579                  pdst=self.pg1.local_ip4,
580                  psrc=self.pg1.remote_hosts[10].ip4))
581
582         r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
583                         [VppRoutePath(self.pg1.remote_hosts[10].ip4,
584                                       self.pg1.sw_if_index)])
585         r1.add_vpp_config()
586
587         self.pg1.add_stream(p)
588         self.pg_enable_capture(self.pg_interfaces)
589         self.pg_start()
590         rx = self.pg1.get_capture(1)
591         self.verify_arp_resp(rx[0],
592                              self.pg1.local_mac,
593                              self.pg1.remote_mac,
594                              self.pg1.local_ip4,
595                              self.pg1.remote_hosts[10].ip4)
596
597         r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
598                         [VppRoutePath(self.pg1.remote_hosts[10].ip4,
599                                       self.pg1.sw_if_index)])
600         r2.add_vpp_config()
601
602         self.pg1.add_stream(p)
603         self.pg_enable_capture(self.pg_interfaces)
604         self.pg_start()
605         rx = self.pg1.get_capture(1)
606         self.verify_arp_resp(rx[0],
607                              self.pg1.local_mac,
608                              self.pg1.remote_mac,
609                              self.pg1.local_ip4,
610                              self.pg1.remote_hosts[10].ip4)
611
612         #
613         # add an ARP entry that's not on the sub-net and so whose
614         # adj-fib fails the refinement check. then send an ARP request
615         # from that source
616         #
617         a1 = VppNeighbor(self,
618                          self.pg0.sw_if_index,
619                          self.pg0.remote_mac,
620                          "100.100.100.50")
621         a1.add_vpp_config()
622
623         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
624              ARP(op="who-has",
625                  hwsrc=self.pg0.remote_mac,
626                  psrc="100.100.100.50",
627                  pdst=self.pg0.remote_ip4))
628         self.send_and_assert_no_replies(self.pg0, p,
629                                         "ARP req for from failed adj-fib")
630
631         #
632         # ERROR Cases
633         #  1 - don't respond to ARP request for address not within the
634         #      interface's sub-net
635         #  1b - nor within the unnumbered subnet
636         #  1c - nor within the subnet of a different interface
637         #
638         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
639              ARP(op="who-has",
640                  hwsrc=self.pg0.remote_mac,
641                  pdst="10.10.10.3",
642                  psrc=self.pg0.remote_ip4))
643         self.send_and_assert_no_replies(self.pg0, p,
644                                         "ARP req for non-local destination")
645         self.assertFalse(find_nbr(self,
646                                   self.pg0.sw_if_index,
647                                   "10.10.10.3"))
648
649         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
650              ARP(op="who-has",
651                  hwsrc=self.pg2.remote_mac,
652                  pdst="10.10.10.3",
653                  psrc=self.pg1.remote_hosts[7].ip4))
654         self.send_and_assert_no_replies(
655             self.pg0, p,
656             "ARP req for non-local destination - unnum")
657
658         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
659              ARP(op="who-has",
660                  hwsrc=self.pg0.remote_mac,
661                  pdst=self.pg1.local_ip4,
662                  psrc=self.pg1.remote_ip4))
663         self.send_and_assert_no_replies(self.pg0, p,
664                                         "ARP req diff sub-net")
665         self.assertFalse(find_nbr(self,
666                                   self.pg0.sw_if_index,
667                                   self.pg1.remote_ip4))
668
669         #
670         #  2 - don't respond to ARP request from an address not within the
671         #      interface's sub-net
672         #   2b - to a proxied address
673         #   2c - not within a different interface's sub-net
674         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
675              ARP(op="who-has",
676                  hwsrc=self.pg0.remote_mac,
677                  psrc="10.10.10.3",
678                  pdst=self.pg0.local_ip4))
679         self.send_and_assert_no_replies(self.pg0, p,
680                                         "ARP req for non-local source")
681         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
682              ARP(op="who-has",
683                  hwsrc=self.pg2.remote_mac,
684                  psrc="10.10.10.3",
685                  pdst=self.pg0.local_ip4))
686         self.send_and_assert_no_replies(
687             self.pg0, p,
688             "ARP req for non-local source - unnum")
689         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
690              ARP(op="who-has",
691                  hwsrc=self.pg0.remote_mac,
692                  psrc=self.pg1.remote_ip4,
693                  pdst=self.pg0.local_ip4))
694         self.send_and_assert_no_replies(self.pg0, p,
695                                         "ARP req for non-local source 2c")
696
697         #
698         #  3 - don't respond to ARP request from an address that belongs to
699         #      the router
700         #
701         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
702              ARP(op="who-has",
703                  hwsrc=self.pg0.remote_mac,
704                  psrc=self.pg0.local_ip4,
705                  pdst=self.pg0.local_ip4))
706         self.send_and_assert_no_replies(self.pg0, p,
707                                         "ARP req for non-local source")
708
709         #
710         #  4 - don't respond to ARP requests that has mac source different
711         #      from ARP request HW source
712         #
713         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
714              ARP(op="who-has",
715                  hwsrc="00:00:00:DE:AD:BE",
716                  psrc=self.pg0.remote_ip4,
717                  pdst=self.pg0.local_ip4))
718         self.send_and_assert_no_replies(self.pg0, p,
719                                         "ARP req for non-local source")
720
721         #
722         #  5 - don't respond to ARP requests for address within the
723         #      interface's sub-net but not the interface's address
724         #
725         self.pg0.generate_remote_hosts(2)
726         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
727              ARP(op="who-has",
728                  hwsrc=self.pg0.remote_mac,
729                  psrc=self.pg0.remote_hosts[0].ip4,
730                  pdst=self.pg0.remote_hosts[1].ip4))
731         self.send_and_assert_no_replies(self.pg0, p,
732                                         "ARP req for non-local destination")
733
734         #
735         # cleanup
736         #
737         static_arp.remove_vpp_config()
738         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
739
740         # need this to flush the adj-fibs
741         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
742         self.pg2.admin_down()
743         self.pg1.admin_down()
744
745     def test_proxy_mirror_arp(self):
746         """ Interface Mirror Proxy ARP """
747
748         #
749         # When VPP has an interface whose address is also applied to a TAP
750         # interface on the host, then VPP's TAP interface will be unnumbered
751         # to the 'real' interface and do proxy ARP from the host.
752         # the curious aspect of this setup is that ARP requests from the host
753         # will come from the VPP's own address.
754         #
755         self.pg0.generate_remote_hosts(2)
756
757         arp_req_from_me = (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=self.pg0.remote_hosts[1].ip4,
762                                psrc=self.pg0.local_ip4))
763
764         #
765         # Configure Proxy ARP for the subnet on PG0addresses on pg0
766         #
767         self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
768                                            'low': self.pg0._local_ip4_subnet,
769                                            'hi': self.pg0._local_ip4_bcast},
770                                     is_add=1)
771
772         # Make pg2 un-numbered to pg0
773         #
774         self.pg2.set_unnumbered(self.pg0.sw_if_index)
775
776         #
777         # Enable pg2 for proxy ARP
778         #
779         self.pg2.set_proxy_arp()
780
781         #
782         # Send the ARP request with an originating address that
783         # is VPP's own address
784         #
785         rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
786         self.verify_arp_resp(rx[0],
787                              self.pg2.local_mac,
788                              self.pg2.remote_mac,
789                              self.pg0.remote_hosts[1].ip4,
790                              self.pg0.local_ip4)
791
792         #
793         # validate we have not learned an ARP entry as a result of this
794         #
795         self.assertFalse(find_nbr(self,
796                                   self.pg2.sw_if_index,
797                                   self.pg0.local_ip4))
798
799         #
800         # setup a punt redirect so packets from the uplink go to the tap
801         #
802         redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index,
803                                      self.pg2.sw_if_index, self.pg0.local_ip4)
804         redirect.add_vpp_config()
805
806         p_tcp = (Ether(src=self.pg0.remote_mac,
807                        dst=self.pg0.local_mac,) /
808                  IP(src=self.pg0.remote_ip4,
809                     dst=self.pg0.local_ip4) /
810                  TCP(sport=80, dport=80) /
811                  Raw())
812         rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
813
814         # there's no ARP entry so this is an ARP req
815         self.assertTrue(rx[0].haslayer(ARP))
816
817         # and ARP entry for VPP's pg0 address on the host interface
818         n1 = VppNeighbor(self,
819                          self.pg2.sw_if_index,
820                          self.pg2.remote_mac,
821                          self.pg0.local_ip4,
822                          is_no_fib_entry=True).add_vpp_config()
823         # now the packets shold forward
824         rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
825         self.assertFalse(rx[0].haslayer(ARP))
826         self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
827
828         #
829         # flush the neighbor cache on the uplink
830         #
831         af = VppEnum.vl_api_address_family_t
832         self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
833
834         # ensure we can still resolve the ARPs on the uplink
835         self.pg0.resolve_arp()
836
837         self.assertTrue(find_nbr(self,
838                                  self.pg0.sw_if_index,
839                                  self.pg0.remote_ip4))
840
841         #
842         # cleanup
843         #
844         self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
845                                            'low': self.pg0._local_ip4_subnet,
846                                            'hi': self.pg0._local_ip4_bcast},
847                                     is_add=0)
848         redirect.remove_vpp_config()
849
850     def test_proxy_arp(self):
851         """ Proxy ARP """
852
853         self.pg1.generate_remote_hosts(2)
854
855         #
856         # Proxy ARP request packets for each interface
857         #
858         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
859                              dst="ff:ff:ff:ff:ff:ff") /
860                        ARP(op="who-has",
861                            hwsrc=self.pg0.remote_mac,
862                            pdst="10.10.10.3",
863                            psrc=self.pg0.remote_ip4))
864         arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
865                                     dst="ff:ff:ff:ff:ff:ff") /
866                               Dot1Q(vlan=0) /
867                               ARP(op="who-has",
868                                   hwsrc=self.pg0.remote_mac,
869                                   pdst="10.10.10.3",
870                                   psrc=self.pg0.remote_ip4))
871         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
872                              dst="ff:ff:ff:ff:ff:ff") /
873                        ARP(op="who-has",
874                            hwsrc=self.pg1.remote_mac,
875                            pdst="10.10.10.3",
876                            psrc=self.pg1.remote_ip4))
877         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
878                              dst="ff:ff:ff:ff:ff:ff") /
879                        ARP(op="who-has",
880                            hwsrc=self.pg2.remote_mac,
881                            pdst="10.10.10.3",
882                            psrc=self.pg1.remote_hosts[1].ip4))
883         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
884                              dst="ff:ff:ff:ff:ff:ff") /
885                        ARP(op="who-has",
886                            hwsrc=self.pg3.remote_mac,
887                            pdst="10.10.10.3",
888                            psrc=self.pg3.remote_ip4))
889
890         #
891         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
892         #
893         self.vapi.proxy_arp_add_del(proxy={'table_id': 0,
894                                            'low': "10.10.10.2",
895                                            'hi': "10.10.10.124"},
896                                     is_add=1)
897
898         #
899         # No responses are sent when the interfaces are not enabled for proxy
900         # ARP
901         #
902         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
903                                         "ARP req from unconfigured interface")
904         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
905                                         "ARP req from unconfigured interface")
906
907         #
908         # Make pg2 un-numbered to pg1
909         #  still won't reply.
910         #
911         self.pg2.set_unnumbered(self.pg1.sw_if_index)
912
913         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
914                                         "ARP req from unnumbered interface")
915
916         #
917         # Enable each interface to reply to proxy ARPs
918         #
919         for i in self.pg_interfaces:
920             i.set_proxy_arp()
921
922         #
923         # Now each of the interfaces should reply to a request to a proxied
924         # address
925         #
926         self.pg0.add_stream(arp_req_pg0)
927         self.pg_enable_capture(self.pg_interfaces)
928         self.pg_start()
929
930         rx = self.pg0.get_capture(1)
931         self.verify_arp_resp(rx[0],
932                              self.pg0.local_mac,
933                              self.pg0.remote_mac,
934                              "10.10.10.3",
935                              self.pg0.remote_ip4)
936
937         self.pg0.add_stream(arp_req_pg0_tagged)
938         self.pg_enable_capture(self.pg_interfaces)
939         self.pg_start()
940
941         rx = self.pg0.get_capture(1)
942         self.verify_arp_resp(rx[0],
943                              self.pg0.local_mac,
944                              self.pg0.remote_mac,
945                              "10.10.10.3",
946                              self.pg0.remote_ip4)
947
948         self.pg1.add_stream(arp_req_pg1)
949         self.pg_enable_capture(self.pg_interfaces)
950         self.pg_start()
951
952         rx = self.pg1.get_capture(1)
953         self.verify_arp_resp(rx[0],
954                              self.pg1.local_mac,
955                              self.pg1.remote_mac,
956                              "10.10.10.3",
957                              self.pg1.remote_ip4)
958
959         self.pg2.add_stream(arp_req_pg2)
960         self.pg_enable_capture(self.pg_interfaces)
961         self.pg_start()
962
963         rx = self.pg2.get_capture(1)
964         self.verify_arp_resp(rx[0],
965                              self.pg2.local_mac,
966                              self.pg2.remote_mac,
967                              "10.10.10.3",
968                              self.pg1.remote_hosts[1].ip4)
969
970         #
971         # A request for an address out of the configured range
972         #
973         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
974                                 dst="ff:ff:ff:ff:ff:ff") /
975                           ARP(op="who-has",
976                               hwsrc=self.pg1.remote_mac,
977                               pdst="10.10.10.125",
978                               psrc=self.pg1.remote_ip4))
979         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
980                                         "ARP req out of range HI")
981         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
982                                  dst="ff:ff:ff:ff:ff:ff") /
983                            ARP(op="who-has",
984                                hwsrc=self.pg1.remote_mac,
985                                pdst="10.10.10.1",
986                                psrc=self.pg1.remote_ip4))
987         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
988                                         "ARP req out of range Low")
989
990         #
991         # Request for an address in the proxy range but from an interface
992         # in a different VRF
993         #
994         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
995                                         "ARP req from different VRF")
996
997         #
998         # Disable Each interface for proxy ARP
999         #  - expect none to respond
1000         #
1001         for i in self.pg_interfaces:
1002             i.set_proxy_arp(0)
1003
1004         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
1005                                         "ARP req from disable")
1006         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1007                                         "ARP req from disable")
1008         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1009                                         "ARP req from disable")
1010
1011         #
1012         # clean up on interface 2
1013         #
1014         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1015
1016     def test_mpls(self):
1017         """ MPLS """
1018
1019         #
1020         # Interface 2 does not yet have ip4 config
1021         #
1022         self.pg2.config_ip4()
1023         self.pg2.generate_remote_hosts(2)
1024
1025         #
1026         # Add a route with out going label via an ARP unresolved next-hop
1027         #
1028         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1029                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1030                                                self.pg2.sw_if_index,
1031                                                labels=[55])])
1032         ip_10_0_0_1.add_vpp_config()
1033
1034         #
1035         # packets should generate an ARP request
1036         #
1037         p = (Ether(src=self.pg0.remote_mac,
1038                    dst=self.pg0.local_mac) /
1039              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1040              UDP(sport=1234, dport=1234) /
1041              Raw(b'\xa5' * 100))
1042
1043         self.pg0.add_stream(p)
1044         self.pg_enable_capture(self.pg_interfaces)
1045         self.pg_start()
1046
1047         rx = self.pg2.get_capture(1)
1048         self.verify_arp_req(rx[0],
1049                             self.pg2.local_mac,
1050                             self.pg2.local_ip4,
1051                             self.pg2._remote_hosts[1].ip4)
1052
1053         #
1054         # now resolve the neighbours
1055         #
1056         self.pg2.configure_ipv4_neighbors()
1057
1058         #
1059         # Now packet should be properly MPLS encapped.
1060         #  This verifies that MPLS link-type adjacencies are completed
1061         #  when the ARP entry resolves
1062         #
1063         self.pg0.add_stream(p)
1064         self.pg_enable_capture(self.pg_interfaces)
1065         self.pg_start()
1066
1067         rx = self.pg2.get_capture(1)
1068         self.verify_ip_o_mpls(rx[0],
1069                               self.pg2.local_mac,
1070                               self.pg2.remote_hosts[1].mac,
1071                               55,
1072                               self.pg0.remote_ip4,
1073                               "10.0.0.1")
1074         self.pg2.unconfig_ip4()
1075
1076     def test_arp_vrrp(self):
1077         """ ARP reply with VRRP virtual src hw addr """
1078
1079         #
1080         # IP packet destined for pg1 remote host arrives on pg0 resulting
1081         # in an ARP request for the address of the remote host on pg1
1082         #
1083         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1084               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1085               UDP(sport=1234, dport=1234) /
1086               Raw())
1087
1088         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1089
1090         self.verify_arp_req(rx1[0],
1091                             self.pg1.local_mac,
1092                             self.pg1.local_ip4,
1093                             self.pg1.remote_ip4)
1094
1095         #
1096         # ARP reply for address of pg1 remote host arrives on pg1 with
1097         # the hw src addr set to a value in the VRRP IPv4 range of
1098         # MAC addresses
1099         #
1100         p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1101               ARP(op="is-at", hwdst=self.pg1.local_mac,
1102                   hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1103                   psrc=self.pg1.remote_ip4))
1104
1105         self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1106
1107         #
1108         # IP packet destined for pg1 remote host arrives on pg0 again.
1109         # VPP should have an ARP entry for that address now and the packet
1110         # should be sent out pg1.
1111         #
1112         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1113
1114         self.verify_ip(rx1[0],
1115                        self.pg1.local_mac,
1116                        "00:00:5e:00:01:09",
1117                        self.pg0.remote_ip4,
1118                        self.pg1.remote_ip4)
1119
1120         self.pg1.admin_down()
1121         self.pg1.admin_up()
1122
1123     def test_arp_duplicates(self):
1124         """ ARP Duplicates"""
1125
1126         #
1127         # Generate some hosts on the LAN
1128         #
1129         self.pg1.generate_remote_hosts(3)
1130
1131         #
1132         # Add host 1 on pg1 and pg2
1133         #
1134         arp_pg1 = VppNeighbor(self,
1135                               self.pg1.sw_if_index,
1136                               self.pg1.remote_hosts[1].mac,
1137                               self.pg1.remote_hosts[1].ip4)
1138         arp_pg1.add_vpp_config()
1139         arp_pg2 = VppNeighbor(self,
1140                               self.pg2.sw_if_index,
1141                               self.pg2.remote_mac,
1142                               self.pg1.remote_hosts[1].ip4)
1143         arp_pg2.add_vpp_config()
1144
1145         #
1146         # IP packet destined for pg1 remote host arrives on pg1 again.
1147         #
1148         p = (Ether(dst=self.pg0.local_mac,
1149                    src=self.pg0.remote_mac) /
1150              IP(src=self.pg0.remote_ip4,
1151                 dst=self.pg1.remote_hosts[1].ip4) /
1152              UDP(sport=1234, dport=1234) /
1153              Raw())
1154
1155         self.pg0.add_stream(p)
1156         self.pg_enable_capture(self.pg_interfaces)
1157         self.pg_start()
1158
1159         rx1 = self.pg1.get_capture(1)
1160
1161         self.verify_ip(rx1[0],
1162                        self.pg1.local_mac,
1163                        self.pg1.remote_hosts[1].mac,
1164                        self.pg0.remote_ip4,
1165                        self.pg1.remote_hosts[1].ip4)
1166
1167         #
1168         # remove the duplicate on pg1
1169         # packet stream should generate ARPs out of pg1
1170         #
1171         arp_pg1.remove_vpp_config()
1172
1173         self.pg0.add_stream(p)
1174         self.pg_enable_capture(self.pg_interfaces)
1175         self.pg_start()
1176
1177         rx1 = self.pg1.get_capture(1)
1178
1179         self.verify_arp_req(rx1[0],
1180                             self.pg1.local_mac,
1181                             self.pg1.local_ip4,
1182                             self.pg1.remote_hosts[1].ip4)
1183
1184         #
1185         # Add it back
1186         #
1187         arp_pg1.add_vpp_config()
1188
1189         self.pg0.add_stream(p)
1190         self.pg_enable_capture(self.pg_interfaces)
1191         self.pg_start()
1192
1193         rx1 = self.pg1.get_capture(1)
1194
1195         self.verify_ip(rx1[0],
1196                        self.pg1.local_mac,
1197                        self.pg1.remote_hosts[1].mac,
1198                        self.pg0.remote_ip4,
1199                        self.pg1.remote_hosts[1].ip4)
1200
1201     def test_arp_static(self):
1202         """ ARP Static"""
1203         self.pg2.generate_remote_hosts(3)
1204
1205         #
1206         # Add a static ARP entry
1207         #
1208         static_arp = VppNeighbor(self,
1209                                  self.pg2.sw_if_index,
1210                                  self.pg2.remote_hosts[1].mac,
1211                                  self.pg2.remote_hosts[1].ip4,
1212                                  is_static=1)
1213         static_arp.add_vpp_config()
1214
1215         #
1216         # Add the connected prefix to the interface
1217         #
1218         self.pg2.config_ip4()
1219
1220         #
1221         # We should now find the adj-fib
1222         #
1223         self.assertTrue(find_nbr(self,
1224                                  self.pg2.sw_if_index,
1225                                  self.pg2.remote_hosts[1].ip4,
1226                                  is_static=1))
1227         self.assertTrue(find_route(self,
1228                                    self.pg2.remote_hosts[1].ip4,
1229                                    32))
1230
1231         #
1232         # remove the connected
1233         #
1234         self.pg2.unconfig_ip4()
1235
1236         #
1237         # put the interface into table 1
1238         #
1239         self.pg2.set_table_ip4(1)
1240
1241         #
1242         # configure the same connected and expect to find the
1243         # adj fib in the new table
1244         #
1245         self.pg2.config_ip4()
1246         self.assertTrue(find_route(self,
1247                                    self.pg2.remote_hosts[1].ip4,
1248                                    32,
1249                                    table_id=1))
1250
1251         #
1252         # clean-up
1253         #
1254         self.pg2.unconfig_ip4()
1255         static_arp.remove_vpp_config()
1256         self.pg2.set_table_ip4(0)
1257
1258     def test_arp_static_replace_dynamic_same_mac(self):
1259         """ ARP Static can replace Dynamic (same mac) """
1260         self.pg2.generate_remote_hosts(1)
1261
1262         dyn_arp = VppNeighbor(self,
1263                               self.pg2.sw_if_index,
1264                               self.pg2.remote_hosts[0].mac,
1265                               self.pg2.remote_hosts[0].ip4)
1266         static_arp = VppNeighbor(self,
1267                                  self.pg2.sw_if_index,
1268                                  self.pg2.remote_hosts[0].mac,
1269                                  self.pg2.remote_hosts[0].ip4,
1270                                  is_static=1)
1271
1272         #
1273         # Add a dynamic ARP entry
1274         #
1275         dyn_arp.add_vpp_config()
1276
1277         #
1278         # We should find the dynamic nbr
1279         #
1280         self.assertFalse(find_nbr(self,
1281                                   self.pg2.sw_if_index,
1282                                   self.pg2.remote_hosts[0].ip4,
1283                                   is_static=1))
1284         self.assertTrue(find_nbr(self,
1285                                  self.pg2.sw_if_index,
1286                                  self.pg2.remote_hosts[0].ip4,
1287                                  is_static=0,
1288                                  mac=self.pg2.remote_hosts[0].mac))
1289
1290         #
1291         # Add a static ARP entry with the same mac
1292         #
1293         static_arp.add_vpp_config()
1294
1295         #
1296         # We should now find the static nbr with the same mac
1297         #
1298         self.assertFalse(find_nbr(self,
1299                                   self.pg2.sw_if_index,
1300                                   self.pg2.remote_hosts[0].ip4,
1301                                   is_static=0))
1302         self.assertTrue(find_nbr(self,
1303                                  self.pg2.sw_if_index,
1304                                  self.pg2.remote_hosts[0].ip4,
1305                                  is_static=1,
1306                                  mac=self.pg2.remote_hosts[0].mac))
1307
1308         #
1309         # clean-up
1310         #
1311         static_arp.remove_vpp_config()
1312
1313     def test_arp_static_replace_dynamic_diff_mac(self):
1314         """ ARP Static can replace Dynamic (diff mac) """
1315         self.pg2.generate_remote_hosts(2)
1316
1317         dyn_arp = VppNeighbor(self,
1318                               self.pg2.sw_if_index,
1319                               self.pg2.remote_hosts[0].mac,
1320                               self.pg2.remote_hosts[0].ip4)
1321         static_arp = VppNeighbor(self,
1322                                  self.pg2.sw_if_index,
1323                                  self.pg2.remote_hosts[1].mac,
1324                                  self.pg2.remote_hosts[0].ip4,
1325                                  is_static=1)
1326
1327         #
1328         # Add a dynamic ARP entry
1329         #
1330         dyn_arp.add_vpp_config()
1331
1332         #
1333         # We should find the dynamic nbr
1334         #
1335         self.assertFalse(find_nbr(self,
1336                                   self.pg2.sw_if_index,
1337                                   self.pg2.remote_hosts[0].ip4,
1338                                   is_static=1))
1339         self.assertTrue(find_nbr(self,
1340                                  self.pg2.sw_if_index,
1341                                  self.pg2.remote_hosts[0].ip4,
1342                                  is_static=0,
1343                                  mac=self.pg2.remote_hosts[0].mac))
1344
1345         #
1346         # Add a static ARP entry with a changed mac
1347         #
1348         static_arp.add_vpp_config()
1349
1350         #
1351         # We should now find the static nbr with a changed mac
1352         #
1353         self.assertFalse(find_nbr(self,
1354                                   self.pg2.sw_if_index,
1355                                   self.pg2.remote_hosts[0].ip4,
1356                                   is_static=0))
1357         self.assertTrue(find_nbr(self,
1358                                  self.pg2.sw_if_index,
1359                                  self.pg2.remote_hosts[0].ip4,
1360                                  is_static=1,
1361                                  mac=self.pg2.remote_hosts[1].mac))
1362
1363         #
1364         # clean-up
1365         #
1366         static_arp.remove_vpp_config()
1367
1368     def test_arp_incomplete(self):
1369         """ ARP Incomplete"""
1370         self.pg1.generate_remote_hosts(3)
1371
1372         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1373               IP(src=self.pg0.remote_ip4,
1374                  dst=self.pg1.remote_hosts[1].ip4) /
1375               UDP(sport=1234, dport=1234) /
1376               Raw())
1377         p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1378               IP(src=self.pg0.remote_ip4,
1379                  dst=self.pg1.remote_hosts[2].ip4) /
1380               UDP(sport=1234, dport=1234) /
1381               Raw())
1382
1383         #
1384         # a packet to an unresolved destination generates an ARP request
1385         #
1386         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1387         self.verify_arp_req(rx[0],
1388                             self.pg1.local_mac,
1389                             self.pg1.local_ip4,
1390                             self.pg1._remote_hosts[1].ip4)
1391
1392         #
1393         # add a neighbour for remote host 1
1394         #
1395         static_arp = VppNeighbor(self,
1396                                  self.pg1.sw_if_index,
1397                                  self.pg1.remote_hosts[1].mac,
1398                                  self.pg1.remote_hosts[1].ip4,
1399                                  is_static=1)
1400         static_arp.add_vpp_config()
1401
1402         #
1403         # change the interface's MAC
1404         #
1405         self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1406                                                "00:00:00:33:33:33")
1407
1408         #
1409         # now ARP requests come from the new source mac
1410         #
1411         rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1412         self.verify_arp_req(rx[0],
1413                             "00:00:00:33:33:33",
1414                             self.pg1.local_ip4,
1415                             self.pg1._remote_hosts[2].ip4)
1416
1417         #
1418         # packets to the resolved host also have the new source mac
1419         #
1420         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1421         self.verify_ip(rx[0],
1422                        "00:00:00:33:33:33",
1423                        self.pg1.remote_hosts[1].mac,
1424                        self.pg0.remote_ip4,
1425                        self.pg1.remote_hosts[1].ip4)
1426
1427         #
1428         # set the mac address on the interface that does not have a
1429         # configured subnet and thus no glean
1430         #
1431         self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1432                                                "00:00:00:33:33:33")
1433
1434     def test_garp(self):
1435         """ GARP """
1436
1437         #
1438         # Generate some hosts on the LAN
1439         #
1440         self.pg1.generate_remote_hosts(4)
1441         self.pg2.generate_remote_hosts(4)
1442
1443         #
1444         # And an ARP entry
1445         #
1446         arp = VppNeighbor(self,
1447                           self.pg1.sw_if_index,
1448                           self.pg1.remote_hosts[1].mac,
1449                           self.pg1.remote_hosts[1].ip4)
1450         arp.add_vpp_config()
1451
1452         self.assertTrue(find_nbr(self,
1453                                  self.pg1.sw_if_index,
1454                                  self.pg1.remote_hosts[1].ip4,
1455                                  mac=self.pg1.remote_hosts[1].mac))
1456
1457         #
1458         # Send a GARP (request) to swap the host 1's address to that of host 2
1459         #
1460         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1461                     src=self.pg1.remote_hosts[2].mac) /
1462               ARP(op="who-has",
1463                   hwdst=self.pg1.local_mac,
1464                   hwsrc=self.pg1.remote_hosts[2].mac,
1465                   pdst=self.pg1.remote_hosts[1].ip4,
1466                   psrc=self.pg1.remote_hosts[1].ip4))
1467
1468         self.pg1.add_stream(p1)
1469         self.pg_enable_capture(self.pg_interfaces)
1470         self.pg_start()
1471
1472         self.assertTrue(find_nbr(self,
1473                                  self.pg1.sw_if_index,
1474                                  self.pg1.remote_hosts[1].ip4,
1475                                  mac=self.pg1.remote_hosts[2].mac))
1476
1477         #
1478         # Send a GARP (reply) to swap the host 1's address to that of host 3
1479         #
1480         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1481                     src=self.pg1.remote_hosts[3].mac) /
1482               ARP(op="is-at",
1483                   hwdst=self.pg1.local_mac,
1484                   hwsrc=self.pg1.remote_hosts[3].mac,
1485                   pdst=self.pg1.remote_hosts[1].ip4,
1486                   psrc=self.pg1.remote_hosts[1].ip4))
1487
1488         self.pg1.add_stream(p1)
1489         self.pg_enable_capture(self.pg_interfaces)
1490         self.pg_start()
1491
1492         self.assertTrue(find_nbr(self,
1493                                  self.pg1.sw_if_index,
1494                                  self.pg1.remote_hosts[1].ip4,
1495                                  mac=self.pg1.remote_hosts[3].mac))
1496
1497         #
1498         # GARPs (request nor replies) for host we don't know yet
1499         # don't result in new neighbour entries
1500         #
1501         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1502                     src=self.pg1.remote_hosts[3].mac) /
1503               ARP(op="who-has",
1504                   hwdst=self.pg1.local_mac,
1505                   hwsrc=self.pg1.remote_hosts[3].mac,
1506                   pdst=self.pg1.remote_hosts[2].ip4,
1507                   psrc=self.pg1.remote_hosts[2].ip4))
1508
1509         self.pg1.add_stream(p1)
1510         self.pg_enable_capture(self.pg_interfaces)
1511         self.pg_start()
1512
1513         self.assertFalse(find_nbr(self,
1514                                   self.pg1.sw_if_index,
1515                                   self.pg1.remote_hosts[2].ip4))
1516
1517         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1518                     src=self.pg1.remote_hosts[3].mac) /
1519               ARP(op="is-at",
1520                   hwdst=self.pg1.local_mac,
1521                   hwsrc=self.pg1.remote_hosts[3].mac,
1522                   pdst=self.pg1.remote_hosts[2].ip4,
1523                   psrc=self.pg1.remote_hosts[2].ip4))
1524
1525         self.pg1.add_stream(p1)
1526         self.pg_enable_capture(self.pg_interfaces)
1527         self.pg_start()
1528
1529         self.assertFalse(find_nbr(self,
1530                                   self.pg1.sw_if_index,
1531                                   self.pg1.remote_hosts[2].ip4))
1532
1533         #
1534         # IP address in different subnets are not learnt
1535         #
1536         self.pg2.configure_ipv4_neighbors()
1537
1538         for op in ["is-at", "who-has"]:
1539             p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1540                          src=self.pg2.remote_hosts[1].mac) /
1541                    ARP(op=op,
1542                        hwdst=self.pg2.local_mac,
1543                        hwsrc=self.pg2.remote_hosts[1].mac,
1544                        pdst=self.pg2.remote_hosts[1].ip4,
1545                        psrc=self.pg2.remote_hosts[1].ip4)),
1546                   (Ether(dst="ff:ff:ff:ff:ff:ff",
1547                          src=self.pg2.remote_hosts[1].mac) /
1548                    ARP(op=op,
1549                        hwdst="ff:ff:ff:ff:ff:ff",
1550                        hwsrc=self.pg2.remote_hosts[1].mac,
1551                        pdst=self.pg2.remote_hosts[1].ip4,
1552                        psrc=self.pg2.remote_hosts[1].ip4))]
1553
1554             self.send_and_assert_no_replies(self.pg1, p1)
1555             self.assertFalse(find_nbr(self,
1556                                       self.pg1.sw_if_index,
1557                                       self.pg2.remote_hosts[1].ip4))
1558
1559         # they are all dropped because the subnet's don't match
1560         self.assertEqual(4, self.statistics.get_err_counter(
1561             "/err/arp-reply/IP4 destination address not local to subnet"))
1562
1563     def test_arp_incomplete2(self):
1564         """ Incomplete Entries """
1565
1566         #
1567         # ensure that we throttle the ARP and ND requests
1568         #
1569         self.pg0.generate_remote_hosts(2)
1570
1571         #
1572         # IPv4/ARP
1573         #
1574         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1575                                  [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1576                                                self.pg0.sw_if_index)])
1577         ip_10_0_0_1.add_vpp_config()
1578
1579         p1 = (Ether(dst=self.pg1.local_mac,
1580                     src=self.pg1.remote_mac) /
1581               IP(src=self.pg1.remote_ip4,
1582                  dst="10.0.0.1") /
1583               UDP(sport=1234, dport=1234) /
1584               Raw())
1585
1586         self.pg1.add_stream(p1 * 257)
1587         self.pg_enable_capture(self.pg_interfaces)
1588         self.pg_start()
1589         rx = self.pg0._get_capture(1)
1590
1591         #
1592         # how many we get is going to be dependent on the time for packet
1593         # processing but it should be small
1594         #
1595         self.assertLess(len(rx), 64)
1596
1597         #
1598         # IPv6/ND
1599         #
1600         ip_10_1 = VppIpRoute(self, "10::1", 128,
1601                              [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1602                                            self.pg0.sw_if_index,
1603                                            proto=DpoProto.DPO_PROTO_IP6)])
1604         ip_10_1.add_vpp_config()
1605
1606         p1 = (Ether(dst=self.pg1.local_mac,
1607                     src=self.pg1.remote_mac) /
1608               IPv6(src=self.pg1.remote_ip6,
1609                    dst="10::1") /
1610               UDP(sport=1234, dport=1234) /
1611               Raw())
1612
1613         self.pg1.add_stream(p1 * 257)
1614         self.pg_enable_capture(self.pg_interfaces)
1615         self.pg_start()
1616         rx = self.pg0._get_capture(1)
1617
1618         #
1619         # how many we get is going to be dependent on the time for packet
1620         # processing but it should be small
1621         #
1622         self.assertLess(len(rx), 64)
1623
1624     def test_arp_forus(self):
1625         """ ARP for for-us """
1626
1627         #
1628         # Test that VPP responds with ARP requests to addresses that
1629         # are connected and local routes.
1630         # Use one of the 'remote' addresses in the subnet as a local address
1631         # The intention of this route is that it then acts like a secondary
1632         # address added to an interface
1633         #
1634         self.pg0.generate_remote_hosts(2)
1635
1636         forus = VppIpRoute(
1637             self, self.pg0.remote_hosts[1].ip4, 32,
1638             [VppRoutePath("0.0.0.0",
1639                           self.pg0.sw_if_index,
1640                           type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1641         forus.add_vpp_config()
1642
1643         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1644                    src=self.pg0.remote_mac) /
1645              ARP(op="who-has",
1646                  hwdst=self.pg0.local_mac,
1647                  hwsrc=self.pg0.remote_mac,
1648                  pdst=self.pg0.remote_hosts[1].ip4,
1649                  psrc=self.pg0.remote_ip4))
1650
1651         rx = self.send_and_expect(self.pg0, [p], self.pg0)
1652
1653         self.verify_arp_resp(rx[0],
1654                              self.pg0.local_mac,
1655                              self.pg0.remote_mac,
1656                              self.pg0.remote_hosts[1].ip4,
1657                              self.pg0.remote_ip4)
1658
1659     def test_arp_table_swap(self):
1660         #
1661         # Generate some hosts on the LAN
1662         #
1663         N_NBRS = 4
1664         self.pg1.generate_remote_hosts(N_NBRS)
1665
1666         for n in range(N_NBRS):
1667             # a route thru each neighbour
1668             VppIpRoute(self, "10.0.0.%d" % n, 32,
1669                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1670                                      self.pg1.sw_if_index)]).add_vpp_config()
1671
1672             # resolve each neighbour
1673             p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1674                   ARP(op="is-at", hwdst=self.pg1.local_mac,
1675                       hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1676                       psrc=self.pg1.remote_hosts[n].ip4))
1677
1678             self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1679
1680         self.logger.info(self.vapi.cli("sh ip neighbors"))
1681
1682         #
1683         # swap the table pg1 is in
1684         #
1685         table = VppIpTable(self, 100).add_vpp_config()
1686
1687         self.pg1.unconfig_ip4()
1688         self.pg1.set_table_ip4(100)
1689         self.pg1.config_ip4()
1690
1691         #
1692         # all neighbours are cleared
1693         #
1694         for n in range(N_NBRS):
1695             self.assertFalse(find_nbr(self,
1696                                       self.pg1.sw_if_index,
1697                                       self.pg1.remote_hosts[n].ip4))
1698
1699         #
1700         # packets to all neighbours generate ARP requests
1701         #
1702         for n in range(N_NBRS):
1703             # a route thru each neighbour
1704             VppIpRoute(self, "10.0.0.%d" % n, 32,
1705                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1706                                      self.pg1.sw_if_index)],
1707                        table_id=100).add_vpp_config()
1708
1709             p = (Ether(src=self.pg1.remote_hosts[n].mac,
1710                        dst=self.pg1.local_mac) /
1711                  IP(src=self.pg1.remote_hosts[n].ip4,
1712                     dst="10.0.0.%d" % n) /
1713                  Raw(b'0x5' * 100))
1714             rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1715             for rx in rxs:
1716                 self.verify_arp_req(rx,
1717                                     self.pg1.local_mac,
1718                                     self.pg1.local_ip4,
1719                                     self.pg1.remote_hosts[n].ip4)
1720
1721         self.pg1.unconfig_ip4()
1722         self.pg1.set_table_ip4(0)
1723
1724
1725 class NeighborStatsTestCase(VppTestCase):
1726     """ ARP/ND Counters """
1727
1728     @classmethod
1729     def setUpClass(cls):
1730         super(NeighborStatsTestCase, cls).setUpClass()
1731
1732     @classmethod
1733     def tearDownClass(cls):
1734         super(NeighborStatsTestCase, cls).tearDownClass()
1735
1736     def setUp(self):
1737         super(NeighborStatsTestCase, self).setUp()
1738
1739         self.create_pg_interfaces(range(2))
1740
1741         # pg0 configured with ip4 and 6 addresses used for input
1742         # pg1 configured with ip4 and 6 addresses used for output
1743         # pg2 is unnumbered to pg0
1744         for i in self.pg_interfaces:
1745             i.admin_up()
1746             i.config_ip4()
1747             i.config_ip6()
1748             i.resolve_arp()
1749             i.resolve_ndp()
1750
1751     def tearDown(self):
1752         super(NeighborStatsTestCase, self).tearDown()
1753
1754         for i in self.pg_interfaces:
1755             i.unconfig_ip4()
1756             i.unconfig_ip6()
1757             i.admin_down()
1758
1759     def test_arp_stats(self):
1760         """ ARP Counters """
1761
1762         self.vapi.cli("adj counters enable")
1763         self.pg1.generate_remote_hosts(2)
1764
1765         arp1 = VppNeighbor(self,
1766                            self.pg1.sw_if_index,
1767                            self.pg1.remote_hosts[0].mac,
1768                            self.pg1.remote_hosts[0].ip4)
1769         arp1.add_vpp_config()
1770         arp2 = VppNeighbor(self,
1771                            self.pg1.sw_if_index,
1772                            self.pg1.remote_hosts[1].mac,
1773                            self.pg1.remote_hosts[1].ip4)
1774         arp2.add_vpp_config()
1775
1776         p1 = (Ether(dst=self.pg0.local_mac,
1777                     src=self.pg0.remote_mac) /
1778               IP(src=self.pg0.remote_ip4,
1779                  dst=self.pg1.remote_hosts[0].ip4) /
1780               UDP(sport=1234, dport=1234) /
1781               Raw())
1782         p2 = (Ether(dst=self.pg0.local_mac,
1783                     src=self.pg0.remote_mac) /
1784               IP(src=self.pg0.remote_ip4,
1785                  dst=self.pg1.remote_hosts[1].ip4) /
1786               UDP(sport=1234, dport=1234) /
1787               Raw())
1788
1789         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1790         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1791
1792         self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1793         self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1794
1795         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1796         self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1797
1798     def test_nd_stats(self):
1799         """ ND Counters """
1800
1801         self.vapi.cli("adj counters enable")
1802         self.pg0.generate_remote_hosts(3)
1803
1804         nd1 = VppNeighbor(self,
1805                           self.pg0.sw_if_index,
1806                           self.pg0.remote_hosts[1].mac,
1807                           self.pg0.remote_hosts[1].ip6)
1808         nd1.add_vpp_config()
1809         nd2 = VppNeighbor(self,
1810                           self.pg0.sw_if_index,
1811                           self.pg0.remote_hosts[2].mac,
1812                           self.pg0.remote_hosts[2].ip6)
1813         nd2.add_vpp_config()
1814
1815         p1 = (Ether(dst=self.pg1.local_mac,
1816                     src=self.pg1.remote_mac) /
1817               IPv6(src=self.pg1.remote_ip6,
1818                    dst=self.pg0.remote_hosts[1].ip6) /
1819               UDP(sport=1234, dport=1234) /
1820               Raw())
1821         p2 = (Ether(dst=self.pg1.local_mac,
1822                     src=self.pg1.remote_mac) /
1823               IPv6(src=self.pg1.remote_ip6,
1824                    dst=self.pg0.remote_hosts[2].ip6) /
1825               UDP(sport=1234, dport=1234) /
1826               Raw())
1827
1828         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1829         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1830
1831         self.assertEqual(16, nd1.get_stats()['packets'])
1832         self.assertEqual(16, nd2.get_stats()['packets'])
1833
1834         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1835         self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1836
1837
1838 class NeighborAgeTestCase(VppTestCase):
1839     """ ARP/ND Aging """
1840
1841     @classmethod
1842     def setUpClass(cls):
1843         super(NeighborAgeTestCase, cls).setUpClass()
1844
1845     @classmethod
1846     def tearDownClass(cls):
1847         super(NeighborAgeTestCase, cls).tearDownClass()
1848
1849     def setUp(self):
1850         super(NeighborAgeTestCase, self).setUp()
1851
1852         self.create_pg_interfaces(range(1))
1853
1854         # pg0 configured with ip4 and 6 addresses used for input
1855         # pg1 configured with ip4 and 6 addresses used for output
1856         # pg2 is unnumbered to pg0
1857         for i in self.pg_interfaces:
1858             i.admin_up()
1859             i.config_ip4()
1860             i.config_ip6()
1861             i.resolve_arp()
1862             i.resolve_ndp()
1863
1864     def tearDown(self):
1865         super(NeighborAgeTestCase, self).tearDown()
1866
1867         for i in self.pg_interfaces:
1868             i.unconfig_ip4()
1869             i.unconfig_ip6()
1870             i.admin_down()
1871
1872     def wait_for_no_nbr(self, intf, address,
1873                         n_tries=50, s_time=1):
1874         while (n_tries):
1875             if not find_nbr(self, intf, address):
1876                 return True
1877             n_tries = n_tries - 1
1878             self.sleep(s_time)
1879
1880         return False
1881
1882     def verify_arp_req(self, rx, smac, sip, dip):
1883         ether = rx[Ether]
1884         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1885         self.assertEqual(ether.src, smac)
1886
1887         arp = rx[ARP]
1888         self.assertEqual(arp.hwtype, 1)
1889         self.assertEqual(arp.ptype, 0x800)
1890         self.assertEqual(arp.hwlen, 6)
1891         self.assertEqual(arp.plen, 4)
1892         self.assertEqual(arp.op, arp_opts["who-has"])
1893         self.assertEqual(arp.hwsrc, smac)
1894         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1895         self.assertEqual(arp.psrc, sip)
1896         self.assertEqual(arp.pdst, dip)
1897
1898     def test_age(self):
1899         """ Aging/Recycle """
1900
1901         self.vapi.cli("set logging unthrottle 0")
1902         self.vapi.cli("set logging size %d" % 0xffff)
1903
1904         self.pg0.generate_remote_hosts(201)
1905
1906         vaf = VppEnum.vl_api_address_family_t
1907
1908         #
1909         # start listening on all interfaces
1910         #
1911         self.pg_enable_capture(self.pg_interfaces)
1912
1913         #
1914         # Set the neighbor configuration:
1915         #   limi = 200
1916         #   age  = 0 seconds
1917         #   recycle = false
1918         #
1919         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1920                                      max_number=200,
1921                                      max_age=0,
1922                                      recycle=False)
1923
1924         self.vapi.cli("sh ip neighbor-config")
1925
1926         # add the 198 neighbours that should pass (-1 for one created in setup)
1927         for ii in range(200):
1928             VppNeighbor(self,
1929                         self.pg0.sw_if_index,
1930                         self.pg0.remote_hosts[ii].mac,
1931                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1932
1933         # one more neighbor over the limit should fail
1934         with self.vapi.assert_negative_api_retval():
1935             VppNeighbor(self,
1936                         self.pg0.sw_if_index,
1937                         self.pg0.remote_hosts[200].mac,
1938                         self.pg0.remote_hosts[200].ip4).add_vpp_config()
1939
1940         #
1941         # change the config to allow recycling the old neighbors
1942         #
1943         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1944                                      max_number=200,
1945                                      max_age=0,
1946                                      recycle=True)
1947
1948         # now new additions are allowed
1949         VppNeighbor(self,
1950                     self.pg0.sw_if_index,
1951                     self.pg0.remote_hosts[200].mac,
1952                     self.pg0.remote_hosts[200].ip4).add_vpp_config()
1953
1954         # add the first neighbor we configured has been re-used
1955         self.assertFalse(find_nbr(self,
1956                                   self.pg0.sw_if_index,
1957                                   self.pg0.remote_hosts[0].ip4))
1958         self.assertTrue(find_nbr(self,
1959                                  self.pg0.sw_if_index,
1960                                  self.pg0.remote_hosts[200].ip4))
1961
1962         #
1963         # change the config to age old neighbors
1964         #
1965         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1966                                      max_number=200,
1967                                      max_age=2,
1968                                      recycle=True)
1969
1970         self.vapi.cli("sh ip4 neighbor-sorted")
1971
1972         #
1973         # expect probes from all these ARP entries as they age
1974         # 3 probes for each neighbor 3*200 = 600
1975         rxs = self.pg0.get_capture(600, timeout=8)
1976
1977         for ii in range(3):
1978             for jj in range(200):
1979                 rx = rxs[ii*200 + jj]
1980                 # rx.show()
1981
1982         #
1983         # 3 probes sent then 1 more second to see if a reply comes, before
1984         # they age out
1985         #
1986         for jj in range(1, 201):
1987             self.wait_for_no_nbr(self.pg0.sw_if_index,
1988                                  self.pg0.remote_hosts[jj].ip4)
1989
1990         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1991                                                     af=vaf.ADDRESS_IP4))
1992
1993         #
1994         # load up some neighbours again with 2s aging enabled
1995         # they should be removed after 10s (2s age + 4s for probes + gap)
1996         # check for the add and remove events
1997         #
1998         enum = VppEnum.vl_api_ip_neighbor_event_flags_t
1999
2000         self.vapi.want_ip_neighbor_events_v2(enable=1)
2001         for ii in range(10):
2002             VppNeighbor(self,
2003                         self.pg0.sw_if_index,
2004                         self.pg0.remote_hosts[ii].mac,
2005                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2006
2007             e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2008             self.assertEqual(e.flags,
2009                              enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2010             self.assertEqual(str(e.neighbor.ip_address),
2011                              self.pg0.remote_hosts[ii].ip4)
2012             self.assertEqual(e.neighbor.mac_address,
2013                              self.pg0.remote_hosts[ii].mac)
2014
2015         self.sleep(10)
2016         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2017                                                     af=vaf.ADDRESS_IP4))
2018
2019         evs = []
2020         for ii in range(10):
2021             e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2022             self.assertEqual(e.flags,
2023                              enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2024             evs.append(e)
2025
2026         # check we got the correct mac/ip pairs - done separately
2027         # because we don't care about the order the remove notifications
2028         # arrive
2029         for ii in range(10):
2030             found = False
2031             mac = self.pg0.remote_hosts[ii].mac
2032             ip = self.pg0.remote_hosts[ii].ip4
2033
2034             for e in evs:
2035                 if (e.neighbor.mac_address == mac and
2036                    str(e.neighbor.ip_address) == ip):
2037                     found = True
2038                     break
2039             self.assertTrue(found)
2040
2041         #
2042         # check if we can set age and recycle with empty neighbor list
2043         #
2044         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2045                                      max_number=200,
2046                                      max_age=1000,
2047                                      recycle=True)
2048
2049         #
2050         # load up some neighbours again, then disable the aging
2051         # they should still be there in 10 seconds time
2052         #
2053         for ii in range(10):
2054             VppNeighbor(self,
2055                         self.pg0.sw_if_index,
2056                         self.pg0.remote_hosts[ii].mac,
2057                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2058         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2059                                      max_number=200,
2060                                      max_age=0,
2061                                      recycle=False)
2062
2063         self.sleep(10)
2064         self.assertTrue(find_nbr(self,
2065                                  self.pg0.sw_if_index,
2066                                  self.pg0.remote_hosts[0].ip4))
2067
2068
2069 class NeighborReplaceTestCase(VppTestCase):
2070     """ ARP/ND Replacement """
2071
2072     @classmethod
2073     def setUpClass(cls):
2074         super(NeighborReplaceTestCase, cls).setUpClass()
2075
2076     @classmethod
2077     def tearDownClass(cls):
2078         super(NeighborReplaceTestCase, cls).tearDownClass()
2079
2080     def setUp(self):
2081         super(NeighborReplaceTestCase, self).setUp()
2082
2083         self.create_pg_interfaces(range(4))
2084
2085         # pg0 configured with ip4 and 6 addresses used for input
2086         # pg1 configured with ip4 and 6 addresses used for output
2087         # pg2 is unnumbered to pg0
2088         for i in self.pg_interfaces:
2089             i.admin_up()
2090             i.config_ip4()
2091             i.config_ip6()
2092             i.resolve_arp()
2093             i.resolve_ndp()
2094
2095     def tearDown(self):
2096         super(NeighborReplaceTestCase, self).tearDown()
2097
2098         for i in self.pg_interfaces:
2099             i.unconfig_ip4()
2100             i.unconfig_ip6()
2101             i.admin_down()
2102
2103     def test_replace(self):
2104         """ replace """
2105
2106         N_HOSTS = 16
2107
2108         for i in self.pg_interfaces:
2109             i.generate_remote_hosts(N_HOSTS)
2110             i.configure_ipv4_neighbors()
2111             i.configure_ipv6_neighbors()
2112
2113         # replace them all
2114         self.vapi.ip_neighbor_replace_begin()
2115         self.vapi.ip_neighbor_replace_end()
2116
2117         for i in self.pg_interfaces:
2118             for h in range(N_HOSTS):
2119                 self.assertFalse(find_nbr(self,
2120                                           self.pg0.sw_if_index,
2121                                           self.pg0.remote_hosts[h].ip4))
2122                 self.assertFalse(find_nbr(self,
2123                                           self.pg0.sw_if_index,
2124                                           self.pg0.remote_hosts[h].ip6))
2125
2126         #
2127         # and them all back via the API
2128         #
2129         for i in self.pg_interfaces:
2130             for h in range(N_HOSTS):
2131                 VppNeighbor(self,
2132                             i.sw_if_index,
2133                             i.remote_hosts[h].mac,
2134                             i.remote_hosts[h].ip4).add_vpp_config()
2135                 VppNeighbor(self,
2136                             i.sw_if_index,
2137                             i.remote_hosts[h].mac,
2138                             i.remote_hosts[h].ip6).add_vpp_config()
2139
2140         #
2141         # begin the replacement again, this time touch some
2142         # the neighbours on pg1 so they are not deleted
2143         #
2144         self.vapi.ip_neighbor_replace_begin()
2145
2146         # update from the API all neighbours on pg1
2147         for h in range(N_HOSTS):
2148             VppNeighbor(self,
2149                         self.pg1.sw_if_index,
2150                         self.pg1.remote_hosts[h].mac,
2151                         self.pg1.remote_hosts[h].ip4).add_vpp_config()
2152             VppNeighbor(self,
2153                         self.pg1.sw_if_index,
2154                         self.pg1.remote_hosts[h].mac,
2155                         self.pg1.remote_hosts[h].ip6).add_vpp_config()
2156
2157         # update from the data-plane all neighbours on pg3
2158         self.pg3.configure_ipv4_neighbors()
2159         self.pg3.configure_ipv6_neighbors()
2160
2161         # complete the replacement
2162         self.logger.info(self.vapi.cli("sh ip neighbors"))
2163         self.vapi.ip_neighbor_replace_end()
2164
2165         for i in self.pg_interfaces:
2166             if i == self.pg1 or i == self.pg3:
2167                 # neighbours on pg1 and pg3 are still present
2168                 for h in range(N_HOSTS):
2169                     self.assertTrue(find_nbr(self,
2170                                              i.sw_if_index,
2171                                              i.remote_hosts[h].ip4))
2172                     self.assertTrue(find_nbr(self,
2173                                              i.sw_if_index,
2174                                              i.remote_hosts[h].ip6))
2175             else:
2176                 # all other neighbours are toast
2177                 for h in range(N_HOSTS):
2178                     self.assertFalse(find_nbr(self,
2179                                               i.sw_if_index,
2180                                               i.remote_hosts[h].ip4))
2181                     self.assertFalse(find_nbr(self,
2182                                               i.sw_if_index,
2183                                               i.remote_hosts[h].ip6))
2184
2185
2186 class NeighborFlush(VppTestCase):
2187     """ Neighbor Flush """
2188
2189     @classmethod
2190     def setUpClass(cls):
2191         super(NeighborFlush, cls).setUpClass()
2192
2193     @classmethod
2194     def tearDownClass(cls):
2195         super(NeighborFlush, cls).tearDownClass()
2196
2197     def setUp(self):
2198         super(NeighborFlush, self).setUp()
2199
2200         self.create_pg_interfaces(range(2))
2201
2202         for i in self.pg_interfaces:
2203             i.admin_up()
2204             i.config_ip4()
2205             i.config_ip6()
2206             i.resolve_arp()
2207             i.resolve_ndp()
2208
2209     def tearDown(self):
2210         super(NeighborFlush, self).tearDown()
2211
2212         for i in self.pg_interfaces:
2213             i.unconfig_ip4()
2214             i.unconfig_ip6()
2215             i.admin_down()
2216
2217     def test_flush(self):
2218         """ Neighbour Flush """
2219
2220         e = VppEnum
2221         nf = e.vl_api_ip_neighbor_flags_t
2222         af = e.vl_api_address_family_t
2223         N_HOSTS = 16
2224         static = [False, True]
2225         self.pg0.generate_remote_hosts(N_HOSTS)
2226         self.pg1.generate_remote_hosts(N_HOSTS)
2227
2228         for s in static:
2229             # a few v4 and v6 dynamic neoghbors
2230             for n in range(N_HOSTS):
2231                 VppNeighbor(self,
2232                             self.pg0.sw_if_index,
2233                             self.pg0.remote_hosts[n].mac,
2234                             self.pg0.remote_hosts[n].ip4,
2235                             is_static=s).add_vpp_config()
2236                 VppNeighbor(self,
2237                             self.pg1.sw_if_index,
2238                             self.pg1.remote_hosts[n].mac,
2239                             self.pg1.remote_hosts[n].ip6,
2240                             is_static=s).add_vpp_config()
2241
2242             # flush the interfaces individually
2243             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2244
2245             # check we haven't flushed that which we shouldn't
2246             for n in range(N_HOSTS):
2247                 self.assertTrue(find_nbr(self,
2248                                          self.pg1.sw_if_index,
2249                                          self.pg1.remote_hosts[n].ip6,
2250                                          is_static=s))
2251
2252             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2253
2254             for n in range(N_HOSTS):
2255                 self.assertFalse(find_nbr(self,
2256                                           self.pg0.sw_if_index,
2257                                           self.pg0.remote_hosts[n].ip4))
2258                 self.assertFalse(find_nbr(self,
2259                                           self.pg1.sw_if_index,
2260                                           self.pg1.remote_hosts[n].ip6))
2261
2262             # add the nieghbours back
2263             for n in range(N_HOSTS):
2264                 VppNeighbor(self,
2265                             self.pg0.sw_if_index,
2266                             self.pg0.remote_hosts[n].mac,
2267                             self.pg0.remote_hosts[n].ip4,
2268                             is_static=s).add_vpp_config()
2269                 VppNeighbor(self,
2270                             self.pg1.sw_if_index,
2271                             self.pg1.remote_hosts[n].mac,
2272                             self.pg1.remote_hosts[n].ip6,
2273                             is_static=s).add_vpp_config()
2274
2275             self.logger.info(self.vapi.cli("sh ip neighbor"))
2276
2277             # flush both interfaces at the same time
2278             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2279
2280             # check we haven't flushed that which we shouldn't
2281             for n in range(N_HOSTS):
2282                 self.assertTrue(find_nbr(self,
2283                                          self.pg0.sw_if_index,
2284                                          self.pg0.remote_hosts[n].ip4,
2285                                          is_static=s))
2286
2287             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2288
2289             for n in range(N_HOSTS):
2290                 self.assertFalse(find_nbr(self,
2291                                           self.pg0.sw_if_index,
2292                                           self.pg0.remote_hosts[n].ip4))
2293                 self.assertFalse(find_nbr(self,
2294                                           self.pg1.sw_if_index,
2295                                           self.pg1.remote_hosts[n].ip6))
2296
2297
2298 if __name__ == '__main__':
2299     unittest.main(testRunner=VppTestRunner)