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