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