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