FD.io VPP  v21.01.1
Vector Packet Processing
arp.c
Go to the documentation of this file.
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 
28 
29 #include <vlibmemory/api.h>
30 
31 /**
32  * @file
33  * @brief IPv4 ARP.
34  *
35  * This file contains code to manage the IPv4 ARP tables (IP Address
36  * to MAC Address lookup).
37  */
38 
39 /**
40  * @brief Per-interface ARP configuration and state
41  */
43 {
44  /**
45  * Is ARP enabled on this interface
46  */
49 
50 typedef struct
51 {
52  /* Hash tables mapping name to opcode. */
54 
55  /** Per interface state */
57 
58  /* ARP feature arc index */
61 
63 
64 static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 };
65 
66 static uword
68  va_list * args)
69 {
70  int *result = va_arg (*args, int *);
72  int x, i;
73 
74  /* Numeric opcode. */
75  if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
76  {
77  if (x >= (1 << 16))
78  return 0;
79  *result = x;
80  return 1;
81  }
82 
83  /* Named type. */
85  am->opcode_by_name, &i))
86  {
87  *result = i;
88  return 1;
89  }
90 
91  return 0;
92 }
93 
94 static uword
96  va_list * args)
97 {
98  int *result = va_arg (*args, int *);
99  if (!unformat_user
101  return 0;
102 
103  *result = clib_host_to_net_u16 ((u16) * result);
104  return 1;
105 }
106 
107 typedef struct
108 {
109  u8 packet_data[64];
111 
112 static u8 *
114 {
115  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
116  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
118 
119  s = format (s, "%U",
121  t->packet_data, sizeof (t->packet_data));
122 
123  return s;
124 }
125 
126 static int
128 {
129  if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
130  return 0;
131 
132  return (am->ethernet_arp_by_sw_if_index[sw_if_index].enabled);
133 }
134 
135 static void
137 {
138  if (arp_is_enabled (am, sw_if_index))
139  return;
140 
141  vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
142 
144 
145  vnet_feature_enable_disable ("arp", "arp-reply", sw_if_index, 1, NULL, 0);
146  vnet_feature_enable_disable ("arp", "arp-disabled", sw_if_index, 0, NULL,
147  0);
148 }
149 
150 static void
152 {
153  if (!arp_is_enabled (am, sw_if_index))
154  return;
155 
156  vnet_feature_enable_disable ("arp", "arp-disabled", sw_if_index, 1, NULL,
157  0);
158  vnet_feature_enable_disable ("arp", "arp-reply", sw_if_index, 0, NULL, 0);
159 
161 }
162 
163 static int
165  u32 input_sw_if_index, u32 conn_sw_if_index)
166 {
167  vnet_main_t *vnm = vnet_get_main ();
170 
171  /* verify that the input interface is unnumbered to the connected.
172  * the connected interface is the interface on which the subnet is
173  * configured */
174  si = &vim->sw_interfaces[input_sw_if_index];
175 
177  (si->unnumbered_sw_if_index == conn_sw_if_index)))
178  {
179  /* the input interface is not unnumbered to the interface on which
180  * the sub-net is configured that covers the ARP request.
181  * So this is not the case for unnumbered.. */
182  return 0;
183  }
184 
185  return !0;
186 }
187 
190  const ethernet_arp_ip4_over_ethernet_address_t * addr)
191 {
192  /* *INDENT-OFF* */
193  ip_neighbor_learn_t l = {
194  .ip = {
195  .ip.ip4 = addr->ip4,
196  .version = AF_IP4,
197  },
198  .mac = addr->mac,
199  .sw_if_index = sw_if_index,
200  };
201  /* *INDENT-ON* */
202 
204 
205  return (ETHERNET_ARP_ERROR_l3_src_address_learned);
206 }
207 
208 typedef enum arp_input_next_t_
209 {
214 
215 static uword
217 {
218  u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
220 
221  from = vlib_frame_vector_args (frame);
222  n_left_from = frame->n_vectors;
223  next_index = node->cached_next_index;
224 
225  if (node->flags & VLIB_NODE_FLAG_TRACE)
226  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
227  /* stride */ 1,
228  sizeof (ethernet_arp_input_trace_t));
229 
230  while (n_left_from > 0)
231  {
232  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
233 
234  while (n_left_from > 0 && n_left_to_next > 0)
235  {
236  const ethernet_arp_header_t *arp0;
237  arp_input_next_t next0;
238  vlib_buffer_t *p0;
239  u32 pi0, error0;
240 
241  pi0 = to_next[0] = from[0];
242  from += 1;
243  to_next += 1;
244  n_left_from -= 1;
245  n_left_to_next -= 1;
246 
247  p0 = vlib_get_buffer (vm, pi0);
248  arp0 = vlib_buffer_get_current (p0);
249 
250  error0 = ETHERNET_ARP_ERROR_replies_sent;
251  next0 = ARP_INPUT_NEXT_DROP;
252 
253  error0 =
254  (arp0->l2_type !=
255  clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
256  ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
257  error0 =
258  (arp0->l3_type !=
259  clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
260  ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
261  error0 =
262  (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ?
263  ETHERNET_ARP_ERROR_l3_dst_address_unset : error0);
264 
265  if (ETHERNET_ARP_ERROR_replies_sent == error0)
266  {
267  next0 = ARP_INPUT_NEXT_DISABLED;
270  &next0, p0);
271  }
272  else
273  p0->error = node->errors[error0];
274 
275  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
276  n_left_to_next, pi0, next0);
277  }
278 
279  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
280  }
281 
282  return frame->n_vectors;
283 }
284 
286 {
290 
291 #define foreach_arp_disabled_error \
292  _ (DISABLED, "ARP Disabled on this interface") \
293 
294 typedef enum
295 {
296 #define _(sym,string) ARP_DISABLED_ERROR_##sym,
298 #undef _
301 
302 static char *arp_disabled_error_strings[] = {
303 #define _(sym,string) string,
305 #undef _
306 };
307 
308 static uword
311 {
312  u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
313 
314  from = vlib_frame_vector_args (frame);
315  n_left_from = frame->n_vectors;
316  next_index = node->cached_next_index;
317 
318  if (node->flags & VLIB_NODE_FLAG_TRACE)
319  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
320  /* stride */ 1,
321  sizeof (ethernet_arp_input_trace_t));
322 
323  while (n_left_from > 0)
324  {
325  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
326 
327  while (n_left_from > 0 && n_left_to_next > 0)
328  {
330  vlib_buffer_t *p0;
331  u32 pi0, error0;
332 
333  next0 = ARP_DISABLED_NEXT_DROP;
334  error0 = ARP_DISABLED_ERROR_DISABLED;
335 
336  pi0 = to_next[0] = from[0];
337  from += 1;
338  to_next += 1;
339  n_left_from -= 1;
340  n_left_to_next -= 1;
341 
342  p0 = vlib_get_buffer (vm, pi0);
343  p0->error = node->errors[error0];
344 
345  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
346  n_left_to_next, pi0, next0);
347  }
348 
349  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
350  }
351 
352  return frame->n_vectors;
353 }
354 
356 {
360 };
361 
362 /*
363  * we're looking for FIB sources that indicate the destination
364  * is attached. There may be interposed DPO prior to the one
365  * we are looking for
366  */
367 static enum arp_dst_fib_type
369 {
370  const fib_entry_t *entry = fib_entry_get (fei);
371  const fib_entry_src_t *entry_src;
373  /* *INDENT-OFF* */
374  FOR_EACH_SRC_ADDED(entry, entry_src, src,
375  ({
376  *flags = fib_entry_get_flags_for_source (fei, src);
378  return ARP_DST_FIB_ADJ;
379  else if (FIB_ENTRY_FLAG_CONNECTED & *flags)
380  return ARP_DST_FIB_CONN;
381  }))
382  /* *INDENT-ON* */
383 
384  return ARP_DST_FIB_NONE;
385 }
386 
387 static uword
389 {
390  vnet_main_t *vnm = vnet_get_main ();
391  u32 n_left_from, next_index, *from, *to_next;
392  u32 n_replies_sent = 0;
393 
394  from = vlib_frame_vector_args (frame);
395  n_left_from = frame->n_vectors;
396  next_index = node->cached_next_index;
397 
398  if (node->flags & VLIB_NODE_FLAG_TRACE)
399  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
400  /* stride */ 1,
401  sizeof (ethernet_arp_input_trace_t));
402 
403  while (n_left_from > 0)
404  {
405  u32 n_left_to_next;
406 
407  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
408 
409  while (n_left_from > 0 && n_left_to_next > 0)
410  {
411  vlib_buffer_t *p0;
412  ethernet_arp_header_t *arp0;
413  ethernet_header_t *eth_rx;
414  const ip4_address_t *if_addr0;
415  u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
416  u8 dst_is_local0, is_vrrp_reply0;
417  fib_node_index_t dst_fei, src_fei;
418  const fib_prefix_t *pfx0;
419  fib_entry_flag_t src_flags, dst_flags;
420 
421  pi0 = from[0];
422  to_next[0] = pi0;
423  from += 1;
424  to_next += 1;
425  n_left_from -= 1;
426  n_left_to_next -= 1;
427 
428  p0 = vlib_get_buffer (vm, pi0);
429  arp0 = vlib_buffer_get_current (p0);
430  /* Fill in ethernet header. */
431  eth_rx = ethernet_buffer_get_header (p0);
432 
433  next0 = ARP_REPLY_NEXT_DROP;
434  error0 = ETHERNET_ARP_ERROR_replies_sent;
435  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
436 
437  /* Check that IP address is local and matches incoming interface. */
438  fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
439  if (~0 == fib_index0)
440  {
441  error0 = ETHERNET_ARP_ERROR_interface_no_table;
442  goto drop;
443 
444  }
445 
446  {
447  /*
448  * we're looking for FIB entries that indicate the source
449  * is attached. There may be more specific non-attached
450  * routes that match the source, but these do not influence
451  * whether we respond to an ARP request, i.e. they do not
452  * influence whether we are the correct way for the sender
453  * to reach us, they only affect how we reach the sender.
454  */
455  fib_entry_t *src_fib_entry;
456  const fib_prefix_t *pfx;
458  fib_source_t source;
459  int attached;
460  int mask;
461 
462  mask = 32;
463  attached = 0;
464 
465  do
466  {
467  src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
468  &arp0->
469  ip4_over_ethernet[0].ip4,
470  mask);
471  src_fib_entry = fib_entry_get (src_fei);
472 
473  /*
474  * It's possible that the source that provides the
475  * flags we need, or the flags we must not have,
476  * is not the best source, so check then all.
477  */
478  /* *INDENT-OFF* */
479  FOR_EACH_SRC_ADDED(src_fib_entry, src, source,
480  ({
481  src_flags = fib_entry_get_flags_for_source (src_fei, source);
482 
483  /* Reject requests/replies with our local interface
484  address. */
485  if (FIB_ENTRY_FLAG_LOCAL & src_flags)
486  {
487  error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
488  /*
489  * When VPP has an interface whose address is also
490  * applied to a TAP interface on the host, then VPP's
491  * TAP interface will be unnumbered to the 'real'
492  * interface and do proxy ARP from the host.
493  * The curious aspect of this setup is that ARP requests
494  * from the host will come from the VPP's own address.
495  * So don't drop immediately here, instead go see if this
496  * is a proxy ARP case.
497  */
498  goto next_feature;
499  }
500  /* A Source must also be local to subnet of matching
501  * interface address. */
502  if ((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
503  (FIB_ENTRY_FLAG_CONNECTED & src_flags))
504  {
505  attached = 1;
506  break;
507  }
508  /*
509  * else
510  * The packet was sent from an address that is not
511  * connected nor attached i.e. it is not from an
512  * address that is covered by a link's sub-net,
513  * nor is it a already learned host resp.
514  */
515  }));
516  /* *INDENT-ON* */
517 
518  /*
519  * shorter mask lookup for the next iteration.
520  */
521  pfx = fib_entry_get_prefix (src_fei);
522  mask = pfx->fp_len - 1;
523 
524  /*
525  * continue until we hit the default route or we find
526  * the attached we are looking for. The most likely
527  * outcome is we find the attached with the first source
528  * on the first lookup.
529  */
530  }
531  while (!attached &&
533 
534  if (!attached)
535  {
536  /*
537  * the matching route is a not attached, i.e. it was
538  * added as a result of routing, rather than interface/ARP
539  * configuration. If the matching route is not a host route
540  * (i.e. a /32)
541  */
542  error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
543  goto drop;
544  }
545  }
546 
547  dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
548  &arp0->ip4_over_ethernet[1].ip4,
549  32);
550  conn_sw_if_index0 = fib_entry_get_any_resolving_interface (dst_fei);
551 
552  switch (arp_dst_fib_check (dst_fei, &dst_flags))
553  {
554  case ARP_DST_FIB_ADJ:
555  /*
556  * We matched an adj-fib on ths source subnet (a /32 previously
557  * added as a result of ARP). If this request is a gratuitous
558  * ARP, then learn from it.
559  * The check for matching an adj-fib, is to prevent hosts
560  * from spamming us with gratuitous ARPS that might otherwise
561  * blow our ARP cache
562  */
563  if (conn_sw_if_index0 != sw_if_index0)
564  error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
565  else if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
566  arp0->ip4_over_ethernet[1].ip4.as_u32)
567  error0 = arp_learn (sw_if_index0,
568  &arp0->ip4_over_ethernet[0]);
569  goto drop;
570  case ARP_DST_FIB_CONN:
571  /* destination is connected, continue to process */
572  break;
573  case ARP_DST_FIB_NONE:
574  /* destination is not connected, stop here */
575  error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
576  goto next_feature;
577  }
578 
579  dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
580  pfx0 = fib_entry_get_prefix (dst_fei);
581  if_addr0 = &pfx0->fp_addr.ip4;
582 
583  is_vrrp_reply0 =
584  ((arp0->opcode ==
585  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
586  &&
587  (!memcmp
588  (arp0->ip4_over_ethernet[0].mac.bytes, vrrp_prefix,
589  sizeof (vrrp_prefix))));
590 
591  /* Trash ARP packets whose ARP-level source addresses do not
592  match their L2-frame-level source addresses, unless it's
593  a reply from a VRRP virtual router */
595  (eth_rx->src_address,
596  arp0->ip4_over_ethernet[0].mac.bytes) && !is_vrrp_reply0)
597  {
598  error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
599  goto drop;
600  }
601 
602  /* Learn or update sender's mapping only for replies to addresses
603  * that are local to the subnet */
604  if (arp0->opcode ==
605  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
606  {
607  if (dst_is_local0)
608  error0 =
609  arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
610  else
611  /* a reply for a non-local destination could be a GARP.
612  * GARPs for hosts we know were handled above, so this one
613  * we drop */
614  error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
615 
616  goto next_feature;
617  }
618  else if (arp0->opcode ==
619  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request) &&
620  (dst_is_local0 == 0))
621  {
622  goto next_feature;
623  }
624 
625  /* Honor unnumbered interface, if any */
626  if (sw_if_index0 != conn_sw_if_index0 ||
627  sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
628  {
629  /*
630  * The interface the ARP is sent to or was received on is not the
631  * interface on which the covering prefix is configured.
632  * Maybe this is a case for unnumbered.
633  */
634  if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
635  {
636  error0 = ETHERNET_ARP_ERROR_unnumbered_mismatch;
637  goto drop;
638  }
639  }
640  if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
641  arp0->ip4_over_ethernet[1].ip4.as_u32)
642  {
643  error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
644  goto drop;
645  }
646 
647  next0 = arp_mk_reply (vnm, p0, sw_if_index0,
648  if_addr0, arp0, eth_rx);
649 
650  /* We are going to reply to this request, so, in the absence of
651  errors, learn the sender */
652  if (!error0)
653  error0 = arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[1]);
654 
655  n_replies_sent += 1;
656  goto enqueue;
657 
658  next_feature:
659  vnet_feature_next (&next0, p0);
660  goto enqueue;
661 
662  drop:
663  p0->error = node->errors[error0];
664 
665  enqueue:
666  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
667  n_left_to_next, pi0, next0);
668  }
669 
670  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
671  }
672 
673  vlib_error_count (vm, node->node_index,
674  ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
675 
676  return frame->n_vectors;
677 }
678 
679 
680 static char *ethernet_arp_error_strings[] = {
681 #define _(sym,string) string,
683 #undef _
684 };
685 
686 /* *INDENT-OFF* */
687 
689 {
690  .function = arp_input,
691  .name = "arp-input",
692  .vector_size = sizeof (u32),
693  .n_errors = ETHERNET_ARP_N_ERROR,
694  .error_strings = ethernet_arp_error_strings,
695  .n_next_nodes = ARP_INPUT_N_NEXT,
696  .next_nodes = {
697  [ARP_INPUT_NEXT_DROP] = "error-drop",
698  [ARP_INPUT_NEXT_DISABLED] = "arp-disabled",
699  },
700  .format_buffer = format_ethernet_arp_header,
701  .format_trace = format_ethernet_arp_input_trace,
702 };
703 
705 {
706  .function = arp_disabled,
707  .name = "arp-disabled",
708  .vector_size = sizeof (u32),
709  .n_errors = ARP_DISABLED_N_ERROR,
710  .error_strings = arp_disabled_error_strings,
711  .n_next_nodes = ARP_DISABLED_N_NEXT,
712  .next_nodes = {
713  [ARP_INPUT_NEXT_DROP] = "error-drop",
714  },
715  .format_buffer = format_ethernet_arp_header,
716  .format_trace = format_ethernet_arp_input_trace,
717 };
718 
720 {
721  .function = arp_reply,
722  .name = "arp-reply",
723  .vector_size = sizeof (u32),
724  .n_errors = ETHERNET_ARP_N_ERROR,
725  .error_strings = ethernet_arp_error_strings,
726  .n_next_nodes = ARP_REPLY_N_NEXT,
727  .next_nodes = {
728  [ARP_REPLY_NEXT_DROP] = "error-drop",
729  [ARP_REPLY_NEXT_REPLY_TX] = "interface-output",
730  },
731  .format_buffer = format_ethernet_arp_header,
732  .format_trace = format_ethernet_arp_input_trace,
733 };
734 
735 /* Built-in ARP rx feature path definition */
736 VNET_FEATURE_ARC_INIT (arp_feat, static) =
737 {
738  .arc_name = "arp",
739  .start_nodes = VNET_FEATURES ("arp-input"),
740  .last_in_arc = "error-drop",
741  .arc_index_ptr = &ethernet_arp_main.feature_arc_index,
742 };
743 
744 VNET_FEATURE_INIT (arp_reply_feat_node, static) =
745 {
746  .arc_name = "arp",
747  .node_name = "arp-reply",
748  .runs_before = VNET_FEATURES ("arp-disabled"),
749 };
750 
751 VNET_FEATURE_INIT (arp_proxy_feat_node, static) =
752 {
753  .arc_name = "arp",
754  .node_name = "arp-proxy",
755  .runs_after = VNET_FEATURES ("arp-reply"),
756  .runs_before = VNET_FEATURES ("arp-disabled"),
757 };
758 
759 VNET_FEATURE_INIT (arp_disabled_feat_node, static) =
760 {
761  .arc_name = "arp",
762  .node_name = "arp-disabled",
763  .runs_before = VNET_FEATURES ("error-drop"),
764 };
765 
766 VNET_FEATURE_INIT (arp_drop_feat_node, static) =
767 {
768  .arc_name = "arp",
769  .node_name = "error-drop",
770  .runs_before = 0, /* last feature */
771 };
772 
773 /* *INDENT-ON* */
774 
775 typedef struct
776 {
777  pg_edit_t l2_type, l3_type;
778  pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
780  struct
781  {
784  } ip4_over_ethernet[2];
786 
787 static inline void
789 {
790  /* Initialize fields that are not bit fields in the IP header. */
791 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
792  _(l2_type);
793  _(l3_type);
794  _(n_l2_address_bytes);
795  _(n_l3_address_bytes);
796  _(opcode);
797  _(ip4_over_ethernet[0].mac);
798  _(ip4_over_ethernet[0].ip4);
799  _(ip4_over_ethernet[1].mac);
800  _(ip4_over_ethernet[1].ip4);
801 #undef _
802 }
803 
804 uword
805 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
806 {
807  pg_stream_t *s = va_arg (*args, pg_stream_t *);
809  u32 group_index;
810 
811  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
812  &group_index);
814 
815  /* Defaults. */
816  pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
817  pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
820 
821  if (!unformat (input, "%U: %U/%U -> %U/%U",
832  {
833  /* Free up any edits we may have added. */
834  pg_free_edit_group (s);
835  return 0;
836  }
837  return 1;
838 }
839 
840 /*
841  * callback when an interface address is added or deleted
842  */
843 static void
845  uword opaque, u32 sw_if_index, u32 is_enable)
846 {
848 
849  if (is_enable)
850  arp_enable (am, sw_if_index);
851  else
852  arp_disable (am, sw_if_index);
853 }
854 
855 /*
856  * Remove any arp entries associated with the specified interface
857  */
858 static clib_error_t *
860 {
862  if (is_add)
863  arp_disable (am, sw_if_index);
864  return (NULL);
865 }
866 
868 
869 const static ip_neighbor_vft_t arp_vft = {
871  .inv_proxy4_del = arp_proxy_del,
872  .inv_proxy4_enable = arp_proxy_disable,
873  .inv_proxy4_disable = arp_proxy_disable,
874 };
875 
876 static clib_error_t *
878 {
880  ip4_main_t *im = &ip4_main;
881  pg_node_t *pn;
882 
883  ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
884 
885  pn = pg_get_node (arp_input_node.index);
887 
888  am->opcode_by_name = hash_create_string (0, sizeof (uword));
889 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
891 #undef _
892 
893  /* don't trace ARP error packets */
894  {
895  vlib_node_runtime_t *rt =
897 
898 #define _(a,b) \
899  vnet_pcap_drop_trace_filter_add_del \
900  (rt->errors[ETHERNET_ARP_ERROR_##a], \
901  1 /* is_add */);
903 #undef _
904  }
905 
906  {
909  };
911  }
912 
913  ip_neighbor_register (AF_IP4, &arp_vft);
914 
915  return 0;
916 }
917 
918 /* *INDENT-OFF* */
920 {
921  .runs_after = VLIB_INITS("ethernet_init",
922  "ip_neighbor_init"),
923 };
924 /* *INDENT-ON* */
925 
926 /*
927  * fd.io coding-style-patch-verification: ON
928  *
929  * Local Variables:
930  * eval: (c-set-style "gnu")
931  * End:
932  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
Definition: edit.h:64
#define foreach_ethernet_arp_error
Definition: arp.h:23
enum fib_source_t_ fib_source_t
The different sources that can create a route.
static void arp_enable(ethernet_arp_main_t *am, u32 sw_if_index)
Definition: arp.c:136
An entry in a FIB table.
Definition: fib_entry.h:305
static uword arp_disabled(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp.c:309
#define CLIB_UNUSED(x)
Definition: clib.h:87
arp_dst_fib_type
Definition: arp.c:355
vl_api_mac_address_t mac
Definition: l2.api:502
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
static uword arp_reply(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp.c:388
u32 enabled
Is ARP enabled on this interface.
Definition: arp.c:47
uword unformat_pg_arp_header(unformat_input_t *input, va_list *args)
Definition: arp.c:805
static void pg_ethernet_arp_header_init(pg_ethernet_arp_header_t *p)
Definition: arp.c:788
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static void pg_edit_set_fixed(pg_edit_t *e, u64 value)
Definition: edit.h:153
vnet_interface_main_t interface_main
Definition: vnet.h:65
void ip_neighbor_learn_dp(const ip_neighbor_learn_t *l)
APIs invoked by neighbor implementation (i.s.
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
static vlib_node_registration_t arp_reply_node
(constructor) VLIB_REGISTER_NODE (arp_reply_node)
Definition: arp.c:719
Information related to the source of a FIB entry.
Definition: fib_entry.h:197
struct ethernet_arp_interface_t_ ethernet_arp_interface_t
Per-interface ARP configuration and state.
#define foreach_arp_disabled_error
Definition: arp.c:291
u8 src_address[6]
Definition: packet.h:56
static uword arp_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp.c:216
ip46_address_t ip
Definition: ip_types.h:81
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
static vlib_node_registration_t arp_disabled_node
(constructor) VLIB_REGISTER_NODE (arp_disabled_node)
Definition: arp.c:704
vl_api_address_t src
Definition: gre.api:54
static uword unformat_ethernet_arp_opcode_host_byte_order(unformat_input_t *input, va_list *args)
Definition: arp.c:67
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
uword unformat_pg_edit(unformat_input_t *input, va_list *args)
Definition: edit.c:106
static void arp_enable_disable_interface(ip4_main_t *im, uword opaque, u32 sw_if_index, u32 is_enable)
Definition: arp.c:844
pg_edit_t l2_type
Definition: arp.c:777
vlib_main_t * vm
Definition: in2out_ed.c:1580
const fib_prefix_t * fib_entry_get_prefix(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:1712
uword * opcode_by_name
Definition: arp.c:53
u8 feature_arc_index
Definition: arp.c:59
int arp_proxy_del(u32 fib_index, const ip4_address_t *lo_addr, const ip4_address_t *hi_addr)
Definition: arp_proxy.c:134
u16 mask
Definition: flow_types.api:52
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
Definition: fib_entry.h:114
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:378
static const u8 vrrp_prefix[]
Definition: arp.c:64
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:227
pg_edit_t n_l3_address_bytes
Definition: arp.c:778
ip4_enable_disable_interface_callback_t * enable_disable_interface_callbacks
Functions to call when interface becomes IPv4 enabled/disable.
Definition: ip4.h:145
unformat_function_t unformat_ip4_address
Definition: format.h:68
ethernet_arp_ip4_over_ethernet_address_t ip4_over_ethernet[2]
Definition: arp_packet.h:142
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
description fragment has unexpected format
Definition: map.api:433
enum arp_input_next_t_ arp_input_next_t
Aggregate type for a prefix.
Definition: fib_types.h:202
static u8 * format_ethernet_arp_input_trace(u8 *s, va_list *va)
Definition: arp.c:113
unsigned int u32
Definition: types.h:88
static void * pg_create_edit_group(pg_stream_t *s, int n_edit_bytes, int n_packet_bytes, u32 *group_index)
Definition: pg.h:236
u16 fp_len
The mask length.
Definition: fib_types.h:206
static enum arp_dst_fib_type arp_dst_fib_check(const fib_node_index_t fei, fib_entry_flag_t *flags)
Definition: arp.c:368
int arp_proxy_add(u32 fib_index, const ip4_address_t *lo_addr, const ip4_address_t *hi_addr)
Definition: arp_proxy.c:127
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
pg_edit_t l3_type
Definition: arp.c:777
#define foreach_ethernet_arp_opcode
Definition: arp_packet.h:64
Per-interface ARP configuration and state.
Definition: arp.c:42
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
#define FOR_EACH_SRC_ADDED(_entry, _src, _source, action)
static int arp_is_enabled(ethernet_arp_main_t *am, u32 sw_if_index)
Definition: arp.c:127
Definition: fib_entry.h:117
static ethernet_header_t * ethernet_buffer_get_header(vlib_buffer_t *b)
Definition: ethernet.h:419
u32 fib_entry_get_any_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1468
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:225
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static clib_error_t * vnet_arp_add_del_sw_interface(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: arp.c:859
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
struct pg_ethernet_arp_header_t::@165 ip4_over_ethernet[2]
#define always_inline
Definition: ipsec.h:28
vnet_sw_interface_flags_t flags
Definition: interface.h:739
ethernet_arp_interface_t * ethernet_arp_by_sw_if_index
Per interface state.
Definition: arp.c:56
vl_api_ip4_address_t ip4
Definition: one.api:376
Adjacency source.
Definition: fib_source.h:102
u32 node_index
Node index.
Definition: node.h:488
static clib_error_t * ethernet_arp_init(vlib_main_t *vm)
Definition: arp.c:877
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
static_always_inline u32 arp_mk_reply(vnet_main_t *vnm, vlib_buffer_t *p0, u32 sw_if_index0, const ip4_address_t *if_addr0, ethernet_arp_header_t *arp0, ethernet_header_t *eth_rx)
Definition: arp_packet.h:32
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:391
uword unformat_mac_address_t(unformat_input_t *input, va_list *args)
Definition: mac_address.c:37
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1458
fib_node_index_t ip4_fib_table_lookup(const ip4_fib_t *fib, const ip4_address_t *addr, u32 len)
Definition: ip4_fib.c:294
int arp_proxy_disable(u32 sw_if_index)
Definition: arp_proxy.c:55
int fib_entry_is_sourced(fib_node_index_t fib_entry_index, fib_source_t source)
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
u16 n_vectors
Definition: node.h:397
pg_edit_t n_l2_address_bytes
Definition: arp.c:778
static void arp_disable(ethernet_arp_main_t *am, u32 sw_if_index)
Definition: arp.c:151
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
ip4_enable_disable_interface_function_t * function
Definition: ip4.h:84
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
static ethernet_arp_main_t ethernet_arp_main
Definition: arp.c:62
static ip4_fib_t * ip4_fib_get(u32 index)
Get the FIB at the given index.
Definition: ip4_fib.h:113
static int ethernet_mac_address_equal(const u8 *a, const u8 *b)
Definition: mac_address.h:85
static char * ethernet_arp_error_strings[]
Definition: arp.c:680
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:115
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(vnet_arp_add_del_sw_interface)
unformat_function_t * unformat_edit
Definition: pg.h:324
Virtual function Table for neighbor protocol implementations to register.
Definition: ip_neighbor.h:101
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:483
fib_entry_t * fib_entry_get(fib_node_index_t index)
Definition: fib_entry.c:51
enum fib_entry_flag_t_ fib_entry_flag_t
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
arp_disabled_error_t
Definition: arp.c:294
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:511
VNET_FEATURE_ARC_INIT(arp_feat, static)
IPv4 main type.
Definition: ip4.h:107
uword unformat_vlib_number_by_name(unformat_input_t *input, va_list *args)
Definition: format.c:157
static void pg_free_edit_group(pg_stream_t *s)
Definition: pg.h:289
arp_input_next_t_
Definition: arp.c:208
VNET_FEATURE_INIT(arp_reply_feat_node, static)
static char * arp_disabled_error_strings[]
Definition: arp.c:302
Definition: pg.h:96
#define VNET_FEATURES(...)
Definition: feature.h:470
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:2288
fib_entry_flag_t fib_entry_get_flags_for_source(fib_node_index_t fib_entry_index, fib_source_t source)
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:48
static vlib_node_registration_t arp_input_node
(constructor) VLIB_REGISTER_NODE (arp_input_node)
Definition: arp.c:688
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1581
Definition: fib_entry.h:113
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:873
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
The default route source.
Definition: fib_source.h:131
pg_edit_t opcode
Definition: arp.c:779
u8 * format_ethernet_arp_header(u8 *s, va_list *va)
Definition: arp_packet.c:59
#define vnet_buffer(b)
Definition: buffer.h:417
enum arp_disabled_next_t_ arp_disabled_next_t
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1105
u16 flags
Copy of main node flags.
Definition: node.h:501
static int arp_unnumbered(vlib_buffer_t *p0, u32 input_sw_if_index, u32 conn_sw_if_index)
Definition: arp.c:164
u8 si
Definition: lisp_types.api:47
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
arp_disabled_next_t_
Definition: arp.c:285
static uword unformat_ethernet_arp_opcode_net_byte_order(unformat_input_t *input, va_list *args)
Definition: arp.c:95
#define VLIB_INITS(...)
Definition: init.h:357
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
ip4_neighbor_proxy_addr_t inv_proxy4_add
Definition: ip_neighbor.h:105
Definition: pg.h:321
void ip_neighbor_register(ip_address_family_t af, const ip_neighbor_vft_t *vft)
Definition: ip_neighbor.c:1008
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
static u32 arp_learn(u32 sw_if_index, const ethernet_arp_ip4_over_ethernet_address_t *addr)
Definition: arp.c:189
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
Definition: defs.h:46
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:303
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:302