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