Line data Source code
1 : /*
2 : * ethernet/arp.c: IP v4 ARP node
3 : *
4 : * Copyright (c) 2010 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vnet/arp/arp.h>
19 : #include <vnet/arp/arp_packet.h>
20 :
21 : #include <vnet/fib/ip4_fib.h>
22 : #include <vnet/fib/fib_entry_src.h>
23 : #include <vnet/adj/adj_nbr.h>
24 : #include <vnet/adj/adj_mcast.h>
25 : #include <vnet/pg/pg.h>
26 :
27 : #include <vnet/ip-neighbor/ip_neighbor.h>
28 : #include <vnet/ip-neighbor/ip4_neighbor.h>
29 : #include <vnet/ip-neighbor/ip_neighbor_dp.h>
30 :
31 : #include <vlibmemory/api.h>
32 :
33 : /**
34 : * @file
35 : * @brief IPv4 ARP.
36 : *
37 : * This file contains code to manage the IPv4 ARP tables (IP Address
38 : * to MAC Address lookup).
39 : */
40 :
41 : /**
42 : * @brief Per-interface ARP configuration and state
43 : */
44 : typedef struct ethernet_arp_interface_t_
45 : {
46 : /**
47 : * Is ARP enabled on this interface
48 : */
49 : u32 enabled;
50 : } ethernet_arp_interface_t;
51 :
52 : typedef struct
53 : {
54 : /* Hash tables mapping name to opcode. */
55 : uword *opcode_by_name;
56 :
57 : /** Per interface state */
58 : ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
59 :
60 : /* ARP feature arc index */
61 : u8 feature_arc_index;
62 : } ethernet_arp_main_t;
63 :
64 : static ethernet_arp_main_t ethernet_arp_main;
65 :
66 : static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 };
67 :
68 : static uword
69 0 : unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
70 : va_list * args)
71 : {
72 0 : int *result = va_arg (*args, int *);
73 0 : ethernet_arp_main_t *am = ðernet_arp_main;
74 : int x, i;
75 :
76 : /* Numeric opcode. */
77 0 : if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
78 : {
79 0 : if (x >= (1 << 16))
80 0 : return 0;
81 0 : *result = x;
82 0 : return 1;
83 : }
84 :
85 : /* Named type. */
86 0 : if (unformat_user (input, unformat_vlib_number_by_name,
87 : am->opcode_by_name, &i))
88 : {
89 0 : *result = i;
90 0 : return 1;
91 : }
92 :
93 0 : return 0;
94 : }
95 :
96 : static uword
97 0 : unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
98 : va_list * args)
99 : {
100 0 : int *result = va_arg (*args, int *);
101 0 : if (!unformat_user
102 : (input, unformat_ethernet_arp_opcode_host_byte_order, result))
103 0 : return 0;
104 :
105 0 : *result = clib_host_to_net_u16 ((u16) * result);
106 0 : return 1;
107 : }
108 :
109 : typedef struct
110 : {
111 : u8 packet_data[64];
112 : } ethernet_arp_input_trace_t;
113 :
114 : static u8 *
115 4029 : format_ethernet_arp_input_trace (u8 * s, va_list * va)
116 : {
117 4029 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
118 4029 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
119 4029 : ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
120 :
121 4029 : s = format (s, "%U",
122 : format_ethernet_arp_header,
123 4029 : t->packet_data, sizeof (t->packet_data));
124 :
125 4029 : return s;
126 : }
127 :
128 : static int
129 12089 : arp_is_enabled (ethernet_arp_main_t * am, u32 sw_if_index)
130 : {
131 12089 : if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
132 8019 : return 0;
133 :
134 4070 : return (am->ethernet_arp_by_sw_if_index[sw_if_index].enabled);
135 : }
136 :
137 : static void
138 2463 : arp_enable (ethernet_arp_main_t * am, u32 sw_if_index)
139 : {
140 2463 : if (arp_is_enabled (am, sw_if_index))
141 0 : return;
142 :
143 2463 : vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
144 :
145 2463 : am->ethernet_arp_by_sw_if_index[sw_if_index].enabled = 1;
146 :
147 2463 : vnet_feature_enable_disable ("arp", "arp-reply", sw_if_index, 1, NULL, 0);
148 2463 : vnet_feature_enable_disable ("arp", "arp-disabled", sw_if_index, 0, NULL,
149 : 0);
150 : }
151 :
152 : static void
153 9626 : arp_disable (ethernet_arp_main_t * am, u32 sw_if_index)
154 : {
155 9626 : if (!arp_is_enabled (am, sw_if_index))
156 7418 : return;
157 :
158 2208 : vnet_feature_enable_disable ("arp", "arp-disabled", sw_if_index, 1, NULL,
159 : 0);
160 2208 : vnet_feature_enable_disable ("arp", "arp-reply", sw_if_index, 0, NULL, 0);
161 :
162 2208 : am->ethernet_arp_by_sw_if_index[sw_if_index].enabled = 0;
163 : }
164 :
165 : static int
166 22 : arp_unnumbered (vlib_buffer_t * p0,
167 : u32 input_sw_if_index, u32 conn_sw_if_index)
168 : {
169 22 : vnet_main_t *vnm = vnet_get_main ();
170 22 : vnet_interface_main_t *vim = &vnm->interface_main;
171 : vnet_sw_interface_t *si;
172 :
173 : /* verify that the input interface is unnumbered to the connected.
174 : * the connected interface is the interface on which the subnet is
175 : * configured */
176 22 : si = &vim->sw_interfaces[input_sw_if_index];
177 :
178 22 : if (!(si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
179 5 : (si->unnumbered_sw_if_index == conn_sw_if_index)))
180 : {
181 : /* the input interface is not unnumbered to the interface on which
182 : * the sub-net is configured that covers the ARP request.
183 : * So this is not the case for unnumbered.. */
184 17 : return 0;
185 : }
186 :
187 5 : return !0;
188 : }
189 :
190 : always_inline u32
191 2010 : arp_learn (u32 sw_if_index,
192 : const ethernet_arp_ip4_over_ethernet_address_t * addr)
193 : {
194 : /* *INDENT-OFF* */
195 2010 : ip_neighbor_learn_t l = {
196 : .ip = {
197 : .ip.ip4 = addr->ip4,
198 : .version = AF_IP4,
199 : },
200 : .mac = addr->mac,
201 : .sw_if_index = sw_if_index,
202 : };
203 : /* *INDENT-ON* */
204 :
205 2010 : ip_neighbor_learn_dp (&l);
206 :
207 2010 : return (ARP_ERROR_L3_SRC_ADDRESS_LEARNED);
208 : }
209 :
210 : typedef enum arp_input_next_t_
211 : {
212 : ARP_INPUT_NEXT_DROP,
213 : ARP_INPUT_NEXT_DISABLED,
214 : ARP_INPUT_N_NEXT,
215 : } arp_input_next_t;
216 :
217 : static uword
218 2120 : arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
219 : {
220 : u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
221 2120 : ethernet_arp_main_t *am = ðernet_arp_main;
222 :
223 2120 : from = vlib_frame_vector_args (frame);
224 2120 : n_left_from = frame->n_vectors;
225 2120 : next_index = node->cached_next_index;
226 :
227 2120 : if (node->flags & VLIB_NODE_FLAG_TRACE)
228 2009 : vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
229 : /* stride */ 1,
230 : sizeof (ethernet_arp_input_trace_t));
231 :
232 4240 : while (n_left_from > 0)
233 : {
234 2120 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
235 :
236 4242 : while (n_left_from > 0 && n_left_to_next > 0)
237 : {
238 : const ethernet_arp_header_t *arp0;
239 : arp_input_next_t next0;
240 : vlib_buffer_t *p0;
241 : u32 pi0, error0;
242 :
243 2122 : pi0 = to_next[0] = from[0];
244 2122 : from += 1;
245 2122 : to_next += 1;
246 2122 : n_left_from -= 1;
247 2122 : n_left_to_next -= 1;
248 :
249 2122 : p0 = vlib_get_buffer (vm, pi0);
250 2122 : arp0 = vlib_buffer_get_current (p0);
251 :
252 2122 : error0 = ARP_ERROR_REPLIES_SENT;
253 2122 : next0 = ARP_INPUT_NEXT_DROP;
254 :
255 2122 : error0 = (arp0->l2_type != clib_net_to_host_u16 (
256 : ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
257 2122 : ARP_ERROR_L2_TYPE_NOT_ETHERNET :
258 : error0);
259 2122 : error0 = (arp0->l3_type != clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
260 2122 : ARP_ERROR_L3_TYPE_NOT_IP4 :
261 : error0);
262 4244 : error0 = (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ?
263 2122 : ARP_ERROR_L3_DST_ADDRESS_UNSET :
264 : error0);
265 :
266 2122 : if (ARP_ERROR_REPLIES_SENT == error0)
267 : {
268 2122 : next0 = ARP_INPUT_NEXT_DISABLED;
269 2122 : vnet_feature_arc_start (am->feature_arc_index,
270 2122 : vnet_buffer (p0)->sw_if_index[VLIB_RX],
271 : &next0, p0);
272 : }
273 : else
274 0 : p0->error = node->errors[error0];
275 :
276 2122 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
277 : n_left_to_next, pi0, next0);
278 : }
279 :
280 2120 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
281 : }
282 :
283 2120 : return frame->n_vectors;
284 : }
285 :
286 : typedef enum arp_disabled_next_t_
287 : {
288 : ARP_DISABLED_NEXT_DROP,
289 : ARP_DISABLED_N_NEXT,
290 : } arp_disabled_next_t;
291 :
292 : static uword
293 5 : arp_disabled (vlib_main_t * vm,
294 : vlib_node_runtime_t * node, vlib_frame_t * frame)
295 : {
296 : u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
297 :
298 5 : from = vlib_frame_vector_args (frame);
299 5 : n_left_from = frame->n_vectors;
300 5 : next_index = node->cached_next_index;
301 :
302 5 : if (node->flags & VLIB_NODE_FLAG_TRACE)
303 5 : vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
304 : /* stride */ 1,
305 : sizeof (ethernet_arp_input_trace_t));
306 :
307 10 : while (n_left_from > 0)
308 : {
309 5 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
310 :
311 10 : while (n_left_from > 0 && n_left_to_next > 0)
312 : {
313 5 : arp_disabled_next_t next0 = ARP_DISABLED_NEXT_DROP;
314 : vlib_buffer_t *p0;
315 : u32 pi0, error0;
316 :
317 5 : next0 = ARP_DISABLED_NEXT_DROP;
318 5 : error0 = ARP_ERROR_DISABLED;
319 :
320 5 : pi0 = to_next[0] = from[0];
321 5 : from += 1;
322 5 : to_next += 1;
323 5 : n_left_from -= 1;
324 5 : n_left_to_next -= 1;
325 :
326 5 : p0 = vlib_get_buffer (vm, pi0);
327 5 : p0->error = node->errors[error0];
328 :
329 5 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
330 : n_left_to_next, pi0, next0);
331 : }
332 :
333 5 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
334 : }
335 :
336 5 : return frame->n_vectors;
337 : }
338 :
339 : enum arp_dst_fib_type
340 : {
341 : ARP_DST_FIB_NONE,
342 : ARP_DST_FIB_ADJ,
343 : ARP_DST_FIB_CONN
344 : };
345 :
346 : /*
347 : * we're looking for FIB sources that indicate the destination
348 : * is attached. There may be interposed DPO prior to the one
349 : * we are looking for
350 : */
351 : static enum arp_dst_fib_type
352 2052 : arp_dst_fib_check (const fib_node_index_t fei, fib_entry_flag_t * flags)
353 : {
354 2052 : const fib_entry_t *entry = fib_entry_get (fei);
355 : const fib_entry_src_t *entry_src;
356 : fib_source_t src;
357 : /* *INDENT-OFF* */
358 2066 : FOR_EACH_SRC_ADDED(entry, entry_src, src,
359 : ({
360 : *flags = fib_entry_get_flags_for_source (fei, src);
361 : if (fib_entry_is_sourced (fei, FIB_SOURCE_ADJ))
362 : return ARP_DST_FIB_ADJ;
363 : else if (FIB_ENTRY_FLAG_CONNECTED & *flags)
364 : return ARP_DST_FIB_CONN;
365 : }))
366 : /* *INDENT-ON* */
367 :
368 14 : return ARP_DST_FIB_NONE;
369 : }
370 :
371 : static uword
372 2106 : arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
373 : {
374 2106 : vnet_main_t *vnm = vnet_get_main ();
375 : u32 n_left_from, next_index, *from, *to_next;
376 2106 : u32 n_replies_sent = 0;
377 :
378 2106 : from = vlib_frame_vector_args (frame);
379 2106 : n_left_from = frame->n_vectors;
380 2106 : next_index = node->cached_next_index;
381 :
382 2106 : if (node->flags & VLIB_NODE_FLAG_TRACE)
383 1995 : vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
384 : /* stride */ 1,
385 : sizeof (ethernet_arp_input_trace_t));
386 :
387 4212 : while (n_left_from > 0)
388 : {
389 : u32 n_left_to_next;
390 :
391 2106 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
392 :
393 4214 : while (n_left_from > 0 && n_left_to_next > 0)
394 : {
395 : vlib_buffer_t *p0;
396 : ethernet_arp_header_t *arp0;
397 : ethernet_header_t *eth_rx;
398 : const ip4_address_t *if_addr0;
399 : u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
400 : u8 dst_is_local0, is_vrrp_reply0;
401 : fib_node_index_t dst_fei, src_fei;
402 : const fib_prefix_t *pfx0;
403 : fib_entry_flag_t src_flags, dst_flags;
404 :
405 2108 : pi0 = from[0];
406 2108 : to_next[0] = pi0;
407 2108 : from += 1;
408 2108 : to_next += 1;
409 2108 : n_left_from -= 1;
410 2108 : n_left_to_next -= 1;
411 :
412 2108 : p0 = vlib_get_buffer (vm, pi0);
413 2108 : arp0 = vlib_buffer_get_current (p0);
414 : /* Fill in ethernet header. */
415 2108 : eth_rx = ethernet_buffer_get_header (p0);
416 :
417 2108 : next0 = ARP_REPLY_NEXT_DROP;
418 2108 : error0 = ARP_ERROR_REPLIES_SENT;
419 2108 : sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
420 :
421 : /* Check that IP address is local and matches incoming interface. */
422 2108 : fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
423 2108 : if (~0 == fib_index0)
424 : {
425 0 : error0 = ARP_ERROR_INTERFACE_NO_TABLE;
426 0 : goto drop;
427 :
428 : }
429 :
430 : {
431 : /*
432 : * we're looking for FIB entries that indicate the source
433 : * is attached. There may be more specific non-attached
434 : * routes that match the source, but these do not influence
435 : * whether we respond to an ARP request, i.e. they do not
436 : * influence whether we are the correct way for the sender
437 : * to reach us, they only affect how we reach the sender.
438 : */
439 : fib_entry_t *src_fib_entry;
440 : const fib_prefix_t *pfx;
441 : fib_entry_src_t *src;
442 : fib_source_t source;
443 : int attached;
444 : int mask;
445 :
446 2108 : mask = 32;
447 2108 : attached = 0;
448 :
449 : do
450 : {
451 2109 : src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
452 2109 : &arp0->
453 : ip4_over_ethernet[0].ip4,
454 : mask);
455 2109 : src_fib_entry = fib_entry_get (src_fei);
456 :
457 : /*
458 : * It's possible that the source that provides the
459 : * flags we need, or the flags we must not have,
460 : * is not the best source, so check then all.
461 : */
462 : /* *INDENT-OFF* */
463 2114 : FOR_EACH_SRC_ADDED(src_fib_entry, src, source,
464 : ({
465 : src_flags = fib_entry_get_flags_for_source (src_fei, source);
466 :
467 : /* Reject requests/replies with our local interface
468 : address. */
469 : if (FIB_ENTRY_FLAG_LOCAL & src_flags)
470 : {
471 : error0 = ARP_ERROR_L3_SRC_ADDRESS_IS_LOCAL;
472 : /*
473 : * When VPP has an interface whose address is also
474 : * applied to a TAP interface on the host, then VPP's
475 : * TAP interface will be unnumbered to the 'real'
476 : * interface and do proxy ARP from the host.
477 : * The curious aspect of this setup is that ARP requests
478 : * from the host will come from the VPP's own address.
479 : * So don't drop immediately here, instead go see if this
480 : * is a proxy ARP case.
481 : */
482 : goto next_feature;
483 : }
484 : /* A Source must also be local to subnet of matching
485 : * interface address. */
486 : if ((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
487 : (FIB_ENTRY_FLAG_CONNECTED & src_flags))
488 : {
489 : attached = 1;
490 : break;
491 : }
492 : /*
493 : * else
494 : * The packet was sent from an address that is not
495 : * connected nor attached i.e. it is not from an
496 : * address that is covered by a link's sub-net,
497 : * nor is it a already learned host resp.
498 : */
499 : }));
500 : /* *INDENT-ON* */
501 :
502 : /*
503 : * shorter mask lookup for the next iteration.
504 : */
505 2056 : pfx = fib_entry_get_prefix (src_fei);
506 2056 : mask = pfx->fp_len - 1;
507 :
508 : /*
509 : * continue until we hit the default route or we find
510 : * the attached we are looking for. The most likely
511 : * outcome is we find the attached with the first source
512 : * on the first lookup.
513 : */
514 : }
515 4 : while (!attached &&
516 2056 : !fib_entry_is_sourced (src_fei, FIB_SOURCE_DEFAULT_ROUTE));
517 :
518 2055 : if (!attached)
519 : {
520 : /*
521 : * the matching route is a not attached, i.e. it was
522 : * added as a result of routing, rather than interface/ARP
523 : * configuration. If the matching route is not a host route
524 : * (i.e. a /32)
525 : */
526 3 : error0 = ARP_ERROR_L3_SRC_ADDRESS_NOT_LOCAL;
527 3 : goto drop;
528 : }
529 : }
530 :
531 2052 : dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
532 2052 : &arp0->ip4_over_ethernet[1].ip4,
533 : 32);
534 2052 : conn_sw_if_index0 = fib_entry_get_any_resolving_interface (dst_fei);
535 :
536 2052 : switch (arp_dst_fib_check (dst_fei, &dst_flags))
537 : {
538 7 : case ARP_DST_FIB_ADJ:
539 : /*
540 : * We matched an adj-fib on ths source subnet (a /32 previously
541 : * added as a result of ARP). If this request is a gratuitous
542 : * ARP, then learn from it.
543 : * The check for matching an adj-fib, is to prevent hosts
544 : * from spamming us with gratuitous ARPS that might otherwise
545 : * blow our ARP cache
546 : */
547 7 : if (conn_sw_if_index0 != sw_if_index0)
548 4 : error0 = ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL;
549 3 : else if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
550 3 : arp0->ip4_over_ethernet[1].ip4.as_u32)
551 : {
552 2 : vlib_increment_simple_counter (
553 : &ip_neighbor_counters[AF_IP4]
554 : .ipnc[VLIB_RX][IP_NEIGHBOR_CTR_GRAT],
555 : vm->thread_index, sw_if_index0, 1);
556 : error0 =
557 2 : arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
558 : }
559 7 : goto next_feature;
560 2031 : case ARP_DST_FIB_CONN:
561 : /* destination is connected, continue to process */
562 2031 : break;
563 14 : case ARP_DST_FIB_NONE:
564 : /* destination is not connected, stop here */
565 14 : error0 = ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL;
566 14 : goto next_feature;
567 : }
568 :
569 2031 : dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
570 2031 : pfx0 = fib_entry_get_prefix (dst_fei);
571 2031 : if_addr0 = &pfx0->fp_addr.ip4;
572 :
573 2031 : is_vrrp_reply0 =
574 2031 : ((arp0->opcode ==
575 2031 : clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
576 2071 : &&
577 40 : (!memcmp
578 40 : (arp0->ip4_over_ethernet[0].mac.bytes, vrrp_prefix,
579 : sizeof (vrrp_prefix))));
580 :
581 : /* Trash ARP packets whose ARP-level source addresses do not
582 : match their L2-frame-level source addresses, unless it's
583 : a reply from a VRRP virtual router */
584 2031 : if (!ethernet_mac_address_equal
585 2031 : (eth_rx->src_address,
586 2037 : arp0->ip4_over_ethernet[0].mac.bytes) && !is_vrrp_reply0)
587 : {
588 1 : error0 = ARP_ERROR_L2_ADDRESS_MISMATCH;
589 1 : goto drop;
590 : }
591 :
592 4060 : vlib_increment_simple_counter (
593 : &ip_neighbor_counters[AF_IP4]
594 2030 : .ipnc[VLIB_RX][arp0->opcode == clib_host_to_net_u16 (
595 : ETHERNET_ARP_OPCODE_reply) ?
596 2030 : IP_NEIGHBOR_CTR_REPLY :
597 : IP_NEIGHBOR_CTR_REQUEST],
598 : vm->thread_index, sw_if_index0, 1);
599 :
600 : /* Learn or update sender's mapping only for replies to addresses
601 : * that are local to the subnet */
602 2030 : if (arp0->opcode ==
603 2030 : clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
604 : {
605 40 : if (dst_is_local0)
606 : error0 =
607 39 : arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
608 : else
609 : /* a reply for a non-local destination could be a GARP.
610 : * GARPs for hosts we know were handled above, so this one
611 : * we drop */
612 1 : error0 = ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL;
613 :
614 40 : goto next_feature;
615 : }
616 1990 : else if (arp0->opcode ==
617 3980 : clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request) &&
618 : (dst_is_local0 == 0))
619 : {
620 4 : goto next_feature;
621 : }
622 :
623 : /* Honor unnumbered interface, if any */
624 3951 : if (sw_if_index0 != conn_sw_if_index0 ||
625 1965 : sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
626 : {
627 : /*
628 : * The interface the ARP is sent to or was received on is not the
629 : * interface on which the covering prefix is configured.
630 : * Maybe this is a case for unnumbered.
631 : */
632 22 : if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
633 : {
634 17 : error0 = ARP_ERROR_UNNUMBERED_MISMATCH;
635 17 : goto drop;
636 : }
637 : }
638 1969 : if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
639 1969 : arp0->ip4_over_ethernet[1].ip4.as_u32)
640 : {
641 0 : error0 = ARP_ERROR_GRATUITOUS_ARP;
642 0 : goto drop;
643 : }
644 :
645 1969 : next0 = arp_mk_reply (vnm, p0, sw_if_index0,
646 : if_addr0, arp0, eth_rx);
647 :
648 : /* We are going to reply to this request, so, in the absence of
649 : errors, learn the sender */
650 1969 : if (!error0)
651 1969 : error0 = arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[1]);
652 :
653 1969 : vlib_increment_simple_counter (
654 : &ip_neighbor_counters[AF_IP4].ipnc[VLIB_TX][IP_NEIGHBOR_CTR_REPLY],
655 : vm->thread_index, sw_if_index0, 1);
656 1969 : n_replies_sent += 1;
657 1969 : goto enqueue;
658 :
659 118 : next_feature:
660 118 : vnet_feature_next (&next0, p0);
661 :
662 139 : drop:
663 139 : p0->error = node->errors[error0];
664 :
665 2108 : enqueue:
666 2108 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
667 : n_left_to_next, pi0, next0);
668 : }
669 :
670 2106 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
671 : }
672 :
673 2106 : vlib_error_count (vm, node->node_index, ARP_ERROR_REPLIES_SENT,
674 : n_replies_sent);
675 :
676 2106 : return frame->n_vectors;
677 : }
678 :
679 :
680 : /* *INDENT-OFF* */
681 :
682 178120 : VLIB_REGISTER_NODE (arp_input_node, static) =
683 : {
684 : .function = arp_input,
685 : .name = "arp-input",
686 : .vector_size = sizeof (u32),
687 : .n_errors = ARP_N_ERROR,
688 : .error_counters = arp_error_counters,
689 : .n_next_nodes = ARP_INPUT_N_NEXT,
690 : .next_nodes = {
691 : [ARP_INPUT_NEXT_DROP] = "error-drop",
692 : [ARP_INPUT_NEXT_DISABLED] = "arp-disabled",
693 : },
694 : .format_buffer = format_ethernet_arp_header,
695 : .format_trace = format_ethernet_arp_input_trace,
696 : };
697 :
698 178120 : VLIB_REGISTER_NODE (arp_disabled_node, static) =
699 : {
700 : .function = arp_disabled,
701 : .name = "arp-disabled",
702 : .vector_size = sizeof (u32),
703 : .n_errors = ARP_N_ERROR,
704 : .error_counters = arp_error_counters,
705 : .n_next_nodes = ARP_DISABLED_N_NEXT,
706 : .next_nodes = {
707 : [ARP_INPUT_NEXT_DROP] = "error-drop",
708 : },
709 : .format_buffer = format_ethernet_arp_header,
710 : .format_trace = format_ethernet_arp_input_trace,
711 : };
712 :
713 178120 : VLIB_REGISTER_NODE (arp_reply_node, static) =
714 : {
715 : .function = arp_reply,
716 : .name = "arp-reply",
717 : .vector_size = sizeof (u32),
718 : .n_errors = ARP_N_ERROR,
719 : .error_counters = arp_error_counters,
720 : .n_next_nodes = ARP_REPLY_N_NEXT,
721 : .next_nodes = {
722 : [ARP_REPLY_NEXT_DROP] = "error-drop",
723 : [ARP_REPLY_NEXT_REPLY_TX] = "interface-output",
724 : },
725 : .format_buffer = format_ethernet_arp_header,
726 : .format_trace = format_ethernet_arp_input_trace,
727 : };
728 :
729 : /* Built-in ARP rx feature path definition */
730 1119 : VNET_FEATURE_ARC_INIT (arp_feat, static) =
731 : {
732 : .arc_name = "arp",
733 : .start_nodes = VNET_FEATURES ("arp-input"),
734 : .last_in_arc = "error-drop",
735 : .arc_index_ptr = ðernet_arp_main.feature_arc_index,
736 : };
737 :
738 70583 : VNET_FEATURE_INIT (arp_reply_feat_node, static) =
739 : {
740 : .arc_name = "arp",
741 : .node_name = "arp-reply",
742 : .runs_before = VNET_FEATURES ("arp-disabled"),
743 : };
744 :
745 70583 : VNET_FEATURE_INIT (arp_proxy_feat_node, static) =
746 : {
747 : .arc_name = "arp",
748 : .node_name = "arp-proxy",
749 : .runs_after = VNET_FEATURES ("arp-reply"),
750 : .runs_before = VNET_FEATURES ("arp-disabled"),
751 : };
752 :
753 70583 : VNET_FEATURE_INIT (arp_disabled_feat_node, static) =
754 : {
755 : .arc_name = "arp",
756 : .node_name = "arp-disabled",
757 : .runs_before = VNET_FEATURES ("error-drop"),
758 : };
759 :
760 70583 : VNET_FEATURE_INIT (arp_drop_feat_node, static) =
761 : {
762 : .arc_name = "arp",
763 : .node_name = "error-drop",
764 : .runs_before = 0, /* last feature */
765 : };
766 :
767 : /* *INDENT-ON* */
768 :
769 : typedef struct
770 : {
771 : pg_edit_t l2_type, l3_type;
772 : pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
773 : pg_edit_t opcode;
774 : struct
775 : {
776 : pg_edit_t mac;
777 : pg_edit_t ip4;
778 : } ip4_over_ethernet[2];
779 : } pg_ethernet_arp_header_t;
780 :
781 : static inline void
782 0 : pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
783 : {
784 : /* Initialize fields that are not bit fields in the IP header. */
785 : #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
786 0 : _(l2_type);
787 0 : _(l3_type);
788 0 : _(n_l2_address_bytes);
789 0 : _(n_l3_address_bytes);
790 0 : _(opcode);
791 0 : _(ip4_over_ethernet[0].mac);
792 0 : _(ip4_over_ethernet[0].ip4);
793 0 : _(ip4_over_ethernet[1].mac);
794 0 : _(ip4_over_ethernet[1].ip4);
795 : #undef _
796 0 : }
797 :
798 : uword
799 0 : unformat_pg_arp_header (unformat_input_t * input, va_list * args)
800 : {
801 0 : pg_stream_t *s = va_arg (*args, pg_stream_t *);
802 : pg_ethernet_arp_header_t *p;
803 : u32 group_index;
804 :
805 0 : p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
806 : &group_index);
807 0 : pg_ethernet_arp_header_init (p);
808 :
809 : /* Defaults. */
810 0 : pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
811 0 : pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
812 0 : pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
813 0 : pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
814 :
815 0 : if (!unformat (input, "%U: %U/%U -> %U/%U",
816 : unformat_pg_edit,
817 : unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
818 : unformat_pg_edit,
819 : unformat_mac_address_t, &p->ip4_over_ethernet[0].mac,
820 : unformat_pg_edit,
821 : unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
822 : unformat_pg_edit,
823 : unformat_mac_address_t, &p->ip4_over_ethernet[1].mac,
824 : unformat_pg_edit,
825 : unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
826 : {
827 : /* Free up any edits we may have added. */
828 0 : pg_free_edit_group (s);
829 0 : return 0;
830 : }
831 0 : return 1;
832 : }
833 :
834 : /*
835 : * callback when an interface address is added or deleted
836 : */
837 : static void
838 4671 : arp_enable_disable_interface (ip4_main_t * im,
839 : uword opaque, u32 sw_if_index, u32 is_enable)
840 : {
841 4671 : ethernet_arp_main_t *am = ðernet_arp_main;
842 :
843 4671 : if (is_enable)
844 2463 : arp_enable (am, sw_if_index);
845 : else
846 2208 : arp_disable (am, sw_if_index);
847 4671 : }
848 :
849 : /*
850 : * Remove any arp entries associated with the specified interface
851 : */
852 : static clib_error_t *
853 11597 : vnet_arp_add_del_sw_interface (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
854 : {
855 11597 : ethernet_arp_main_t *am = ðernet_arp_main;
856 11597 : if (is_add)
857 7418 : arp_disable (am, sw_if_index);
858 11597 : return (NULL);
859 : }
860 :
861 3363 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (vnet_arp_add_del_sw_interface);
862 :
863 : const static ip_neighbor_vft_t arp_vft = {
864 : .inv_proxy4_add = arp_proxy_add,
865 : .inv_proxy4_del = arp_proxy_del,
866 : .inv_proxy4_enable = arp_proxy_enable,
867 : .inv_proxy4_disable = arp_proxy_disable,
868 : };
869 :
870 : static clib_error_t *
871 559 : ethernet_arp_init (vlib_main_t * vm)
872 : {
873 559 : ethernet_arp_main_t *am = ðernet_arp_main;
874 559 : ip4_main_t *im = &ip4_main;
875 : pg_node_t *pn;
876 :
877 559 : ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
878 :
879 559 : pn = pg_get_node (arp_input_node.index);
880 559 : pn->unformat_edit = unformat_pg_arp_header;
881 :
882 559 : am->opcode_by_name = hash_create_string (0, sizeof (uword));
883 : #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
884 15093 : foreach_ethernet_arp_opcode;
885 : #undef _
886 :
887 : /* don't trace ARP error packets */
888 : {
889 : vlib_node_runtime_t *rt =
890 559 : vlib_node_get_runtime (vm, arp_input_node.index);
891 :
892 559 : vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_REPLIES_SENT],
893 : 1);
894 559 : vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_DISABLED], 1);
895 559 : vnet_pcap_drop_trace_filter_add_del (
896 559 : rt->errors[ARP_ERROR_L2_TYPE_NOT_ETHERNET], 1);
897 559 : vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_L3_TYPE_NOT_IP4],
898 : 1);
899 559 : vnet_pcap_drop_trace_filter_add_del (
900 559 : rt->errors[ARP_ERROR_L3_SRC_ADDRESS_NOT_LOCAL], 1);
901 559 : vnet_pcap_drop_trace_filter_add_del (
902 559 : rt->errors[ARP_ERROR_L3_DST_ADDRESS_NOT_LOCAL], 1);
903 559 : vnet_pcap_drop_trace_filter_add_del (
904 559 : rt->errors[ARP_ERROR_L3_DST_ADDRESS_UNSET], 1);
905 559 : vnet_pcap_drop_trace_filter_add_del (
906 559 : rt->errors[ARP_ERROR_L3_SRC_ADDRESS_IS_LOCAL], 1);
907 559 : vnet_pcap_drop_trace_filter_add_del (
908 559 : rt->errors[ARP_ERROR_L3_SRC_ADDRESS_LEARNED], 1);
909 559 : vnet_pcap_drop_trace_filter_add_del (
910 559 : rt->errors[ARP_ERROR_REPLIES_RECEIVED], 1);
911 559 : vnet_pcap_drop_trace_filter_add_del (
912 559 : rt->errors[ARP_ERROR_OPCODE_NOT_REQUEST], 1);
913 559 : vnet_pcap_drop_trace_filter_add_del (
914 559 : rt->errors[ARP_ERROR_PROXY_ARP_REPLIES_SENT], 1);
915 559 : vnet_pcap_drop_trace_filter_add_del (
916 559 : rt->errors[ARP_ERROR_L2_ADDRESS_MISMATCH], 1);
917 559 : vnet_pcap_drop_trace_filter_add_del (rt->errors[ARP_ERROR_GRATUITOUS_ARP],
918 : 1);
919 559 : vnet_pcap_drop_trace_filter_add_del (
920 559 : rt->errors[ARP_ERROR_INTERFACE_NO_TABLE], 1);
921 559 : vnet_pcap_drop_trace_filter_add_del (
922 559 : rt->errors[ARP_ERROR_INTERFACE_NOT_IP_ENABLED], 1);
923 559 : vnet_pcap_drop_trace_filter_add_del (
924 559 : rt->errors[ARP_ERROR_UNNUMBERED_MISMATCH], 1);
925 : }
926 :
927 : {
928 559 : ip4_enable_disable_interface_callback_t cb = {
929 : .function = arp_enable_disable_interface,
930 : };
931 559 : vec_add1 (im->enable_disable_interface_callbacks, cb);
932 : }
933 :
934 559 : ip_neighbor_register (AF_IP4, &arp_vft);
935 :
936 559 : return 0;
937 : }
938 :
939 : /* *INDENT-OFF* */
940 94079 : VLIB_INIT_FUNCTION (ethernet_arp_init) =
941 : {
942 : .runs_after = VLIB_INITS("ethernet_init",
943 : "ip_neighbor_init"),
944 : };
945 : /* *INDENT-ON* */
946 :
947 : /*
948 : * fd.io coding-style-patch-verification: ON
949 : *
950 : * Local Variables:
951 : * eval: (c-set-style "gnu")
952 : * End:
953 : */
|