Adjacency refinement; check the cover's interface against the adjacency's
[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(6)
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         # A neighbor entry that has no associated FIB-entry
255         #
256         arp_no_fib = VppNeighbor(self,
257                                  self.pg1.sw_if_index,
258                                  self.pg1.remote_hosts[4].mac,
259                                  self.pg1.remote_hosts[4].ip4,
260                                  is_no_fib_entry=1)
261         arp_no_fib.add_vpp_config()
262
263         #
264         # check we have the neighbor, but no route
265         #
266         self.assertTrue(find_nbr(self,
267                                  self.pg1.sw_if_index,
268                                  self.pg1._remote_hosts[4].ip4))
269         self.assertFalse(find_route(self,
270                                     self.pg1._remote_hosts[4].ip4,
271                                     32))
272         #
273         # Unnumbered pg2 to pg1
274         #
275         self.pg2.set_unnumbered(self.pg1.sw_if_index)
276
277         #
278         # now we can form adjacencies out of pg2 from within pg1's subnet
279         #
280         arp_unnum = VppNeighbor(self,
281                                 self.pg2.sw_if_index,
282                                 self.pg1.remote_hosts[5].mac,
283                                 self.pg1.remote_hosts[5].ip4)
284         arp_unnum.add_vpp_config()
285
286         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
287              IP(src=self.pg0.remote_ip4,
288                 dst=self.pg1._remote_hosts[5].ip4) /
289              UDP(sport=1234, dport=1234) /
290              Raw())
291
292         self.pg0.add_stream(p)
293         self.pg_enable_capture(self.pg_interfaces)
294         self.pg_start()
295
296         rx = self.pg2.get_capture(1)
297
298         self.verify_ip(rx[0],
299                        self.pg2.local_mac,
300                        self.pg1.remote_hosts[5].mac,
301                        self.pg0.remote_ip4,
302                        self.pg1._remote_hosts[5].ip4)
303
304         #
305         # ERROR Cases
306         #  1 - don't respond to ARP request for address not within the
307         #      interface's sub-net
308         #
309         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
310              ARP(op="who-has",
311                  hwsrc=self.pg0.remote_mac,
312                  pdst="10.10.10.3",
313                  psrc=self.pg0.remote_ip4))
314         self.send_and_assert_no_replies(self.pg0, p,
315                                         "ARP req for non-local destination")
316
317         #
318         #  2 - don't respond to ARP request from an address not within the
319         #      interface's sub-net
320         #
321         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
322              ARP(op="who-has",
323                  hwsrc=self.pg0.remote_mac,
324                  psrc="10.10.10.3",
325                  pdst=self.pg0.local_ip4))
326         self.send_and_assert_no_replies(self.pg0, p,
327                                         "ARP req for non-local source")
328
329         #
330         #  3 - don't respond to ARP request from an address that belongs to
331         #      the router
332         #
333         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
334              ARP(op="who-has",
335                  hwsrc=self.pg0.remote_mac,
336                  psrc=self.pg0.local_ip4,
337                  pdst=self.pg0.local_ip4))
338         self.send_and_assert_no_replies(self.pg0, p,
339                                         "ARP req for non-local source")
340
341         #
342         #  4 - don't respond to ARP requests that has mac source different
343         #      from ARP request HW source
344         #      the router
345         #
346         p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
347              ARP(op="who-has",
348                  hwsrc="00:00:00:DE:AD:BE",
349                  psrc=self.pg0.remote_ip4,
350                  pdst=self.pg0.local_ip4))
351         self.send_and_assert_no_replies(self.pg0, p,
352                                         "ARP req for non-local source")
353
354         #
355         # cleanup
356         #
357         dyn_arp.remove_vpp_config()
358         static_arp.remove_vpp_config()
359         self.pg2.unset_unnumbered(self.pg1.sw_if_index)
360
361     def test_proxy_arp(self):
362         """ Proxy ARP """
363
364         #
365         # Proxy ARP rewquest packets for each interface
366         #
367         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
368                              dst="ff:ff:ff:ff:ff:ff") /
369                        ARP(op="who-has",
370                            hwsrc=self.pg2.remote_mac,
371                            pdst="10.10.10.3",
372                            psrc=self.pg1.remote_ip4))
373         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
374                              dst="ff:ff:ff:ff:ff:ff") /
375                        ARP(op="who-has",
376                            hwsrc=self.pg0.remote_mac,
377                            pdst="10.10.10.3",
378                            psrc=self.pg0.remote_ip4))
379         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
380                              dst="ff:ff:ff:ff:ff:ff") /
381                        ARP(op="who-has",
382                            hwsrc=self.pg1.remote_mac,
383                            pdst="10.10.10.3",
384                            psrc=self.pg1.remote_ip4))
385         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
386                              dst="ff:ff:ff:ff:ff:ff") /
387                        ARP(op="who-has",
388                            hwsrc=self.pg3.remote_mac,
389                            pdst="10.10.10.3",
390                            psrc=self.pg3.remote_ip4))
391
392         #
393         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
394         #
395         self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
396                                     inet_pton(AF_INET, "10.10.10.124"))
397
398         #
399         # No responses are sent when the interfaces are not enabled for proxy
400         # ARP
401         #
402         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
403                                         "ARP req from unconfigured interface")
404         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
405                                         "ARP req from unconfigured interface")
406
407         #
408         # Make pg2 un-numbered to pg1
409         #  still won't reply.
410         #
411         self.pg2.set_unnumbered(self.pg1.sw_if_index)
412
413         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
414                                         "ARP req from unnumbered interface")
415
416         #
417         # Enable each interface to reply to proxy ARPs
418         #
419         for i in self.pg_interfaces:
420             i.set_proxy_arp()
421
422         #
423         # Now each of the interfaces should reply to a request to a proxied
424         # address
425         #
426         self.pg0.add_stream(arp_req_pg0)
427         self.pg_enable_capture(self.pg_interfaces)
428         self.pg_start()
429
430         rx = self.pg0.get_capture(1)
431         self.verify_arp_resp(rx[0],
432                              self.pg0.local_mac,
433                              self.pg0.remote_mac,
434                              "10.10.10.3",
435                              self.pg0.remote_ip4)
436
437         self.pg1.add_stream(arp_req_pg1)
438         self.pg_enable_capture(self.pg_interfaces)
439         self.pg_start()
440
441         rx = self.pg1.get_capture(1)
442         self.verify_arp_resp(rx[0],
443                              self.pg1.local_mac,
444                              self.pg1.remote_mac,
445                              "10.10.10.3",
446                              self.pg1.remote_ip4)
447
448         self.pg2.add_stream(arp_req_pg2)
449         self.pg_enable_capture(self.pg_interfaces)
450         self.pg_start()
451
452         rx = self.pg2.get_capture(1)
453         self.verify_arp_resp(rx[0],
454                              self.pg2.local_mac,
455                              self.pg2.remote_mac,
456                              "10.10.10.3",
457                              self.pg1.remote_ip4)
458
459         #
460         # A request for an address out of the configured range
461         #
462         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
463                                 dst="ff:ff:ff:ff:ff:ff") /
464                           ARP(op="who-has",
465                               hwsrc=self.pg1.remote_mac,
466                               pdst="10.10.10.125",
467                               psrc=self.pg1.remote_ip4))
468         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
469                                         "ARP req out of range HI")
470         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
471                                  dst="ff:ff:ff:ff:ff:ff") /
472                            ARP(op="who-has",
473                                hwsrc=self.pg1.remote_mac,
474                                pdst="10.10.10.1",
475                                psrc=self.pg1.remote_ip4))
476         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
477                                         "ARP req out of range Low")
478
479         #
480         # Request for an address in the proxy range but from an interface
481         # in a different VRF
482         #
483         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
484                                         "ARP req from different VRF")
485
486         #
487         # Disable Each interface for proxy ARP
488         #  - expect none to respond
489         #
490         for i in self.pg_interfaces:
491             i.set_proxy_arp(0)
492
493         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
494                                         "ARP req from disable")
495         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
496                                         "ARP req from disable")
497         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
498                                         "ARP req from disable")
499
500         #
501         # clean up on interface 2
502         #
503         self.pg2.set_unnumbered(self.pg1.sw_if_index)
504
505     def test_mpls(self):
506         """ MPLS """
507
508         #
509         # Interface 2 does not yet have ip4 config
510         #
511         self.pg2.config_ip4()
512         self.pg2.generate_remote_hosts(2)
513
514         #
515         # Add a reoute with out going label via an ARP unresolved next-hop
516         #
517         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
518                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
519                                                self.pg2.sw_if_index,
520                                                labels=[55])])
521         ip_10_0_0_1.add_vpp_config()
522
523         #
524         # packets should generate an ARP request
525         #
526         p = (Ether(src=self.pg0.remote_mac,
527                    dst=self.pg0.local_mac) /
528              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
529              UDP(sport=1234, dport=1234) /
530              Raw('\xa5' * 100))
531
532         self.pg0.add_stream(p)
533         self.pg_enable_capture(self.pg_interfaces)
534         self.pg_start()
535
536         rx = self.pg2.get_capture(1)
537         self.verify_arp_req(rx[0],
538                             self.pg2.local_mac,
539                             self.pg2.local_ip4,
540                             self.pg2._remote_hosts[1].ip4)
541
542         #
543         # now resolve the neighbours
544         #
545         self.pg2.configure_ipv4_neighbors()
546
547         #
548         # Now packet should be properly MPLS encapped.
549         #  This verifies that MPLS link-type adjacencies are completed
550         #  when the ARP entry resolves
551         #
552         self.pg0.add_stream(p)
553         self.pg_enable_capture(self.pg_interfaces)
554         self.pg_start()
555
556         rx = self.pg2.get_capture(1)
557         self.verify_ip_o_mpls(rx[0],
558                               self.pg2.local_mac,
559                               self.pg2.remote_hosts[1].mac,
560                               55,
561                               self.pg0.remote_ip4,
562                               "10.0.0.1")
563
564 if __name__ == '__main__':
565     unittest.main(testRunner=VppTestRunner)