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