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