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