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