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