ip-neighbor: Use ip_address_t rather than ip46_address_t
[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         mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1400                scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1401                scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1402         mac_string = ''.join(mac)
1403
1404         self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1405                                                mac_string)
1406
1407         #
1408         # now ARP requests come from the new source mac
1409         #
1410         rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1411         self.verify_arp_req(rx[0],
1412                             "00:00:00:33:33:33",
1413                             self.pg1.local_ip4,
1414                             self.pg1._remote_hosts[2].ip4)
1415
1416         #
1417         # packets to the resolved host also have the new source mac
1418         #
1419         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1420         self.verify_ip(rx[0],
1421                        "00:00:00:33:33:33",
1422                        self.pg1.remote_hosts[1].mac,
1423                        self.pg0.remote_ip4,
1424                        self.pg1.remote_hosts[1].ip4)
1425
1426         #
1427         # set the mac address on the interface that does not have a
1428         # configured subnet and thus no glean
1429         #
1430         self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1431                                                mac_string)
1432
1433     def test_garp(self):
1434         """ GARP """
1435
1436         #
1437         # Generate some hosts on the LAN
1438         #
1439         self.pg1.generate_remote_hosts(4)
1440         self.pg2.generate_remote_hosts(4)
1441
1442         #
1443         # And an ARP entry
1444         #
1445         arp = VppNeighbor(self,
1446                           self.pg1.sw_if_index,
1447                           self.pg1.remote_hosts[1].mac,
1448                           self.pg1.remote_hosts[1].ip4)
1449         arp.add_vpp_config()
1450
1451         self.assertTrue(find_nbr(self,
1452                                  self.pg1.sw_if_index,
1453                                  self.pg1.remote_hosts[1].ip4,
1454                                  mac=self.pg1.remote_hosts[1].mac))
1455
1456         #
1457         # Send a GARP (request) to swap the host 1's address to that of host 2
1458         #
1459         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1460                     src=self.pg1.remote_hosts[2].mac) /
1461               ARP(op="who-has",
1462                   hwdst=self.pg1.local_mac,
1463                   hwsrc=self.pg1.remote_hosts[2].mac,
1464                   pdst=self.pg1.remote_hosts[1].ip4,
1465                   psrc=self.pg1.remote_hosts[1].ip4))
1466
1467         self.pg1.add_stream(p1)
1468         self.pg_enable_capture(self.pg_interfaces)
1469         self.pg_start()
1470
1471         self.assertTrue(find_nbr(self,
1472                                  self.pg1.sw_if_index,
1473                                  self.pg1.remote_hosts[1].ip4,
1474                                  mac=self.pg1.remote_hosts[2].mac))
1475
1476         #
1477         # Send a GARP (reply) to swap the host 1's address to that of host 3
1478         #
1479         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1480                     src=self.pg1.remote_hosts[3].mac) /
1481               ARP(op="is-at",
1482                   hwdst=self.pg1.local_mac,
1483                   hwsrc=self.pg1.remote_hosts[3].mac,
1484                   pdst=self.pg1.remote_hosts[1].ip4,
1485                   psrc=self.pg1.remote_hosts[1].ip4))
1486
1487         self.pg1.add_stream(p1)
1488         self.pg_enable_capture(self.pg_interfaces)
1489         self.pg_start()
1490
1491         self.assertTrue(find_nbr(self,
1492                                  self.pg1.sw_if_index,
1493                                  self.pg1.remote_hosts[1].ip4,
1494                                  mac=self.pg1.remote_hosts[3].mac))
1495
1496         #
1497         # GARPs (request nor replies) for host we don't know yet
1498         # don't result in new neighbour entries
1499         #
1500         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1501                     src=self.pg1.remote_hosts[3].mac) /
1502               ARP(op="who-has",
1503                   hwdst=self.pg1.local_mac,
1504                   hwsrc=self.pg1.remote_hosts[3].mac,
1505                   pdst=self.pg1.remote_hosts[2].ip4,
1506                   psrc=self.pg1.remote_hosts[2].ip4))
1507
1508         self.pg1.add_stream(p1)
1509         self.pg_enable_capture(self.pg_interfaces)
1510         self.pg_start()
1511
1512         self.assertFalse(find_nbr(self,
1513                                   self.pg1.sw_if_index,
1514                                   self.pg1.remote_hosts[2].ip4))
1515
1516         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1517                     src=self.pg1.remote_hosts[3].mac) /
1518               ARP(op="is-at",
1519                   hwdst=self.pg1.local_mac,
1520                   hwsrc=self.pg1.remote_hosts[3].mac,
1521                   pdst=self.pg1.remote_hosts[2].ip4,
1522                   psrc=self.pg1.remote_hosts[2].ip4))
1523
1524         self.pg1.add_stream(p1)
1525         self.pg_enable_capture(self.pg_interfaces)
1526         self.pg_start()
1527
1528         self.assertFalse(find_nbr(self,
1529                                   self.pg1.sw_if_index,
1530                                   self.pg1.remote_hosts[2].ip4))
1531
1532         #
1533         # IP address in different subnets are not learnt
1534         #
1535         self.pg2.configure_ipv4_neighbors()
1536
1537         for op in ["is-at", "who-has"]:
1538             p1 = [(Ether(dst="ff:ff:ff:ff:ff:ff",
1539                          src=self.pg2.remote_hosts[1].mac) /
1540                    ARP(op=op,
1541                        hwdst=self.pg2.local_mac,
1542                        hwsrc=self.pg2.remote_hosts[1].mac,
1543                        pdst=self.pg2.remote_hosts[1].ip4,
1544                        psrc=self.pg2.remote_hosts[1].ip4)),
1545                   (Ether(dst="ff:ff:ff:ff:ff:ff",
1546                          src=self.pg2.remote_hosts[1].mac) /
1547                    ARP(op=op,
1548                        hwdst="ff:ff:ff:ff:ff:ff",
1549                        hwsrc=self.pg2.remote_hosts[1].mac,
1550                        pdst=self.pg2.remote_hosts[1].ip4,
1551                        psrc=self.pg2.remote_hosts[1].ip4))]
1552
1553             self.send_and_assert_no_replies(self.pg1, p1)
1554             self.assertFalse(find_nbr(self,
1555                                       self.pg1.sw_if_index,
1556                                       self.pg2.remote_hosts[1].ip4))
1557
1558         # they are all dropped because the subnet's don't match
1559         self.assertEqual(4, self.statistics.get_err_counter(
1560             "/err/arp-reply/IP4 destination address not local to subnet"))
1561
1562     def test_arp_incomplete(self):
1563         """ Incomplete Entries """
1564
1565         #
1566         # ensure that we throttle the ARP and ND requests
1567         #
1568         self.pg0.generate_remote_hosts(2)
1569
1570         #
1571         # IPv4/ARP
1572         #
1573         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1574                                  [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1575                                                self.pg0.sw_if_index)])
1576         ip_10_0_0_1.add_vpp_config()
1577
1578         p1 = (Ether(dst=self.pg1.local_mac,
1579                     src=self.pg1.remote_mac) /
1580               IP(src=self.pg1.remote_ip4,
1581                  dst="10.0.0.1") /
1582               UDP(sport=1234, dport=1234) /
1583               Raw())
1584
1585         self.pg1.add_stream(p1 * 257)
1586         self.pg_enable_capture(self.pg_interfaces)
1587         self.pg_start()
1588         rx = self.pg0._get_capture(1)
1589
1590         #
1591         # how many we get is going to be dependent on the time for packet
1592         # processing but it should be small
1593         #
1594         self.assertLess(len(rx), 64)
1595
1596         #
1597         # IPv6/ND
1598         #
1599         ip_10_1 = VppIpRoute(self, "10::1", 128,
1600                              [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1601                                            self.pg0.sw_if_index,
1602                                            proto=DpoProto.DPO_PROTO_IP6)])
1603         ip_10_1.add_vpp_config()
1604
1605         p1 = (Ether(dst=self.pg1.local_mac,
1606                     src=self.pg1.remote_mac) /
1607               IPv6(src=self.pg1.remote_ip6,
1608                    dst="10::1") /
1609               UDP(sport=1234, dport=1234) /
1610               Raw())
1611
1612         self.pg1.add_stream(p1 * 257)
1613         self.pg_enable_capture(self.pg_interfaces)
1614         self.pg_start()
1615         rx = self.pg0._get_capture(1)
1616
1617         #
1618         # how many we get is going to be dependent on the time for packet
1619         # processing but it should be small
1620         #
1621         self.assertLess(len(rx), 64)
1622
1623     def test_arp_forus(self):
1624         """ ARP for for-us """
1625
1626         #
1627         # Test that VPP responds with ARP requests to addresses that
1628         # are connected and local routes.
1629         # Use one of the 'remote' addresses in the subnet as a local address
1630         # The intention of this route is that it then acts like a secondary
1631         # address added to an interface
1632         #
1633         self.pg0.generate_remote_hosts(2)
1634
1635         forus = VppIpRoute(
1636             self, self.pg0.remote_hosts[1].ip4, 32,
1637             [VppRoutePath("0.0.0.0",
1638                           self.pg0.sw_if_index,
1639                           type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1640         forus.add_vpp_config()
1641
1642         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1643                    src=self.pg0.remote_mac) /
1644              ARP(op="who-has",
1645                  hwdst=self.pg0.local_mac,
1646                  hwsrc=self.pg0.remote_mac,
1647                  pdst=self.pg0.remote_hosts[1].ip4,
1648                  psrc=self.pg0.remote_ip4))
1649
1650         rx = self.send_and_expect(self.pg0, [p], self.pg0)
1651
1652         self.verify_arp_resp(rx[0],
1653                              self.pg0.local_mac,
1654                              self.pg0.remote_mac,
1655                              self.pg0.remote_hosts[1].ip4,
1656                              self.pg0.remote_ip4)
1657
1658     def test_arp_table_swap(self):
1659         #
1660         # Generate some hosts on the LAN
1661         #
1662         N_NBRS = 4
1663         self.pg1.generate_remote_hosts(N_NBRS)
1664
1665         for n in range(N_NBRS):
1666             # a route thru each neighbour
1667             VppIpRoute(self, "10.0.0.%d" % n, 32,
1668                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1669                                      self.pg1.sw_if_index)]).add_vpp_config()
1670
1671             # resolve each neighbour
1672             p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1673                   ARP(op="is-at", hwdst=self.pg1.local_mac,
1674                       hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1675                       psrc=self.pg1.remote_hosts[n].ip4))
1676
1677             self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1678
1679         self.logger.info(self.vapi.cli("sh ip neighbors"))
1680
1681         #
1682         # swap the table pg1 is in
1683         #
1684         table = VppIpTable(self, 100).add_vpp_config()
1685
1686         self.pg1.unconfig_ip4()
1687         self.pg1.set_table_ip4(100)
1688         self.pg1.config_ip4()
1689
1690         #
1691         # all neighbours are cleared
1692         #
1693         for n in range(N_NBRS):
1694             self.assertFalse(find_nbr(self,
1695                                       self.pg1.sw_if_index,
1696                                       self.pg1.remote_hosts[n].ip4))
1697
1698         #
1699         # packets to all neighbours generate ARP requests
1700         #
1701         for n in range(N_NBRS):
1702             # a route thru each neighbour
1703             VppIpRoute(self, "10.0.0.%d" % n, 32,
1704                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1705                                      self.pg1.sw_if_index)],
1706                        table_id=100).add_vpp_config()
1707
1708             p = (Ether(src=self.pg1.remote_hosts[n].mac,
1709                        dst=self.pg1.local_mac) /
1710                  IP(src=self.pg1.remote_hosts[n].ip4,
1711                     dst="10.0.0.%d" % n) /
1712                  Raw(b'0x5' * 100))
1713             rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1714             for rx in rxs:
1715                 self.verify_arp_req(rx,
1716                                     self.pg1.local_mac,
1717                                     self.pg1.local_ip4,
1718                                     self.pg1.remote_hosts[n].ip4)
1719
1720         self.pg1.unconfig_ip4()
1721         self.pg1.set_table_ip4(0)
1722
1723
1724 class NeighborStatsTestCase(VppTestCase):
1725     """ ARP/ND Counters """
1726
1727     @classmethod
1728     def setUpClass(cls):
1729         super(NeighborStatsTestCase, cls).setUpClass()
1730
1731     @classmethod
1732     def tearDownClass(cls):
1733         super(NeighborStatsTestCase, cls).tearDownClass()
1734
1735     def setUp(self):
1736         super(NeighborStatsTestCase, self).setUp()
1737
1738         self.create_pg_interfaces(range(2))
1739
1740         # pg0 configured with ip4 and 6 addresses used for input
1741         # pg1 configured with ip4 and 6 addresses used for output
1742         # pg2 is unnumbered to pg0
1743         for i in self.pg_interfaces:
1744             i.admin_up()
1745             i.config_ip4()
1746             i.config_ip6()
1747             i.resolve_arp()
1748             i.resolve_ndp()
1749
1750     def tearDown(self):
1751         super(NeighborStatsTestCase, self).tearDown()
1752
1753         for i in self.pg_interfaces:
1754             i.unconfig_ip4()
1755             i.unconfig_ip6()
1756             i.admin_down()
1757
1758     def test_arp_stats(self):
1759         """ ARP Counters """
1760
1761         self.vapi.cli("adj counters enable")
1762         self.pg1.generate_remote_hosts(2)
1763
1764         arp1 = VppNeighbor(self,
1765                            self.pg1.sw_if_index,
1766                            self.pg1.remote_hosts[0].mac,
1767                            self.pg1.remote_hosts[0].ip4)
1768         arp1.add_vpp_config()
1769         arp2 = VppNeighbor(self,
1770                            self.pg1.sw_if_index,
1771                            self.pg1.remote_hosts[1].mac,
1772                            self.pg1.remote_hosts[1].ip4)
1773         arp2.add_vpp_config()
1774
1775         p1 = (Ether(dst=self.pg0.local_mac,
1776                     src=self.pg0.remote_mac) /
1777               IP(src=self.pg0.remote_ip4,
1778                  dst=self.pg1.remote_hosts[0].ip4) /
1779               UDP(sport=1234, dport=1234) /
1780               Raw())
1781         p2 = (Ether(dst=self.pg0.local_mac,
1782                     src=self.pg0.remote_mac) /
1783               IP(src=self.pg0.remote_ip4,
1784                  dst=self.pg1.remote_hosts[1].ip4) /
1785               UDP(sport=1234, dport=1234) /
1786               Raw())
1787
1788         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1789         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1790
1791         self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1792         self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1793
1794         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1795         self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1796
1797     def test_nd_stats(self):
1798         """ ND Counters """
1799
1800         self.vapi.cli("adj counters enable")
1801         self.pg0.generate_remote_hosts(3)
1802
1803         nd1 = VppNeighbor(self,
1804                           self.pg0.sw_if_index,
1805                           self.pg0.remote_hosts[1].mac,
1806                           self.pg0.remote_hosts[1].ip6)
1807         nd1.add_vpp_config()
1808         nd2 = VppNeighbor(self,
1809                           self.pg0.sw_if_index,
1810                           self.pg0.remote_hosts[2].mac,
1811                           self.pg0.remote_hosts[2].ip6)
1812         nd2.add_vpp_config()
1813
1814         p1 = (Ether(dst=self.pg1.local_mac,
1815                     src=self.pg1.remote_mac) /
1816               IPv6(src=self.pg1.remote_ip6,
1817                    dst=self.pg0.remote_hosts[1].ip6) /
1818               UDP(sport=1234, dport=1234) /
1819               Raw())
1820         p2 = (Ether(dst=self.pg1.local_mac,
1821                     src=self.pg1.remote_mac) /
1822               IPv6(src=self.pg1.remote_ip6,
1823                    dst=self.pg0.remote_hosts[2].ip6) /
1824               UDP(sport=1234, dport=1234) /
1825               Raw())
1826
1827         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1828         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1829
1830         self.assertEqual(16, nd1.get_stats()['packets'])
1831         self.assertEqual(16, nd2.get_stats()['packets'])
1832
1833         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1834         self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1835
1836
1837 class NeighborAgeTestCase(VppTestCase):
1838     """ ARP/ND Aging """
1839
1840     @classmethod
1841     def setUpClass(cls):
1842         super(NeighborAgeTestCase, cls).setUpClass()
1843
1844     @classmethod
1845     def tearDownClass(cls):
1846         super(NeighborAgeTestCase, cls).tearDownClass()
1847
1848     def setUp(self):
1849         super(NeighborAgeTestCase, self).setUp()
1850
1851         self.create_pg_interfaces(range(1))
1852
1853         # pg0 configured with ip4 and 6 addresses used for input
1854         # pg1 configured with ip4 and 6 addresses used for output
1855         # pg2 is unnumbered to pg0
1856         for i in self.pg_interfaces:
1857             i.admin_up()
1858             i.config_ip4()
1859             i.config_ip6()
1860             i.resolve_arp()
1861             i.resolve_ndp()
1862
1863     def tearDown(self):
1864         super(NeighborAgeTestCase, self).tearDown()
1865
1866         for i in self.pg_interfaces:
1867             i.unconfig_ip4()
1868             i.unconfig_ip6()
1869             i.admin_down()
1870
1871     def wait_for_no_nbr(self, intf, address,
1872                         n_tries=50, s_time=1):
1873         while (n_tries):
1874             if not find_nbr(self, intf, address):
1875                 return True
1876             n_tries = n_tries - 1
1877             self.sleep(s_time)
1878
1879         return False
1880
1881     def verify_arp_req(self, rx, smac, sip, dip):
1882         ether = rx[Ether]
1883         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1884         self.assertEqual(ether.src, smac)
1885
1886         arp = rx[ARP]
1887         self.assertEqual(arp.hwtype, 1)
1888         self.assertEqual(arp.ptype, 0x800)
1889         self.assertEqual(arp.hwlen, 6)
1890         self.assertEqual(arp.plen, 4)
1891         self.assertEqual(arp.op, arp_opts["who-has"])
1892         self.assertEqual(arp.hwsrc, smac)
1893         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1894         self.assertEqual(arp.psrc, sip)
1895         self.assertEqual(arp.pdst, dip)
1896
1897     def test_age(self):
1898         """ Aging/Recycle """
1899
1900         self.vapi.cli("set logging unthrottle 0")
1901         self.vapi.cli("set logging size %d" % 0xffff)
1902
1903         self.pg0.generate_remote_hosts(201)
1904
1905         vaf = VppEnum.vl_api_address_family_t
1906
1907         #
1908         # start listening on all interfaces
1909         #
1910         self.pg_enable_capture(self.pg_interfaces)
1911
1912         #
1913         # Set the neighbor configuration:
1914         #   limi = 200
1915         #   age  = 0 seconds
1916         #   recycle = false
1917         #
1918         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1919                                      max_number=200,
1920                                      max_age=0,
1921                                      recycle=False)
1922
1923         self.vapi.cli("sh ip neighbor-config")
1924
1925         # add the 198 neighbours that should pass (-1 for one created in setup)
1926         for ii in range(200):
1927             VppNeighbor(self,
1928                         self.pg0.sw_if_index,
1929                         self.pg0.remote_hosts[ii].mac,
1930                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1931
1932         # one more neighbor over the limit should fail
1933         with self.vapi.assert_negative_api_retval():
1934             VppNeighbor(self,
1935                         self.pg0.sw_if_index,
1936                         self.pg0.remote_hosts[200].mac,
1937                         self.pg0.remote_hosts[200].ip4).add_vpp_config()
1938
1939         #
1940         # change the config to allow recycling the old neighbors
1941         #
1942         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1943                                      max_number=200,
1944                                      max_age=0,
1945                                      recycle=True)
1946
1947         # now new additions are allowed
1948         VppNeighbor(self,
1949                     self.pg0.sw_if_index,
1950                     self.pg0.remote_hosts[200].mac,
1951                     self.pg0.remote_hosts[200].ip4).add_vpp_config()
1952
1953         # add the first neighbor we configured has been re-used
1954         self.assertFalse(find_nbr(self,
1955                                   self.pg0.sw_if_index,
1956                                   self.pg0.remote_hosts[0].ip4))
1957         self.assertTrue(find_nbr(self,
1958                                  self.pg0.sw_if_index,
1959                                  self.pg0.remote_hosts[200].ip4))
1960
1961         #
1962         # change the config to age old neighbors
1963         #
1964         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1965                                      max_number=200,
1966                                      max_age=2,
1967                                      recycle=True)
1968
1969         self.vapi.cli("sh ip4 neighbor-sorted")
1970
1971         #
1972         # expect probes from all these ARP entries as they age
1973         # 3 probes for each neighbor 3*200 = 600
1974         rxs = self.pg0.get_capture(600, timeout=8)
1975
1976         for ii in range(3):
1977             for jj in range(200):
1978                 rx = rxs[ii*200 + jj]
1979                 # rx.show()
1980
1981         #
1982         # 3 probes sent then 1 more second to see if a reply comes, before
1983         # they age out
1984         #
1985         for jj in range(1, 201):
1986             self.wait_for_no_nbr(self.pg0.sw_if_index,
1987                                  self.pg0.remote_hosts[jj].ip4)
1988
1989         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1990                                                     af=vaf.ADDRESS_IP4))
1991
1992         #
1993         # load up some neighbours again with 2s aging enabled
1994         # they should be removed after 10s (2s age + 4s for probes + gap)
1995         #
1996         for ii in range(10):
1997             VppNeighbor(self,
1998                         self.pg0.sw_if_index,
1999                         self.pg0.remote_hosts[ii].mac,
2000                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2001         self.sleep(10)
2002         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
2003                                                     af=vaf.ADDRESS_IP4))
2004
2005         #
2006         # check if we can set age and recycle with empty neighbor list
2007         #
2008         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2009                                      max_number=200,
2010                                      max_age=1000,
2011                                      recycle=True)
2012
2013         #
2014         # load up some neighbours again, then disable the aging
2015         # they should still be there in 10 seconds time
2016         #
2017         for ii in range(10):
2018             VppNeighbor(self,
2019                         self.pg0.sw_if_index,
2020                         self.pg0.remote_hosts[ii].mac,
2021                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
2022         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
2023                                      max_number=200,
2024                                      max_age=0,
2025                                      recycle=False)
2026
2027         self.sleep(10)
2028         self.assertTrue(find_nbr(self,
2029                                  self.pg0.sw_if_index,
2030                                  self.pg0.remote_hosts[0].ip4))
2031
2032
2033 class NeighborReplaceTestCase(VppTestCase):
2034     """ ARP/ND Replacement """
2035
2036     @classmethod
2037     def setUpClass(cls):
2038         super(NeighborReplaceTestCase, cls).setUpClass()
2039
2040     @classmethod
2041     def tearDownClass(cls):
2042         super(NeighborReplaceTestCase, cls).tearDownClass()
2043
2044     def setUp(self):
2045         super(NeighborReplaceTestCase, self).setUp()
2046
2047         self.create_pg_interfaces(range(4))
2048
2049         # pg0 configured with ip4 and 6 addresses used for input
2050         # pg1 configured with ip4 and 6 addresses used for output
2051         # pg2 is unnumbered to pg0
2052         for i in self.pg_interfaces:
2053             i.admin_up()
2054             i.config_ip4()
2055             i.config_ip6()
2056             i.resolve_arp()
2057             i.resolve_ndp()
2058
2059     def tearDown(self):
2060         super(NeighborReplaceTestCase, self).tearDown()
2061
2062         for i in self.pg_interfaces:
2063             i.unconfig_ip4()
2064             i.unconfig_ip6()
2065             i.admin_down()
2066
2067     def test_replace(self):
2068         """ replace """
2069
2070         N_HOSTS = 16
2071
2072         for i in self.pg_interfaces:
2073             i.generate_remote_hosts(N_HOSTS)
2074             i.configure_ipv4_neighbors()
2075             i.configure_ipv6_neighbors()
2076
2077         # replace them all
2078         self.vapi.ip_neighbor_replace_begin()
2079         self.vapi.ip_neighbor_replace_end()
2080
2081         for i in self.pg_interfaces:
2082             for h in range(N_HOSTS):
2083                 self.assertFalse(find_nbr(self,
2084                                           self.pg0.sw_if_index,
2085                                           self.pg0.remote_hosts[h].ip4))
2086                 self.assertFalse(find_nbr(self,
2087                                           self.pg0.sw_if_index,
2088                                           self.pg0.remote_hosts[h].ip6))
2089
2090         #
2091         # and them all back via the API
2092         #
2093         for i in self.pg_interfaces:
2094             for h in range(N_HOSTS):
2095                 VppNeighbor(self,
2096                             i.sw_if_index,
2097                             i.remote_hosts[h].mac,
2098                             i.remote_hosts[h].ip4).add_vpp_config()
2099                 VppNeighbor(self,
2100                             i.sw_if_index,
2101                             i.remote_hosts[h].mac,
2102                             i.remote_hosts[h].ip6).add_vpp_config()
2103
2104         #
2105         # begin the replacement again, this time touch some
2106         # the neighbours on pg1 so they are not deleted
2107         #
2108         self.vapi.ip_neighbor_replace_begin()
2109
2110         # update from the API all neighbours on pg1
2111         for h in range(N_HOSTS):
2112             VppNeighbor(self,
2113                         self.pg1.sw_if_index,
2114                         self.pg1.remote_hosts[h].mac,
2115                         self.pg1.remote_hosts[h].ip4).add_vpp_config()
2116             VppNeighbor(self,
2117                         self.pg1.sw_if_index,
2118                         self.pg1.remote_hosts[h].mac,
2119                         self.pg1.remote_hosts[h].ip6).add_vpp_config()
2120
2121         # update from the data-plane all neighbours on pg3
2122         self.pg3.configure_ipv4_neighbors()
2123         self.pg3.configure_ipv6_neighbors()
2124
2125         # complete the replacement
2126         self.logger.info(self.vapi.cli("sh ip neighbors"))
2127         self.vapi.ip_neighbor_replace_end()
2128
2129         for i in self.pg_interfaces:
2130             if i == self.pg1 or i == self.pg3:
2131                 # neighbours on pg1 and pg3 are still present
2132                 for h in range(N_HOSTS):
2133                     self.assertTrue(find_nbr(self,
2134                                              i.sw_if_index,
2135                                              i.remote_hosts[h].ip4))
2136                     self.assertTrue(find_nbr(self,
2137                                              i.sw_if_index,
2138                                              i.remote_hosts[h].ip6))
2139             else:
2140                 # all other neighbours are toast
2141                 for h in range(N_HOSTS):
2142                     self.assertFalse(find_nbr(self,
2143                                               i.sw_if_index,
2144                                               i.remote_hosts[h].ip4))
2145                     self.assertFalse(find_nbr(self,
2146                                               i.sw_if_index,
2147                                               i.remote_hosts[h].ip6))
2148
2149
2150 class NeighborFlush(VppTestCase):
2151     """ Neighbor Flush """
2152
2153     @classmethod
2154     def setUpClass(cls):
2155         super(NeighborFlush, cls).setUpClass()
2156
2157     @classmethod
2158     def tearDownClass(cls):
2159         super(NeighborFlush, cls).tearDownClass()
2160
2161     def setUp(self):
2162         super(NeighborFlush, self).setUp()
2163
2164         self.create_pg_interfaces(range(2))
2165
2166         for i in self.pg_interfaces:
2167             i.admin_up()
2168             i.config_ip4()
2169             i.config_ip6()
2170             i.resolve_arp()
2171             i.resolve_ndp()
2172
2173     def tearDown(self):
2174         super(NeighborFlush, self).tearDown()
2175
2176         for i in self.pg_interfaces:
2177             i.unconfig_ip4()
2178             i.unconfig_ip6()
2179             i.admin_down()
2180
2181     def test_flush(self):
2182         """ Neighbour Flush """
2183
2184         e = VppEnum
2185         nf = e.vl_api_ip_neighbor_flags_t
2186         af = e.vl_api_address_family_t
2187         N_HOSTS = 16
2188         static = [False, True]
2189         self.pg0.generate_remote_hosts(N_HOSTS)
2190         self.pg1.generate_remote_hosts(N_HOSTS)
2191
2192         for s in static:
2193             # a few v4 and v6 dynamic neoghbors
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             # flush the interfaces individually
2207             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2208
2209             # check we haven't flushed that which we shouldn't
2210             for n in range(N_HOSTS):
2211                 self.assertTrue(find_nbr(self,
2212                                          self.pg1.sw_if_index,
2213                                          self.pg1.remote_hosts[n].ip6,
2214                                          is_static=s))
2215
2216             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2217
2218             for n in range(N_HOSTS):
2219                 self.assertFalse(find_nbr(self,
2220                                           self.pg0.sw_if_index,
2221                                           self.pg0.remote_hosts[n].ip4))
2222                 self.assertFalse(find_nbr(self,
2223                                           self.pg1.sw_if_index,
2224                                           self.pg1.remote_hosts[n].ip6))
2225
2226             # add the nieghbours back
2227             for n in range(N_HOSTS):
2228                 VppNeighbor(self,
2229                             self.pg0.sw_if_index,
2230                             self.pg0.remote_hosts[n].mac,
2231                             self.pg0.remote_hosts[n].ip4,
2232                             is_static=s).add_vpp_config()
2233                 VppNeighbor(self,
2234                             self.pg1.sw_if_index,
2235                             self.pg1.remote_hosts[n].mac,
2236                             self.pg1.remote_hosts[n].ip6,
2237                             is_static=s).add_vpp_config()
2238
2239             self.logger.info(self.vapi.cli("sh ip neighbor"))
2240
2241             # flush both interfaces at the same time
2242             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xffffffff)
2243
2244             # check we haven't flushed that which we shouldn't
2245             for n in range(N_HOSTS):
2246                 self.assertTrue(find_nbr(self,
2247                                          self.pg0.sw_if_index,
2248                                          self.pg0.remote_hosts[n].ip4,
2249                                          is_static=s))
2250
2251             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xffffffff)
2252
2253             for n in range(N_HOSTS):
2254                 self.assertFalse(find_nbr(self,
2255                                           self.pg0.sw_if_index,
2256                                           self.pg0.remote_hosts[n].ip4))
2257                 self.assertFalse(find_nbr(self,
2258                                           self.pg1.sw_if_index,
2259                                           self.pg1.remote_hosts[n].ip6))
2260
2261
2262 if __name__ == '__main__':
2263     unittest.main(testRunner=VppTestRunner)