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