arp: Use the new style error count declaration
[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
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         for op in ["is-at", "who-has"]:
1766             p1 = [
1767                 (
1768                     Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1769                     / ARP(
1770                         op=op,
1771                         hwdst=self.pg2.local_mac,
1772                         hwsrc=self.pg2.remote_hosts[1].mac,
1773                         pdst=self.pg2.remote_hosts[1].ip4,
1774                         psrc=self.pg2.remote_hosts[1].ip4,
1775                     )
1776                 ),
1777                 (
1778                     Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_hosts[1].mac)
1779                     / ARP(
1780                         op=op,
1781                         hwdst="ff:ff:ff:ff:ff:ff",
1782                         hwsrc=self.pg2.remote_hosts[1].mac,
1783                         pdst=self.pg2.remote_hosts[1].ip4,
1784                         psrc=self.pg2.remote_hosts[1].ip4,
1785                     )
1786                 ),
1787             ]
1788
1789             self.send_and_assert_no_replies(self.pg1, p1)
1790             self.assertFalse(
1791                 find_nbr(self, self.pg1.sw_if_index, self.pg2.remote_hosts[1].ip4)
1792             )
1793
1794         # they are all dropped because the subnet's don't match
1795         self.assertEqual(
1796             4,
1797             self.statistics.get_err_counter("/err/arp-reply/l3_dst_address_not_local"),
1798         )
1799
1800     def test_arp_incomplete2(self):
1801         """Incomplete Entries"""
1802
1803         #
1804         # ensure that we throttle the ARP and ND requests
1805         #
1806         self.pg0.generate_remote_hosts(2)
1807
1808         #
1809         # IPv4/ARP
1810         #
1811         ip_10_0_0_1 = VppIpRoute(
1812             self,
1813             "10.0.0.1",
1814             32,
1815             [VppRoutePath(self.pg0.remote_hosts[1].ip4, self.pg0.sw_if_index)],
1816         )
1817         ip_10_0_0_1.add_vpp_config()
1818
1819         p1 = (
1820             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1821             / IP(src=self.pg1.remote_ip4, dst="10.0.0.1")
1822             / UDP(sport=1234, dport=1234)
1823             / Raw()
1824         )
1825
1826         self.pg1.add_stream(p1 * 257)
1827         self.pg_enable_capture(self.pg_interfaces)
1828         self.pg_start()
1829         rx = self.pg0._get_capture(1)
1830
1831         #
1832         # how many we get is going to be dependent on the time for packet
1833         # processing but it should be small
1834         #
1835         self.assertLess(len(rx), 64)
1836
1837         #
1838         # IPv6/ND
1839         #
1840         ip_10_1 = VppIpRoute(
1841             self,
1842             "10::1",
1843             128,
1844             [
1845                 VppRoutePath(
1846                     self.pg0.remote_hosts[1].ip6,
1847                     self.pg0.sw_if_index,
1848                     proto=DpoProto.DPO_PROTO_IP6,
1849                 )
1850             ],
1851         )
1852         ip_10_1.add_vpp_config()
1853
1854         p1 = (
1855             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1856             / IPv6(src=self.pg1.remote_ip6, dst="10::1")
1857             / UDP(sport=1234, dport=1234)
1858             / Raw()
1859         )
1860
1861         self.pg1.add_stream(p1 * 257)
1862         self.pg_enable_capture(self.pg_interfaces)
1863         self.pg_start()
1864         rx = self.pg0._get_capture(1)
1865
1866         #
1867         # how many we get is going to be dependent on the time for packet
1868         # processing but it should be small
1869         #
1870         self.assertLess(len(rx), 64)
1871
1872     def test_arp_forus(self):
1873         """ARP for for-us"""
1874
1875         #
1876         # Test that VPP responds with ARP requests to addresses that
1877         # are connected and local routes.
1878         # Use one of the 'remote' addresses in the subnet as a local address
1879         # The intention of this route is that it then acts like a secondary
1880         # address added to an interface
1881         #
1882         self.pg0.generate_remote_hosts(2)
1883
1884         forus = VppIpRoute(
1885             self,
1886             self.pg0.remote_hosts[1].ip4,
1887             32,
1888             [
1889                 VppRoutePath(
1890                     "0.0.0.0",
1891                     self.pg0.sw_if_index,
1892                     type=FibPathType.FIB_PATH_TYPE_LOCAL,
1893                 )
1894             ],
1895         )
1896         forus.add_vpp_config()
1897
1898         p = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
1899             op="who-has",
1900             hwdst=self.pg0.local_mac,
1901             hwsrc=self.pg0.remote_mac,
1902             pdst=self.pg0.remote_hosts[1].ip4,
1903             psrc=self.pg0.remote_ip4,
1904         )
1905
1906         rx = self.send_and_expect(self.pg0, [p], self.pg0)
1907
1908         self.verify_arp_resp(
1909             rx[0],
1910             self.pg0.local_mac,
1911             self.pg0.remote_mac,
1912             self.pg0.remote_hosts[1].ip4,
1913             self.pg0.remote_ip4,
1914         )
1915
1916     def test_arp_table_swap(self):
1917         #
1918         # Generate some hosts on the LAN
1919         #
1920         N_NBRS = 4
1921         self.pg1.generate_remote_hosts(N_NBRS)
1922
1923         for n in range(N_NBRS):
1924             # a route thru each neighbour
1925             VppIpRoute(
1926                 self,
1927                 "10.0.0.%d" % n,
1928                 32,
1929                 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
1930             ).add_vpp_config()
1931
1932             # resolve each neighbour
1933             p1 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / ARP(
1934                 op="is-at",
1935                 hwdst=self.pg1.local_mac,
1936                 hwsrc="00:00:5e:00:01:09",
1937                 pdst=self.pg1.local_ip4,
1938                 psrc=self.pg1.remote_hosts[n].ip4,
1939             )
1940
1941             self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1942
1943         self.logger.info(self.vapi.cli("sh ip neighbors"))
1944
1945         #
1946         # swap the table pg1 is in
1947         #
1948         table = VppIpTable(self, 100).add_vpp_config()
1949
1950         self.pg1.unconfig_ip4()
1951         self.pg1.set_table_ip4(100)
1952         self.pg1.config_ip4()
1953
1954         #
1955         # all neighbours are cleared
1956         #
1957         for n in range(N_NBRS):
1958             self.assertFalse(
1959                 find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip4)
1960             )
1961
1962         #
1963         # packets to all neighbours generate ARP requests
1964         #
1965         for n in range(N_NBRS):
1966             # a route thru each neighbour
1967             VppIpRoute(
1968                 self,
1969                 "10.0.0.%d" % n,
1970                 32,
1971                 [VppRoutePath(self.pg1.remote_hosts[n].ip4, self.pg1.sw_if_index)],
1972                 table_id=100,
1973             ).add_vpp_config()
1974
1975             p = (
1976                 Ether(src=self.pg1.remote_hosts[n].mac, dst=self.pg1.local_mac)
1977                 / IP(src=self.pg1.remote_hosts[n].ip4, dst="10.0.0.%d" % n)
1978                 / Raw(b"0x5" * 100)
1979             )
1980             rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1981             for rx in rxs:
1982                 self.verify_arp_req(
1983                     rx,
1984                     self.pg1.local_mac,
1985                     self.pg1.local_ip4,
1986                     self.pg1.remote_hosts[n].ip4,
1987                 )
1988
1989         self.pg1.unconfig_ip4()
1990         self.pg1.set_table_ip4(0)
1991
1992     def test_glean_src_select(self):
1993         """Multi Connecteds"""
1994
1995         #
1996         # configure multiple connected subnets on an interface
1997         # and ensure that ARP requests for hosts on those subnets
1998         # pick up the correct source address
1999         #
2000         conn1 = VppIpInterfaceAddress(self, self.pg1, "10.0.0.1", 24).add_vpp_config()
2001         conn2 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.1", 24).add_vpp_config()
2002
2003         p1 = (
2004             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2005             / IP(src=self.pg1.remote_ip4, dst="10.0.0.128")
2006             / Raw(b"0x5" * 100)
2007         )
2008
2009         rxs = self.send_and_expect(self.pg0, [p1], self.pg1)
2010         for rx in rxs:
2011             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.0.1", "10.0.0.128")
2012
2013         p2 = (
2014             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2015             / IP(src=self.pg1.remote_ip4, dst="10.0.1.128")
2016             / Raw(b"0x5" * 100)
2017         )
2018
2019         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2020         for rx in rxs:
2021             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2022
2023         #
2024         # add a local address in the same subnet
2025         #  the source addresses are equivalent. VPP happens to
2026         #  choose the last one that was added
2027         conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2028
2029         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2030         for rx in rxs:
2031             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2032
2033         #
2034         # remove
2035         #
2036         conn3.remove_vpp_config()
2037         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2038         for rx in rxs:
2039             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.1", "10.0.1.128")
2040
2041         #
2042         # add back, this time remove the first one
2043         #
2044         conn3 = VppIpInterfaceAddress(self, self.pg1, "10.0.1.2", 24).add_vpp_config()
2045
2046         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2047         for rx in rxs:
2048             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2049
2050         conn1.remove_vpp_config()
2051         rxs = self.send_and_expect(self.pg0, [p2], self.pg1)
2052         for rx in rxs:
2053             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2054
2055         # apply a connected prefix to an interface in a different table
2056         VppIpRoute(
2057             self,
2058             "10.0.1.0",
2059             24,
2060             [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
2061             table_id=1,
2062         ).add_vpp_config()
2063
2064         rxs = self.send_and_expect(self.pg3, [p2], self.pg1)
2065         for rx in rxs:
2066             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
2067
2068         # cleanup
2069         conn3.remove_vpp_config()
2070         conn2.remove_vpp_config()
2071
2072
2073 @tag_fixme_vpp_workers
2074 class NeighborStatsTestCase(VppTestCase):
2075     """ARP/ND Counters"""
2076
2077     @classmethod
2078     def setUpClass(cls):
2079         super(NeighborStatsTestCase, cls).setUpClass()
2080
2081     @classmethod
2082     def tearDownClass(cls):
2083         super(NeighborStatsTestCase, cls).tearDownClass()
2084
2085     def setUp(self):
2086         super(NeighborStatsTestCase, self).setUp()
2087
2088         self.create_pg_interfaces(range(2))
2089
2090         # pg0 configured with ip4 and 6 addresses used for input
2091         # pg1 configured with ip4 and 6 addresses used for output
2092         # pg2 is unnumbered to pg0
2093         for i in self.pg_interfaces:
2094             i.admin_up()
2095             i.config_ip4()
2096             i.config_ip6()
2097             i.resolve_arp()
2098             i.resolve_ndp()
2099
2100     def tearDown(self):
2101         super(NeighborStatsTestCase, self).tearDown()
2102
2103         for i in self.pg_interfaces:
2104             i.unconfig_ip4()
2105             i.unconfig_ip6()
2106             i.admin_down()
2107
2108     def test_arp_stats(self):
2109         """ARP Counters"""
2110
2111         self.vapi.cli("adj counters enable")
2112         self.pg1.generate_remote_hosts(2)
2113
2114         arp1 = VppNeighbor(
2115             self,
2116             self.pg1.sw_if_index,
2117             self.pg1.remote_hosts[0].mac,
2118             self.pg1.remote_hosts[0].ip4,
2119         )
2120         arp1.add_vpp_config()
2121         arp2 = VppNeighbor(
2122             self,
2123             self.pg1.sw_if_index,
2124             self.pg1.remote_hosts[1].mac,
2125             self.pg1.remote_hosts[1].ip4,
2126         )
2127         arp2.add_vpp_config()
2128
2129         p1 = (
2130             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2131             / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[0].ip4)
2132             / UDP(sport=1234, dport=1234)
2133             / Raw()
2134         )
2135         p2 = (
2136             Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2137             / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4)
2138             / UDP(sport=1234, dport=1234)
2139             / Raw()
2140         )
2141
2142         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2143         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
2144
2145         self.assertEqual(NUM_PKTS, arp1.get_stats()["packets"])
2146         self.assertEqual(NUM_PKTS, arp2.get_stats()["packets"])
2147
2148         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
2149         self.assertEqual(NUM_PKTS * 2, arp1.get_stats()["packets"])
2150
2151     def test_nd_stats(self):
2152         """ND Counters"""
2153
2154         self.vapi.cli("adj counters enable")
2155         self.pg0.generate_remote_hosts(3)
2156
2157         nd1 = VppNeighbor(
2158             self,
2159             self.pg0.sw_if_index,
2160             self.pg0.remote_hosts[1].mac,
2161             self.pg0.remote_hosts[1].ip6,
2162         )
2163         nd1.add_vpp_config()
2164         nd2 = VppNeighbor(
2165             self,
2166             self.pg0.sw_if_index,
2167             self.pg0.remote_hosts[2].mac,
2168             self.pg0.remote_hosts[2].ip6,
2169         )
2170         nd2.add_vpp_config()
2171
2172         p1 = (
2173             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2174             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[1].ip6)
2175             / UDP(sport=1234, dport=1234)
2176             / Raw()
2177         )
2178         p2 = (
2179             Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
2180             / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.remote_hosts[2].ip6)
2181             / UDP(sport=1234, dport=1234)
2182             / Raw()
2183         )
2184
2185         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
2186         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
2187
2188         self.assertEqual(16, nd1.get_stats()["packets"])
2189         self.assertEqual(16, nd2.get_stats()["packets"])
2190
2191         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
2192         self.assertEqual(NUM_PKTS + 16, nd1.get_stats()["packets"])
2193
2194
2195 class NeighborAgeTestCase(VppTestCase):
2196     """ARP/ND Aging"""
2197
2198     @classmethod
2199     def setUpClass(cls):
2200         super(NeighborAgeTestCase, cls).setUpClass()
2201
2202     @classmethod
2203     def tearDownClass(cls):
2204         super(NeighborAgeTestCase, cls).tearDownClass()
2205
2206     def setUp(self):
2207         super(NeighborAgeTestCase, self).setUp()
2208
2209         self.create_pg_interfaces(range(1))
2210
2211         # pg0 configured with ip4 and 6 addresses used for input
2212         # pg1 configured with ip4 and 6 addresses used for output
2213         # pg2 is unnumbered to pg0
2214         for i in self.pg_interfaces:
2215             i.admin_up()
2216             i.config_ip4()
2217             i.config_ip6()
2218             i.resolve_arp()
2219             i.resolve_ndp()
2220
2221     def tearDown(self):
2222         super(NeighborAgeTestCase, self).tearDown()
2223
2224         for i in self.pg_interfaces:
2225             i.unconfig_ip4()
2226             i.unconfig_ip6()
2227             i.admin_down()
2228
2229     def verify_arp_req(self, rx, smac, sip, dip):
2230         ether = rx[Ether]
2231         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2232         self.assertEqual(ether.src, smac)
2233
2234         arp = rx[ARP]
2235         self.assertEqual(arp.hwtype, 1)
2236         self.assertEqual(arp.ptype, 0x800)
2237         self.assertEqual(arp.hwlen, 6)
2238         self.assertEqual(arp.plen, 4)
2239         self.assertEqual(arp.op, arp_opts["who-has"])
2240         self.assertEqual(arp.hwsrc, smac)
2241         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2242         self.assertEqual(arp.psrc, sip)
2243         self.assertEqual(arp.pdst, dip)
2244
2245     def test_age(self):
2246         """Aging/Recycle"""
2247
2248         self.vapi.cli("set logging unthrottle 0")
2249         self.vapi.cli("set logging size %d" % 0xFFFF)
2250
2251         self.pg0.generate_remote_hosts(201)
2252
2253         vaf = VppEnum.vl_api_address_family_t
2254
2255         #
2256         # start listening on all interfaces
2257         #
2258         self.pg_enable_capture(self.pg_interfaces)
2259
2260         #
2261         # Set the neighbor configuration:
2262         #   limi = 200
2263         #   age  = 0 seconds
2264         #   recycle = false
2265         #
2266         self.vapi.ip_neighbor_config(
2267             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2268         )
2269
2270         self.vapi.cli("sh ip neighbor-config")
2271
2272         # add the 198 neighbours that should pass (-1 for one created in setup)
2273         for ii in range(200):
2274             VppNeighbor(
2275                 self,
2276                 self.pg0.sw_if_index,
2277                 self.pg0.remote_hosts[ii].mac,
2278                 self.pg0.remote_hosts[ii].ip4,
2279             ).add_vpp_config()
2280
2281         # one more neighbor over the limit should fail
2282         with self.vapi.assert_negative_api_retval():
2283             VppNeighbor(
2284                 self,
2285                 self.pg0.sw_if_index,
2286                 self.pg0.remote_hosts[200].mac,
2287                 self.pg0.remote_hosts[200].ip4,
2288             ).add_vpp_config()
2289
2290         #
2291         # change the config to allow recycling the old neighbors
2292         #
2293         self.vapi.ip_neighbor_config(
2294             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=True
2295         )
2296
2297         # now new additions are allowed
2298         VppNeighbor(
2299             self,
2300             self.pg0.sw_if_index,
2301             self.pg0.remote_hosts[200].mac,
2302             self.pg0.remote_hosts[200].ip4,
2303         ).add_vpp_config()
2304
2305         # add the first neighbor we configured has been re-used
2306         self.assertFalse(
2307             find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2308         )
2309         self.assertTrue(
2310             find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[200].ip4)
2311         )
2312
2313         #
2314         # change the config to age old neighbors
2315         #
2316         self.vapi.ip_neighbor_config(
2317             af=vaf.ADDRESS_IP4, max_number=200, max_age=2, recycle=True
2318         )
2319
2320         self.vapi.cli("sh ip4 neighbor-sorted")
2321
2322         # age out neighbors
2323         self.virtual_sleep(3)
2324
2325         #
2326         # expect probes from all these ARP entries as they age
2327         # 3 probes for each neighbor 3*200 = 600
2328         rxs = self.pg0.get_capture(600, timeout=2)
2329
2330         for ii in range(3):
2331             for jj in range(200):
2332                 rx = rxs[ii * 200 + jj]
2333                 # rx.show()
2334
2335         #
2336         # 3 probes sent then 1 more second to see if a reply comes, before
2337         # they age out
2338         #
2339         self.virtual_sleep(1)
2340
2341         self.assertFalse(
2342             self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2343         )
2344
2345         #
2346         # load up some neighbours again with 2s aging enabled
2347         # they should be removed after 10s (2s age + 4s for probes + gap)
2348         # check for the add and remove events
2349         #
2350         enum = VppEnum.vl_api_ip_neighbor_event_flags_t
2351
2352         self.vapi.want_ip_neighbor_events_v2(enable=1)
2353         for ii in range(10):
2354             VppNeighbor(
2355                 self,
2356                 self.pg0.sw_if_index,
2357                 self.pg0.remote_hosts[ii].mac,
2358                 self.pg0.remote_hosts[ii].ip4,
2359             ).add_vpp_config()
2360
2361             e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2362             self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_ADDED)
2363             self.assertEqual(str(e.neighbor.ip_address), self.pg0.remote_hosts[ii].ip4)
2364             self.assertEqual(e.neighbor.mac_address, self.pg0.remote_hosts[ii].mac)
2365
2366         self.virtual_sleep(10)
2367         self.assertFalse(
2368             self.vapi.ip_neighbor_dump(sw_if_index=0xFFFFFFFF, af=vaf.ADDRESS_IP4)
2369         )
2370
2371         evs = []
2372         for ii in range(10):
2373             e = self.vapi.wait_for_event(1, "ip_neighbor_event_v2")
2374             self.assertEqual(e.flags, enum.IP_NEIGHBOR_API_EVENT_FLAG_REMOVED)
2375             evs.append(e)
2376
2377         # check we got the correct mac/ip pairs - done separately
2378         # because we don't care about the order the remove notifications
2379         # arrive
2380         for ii in range(10):
2381             found = False
2382             mac = self.pg0.remote_hosts[ii].mac
2383             ip = self.pg0.remote_hosts[ii].ip4
2384
2385             for e in evs:
2386                 if e.neighbor.mac_address == mac and str(e.neighbor.ip_address) == ip:
2387                     found = True
2388                     break
2389             self.assertTrue(found)
2390
2391         #
2392         # check if we can set age and recycle with empty neighbor list
2393         #
2394         self.vapi.ip_neighbor_config(
2395             af=vaf.ADDRESS_IP4, max_number=200, max_age=1000, recycle=True
2396         )
2397
2398         #
2399         # load up some neighbours again, then disable the aging
2400         # they should still be there in 10 seconds time
2401         #
2402         for ii in range(10):
2403             VppNeighbor(
2404                 self,
2405                 self.pg0.sw_if_index,
2406                 self.pg0.remote_hosts[ii].mac,
2407                 self.pg0.remote_hosts[ii].ip4,
2408             ).add_vpp_config()
2409         self.vapi.ip_neighbor_config(
2410             af=vaf.ADDRESS_IP4, max_number=200, max_age=0, recycle=False
2411         )
2412
2413         self.virtual_sleep(10)
2414         self.assertTrue(
2415             find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[0].ip4)
2416         )
2417
2418
2419 class NeighborReplaceTestCase(VppTestCase):
2420     """ARP/ND Replacement"""
2421
2422     @classmethod
2423     def setUpClass(cls):
2424         super(NeighborReplaceTestCase, cls).setUpClass()
2425
2426     @classmethod
2427     def tearDownClass(cls):
2428         super(NeighborReplaceTestCase, cls).tearDownClass()
2429
2430     def setUp(self):
2431         super(NeighborReplaceTestCase, self).setUp()
2432
2433         self.create_pg_interfaces(range(4))
2434
2435         # pg0 configured with ip4 and 6 addresses used for input
2436         # pg1 configured with ip4 and 6 addresses used for output
2437         # pg2 is unnumbered to pg0
2438         for i in self.pg_interfaces:
2439             i.admin_up()
2440             i.config_ip4()
2441             i.config_ip6()
2442             i.resolve_arp()
2443             i.resolve_ndp()
2444
2445     def tearDown(self):
2446         super(NeighborReplaceTestCase, self).tearDown()
2447
2448         for i in self.pg_interfaces:
2449             i.unconfig_ip4()
2450             i.unconfig_ip6()
2451             i.admin_down()
2452
2453     def test_replace(self):
2454         """replace"""
2455
2456         N_HOSTS = 16
2457
2458         for i in self.pg_interfaces:
2459             i.generate_remote_hosts(N_HOSTS)
2460             i.configure_ipv4_neighbors()
2461             i.configure_ipv6_neighbors()
2462
2463         # replace them all
2464         self.vapi.ip_neighbor_replace_begin()
2465         self.vapi.ip_neighbor_replace_end()
2466
2467         for i in self.pg_interfaces:
2468             for h in range(N_HOSTS):
2469                 self.assertFalse(
2470                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip4)
2471                 )
2472                 self.assertFalse(
2473                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[h].ip6)
2474                 )
2475
2476         #
2477         # and them all back via the API
2478         #
2479         for i in self.pg_interfaces:
2480             for h in range(N_HOSTS):
2481                 VppNeighbor(
2482                     self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip4
2483                 ).add_vpp_config()
2484                 VppNeighbor(
2485                     self, i.sw_if_index, i.remote_hosts[h].mac, i.remote_hosts[h].ip6
2486                 ).add_vpp_config()
2487
2488         #
2489         # begin the replacement again, this time touch some
2490         # the neighbours on pg1 so they are not deleted
2491         #
2492         self.vapi.ip_neighbor_replace_begin()
2493
2494         # update from the API all neighbours on pg1
2495         for h in range(N_HOSTS):
2496             VppNeighbor(
2497                 self,
2498                 self.pg1.sw_if_index,
2499                 self.pg1.remote_hosts[h].mac,
2500                 self.pg1.remote_hosts[h].ip4,
2501             ).add_vpp_config()
2502             VppNeighbor(
2503                 self,
2504                 self.pg1.sw_if_index,
2505                 self.pg1.remote_hosts[h].mac,
2506                 self.pg1.remote_hosts[h].ip6,
2507             ).add_vpp_config()
2508
2509         # update from the data-plane all neighbours on pg3
2510         self.pg3.configure_ipv4_neighbors()
2511         self.pg3.configure_ipv6_neighbors()
2512
2513         # complete the replacement
2514         self.logger.info(self.vapi.cli("sh ip neighbors"))
2515         self.vapi.ip_neighbor_replace_end()
2516
2517         for i in self.pg_interfaces:
2518             if i == self.pg1 or i == self.pg3:
2519                 # neighbours on pg1 and pg3 are still present
2520                 for h in range(N_HOSTS):
2521                     self.assertTrue(
2522                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2523                     )
2524                     self.assertTrue(
2525                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2526                     )
2527             else:
2528                 # all other neighbours are toast
2529                 for h in range(N_HOSTS):
2530                     self.assertFalse(
2531                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip4)
2532                     )
2533                     self.assertFalse(
2534                         find_nbr(self, i.sw_if_index, i.remote_hosts[h].ip6)
2535                     )
2536
2537
2538 class NeighborFlush(VppTestCase):
2539     """Neighbor Flush"""
2540
2541     @classmethod
2542     def setUpClass(cls):
2543         super(NeighborFlush, cls).setUpClass()
2544
2545     @classmethod
2546     def tearDownClass(cls):
2547         super(NeighborFlush, cls).tearDownClass()
2548
2549     def setUp(self):
2550         super(NeighborFlush, self).setUp()
2551
2552         self.create_pg_interfaces(range(2))
2553
2554         for i in self.pg_interfaces:
2555             i.admin_up()
2556             i.config_ip4()
2557             i.config_ip6()
2558             i.resolve_arp()
2559             i.resolve_ndp()
2560
2561     def tearDown(self):
2562         super(NeighborFlush, self).tearDown()
2563
2564         for i in self.pg_interfaces:
2565             i.unconfig_ip4()
2566             i.unconfig_ip6()
2567             i.admin_down()
2568
2569     def test_flush(self):
2570         """Neighbour Flush"""
2571
2572         e = VppEnum
2573         nf = e.vl_api_ip_neighbor_flags_t
2574         af = e.vl_api_address_family_t
2575         N_HOSTS = 16
2576         static = [False, True]
2577         self.pg0.generate_remote_hosts(N_HOSTS)
2578         self.pg1.generate_remote_hosts(N_HOSTS)
2579
2580         for s in static:
2581             # a few v4 and v6 dynamic neoghbors
2582             for n in range(N_HOSTS):
2583                 VppNeighbor(
2584                     self,
2585                     self.pg0.sw_if_index,
2586                     self.pg0.remote_hosts[n].mac,
2587                     self.pg0.remote_hosts[n].ip4,
2588                     is_static=s,
2589                 ).add_vpp_config()
2590                 VppNeighbor(
2591                     self,
2592                     self.pg1.sw_if_index,
2593                     self.pg1.remote_hosts[n].mac,
2594                     self.pg1.remote_hosts[n].ip6,
2595                     is_static=s,
2596                 ).add_vpp_config()
2597
2598             # flush the interfaces individually
2599             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, self.pg0.sw_if_index)
2600
2601             # check we haven't flushed that which we shouldn't
2602             for n in range(N_HOSTS):
2603                 self.assertTrue(
2604                     find_nbr(
2605                         self,
2606                         self.pg1.sw_if_index,
2607                         self.pg1.remote_hosts[n].ip6,
2608                         is_static=s,
2609                     )
2610                 )
2611
2612             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, self.pg1.sw_if_index)
2613
2614             for n in range(N_HOSTS):
2615                 self.assertFalse(
2616                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2617                 )
2618                 self.assertFalse(
2619                     find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2620                 )
2621
2622             # add the nieghbours back
2623             for n in range(N_HOSTS):
2624                 VppNeighbor(
2625                     self,
2626                     self.pg0.sw_if_index,
2627                     self.pg0.remote_hosts[n].mac,
2628                     self.pg0.remote_hosts[n].ip4,
2629                     is_static=s,
2630                 ).add_vpp_config()
2631                 VppNeighbor(
2632                     self,
2633                     self.pg1.sw_if_index,
2634                     self.pg1.remote_hosts[n].mac,
2635                     self.pg1.remote_hosts[n].ip6,
2636                     is_static=s,
2637                 ).add_vpp_config()
2638
2639             self.logger.info(self.vapi.cli("sh ip neighbor"))
2640
2641             # flush both interfaces at the same time
2642             self.vapi.ip_neighbor_flush(af.ADDRESS_IP6, 0xFFFFFFFF)
2643
2644             # check we haven't flushed that which we shouldn't
2645             for n in range(N_HOSTS):
2646                 self.assertTrue(
2647                     find_nbr(
2648                         self,
2649                         self.pg0.sw_if_index,
2650                         self.pg0.remote_hosts[n].ip4,
2651                         is_static=s,
2652                     )
2653                 )
2654
2655             self.vapi.ip_neighbor_flush(af.ADDRESS_IP4, 0xFFFFFFFF)
2656
2657             for n in range(N_HOSTS):
2658                 self.assertFalse(
2659                     find_nbr(self, self.pg0.sw_if_index, self.pg0.remote_hosts[n].ip4)
2660                 )
2661                 self.assertFalse(
2662                     find_nbr(self, self.pg1.sw_if_index, self.pg1.remote_hosts[n].ip6)
2663                 )
2664
2665
2666 if __name__ == "__main__":
2667     unittest.main(testRunner=VppTestRunner)