Tests to target holes in adjacency and DPO test coverage
[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
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(4)
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         # cleanup
305         #
306         dyn_arp.remove_vpp_config()
307         static_arp.remove_vpp_config()
308
309     def test_proxy_arp(self):
310         """ Proxy ARP """
311
312         #
313         # Proxy ARP rewquest packets for each interface
314         #
315         arp_req_pg2 = (Ether(src=self.pg2.remote_mac,
316                              dst="ff:ff:ff:ff:ff:ff") /
317                        ARP(op="who-has",
318                            hwsrc=self.pg2.remote_mac,
319                            pdst="10.10.10.3",
320                            psrc=self.pg1.remote_ip4))
321         arp_req_pg0 = (Ether(src=self.pg0.remote_mac,
322                              dst="ff:ff:ff:ff:ff:ff") /
323                        ARP(op="who-has",
324                            hwsrc=self.pg0.remote_mac,
325                            pdst="10.10.10.3",
326                            psrc=self.pg0.remote_ip4))
327         arp_req_pg1 = (Ether(src=self.pg1.remote_mac,
328                              dst="ff:ff:ff:ff:ff:ff") /
329                        ARP(op="who-has",
330                            hwsrc=self.pg1.remote_mac,
331                            pdst="10.10.10.3",
332                            psrc=self.pg1.remote_ip4))
333         arp_req_pg3 = (Ether(src=self.pg3.remote_mac,
334                              dst="ff:ff:ff:ff:ff:ff") /
335                        ARP(op="who-has",
336                            hwsrc=self.pg3.remote_mac,
337                            pdst="10.10.10.3",
338                            psrc=self.pg3.remote_ip4))
339
340         #
341         # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124
342         #
343         self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"),
344                                     inet_pton(AF_INET, "10.10.10.124"))
345
346         #
347         # No responses are sent when the interfaces are not enabled for proxy
348         # ARP
349         #
350         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
351                                         "ARP req from unconfigured interface")
352         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
353                                         "ARP req from unconfigured interface")
354
355         #
356         # Make pg2 un-numbered to pg1
357         #  still won't reply.
358         #
359         self.pg2.set_unnumbered(self.pg1.sw_if_index)
360
361         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
362                                         "ARP req from unnumbered interface")
363
364         #
365         # Enable each interface to reply to proxy ARPs
366         #
367         for i in self.pg_interfaces:
368             i.set_proxy_arp()
369
370         #
371         # Now each of the interfaces should reply to a request to a proxied
372         # address
373         #
374         self.pg0.add_stream(arp_req_pg0)
375         self.pg_enable_capture(self.pg_interfaces)
376         self.pg_start()
377
378         rx = self.pg0.get_capture(1)
379         self.verify_arp_resp(rx[0],
380                              self.pg0.local_mac,
381                              self.pg0.remote_mac,
382                              "10.10.10.3",
383                              self.pg0.remote_ip4)
384
385         self.pg1.add_stream(arp_req_pg1)
386         self.pg_enable_capture(self.pg_interfaces)
387         self.pg_start()
388
389         rx = self.pg1.get_capture(1)
390         self.verify_arp_resp(rx[0],
391                              self.pg1.local_mac,
392                              self.pg1.remote_mac,
393                              "10.10.10.3",
394                              self.pg1.remote_ip4)
395
396         self.pg2.add_stream(arp_req_pg2)
397         self.pg_enable_capture(self.pg_interfaces)
398         self.pg_start()
399
400         rx = self.pg2.get_capture(1)
401         self.verify_arp_resp(rx[0],
402                              self.pg2.local_mac,
403                              self.pg2.remote_mac,
404                              "10.10.10.3",
405                              self.pg1.remote_ip4)
406
407         #
408         # A request for an address out of the configured range
409         #
410         arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac,
411                                 dst="ff:ff:ff:ff:ff:ff") /
412                           ARP(op="who-has",
413                               hwsrc=self.pg1.remote_mac,
414                               pdst="10.10.10.125",
415                               psrc=self.pg1.remote_ip4))
416         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi,
417                                         "ARP req out of range HI")
418         arp_req_pg1_low = (Ether(src=self.pg1.remote_mac,
419                                  dst="ff:ff:ff:ff:ff:ff") /
420                            ARP(op="who-has",
421                                hwsrc=self.pg1.remote_mac,
422                                pdst="10.10.10.1",
423                                psrc=self.pg1.remote_ip4))
424         self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low,
425                                         "ARP req out of range Low")
426
427         #
428         # Request for an address in the proxy range but from an interface
429         # in a different VRF
430         #
431         self.send_and_assert_no_replies(self.pg3, arp_req_pg3,
432                                         "ARP req from different VRF")
433
434         #
435         # Disable Each interface for proxy ARP
436         #  - expect none to respond
437         #
438         for i in self.pg_interfaces:
439             i.set_proxy_arp(0)
440
441         self.send_and_assert_no_replies(self.pg0, arp_req_pg0,
442                                         "ARP req from disable")
443         self.send_and_assert_no_replies(self.pg1, arp_req_pg1,
444                                         "ARP req from disable")
445         self.send_and_assert_no_replies(self.pg2, arp_req_pg2,
446                                         "ARP req from disable")
447
448         #
449         # clean up on interface 2
450         #
451         self.pg2.set_unnumbered(self.pg1.sw_if_index)
452
453     def test_mpls(self):
454         """ MPLS """
455
456         #
457         # Interface 2 does not yet have ip4 config
458         #
459         self.pg2.config_ip4()
460         self.pg2.generate_remote_hosts(2)
461
462         #
463         # Add a reoute with out going label via an ARP unresolved next-hop
464         #
465         ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
466                                  [VppRoutePath(self.pg2.remote_hosts[1].ip4,
467                                                self.pg2.sw_if_index,
468                                                labels=[55])])
469         ip_10_0_0_1.add_vpp_config()
470
471         #
472         # packets should generate an ARP request
473         #
474         p = (Ether(src=self.pg0.remote_mac,
475                    dst=self.pg0.local_mac) /
476              IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
477              UDP(sport=1234, dport=1234) /
478              Raw('\xa5' * 100))
479
480         self.pg0.add_stream(p)
481         self.pg_enable_capture(self.pg_interfaces)
482         self.pg_start()
483
484         rx = self.pg2.get_capture(1)
485         self.verify_arp_req(rx[0],
486                             self.pg2.local_mac,
487                             self.pg2.local_ip4,
488                             self.pg2._remote_hosts[1].ip4)
489
490         #
491         # now resolve the neighbours
492         #
493         self.pg2.configure_ipv4_neighbors()
494
495         #
496         # Now packet should be properly MPLS encapped.
497         #  This verifies that MPLS link-type adjacencies are completed
498         #  when the ARP entry resolves
499         #
500         self.pg0.add_stream(p)
501         self.pg_enable_capture(self.pg_interfaces)
502         self.pg_start()
503
504         rx = self.pg2.get_capture(1)
505         self.verify_ip_o_mpls(rx[0],
506                               self.pg2.local_mac,
507                               self.pg2.remote_hosts[1].mac,
508                               55,
509                               self.pg0.remote_ip4,
510                               "10.0.0.1")
511
512 if __name__ == '__main__':
513     unittest.main(testRunner=VppTestRunner)