FD.io VPP  v20.09-64-g4f7b92f0a
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  ip_neighbor_learn_t l = {
193  .ip.ip4 = addr->ip4,
194  .type = IP46_TYPE_IP4,
195  .mac = addr->mac,
196  .sw_if_index = sw_if_index,
197  };
198 
200 
201  return (ETHERNET_ARP_ERROR_l3_src_address_learned);
202 }
203 
204 typedef enum arp_input_next_t_
205 {
210 
211 static uword
213 {
214  u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
216 
217  from = vlib_frame_vector_args (frame);
218  n_left_from = frame->n_vectors;
219  next_index = node->cached_next_index;
220 
221  if (node->flags & VLIB_NODE_FLAG_TRACE)
222  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
223  /* stride */ 1,
224  sizeof (ethernet_arp_input_trace_t));
225 
226  while (n_left_from > 0)
227  {
228  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
229 
230  while (n_left_from > 0 && n_left_to_next > 0)
231  {
232  const ethernet_arp_header_t *arp0;
233  arp_input_next_t next0;
234  vlib_buffer_t *p0;
235  u32 pi0, error0;
236 
237  pi0 = to_next[0] = from[0];
238  from += 1;
239  to_next += 1;
240  n_left_from -= 1;
241  n_left_to_next -= 1;
242 
243  p0 = vlib_get_buffer (vm, pi0);
244  arp0 = vlib_buffer_get_current (p0);
245 
246  error0 = ETHERNET_ARP_ERROR_replies_sent;
247  next0 = ARP_INPUT_NEXT_DROP;
248 
249  error0 =
250  (arp0->l2_type !=
251  clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
252  ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
253  error0 =
254  (arp0->l3_type !=
255  clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
256  ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
257  error0 =
258  (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ?
259  ETHERNET_ARP_ERROR_l3_dst_address_unset : error0);
260 
261  if (ETHERNET_ARP_ERROR_replies_sent == error0)
262  {
263  next0 = ARP_INPUT_NEXT_DISABLED;
266  &next0, p0);
267  }
268  else
269  p0->error = node->errors[error0];
270 
271  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
272  n_left_to_next, pi0, next0);
273  }
274 
275  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
276  }
277 
278  return frame->n_vectors;
279 }
280 
282 {
286 
287 #define foreach_arp_disabled_error \
288  _ (DISABLED, "ARP Disabled on this interface") \
289 
290 typedef enum
291 {
292 #define _(sym,string) ARP_DISABLED_ERROR_##sym,
294 #undef _
297 
298 static char *arp_disabled_error_strings[] = {
299 #define _(sym,string) string,
301 #undef _
302 };
303 
304 static uword
307 {
308  u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
309 
310  from = vlib_frame_vector_args (frame);
311  n_left_from = frame->n_vectors;
312  next_index = node->cached_next_index;
313 
314  if (node->flags & VLIB_NODE_FLAG_TRACE)
315  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
316  /* stride */ 1,
317  sizeof (ethernet_arp_input_trace_t));
318 
319  while (n_left_from > 0)
320  {
321  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
322 
323  while (n_left_from > 0 && n_left_to_next > 0)
324  {
326  vlib_buffer_t *p0;
327  u32 pi0, error0;
328 
329  next0 = ARP_DISABLED_NEXT_DROP;
330  error0 = ARP_DISABLED_ERROR_DISABLED;
331 
332  pi0 = to_next[0] = from[0];
333  from += 1;
334  to_next += 1;
335  n_left_from -= 1;
336  n_left_to_next -= 1;
337 
338  p0 = vlib_get_buffer (vm, pi0);
339  p0->error = node->errors[error0];
340 
341  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
342  n_left_to_next, pi0, next0);
343  }
344 
345  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
346  }
347 
348  return frame->n_vectors;
349 }
350 
352 {
356 };
357 
358 /*
359  * we're looking for FIB sources that indicate the destination
360  * is attached. There may be interposed DPO prior to the one
361  * we are looking for
362  */
363 static enum arp_dst_fib_type
365 {
366  const fib_entry_t *entry = fib_entry_get (fei);
367  const fib_entry_src_t *entry_src;
369  /* *INDENT-OFF* */
370  FOR_EACH_SRC_ADDED(entry, entry_src, src,
371  ({
372  *flags = fib_entry_get_flags_for_source (fei, src);
374  return ARP_DST_FIB_ADJ;
375  else if (FIB_ENTRY_FLAG_CONNECTED & *flags)
376  return ARP_DST_FIB_CONN;
377  }))
378  /* *INDENT-ON* */
379 
380  return ARP_DST_FIB_NONE;
381 }
382 
383 static uword
385 {
386  vnet_main_t *vnm = vnet_get_main ();
387  u32 n_left_from, next_index, *from, *to_next;
388  u32 n_replies_sent = 0;
389 
390  from = vlib_frame_vector_args (frame);
391  n_left_from = frame->n_vectors;
392  next_index = node->cached_next_index;
393 
394  if (node->flags & VLIB_NODE_FLAG_TRACE)
395  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
396  /* stride */ 1,
397  sizeof (ethernet_arp_input_trace_t));
398 
399  while (n_left_from > 0)
400  {
401  u32 n_left_to_next;
402 
403  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
404 
405  while (n_left_from > 0 && n_left_to_next > 0)
406  {
407  vlib_buffer_t *p0;
408  ethernet_arp_header_t *arp0;
409  ethernet_header_t *eth_rx;
410  const ip4_address_t *if_addr0;
411  u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
412  u8 dst_is_local0, is_vrrp_reply0;
413  fib_node_index_t dst_fei, src_fei;
414  const fib_prefix_t *pfx0;
415  fib_entry_flag_t src_flags, dst_flags;
416 
417  pi0 = from[0];
418  to_next[0] = pi0;
419  from += 1;
420  to_next += 1;
421  n_left_from -= 1;
422  n_left_to_next -= 1;
423 
424  p0 = vlib_get_buffer (vm, pi0);
425  arp0 = vlib_buffer_get_current (p0);
426  /* Fill in ethernet header. */
427  eth_rx = ethernet_buffer_get_header (p0);
428 
429  next0 = ARP_REPLY_NEXT_DROP;
430  error0 = ETHERNET_ARP_ERROR_replies_sent;
431  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
432 
433  /* Check that IP address is local and matches incoming interface. */
434  fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
435  if (~0 == fib_index0)
436  {
437  error0 = ETHERNET_ARP_ERROR_interface_no_table;
438  goto drop;
439 
440  }
441 
442  {
443  /*
444  * we're looking for FIB entries that indicate the source
445  * is attached. There may be more specific non-attached
446  * routes that match the source, but these do not influence
447  * whether we respond to an ARP request, i.e. they do not
448  * influence whether we are the correct way for the sender
449  * to reach us, they only affect how we reach the sender.
450  */
451  fib_entry_t *src_fib_entry;
452  const fib_prefix_t *pfx;
454  fib_source_t source;
455  int attached;
456  int mask;
457 
458  mask = 32;
459  attached = 0;
460 
461  do
462  {
463  src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
464  &arp0->
465  ip4_over_ethernet[0].ip4,
466  mask);
467  src_fib_entry = fib_entry_get (src_fei);
468 
469  /*
470  * It's possible that the source that provides the
471  * flags we need, or the flags we must not have,
472  * is not the best source, so check then all.
473  */
474  /* *INDENT-OFF* */
475  FOR_EACH_SRC_ADDED(src_fib_entry, src, source,
476  ({
477  src_flags = fib_entry_get_flags_for_source (src_fei, source);
478 
479  /* Reject requests/replies with our local interface
480  address. */
481  if (FIB_ENTRY_FLAG_LOCAL & src_flags)
482  {
483  error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
484  /*
485  * When VPP has an interface whose address is also
486  * applied to a TAP interface on the host, then VPP's
487  * TAP interface will be unnumbered to the 'real'
488  * interface and do proxy ARP from the host.
489  * The curious aspect of this setup is that ARP requests
490  * from the host will come from the VPP's own address.
491  * So don't drop immediately here, instead go see if this
492  * is a proxy ARP case.
493  */
494  goto next_feature;
495  }
496  /* A Source must also be local to subnet of matching
497  * interface address. */
498  if ((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
499  (FIB_ENTRY_FLAG_CONNECTED & src_flags))
500  {
501  attached = 1;
502  break;
503  }
504  /*
505  * else
506  * The packet was sent from an address that is not
507  * connected nor attached i.e. it is not from an
508  * address that is covered by a link's sub-net,
509  * nor is it a already learned host resp.
510  */
511  }));
512  /* *INDENT-ON* */
513 
514  /*
515  * shorter mask lookup for the next iteration.
516  */
517  pfx = fib_entry_get_prefix (src_fei);
518  mask = pfx->fp_len - 1;
519 
520  /*
521  * continue until we hit the default route or we find
522  * the attached we are looking for. The most likely
523  * outcome is we find the attached with the first source
524  * on the first lookup.
525  */
526  }
527  while (!attached &&
529 
530  if (!attached)
531  {
532  /*
533  * the matching route is a not attached, i.e. it was
534  * added as a result of routing, rather than interface/ARP
535  * configuration. If the matching route is not a host route
536  * (i.e. a /32)
537  */
538  error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
539  goto drop;
540  }
541  }
542 
543  dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
544  &arp0->ip4_over_ethernet[1].ip4,
545  32);
546  switch (arp_dst_fib_check (dst_fei, &dst_flags))
547  {
548  case ARP_DST_FIB_ADJ:
549  /*
550  * We matched an adj-fib on ths source subnet (a /32 previously
551  * added as a result of ARP). If this request is a gratuitous
552  * ARP, then learn from it.
553  * The check for matching an adj-fib, is to prevent hosts
554  * from spamming us with gratuitous ARPS that might otherwise
555  * blow our ARP cache
556  */
557  if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
558  arp0->ip4_over_ethernet[1].ip4.as_u32)
559  error0 =
560  arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
561  goto drop;
562  case ARP_DST_FIB_CONN:
563  /* destination is connected, continue to process */
564  break;
565  case ARP_DST_FIB_NONE:
566  /* destination is not connected, stop here */
567  error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
568  goto next_feature;
569  }
570 
571  dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
572  pfx0 = fib_entry_get_prefix (dst_fei);
573  if_addr0 = &pfx0->fp_addr.ip4;
574 
575  is_vrrp_reply0 =
576  ((arp0->opcode ==
577  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
578  &&
579  (!memcmp
580  (arp0->ip4_over_ethernet[0].mac.bytes, vrrp_prefix,
581  sizeof (vrrp_prefix))));
582 
583  /* Trash ARP packets whose ARP-level source addresses do not
584  match their L2-frame-level source addresses, unless it's
585  a reply from a VRRP virtual router */
587  (eth_rx->src_address,
588  arp0->ip4_over_ethernet[0].mac.bytes) && !is_vrrp_reply0)
589  {
590  error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
591  goto drop;
592  }
593 
594  /* Learn or update sender's mapping only for replies to addresses
595  * that are local to the subnet */
596  if (arp0->opcode ==
597  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply))
598  {
599  if (dst_is_local0)
600  error0 =
601  arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[0]);
602  else
603  /* a reply for a non-local destination could be a GARP.
604  * GARPs for hosts we know were handled above, so this one
605  * we drop */
606  error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
607 
608  goto next_feature;
609  }
610  else if (arp0->opcode ==
611  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request) &&
612  (dst_is_local0 == 0))
613  {
614  goto next_feature;
615  }
616 
617  /* Honor unnumbered interface, if any */
618  conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
619  if (sw_if_index0 != conn_sw_if_index0 ||
620  sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
621  {
622  /*
623  * The interface the ARP is sent to or was received on is not the
624  * interface on which the covering prefix is configured.
625  * Maybe this is a case for unnumbered.
626  */
627  if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
628  {
629  error0 = ETHERNET_ARP_ERROR_unnumbered_mismatch;
630  goto drop;
631  }
632  }
633  if (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
634  arp0->ip4_over_ethernet[1].ip4.as_u32)
635  {
636  error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
637  goto drop;
638  }
639 
640  next0 = arp_mk_reply (vnm, p0, sw_if_index0,
641  if_addr0, arp0, eth_rx);
642 
643  /* We are going to reply to this request, so, in the absence of
644  errors, learn the sender */
645  if (!error0)
646  error0 = arp_learn (sw_if_index0, &arp0->ip4_over_ethernet[1]);
647 
648  n_replies_sent += 1;
649  goto enqueue;
650 
651  next_feature:
652  vnet_feature_next (&next0, p0);
653  goto enqueue;
654 
655  drop:
656  p0->error = node->errors[error0];
657 
658  enqueue:
659  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
660  n_left_to_next, pi0, next0);
661  }
662 
663  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
664  }
665 
666  vlib_error_count (vm, node->node_index,
667  ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
668 
669  return frame->n_vectors;
670 }
671 
672 
673 static char *ethernet_arp_error_strings[] = {
674 #define _(sym,string) string,
676 #undef _
677 };
678 
679 /* *INDENT-OFF* */
680 
682 {
683  .function = arp_input,
684  .name = "arp-input",
685  .vector_size = sizeof (u32),
686  .n_errors = ETHERNET_ARP_N_ERROR,
687  .error_strings = ethernet_arp_error_strings,
688  .n_next_nodes = ARP_INPUT_N_NEXT,
689  .next_nodes = {
690  [ARP_INPUT_NEXT_DROP] = "error-drop",
691  [ARP_INPUT_NEXT_DISABLED] = "arp-disabled",
692  },
693  .format_buffer = format_ethernet_arp_header,
694  .format_trace = format_ethernet_arp_input_trace,
695 };
696 
698 {
699  .function = arp_disabled,
700  .name = "arp-disabled",
701  .vector_size = sizeof (u32),
702  .n_errors = ARP_DISABLED_N_ERROR,
703  .error_strings = arp_disabled_error_strings,
704  .n_next_nodes = ARP_DISABLED_N_NEXT,
705  .next_nodes = {
706  [ARP_INPUT_NEXT_DROP] = "error-drop",
707  },
708  .format_buffer = format_ethernet_arp_header,
709  .format_trace = format_ethernet_arp_input_trace,
710 };
711 
713 {
714  .function = arp_reply,
715  .name = "arp-reply",
716  .vector_size = sizeof (u32),
717  .n_errors = ETHERNET_ARP_N_ERROR,
718  .error_strings = ethernet_arp_error_strings,
719  .n_next_nodes = ARP_REPLY_N_NEXT,
720  .next_nodes = {
721  [ARP_REPLY_NEXT_DROP] = "error-drop",
722  [ARP_REPLY_NEXT_REPLY_TX] = "interface-output",
723  },
724  .format_buffer = format_ethernet_arp_header,
725  .format_trace = format_ethernet_arp_input_trace,
726 };
727 
728 /* Built-in ARP rx feature path definition */
729 VNET_FEATURE_ARC_INIT (arp_feat, static) =
730 {
731  .arc_name = "arp",
732  .start_nodes = VNET_FEATURES ("arp-input"),
733  .last_in_arc = "error-drop",
734  .arc_index_ptr = &ethernet_arp_main.feature_arc_index,
735 };
736 
737 VNET_FEATURE_INIT (arp_reply_feat_node, static) =
738 {
739  .arc_name = "arp",
740  .node_name = "arp-reply",
741  .runs_before = VNET_FEATURES ("arp-disabled"),
742 };
743 
744 VNET_FEATURE_INIT (arp_proxy_feat_node, static) =
745 {
746  .arc_name = "arp",
747  .node_name = "arp-proxy",
748  .runs_after = VNET_FEATURES ("arp-reply"),
749  .runs_before = VNET_FEATURES ("arp-disabled"),
750 };
751 
752 VNET_FEATURE_INIT (arp_disabled_feat_node, static) =
753 {
754  .arc_name = "arp",
755  .node_name = "arp-disabled",
756  .runs_before = VNET_FEATURES ("error-drop"),
757 };
758 
759 VNET_FEATURE_INIT (arp_drop_feat_node, static) =
760 {
761  .arc_name = "arp",
762  .node_name = "error-drop",
763  .runs_before = 0, /* last feature */
764 };
765 
766 /* *INDENT-ON* */
767 
768 typedef struct
769 {
770  pg_edit_t l2_type, l3_type;
771  pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
773  struct
774  {
777  } ip4_over_ethernet[2];
779 
780 static inline void
782 {
783  /* Initialize fields that are not bit fields in the IP header. */
784 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
785  _(l2_type);
786  _(l3_type);
787  _(n_l2_address_bytes);
788  _(n_l3_address_bytes);
789  _(opcode);
790  _(ip4_over_ethernet[0].mac);
791  _(ip4_over_ethernet[0].ip4);
792  _(ip4_over_ethernet[1].mac);
793  _(ip4_over_ethernet[1].ip4);
794 #undef _
795 }
796 
797 uword
798 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
799 {
800  pg_stream_t *s = va_arg (*args, pg_stream_t *);
802  u32 group_index;
803 
804  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
805  &group_index);
807 
808  /* Defaults. */
809  pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
810  pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
813 
814  if (!unformat (input, "%U: %U/%U -> %U/%U",
825  {
826  /* Free up any edits we may have added. */
827  pg_free_edit_group (s);
828  return 0;
829  }
830  return 1;
831 }
832 
833 /*
834  * callback when an interface address is added or deleted
835  */
836 static void
838  uword opaque, u32 sw_if_index, u32 is_enable)
839 {
841 
842  if (is_enable)
843  arp_enable (am, sw_if_index);
844  else
845  arp_disable (am, sw_if_index);
846 }
847 
848 /*
849  * Remove any arp entries associated with the specified interface
850  */
851 static clib_error_t *
853 {
855  if (is_add)
856  arp_disable (am, sw_if_index);
857  return (NULL);
858 }
859 
861 
862 const static ip_neighbor_vft_t arp_vft = {
864  .inv_proxy4_del = arp_proxy_del,
865  .inv_proxy4_enable = arp_proxy_disable,
866  .inv_proxy4_disable = arp_proxy_disable,
867 };
868 
869 static clib_error_t *
871 {
873  ip4_main_t *im = &ip4_main;
874  pg_node_t *pn;
875 
876  ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
877 
878  pn = pg_get_node (arp_input_node.index);
880 
881  am->opcode_by_name = hash_create_string (0, sizeof (uword));
882 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
884 #undef _
885 
886  /* don't trace ARP error packets */
887  {
888  vlib_node_runtime_t *rt =
890 
891 #define _(a,b) \
892  vnet_pcap_drop_trace_filter_add_del \
893  (rt->errors[ETHERNET_ARP_ERROR_##a], \
894  1 /* is_add */);
896 #undef _
897  }
898 
899  {
902  };
904  }
905 
907 
908  return 0;
909 }
910 
911 /* *INDENT-OFF* */
913 {
914  .runs_after = VLIB_INITS("ethernet_init",
915  "ip_neighbor_init"),
916 };
917 /* *INDENT-ON* */
918 
919 /*
920  * fd.io coding-style-patch-verification: ON
921  *
922  * Local Variables:
923  * eval: (c-set-style "gnu")
924  * End:
925  */
#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:305
#define CLIB_UNUSED(x)
Definition: clib.h:87
arp_dst_fib_type
Definition: arp.c:351
vl_api_mac_address_t mac
Definition: l2.api:502
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:103
static uword arp_reply(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp.c:384
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:798
static void pg_ethernet_arp_header_init(pg_ethernet_arp_header_t *p)
Definition: arp.c:781
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:59
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:712
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:287
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:212
#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:697
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:837
pg_edit_t l2_type
Definition: arp.c:770
vlib_main_t * vm
Definition: in2out_ed.c:1582
const fib_prefix_t * fib_entry_get_prefix(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:1691
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
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:469
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:374
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:230
pg_edit_t n_l3_address_bytes
Definition: arp.c:771
ip4_enable_disable_interface_callback_t * enable_disable_interface_callbacks
Functions to call when interface becomes IPv4 enabled/disable.
Definition: ip4.h:144
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
enum arp_input_next_t_ arp_input_next_t
Aggregate type for a prefix.
Definition: fib_types.h:203
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:235
u16 fp_len
The mask length.
Definition: fib_types.h:207
static enum arp_dst_fib_type arp_dst_fib_check(const fib_node_index_t fei, fib_entry_flag_t *flags)
Definition: arp.c:364
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:770
#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:408
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
void ip_neighbor_register(ip46_type_t type, const ip_neighbor_vft_t *vft)
Definition: ip_neighbor.c:994
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:852
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define always_inline
Definition: ipsec.h:28
vnet_sw_interface_flags_t flags
Definition: interface.h:738
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:487
static clib_error_t * ethernet_arp_init(vlib_main_t *vm)
Definition: arp.c:870
#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:297
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:169
u16 n_vectors
Definition: node.h:396
pg_edit_t n_l2_address_bytes
Definition: arp.c:771
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:83
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:673
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:321
Virtual function Table for neighbor protocol implementations to register.
Definition: ip_neighbor.h:105
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
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:1582
arp_disabled_error_t
Definition: arp.c:290
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:510
VNET_FEATURE_ARC_INIT(arp_feat, static)
IPv4 main type.
Definition: ip4.h:106
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:288
arp_input_next_t_
Definition: arp.c:204
VNET_FEATURE_INIT(arp_reply_feat_node, static)
static char * arp_disabled_error_strings[]
Definition: arp.c:298
Definition: pg.h:95
#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:2276
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:47
struct pg_ethernet_arp_header_t::@153 ip4_over_ethernet[2]
static vlib_node_registration_t arp_input_node
(constructor) VLIB_REGISTER_NODE (arp_input_node)
Definition: arp.c:681
#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:1583
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:872
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:772
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:1144
u16 flags
Copy of main node flags.
Definition: node.h:500
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:301
arp_disabled_next_t_
Definition: arp.c:281
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:109
Definition: pg.h:318
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
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