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