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