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