tests: [re]enable an ARP test form incomplete
[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(self.pg0._local_ip4_subnet,
767                                     self.pg0._local_ip4_bcast)
768
769         # Make pg2 un-numbered to pg0
770         #
771         self.pg2.set_unnumbered(self.pg0.sw_if_index)
772
773         #
774         # Enable pg2 for proxy ARP
775         #
776         self.pg2.set_proxy_arp()
777
778         #
779         # Send the ARP request with an originating address that
780         # is VPP's own address
781         #
782         rx = self.send_and_expect(self.pg2, [arp_req_from_me], self.pg2)
783         self.verify_arp_resp(rx[0],
784                              self.pg2.local_mac,
785                              self.pg2.remote_mac,
786                              self.pg0.remote_hosts[1].ip4,
787                              self.pg0.local_ip4)
788
789         #
790         # validate we have not learned an ARP entry as a result of this
791         #
792         self.assertFalse(find_nbr(self,
793                                   self.pg2.sw_if_index,
794                                   self.pg0.local_ip4))
795
796         #
797         # setup a punt redirect so packets from the uplink go to the tap
798         #
799         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
800                                    self.pg2.sw_if_index,
801                                    self.pg0.local_ip4)
802
803         p_tcp = (Ether(src=self.pg0.remote_mac,
804                        dst=self.pg0.local_mac,) /
805                  IP(src=self.pg0.remote_ip4,
806                     dst=self.pg0.local_ip4) /
807                  TCP(sport=80, dport=80) /
808                  Raw())
809         rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
810
811         # there's no ARP entry so this is an ARP req
812         self.assertTrue(rx[0].haslayer(ARP))
813
814         # and ARP entry for VPP's pg0 address on the host interface
815         n1 = VppNeighbor(self,
816                          self.pg2.sw_if_index,
817                          self.pg2.remote_mac,
818                          self.pg0.local_ip4,
819                          is_no_fib_entry=True).add_vpp_config()
820         # now the packets shold forward
821         rx = self.send_and_expect(self.pg0, [p_tcp], self.pg2)
822         self.assertFalse(rx[0].haslayer(ARP))
823         self.assertEqual(rx[0][Ether].dst, self.pg2.remote_mac)
824
825         #
826         # flush the neighbor cache on the uplink
827         #
828         af = VppEnum.vl_api_address_family_t
829         self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
830
831         # ensure we can still resolve the ARPs on the uplink
832         self.pg0.resolve_arp()
833
834         self.assertTrue(find_nbr(self,
835                                  self.pg0.sw_if_index,
836                                  self.pg0.remote_ip4))
837
838         #
839         # cleanup
840         #
841         self.pg2.set_proxy_arp(0)
842         self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
843                                     self.pg0._local_ip4_bcast,
844                                     is_add=0)
845
846     def test_proxy_arp(self):
847         """ Proxy ARP """
848
849         self.pg1.generate_remote_hosts(2)
850
851         #
852         # Proxy ARP request packets for each interface
853         #
854         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
855                              dst="ff:ff:ff:ff:ff:ff") /
856                        ARP(op="who-has",
857                            hwsrc=self.pg0.remote_mac,
858                            pdst="10.10.10.3",
859                            psrc=self.pg0.remote_ip4))
860         arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
861                                     dst="ff:ff:ff:ff:ff:ff") /
862                               Dot1Q(vlan=0) /
863                               ARP(op="who-has",
864                                   hwsrc=self.pg0.remote_mac,
865                                   pdst="10.10.10.3",
866                                   psrc=self.pg0.remote_ip4))
867         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
868                              dst="ff:ff:ff:ff:ff:ff") /
869                        ARP(op="who-has",
870                            hwsrc=self.pg1.remote_mac,
871                            pdst="10.10.10.3",
872                            psrc=self.pg1.remote_ip4))
873         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
874                              dst="ff:ff:ff:ff:ff:ff") /
875                        ARP(op="who-has",
876                            hwsrc=self.pg2.remote_mac,
877                            pdst="10.10.10.3",
878                            psrc=self.pg1.remote_hosts[1].ip4))
879         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
880                              dst="ff:ff:ff:ff:ff:ff") /
881                        ARP(op="who-has",
882                            hwsrc=self.pg3.remote_mac,
883                            pdst="10.10.10.3",
884                            psrc=self.pg3.remote_ip4))
885
886         #
887         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
888         #
889         self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
890                                     inet_pton(AF_INET, "10.10.10.124"))
891
892         #
893         # No responses are sent when the interfaces are not enabled for proxy
894         # ARP
895         #
896         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
897                                         "ARP req from unconfigured interface")
898         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
899                                         "ARP req from unconfigured interface")
900
901         #
902         # Make pg2 un-numbered to pg1
903         #  still won't reply.
904         #
905         self.pg2.set_unnumbered(self.pg1.sw_if_index)
906
907         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
908                                         "ARP req from unnumbered interface")
909
910         #
911         # Enable each interface to reply to proxy ARPs
912         #
913         for i in self.pg_interfaces:
914             i.set_proxy_arp()
915
916         #
917         # Now each of the interfaces should reply to a request to a proxied
918         # address
919         #
920         self.pg0.add_stream(arp_req_pg0)
921         self.pg_enable_capture(self.pg_interfaces)
922         self.pg_start()
923
924         rx = self.pg0.get_capture(1)
925         self.verify_arp_resp(rx[0],
926                              self.pg0.local_mac,
927                              self.pg0.remote_mac,
928                              "10.10.10.3",
929                              self.pg0.remote_ip4)
930
931         self.pg0.add_stream(arp_req_pg0_tagged)
932         self.pg_enable_capture(self.pg_interfaces)
933         self.pg_start()
934
935         rx = self.pg0.get_capture(1)
936         self.verify_arp_resp(rx[0],
937                              self.pg0.local_mac,
938                              self.pg0.remote_mac,
939                              "10.10.10.3",
940                              self.pg0.remote_ip4)
941
942         self.pg1.add_stream(arp_req_pg1)
943         self.pg_enable_capture(self.pg_interfaces)
944         self.pg_start()
945
946         rx = self.pg1.get_capture(1)
947         self.verify_arp_resp(rx[0],
948                              self.pg1.local_mac,
949                              self.pg1.remote_mac,
950                              "10.10.10.3",
951                              self.pg1.remote_ip4)
952
953         self.pg2.add_stream(arp_req_pg2)
954         self.pg_enable_capture(self.pg_interfaces)
955         self.pg_start()
956
957         rx = self.pg2.get_capture(1)
958         self.verify_arp_resp(rx[0],
959                              self.pg2.local_mac,
960                              self.pg2.remote_mac,
961                              "10.10.10.3",
962                              self.pg1.remote_hosts[1].ip4)
963
964         #
965         # A request for an address out of the configured range
966         #
967         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
968                                 dst="ff:ff:ff:ff:ff:ff") /
969                           ARP(op="who-has",
970                               hwsrc=self.pg1.remote_mac,
971                               pdst="10.10.10.125",
972                               psrc=self.pg1.remote_ip4))
973         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
974                                         "ARP req out of range HI")
975         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
976                                  dst="ff:ff:ff:ff:ff:ff") /
977                            ARP(op="who-has",
978                                hwsrc=self.pg1.remote_mac,
979                                pdst="10.10.10.1",
980                                psrc=self.pg1.remote_ip4))
981         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
982                                         "ARP req out of range Low")
983
984         #
985         # Request for an address in the proxy range but from an interface
986         # in a different VRF
987         #
988         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
989                                         "ARP req from different VRF")
990
991         #
992         # Disable Each interface for proxy ARP
993         #  - expect none to respond
994         #
995         for i in self.pg_interfaces:
996             i.set_proxy_arp(0)
997
998         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
999                                         "ARP req from disable")
1000         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
1001                                         "ARP req from disable")
1002         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
1003                                         "ARP req from disable")
1004
1005         #
1006         # clean up on interface 2
1007         #
1008         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
1009
1010     def test_mpls(self):
1011         """ MPLS """
1012
1013         #
1014         # Interface 2 does not yet have ip4 config
1015         #
1016         self.pg2.config_ip4()
1017         self.pg2.generate_remote_hosts(2)
1018
1019         #
1020         # Add a route with out going label via an ARP unresolved next-hop
1021         #
1022         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1023                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
1024                                                self.pg2.sw_if_index,
1025                                                labels=[55])])
1026         ip_10_0_0_1.add_vpp_config()
1027
1028         #
1029         # packets should generate an ARP request
1030         #
1031         p = (Ether(src=self.pg0.remote_mac,
1032                    dst=self.pg0.local_mac) /
1033              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
1034              UDP(sport=1234, dport=1234) /
1035              Raw(b'\xa5' * 100))
1036
1037         self.pg0.add_stream(p)
1038         self.pg_enable_capture(self.pg_interfaces)
1039         self.pg_start()
1040
1041         rx = self.pg2.get_capture(1)
1042         self.verify_arp_req(rx[0],
1043                             self.pg2.local_mac,
1044                             self.pg2.local_ip4,
1045                             self.pg2._remote_hosts[1].ip4)
1046
1047         #
1048         # now resolve the neighbours
1049         #
1050         self.pg2.configure_ipv4_neighbors()
1051
1052         #
1053         # Now packet should be properly MPLS encapped.
1054         #  This verifies that MPLS link-type adjacencies are completed
1055         #  when the ARP entry resolves
1056         #
1057         self.pg0.add_stream(p)
1058         self.pg_enable_capture(self.pg_interfaces)
1059         self.pg_start()
1060
1061         rx = self.pg2.get_capture(1)
1062         self.verify_ip_o_mpls(rx[0],
1063                               self.pg2.local_mac,
1064                               self.pg2.remote_hosts[1].mac,
1065                               55,
1066                               self.pg0.remote_ip4,
1067                               "10.0.0.1")
1068         self.pg2.unconfig_ip4()
1069
1070     def test_arp_vrrp(self):
1071         """ ARP reply with VRRP virtual src hw addr """
1072
1073         #
1074         # IP packet destined for pg1 remote host arrives on pg0 resulting
1075         # in an ARP request for the address of the remote host on pg1
1076         #
1077         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1078               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1079               UDP(sport=1234, dport=1234) /
1080               Raw())
1081
1082         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1083
1084         self.verify_arp_req(rx1[0],
1085                             self.pg1.local_mac,
1086                             self.pg1.local_ip4,
1087                             self.pg1.remote_ip4)
1088
1089         #
1090         # ARP reply for address of pg1 remote host arrives on pg1 with
1091         # the hw src addr set to a value in the VRRP IPv4 range of
1092         # MAC addresses
1093         #
1094         p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1095               ARP(op="is-at", hwdst=self.pg1.local_mac,
1096                   hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1097                   psrc=self.pg1.remote_ip4))
1098
1099         self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1100
1101         #
1102         # IP packet destined for pg1 remote host arrives on pg0 again.
1103         # VPP should have an ARP entry for that address now and the packet
1104         # should be sent out pg1.
1105         #
1106         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1107
1108         self.verify_ip(rx1[0],
1109                        self.pg1.local_mac,
1110                        "00:00:5e:00:01:09",
1111                        self.pg0.remote_ip4,
1112                        self.pg1.remote_ip4)
1113
1114         self.pg1.admin_down()
1115         self.pg1.admin_up()
1116
1117     def test_arp_duplicates(self):
1118         """ ARP Duplicates"""
1119
1120         #
1121         # Generate some hosts on the LAN
1122         #
1123         self.pg1.generate_remote_hosts(3)
1124
1125         #
1126         # Add host 1 on pg1 and pg2
1127         #
1128         arp_pg1 = VppNeighbor(self,
1129                               self.pg1.sw_if_index,
1130                               self.pg1.remote_hosts[1].mac,
1131                               self.pg1.remote_hosts[1].ip4)
1132         arp_pg1.add_vpp_config()
1133         arp_pg2 = VppNeighbor(self,
1134                               self.pg2.sw_if_index,
1135                               self.pg2.remote_mac,
1136                               self.pg1.remote_hosts[1].ip4)
1137         arp_pg2.add_vpp_config()
1138
1139         #
1140         # IP packet destined for pg1 remote host arrives on pg1 again.
1141         #
1142         p = (Ether(dst=self.pg0.local_mac,
1143                    src=self.pg0.remote_mac) /
1144              IP(src=self.pg0.remote_ip4,
1145                 dst=self.pg1.remote_hosts[1].ip4) /
1146              UDP(sport=1234, dport=1234) /
1147              Raw())
1148
1149         self.pg0.add_stream(p)
1150         self.pg_enable_capture(self.pg_interfaces)
1151         self.pg_start()
1152
1153         rx1 = self.pg1.get_capture(1)
1154
1155         self.verify_ip(rx1[0],
1156                        self.pg1.local_mac,
1157                        self.pg1.remote_hosts[1].mac,
1158                        self.pg0.remote_ip4,
1159                        self.pg1.remote_hosts[1].ip4)
1160
1161         #
1162         # remove the duplicate on pg1
1163         # packet stream should generate ARPs out of pg1
1164         #
1165         arp_pg1.remove_vpp_config()
1166
1167         self.pg0.add_stream(p)
1168         self.pg_enable_capture(self.pg_interfaces)
1169         self.pg_start()
1170
1171         rx1 = self.pg1.get_capture(1)
1172
1173         self.verify_arp_req(rx1[0],
1174                             self.pg1.local_mac,
1175                             self.pg1.local_ip4,
1176                             self.pg1.remote_hosts[1].ip4)
1177
1178         #
1179         # Add it back
1180         #
1181         arp_pg1.add_vpp_config()
1182
1183         self.pg0.add_stream(p)
1184         self.pg_enable_capture(self.pg_interfaces)
1185         self.pg_start()
1186
1187         rx1 = self.pg1.get_capture(1)
1188
1189         self.verify_ip(rx1[0],
1190                        self.pg1.local_mac,
1191                        self.pg1.remote_hosts[1].mac,
1192                        self.pg0.remote_ip4,
1193                        self.pg1.remote_hosts[1].ip4)
1194
1195     def test_arp_static(self):
1196         """ ARP Static"""
1197         self.pg2.generate_remote_hosts(3)
1198
1199         #
1200         # Add a static ARP entry
1201         #
1202         static_arp = VppNeighbor(self,
1203                                  self.pg2.sw_if_index,
1204                                  self.pg2.remote_hosts[1].mac,
1205                                  self.pg2.remote_hosts[1].ip4,
1206                                  is_static=1)
1207         static_arp.add_vpp_config()
1208
1209         #
1210         # Add the connected prefix to the interface
1211         #
1212         self.pg2.config_ip4()
1213
1214         #
1215         # We should now find the adj-fib
1216         #
1217         self.assertTrue(find_nbr(self,
1218                                  self.pg2.sw_if_index,
1219                                  self.pg2.remote_hosts[1].ip4,
1220                                  is_static=1))
1221         self.assertTrue(find_route(self,
1222                                    self.pg2.remote_hosts[1].ip4,
1223                                    32))
1224
1225         #
1226         # remove the connected
1227         #
1228         self.pg2.unconfig_ip4()
1229
1230         #
1231         # put the interface into table 1
1232         #
1233         self.pg2.set_table_ip4(1)
1234
1235         #
1236         # configure the same connected and expect to find the
1237         # adj fib in the new table
1238         #
1239         self.pg2.config_ip4()
1240         self.assertTrue(find_route(self,
1241                                    self.pg2.remote_hosts[1].ip4,
1242                                    32,
1243                                    table_id=1))
1244
1245         #
1246         # clean-up
1247         #
1248         self.pg2.unconfig_ip4()
1249         static_arp.remove_vpp_config()
1250         self.pg2.set_table_ip4(0)
1251
1252     def test_arp_static_replace_dynamic_same_mac(self):
1253         """ ARP Static can replace Dynamic (same mac) """
1254         self.pg2.generate_remote_hosts(1)
1255
1256         dyn_arp = VppNeighbor(self,
1257                               self.pg2.sw_if_index,
1258                               self.pg2.remote_hosts[0].mac,
1259                               self.pg2.remote_hosts[0].ip4)
1260         static_arp = VppNeighbor(self,
1261                                  self.pg2.sw_if_index,
1262                                  self.pg2.remote_hosts[0].mac,
1263                                  self.pg2.remote_hosts[0].ip4,
1264                                  is_static=1)
1265
1266         #
1267         # Add a dynamic ARP entry
1268         #
1269         dyn_arp.add_vpp_config()
1270
1271         #
1272         # We should find the dynamic nbr
1273         #
1274         self.assertFalse(find_nbr(self,
1275                                   self.pg2.sw_if_index,
1276                                   self.pg2.remote_hosts[0].ip4,
1277                                   is_static=1))
1278         self.assertTrue(find_nbr(self,
1279                                  self.pg2.sw_if_index,
1280                                  self.pg2.remote_hosts[0].ip4,
1281                                  is_static=0,
1282                                  mac=self.pg2.remote_hosts[0].mac))
1283
1284         #
1285         # Add a static ARP entry with the same mac
1286         #
1287         static_arp.add_vpp_config()
1288
1289         #
1290         # We should now find the static nbr with the same mac
1291         #
1292         self.assertFalse(find_nbr(self,
1293                                   self.pg2.sw_if_index,
1294                                   self.pg2.remote_hosts[0].ip4,
1295                                   is_static=0))
1296         self.assertTrue(find_nbr(self,
1297                                  self.pg2.sw_if_index,
1298                                  self.pg2.remote_hosts[0].ip4,
1299                                  is_static=1,
1300                                  mac=self.pg2.remote_hosts[0].mac))
1301
1302         #
1303         # clean-up
1304         #
1305         static_arp.remove_vpp_config()
1306
1307     def test_arp_static_replace_dynamic_diff_mac(self):
1308         """ ARP Static can replace Dynamic (diff mac) """
1309         self.pg2.generate_remote_hosts(2)
1310
1311         dyn_arp = VppNeighbor(self,
1312                               self.pg2.sw_if_index,
1313                               self.pg2.remote_hosts[0].mac,
1314                               self.pg2.remote_hosts[0].ip4)
1315         static_arp = VppNeighbor(self,
1316                                  self.pg2.sw_if_index,
1317                                  self.pg2.remote_hosts[1].mac,
1318                                  self.pg2.remote_hosts[0].ip4,
1319                                  is_static=1)
1320
1321         #
1322         # Add a dynamic ARP entry
1323         #
1324         dyn_arp.add_vpp_config()
1325
1326         #
1327         # We should find the dynamic nbr
1328         #
1329         self.assertFalse(find_nbr(self,
1330                                   self.pg2.sw_if_index,
1331                                   self.pg2.remote_hosts[0].ip4,
1332                                   is_static=1))
1333         self.assertTrue(find_nbr(self,
1334                                  self.pg2.sw_if_index,
1335                                  self.pg2.remote_hosts[0].ip4,
1336                                  is_static=0,
1337                                  mac=self.pg2.remote_hosts[0].mac))
1338
1339         #
1340         # Add a static ARP entry with a changed mac
1341         #
1342         static_arp.add_vpp_config()
1343
1344         #
1345         # We should now find the static nbr with a changed mac
1346         #
1347         self.assertFalse(find_nbr(self,
1348                                   self.pg2.sw_if_index,
1349                                   self.pg2.remote_hosts[0].ip4,
1350                                   is_static=0))
1351         self.assertTrue(find_nbr(self,
1352                                  self.pg2.sw_if_index,
1353                                  self.pg2.remote_hosts[0].ip4,
1354                                  is_static=1,
1355                                  mac=self.pg2.remote_hosts[1].mac))
1356
1357         #
1358         # clean-up
1359         #
1360         static_arp.remove_vpp_config()
1361
1362     def test_arp_incomplete(self):
1363         """ ARP Incomplete"""
1364         self.pg1.generate_remote_hosts(3)
1365
1366         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1367               IP(src=self.pg0.remote_ip4,
1368                  dst=self.pg1.remote_hosts[1].ip4) /
1369               UDP(sport=1234, dport=1234) /
1370               Raw())
1371         p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1372               IP(src=self.pg0.remote_ip4,
1373                  dst=self.pg1.remote_hosts[2].ip4) /
1374               UDP(sport=1234, dport=1234) /
1375               Raw())
1376
1377         #
1378         # a packet to an unresolved destination generates an ARP request
1379         #
1380         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1381         self.verify_arp_req(rx[0],
1382                             self.pg1.local_mac,
1383                             self.pg1.local_ip4,
1384                             self.pg1._remote_hosts[1].ip4)
1385
1386         #
1387         # add a neighbour for remote host 1
1388         #
1389         static_arp = VppNeighbor(self,
1390                                  self.pg1.sw_if_index,
1391                                  self.pg1.remote_hosts[1].mac,
1392                                  self.pg1.remote_hosts[1].ip4,
1393                                  is_static=1)
1394         static_arp.add_vpp_config()
1395
1396         #
1397         # change the interface's MAC
1398         #
1399         self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1400                                                "00:00:00:33:33:33")
1401
1402         #
1403         # now ARP requests come from the new source mac
1404         #
1405         rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1406         self.verify_arp_req(rx[0],
1407                             "00:00:00:33:33:33",
1408                             self.pg1.local_ip4,
1409                             self.pg1._remote_hosts[2].ip4)
1410
1411         #
1412         # packets to the resolved host also have the new source mac
1413         #
1414         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1415         self.verify_ip(rx[0],
1416                        "00:00:00:33:33:33",
1417                        self.pg1.remote_hosts[1].mac,
1418                        self.pg0.remote_ip4,
1419                        self.pg1.remote_hosts[1].ip4)
1420
1421         #
1422         # set the mac address on the interface that does not have a
1423         # configured subnet and thus no glean
1424         #
1425         self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1426                                                "00:00:00:33:33:33")
1427
1428     def test_garp(self):
1429         """ GARP """
1430
1431         #
1432         # Generate some hosts on the LAN
1433         #
1434         self.pg1.generate_remote_hosts(4)
1435         self.pg2.generate_remote_hosts(4)
1436
1437         #
1438         # And an ARP entry
1439         #
1440         arp = VppNeighbor(self,
1441                           self.pg1.sw_if_index,
1442                           self.pg1.remote_hosts[1].mac,
1443                           self.pg1.remote_hosts[1].ip4)
1444         arp.add_vpp_config()
1445
1446         self.assertTrue(find_nbr(self,
1447                                  self.pg1.sw_if_index,
1448                                  self.pg1.remote_hosts[1].ip4,
1449                                  mac=self.pg1.remote_hosts[1].mac))
1450
1451         #
1452         # Send a GARP (request) to swap the host 1's address to that of host 2
1453         #
1454         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1455                     src=self.pg1.remote_hosts[2].mac) /
1456               ARP(op="who-has",
1457                   hwdst=self.pg1.local_mac,
1458                   hwsrc=self.pg1.remote_hosts[2].mac,
1459                   pdst=self.pg1.remote_hosts[1].ip4,
1460                   psrc=self.pg1.remote_hosts[1].ip4))
1461
1462         self.pg1.add_stream(p1)
1463         self.pg_enable_capture(self.pg_interfaces)
1464         self.pg_start()
1465
1466         self.assertTrue(find_nbr(self,
1467                                  self.pg1.sw_if_index,
1468                                  self.pg1.remote_hosts[1].ip4,
1469                                  mac=self.pg1.remote_hosts[2].mac))
1470
1471         #
1472         # Send a GARP (reply) to swap the host 1's address to that of host 3
1473         #
1474         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1475                     src=self.pg1.remote_hosts[3].mac) /
1476               ARP(op="is-at",
1477                   hwdst=self.pg1.local_mac,
1478                   hwsrc=self.pg1.remote_hosts[3].mac,
1479                   pdst=self.pg1.remote_hosts[1].ip4,
1480                   psrc=self.pg1.remote_hosts[1].ip4))
1481
1482         self.pg1.add_stream(p1)
1483         self.pg_enable_capture(self.pg_interfaces)
1484         self.pg_start()
1485
1486         self.assertTrue(find_nbr(self,
1487                                  self.pg1.sw_if_index,
1488                                  self.pg1.remote_hosts[1].ip4,
1489                                  mac=self.pg1.remote_hosts[3].mac))
1490
1491         #
1492         # GARPs (request nor replies) for host we don't know yet
1493         # don't result in new neighbour entries
1494         #
1495         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1496                     src=self.pg1.remote_hosts[3].mac) /
1497               ARP(op="who-has",
1498                   hwdst=self.pg1.local_mac,
1499                   hwsrc=self.pg1.remote_hosts[3].mac,
1500                   pdst=self.pg1.remote_hosts[2].ip4,
1501                   psrc=self.pg1.remote_hosts[2].ip4))
1502
1503         self.pg1.add_stream(p1)
1504         self.pg_enable_capture(self.pg_interfaces)
1505         self.pg_start()
1506
1507         self.assertFalse(find_nbr(self,
1508                                   self.pg1.sw_if_index,
1509                                   self.pg1.remote_hosts[2].ip4))
1510
1511         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1512                     src=self.pg1.remote_hosts[3].mac) /
1513               ARP(op="is-at",
1514                   hwdst=self.pg1.local_mac,
1515                   hwsrc=self.pg1.remote_hosts[3].mac,
1516                   pdst=self.pg1.remote_hosts[2].ip4,
1517                   psrc=self.pg1.remote_hosts[2].ip4))
1518
1519         self.pg1.add_stream(p1)
1520         self.pg_enable_capture(self.pg_interfaces)
1521         self.pg_start()
1522
1523         self.assertFalse(find_nbr(self,
1524                                   self.pg1.sw_if_index,
1525                                   self.pg1.remote_hosts[2].ip4))
1526
1527         #
1528         # IP address in different subnets are not learnt
1529         #
1530         self.pg2.configure_ipv4_neighbors()
1531
1532         for op in ["is-at", "who-has"]:
1533             p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1534                          src=self.pg2.remote_hosts[1].mac) /
1535                    ARP(op=op,
1536                        hwdst=self.pg2.local_mac,
1537                        hwsrc=self.pg2.remote_hosts[1].mac,
1538                        pdst=self.pg2.remote_hosts[1].ip4,
1539                        psrc=self.pg2.remote_hosts[1].ip4)),
1540                   (Ether(dst="ff:ff:ff:ff:ff:ff",
1541                          src=self.pg2.remote_hosts[1].mac) /
1542                    ARP(op=op,
1543                        hwdst="ff:ff:ff:ff:ff:ff",
1544                        hwsrc=self.pg2.remote_hosts[1].mac,
1545                        pdst=self.pg2.remote_hosts[1].ip4,
1546                        psrc=self.pg2.remote_hosts[1].ip4))]
1547
1548             self.send_and_assert_no_replies(self.pg1, p1)
1549             self.assertFalse(find_nbr(self,
1550                                       self.pg1.sw_if_index,
1551                                       self.pg2.remote_hosts[1].ip4))
1552
1553         # they are all dropped because the subnet's don't match
1554         self.assertEqual(4, self.statistics.get_err_counter(
1555             "/err/arp-reply/IP4 destination address not local to subnet"))
1556
1557     def test_arp_incomplete2(self):
1558         """ Incomplete Entries """
1559
1560         #
1561         # ensure that we throttle the ARP and ND requests
1562         #
1563         self.pg0.generate_remote_hosts(2)
1564
1565         #
1566         # IPv4/ARP
1567         #
1568         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1569                                  [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1570                                                self.pg0.sw_if_index)])
1571         ip_10_0_0_1.add_vpp_config()
1572
1573         p1 = (Ether(dst=self.pg1.local_mac,
1574                     src=self.pg1.remote_mac) /
1575               IP(src=self.pg1.remote_ip4,
1576                  dst="10.0.0.1") /
1577               UDP(sport=1234, dport=1234) /
1578               Raw())
1579
1580         self.pg1.add_stream(p1 * 257)
1581         self.pg_enable_capture(self.pg_interfaces)
1582         self.pg_start()
1583         rx = self.pg0._get_capture(1)
1584
1585         #
1586         # how many we get is going to be dependent on the time for packet
1587         # processing but it should be small
1588         #
1589         self.assertLess(len(rx), 64)
1590
1591         #
1592         # IPv6/ND
1593         #
1594         ip_10_1 = VppIpRoute(self, "10::1", 128,
1595                              [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1596                                            self.pg0.sw_if_index,
1597                                            proto=DpoProto.DPO_PROTO_IP6)])
1598         ip_10_1.add_vpp_config()
1599
1600         p1 = (Ether(dst=self.pg1.local_mac,
1601                     src=self.pg1.remote_mac) /
1602               IPv6(src=self.pg1.remote_ip6,
1603                    dst="10::1") /
1604               UDP(sport=1234, dport=1234) /
1605               Raw())
1606
1607         self.pg1.add_stream(p1 * 257)
1608         self.pg_enable_capture(self.pg_interfaces)
1609         self.pg_start()
1610         rx = self.pg0._get_capture(1)
1611
1612         #
1613         # how many we get is going to be dependent on the time for packet
1614         # processing but it should be small
1615         #
1616         self.assertLess(len(rx), 64)
1617
1618     def test_arp_forus(self):
1619         """ ARP for for-us """
1620
1621         #
1622         # Test that VPP responds with ARP requests to addresses that
1623         # are connected and local routes.
1624         # Use one of the 'remote' addresses in the subnet as a local address
1625         # The intention of this route is that it then acts like a secondary
1626         # address added to an interface
1627         #
1628         self.pg0.generate_remote_hosts(2)
1629
1630         forus = VppIpRoute(
1631             self, self.pg0.remote_hosts[1].ip4, 32,
1632             [VppRoutePath("0.0.0.0",
1633                           self.pg0.sw_if_index,
1634                           type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1635         forus.add_vpp_config()
1636
1637         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1638                    src=self.pg0.remote_mac) /
1639              ARP(op="who-has",
1640                  hwdst=self.pg0.local_mac,
1641                  hwsrc=self.pg0.remote_mac,
1642                  pdst=self.pg0.remote_hosts[1].ip4,
1643                  psrc=self.pg0.remote_ip4))
1644
1645         rx = self.send_and_expect(self.pg0, [p], self.pg0)
1646
1647         self.verify_arp_resp(rx[0],
1648                              self.pg0.local_mac,
1649                              self.pg0.remote_mac,
1650                              self.pg0.remote_hosts[1].ip4,
1651                              self.pg0.remote_ip4)
1652
1653     def test_arp_table_swap(self):
1654         #
1655         # Generate some hosts on the LAN
1656         #
1657         N_NBRS = 4
1658         self.pg1.generate_remote_hosts(N_NBRS)
1659
1660         for n in range(N_NBRS):
1661             # a route thru each neighbour
1662             VppIpRoute(self, "10.0.0.%d" % n, 32,
1663                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1664                                      self.pg1.sw_if_index)]).add_vpp_config()
1665
1666             # resolve each neighbour
1667             p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1668                   ARP(op="is-at", hwdst=self.pg1.local_mac,
1669                       hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1670                       psrc=self.pg1.remote_hosts[n].ip4))
1671
1672             self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1673
1674         self.logger.info(self.vapi.cli("sh ip neighbors"))
1675
1676         #
1677         # swap the table pg1 is in
1678         #
1679         table = VppIpTable(self, 100).add_vpp_config()
1680
1681         self.pg1.unconfig_ip4()
1682         self.pg1.set_table_ip4(100)
1683         self.pg1.config_ip4()
1684
1685         #
1686         # all neighbours are cleared
1687         #
1688         for n in range(N_NBRS):
1689             self.assertFalse(find_nbr(self,
1690                                       self.pg1.sw_if_index,
1691                                       self.pg1.remote_hosts[n].ip4))
1692
1693         #
1694         # packets to all neighbours generate ARP requests
1695         #
1696         for n in range(N_NBRS):
1697             # a route thru each neighbour
1698             VppIpRoute(self, "10.0.0.%d" % n, 32,
1699                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1700                                      self.pg1.sw_if_index)],
1701                        table_id=100).add_vpp_config()
1702
1703             p = (Ether(src=self.pg1.remote_hosts[n].mac,
1704                        dst=self.pg1.local_mac) /
1705                  IP(src=self.pg1.remote_hosts[n].ip4,
1706                     dst="10.0.0.%d" % n) /
1707                  Raw(b'0x5' * 100))
1708             rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1709             for rx in rxs:
1710                 self.verify_arp_req(rx,
1711                                     self.pg1.local_mac,
1712                                     self.pg1.local_ip4,
1713                                     self.pg1.remote_hosts[n].ip4)
1714
1715         self.pg1.unconfig_ip4()
1716         self.pg1.set_table_ip4(0)
1717
1718
1719 class NeighborStatsTestCase(VppTestCase):
1720     """ ARP/ND Counters """
1721
1722     @classmethod
1723     def setUpClass(cls):
1724         super(NeighborStatsTestCase, cls).setUpClass()
1725
1726     @classmethod
1727     def tearDownClass(cls):
1728         super(NeighborStatsTestCase, cls).tearDownClass()
1729
1730     def setUp(self):
1731         super(NeighborStatsTestCase, self).setUp()
1732
1733         self.create_pg_interfaces(range(2))
1734
1735         # pg0 configured with ip4 and 6 addresses used for input
1736         # pg1 configured with ip4 and 6 addresses used for output
1737         # pg2 is unnumbered to pg0
1738         for i in self.pg_interfaces:
1739             i.admin_up()
1740             i.config_ip4()
1741             i.config_ip6()
1742             i.resolve_arp()
1743             i.resolve_ndp()
1744
1745     def tearDown(self):
1746         super(NeighborStatsTestCase, self).tearDown()
1747
1748         for i in self.pg_interfaces:
1749             i.unconfig_ip4()
1750             i.unconfig_ip6()
1751             i.admin_down()
1752
1753     def test_arp_stats(self):
1754         """ ARP Counters """
1755
1756         self.vapi.cli("adj counters enable")
1757         self.pg1.generate_remote_hosts(2)
1758
1759         arp1 = VppNeighbor(self,
1760                            self.pg1.sw_if_index,
1761                            self.pg1.remote_hosts[0].mac,
1762                            self.pg1.remote_hosts[0].ip4)
1763         arp1.add_vpp_config()
1764         arp2 = VppNeighbor(self,
1765                            self.pg1.sw_if_index,
1766                            self.pg1.remote_hosts[1].mac,
1767                            self.pg1.remote_hosts[1].ip4)
1768         arp2.add_vpp_config()
1769
1770         p1 = (Ether(dst=self.pg0.local_mac,
1771                     src=self.pg0.remote_mac) /
1772               IP(src=self.pg0.remote_ip4,
1773                  dst=self.pg1.remote_hosts[0].ip4) /
1774               UDP(sport=1234, dport=1234) /
1775               Raw())
1776         p2 = (Ether(dst=self.pg0.local_mac,
1777                     src=self.pg0.remote_mac) /
1778               IP(src=self.pg0.remote_ip4,
1779                  dst=self.pg1.remote_hosts[1].ip4) /
1780               UDP(sport=1234, dport=1234) /
1781               Raw())
1782
1783         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1784         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1785
1786         self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1787         self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1788
1789         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1790         self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1791
1792     def test_nd_stats(self):
1793         """ ND Counters """
1794
1795         self.vapi.cli("adj counters enable")
1796         self.pg0.generate_remote_hosts(3)
1797
1798         nd1 = VppNeighbor(self,
1799                           self.pg0.sw_if_index,
1800                           self.pg0.remote_hosts[1].mac,
1801                           self.pg0.remote_hosts[1].ip6)
1802         nd1.add_vpp_config()
1803         nd2 = VppNeighbor(self,
1804                           self.pg0.sw_if_index,
1805                           self.pg0.remote_hosts[2].mac,
1806                           self.pg0.remote_hosts[2].ip6)
1807         nd2.add_vpp_config()
1808
1809         p1 = (Ether(dst=self.pg1.local_mac,
1810                     src=self.pg1.remote_mac) /
1811               IPv6(src=self.pg1.remote_ip6,
1812                    dst=self.pg0.remote_hosts[1].ip6) /
1813               UDP(sport=1234, dport=1234) /
1814               Raw())
1815         p2 = (Ether(dst=self.pg1.local_mac,
1816                     src=self.pg1.remote_mac) /
1817               IPv6(src=self.pg1.remote_ip6,
1818                    dst=self.pg0.remote_hosts[2].ip6) /
1819               UDP(sport=1234, dport=1234) /
1820               Raw())
1821
1822         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1823         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1824
1825         self.assertEqual(16, nd1.get_stats()['packets'])
1826         self.assertEqual(16, nd2.get_stats()['packets'])
1827
1828         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1829         self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1830
1831
1832 class NeighborAgeTestCase(VppTestCase):
1833     """ ARP/ND Aging """
1834
1835     @classmethod
1836     def setUpClass(cls):
1837         super(NeighborAgeTestCase, cls).setUpClass()
1838
1839     @classmethod
1840     def tearDownClass(cls):
1841         super(NeighborAgeTestCase, cls).tearDownClass()
1842
1843     def setUp(self):
1844         super(NeighborAgeTestCase, self).setUp()
1845
1846         self.create_pg_interfaces(range(1))
1847
1848         # pg0 configured with ip4 and 6 addresses used for input
1849         # pg1 configured with ip4 and 6 addresses used for output
1850         # pg2 is unnumbered to pg0
1851         for i in self.pg_interfaces:
1852             i.admin_up()
1853             i.config_ip4()
1854             i.config_ip6()
1855             i.resolve_arp()
1856             i.resolve_ndp()
1857
1858     def tearDown(self):
1859         super(NeighborAgeTestCase, self).tearDown()
1860
1861         for i in self.pg_interfaces:
1862             i.unconfig_ip4()
1863             i.unconfig_ip6()
1864             i.admin_down()
1865
1866     def wait_for_no_nbr(self, intf, address,
1867                         n_tries=50, s_time=1):
1868         while (n_tries):
1869             if not find_nbr(self, intf, address):
1870                 return True
1871             n_tries = n_tries - 1
1872             self.sleep(s_time)
1873
1874         return False
1875
1876     def verify_arp_req(self, rx, smac, sip, dip):
1877         ether = rx[Ether]
1878         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1879         self.assertEqual(ether.src, smac)
1880
1881         arp = rx[ARP]
1882         self.assertEqual(arp.hwtype, 1)
1883         self.assertEqual(arp.ptype, 0x800)
1884         self.assertEqual(arp.hwlen, 6)
1885         self.assertEqual(arp.plen, 4)
1886         self.assertEqual(arp.op, arp_opts["who-has"])
1887         self.assertEqual(arp.hwsrc, smac)
1888         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1889         self.assertEqual(arp.psrc, sip)
1890         self.assertEqual(arp.pdst, dip)
1891
1892     def test_age(self):
1893         """ Aging/Recycle """
1894
1895         self.vapi.cli("set logging unthrottle 0")
1896         self.vapi.cli("set logging size %d" % 0xffff)
1897
1898         self.pg0.generate_remote_hosts(201)
1899
1900         vaf = VppEnum.vl_api_address_family_t
1901
1902         #
1903         # start listening on all interfaces
1904         #
1905         self.pg_enable_capture(self.pg_interfaces)
1906
1907         #
1908         # Set the neighbor configuration:
1909         #   limi = 200
1910         #   age  = 0 seconds
1911         #   recycle = false
1912         #
1913         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1914                                      max_number=200,
1915                                      max_age=0,
1916                                      recycle=False)
1917
1918         self.vapi.cli("sh ip neighbor-config")
1919
1920         # add the 198 neighbours that should pass (-1 for one created in setup)
1921         for ii in range(200):
1922             VppNeighbor(self,
1923                         self.pg0.sw_if_index,
1924                         self.pg0.remote_hosts[ii].mac,
1925                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1926
1927         # one more neighbor over the limit should fail
1928         with self.vapi.assert_negative_api_retval():
1929             VppNeighbor(self,
1930                         self.pg0.sw_if_index,
1931                         self.pg0.remote_hosts[200].mac,
1932                         self.pg0.remote_hosts[200].ip4).add_vpp_config()
1933
1934         #
1935         # change the config to allow recycling the old neighbors
1936         #
1937         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1938                                      max_number=200,
1939                                      max_age=0,
1940                                      recycle=True)
1941
1942         # now new additions are allowed
1943         VppNeighbor(self,
1944                     self.pg0.sw_if_index,
1945                     self.pg0.remote_hosts[200].mac,
1946                     self.pg0.remote_hosts[200].ip4).add_vpp_config()
1947
1948         # add the first neighbor we configured has been re-used
1949         self.assertFalse(find_nbr(self,
1950                                   self.pg0.sw_if_index,
1951                                   self.pg0.remote_hosts[0].ip4))
1952         self.assertTrue(find_nbr(self,
1953                                  self.pg0.sw_if_index,
1954                                  self.pg0.remote_hosts[200].ip4))
1955
1956         #
1957         # change the config to age old neighbors
1958         #
1959         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1960                                      max_number=200,
1961                                      max_age=2,
1962                                      recycle=True)
1963
1964         self.vapi.cli("sh ip4 neighbor-sorted")
1965
1966         #
1967         # expect probes from all these ARP entries as they age
1968         # 3 probes for each neighbor 3*200 = 600
1969         rxs = self.pg0.get_capture(600, timeout=8)
1970
1971         for ii in range(3):
1972             for jj in range(200):
1973                 rx = rxs[ii*200 + jj]
1974                 # rx.show()
1975
1976         #
1977         # 3 probes sent then 1 more second to see if a reply comes, before
1978         # they age out
1979         #
1980         for jj in range(1, 201):
1981             self.wait_for_no_nbr(self.pg0.sw_if_index,
1982                                  self.pg0.remote_hosts[jj].ip4)
1983
1984         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1985                                                     af=vaf.ADDRESS_IP4))
1986
1987         #
1988         # load up some neighbours again with 2s aging enabled
1989         # they should be removed after 10s (2s age + 4s for probes + gap)
1990         #
1991         for ii in range(10):
1992             VppNeighbor(self,
1993                         self.pg0.sw_if_index,
1994                         self.pg0.remote_hosts[ii].mac,
1995                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1996         self.sleep(10)
1997         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1998                                                     af=vaf.ADDRESS_IP4))
1999
2000         #
2001         # check if we can set age and recycle with empty neighbor list
2002         #
2003         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2004                                      max_number=200,
2005                                      max_age=1000,
2006                                      recycle=True)
2007
2008         #
2009         # load up some neighbours again, then disable the aging
2010         # they should still be there in 10 seconds time
2011         #
2012         for ii in range(10):
2013             VppNeighbor(self,
2014                         self.pg0.sw_if_index,
2015                         self.pg0.remote_hosts[ii].mac,
2016                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2017         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2018                                      max_number=200,
2019                                      max_age=0,
2020                                      recycle=False)
2021
2022         self.sleep(10)
2023         self.assertTrue(find_nbr(self,
2024                                  self.pg0.sw_if_index,
2025                                  self.pg0.remote_hosts[0].ip4))
2026
2027
2028 class NeighborReplaceTestCase(VppTestCase):
2029     """ ARP/ND Replacement """
2030
2031     @classmethod
2032     def setUpClass(cls):
2033         super(NeighborReplaceTestCase, cls).setUpClass()
2034
2035     @classmethod
2036     def tearDownClass(cls):
2037         super(NeighborReplaceTestCase, cls).tearDownClass()
2038
2039     def setUp(self):
2040         super(NeighborReplaceTestCase, self).setUp()
2041
2042         self.create_pg_interfaces(range(4))
2043
2044         # pg0 configured with ip4 and 6 addresses used for input
2045         # pg1 configured with ip4 and 6 addresses used for output
2046         # pg2 is unnumbered to pg0
2047         for i in self.pg_interfaces:
2048             i.admin_up()
2049             i.config_ip4()
2050             i.config_ip6()
2051             i.resolve_arp()
2052             i.resolve_ndp()
2053
2054     def tearDown(self):
2055         super(NeighborReplaceTestCase, self).tearDown()
2056
2057         for i in self.pg_interfaces:
2058             i.unconfig_ip4()
2059             i.unconfig_ip6()
2060             i.admin_down()
2061
2062     def test_replace(self):
2063         """ replace """
2064
2065         N_HOSTS = 16
2066
2067         for i in self.pg_interfaces:
2068             i.generate_remote_hosts(N_HOSTS)
2069             i.configure_ipv4_neighbors()
2070             i.configure_ipv6_neighbors()
2071
2072         # replace them all
2073         self.vapi.ip_neighbor_replace_begin()
2074         self.vapi.ip_neighbor_replace_end()
2075
2076         for i in self.pg_interfaces:
2077             for h in range(N_HOSTS):
2078                 self.assertFalse(find_nbr(self,
2079                                           self.pg0.sw_if_index,
2080                                           self.pg0.remote_hosts[h].ip4))
2081                 self.assertFalse(find_nbr(self,
2082                                           self.pg0.sw_if_index,
2083                                           self.pg0.remote_hosts[h].ip6))
2084
2085         #
2086         # and them all back via the API
2087         #
2088         for i in self.pg_interfaces:
2089             for h in range(N_HOSTS):
2090                 VppNeighbor(self,
2091                             i.sw_if_index,
2092                             i.remote_hosts[h].mac,
2093                             i.remote_hosts[h].ip4).add_vpp_config()
2094                 VppNeighbor(self,
2095                             i.sw_if_index,
2096                             i.remote_hosts[h].mac,
2097                             i.remote_hosts[h].ip6).add_vpp_config()
2098
2099         #
2100         # begin the replacement again, this time touch some
2101         # the neighbours on pg1 so they are not deleted
2102         #
2103         self.vapi.ip_neighbor_replace_begin()
2104
2105         # update from the API all neighbours on pg1
2106         for h in range(N_HOSTS):
2107             VppNeighbor(self,
2108                         self.pg1.sw_if_index,
2109                         self.pg1.remote_hosts[h].mac,
2110                         self.pg1.remote_hosts[h].ip4).add_vpp_config()
2111             VppNeighbor(self,
2112                         self.pg1.sw_if_index,
2113                         self.pg1.remote_hosts[h].mac,
2114                         self.pg1.remote_hosts[h].ip6).add_vpp_config()
2115
2116         # update from the data-plane all neighbours on pg3
2117         self.pg3.configure_ipv4_neighbors()
2118         self.pg3.configure_ipv6_neighbors()
2119
2120         # complete the replacement
2121         self.logger.info(self.vapi.cli("sh ip neighbors"))
2122         self.vapi.ip_neighbor_replace_end()
2123
2124         for i in self.pg_interfaces:
2125             if i == self.pg1 or i == self.pg3:
2126                 # neighbours on pg1 and pg3 are still present
2127                 for h in range(N_HOSTS):
2128                     self.assertTrue(find_nbr(self,
2129                                              i.sw_if_index,
2130                                              i.remote_hosts[h].ip4))
2131                     self.assertTrue(find_nbr(self,
2132                                              i.sw_if_index,
2133                                              i.remote_hosts[h].ip6))
2134             else:
2135                 # all other neighbours are toast
2136                 for h in range(N_HOSTS):
2137                     self.assertFalse(find_nbr(self,
2138                                               i.sw_if_index,
2139                                               i.remote_hosts[h].ip4))
2140                     self.assertFalse(find_nbr(self,
2141                                               i.sw_if_index,
2142                                               i.remote_hosts[h].ip6))
2143
2144
2145 class NeighborFlush(VppTestCase):
2146     """ Neighbor Flush """
2147
2148     @classmethod
2149     def setUpClass(cls):
2150         super(NeighborFlush, cls).setUpClass()
2151
2152     @classmethod
2153     def tearDownClass(cls):
2154         super(NeighborFlush, cls).tearDownClass()
2155
2156     def setUp(self):
2157         super(NeighborFlush, self).setUp()
2158
2159         self.create_pg_interfaces(range(2))
2160
2161         for i in self.pg_interfaces:
2162             i.admin_up()
2163             i.config_ip4()
2164             i.config_ip6()
2165             i.resolve_arp()
2166             i.resolve_ndp()
2167
2168     def tearDown(self):
2169         super(NeighborFlush, self).tearDown()
2170
2171         for i in self.pg_interfaces:
2172             i.unconfig_ip4()
2173             i.unconfig_ip6()
2174             i.admin_down()
2175
2176     def test_flush(self):
2177         """ Neighbour Flush """
2178
2179         e = VppEnum
2180         nf = e.vl_api_ip_neighbor_flags_t
2181         af = e.vl_api_address_family_t
2182         N_HOSTS = 16
2183         static = [False, True]
2184         self.pg0.generate_remote_hosts(N_HOSTS)
2185         self.pg1.generate_remote_hosts(N_HOSTS)
2186
2187         for s in static:
2188             # a few v4 and v6 dynamic neoghbors
2189             for n in range(N_HOSTS):
2190                 VppNeighbor(self,
2191                             self.pg0.sw_if_index,
2192                             self.pg0.remote_hosts[n].mac,
2193                             self.pg0.remote_hosts[n].ip4,
2194                             is_static=s).add_vpp_config()
2195                 VppNeighbor(self,
2196                             self.pg1.sw_if_index,
2197                             self.pg1.remote_hosts[n].mac,
2198                             self.pg1.remote_hosts[n].ip6,
2199                             is_static=s).add_vpp_config()
2200
2201             # flush the interfaces individually
2202             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2203
2204             # check we haven't flushed that which we shouldn't
2205             for n in range(N_HOSTS):
2206                 self.assertTrue(find_nbr(self,
2207                                          self.pg1.sw_if_index,
2208                                          self.pg1.remote_hosts[n].ip6,
2209                                          is_static=s))
2210
2211             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2212
2213             for n in range(N_HOSTS):
2214                 self.assertFalse(find_nbr(self,
2215                                           self.pg0.sw_if_index,
2216                                           self.pg0.remote_hosts[n].ip4))
2217                 self.assertFalse(find_nbr(self,
2218                                           self.pg1.sw_if_index,
2219                                           self.pg1.remote_hosts[n].ip6))
2220
2221             # add the nieghbours back
2222             for n in range(N_HOSTS):
2223                 VppNeighbor(self,
2224                             self.pg0.sw_if_index,
2225                             self.pg0.remote_hosts[n].mac,
2226                             self.pg0.remote_hosts[n].ip4,
2227                             is_static=s).add_vpp_config()
2228                 VppNeighbor(self,
2229                             self.pg1.sw_if_index,
2230                             self.pg1.remote_hosts[n].mac,
2231                             self.pg1.remote_hosts[n].ip6,
2232                             is_static=s).add_vpp_config()
2233
2234             self.logger.info(self.vapi.cli("sh ip neighbor"))
2235
2236             # flush both interfaces at the same time
2237             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2238
2239             # check we haven't flushed that which we shouldn't
2240             for n in range(N_HOSTS):
2241                 self.assertTrue(find_nbr(self,
2242                                          self.pg0.sw_if_index,
2243                                          self.pg0.remote_hosts[n].ip4,
2244                                          is_static=s))
2245
2246             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2247
2248             for n in range(N_HOSTS):
2249                 self.assertFalse(find_nbr(self,
2250                                           self.pg0.sw_if_index,
2251                                           self.pg0.remote_hosts[n].ip4))
2252                 self.assertFalse(find_nbr(self,
2253                                           self.pg1.sw_if_index,
2254                                           self.pg1.remote_hosts[n].ip6))
2255
2256
2257 if __name__ == '__main__':
2258     unittest.main(testRunner=VppTestRunner)