lb: remove api boilerplate
[vpp.git] / test / test_neighbor.py
1 #!/usr/bin/env python
2
3 import unittest
4 from socket import AF_INET, AF_INET6, inet_pton
5
6 from framework import VppTestCase, VppTestRunner
7 from vpp_neighbor import VppNeighbor, find_nbr
8 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, \
9     VppIpTable, DpoProto, FibPathType
10 from vpp_papi import VppEnum
11
12 import scapy.compat
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, ARP, Dot1Q
15 from scapy.layers.inet import IP, UDP
16 from scapy.layers.inet6 import IPv6
17 from scapy.contrib.mpls import MPLS
18 from scapy.layers.inet6 import IPv6
19
20
21 NUM_PKTS = 67
22
23 # not exported by scapy, so redefined here
24 arp_opts = {"who-has": 1, "is-at": 2}
25
26
27 class ARPTestCase(VppTestCase):
28     """ ARP Test Case """
29
30     @classmethod
31     def setUpClass(cls):
32         super(ARPTestCase, cls).setUpClass()
33
34     @classmethod
35     def tearDownClass(cls):
36         super(ARPTestCase, cls).tearDownClass()
37
38     def setUp(self):
39         super(ARPTestCase, self).setUp()
40
41         # create 3 pg interfaces
42         self.create_pg_interfaces(range(4))
43
44         # pg0 configured with ip4 and 6 addresses used for input
45         # pg1 configured with ip4 and 6 addresses used for output
46         # pg2 is unnumbered to pg0
47         for i in self.pg_interfaces:
48             i.admin_up()
49
50         self.pg0.config_ip4()
51         self.pg0.config_ip6()
52         self.pg0.resolve_arp()
53
54         self.pg1.config_ip4()
55         self.pg1.config_ip6()
56
57         # pg3 in a different VRF
58         self.tbl = VppIpTable(self, 1)
59         self.tbl.add_vpp_config()
60
61         self.pg3.set_table_ip4(1)
62         self.pg3.config_ip4()
63
64     def tearDown(self):
65         self.pg0.unconfig_ip4()
66         self.pg0.unconfig_ip6()
67
68         self.pg1.unconfig_ip4()
69         self.pg1.unconfig_ip6()
70
71         self.pg3.unconfig_ip4()
72         self.pg3.set_table_ip4(0)
73
74         for i in self.pg_interfaces:
75             i.admin_down()
76
77         super(ARPTestCase, self).tearDown()
78
79     def verify_arp_req(self, rx, smac, sip, dip):
80         ether = rx[Ether]
81         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
82         self.assertEqual(ether.src, smac)
83
84         arp = rx[ARP]
85         self.assertEqual(arp.hwtype, 1)
86         self.assertEqual(arp.ptype, 0x800)
87         self.assertEqual(arp.hwlen, 6)
88         self.assertEqual(arp.plen, 4)
89         self.assertEqual(arp.op, arp_opts["who-has"])
90         self.assertEqual(arp.hwsrc, smac)
91         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
92         self.assertEqual(arp.psrc, sip)
93         self.assertEqual(arp.pdst, dip)
94
95     def verify_arp_resp(self, rx, smac, dmac, sip, dip):
96         ether = rx[Ether]
97         self.assertEqual(ether.dst, dmac)
98         self.assertEqual(ether.src, smac)
99
100         arp = rx[ARP]
101         self.assertEqual(arp.hwtype, 1)
102         self.assertEqual(arp.ptype, 0x800)
103         self.assertEqual(arp.hwlen, 6)
104         self.assertEqual(arp.plen, 4)
105         self.assertEqual(arp.op, arp_opts["is-at"])
106         self.assertEqual(arp.hwsrc, smac)
107         self.assertEqual(arp.hwdst, dmac)
108         self.assertEqual(arp.psrc, sip)
109         self.assertEqual(arp.pdst, dip)
110
111     def verify_arp_vrrp_resp(self, rx, smac, dmac, sip, dip):
112         ether = rx[Ether]
113         self.assertEqual(ether.dst, dmac)
114         self.assertEqual(ether.src, smac)
115
116         arp = rx[ARP]
117         self.assertEqual(arp.hwtype, 1)
118         self.assertEqual(arp.ptype, 0x800)
119         self.assertEqual(arp.hwlen, 6)
120         self.assertEqual(arp.plen, 4)
121         self.assertEqual(arp.op, arp_opts["is-at"])
122         self.assertNotEqual(arp.hwsrc, smac)
123         self.assertTrue("00:00:5e:00:01" in arp.hwsrc or
124                         "00:00:5E:00:01" in arp.hwsrc)
125         self.assertEqual(arp.hwdst, dmac)
126         self.assertEqual(arp.psrc, sip)
127         self.assertEqual(arp.pdst, dip)
128
129     def verify_ip(self, rx, smac, dmac, sip, dip):
130         ether = rx[Ether]
131         self.assertEqual(ether.dst, dmac)
132         self.assertEqual(ether.src, smac)
133
134         ip = rx[IP]
135         self.assertEqual(ip.src, sip)
136         self.assertEqual(ip.dst, dip)
137
138     def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
139         ether = rx[Ether]
140         self.assertEqual(ether.dst, dmac)
141         self.assertEqual(ether.src, smac)
142
143         mpls = rx[MPLS]
144         self.assertTrue(mpls.label, label)
145
146         ip = rx[IP]
147         self.assertEqual(ip.src, sip)
148         self.assertEqual(ip.dst, dip)
149
150     def test_arp(self):
151         """ ARP """
152
153         #
154         # Generate some hosts on the LAN
155         #
156         self.pg1.generate_remote_hosts(11)
157
158         #
159         # Send IP traffic to one of these unresolved hosts.
160         #  expect the generation of an ARP request
161         #
162         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
163              IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
164              UDP(sport=1234, dport=1234) /
165              Raw())
166
167         self.pg0.add_stream(p)
168         self.pg_enable_capture(self.pg_interfaces)
169         self.pg_start()
170
171         rx = self.pg1.get_capture(1)
172
173         self.verify_arp_req(rx[0],
174                             self.pg1.local_mac,
175                             self.pg1.local_ip4,
176                             self.pg1._remote_hosts[1].ip4)
177
178         #
179         # And a dynamic ARP entry for host 1
180         #
181         dyn_arp = VppNeighbor(self,
182                               self.pg1.sw_if_index,
183                               self.pg1.remote_hosts[1].mac,
184                               self.pg1.remote_hosts[1].ip4)
185         dyn_arp.add_vpp_config()
186
187         #
188         # now we expect IP traffic forwarded
189         #
190         dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
191                  IP(src=self.pg0.remote_ip4,
192                     dst=self.pg1._remote_hosts[1].ip4) /
193                  UDP(sport=1234, dport=1234) /
194                  Raw())
195
196         self.pg0.add_stream(dyn_p)
197         self.pg_enable_capture(self.pg_interfaces)
198         self.pg_start()
199
200         rx = self.pg1.get_capture(1)
201
202         self.verify_ip(rx[0],
203                        self.pg1.local_mac,
204                        self.pg1.remote_hosts[1].mac,
205                        self.pg0.remote_ip4,
206                        self.pg1._remote_hosts[1].ip4)
207
208         #
209         # And a Static ARP entry for host 2
210         #
211         static_arp = VppNeighbor(self,
212                                  self.pg1.sw_if_index,
213                                  self.pg1.remote_hosts[2].mac,
214                                  self.pg1.remote_hosts[2].ip4,
215                                  is_static=1)
216         static_arp.add_vpp_config()
217
218         static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
219                     IP(src=self.pg0.remote_ip4,
220                        dst=self.pg1._remote_hosts[2].ip4) /
221                     UDP(sport=1234, dport=1234) /
222                     Raw())
223
224         self.pg0.add_stream(static_p)
225         self.pg_enable_capture(self.pg_interfaces)
226         self.pg_start()
227
228         rx = self.pg1.get_capture(1)
229
230         self.verify_ip(rx[0],
231                        self.pg1.local_mac,
232                        self.pg1.remote_hosts[2].mac,
233                        self.pg0.remote_ip4,
234                        self.pg1._remote_hosts[2].ip4)
235
236         #
237         # flap the link. dynamic ARPs get flush, statics don't
238         #
239         self.pg1.admin_down()
240         self.pg1.admin_up()
241
242         self.pg0.add_stream(static_p)
243         self.pg_enable_capture(self.pg_interfaces)
244         self.pg_start()
245         rx = self.pg1.get_capture(1)
246
247         self.verify_ip(rx[0],
248                        self.pg1.local_mac,
249                        self.pg1.remote_hosts[2].mac,
250                        self.pg0.remote_ip4,
251                        self.pg1._remote_hosts[2].ip4)
252
253         self.pg0.add_stream(dyn_p)
254         self.pg_enable_capture(self.pg_interfaces)
255         self.pg_start()
256
257         rx = self.pg1.get_capture(1)
258         self.verify_arp_req(rx[0],
259                             self.pg1.local_mac,
260                             self.pg1.local_ip4,
261                             self.pg1._remote_hosts[1].ip4)
262
263         #
264         # Send an ARP request from one of the so-far unlearned remote hosts
265         #
266         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
267                    src=self.pg1._remote_hosts[3].mac) /
268              ARP(op="who-has",
269                  hwsrc=self.pg1._remote_hosts[3].mac,
270                  pdst=self.pg1.local_ip4,
271                  psrc=self.pg1._remote_hosts[3].ip4))
272
273         self.pg1.add_stream(p)
274         self.pg_enable_capture(self.pg_interfaces)
275         self.pg_start()
276
277         rx = self.pg1.get_capture(1)
278         self.verify_arp_resp(rx[0],
279                              self.pg1.local_mac,
280                              self.pg1._remote_hosts[3].mac,
281                              self.pg1.local_ip4,
282                              self.pg1._remote_hosts[3].ip4)
283
284         #
285         # VPP should have learned the mapping for the remote host
286         #
287         self.assertTrue(find_nbr(self,
288                                  self.pg1.sw_if_index,
289                                  self.pg1._remote_hosts[3].ip4))
290         #
291         # Fire in an ARP request before the interface becomes IP enabled
292         #
293         self.pg2.generate_remote_hosts(4)
294
295         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
296              ARP(op="who-has",
297                  hwsrc=self.pg2.remote_mac,
298                  pdst=self.pg1.local_ip4,
299                  psrc=self.pg2.remote_hosts[3].ip4))
300         pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
301               Dot1Q(vlan=0) /
302               ARP(op="who-has",
303                   hwsrc=self.pg2.remote_mac,
304                   pdst=self.pg1.local_ip4,
305                   psrc=self.pg2.remote_hosts[3].ip4))
306         self.send_and_assert_no_replies(self.pg2, p,
307                                         "interface not IP enabled")
308
309         #
310         # Make pg2 un-numbered to pg1
311         #
312         self.pg2.set_unnumbered(self.pg1.sw_if_index)
313
314         unnum = self.vapi.ip_unnumbered_dump()
315         self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
316         self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
317
318         #
319         # We should respond to ARP requests for the unnumbered to address
320         # once an attached route to the source is known
321         #
322         self.send_and_assert_no_replies(
323             self.pg2, p,
324             "ARP req for unnumbered address - no source")
325
326         attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32,
327                                    [VppRoutePath("0.0.0.0",
328                                                  self.pg2.sw_if_index)])
329         attached_host.add_vpp_config()
330
331         self.pg2.add_stream(p)
332         self.pg_enable_capture(self.pg_interfaces)
333         self.pg_start()
334
335         rx = self.pg2.get_capture(1)
336         self.verify_arp_resp(rx[0],
337                              self.pg2.local_mac,
338                              self.pg2.remote_mac,
339                              self.pg1.local_ip4,
340                              self.pg2.remote_hosts[3].ip4)
341
342         self.pg2.add_stream(pt)
343         self.pg_enable_capture(self.pg_interfaces)
344         self.pg_start()
345
346         rx = self.pg2.get_capture(1)
347         self.verify_arp_resp(rx[0],
348                              self.pg2.local_mac,
349                              self.pg2.remote_mac,
350                              self.pg1.local_ip4,
351                              self.pg2.remote_hosts[3].ip4)
352
353         #
354         # A neighbor entry that has no associated FIB-entry
355         #
356         arp_no_fib = VppNeighbor(self,
357                                  self.pg1.sw_if_index,
358                                  self.pg1.remote_hosts[4].mac,
359                                  self.pg1.remote_hosts[4].ip4,
360                                  is_no_fib_entry=1)
361         arp_no_fib.add_vpp_config()
362
363         #
364         # check we have the neighbor, but no route
365         #
366         self.assertTrue(find_nbr(self,
367                                  self.pg1.sw_if_index,
368                                  self.pg1._remote_hosts[4].ip4))
369         self.assertFalse(find_route(self,
370                                     self.pg1._remote_hosts[4].ip4,
371                                     32))
372         #
373         # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2
374         # from within pg1's subnet
375         #
376         arp_unnum = VppNeighbor(self,
377                                 self.pg2.sw_if_index,
378                                 self.pg1.remote_hosts[5].mac,
379                                 self.pg1.remote_hosts[5].ip4)
380         arp_unnum.add_vpp_config()
381
382         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
383              IP(src=self.pg0.remote_ip4,
384                 dst=self.pg1._remote_hosts[5].ip4) /
385              UDP(sport=1234, dport=1234) /
386              Raw())
387
388         self.pg0.add_stream(p)
389         self.pg_enable_capture(self.pg_interfaces)
390         self.pg_start()
391
392         rx = self.pg2.get_capture(1)
393
394         self.verify_ip(rx[0],
395                        self.pg2.local_mac,
396                        self.pg1.remote_hosts[5].mac,
397                        self.pg0.remote_ip4,
398                        self.pg1._remote_hosts[5].ip4)
399
400         #
401         # ARP requests from hosts in pg1's subnet sent on pg2 are replied to
402         # with the unnumbered interface's address as the source
403         #
404         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
405              ARP(op="who-has",
406                  hwsrc=self.pg2.remote_mac,
407                  pdst=self.pg1.local_ip4,
408                  psrc=self.pg1.remote_hosts[6].ip4))
409
410         self.pg2.add_stream(p)
411         self.pg_enable_capture(self.pg_interfaces)
412         self.pg_start()
413
414         rx = self.pg2.get_capture(1)
415         self.verify_arp_resp(rx[0],
416                              self.pg2.local_mac,
417                              self.pg2.remote_mac,
418                              self.pg1.local_ip4,
419                              self.pg1.remote_hosts[6].ip4)
420
421         #
422         # An attached host route out of pg2 for an undiscovered hosts generates
423         # an ARP request with the unnumbered address as the source
424         #
425         att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32,
426                                [VppRoutePath("0.0.0.0",
427                                              self.pg2.sw_if_index)])
428         att_unnum.add_vpp_config()
429
430         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
431              IP(src=self.pg0.remote_ip4,
432                 dst=self.pg1._remote_hosts[7].ip4) /
433              UDP(sport=1234, dport=1234) /
434              Raw())
435
436         self.pg0.add_stream(p)
437         self.pg_enable_capture(self.pg_interfaces)
438         self.pg_start()
439
440         rx = self.pg2.get_capture(1)
441
442         self.verify_arp_req(rx[0],
443                             self.pg2.local_mac,
444                             self.pg1.local_ip4,
445                             self.pg1._remote_hosts[7].ip4)
446
447         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
448              ARP(op="who-has",
449                  hwsrc=self.pg2.remote_mac,
450                  pdst=self.pg1.local_ip4,
451                  psrc=self.pg1.remote_hosts[7].ip4))
452
453         self.pg2.add_stream(p)
454         self.pg_enable_capture(self.pg_interfaces)
455         self.pg_start()
456
457         rx = self.pg2.get_capture(1)
458         self.verify_arp_resp(rx[0],
459                              self.pg2.local_mac,
460                              self.pg2.remote_mac,
461                              self.pg1.local_ip4,
462                              self.pg1.remote_hosts[7].ip4)
463
464         #
465         # An attached host route as yet unresolved out of pg2 for an
466         # undiscovered host, an ARP requests begets a response.
467         #
468         att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32,
469                                 [VppRoutePath("0.0.0.0",
470                                               self.pg2.sw_if_index)])
471         att_unnum1.add_vpp_config()
472
473         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
474              ARP(op="who-has",
475                  hwsrc=self.pg2.remote_mac,
476                  pdst=self.pg1.local_ip4,
477                  psrc=self.pg1.remote_hosts[8].ip4))
478
479         self.pg2.add_stream(p)
480         self.pg_enable_capture(self.pg_interfaces)
481         self.pg_start()
482
483         rx = self.pg2.get_capture(1)
484         self.verify_arp_resp(rx[0],
485                              self.pg2.local_mac,
486                              self.pg2.remote_mac,
487                              self.pg1.local_ip4,
488                              self.pg1.remote_hosts[8].ip4)
489
490         #
491         # Send an ARP request from one of the so-far unlearned remote hosts
492         # with a VLAN0 tag
493         #
494         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
495                    src=self.pg1._remote_hosts[9].mac) /
496              Dot1Q(vlan=0) /
497              ARP(op="who-has",
498                  hwsrc=self.pg1._remote_hosts[9].mac,
499                  pdst=self.pg1.local_ip4,
500                  psrc=self.pg1._remote_hosts[9].ip4))
501
502         self.pg1.add_stream(p)
503         self.pg_enable_capture(self.pg_interfaces)
504         self.pg_start()
505
506         rx = self.pg1.get_capture(1)
507         self.verify_arp_resp(rx[0],
508                              self.pg1.local_mac,
509                              self.pg1._remote_hosts[9].mac,
510                              self.pg1.local_ip4,
511                              self.pg1._remote_hosts[9].ip4)
512
513         #
514         # Add a hierarchy of routes for a host in the sub-net.
515         # Should still get an ARP resp since the cover is attached
516         #
517         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) /
518              ARP(op="who-has",
519                  hwsrc=self.pg1.remote_mac,
520                  pdst=self.pg1.local_ip4,
521                  psrc=self.pg1.remote_hosts[10].ip4))
522
523         r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30,
524                         [VppRoutePath(self.pg1.remote_hosts[10].ip4,
525                                       self.pg1.sw_if_index)])
526         r1.add_vpp_config()
527
528         self.pg1.add_stream(p)
529         self.pg_enable_capture(self.pg_interfaces)
530         self.pg_start()
531         rx = self.pg1.get_capture(1)
532         self.verify_arp_resp(rx[0],
533                              self.pg1.local_mac,
534                              self.pg1.remote_mac,
535                              self.pg1.local_ip4,
536                              self.pg1.remote_hosts[10].ip4)
537
538         r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32,
539                         [VppRoutePath(self.pg1.remote_hosts[10].ip4,
540                                       self.pg1.sw_if_index)])
541         r2.add_vpp_config()
542
543         self.pg1.add_stream(p)
544         self.pg_enable_capture(self.pg_interfaces)
545         self.pg_start()
546         rx = self.pg1.get_capture(1)
547         self.verify_arp_resp(rx[0],
548                              self.pg1.local_mac,
549                              self.pg1.remote_mac,
550                              self.pg1.local_ip4,
551                              self.pg1.remote_hosts[10].ip4)
552
553         #
554         # add an ARP entry that's not on the sub-net and so whose
555         # adj-fib fails the refinement check. then send an ARP request
556         # from that source
557         #
558         a1 = VppNeighbor(self,
559                          self.pg0.sw_if_index,
560                          self.pg0.remote_mac,
561                          "100.100.100.50")
562         a1.add_vpp_config()
563
564         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
565              ARP(op="who-has",
566                  hwsrc=self.pg0.remote_mac,
567                  psrc="100.100.100.50",
568                  pdst=self.pg0.remote_ip4))
569         self.send_and_assert_no_replies(self.pg0, p,
570                                         "ARP req for from failed adj-fib")
571
572         #
573         # ERROR Cases
574         #  1 - don't respond to ARP request for address not within the
575         #      interface's sub-net
576         #  1b - nor within the unnumbered subnet
577         #  1c - nor within the subnet of a different interface
578         #
579         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
580              ARP(op="who-has",
581                  hwsrc=self.pg0.remote_mac,
582                  pdst="10.10.10.3",
583                  psrc=self.pg0.remote_ip4))
584         self.send_and_assert_no_replies(self.pg0, p,
585                                         "ARP req for non-local destination")
586         self.assertFalse(find_nbr(self,
587                                   self.pg0.sw_if_index,
588                                   "10.10.10.3"))
589
590         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
591              ARP(op="who-has",
592                  hwsrc=self.pg2.remote_mac,
593                  pdst="10.10.10.3",
594                  psrc=self.pg1.remote_hosts[7].ip4))
595         self.send_and_assert_no_replies(
596             self.pg0, p,
597             "ARP req for non-local destination - unnum")
598
599         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
600              ARP(op="who-has",
601                  hwsrc=self.pg0.remote_mac,
602                  pdst=self.pg1.local_ip4,
603                  psrc=self.pg1.remote_ip4))
604         self.send_and_assert_no_replies(self.pg0, p,
605                                         "ARP req diff sub-net")
606         self.assertFalse(find_nbr(self,
607                                   self.pg0.sw_if_index,
608                                   self.pg1.remote_ip4))
609
610         #
611         #  2 - don't respond to ARP request from an address not within the
612         #      interface's sub-net
613         #   2b - to a proxied address
614         #   2c - not within a different interface's sub-net
615         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
616              ARP(op="who-has",
617                  hwsrc=self.pg0.remote_mac,
618                  psrc="10.10.10.3",
619                  pdst=self.pg0.local_ip4))
620         self.send_and_assert_no_replies(self.pg0, p,
621                                         "ARP req for non-local source")
622         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) /
623              ARP(op="who-has",
624                  hwsrc=self.pg2.remote_mac,
625                  psrc="10.10.10.3",
626                  pdst=self.pg0.local_ip4))
627         self.send_and_assert_no_replies(
628             self.pg0, p,
629             "ARP req for non-local source - unnum")
630         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
631              ARP(op="who-has",
632                  hwsrc=self.pg0.remote_mac,
633                  psrc=self.pg1.remote_ip4,
634                  pdst=self.pg0.local_ip4))
635         self.send_and_assert_no_replies(self.pg0, p,
636                                         "ARP req for non-local source 2c")
637
638         #
639         #  3 - don't respond to ARP request from an address that belongs to
640         #      the router
641         #
642         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
643              ARP(op="who-has",
644                  hwsrc=self.pg0.remote_mac,
645                  psrc=self.pg0.local_ip4,
646                  pdst=self.pg0.local_ip4))
647         self.send_and_assert_no_replies(self.pg0, p,
648                                         "ARP req for non-local source")
649
650         #
651         #  4 - don't respond to ARP requests that has mac source different
652         #      from ARP request HW source
653         #
654         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
655              ARP(op="who-has",
656                  hwsrc="00:00:00:DE:AD:BE",
657                  psrc=self.pg0.remote_ip4,
658                  pdst=self.pg0.local_ip4))
659         self.send_and_assert_no_replies(self.pg0, p,
660                                         "ARP req for non-local source")
661
662         #
663         #  5 - don't respond to ARP requests for address within the
664         #      interface's sub-net but not the interface's address
665         #
666         self.pg0.generate_remote_hosts(2)
667         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
668              ARP(op="who-has",
669                  hwsrc=self.pg0.remote_mac,
670                  psrc=self.pg0.remote_hosts[0].ip4,
671                  pdst=self.pg0.remote_hosts[1].ip4))
672         self.send_and_assert_no_replies(self.pg0, p,
673                                         "ARP req for non-local destination")
674
675         #
676         # cleanup
677         #
678         dyn_arp.remove_vpp_config()
679         static_arp.remove_vpp_config()
680         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
681
682         # need this to flush the adj-fibs
683         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
684         self.pg2.admin_down()
685         self.pg1.admin_down()
686
687     def test_proxy_mirror_arp(self):
688         """ Interface Mirror Proxy ARP """
689
690         #
691         # When VPP has an interface whose address is also applied to a TAP
692         # interface on the host, then VPP's TAP interface will be unnumbered
693         # to the 'real' interface and do proxy ARP from the host.
694         # the curious aspect of this setup is that ARP requests from the host
695         # will come from the VPP's own address.
696         #
697         self.pg0.generate_remote_hosts(2)
698
699         arp_req_from_me = (Ether(src=self.pg2.remote_mac,
700                                  dst="ff:ff:ff:ff:ff:ff") /
701                            ARP(op="who-has",
702                                hwsrc=self.pg2.remote_mac,
703                                pdst=self.pg0.remote_hosts[1].ip4,
704                                psrc=self.pg0.local_ip4))
705
706         #
707         # Configure Proxy ARP for the subnet on PG0addresses on pg0
708         #
709         self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
710                                     self.pg0._local_ip4_bcast)
711
712         # Make pg2 un-numbered to pg0
713         #
714         self.pg2.set_unnumbered(self.pg0.sw_if_index)
715
716         #
717         # Enable pg2 for proxy ARP
718         #
719         self.pg2.set_proxy_arp()
720
721         #
722         # Send the ARP request with an originating address that
723         # is VPP's own address
724         #
725         self.pg2.add_stream(arp_req_from_me)
726         self.pg_enable_capture(self.pg_interfaces)
727         self.pg_start()
728
729         rx = self.pg2.get_capture(1)
730         self.verify_arp_resp(rx[0],
731                              self.pg2.local_mac,
732                              self.pg2.remote_mac,
733                              self.pg0.remote_hosts[1].ip4,
734                              self.pg0.local_ip4)
735
736         #
737         # validate we have not learned an ARP entry as a result of this
738         #
739         self.assertFalse(find_nbr(self,
740                                   self.pg2.sw_if_index,
741                                   self.pg0.local_ip4))
742
743         #
744         # cleanup
745         #
746         self.pg2.set_proxy_arp(0)
747         self.vapi.proxy_arp_add_del(self.pg0._local_ip4_subnet,
748                                     self.pg0._local_ip4_bcast,
749                                     is_add=0)
750
751     def test_proxy_arp(self):
752         """ Proxy ARP """
753
754         self.pg1.generate_remote_hosts(2)
755
756         #
757         # Proxy ARP request packets for each interface
758         #
759         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
760                              dst="ff:ff:ff:ff:ff:ff") /
761                        ARP(op="who-has",
762                            hwsrc=self.pg0.remote_mac,
763                            pdst="10.10.10.3",
764                            psrc=self.pg0.remote_ip4))
765         arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac,
766                                     dst="ff:ff:ff:ff:ff:ff") /
767                               Dot1Q(vlan=0) /
768                               ARP(op="who-has",
769                                   hwsrc=self.pg0.remote_mac,
770                                   pdst="10.10.10.3",
771                                   psrc=self.pg0.remote_ip4))
772         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
773                              dst="ff:ff:ff:ff:ff:ff") /
774                        ARP(op="who-has",
775                            hwsrc=self.pg1.remote_mac,
776                            pdst="10.10.10.3",
777                            psrc=self.pg1.remote_ip4))
778         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
779                              dst="ff:ff:ff:ff:ff:ff") /
780                        ARP(op="who-has",
781                            hwsrc=self.pg2.remote_mac,
782                            pdst="10.10.10.3",
783                            psrc=self.pg1.remote_hosts[1].ip4))
784         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
785                              dst="ff:ff:ff:ff:ff:ff") /
786                        ARP(op="who-has",
787                            hwsrc=self.pg3.remote_mac,
788                            pdst="10.10.10.3",
789                            psrc=self.pg3.remote_ip4))
790
791         #
792         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
793         #
794         self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
795                                     inet_pton(AF_INET, "10.10.10.124"))
796
797         #
798         # No responses are sent when the interfaces are not enabled for proxy
799         # ARP
800         #
801         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
802                                         "ARP req from unconfigured interface")
803         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
804                                         "ARP req from unconfigured interface")
805
806         #
807         # Make pg2 un-numbered to pg1
808         #  still won't reply.
809         #
810         self.pg2.set_unnumbered(self.pg1.sw_if_index)
811
812         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
813                                         "ARP req from unnumbered interface")
814
815         #
816         # Enable each interface to reply to proxy ARPs
817         #
818         for i in self.pg_interfaces:
819             i.set_proxy_arp()
820
821         #
822         # Now each of the interfaces should reply to a request to a proxied
823         # address
824         #
825         self.pg0.add_stream(arp_req_pg0)
826         self.pg_enable_capture(self.pg_interfaces)
827         self.pg_start()
828
829         rx = self.pg0.get_capture(1)
830         self.verify_arp_resp(rx[0],
831                              self.pg0.local_mac,
832                              self.pg0.remote_mac,
833                              "10.10.10.3",
834                              self.pg0.remote_ip4)
835
836         self.pg0.add_stream(arp_req_pg0_tagged)
837         self.pg_enable_capture(self.pg_interfaces)
838         self.pg_start()
839
840         rx = self.pg0.get_capture(1)
841         self.verify_arp_resp(rx[0],
842                              self.pg0.local_mac,
843                              self.pg0.remote_mac,
844                              "10.10.10.3",
845                              self.pg0.remote_ip4)
846
847         self.pg1.add_stream(arp_req_pg1)
848         self.pg_enable_capture(self.pg_interfaces)
849         self.pg_start()
850
851         rx = self.pg1.get_capture(1)
852         self.verify_arp_resp(rx[0],
853                              self.pg1.local_mac,
854                              self.pg1.remote_mac,
855                              "10.10.10.3",
856                              self.pg1.remote_ip4)
857
858         self.pg2.add_stream(arp_req_pg2)
859         self.pg_enable_capture(self.pg_interfaces)
860         self.pg_start()
861
862         rx = self.pg2.get_capture(1)
863         self.verify_arp_resp(rx[0],
864                              self.pg2.local_mac,
865                              self.pg2.remote_mac,
866                              "10.10.10.3",
867                              self.pg1.remote_hosts[1].ip4)
868
869         #
870         # A request for an address out of the configured range
871         #
872         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
873                                 dst="ff:ff:ff:ff:ff:ff") /
874                           ARP(op="who-has",
875                               hwsrc=self.pg1.remote_mac,
876                               pdst="10.10.10.125",
877                               psrc=self.pg1.remote_ip4))
878         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
879                                         "ARP req out of range HI")
880         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
881                                  dst="ff:ff:ff:ff:ff:ff") /
882                            ARP(op="who-has",
883                                hwsrc=self.pg1.remote_mac,
884                                pdst="10.10.10.1",
885                                psrc=self.pg1.remote_ip4))
886         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
887                                         "ARP req out of range Low")
888
889         #
890         # Request for an address in the proxy range but from an interface
891         # in a different VRF
892         #
893         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
894                                         "ARP req from different VRF")
895
896         #
897         # Disable Each interface for proxy ARP
898         #  - expect none to respond
899         #
900         for i in self.pg_interfaces:
901             i.set_proxy_arp(0)
902
903         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
904                                         "ARP req from disable")
905         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
906                                         "ARP req from disable")
907         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
908                                         "ARP req from disable")
909
910         #
911         # clean up on interface 2
912         #
913         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
914
915     def test_mpls(self):
916         """ MPLS """
917
918         #
919         # Interface 2 does not yet have ip4 config
920         #
921         self.pg2.config_ip4()
922         self.pg2.generate_remote_hosts(2)
923
924         #
925         # Add a route with out going label via an ARP unresolved next-hop
926         #
927         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
928                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
929                                                self.pg2.sw_if_index,
930                                                labels=[55])])
931         ip_10_0_0_1.add_vpp_config()
932
933         #
934         # packets should generate an ARP request
935         #
936         p = (Ether(src=self.pg0.remote_mac,
937                    dst=self.pg0.local_mac) /
938              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
939              UDP(sport=1234, dport=1234) /
940              Raw('\xa5' * 100))
941
942         self.pg0.add_stream(p)
943         self.pg_enable_capture(self.pg_interfaces)
944         self.pg_start()
945
946         rx = self.pg2.get_capture(1)
947         self.verify_arp_req(rx[0],
948                             self.pg2.local_mac,
949                             self.pg2.local_ip4,
950                             self.pg2._remote_hosts[1].ip4)
951
952         #
953         # now resolve the neighbours
954         #
955         self.pg2.configure_ipv4_neighbors()
956
957         #
958         # Now packet should be properly MPLS encapped.
959         #  This verifies that MPLS link-type adjacencies are completed
960         #  when the ARP entry resolves
961         #
962         self.pg0.add_stream(p)
963         self.pg_enable_capture(self.pg_interfaces)
964         self.pg_start()
965
966         rx = self.pg2.get_capture(1)
967         self.verify_ip_o_mpls(rx[0],
968                               self.pg2.local_mac,
969                               self.pg2.remote_hosts[1].mac,
970                               55,
971                               self.pg0.remote_ip4,
972                               "10.0.0.1")
973         self.pg2.unconfig_ip4()
974
975     def test_arp_vrrp(self):
976         """ ARP reply with VRRP virtual src hw addr """
977
978         #
979         # IP packet destined for pg1 remote host arrives on pg0 resulting
980         # in an ARP request for the address of the remote host on pg1
981         #
982         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
983               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
984               UDP(sport=1234, dport=1234) /
985               Raw())
986
987         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
988
989         self.verify_arp_req(rx1[0],
990                             self.pg1.local_mac,
991                             self.pg1.local_ip4,
992                             self.pg1.remote_ip4)
993
994         #
995         # ARP reply for address of pg1 remote host arrives on pg1 with
996         # the hw src addr set to a value in the VRRP IPv4 range of
997         # MAC addresses
998         #
999         p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1000               ARP(op="is-at", hwdst=self.pg1.local_mac,
1001                   hwsrc="00:00:5e:00:01:09", pdst=self.pg1.local_ip4,
1002                   psrc=self.pg1.remote_ip4))
1003
1004         self.send_and_assert_no_replies(self.pg1, p1, "ARP reply")
1005
1006         #
1007         # IP packet destined for pg1 remote host arrives on pg0 again.
1008         # VPP should have an ARP entry for that address now and the packet
1009         # should be sent out pg1.
1010         #
1011         rx1 = self.send_and_expect(self.pg0, [p0], self.pg1)
1012
1013         self.verify_ip(rx1[0],
1014                        self.pg1.local_mac,
1015                        "00:00:5e:00:01:09",
1016                        self.pg0.remote_ip4,
1017                        self.pg1.remote_ip4)
1018
1019         self.pg1.admin_down()
1020         self.pg1.admin_up()
1021
1022     def test_arp_duplicates(self):
1023         """ ARP Duplicates"""
1024
1025         #
1026         # Generate some hosts on the LAN
1027         #
1028         self.pg1.generate_remote_hosts(3)
1029
1030         #
1031         # Add host 1 on pg1 and pg2
1032         #
1033         arp_pg1 = VppNeighbor(self,
1034                               self.pg1.sw_if_index,
1035                               self.pg1.remote_hosts[1].mac,
1036                               self.pg1.remote_hosts[1].ip4)
1037         arp_pg1.add_vpp_config()
1038         arp_pg2 = VppNeighbor(self,
1039                               self.pg2.sw_if_index,
1040                               self.pg2.remote_mac,
1041                               self.pg1.remote_hosts[1].ip4)
1042         arp_pg2.add_vpp_config()
1043
1044         #
1045         # IP packet destined for pg1 remote host arrives on pg1 again.
1046         #
1047         p = (Ether(dst=self.pg0.local_mac,
1048                    src=self.pg0.remote_mac) /
1049              IP(src=self.pg0.remote_ip4,
1050                 dst=self.pg1.remote_hosts[1].ip4) /
1051              UDP(sport=1234, dport=1234) /
1052              Raw())
1053
1054         self.pg0.add_stream(p)
1055         self.pg_enable_capture(self.pg_interfaces)
1056         self.pg_start()
1057
1058         rx1 = self.pg1.get_capture(1)
1059
1060         self.verify_ip(rx1[0],
1061                        self.pg1.local_mac,
1062                        self.pg1.remote_hosts[1].mac,
1063                        self.pg0.remote_ip4,
1064                        self.pg1.remote_hosts[1].ip4)
1065
1066         #
1067         # remove the duplicate on pg1
1068         # packet stream should generate ARPs out of pg1
1069         #
1070         arp_pg1.remove_vpp_config()
1071
1072         self.pg0.add_stream(p)
1073         self.pg_enable_capture(self.pg_interfaces)
1074         self.pg_start()
1075
1076         rx1 = self.pg1.get_capture(1)
1077
1078         self.verify_arp_req(rx1[0],
1079                             self.pg1.local_mac,
1080                             self.pg1.local_ip4,
1081                             self.pg1.remote_hosts[1].ip4)
1082
1083         #
1084         # Add it back
1085         #
1086         arp_pg1.add_vpp_config()
1087
1088         self.pg0.add_stream(p)
1089         self.pg_enable_capture(self.pg_interfaces)
1090         self.pg_start()
1091
1092         rx1 = self.pg1.get_capture(1)
1093
1094         self.verify_ip(rx1[0],
1095                        self.pg1.local_mac,
1096                        self.pg1.remote_hosts[1].mac,
1097                        self.pg0.remote_ip4,
1098                        self.pg1.remote_hosts[1].ip4)
1099
1100     def test_arp_static(self):
1101         """ ARP Static"""
1102         self.pg2.generate_remote_hosts(3)
1103
1104         #
1105         # Add a static ARP entry
1106         #
1107         static_arp = VppNeighbor(self,
1108                                  self.pg2.sw_if_index,
1109                                  self.pg2.remote_hosts[1].mac,
1110                                  self.pg2.remote_hosts[1].ip4,
1111                                  is_static=1)
1112         static_arp.add_vpp_config()
1113
1114         #
1115         # Add the connected prefix to the interface
1116         #
1117         self.pg2.config_ip4()
1118
1119         #
1120         # We should now find the adj-fib
1121         #
1122         self.assertTrue(find_nbr(self,
1123                                  self.pg2.sw_if_index,
1124                                  self.pg2.remote_hosts[1].ip4,
1125                                  is_static=1))
1126         self.assertTrue(find_route(self,
1127                                    self.pg2.remote_hosts[1].ip4,
1128                                    32))
1129
1130         #
1131         # remove the connected
1132         #
1133         self.pg2.unconfig_ip4()
1134
1135         #
1136         # put the interface into table 1
1137         #
1138         self.pg2.set_table_ip4(1)
1139
1140         #
1141         # configure the same connected and expect to find the
1142         # adj fib in the new table
1143         #
1144         self.pg2.config_ip4()
1145         self.assertTrue(find_route(self,
1146                                    self.pg2.remote_hosts[1].ip4,
1147                                    32,
1148                                    table_id=1))
1149
1150         #
1151         # clean-up
1152         #
1153         self.pg2.unconfig_ip4()
1154         self.pg2.set_table_ip4(0)
1155
1156     def test_arp_incomplete(self):
1157         """ ARP Incomplete"""
1158         self.pg1.generate_remote_hosts(3)
1159
1160         p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1161               IP(src=self.pg0.remote_ip4,
1162                  dst=self.pg1.remote_hosts[1].ip4) /
1163               UDP(sport=1234, dport=1234) /
1164               Raw())
1165         p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1166               IP(src=self.pg0.remote_ip4,
1167                  dst=self.pg1.remote_hosts[2].ip4) /
1168               UDP(sport=1234, dport=1234) /
1169               Raw())
1170
1171         #
1172         # a packet to an unresolved destination generates an ARP request
1173         #
1174         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1175         self.verify_arp_req(rx[0],
1176                             self.pg1.local_mac,
1177                             self.pg1.local_ip4,
1178                             self.pg1._remote_hosts[1].ip4)
1179
1180         #
1181         # add a neighbour for remote host 1
1182         #
1183         static_arp = VppNeighbor(self,
1184                                  self.pg1.sw_if_index,
1185                                  self.pg1.remote_hosts[1].mac,
1186                                  self.pg1.remote_hosts[1].ip4,
1187                                  is_static=1)
1188         static_arp.add_vpp_config()
1189
1190         #
1191         # change the interface's MAC
1192         #
1193         mac = [scapy.compat.chb(0x00), scapy.compat.chb(0x00),
1194                scapy.compat.chb(0x00), scapy.compat.chb(0x33),
1195                scapy.compat.chb(0x33), scapy.compat.chb(0x33)]
1196         mac_string = ''.join(mac)
1197
1198         self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
1199                                                mac_string)
1200
1201         #
1202         # now ARP requests come from the new source mac
1203         #
1204         rx = self.send_and_expect(self.pg0, [p1], self.pg1)
1205         self.verify_arp_req(rx[0],
1206                             "00:00:00:33:33:33",
1207                             self.pg1.local_ip4,
1208                             self.pg1._remote_hosts[2].ip4)
1209
1210         #
1211         # packets to the resolved host also have the new source mac
1212         #
1213         rx = self.send_and_expect(self.pg0, [p0], self.pg1)
1214         self.verify_ip(rx[0],
1215                        "00:00:00:33:33:33",
1216                        self.pg1.remote_hosts[1].mac,
1217                        self.pg0.remote_ip4,
1218                        self.pg1.remote_hosts[1].ip4)
1219
1220         #
1221         # set the mac address on the interface that does not have a
1222         # configured subnet and thus no glean
1223         #
1224         self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
1225                                                mac_string)
1226
1227     def test_garp(self):
1228         """ GARP """
1229
1230         #
1231         # Generate some hosts on the LAN
1232         #
1233         self.pg1.generate_remote_hosts(4)
1234
1235         #
1236         # And an ARP entry
1237         #
1238         arp = VppNeighbor(self,
1239                           self.pg1.sw_if_index,
1240                           self.pg1.remote_hosts[1].mac,
1241                           self.pg1.remote_hosts[1].ip4)
1242         arp.add_vpp_config()
1243
1244         self.assertTrue(find_nbr(self,
1245                                  self.pg1.sw_if_index,
1246                                  self.pg1.remote_hosts[1].ip4,
1247                                  mac=self.pg1.remote_hosts[1].mac))
1248
1249         #
1250         # Send a GARP (request) to swap the host 1's address to that of host 2
1251         #
1252         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1253                     src=self.pg1.remote_hosts[2].mac) /
1254               ARP(op="who-has",
1255                   hwdst=self.pg1.local_mac,
1256                   hwsrc=self.pg1.remote_hosts[2].mac,
1257                   pdst=self.pg1.remote_hosts[1].ip4,
1258                   psrc=self.pg1.remote_hosts[1].ip4))
1259
1260         self.pg1.add_stream(p1)
1261         self.pg_enable_capture(self.pg_interfaces)
1262         self.pg_start()
1263
1264         self.assertTrue(find_nbr(self,
1265                                  self.pg1.sw_if_index,
1266                                  self.pg1.remote_hosts[1].ip4,
1267                                  mac=self.pg1.remote_hosts[2].mac))
1268
1269         #
1270         # Send a GARP (reply) to swap the host 1's address to that of host 3
1271         #
1272         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1273                     src=self.pg1.remote_hosts[3].mac) /
1274               ARP(op="is-at",
1275                   hwdst=self.pg1.local_mac,
1276                   hwsrc=self.pg1.remote_hosts[3].mac,
1277                   pdst=self.pg1.remote_hosts[1].ip4,
1278                   psrc=self.pg1.remote_hosts[1].ip4))
1279
1280         self.pg1.add_stream(p1)
1281         self.pg_enable_capture(self.pg_interfaces)
1282         self.pg_start()
1283
1284         self.assertTrue(find_nbr(self,
1285                                  self.pg1.sw_if_index,
1286                                  self.pg1.remote_hosts[1].ip4,
1287                                  mac=self.pg1.remote_hosts[3].mac))
1288
1289         #
1290         # GARPs (request nor replies) for host we don't know yet
1291         # don't result in new neighbour entries
1292         #
1293         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1294                     src=self.pg1.remote_hosts[3].mac) /
1295               ARP(op="who-has",
1296                   hwdst=self.pg1.local_mac,
1297                   hwsrc=self.pg1.remote_hosts[3].mac,
1298                   pdst=self.pg1.remote_hosts[2].ip4,
1299                   psrc=self.pg1.remote_hosts[2].ip4))
1300
1301         self.pg1.add_stream(p1)
1302         self.pg_enable_capture(self.pg_interfaces)
1303         self.pg_start()
1304
1305         self.assertFalse(find_nbr(self,
1306                                   self.pg1.sw_if_index,
1307                                   self.pg1.remote_hosts[2].ip4))
1308
1309         p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
1310                     src=self.pg1.remote_hosts[3].mac) /
1311               ARP(op="is-at",
1312                   hwdst=self.pg1.local_mac,
1313                   hwsrc=self.pg1.remote_hosts[3].mac,
1314                   pdst=self.pg1.remote_hosts[2].ip4,
1315                   psrc=self.pg1.remote_hosts[2].ip4))
1316
1317         self.pg1.add_stream(p1)
1318         self.pg_enable_capture(self.pg_interfaces)
1319         self.pg_start()
1320
1321         self.assertFalse(find_nbr(self,
1322                                   self.pg1.sw_if_index,
1323                                   self.pg1.remote_hosts[2].ip4))
1324
1325     def test_arp_incomplete(self):
1326         """ Incomplete Entries """
1327
1328         #
1329         # ensure that we throttle the ARP and ND requests
1330         #
1331         self.pg0.generate_remote_hosts(2)
1332
1333         #
1334         # IPv4/ARP
1335         #
1336         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1337                                  [VppRoutePath(self.pg0.remote_hosts[1].ip4,
1338                                                self.pg0.sw_if_index)])
1339         ip_10_0_0_1.add_vpp_config()
1340
1341         p1 = (Ether(dst=self.pg1.local_mac,
1342                     src=self.pg1.remote_mac) /
1343               IP(src=self.pg1.remote_ip4,
1344                  dst="10.0.0.1") /
1345               UDP(sport=1234, dport=1234) /
1346               Raw())
1347
1348         self.pg1.add_stream(p1 * 257)
1349         self.pg_enable_capture(self.pg_interfaces)
1350         self.pg_start()
1351         rx = self.pg0._get_capture(1)
1352
1353         #
1354         # how many we get is going to be dependent on the time for packet
1355         # processing but it should be small
1356         #
1357         self.assertLess(len(rx), 64)
1358
1359         #
1360         # IPv6/ND
1361         #
1362         ip_10_1 = VppIpRoute(self, "10::1", 128,
1363                              [VppRoutePath(self.pg0.remote_hosts[1].ip6,
1364                                            self.pg0.sw_if_index,
1365                                            proto=DpoProto.DPO_PROTO_IP6)])
1366         ip_10_1.add_vpp_config()
1367
1368         p1 = (Ether(dst=self.pg1.local_mac,
1369                     src=self.pg1.remote_mac) /
1370               IPv6(src=self.pg1.remote_ip6,
1371                    dst="10::1") /
1372               UDP(sport=1234, dport=1234) /
1373               Raw())
1374
1375         self.pg1.add_stream(p1 * 257)
1376         self.pg_enable_capture(self.pg_interfaces)
1377         self.pg_start()
1378         rx = self.pg0._get_capture(1)
1379
1380         #
1381         # how many we get is going to be dependent on the time for packet
1382         # processing but it should be small
1383         #
1384         self.assertLess(len(rx), 64)
1385
1386     def test_arp_forus(self):
1387         """ ARP for for-us """
1388
1389         #
1390         # Test that VPP responds with ARP requests to addresses that
1391         # are connected and local routes.
1392         # Use one of the 'remote' addresses in the subnet as a local address
1393         # The intention of this route is that it then acts like a secondary
1394         # address added to an interface
1395         #
1396         self.pg0.generate_remote_hosts(2)
1397
1398         forus = VppIpRoute(
1399             self, self.pg0.remote_hosts[1].ip4, 32,
1400             [VppRoutePath("0.0.0.0",
1401                           self.pg0.sw_if_index,
1402                           type=FibPathType.FIB_PATH_TYPE_LOCAL)])
1403         forus.add_vpp_config()
1404
1405         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
1406                    src=self.pg0.remote_mac) /
1407              ARP(op="who-has",
1408                  hwdst=self.pg0.local_mac,
1409                  hwsrc=self.pg0.remote_mac,
1410                  pdst=self.pg0.remote_hosts[1].ip4,
1411                  psrc=self.pg0.remote_ip4))
1412
1413         rx = self.send_and_expect(self.pg0, [p], self.pg0)
1414
1415         self.verify_arp_resp(rx[0],
1416                              self.pg0.local_mac,
1417                              self.pg0.remote_mac,
1418                              self.pg0.remote_hosts[1].ip4,
1419                              self.pg0.remote_ip4)
1420
1421
1422 class NeighborStatsTestCase(VppTestCase):
1423     """ ARP/ND Counters """
1424
1425     @classmethod
1426     def setUpClass(cls):
1427         super(NeighborStatsTestCase, cls).setUpClass()
1428
1429     @classmethod
1430     def tearDownClass(cls):
1431         super(NeighborStatsTestCase, cls).tearDownClass()
1432
1433     def setUp(self):
1434         super(NeighborStatsTestCase, self).setUp()
1435
1436         self.create_pg_interfaces(range(2))
1437
1438         # pg0 configured with ip4 and 6 addresses used for input
1439         # pg1 configured with ip4 and 6 addresses used for output
1440         # pg2 is unnumbered to pg0
1441         for i in self.pg_interfaces:
1442             i.admin_up()
1443             i.config_ip4()
1444             i.config_ip6()
1445             i.resolve_arp()
1446             i.resolve_ndp()
1447
1448     def tearDown(self):
1449         super(NeighborStatsTestCase, self).tearDown()
1450
1451         for i in self.pg_interfaces:
1452             i.unconfig_ip4()
1453             i.unconfig_ip6()
1454             i.admin_down()
1455
1456     def test_arp_stats(self):
1457         """ ARP Counters """
1458
1459         self.vapi.cli("adj counters enable")
1460         self.pg1.generate_remote_hosts(2)
1461
1462         arp1 = VppNeighbor(self,
1463                            self.pg1.sw_if_index,
1464                            self.pg1.remote_hosts[0].mac,
1465                            self.pg1.remote_hosts[0].ip4)
1466         arp1.add_vpp_config()
1467         arp2 = VppNeighbor(self,
1468                            self.pg1.sw_if_index,
1469                            self.pg1.remote_hosts[1].mac,
1470                            self.pg1.remote_hosts[1].ip4)
1471         arp2.add_vpp_config()
1472
1473         p1 = (Ether(dst=self.pg0.local_mac,
1474                     src=self.pg0.remote_mac) /
1475               IP(src=self.pg0.remote_ip4,
1476                  dst=self.pg1.remote_hosts[0].ip4) /
1477               UDP(sport=1234, dport=1234) /
1478               Raw())
1479         p2 = (Ether(dst=self.pg0.local_mac,
1480                     src=self.pg0.remote_mac) /
1481               IP(src=self.pg0.remote_ip4,
1482                  dst=self.pg1.remote_hosts[1].ip4) /
1483               UDP(sport=1234, dport=1234) /
1484               Raw())
1485
1486         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1487         rx = self.send_and_expect(self.pg0, p2 * NUM_PKTS, self.pg1)
1488
1489         self.assertEqual(NUM_PKTS, arp1.get_stats()['packets'])
1490         self.assertEqual(NUM_PKTS, arp2.get_stats()['packets'])
1491
1492         rx = self.send_and_expect(self.pg0, p1 * NUM_PKTS, self.pg1)
1493         self.assertEqual(NUM_PKTS*2, arp1.get_stats()['packets'])
1494
1495     def test_nd_stats(self):
1496         """ ND Counters """
1497
1498         self.vapi.cli("adj counters enable")
1499         self.pg0.generate_remote_hosts(3)
1500
1501         nd1 = VppNeighbor(self,
1502                           self.pg0.sw_if_index,
1503                           self.pg0.remote_hosts[1].mac,
1504                           self.pg0.remote_hosts[1].ip6)
1505         nd1.add_vpp_config()
1506         nd2 = VppNeighbor(self,
1507                           self.pg0.sw_if_index,
1508                           self.pg0.remote_hosts[2].mac,
1509                           self.pg0.remote_hosts[2].ip6)
1510         nd2.add_vpp_config()
1511
1512         p1 = (Ether(dst=self.pg1.local_mac,
1513                     src=self.pg1.remote_mac) /
1514               IPv6(src=self.pg1.remote_ip6,
1515                    dst=self.pg0.remote_hosts[1].ip6) /
1516               UDP(sport=1234, dport=1234) /
1517               Raw())
1518         p2 = (Ether(dst=self.pg1.local_mac,
1519                     src=self.pg1.remote_mac) /
1520               IPv6(src=self.pg1.remote_ip6,
1521                    dst=self.pg0.remote_hosts[2].ip6) /
1522               UDP(sport=1234, dport=1234) /
1523               Raw())
1524
1525         rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
1526         rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
1527
1528         self.assertEqual(16, nd1.get_stats()['packets'])
1529         self.assertEqual(16, nd2.get_stats()['packets'])
1530
1531         rx = self.send_and_expect(self.pg1, p1 * NUM_PKTS, self.pg0)
1532         self.assertEqual(NUM_PKTS+16, nd1.get_stats()['packets'])
1533
1534
1535 if __name__ == '__main__':
1536     unittest.main(testRunner=VppTestRunner)