IMplementation for option to not create a FIB table entry when adding a neighbor...
[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
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether, ARP
12 from scapy.layers.inet import IP, UDP
13 from scapy.contrib.mpls import MPLS
14
15 # not exported by scapy, so redefined here
16 arp_opts = {"who-has": 1, "is-at": 2}
17
18
19 class ARPTestCase(VppTestCase):
20     """ ARP Test Case """
21
22     def setUp(self):
23         super(ARPTestCase, self).setUp()
24
25         # create 3 pg interfaces
26         self.create_pg_interfaces(range(4))
27
28         # pg0 configured with ip4 and 6 addresses used for input
29         # pg1 configured with ip4 and 6 addresses used for output
30         # pg2 is unnumbered to pg0
31         for i in self.pg_interfaces:
32             i.admin_up()
33
34         self.pg0.config_ip4()
35         self.pg0.config_ip6()
36         self.pg0.resolve_arp()
37
38         self.pg1.config_ip4()
39         self.pg1.config_ip6()
40
41         # pg3 in a different VRF
42         self.pg3.set_table_ip4(1)
43         self.pg3.config_ip4()
44
45     def tearDown(self):
46         super(ARPTestCase, self).tearDown()
47         for i in self.pg_interfaces:
48             i.unconfig_ip4()
49             i.unconfig_ip6()
50             i.admin_down()
51
52     def verify_arp_req(self, rx, smac, sip, dip):
53         ether = rx[Ether]
54         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
55         self.assertEqual(ether.src, smac)
56
57         arp = rx[ARP]
58         self.assertEqual(arp.hwtype, 1)
59         self.assertEqual(arp.ptype, 0x800)
60         self.assertEqual(arp.hwlen, 6)
61         self.assertEqual(arp.plen, 4)
62         self.assertEqual(arp.op, arp_opts["who-has"])
63         self.assertEqual(arp.hwsrc, smac)
64         self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
65         self.assertEqual(arp.psrc, sip)
66         self.assertEqual(arp.pdst, dip)
67
68     def verify_arp_resp(self, rx, smac, dmac, sip, dip):
69         ether = rx[Ether]
70         self.assertEqual(ether.dst, dmac)
71         self.assertEqual(ether.src, smac)
72
73         arp = rx[ARP]
74         self.assertEqual(arp.hwtype, 1)
75         self.assertEqual(arp.ptype, 0x800)
76         self.assertEqual(arp.hwlen, 6)
77         self.assertEqual(arp.plen, 4)
78         self.assertEqual(arp.op, arp_opts["is-at"])
79         self.assertEqual(arp.hwsrc, smac)
80         self.assertEqual(arp.hwdst, dmac)
81         self.assertEqual(arp.psrc, sip)
82         self.assertEqual(arp.pdst, dip)
83
84     def verify_ip(self, rx, smac, dmac, sip, dip):
85         ether = rx[Ether]
86         self.assertEqual(ether.dst, dmac)
87         self.assertEqual(ether.src, smac)
88
89         ip = rx[IP]
90         self.assertEqual(ip.src, sip)
91         self.assertEqual(ip.dst, dip)
92
93     def verify_ip_o_mpls(self, rx, smac, dmac, label, sip, dip):
94         ether = rx[Ether]
95         self.assertEqual(ether.dst, dmac)
96         self.assertEqual(ether.src, smac)
97
98         mpls = rx[MPLS]
99         self.assertTrue(mpls.label, label)
100
101         ip = rx[IP]
102         self.assertEqual(ip.src, sip)
103         self.assertEqual(ip.dst, dip)
104
105     def send_and_assert_no_replies(self, intf, pkts, remark):
106         intf.add_stream(pkts)
107         self.pg_enable_capture(self.pg_interfaces)
108         self.pg_start()
109         for i in self.pg_interfaces:
110             i.assert_nothing_captured(remark=remark)
111
112     def test_arp(self):
113         """ ARP """
114
115         #
116         # Generate some hosts on the LAN
117         #
118         self.pg1.generate_remote_hosts(5)
119
120         #
121         # Send IP traffic to one of these unresolved hosts.
122         #  expect the generation of an ARP request
123         #
124         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
125              IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) /
126              UDP(sport=1234, dport=1234) /
127              Raw())
128
129         self.pg0.add_stream(p)
130         self.pg_enable_capture(self.pg_interfaces)
131         self.pg_start()
132
133         rx = self.pg1.get_capture(1)
134
135         self.verify_arp_req(rx[0],
136                             self.pg1.local_mac,
137                             self.pg1.local_ip4,
138                             self.pg1._remote_hosts[1].ip4)
139
140         #
141         # And a dynamic ARP entry for host 1
142         #
143         dyn_arp = VppNeighbor(self,
144                               self.pg1.sw_if_index,
145                               self.pg1.remote_hosts[1].mac,
146                               self.pg1.remote_hosts[1].ip4)
147         dyn_arp.add_vpp_config()
148
149         #
150         # now we expect IP traffic forwarded
151         #
152         dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
153                  IP(src=self.pg0.remote_ip4,
154                     dst=self.pg1._remote_hosts[1].ip4) /
155                  UDP(sport=1234, dport=1234) /
156                  Raw())
157
158         self.pg0.add_stream(dyn_p)
159         self.pg_enable_capture(self.pg_interfaces)
160         self.pg_start()
161
162         rx = self.pg1.get_capture(1)
163
164         self.verify_ip(rx[0],
165                        self.pg1.local_mac,
166                        self.pg1.remote_hosts[1].mac,
167                        self.pg0.remote_ip4,
168                        self.pg1._remote_hosts[1].ip4)
169
170         #
171         # And a Static ARP entry for host 2
172         #
173         static_arp = VppNeighbor(self,
174                                  self.pg1.sw_if_index,
175                                  self.pg1.remote_hosts[2].mac,
176                                  self.pg1.remote_hosts[2].ip4,
177                                  is_static=1)
178         static_arp.add_vpp_config()
179
180         static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
181                     IP(src=self.pg0.remote_ip4,
182                        dst=self.pg1._remote_hosts[2].ip4) /
183                     UDP(sport=1234, dport=1234) /
184                     Raw())
185
186         self.pg0.add_stream(static_p)
187         self.pg_enable_capture(self.pg_interfaces)
188         self.pg_start()
189
190         rx = self.pg1.get_capture(1)
191
192         self.verify_ip(rx[0],
193                        self.pg1.local_mac,
194                        self.pg1.remote_hosts[2].mac,
195                        self.pg0.remote_ip4,
196                        self.pg1._remote_hosts[2].ip4)
197
198         #
199         # flap the link. dynamic ARPs get flush, statics don't
200         #
201         self.pg1.admin_down()
202         self.pg1.admin_up()
203
204         self.pg0.add_stream(static_p)
205         self.pg_enable_capture(self.pg_interfaces)
206         self.pg_start()
207         rx = self.pg1.get_capture(1)
208
209         self.verify_ip(rx[0],
210                        self.pg1.local_mac,
211                        self.pg1.remote_hosts[2].mac,
212                        self.pg0.remote_ip4,
213                        self.pg1._remote_hosts[2].ip4)
214
215         self.pg0.add_stream(dyn_p)
216         self.pg_enable_capture(self.pg_interfaces)
217         self.pg_start()
218
219         rx = self.pg1.get_capture(1)
220         self.verify_arp_req(rx[0],
221                             self.pg1.local_mac,
222                             self.pg1.local_ip4,
223                             self.pg1._remote_hosts[1].ip4)
224
225         #
226         # Send an ARP request from one of the so-far unlearned remote hosts
227         #
228         p = (Ether(dst="ff:ff:ff:ff:ff:ff",
229                    src=self.pg1._remote_hosts[3].mac) /
230              ARP(op="who-has",
231                  hwsrc=self.pg1._remote_hosts[3].mac,
232                  pdst=self.pg1.local_ip4,
233                  psrc=self.pg1._remote_hosts[3].ip4))
234
235         self.pg1.add_stream(p)
236         self.pg_enable_capture(self.pg_interfaces)
237         self.pg_start()
238
239         rx = self.pg1.get_capture(1)
240         self.verify_arp_resp(rx[0],
241                              self.pg1.local_mac,
242                              self.pg1._remote_hosts[3].mac,
243                              self.pg1.local_ip4,
244                              self.pg1._remote_hosts[3].ip4)
245
246         #
247         # VPP should have learned the mapping for the remote host
248         #
249         self.assertTrue(find_nbr(self,
250                                  self.pg1.sw_if_index,
251                                  self.pg1._remote_hosts[3].ip4))
252
253         #
254         # ERROR Cases
255         #  1 - don't respond to ARP request for address not within the
256         #      interface's sub-net
257         #
258         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
259              ARP(op="who-has",
260                  hwsrc=self.pg0.remote_mac,
261                  pdst="10.10.10.3",
262                  psrc=self.pg0.remote_ip4))
263         self.send_and_assert_no_replies(self.pg0, p,
264                                         "ARP req for non-local destination")
265
266         #
267         #  2 - don't respond to ARP request from an address not within the
268         #      interface's sub-net
269         #
270         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
271              ARP(op="who-has",
272                  hwsrc=self.pg0.remote_mac,
273                  psrc="10.10.10.3",
274                  pdst=self.pg0.local_ip4))
275         self.send_and_assert_no_replies(self.pg0, p,
276                                         "ARP req for non-local source")
277
278         #
279         #  3 - don't respond to ARP request from an address that belongs to
280         #      the router
281         #
282         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
283              ARP(op="who-has",
284                  hwsrc=self.pg0.remote_mac,
285                  psrc=self.pg0.local_ip4,
286                  pdst=self.pg0.local_ip4))
287         self.send_and_assert_no_replies(self.pg0, p,
288                                         "ARP req for non-local source")
289
290         #
291         #  4 - don't respond to ARP requests that has mac source different
292         #      from ARP request HW source
293         #      the router
294         #
295         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
296              ARP(op="who-has",
297                  hwsrc="00:00:00:DE:AD:BE",
298                  psrc=self.pg0.remote_ip4,
299                  pdst=self.pg0.local_ip4))
300         self.send_and_assert_no_replies(self.pg0, p,
301                                         "ARP req for non-local source")
302
303         #
304         # A neighbor entry that has no associated FIB-entry
305         #
306         arp_no_fib = VppNeighbor(self,
307                                  self.pg1.sw_if_index,
308                                  self.pg1.remote_hosts[4].mac,
309                                  self.pg1.remote_hosts[4].ip4,
310                                  is_no_fib_entry=1)
311         arp_no_fib.add_vpp_config()
312
313         #
314         # check we have the neighbor, but no route
315         #
316         self.assertTrue(find_nbr(self,
317                                  self.pg1.sw_if_index,
318                                  self.pg1._remote_hosts[4].ip4))
319         self.assertFalse(find_route(self,
320                                     self.pg1._remote_hosts[4].ip4,
321                                     32))
322         #
323         # cleanup
324         #
325         dyn_arp.remove_vpp_config()
326         static_arp.remove_vpp_config()
327
328     def test_proxy_arp(self):
329         """ Proxy ARP """
330
331         #
332         # Proxy ARP rewquest packets for each interface
333         #
334         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
335                              dst="ff:ff:ff:ff:ff:ff") /
336                        ARP(op="who-has",
337                            hwsrc=self.pg2.remote_mac,
338                            pdst="10.10.10.3",
339                            psrc=self.pg1.remote_ip4))
340         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
341                              dst="ff:ff:ff:ff:ff:ff") /
342                        ARP(op="who-has",
343                            hwsrc=self.pg0.remote_mac,
344                            pdst="10.10.10.3",
345                            psrc=self.pg0.remote_ip4))
346         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
347                              dst="ff:ff:ff:ff:ff:ff") /
348                        ARP(op="who-has",
349                            hwsrc=self.pg1.remote_mac,
350                            pdst="10.10.10.3",
351                            psrc=self.pg1.remote_ip4))
352         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
353                              dst="ff:ff:ff:ff:ff:ff") /
354                        ARP(op="who-has",
355                            hwsrc=self.pg3.remote_mac,
356                            pdst="10.10.10.3",
357                            psrc=self.pg3.remote_ip4))
358
359         #
360         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
361         #
362         self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
363                                     inet_pton(AF_INET, "10.10.10.124"))
364
365         #
366         # No responses are sent when the interfaces are not enabled for proxy
367         # ARP
368         #
369         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
370                                         "ARP req from unconfigured interface")
371         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
372                                         "ARP req from unconfigured interface")
373
374         #
375         # Make pg2 un-numbered to pg1
376         #  still won't reply.
377         #
378         self.pg2.set_unnumbered(self.pg1.sw_if_index)
379
380         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
381                                         "ARP req from unnumbered interface")
382
383         #
384         # Enable each interface to reply to proxy ARPs
385         #
386         for i in self.pg_interfaces:
387             i.set_proxy_arp()
388
389         #
390         # Now each of the interfaces should reply to a request to a proxied
391         # address
392         #
393         self.pg0.add_stream(arp_req_pg0)
394         self.pg_enable_capture(self.pg_interfaces)
395         self.pg_start()
396
397         rx = self.pg0.get_capture(1)
398         self.verify_arp_resp(rx[0],
399                              self.pg0.local_mac,
400                              self.pg0.remote_mac,
401                              "10.10.10.3",
402                              self.pg0.remote_ip4)
403
404         self.pg1.add_stream(arp_req_pg1)
405         self.pg_enable_capture(self.pg_interfaces)
406         self.pg_start()
407
408         rx = self.pg1.get_capture(1)
409         self.verify_arp_resp(rx[0],
410                              self.pg1.local_mac,
411                              self.pg1.remote_mac,
412                              "10.10.10.3",
413                              self.pg1.remote_ip4)
414
415         self.pg2.add_stream(arp_req_pg2)
416         self.pg_enable_capture(self.pg_interfaces)
417         self.pg_start()
418
419         rx = self.pg2.get_capture(1)
420         self.verify_arp_resp(rx[0],
421                              self.pg2.local_mac,
422                              self.pg2.remote_mac,
423                              "10.10.10.3",
424                              self.pg1.remote_ip4)
425
426         #
427         # A request for an address out of the configured range
428         #
429         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
430                                 dst="ff:ff:ff:ff:ff:ff") /
431                           ARP(op="who-has",
432                               hwsrc=self.pg1.remote_mac,
433                               pdst="10.10.10.125",
434                               psrc=self.pg1.remote_ip4))
435         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
436                                         "ARP req out of range HI")
437         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
438                                  dst="ff:ff:ff:ff:ff:ff") /
439                            ARP(op="who-has",
440                                hwsrc=self.pg1.remote_mac,
441                                pdst="10.10.10.1",
442                                psrc=self.pg1.remote_ip4))
443         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
444                                         "ARP req out of range Low")
445
446         #
447         # Request for an address in the proxy range but from an interface
448         # in a different VRF
449         #
450         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
451                                         "ARP req from different VRF")
452
453         #
454         # Disable Each interface for proxy ARP
455         #  - expect none to respond
456         #
457         for i in self.pg_interfaces:
458             i.set_proxy_arp(0)
459
460         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
461                                         "ARP req from disable")
462         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
463                                         "ARP req from disable")
464         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
465                                         "ARP req from disable")
466
467         #
468         # clean up on interface 2
469         #
470         self.pg2.set_unnumbered(self.pg1.sw_if_index)
471
472     def test_mpls(self):
473         """ MPLS """
474
475         #
476         # Interface 2 does not yet have ip4 config
477         #
478         self.pg2.config_ip4()
479         self.pg2.generate_remote_hosts(2)
480
481         #
482         # Add a reoute with out going label via an ARP unresolved next-hop
483         #
484         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
485                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
486                                                self.pg2.sw_if_index,
487                                                labels=[55])])
488         ip_10_0_0_1.add_vpp_config()
489
490         #
491         # packets should generate an ARP request
492         #
493         p = (Ether(src=self.pg0.remote_mac,
494                    dst=self.pg0.local_mac) /
495              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
496              UDP(sport=1234, dport=1234) /
497              Raw('\xa5' * 100))
498
499         self.pg0.add_stream(p)
500         self.pg_enable_capture(self.pg_interfaces)
501         self.pg_start()
502
503         rx = self.pg2.get_capture(1)
504         self.verify_arp_req(rx[0],
505                             self.pg2.local_mac,
506                             self.pg2.local_ip4,
507                             self.pg2._remote_hosts[1].ip4)
508
509         #
510         # now resolve the neighbours
511         #
512         self.pg2.configure_ipv4_neighbors()
513
514         #
515         # Now packet should be properly MPLS encapped.
516         #  This verifies that MPLS link-type adjacencies are completed
517         #  when the ARP entry resolves
518         #
519         self.pg0.add_stream(p)
520         self.pg_enable_capture(self.pg_interfaces)
521         self.pg_start()
522
523         rx = self.pg2.get_capture(1)
524         self.verify_ip_o_mpls(rx[0],
525                               self.pg2.local_mac,
526                               self.pg2.remote_hosts[1].mac,
527                               55,
528                               self.pg0.remote_ip4,
529                               "10.0.0.1")
530
531 if __name__ == '__main__':
532     unittest.main(testRunner=VppTestRunner)