ip-neighbor: Replace feature for the ip-neighbor data-base
[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
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         self.pg2.add_stream(arp_req_from_me)
781         self.pg_enable_capture(self.pg_interfaces)
782         self.pg_start()
783
784         rx = self.pg2.get_capture(1)
785         self.verify_arp_resp(rx[0],
786                              self.pg2.local_mac,
787                              self.pg2.remote_mac,
788                              self.pg0.remote_hosts[1].ip4,
789                              self.pg0.local_ip4)
790
791         #
792         # validate we have not learned an ARP entry as a result of this
793         #
794         self.assertFalse(find_nbr(self,
795                                   self.pg2.sw_if_index,
796                                   self.pg0.local_ip4))
797
798         #
799         # cleanup
800         #
801         self.pg2.set_proxy_arp(0)
802         self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
803                                     self.pg0._local_ip4_bcast,
804                                     is_add=0)
805
806     def test_proxy_arp(self):
807         """ Proxy ARP """
808
809         self.pg1.generate_remote_hosts(2)
810
811         #
812         # Proxy ARP request packets for each interface
813         #
814         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
815                              dst="ff:ff:ff:ff:ff:ff") /
816                        ARP(op="who-has",
817                            hwsrc=self.pg0.remote_mac,
818                            pdst="10.10.10.3",
819                            psrc=self.pg0.remote_ip4))
820         arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
821                                     dst="ff:ff:ff:ff:ff:ff") /
822                               Dot1Q(vlan=0) /
823                               ARP(op="who-has",
824                                   hwsrc=self.pg0.remote_mac,
825                                   pdst="10.10.10.3",
826                                   psrc=self.pg0.remote_ip4))
827         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
828                              dst="ff:ff:ff:ff:ff:ff") /
829                        ARP(op="who-has",
830                            hwsrc=self.pg1.remote_mac,
831                            pdst="10.10.10.3",
832                            psrc=self.pg1.remote_ip4))
833         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
834                              dst="ff:ff:ff:ff:ff:ff") /
835                        ARP(op="who-has",
836                            hwsrc=self.pg2.remote_mac,
837                            pdst="10.10.10.3",
838                            psrc=self.pg1.remote_hosts[1].ip4))
839         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
840                              dst="ff:ff:ff:ff:ff:ff") /
841                        ARP(op="who-has",
842                            hwsrc=self.pg3.remote_mac,
843                            pdst="10.10.10.3",
844                            psrc=self.pg3.remote_ip4))
845
846         #
847         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
848         #
849         self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
850                                     inet_pton(AF_INET, "10.10.10.124"))
851
852         #
853         # No responses are sent when the interfaces are not enabled for proxy
854         # ARP
855         #
856         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
857                                         "ARP req from unconfigured interface")
858         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
859                                         "ARP req from unconfigured interface")
860
861         #
862         # Make pg2 un-numbered to pg1
863         #  still won't reply.
864         #
865         self.pg2.set_unnumbered(self.pg1.sw_if_index)
866
867         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
868                                         "ARP req from unnumbered interface")
869
870         #
871         # Enable each interface to reply to proxy ARPs
872         #
873         for i in self.pg_interfaces:
874             i.set_proxy_arp()
875
876         #
877         # Now each of the interfaces should reply to a request to a proxied
878         # address
879         #
880         self.pg0.add_stream(arp_req_pg0)
881         self.pg_enable_capture(self.pg_interfaces)
882         self.pg_start()
883
884         rx = self.pg0.get_capture(1)
885         self.verify_arp_resp(rx[0],
886                              self.pg0.local_mac,
887                              self.pg0.remote_mac,
888                              "10.10.10.3",
889                              self.pg0.remote_ip4)
890
891         self.pg0.add_stream(arp_req_pg0_tagged)
892         self.pg_enable_capture(self.pg_interfaces)
893         self.pg_start()
894
895         rx = self.pg0.get_capture(1)
896         self.verify_arp_resp(rx[0],
897                              self.pg0.local_mac,
898                              self.pg0.remote_mac,
899                              "10.10.10.3",
900                              self.pg0.remote_ip4)
901
902         self.pg1.add_stream(arp_req_pg1)
903         self.pg_enable_capture(self.pg_interfaces)
904         self.pg_start()
905
906         rx = self.pg1.get_capture(1)
907         self.verify_arp_resp(rx[0],
908                              self.pg1.local_mac,
909                              self.pg1.remote_mac,
910                              "10.10.10.3",
911                              self.pg1.remote_ip4)
912
913         self.pg2.add_stream(arp_req_pg2)
914         self.pg_enable_capture(self.pg_interfaces)
915         self.pg_start()
916
917         rx = self.pg2.get_capture(1)
918         self.verify_arp_resp(rx[0],
919                              self.pg2.local_mac,
920                              self.pg2.remote_mac,
921                              "10.10.10.3",
922                              self.pg1.remote_hosts[1].ip4)
923
924         #
925         # A request for an address out of the configured range
926         #
927         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
928                                 dst="ff:ff:ff:ff:ff:ff") /
929                           ARP(op="who-has",
930                               hwsrc=self.pg1.remote_mac,
931                               pdst="10.10.10.125",
932                               psrc=self.pg1.remote_ip4))
933         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
934                                         "ARP req out of range HI")
935         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
936                                  dst="ff:ff:ff:ff:ff:ff") /
937                            ARP(op="who-has",
938                                hwsrc=self.pg1.remote_mac,
939                                pdst="10.10.10.1",
940                                psrc=self.pg1.remote_ip4))
941         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
942                                         "ARP req out of range Low")
943
944         #
945         # Request for an address in the proxy range but from an interface
946         # in a different VRF
947         #
948         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
949                                         "ARP req from different VRF")
950
951         #
952         # Disable Each interface for proxy ARP
953         #  - expect none to respond
954         #
955         for i in self.pg_interfaces:
956             i.set_proxy_arp(0)
957
958         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
959                                         "ARP req from disable")
960         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
961                                         "ARP req from disable")
962         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
963                                         "ARP req from disable")
964
965         #
966         # clean up on interface 2
967         #
968         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
969
970     def test_mpls(self):
971         """ MPLS """
972
973         #
974         # Interface 2 does not yet have ip4 config
975         #
976         self.pg2.config_ip4()
977         self.pg2.generate_remote_hosts(2)
978
979         #
980         # Add a route with out going label via an ARP unresolved next-hop
981         #
982         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
983                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
984                                                self.pg2.sw_if_index,
985                                                labels=[55])])
986         ip_10_0_0_1.add_vpp_config()
987
988         #
989         # packets should generate an ARP request
990         #
991         p = (Ether(src=self.pg0.remote_mac,
992                    dst=self.pg0.local_mac) /
993              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
994              UDP(sport=1234, dport=1234) /
995              Raw(b'\xa5' * 100))
996
997         self.pg0.add_stream(p)
998         self.pg_enable_capture(self.pg_interfaces)
999         self.pg_start()
1000
1001         rx = self.pg2.get_capture(1)
1002         self.verify_arp_req(rx[0],
1003                             self.pg2.local_mac,
1004                             self.pg2.local_ip4,
1005                             self.pg2._remote_hosts[1].ip4)
1006
1007         #
1008         # now resolve the neighbours
1009         #
1010         self.pg2.configure_ipv4_neighbors()
1011
1012         #
1013         # Now packet should be properly MPLS encapped.
1014         #  This verifies that MPLS link-type adjacencies are completed
1015         #  when the ARP entry resolves
1016         #
1017         self.pg0.add_stream(p)
1018         self.pg_enable_capture(self.pg_interfaces)
1019         self.pg_start()
1020
1021         rx = self.pg2.get_capture(1)
1022         self.verify_ip_o_mpls(rx[0],
1023                               self.pg2.local_mac,
1024                               self.pg2.remote_hosts[1].mac,
1025                               55,
1026                               self.pg0.remote_ip4,
1027                               "10.0.0.1")
1028         self.pg2.unconfig_ip4()
1029
1030     def test_arp_vrrp(self):
1031         """ ARP reply with VRRP virtual src hw addr """
1032
1033         #
1034         # IP packet destined for pg1 remote host arrives on pg0 resulting
1035         # in an ARP request for the address of the remote host on pg1
1036         #
1037         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1038               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
1039               UDP(sport=1234, dport=1234) /
1040               Raw())
1041
1042         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1043
1044         self.verify_arp_req(rx1[0],
1045                             self.pg1.local_mac,
1046                             self.pg1.local_ip4,
1047                             self.pg1.remote_ip4)
1048
1049         #
1050         # ARP reply for address of pg1 remote host arrives on pg1 with
1051         # the hw src addr set to a value in the VRRP IPv4 range of
1052         # MAC addresses
1053         #
1054         p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1055               ARP(op="is-at", hwdst=self.pg1.local_mac,
1056                   hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1057                   psrc=self.pg1.remote_ip4))
1058
1059         self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1060
1061         #
1062         # IP packet destined for pg1 remote host arrives on pg0 again.
1063         # VPP should have an ARP entry for that address now and the packet
1064         # should be sent out pg1.
1065         #
1066         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1067
1068         self.verify_ip(rx1[0],
1069                        self.pg1.local_mac,
1070                        "00:00:5e:00:01:09",
1071                        self.pg0.remote_ip4,
1072                        self.pg1.remote_ip4)
1073
1074         self.pg1.admin_down()
1075         self.pg1.admin_up()
1076
1077     def test_arp_duplicates(self):
1078         """ ARP Duplicates"""
1079
1080         #
1081         # Generate some hosts on the LAN
1082         #
1083         self.pg1.generate_remote_hosts(3)
1084
1085         #
1086         # Add host 1 on pg1 and pg2
1087         #
1088         arp_pg1 = VppNeighbor(self,
1089                               self.pg1.sw_if_index,
1090                               self.pg1.remote_hosts[1].mac,
1091                               self.pg1.remote_hosts[1].ip4)
1092         arp_pg1.add_vpp_config()
1093         arp_pg2 = VppNeighbor(self,
1094                               self.pg2.sw_if_index,
1095                               self.pg2.remote_mac,
1096                               self.pg1.remote_hosts[1].ip4)
1097         arp_pg2.add_vpp_config()
1098
1099         #
1100         # IP packet destined for pg1 remote host arrives on pg1 again.
1101         #
1102         p = (Ether(dst=self.pg0.local_mac,
1103                    src=self.pg0.remote_mac) /
1104              IP(src=self.pg0.remote_ip4,
1105                 dst=self.pg1.remote_hosts[1].ip4) /
1106              UDP(sport=1234, dport=1234) /
1107              Raw())
1108
1109         self.pg0.add_stream(p)
1110         self.pg_enable_capture(self.pg_interfaces)
1111         self.pg_start()
1112
1113         rx1 = self.pg1.get_capture(1)
1114
1115         self.verify_ip(rx1[0],
1116                        self.pg1.local_mac,
1117                        self.pg1.remote_hosts[1].mac,
1118                        self.pg0.remote_ip4,
1119                        self.pg1.remote_hosts[1].ip4)
1120
1121         #
1122         # remove the duplicate on pg1
1123         # packet stream should generate ARPs out of pg1
1124         #
1125         arp_pg1.remove_vpp_config()
1126
1127         self.pg0.add_stream(p)
1128         self.pg_enable_capture(self.pg_interfaces)
1129         self.pg_start()
1130
1131         rx1 = self.pg1.get_capture(1)
1132
1133         self.verify_arp_req(rx1[0],
1134                             self.pg1.local_mac,
1135                             self.pg1.local_ip4,
1136                             self.pg1.remote_hosts[1].ip4)
1137
1138         #
1139         # Add it back
1140         #
1141         arp_pg1.add_vpp_config()
1142
1143         self.pg0.add_stream(p)
1144         self.pg_enable_capture(self.pg_interfaces)
1145         self.pg_start()
1146
1147         rx1 = self.pg1.get_capture(1)
1148
1149         self.verify_ip(rx1[0],
1150                        self.pg1.local_mac,
1151                        self.pg1.remote_hosts[1].mac,
1152                        self.pg0.remote_ip4,
1153                        self.pg1.remote_hosts[1].ip4)
1154
1155     def test_arp_static(self):
1156         """ ARP Static"""
1157         self.pg2.generate_remote_hosts(3)
1158
1159         #
1160         # Add a static ARP entry
1161         #
1162         static_arp = VppNeighbor(self,
1163                                  self.pg2.sw_if_index,
1164                                  self.pg2.remote_hosts[1].mac,
1165                                  self.pg2.remote_hosts[1].ip4,
1166                                  is_static=1)
1167         static_arp.add_vpp_config()
1168
1169         #
1170         # Add the connected prefix to the interface
1171         #
1172         self.pg2.config_ip4()
1173
1174         #
1175         # We should now find the adj-fib
1176         #
1177         self.assertTrue(find_nbr(self,
1178                                  self.pg2.sw_if_index,
1179                                  self.pg2.remote_hosts[1].ip4,
1180                                  is_static=1))
1181         self.assertTrue(find_route(self,
1182                                    self.pg2.remote_hosts[1].ip4,
1183                                    32))
1184
1185         #
1186         # remove the connected
1187         #
1188         self.pg2.unconfig_ip4()
1189
1190         #
1191         # put the interface into table 1
1192         #
1193         self.pg2.set_table_ip4(1)
1194
1195         #
1196         # configure the same connected and expect to find the
1197         # adj fib in the new table
1198         #
1199         self.pg2.config_ip4()
1200         self.assertTrue(find_route(self,
1201                                    self.pg2.remote_hosts[1].ip4,
1202                                    32,
1203                                    table_id=1))
1204
1205         #
1206         # clean-up
1207         #
1208         self.pg2.unconfig_ip4()
1209         static_arp.remove_vpp_config()
1210         self.pg2.set_table_ip4(0)
1211
1212     def test_arp_incomplete(self):
1213         """ ARP Incomplete"""
1214         self.pg1.generate_remote_hosts(3)
1215
1216         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1217               IP(src=self.pg0.remote_ip4,
1218                  dst=self.pg1.remote_hosts[1].ip4) /
1219               UDP(sport=1234, dport=1234) /
1220               Raw())
1221         p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1222               IP(src=self.pg0.remote_ip4,
1223                  dst=self.pg1.remote_hosts[2].ip4) /
1224               UDP(sport=1234, dport=1234) /
1225               Raw())
1226
1227         #
1228         # a packet to an unresolved destination generates an ARP request
1229         #
1230         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1231         self.verify_arp_req(rx[0],
1232                             self.pg1.local_mac,
1233                             self.pg1.local_ip4,
1234                             self.pg1._remote_hosts[1].ip4)
1235
1236         #
1237         # add a neighbour for remote host 1
1238         #
1239         static_arp = VppNeighbor(self,
1240                                  self.pg1.sw_if_index,
1241                                  self.pg1.remote_hosts[1].mac,
1242                                  self.pg1.remote_hosts[1].ip4,
1243                                  is_static=1)
1244         static_arp.add_vpp_config()
1245
1246         #
1247         # change the interface's MAC
1248         #
1249         mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1250                scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1251                scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1252         mac_string = ''.join(mac)
1253
1254         self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1255                                                mac_string)
1256
1257         #
1258         # now ARP requests come from the new source mac
1259         #
1260         rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1261         self.verify_arp_req(rx[0],
1262                             "00:00:00:33:33:33",
1263                             self.pg1.local_ip4,
1264                             self.pg1._remote_hosts[2].ip4)
1265
1266         #
1267         # packets to the resolved host also have the new source mac
1268         #
1269         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1270         self.verify_ip(rx[0],
1271                        "00:00:00:33:33:33",
1272                        self.pg1.remote_hosts[1].mac,
1273                        self.pg0.remote_ip4,
1274                        self.pg1.remote_hosts[1].ip4)
1275
1276         #
1277         # set the mac address on the interface that does not have a
1278         # configured subnet and thus no glean
1279         #
1280         self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1281                                                mac_string)
1282
1283     def test_garp(self):
1284         """ GARP """
1285
1286         #
1287         # Generate some hosts on the LAN
1288         #
1289         self.pg1.generate_remote_hosts(4)
1290
1291         #
1292         # And an ARP entry
1293         #
1294         arp = VppNeighbor(self,
1295                           self.pg1.sw_if_index,
1296                           self.pg1.remote_hosts[1].mac,
1297                           self.pg1.remote_hosts[1].ip4)
1298         arp.add_vpp_config()
1299
1300         self.assertTrue(find_nbr(self,
1301                                  self.pg1.sw_if_index,
1302                                  self.pg1.remote_hosts[1].ip4,
1303                                  mac=self.pg1.remote_hosts[1].mac))
1304
1305         #
1306         # Send a GARP (request) to swap the host 1's address to that of host 2
1307         #
1308         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1309                     src=self.pg1.remote_hosts[2].mac) /
1310               ARP(op="who-has",
1311                   hwdst=self.pg1.local_mac,
1312                   hwsrc=self.pg1.remote_hosts[2].mac,
1313                   pdst=self.pg1.remote_hosts[1].ip4,
1314                   psrc=self.pg1.remote_hosts[1].ip4))
1315
1316         self.pg1.add_stream(p1)
1317         self.pg_enable_capture(self.pg_interfaces)
1318         self.pg_start()
1319
1320         self.assertTrue(find_nbr(self,
1321                                  self.pg1.sw_if_index,
1322                                  self.pg1.remote_hosts[1].ip4,
1323                                  mac=self.pg1.remote_hosts[2].mac))
1324
1325         #
1326         # Send a GARP (reply) to swap the host 1's address to that of host 3
1327         #
1328         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1329                     src=self.pg1.remote_hosts[3].mac) /
1330               ARP(op="is-at",
1331                   hwdst=self.pg1.local_mac,
1332                   hwsrc=self.pg1.remote_hosts[3].mac,
1333                   pdst=self.pg1.remote_hosts[1].ip4,
1334                   psrc=self.pg1.remote_hosts[1].ip4))
1335
1336         self.pg1.add_stream(p1)
1337         self.pg_enable_capture(self.pg_interfaces)
1338         self.pg_start()
1339
1340         self.assertTrue(find_nbr(self,
1341                                  self.pg1.sw_if_index,
1342                                  self.pg1.remote_hosts[1].ip4,
1343                                  mac=self.pg1.remote_hosts[3].mac))
1344
1345         #
1346         # GARPs (request nor replies) for host we don't know yet
1347         # don't result in new neighbour entries
1348         #
1349         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1350                     src=self.pg1.remote_hosts[3].mac) /
1351               ARP(op="who-has",
1352                   hwdst=self.pg1.local_mac,
1353                   hwsrc=self.pg1.remote_hosts[3].mac,
1354                   pdst=self.pg1.remote_hosts[2].ip4,
1355                   psrc=self.pg1.remote_hosts[2].ip4))
1356
1357         self.pg1.add_stream(p1)
1358         self.pg_enable_capture(self.pg_interfaces)
1359         self.pg_start()
1360
1361         self.assertFalse(find_nbr(self,
1362                                   self.pg1.sw_if_index,
1363                                   self.pg1.remote_hosts[2].ip4))
1364
1365         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1366                     src=self.pg1.remote_hosts[3].mac) /
1367               ARP(op="is-at",
1368                   hwdst=self.pg1.local_mac,
1369                   hwsrc=self.pg1.remote_hosts[3].mac,
1370                   pdst=self.pg1.remote_hosts[2].ip4,
1371                   psrc=self.pg1.remote_hosts[2].ip4))
1372
1373         self.pg1.add_stream(p1)
1374         self.pg_enable_capture(self.pg_interfaces)
1375         self.pg_start()
1376
1377         self.assertFalse(find_nbr(self,
1378                                   self.pg1.sw_if_index,
1379                                   self.pg1.remote_hosts[2].ip4))
1380
1381     def test_arp_incomplete(self):
1382         """ Incomplete Entries """
1383
1384         #
1385         # ensure that we throttle the ARP and ND requests
1386         #
1387         self.pg0.generate_remote_hosts(2)
1388
1389         #
1390         # IPv4/ARP
1391         #
1392         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1393                                  [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1394                                                self.pg0.sw_if_index)])
1395         ip_10_0_0_1.add_vpp_config()
1396
1397         p1 = (Ether(dst=self.pg1.local_mac,
1398                     src=self.pg1.remote_mac) /
1399               IP(src=self.pg1.remote_ip4,
1400                  dst="10.0.0.1") /
1401               UDP(sport=1234, dport=1234) /
1402               Raw())
1403
1404         self.pg1.add_stream(p1 * 257)
1405         self.pg_enable_capture(self.pg_interfaces)
1406         self.pg_start()
1407         rx = self.pg0._get_capture(1)
1408
1409         #
1410         # how many we get is going to be dependent on the time for packet
1411         # processing but it should be small
1412         #
1413         self.assertLess(len(rx), 64)
1414
1415         #
1416         # IPv6/ND
1417         #
1418         ip_10_1 = VppIpRoute(self, "10::1", 128,
1419                              [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1420                                            self.pg0.sw_if_index,
1421                                            proto=DpoProto.DPO_PROTO_IP6)])
1422         ip_10_1.add_vpp_config()
1423
1424         p1 = (Ether(dst=self.pg1.local_mac,
1425                     src=self.pg1.remote_mac) /
1426               IPv6(src=self.pg1.remote_ip6,
1427                    dst="10::1") /
1428               UDP(sport=1234, dport=1234) /
1429               Raw())
1430
1431         self.pg1.add_stream(p1 * 257)
1432         self.pg_enable_capture(self.pg_interfaces)
1433         self.pg_start()
1434         rx = self.pg0._get_capture(1)
1435
1436         #
1437         # how many we get is going to be dependent on the time for packet
1438         # processing but it should be small
1439         #
1440         self.assertLess(len(rx), 64)
1441
1442     def test_arp_forus(self):
1443         """ ARP for for-us """
1444
1445         #
1446         # Test that VPP responds with ARP requests to addresses that
1447         # are connected and local routes.
1448         # Use one of the 'remote' addresses in the subnet as a local address
1449         # The intention of this route is that it then acts like a secondary
1450         # address added to an interface
1451         #
1452         self.pg0.generate_remote_hosts(2)
1453
1454         forus = VppIpRoute(
1455             self, self.pg0.remote_hosts[1].ip4, 32,
1456             [VppRoutePath("0.0.0.0",
1457                           self.pg0.sw_if_index,
1458                           type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1459         forus.add_vpp_config()
1460
1461         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1462                    src=self.pg0.remote_mac) /
1463              ARP(op="who-has",
1464                  hwdst=self.pg0.local_mac,
1465                  hwsrc=self.pg0.remote_mac,
1466                  pdst=self.pg0.remote_hosts[1].ip4,
1467                  psrc=self.pg0.remote_ip4))
1468
1469         rx = self.send_and_expect(self.pg0, [p], self.pg0)
1470
1471         self.verify_arp_resp(rx[0],
1472                              self.pg0.local_mac,
1473                              self.pg0.remote_mac,
1474                              self.pg0.remote_hosts[1].ip4,
1475                              self.pg0.remote_ip4)
1476
1477     def test_arp_table_swap(self):
1478         #
1479         # Generate some hosts on the LAN
1480         #
1481         N_NBRS = 4
1482         self.pg1.generate_remote_hosts(N_NBRS)
1483
1484         for n in range(N_NBRS):
1485             # a route thru each neighbour
1486             VppIpRoute(self, "10.0.0.%d" % n, 32,
1487                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1488                                      self.pg1.sw_if_index)]).add_vpp_config()
1489
1490             # resolve each neighbour
1491             p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1492                   ARP(op="is-at", hwdst=self.pg1.local_mac,
1493                       hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1494                       psrc=self.pg1.remote_hosts[n].ip4))
1495
1496             self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1497
1498         self.logger.info(self.vapi.cli("sh ip neighbors"))
1499
1500         #
1501         # swap the table pg1 is in
1502         #
1503         table = VppIpTable(self, 100).add_vpp_config()
1504
1505         self.pg1.unconfig_ip4()
1506         self.pg1.set_table_ip4(100)
1507         self.pg1.config_ip4()
1508
1509         #
1510         # all neighbours are cleared
1511         #
1512         for n in range(N_NBRS):
1513             self.assertFalse(find_nbr(self,
1514                                       self.pg1.sw_if_index,
1515                                       self.pg1.remote_hosts[n].ip4))
1516
1517         #
1518         # packets to all neighbours generate ARP requests
1519         #
1520         for n in range(N_NBRS):
1521             # a route thru each neighbour
1522             VppIpRoute(self, "10.0.0.%d" % n, 32,
1523                        [VppRoutePath(self.pg1.remote_hosts[n].ip4,
1524                                      self.pg1.sw_if_index)],
1525                        table_id=100).add_vpp_config()
1526
1527             p = (Ether(src=self.pg1.remote_hosts[n].mac,
1528                        dst=self.pg1.local_mac) /
1529                  IP(src=self.pg1.remote_hosts[n].ip4,
1530                     dst="10.0.0.%d" % n) /
1531                  Raw(b'0x5' * 100))
1532             rxs = self.send_and_expect(self.pg1, [p], self.pg1)
1533             for rx in rxs:
1534                 self.verify_arp_req(rx,
1535                                     self.pg1.local_mac,
1536                                     self.pg1.local_ip4,
1537                                     self.pg1.remote_hosts[n].ip4)
1538
1539         self.pg1.unconfig_ip4()
1540         self.pg1.set_table_ip4(0)
1541
1542
1543 class NeighborStatsTestCase(VppTestCase):
1544     """ ARP/ND Counters """
1545
1546     @classmethod
1547     def setUpClass(cls):
1548         super(NeighborStatsTestCase, cls).setUpClass()
1549
1550     @classmethod
1551     def tearDownClass(cls):
1552         super(NeighborStatsTestCase, cls).tearDownClass()
1553
1554     def setUp(self):
1555         super(NeighborStatsTestCase, self).setUp()
1556
1557         self.create_pg_interfaces(range(2))
1558
1559         # pg0 configured with ip4 and 6 addresses used for input
1560         # pg1 configured with ip4 and 6 addresses used for output
1561         # pg2 is unnumbered to pg0
1562         for i in self.pg_interfaces:
1563             i.admin_up()
1564             i.config_ip4()
1565             i.config_ip6()
1566             i.resolve_arp()
1567             i.resolve_ndp()
1568
1569     def tearDown(self):
1570         super(NeighborStatsTestCase, self).tearDown()
1571
1572         for i in self.pg_interfaces:
1573             i.unconfig_ip4()
1574             i.unconfig_ip6()
1575             i.admin_down()
1576
1577     def test_arp_stats(self):
1578         """ ARP Counters """
1579
1580         self.vapi.cli("adj counters enable")
1581         self.pg1.generate_remote_hosts(2)
1582
1583         arp1 = VppNeighbor(self,
1584                            self.pg1.sw_if_index,
1585                            self.pg1.remote_hosts[0].mac,
1586                            self.pg1.remote_hosts[0].ip4)
1587         arp1.add_vpp_config()
1588         arp2 = VppNeighbor(self,
1589                            self.pg1.sw_if_index,
1590                            self.pg1.remote_hosts[1].mac,
1591                            self.pg1.remote_hosts[1].ip4)
1592         arp2.add_vpp_config()
1593
1594         p1 = (Ether(dst=self.pg0.local_mac,
1595                     src=self.pg0.remote_mac) /
1596               IP(src=self.pg0.remote_ip4,
1597                  dst=self.pg1.remote_hosts[0].ip4) /
1598               UDP(sport=1234, dport=1234) /
1599               Raw())
1600         p2 = (Ether(dst=self.pg0.local_mac,
1601                     src=self.pg0.remote_mac) /
1602               IP(src=self.pg0.remote_ip4,
1603                  dst=self.pg1.remote_hosts[1].ip4) /
1604               UDP(sport=1234, dport=1234) /
1605               Raw())
1606
1607         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1608         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1609
1610         self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1611         self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1612
1613         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1614         self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1615
1616     def test_nd_stats(self):
1617         """ ND Counters """
1618
1619         self.vapi.cli("adj counters enable")
1620         self.pg0.generate_remote_hosts(3)
1621
1622         nd1 = VppNeighbor(self,
1623                           self.pg0.sw_if_index,
1624                           self.pg0.remote_hosts[1].mac,
1625                           self.pg0.remote_hosts[1].ip6)
1626         nd1.add_vpp_config()
1627         nd2 = VppNeighbor(self,
1628                           self.pg0.sw_if_index,
1629                           self.pg0.remote_hosts[2].mac,
1630                           self.pg0.remote_hosts[2].ip6)
1631         nd2.add_vpp_config()
1632
1633         p1 = (Ether(dst=self.pg1.local_mac,
1634                     src=self.pg1.remote_mac) /
1635               IPv6(src=self.pg1.remote_ip6,
1636                    dst=self.pg0.remote_hosts[1].ip6) /
1637               UDP(sport=1234, dport=1234) /
1638               Raw())
1639         p2 = (Ether(dst=self.pg1.local_mac,
1640                     src=self.pg1.remote_mac) /
1641               IPv6(src=self.pg1.remote_ip6,
1642                    dst=self.pg0.remote_hosts[2].ip6) /
1643               UDP(sport=1234, dport=1234) /
1644               Raw())
1645
1646         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1647         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1648
1649         self.assertEqual(16, nd1.get_stats()['packets'])
1650         self.assertEqual(16, nd2.get_stats()['packets'])
1651
1652         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1653         self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1654
1655
1656 class NeighborAgeTestCase(VppTestCase):
1657     """ ARP/ND Aging """
1658
1659     @classmethod
1660     def setUpClass(cls):
1661         super(NeighborAgeTestCase, cls).setUpClass()
1662
1663     @classmethod
1664     def tearDownClass(cls):
1665         super(NeighborAgeTestCase, cls).tearDownClass()
1666
1667     def setUp(self):
1668         super(NeighborAgeTestCase, self).setUp()
1669
1670         self.create_pg_interfaces(range(1))
1671
1672         # pg0 configured with ip4 and 6 addresses used for input
1673         # pg1 configured with ip4 and 6 addresses used for output
1674         # pg2 is unnumbered to pg0
1675         for i in self.pg_interfaces:
1676             i.admin_up()
1677             i.config_ip4()
1678             i.config_ip6()
1679             i.resolve_arp()
1680             i.resolve_ndp()
1681
1682     def tearDown(self):
1683         super(NeighborAgeTestCase, self).tearDown()
1684
1685         for i in self.pg_interfaces:
1686             i.unconfig_ip4()
1687             i.unconfig_ip6()
1688             i.admin_down()
1689
1690     def wait_for_no_nbr(self, intf, address,
1691                         n_tries=50, s_time=1):
1692         while (n_tries):
1693             if not find_nbr(self, intf, address):
1694                 return True
1695             n_tries = n_tries - 1
1696             self.sleep(s_time)
1697
1698         return False
1699
1700     def verify_arp_req(self, rx, smac, sip, dip):
1701         ether = rx[Ether]
1702         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
1703         self.assertEqual(ether.src, smac)
1704
1705         arp = rx[ARP]
1706         self.assertEqual(arp.hwtype, 1)
1707         self.assertEqual(arp.ptype, 0x800)
1708         self.assertEqual(arp.hwlen, 6)
1709         self.assertEqual(arp.plen, 4)
1710         self.assertEqual(arp.op, arp_opts["who-has"])
1711         self.assertEqual(arp.hwsrc, smac)
1712         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
1713         self.assertEqual(arp.psrc, sip)
1714         self.assertEqual(arp.pdst, dip)
1715
1716     def test_age(self):
1717         """ Aging/Recycle """
1718
1719         self.vapi.cli("set logging unthrottle 0")
1720         self.vapi.cli("set logging size %d" % 0xffff)
1721
1722         self.pg0.generate_remote_hosts(201)
1723
1724         vaf = VppEnum.vl_api_address_family_t
1725
1726         #
1727         # start listening on all interfaces
1728         #
1729         self.pg_enable_capture(self.pg_interfaces)
1730
1731         #
1732         # Set the neighbor configuration:
1733         #   limi = 200
1734         #   age  = 0 seconds
1735         #   recycle = false
1736         #
1737         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1738                                      max_number=200,
1739                                      max_age=0,
1740                                      recycle=False)
1741
1742         self.vapi.cli("sh ip neighbor-config")
1743
1744         # add the 198 neighbours that should pass (-1 for one created in setup)
1745         for ii in range(200):
1746             VppNeighbor(self,
1747                         self.pg0.sw_if_index,
1748                         self.pg0.remote_hosts[ii].mac,
1749                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1750
1751         # one more neighbor over the limit should fail
1752         with self.vapi.assert_negative_api_retval():
1753             VppNeighbor(self,
1754                         self.pg0.sw_if_index,
1755                         self.pg0.remote_hosts[200].mac,
1756                         self.pg0.remote_hosts[200].ip4).add_vpp_config()
1757
1758         #
1759         # change the config to allow recycling the old neighbors
1760         #
1761         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1762                                      max_number=200,
1763                                      max_age=0,
1764                                      recycle=True)
1765
1766         # now new additions are allowed
1767         VppNeighbor(self,
1768                     self.pg0.sw_if_index,
1769                     self.pg0.remote_hosts[200].mac,
1770                     self.pg0.remote_hosts[200].ip4).add_vpp_config()
1771
1772         # add the first neighbor we configured has been re-used
1773         self.assertFalse(find_nbr(self,
1774                                   self.pg0.sw_if_index,
1775                                   self.pg0.remote_hosts[0].ip4))
1776         self.assertTrue(find_nbr(self,
1777                                  self.pg0.sw_if_index,
1778                                  self.pg0.remote_hosts[200].ip4))
1779
1780         #
1781         # change the config to age old neighbors
1782         #
1783         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1784                                      max_number=200,
1785                                      max_age=2,
1786                                      recycle=True)
1787
1788         self.vapi.cli("sh ip4 neighbor-sorted")
1789
1790         #
1791         # expect probes from all these ARP entries as they age
1792         # 3 probes for each neighbor 3*200 = 600
1793         rxs = self.pg0.get_capture(600, timeout=8)
1794
1795         for ii in range(3):
1796             for jj in range(200):
1797                 rx = rxs[ii*200 + jj]
1798                 # rx.show()
1799
1800         #
1801         # 3 probes sent then 1 more second to see if a reply comes, before
1802         # they age out
1803         #
1804         for jj in range(1, 201):
1805             self.wait_for_no_nbr(self.pg0.sw_if_index,
1806                                  self.pg0.remote_hosts[jj].ip4)
1807
1808         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1809                                                     af=vaf.ADDRESS_IP4))
1810
1811         #
1812         # load up some neighbours again with 2s aging enabled
1813         # they should be removed after 10s (2s age + 4s for probes + gap)
1814         #
1815         for ii in range(10):
1816             VppNeighbor(self,
1817                         self.pg0.sw_if_index,
1818                         self.pg0.remote_hosts[ii].mac,
1819                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1820         self.sleep(10)
1821         self.assertFalse(self.vapi.ip_neighbor_dump(sw_if_index=0xffffffff,
1822                                                     af=vaf.ADDRESS_IP4))
1823
1824         #
1825         # check if we can set age and recycle with empty neighbor list
1826         #
1827         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1828                                      max_number=200,
1829                                      max_age=1000,
1830                                      recycle=True)
1831
1832         #
1833         # load up some neighbours again, then disable the aging
1834         # they should still be there in 10 seconds time
1835         #
1836         for ii in range(10):
1837             VppNeighbor(self,
1838                         self.pg0.sw_if_index,
1839                         self.pg0.remote_hosts[ii].mac,
1840                         self.pg0.remote_hosts[ii].ip4).add_vpp_config()
1841         self.vapi.ip_neighbor_config(af=vaf.ADDRESS_IP4,
1842                                      max_number=200,
1843                                      max_age=0,
1844                                      recycle=False)
1845
1846         self.sleep(10)
1847         self.assertTrue(find_nbr(self,
1848                                  self.pg0.sw_if_index,
1849                                  self.pg0.remote_hosts[0].ip4))
1850
1851
1852 class NeighborReplaceTestCase(VppTestCase):
1853     """ ARP/ND Replacement """
1854
1855     @classmethod
1856     def setUpClass(cls):
1857         super(NeighborReplaceTestCase, cls).setUpClass()
1858
1859     @classmethod
1860     def tearDownClass(cls):
1861         super(NeighborReplaceTestCase, cls).tearDownClass()
1862
1863     def setUp(self):
1864         super(NeighborReplaceTestCase, self).setUp()
1865
1866         self.create_pg_interfaces(range(4))
1867
1868         # pg0 configured with ip4 and 6 addresses used for input
1869         # pg1 configured with ip4 and 6 addresses used for output
1870         # pg2 is unnumbered to pg0
1871         for i in self.pg_interfaces:
1872             i.admin_up()
1873             i.config_ip4()
1874             i.config_ip6()
1875             i.resolve_arp()
1876             i.resolve_ndp()
1877
1878     def tearDown(self):
1879         super(NeighborReplaceTestCase, self).tearDown()
1880
1881         for i in self.pg_interfaces:
1882             i.unconfig_ip4()
1883             i.unconfig_ip6()
1884             i.admin_down()
1885
1886     def test_replace(self):
1887         """ replace """
1888
1889         N_HOSTS = 16
1890
1891         for i in self.pg_interfaces:
1892             i.generate_remote_hosts(N_HOSTS)
1893             i.configure_ipv4_neighbors()
1894             i.configure_ipv6_neighbors()
1895
1896         # replace them all
1897         self.vapi.ip_neighbor_replace_begin()
1898         self.vapi.ip_neighbor_replace_end()
1899
1900         for i in self.pg_interfaces:
1901             for h in range(N_HOSTS):
1902                 self.assertFalse(find_nbr(self,
1903                                           self.pg0.sw_if_index,
1904                                           self.pg0.remote_hosts[h].ip4))
1905                 self.assertFalse(find_nbr(self,
1906                                           self.pg0.sw_if_index,
1907                                           self.pg0.remote_hosts[h].ip6))
1908
1909         #
1910         # and them all back via the API
1911         #
1912         for i in self.pg_interfaces:
1913             for h in range(N_HOSTS):
1914                 VppNeighbor(self,
1915                             i.sw_if_index,
1916                             i.remote_hosts[h].mac,
1917                             i.remote_hosts[h].ip4).add_vpp_config()
1918                 VppNeighbor(self,
1919                             i.sw_if_index,
1920                             i.remote_hosts[h].mac,
1921                             i.remote_hosts[h].ip6).add_vpp_config()
1922
1923         #
1924         # begin the replacement again, this time touch some
1925         # the neighbours on pg1 so they are not deleted
1926         #
1927         self.vapi.ip_neighbor_replace_begin()
1928
1929         # update from the API all neighbours on pg1
1930         for h in range(N_HOSTS):
1931             VppNeighbor(self,
1932                         self.pg1.sw_if_index,
1933                         self.pg1.remote_hosts[h].mac,
1934                         self.pg1.remote_hosts[h].ip4).add_vpp_config()
1935             VppNeighbor(self,
1936                         self.pg1.sw_if_index,
1937                         self.pg1.remote_hosts[h].mac,
1938                         self.pg1.remote_hosts[h].ip6).add_vpp_config()
1939
1940         # update from the data-plane all neighbours on pg3
1941         self.pg3.configure_ipv4_neighbors()
1942         self.pg3.configure_ipv6_neighbors()
1943
1944         # complete the replacement
1945         self.logger.info(self.vapi.cli("sh ip neighbors"))
1946         self.vapi.ip_neighbor_replace_end()
1947
1948         for i in self.pg_interfaces:
1949             if i == self.pg1 or i == self.pg3:
1950                 # neighbours on pg1 and pg3 are still present
1951                 for h in range(N_HOSTS):
1952                     self.assertTrue(find_nbr(self,
1953                                              i.sw_if_index,
1954                                              i.remote_hosts[h].ip4))
1955                     self.assertTrue(find_nbr(self,
1956                                              i.sw_if_index,
1957                                              i.remote_hosts[h].ip6))
1958             else:
1959                 # all other neighbours are toast
1960                 for h in range(N_HOSTS):
1961                     self.assertFalse(find_nbr(self,
1962                                               i.sw_if_index,
1963                                               i.remote_hosts[h].ip4))
1964                     self.assertFalse(find_nbr(self,
1965                                               i.sw_if_index,
1966                                               i.remote_hosts[h].ip6))
1967
1968
1969 if __name__ == '__main__':
1970     unittest.main(testRunner=VppTestRunner)