fib: only update glean for interface if necessary
[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.
2130         # VPP leaves the glean address being used for a prefix
2131         # in place until that address is deleted.
2132         #
2133         conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2134
2135         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2136         for rx in rxs:
2137             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2138
2139         #
2140         # remove first address, which is currently in use
2141         # the second address should be used now
2142         #
2143         conn2.remove_vpp_config()
2144         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2145         for rx in rxs:
2146             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2147
2148         #
2149         # add first address back. Second address should continue
2150         # being used.
2151         #
2152         conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2153         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2154         for rx in rxs:
2155             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2156
2157         conn1.remove_vpp_config()
2158         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2159         for rx in rxs:
2160             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2161
2162         # apply a connected prefix to an interface in a different table
2163         VppIpRoute(
2164             self,
2165             "10.0.1.0",
2166             24,
2167             [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2168             table_id=1,
2169         ).add_vpp_config()
2170
2171         rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2172         for rx in rxs:
2173             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2174
2175         # apply an attached prefix to the interface
2176         # since there's no local address in this prefix,
2177         # any other address is used
2178         p3 = (
2179             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2180             / IP(src=self.pg1.remote_ip4, dst="10.0.2.128")
2181             / Raw(b"0x5" * 100)
2182         )
2183
2184         VppIpRoute(
2185             self,
2186             "10.0.2.0",
2187             24,
2188             [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2189         ).add_vpp_config()
2190
2191         rxs = self.send_and_expect(self.pg0, [p3], self.pg1)
2192         for rx in rxs:
2193             self.verify_arp_req(
2194                 rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128"
2195             )
2196
2197         # cleanup
2198         conn3.remove_vpp_config()
2199         conn2.remove_vpp_config()
2200
2201
2202 @tag_fixme_vpp_workers
2203 class NeighborStatsTestCase(VppTestCase):
2204     """ARP/ND Counters"""
2205
2206     @classmethod
2207     def setUpClass(cls):
2208         super(NeighborStatsTestCase, cls).setUpClass()
2209
2210     @classmethod
2211     def tearDownClass(cls):
2212         super(NeighborStatsTestCase, cls).tearDownClass()
2213
2214     def setUp(self):
2215         super(NeighborStatsTestCase, self).setUp()
2216
2217         self.create_pg_interfaces(range(2))
2218
2219         # pg0 configured with ip4 and 6 addresses used for input
2220         # pg1 configured with ip4 and 6 addresses used for output
2221         # pg2 is unnumbered to pg0
2222         for i in self.pg_interfaces:
2223             i.admin_up()
2224             i.config_ip4()
2225             i.config_ip6()
2226             i.resolve_arp()
2227             i.resolve_ndp()
2228
2229     def tearDown(self):
2230         super(NeighborStatsTestCase, self).tearDown()
2231
2232         for i in self.pg_interfaces:
2233             i.unconfig_ip4()
2234             i.unconfig_ip6()
2235             i.admin_down()
2236
2237     def test_arp_stats(self):
2238         """ARP Counters"""
2239
2240         self.vapi.cli("adj counters enable")
2241         self.pg1.generate_remote_hosts(2)
2242
2243         arp1 = VppNeighbor(
2244             self,
2245             self.pg1.sw_if_index,
2246             self.pg1.remote_hosts[0].mac,
2247             self.pg1.remote_hosts[0].ip4,
2248         )
2249         arp1.add_vpp_config()
2250         arp2 = VppNeighbor(
2251             self,
2252             self.pg1.sw_if_index,
2253             self.pg1.remote_hosts[1].mac,
2254             self.pg1.remote_hosts[1].ip4,
2255         )
2256         arp2.add_vpp_config()
2257
2258         p1 = (
2259             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2260             / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2261             / UDP(sport=1234, dport=1234)
2262             / Raw()
2263         )
2264         p2 = (
2265             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2266             / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2267             / UDP(sport=1234, dport=1234)
2268             / Raw()
2269         )
2270
2271         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2272         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2273
2274         self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2275         self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2276
2277         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2278         self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2279
2280     def test_nd_stats(self):
2281         """ND Counters"""
2282
2283         self.vapi.cli("adj counters enable")
2284         self.pg0.generate_remote_hosts(3)
2285
2286         nd1 = VppNeighbor(
2287             self,
2288             self.pg0.sw_if_index,
2289             self.pg0.remote_hosts[1].mac,
2290             self.pg0.remote_hosts[1].ip6,
2291         )
2292         nd1.add_vpp_config()
2293         nd2 = VppNeighbor(
2294             self,
2295             self.pg0.sw_if_index,
2296             self.pg0.remote_hosts[2].mac,
2297             self.pg0.remote_hosts[2].ip6,
2298         )
2299         nd2.add_vpp_config()
2300
2301         p1 = (
2302             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2303             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2304             / UDP(sport=1234, dport=1234)
2305             / Raw()
2306         )
2307         p2 = (
2308             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2309             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2310             / UDP(sport=1234, dport=1234)
2311             / Raw()
2312         )
2313
2314         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2315         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2316
2317         self.assertEqual(16, nd1.get_stats()["packets"])
2318         self.assertEqual(16, nd2.get_stats()["packets"])
2319
2320         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2321         self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2322
2323
2324 @tag_fixme_ubuntu2204
2325 class NeighborAgeTestCase(VppTestCase):
2326     """ARP/ND Aging"""
2327
2328     @classmethod
2329     def setUpClass(cls):
2330         super(NeighborAgeTestCase, cls).setUpClass()
2331
2332     @classmethod
2333     def tearDownClass(cls):
2334         super(NeighborAgeTestCase, cls).tearDownClass()
2335
2336     def setUp(self):
2337         super(NeighborAgeTestCase, self).setUp()
2338
2339         self.create_pg_interfaces(range(1))
2340
2341         # pg0 configured with ip4 and 6 addresses used for input
2342         # pg1 configured with ip4 and 6 addresses used for output
2343         # pg2 is unnumbered to pg0
2344         for i in self.pg_interfaces:
2345             i.admin_up()
2346             i.config_ip4()
2347             i.config_ip6()
2348             i.resolve_arp()
2349             i.resolve_ndp()
2350
2351     def tearDown(self):
2352         super(NeighborAgeTestCase, self).tearDown()
2353
2354         for i in self.pg_interfaces:
2355             i.unconfig_ip4()
2356             i.unconfig_ip6()
2357             i.admin_down()
2358
2359     def verify_arp_req(self, rx, smac, sip, dip):
2360         ether = rx[Ether]
2361         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2362         self.assertEqual(ether.src, smac)
2363
2364         arp = rx[ARP]
2365         self.assertEqual(arp.hwtype, 1)
2366         self.assertEqual(arp.ptype, 0x800)
2367         self.assertEqual(arp.hwlen, 6)
2368         self.assertEqual(arp.plen, 4)
2369         self.assertEqual(arp.op, arp_opts["who-has"])
2370         self.assertEqual(arp.hwsrc, smac)
2371         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2372         self.assertEqual(arp.psrc, sip)
2373         self.assertEqual(arp.pdst, dip)
2374
2375     def verify_ip_neighbor_config(self, af, max_number, max_age, recycle):
2376         config = self.vapi.ip_neighbor_config_get(af)
2377
2378         self.assertEqual(config.af, af)
2379         self.assertEqual(config.max_number, max_number)
2380         self.assertEqual(config.max_age, max_age)
2381         self.assertEqual(config.recycle, recycle)
2382
2383     def test_age(self):
2384         """Aging/Recycle"""
2385
2386         self.vapi.cli("set logging unthrottle 0")
2387         self.vapi.cli("set logging size %d" % 0xFFFF)
2388
2389         self.pg0.generate_remote_hosts(201)
2390
2391         vaf = VppEnum.vl_api_address_family_t
2392
2393         #
2394         # start listening on all interfaces
2395         #
2396         self.pg_enable_capture(self.pg_interfaces)
2397
2398         #
2399         # Verify neighbor configuration defaults
2400         #
2401         self.verify_ip_neighbor_config(
2402             af=vaf.ADDRESS_IP4, max_number=50000, max_age=0, recycle=False
2403         )
2404
2405         #
2406         # Set the neighbor configuration:
2407         #   limi = 200
2408         #   age  = 0 seconds
2409         #   recycle = false
2410         #
2411         self.vapi.ip_neighbor_config(
2412             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2413         )
2414         self.verify_ip_neighbor_config(
2415             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2416         )
2417
2418         self.vapi.cli("sh ip neighbor-config")
2419
2420         # add the 198 neighbours that should pass (-1 for one created in setup)
2421         for ii in range(200):
2422             VppNeighbor(
2423                 self,
2424                 self.pg0.sw_if_index,
2425                 self.pg0.remote_hosts[ii].mac,
2426                 self.pg0.remote_hosts[ii].ip4,
2427             ).add_vpp_config()
2428
2429         # one more neighbor over the limit should fail
2430         with self.vapi.assert_negative_api_retval():
2431             VppNeighbor(
2432                 self,
2433                 self.pg0.sw_if_index,
2434                 self.pg0.remote_hosts[200].mac,
2435                 self.pg0.remote_hosts[200].ip4,
2436             ).add_vpp_config()
2437
2438         #
2439         # change the config to allow recycling the old neighbors
2440         #
2441         self.vapi.ip_neighbor_config(
2442             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2443         )
2444         self.verify_ip_neighbor_config(
2445             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2446         )
2447
2448         # now new additions are allowed
2449         VppNeighbor(
2450             self,
2451             self.pg0.sw_if_index,
2452             self.pg0.remote_hosts[200].mac,
2453             self.pg0.remote_hosts[200].ip4,
2454         ).add_vpp_config()
2455
2456         # add the first neighbor we configured has been re-used
2457         self.assertFalse(
2458             find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2459         )
2460         self.assertTrue(
2461             find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2462         )
2463
2464         #
2465         # change the config to age old neighbors
2466         #
2467         self.vapi.ip_neighbor_config(
2468             af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2469         )
2470         self.verify_ip_neighbor_config(
2471             af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2472         )
2473
2474         self.vapi.cli("sh ip4 neighbor-sorted")
2475
2476         # age out neighbors
2477         self.virtual_sleep(3)
2478
2479         #
2480         # expect probes from all these ARP entries as they age
2481         # 3 probes for each neighbor 3*200 = 600
2482         rxs = self.pg0.get_capture(600, timeout=2)
2483
2484         for ii in range(3):
2485             for jj in range(200):
2486                 rx = rxs[ii * 200 + jj]
2487                 # rx.show()
2488
2489         #
2490         # 3 probes sent then 1 more second to see if a reply comes, before
2491         # they age out
2492         #
2493         self.virtual_sleep(1)
2494
2495         self.assertFalse(
2496             self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2497         )
2498
2499         #
2500         # load up some neighbours again with 2s aging enabled
2501         # they should be removed after 10s (2s age + 4s for probes + gap)
2502         # check for the add and remove events
2503         #
2504         enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2505
2506         self.vapi.want_ip_neighbor_events_v2(enable=1)
2507         for ii in range(10):
2508             VppNeighbor(
2509                 self,
2510                 self.pg0.sw_if_index,
2511                 self.pg0.remote_hosts[ii].mac,
2512                 self.pg0.remote_hosts[ii].ip4,
2513             ).add_vpp_config()
2514
2515             e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2516             self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2517             self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2518             self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2519
2520         self.virtual_sleep(10)
2521         self.assertFalse(
2522             self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2523         )
2524
2525         evs = []
2526         for ii in range(10):
2527             e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2528             self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2529             evs.append(e)
2530
2531         # check we got the correct mac/ip pairs - done separately
2532         # because we don't care about the order the remove notifications
2533         # arrive
2534         for ii in range(10):
2535             found = False
2536             mac = self.pg0.remote_hosts[ii].mac
2537             ip = self.pg0.remote_hosts[ii].ip4
2538
2539             for e in evs:
2540                 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2541                     found = True
2542                     break
2543             self.assertTrue(found)
2544
2545         #
2546         # check if we can set age and recycle with empty neighbor list
2547         #
2548         self.vapi.ip_neighbor_config(
2549             af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2550         )
2551         self.verify_ip_neighbor_config(
2552             af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2553         )
2554
2555         #
2556         # load up some neighbours again, then disable the aging
2557         # they should still be there in 10 seconds time
2558         #
2559         for ii in range(10):
2560             VppNeighbor(
2561                 self,
2562                 self.pg0.sw_if_index,
2563                 self.pg0.remote_hosts[ii].mac,
2564                 self.pg0.remote_hosts[ii].ip4,
2565             ).add_vpp_config()
2566         self.vapi.ip_neighbor_config(
2567             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2568         )
2569         self.verify_ip_neighbor_config(
2570             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2571         )
2572
2573         self.virtual_sleep(10)
2574         self.assertTrue(
2575             find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2576         )
2577
2578
2579 class NeighborReplaceTestCase(VppTestCase):
2580     """ARP/ND Replacement"""
2581
2582     @classmethod
2583     def setUpClass(cls):
2584         super(NeighborReplaceTestCase, cls).setUpClass()
2585
2586     @classmethod
2587     def tearDownClass(cls):
2588         super(NeighborReplaceTestCase, cls).tearDownClass()
2589
2590     def setUp(self):
2591         super(NeighborReplaceTestCase, self).setUp()
2592
2593         self.create_pg_interfaces(range(4))
2594
2595         # pg0 configured with ip4 and 6 addresses used for input
2596         # pg1 configured with ip4 and 6 addresses used for output
2597         # pg2 is unnumbered to pg0
2598         for i in self.pg_interfaces:
2599             i.admin_up()
2600             i.config_ip4()
2601             i.config_ip6()
2602             i.resolve_arp()
2603             i.resolve_ndp()
2604
2605     def tearDown(self):
2606         super(NeighborReplaceTestCase, self).tearDown()
2607
2608         for i in self.pg_interfaces:
2609             i.unconfig_ip4()
2610             i.unconfig_ip6()
2611             i.admin_down()
2612
2613     def test_replace(self):
2614         """replace"""
2615
2616         N_HOSTS = 16
2617
2618         for i in self.pg_interfaces:
2619             i.generate_remote_hosts(N_HOSTS)
2620             i.configure_ipv4_neighbors()
2621             i.configure_ipv6_neighbors()
2622
2623         # replace them all
2624         self.vapi.ip_neighbor_replace_begin()
2625         self.vapi.ip_neighbor_replace_end()
2626
2627         for i in self.pg_interfaces:
2628             for h in range(N_HOSTS):
2629                 self.assertFalse(
2630                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2631                 )
2632                 self.assertFalse(
2633                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2634                 )
2635
2636         #
2637         # and them all back via the API
2638         #
2639         for i in self.pg_interfaces:
2640             for h in range(N_HOSTS):
2641                 VppNeighbor(
2642                     self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2643                 ).add_vpp_config()
2644                 VppNeighbor(
2645                     self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2646                 ).add_vpp_config()
2647
2648         #
2649         # begin the replacement again, this time touch some
2650         # the neighbours on pg1 so they are not deleted
2651         #
2652         self.vapi.ip_neighbor_replace_begin()
2653
2654         # update from the API all neighbours on pg1
2655         for h in range(N_HOSTS):
2656             VppNeighbor(
2657                 self,
2658                 self.pg1.sw_if_index,
2659                 self.pg1.remote_hosts[h].mac,
2660                 self.pg1.remote_hosts[h].ip4,
2661             ).add_vpp_config()
2662             VppNeighbor(
2663                 self,
2664                 self.pg1.sw_if_index,
2665                 self.pg1.remote_hosts[h].mac,
2666                 self.pg1.remote_hosts[h].ip6,
2667             ).add_vpp_config()
2668
2669         # update from the data-plane all neighbours on pg3
2670         self.pg3.configure_ipv4_neighbors()
2671         self.pg3.configure_ipv6_neighbors()
2672
2673         # complete the replacement
2674         self.logger.info(self.vapi.cli("sh ip neighbors"))
2675         self.vapi.ip_neighbor_replace_end()
2676
2677         for i in self.pg_interfaces:
2678             if i == self.pg1 or i == self.pg3:
2679                 # neighbours on pg1 and pg3 are still present
2680                 for h in range(N_HOSTS):
2681                     self.assertTrue(
2682                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2683                     )
2684                     self.assertTrue(
2685                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2686                     )
2687             else:
2688                 # all other neighbours are toast
2689                 for h in range(N_HOSTS):
2690                     self.assertFalse(
2691                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2692                     )
2693                     self.assertFalse(
2694                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2695                     )
2696
2697
2698 class NeighborFlush(VppTestCase):
2699     """Neighbor Flush"""
2700
2701     @classmethod
2702     def setUpClass(cls):
2703         super(NeighborFlush, cls).setUpClass()
2704
2705     @classmethod
2706     def tearDownClass(cls):
2707         super(NeighborFlush, cls).tearDownClass()
2708
2709     def setUp(self):
2710         super(NeighborFlush, self).setUp()
2711
2712         self.create_pg_interfaces(range(2))
2713
2714         for i in self.pg_interfaces:
2715             i.admin_up()
2716             i.config_ip4()
2717             i.config_ip6()
2718             i.resolve_arp()
2719             i.resolve_ndp()
2720
2721     def tearDown(self):
2722         super(NeighborFlush, self).tearDown()
2723
2724         for i in self.pg_interfaces:
2725             i.unconfig_ip4()
2726             i.unconfig_ip6()
2727             i.admin_down()
2728
2729     def test_flush(self):
2730         """Neighbour Flush"""
2731
2732         e = VppEnum
2733         nf = e.vl_api_ip_neighbor_flags_t
2734         af = e.vl_api_address_family_t
2735         N_HOSTS = 16
2736         static = [False, True]
2737         self.pg0.generate_remote_hosts(N_HOSTS)
2738         self.pg1.generate_remote_hosts(N_HOSTS)
2739
2740         for s in static:
2741             # a few v4 and v6 dynamic neoghbors
2742             for n in range(N_HOSTS):
2743                 VppNeighbor(
2744                     self,
2745                     self.pg0.sw_if_index,
2746                     self.pg0.remote_hosts[n].mac,
2747                     self.pg0.remote_hosts[n].ip4,
2748                     is_static=s,
2749                 ).add_vpp_config()
2750                 VppNeighbor(
2751                     self,
2752                     self.pg1.sw_if_index,
2753                     self.pg1.remote_hosts[n].mac,
2754                     self.pg1.remote_hosts[n].ip6,
2755                     is_static=s,
2756                 ).add_vpp_config()
2757
2758             # flush the interfaces individually
2759             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2760
2761             # check we haven't flushed that which we shouldn't
2762             for n in range(N_HOSTS):
2763                 self.assertTrue(
2764                     find_nbr(
2765                         self,
2766                         self.pg1.sw_if_index,
2767                         self.pg1.remote_hosts[n].ip6,
2768                         is_static=s,
2769                     )
2770                 )
2771
2772             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2773
2774             for n in range(N_HOSTS):
2775                 self.assertFalse(
2776                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2777                 )
2778                 self.assertFalse(
2779                     find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2780                 )
2781
2782             # add the nieghbours back
2783             for n in range(N_HOSTS):
2784                 VppNeighbor(
2785                     self,
2786                     self.pg0.sw_if_index,
2787                     self.pg0.remote_hosts[n].mac,
2788                     self.pg0.remote_hosts[n].ip4,
2789                     is_static=s,
2790                 ).add_vpp_config()
2791                 VppNeighbor(
2792                     self,
2793                     self.pg1.sw_if_index,
2794                     self.pg1.remote_hosts[n].mac,
2795                     self.pg1.remote_hosts[n].ip6,
2796                     is_static=s,
2797                 ).add_vpp_config()
2798
2799             self.logger.info(self.vapi.cli("sh ip neighbor"))
2800
2801             # flush both interfaces at the same time
2802             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2803
2804             # check we haven't flushed that which we shouldn't
2805             for n in range(N_HOSTS):
2806                 self.assertTrue(
2807                     find_nbr(
2808                         self,
2809                         self.pg0.sw_if_index,
2810                         self.pg0.remote_hosts[n].ip4,
2811                         is_static=s,
2812                     )
2813                 )
2814
2815             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2816
2817             for n in range(N_HOSTS):
2818                 self.assertFalse(
2819                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2820                 )
2821                 self.assertFalse(
2822                     find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2823                 )
2824
2825
2826 if __name__ == "__main__":
2827     unittest.main(testRunner=VppTestRunner)