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