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