FD.io VPP  v17.04.2-2-ga8f93f8
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/ip/ip.h>
19 #include <vnet/ip/ip6.h>
20 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/l2/l2_input.h>
23 #include <vppinfra/mhash.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vnet/adj/adj_nbr.h>
26 #include <vnet/adj/adj_mcast.h>
27 #include <vnet/mpls/mpls.h>
28 
29 /**
30  * @file
31  * @brief IPv4 ARP.
32  *
33  * This file contains code to manage the IPv4 ARP tables (IP Address
34  * to MAC Address lookup).
35  */
36 
37 
38 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
39 
40 /**
41  * @brief Per-interface ARP configuration and state
42  */
44 {
45  /**
46  * Hash table of ARP entries.
47  * Since this hash table is per-interface, the key is only the IPv4 address.
48  */
51 
52 typedef struct
53 {
58 
59 typedef struct
60 {
65  /* Used for arp event notification only */
69 
70 typedef struct
71 {
72  /* Hash tables mapping name to opcode. */
74 
75  /* lite beer "glean" adjacency handling */
78 
79  /* Mac address change notification */
82 
84 
85  /* ARP attack mitigation */
88 
89  /** Per interface state */
91 
92  /* Proxy arp vector */
95 
97 
98 typedef struct
99 {
101  ethernet_arp_ip4_over_ethernet_address_t a;
104  int flags;
105 #define ETHERNET_ARP_ARGS_REMOVE (1<<0)
106 #define ETHERNET_ARP_ARGS_FLUSH (1<<1)
107 #define ETHERNET_ARP_ARGS_POPULATE (1<<2)
109 
110 static void
112  * a);
113 
114 static u8 *
116 {
118  char *t = 0;
119  switch (h)
120  {
121 #define _(n,f) case n: t = #f; break;
123 #undef _
124 
125  default:
126  return format (s, "unknown 0x%x", h);
127  }
128 
129  return format (s, "%s", t);
130 }
131 
132 static u8 *
133 format_ethernet_arp_opcode (u8 * s, va_list * va)
134 {
136  char *t = 0;
137  switch (o)
138  {
139 #define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
141 #undef _
142 
143  default:
144  return format (s, "unknown 0x%x", o);
145  }
146 
147  return format (s, "%s", t);
148 }
149 
150 static uword
152  va_list * args)
153 {
154  int *result = va_arg (*args, int *);
156  int x, i;
157 
158  /* Numeric opcode. */
159  if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
160  {
161  if (x >= (1 << 16))
162  return 0;
163  *result = x;
164  return 1;
165  }
166 
167  /* Named type. */
169  am->opcode_by_name, &i))
170  {
171  *result = i;
172  return 1;
173  }
174 
175  return 0;
176 }
177 
178 static uword
180  va_list * args)
181 {
182  int *result = va_arg (*args, int *);
183  if (!unformat_user
185  return 0;
186 
187  *result = clib_host_to_net_u16 ((u16) * result);
188  return 1;
189 }
190 
191 static u8 *
192 format_ethernet_arp_header (u8 * s, va_list * va)
193 {
194  ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
195  u32 max_header_bytes = va_arg (*va, u32);
196  uword indent;
197  u16 l2_type, l3_type;
198 
199  if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
200  return format (s, "ARP header truncated");
201 
202  l2_type = clib_net_to_host_u16 (a->l2_type);
203  l3_type = clib_net_to_host_u16 (a->l3_type);
204 
205  indent = format_get_indent (s);
206 
207  s = format (s, "%U, type %U/%U, address size %d/%d",
208  format_ethernet_arp_opcode, clib_net_to_host_u16 (a->opcode),
210  format_ethernet_type, l3_type,
212 
213  if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
214  && l3_type == ETHERNET_TYPE_IP4)
215  {
216  s = format (s, "\n%U%U/%U -> %U/%U",
217  format_white_space, indent,
222  }
223  else
224  {
225  uword n2 = a->n_l2_address_bytes;
226  uword n3 = a->n_l3_address_bytes;
227  s = format (s, "\n%U%U/%U -> %U/%U",
228  format_white_space, indent,
229  format_hex_bytes, a->data + 0 * n2 + 0 * n3, n2,
230  format_hex_bytes, a->data + 1 * n2 + 0 * n3, n3,
231  format_hex_bytes, a->data + 1 * n2 + 1 * n3, n2,
232  format_hex_bytes, a->data + 2 * n2 + 1 * n3, n3);
233  }
234 
235  return s;
236 }
237 
238 u8 *
240 {
241  vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
244  u8 *flags = 0;
245 
246  if (!e)
247  return format (s, "%=12s%=16s%=6s%=20s%=24s", "Time", "IP4",
248  "Flags", "Ethernet", "Interface");
249 
250  si = vnet_get_sw_interface (vnm, e->sw_if_index);
251 
253  flags = format (flags, "S");
254 
256  flags = format (flags, "D");
257 
259  flags = format (flags, "N");
260 
261  s = format (s, "%=12U%=16U%=6s%=20U%=24U",
264  flags ? (char *) flags : "",
267 
268  vec_free (flags);
269  return s;
270 }
271 
272 typedef struct
273 {
274  u8 packet_data[64];
276 
277 static u8 *
279 {
280  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
281  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
283 
284  s = format (s, "%U",
286  t->packet_data, sizeof (t->packet_data));
287 
288  return s;
289 }
290 
291 static u8 *
292 format_arp_term_input_trace (u8 * s, va_list * va)
293 {
294  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
295  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
297 
298  /* arp-term trace data saved is either arp or ip6/icmp6 packet:
299  - for arp, the 1st 16-bit field is hw type of value of 0x0001.
300  - for ip6, the first nibble has value of 6. */
301  s = format (s, "%U", t->packet_data[0] == 0 ?
303  t->packet_data, sizeof (t->packet_data));
304 
305  return s;
306 }
307 
308 static void
310 {
311  vnet_main_t *vnm = vnet_get_main ();
312  ip4_main_t *im = &ip4_main;
317  ip4_address_t *src;
318  vlib_buffer_t *b;
319  vlib_main_t *vm;
320  u32 bi = 0;
321 
322  vm = vlib_get_main ();
323 
324  si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
325 
327  {
328  return;
329  }
330 
331  src =
333  &adj->sub_type.nbr.next_hop.
334  ip4,
335  adj->rewrite_header.
336  sw_if_index, &ia);
337  if (!src)
338  {
339  return;
340  }
341 
342  h =
344  &bi);
345 
346  hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
347 
348  clib_memcpy (h->ip4_over_ethernet[0].ethernet,
349  hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
350 
351  h->ip4_over_ethernet[0].ip4 = src[0];
352  h->ip4_over_ethernet[1].ip4 = adj->sub_type.nbr.next_hop.ip4;
353 
354  b = vlib_get_buffer (vm, bi);
355  vnet_buffer (b)->sw_if_index[VLIB_RX] =
356  vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
357 
358  /* Add encapsulation string for software interface (e.g. ethernet header). */
359  vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
360  vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
361 
362  {
364  u32 *to_next = vlib_frame_vector_args (f);
365  to_next[0] = bi;
366  f->n_vectors = 1;
368  }
369 }
370 
371 static void
373 {
377  e->sw_if_index,
379 }
380 
381 static void
383 {
384  ip_adjacency_t *adj = adj_get (ai);
385 
387  (ai,
390  adj->rewrite_header.sw_if_index,
393 }
394 
397 {
400  uword *p;
401 
402  if (NULL != eai->arp_entries)
403  {
404  p = hash_get (eai->arp_entries, addr->as_u32);
405  if (!p)
406  return (NULL);
407 
408  e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
409  }
410 
411  return (e);
412 }
413 
414 static adj_walk_rc_t
416 {
417  ethernet_arp_ip4_entry_t *e = ctx;
418 
419  arp_mk_complete (ai, e);
420 
421  return (ADJ_WALK_RC_CONTINUE);
422 }
423 
424 static adj_walk_rc_t
426 {
427  arp_mk_incomplete (ai);
428 
429  return (ADJ_WALK_RC_CONTINUE);
430 }
431 
432 void
433 arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
434 {
436  ethernet_arp_interface_t *arp_int;
438  ip_adjacency_t *adj;
439 
440  adj = adj_get (ai);
441 
442  vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
443  arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
444  e = arp_entry_find (arp_int, &adj->sub_type.nbr.next_hop.ip4);
445 
446  switch (adj->lookup_next_index)
447  {
448  case IP_LOOKUP_NEXT_ARP:
450  if (NULL != e)
451  {
452  adj_nbr_walk_nh4 (sw_if_index,
454  }
455  else
456  {
457  /*
458  * no matching ARP entry.
459  * construct the rewrite required to for an ARP packet, and stick
460  * that in the adj's pipe to smoke.
461  */
463  (ai,
466  (vnm,
467  sw_if_index,
470 
471  /*
472  * since the FIB has added this adj for a route, it makes sense it
473  * may want to forward traffic sometime soon. Let's send a
474  * speculative ARP. just one. If we were to do periodically that
475  * wouldn't be bad either, but that's more code than i'm prepared to
476  * write at this time for relatively little reward.
477  */
478  arp_nbr_probe (adj);
479  }
480  break;
482  /*
483  * Construct a partial rewrite from the known ethernet mcast dest MAC
484  */
486  (ai,
488  sw_if_index,
489  adj->ia_link,
491 
492  /*
493  * Complete the remaining fields of the adj's rewrite to direct the
494  * complete of the rewrite at switch time by copying in the IP
495  * dst address's bytes.
496  * Ofset is 11 bytes from the end of the MAC header - which is three
497  * bytes into the desintation address. And we write 3 bytes.
498  */
499  adj->rewrite_header.dst_mcast_offset = 11;
500  adj->rewrite_header.dst_mcast_n_bytes = 3;
501 
502  break;
503 
504  case IP_LOOKUP_NEXT_DROP:
505  case IP_LOOKUP_NEXT_PUNT:
511  case IP_LOOKUP_N_NEXT:
512  ASSERT (0);
513  break;
514  }
515 }
516 
517 int
520  * args)
521 {
524  ethernet_arp_ip4_over_ethernet_address_t *a = &args->a;
526  int make_new_arp_cache_entry = 1;
527  uword *p;
528  pending_resolution_t *pr, *mc;
529  ethernet_arp_interface_t *arp_int;
530  int is_static = args->is_static;
531  u32 sw_if_index = args->sw_if_index;
532  int is_no_fib_entry = args->is_no_fib_entry;
533 
534  vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
535 
536  arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
537 
538  if (NULL != arp_int->arp_entries)
539  {
540  p = hash_get (arp_int->arp_entries, a->ip4.as_u32);
541  if (p)
542  {
543  e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
544 
545  /* Refuse to over-write static arp. */
546  if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
547  return -2;
548  make_new_arp_cache_entry = 0;
549  }
550  }
551 
552  if (make_new_arp_cache_entry)
553  {
554  pool_get (am->ip4_entry_pool, e);
555 
556  if (NULL == arp_int->arp_entries)
557  {
558  arp_int->arp_entries = hash_create (0, sizeof (u32));
559  }
560 
561  hash_set (arp_int->arp_entries, a->ip4.as_u32, e - am->ip4_entry_pool);
562 
563  e->sw_if_index = sw_if_index;
564  e->ip4_address = a->ip4;
567  a->ethernet, sizeof (e->ethernet_address));
568 
569  if (!is_no_fib_entry)
570  {
571  fib_prefix_t pfx = {
572  .fp_len = 32,
573  .fp_proto = FIB_PROTOCOL_IP4,
574  .fp_addr.ip4 = a->ip4,
575  };
576  u32 fib_index;
577 
578  fib_index =
580  e->fib_entry_index =
584  e->sw_if_index, ~0, 1, NULL,
587  }
588  }
589  else
590  {
591  /*
592  * prevent a DoS attack from the data-plane that
593  * spams us with no-op updates to the MAC address
594  */
595  if (0 == memcmp (e->ethernet_address,
596  a->ethernet, sizeof (e->ethernet_address)))
597  return -1;
598 
599  /* Update time stamp and ethernet address. */
600  clib_memcpy (e->ethernet_address, a->ethernet,
601  sizeof (e->ethernet_address));
602  }
603 
605  if (is_static)
607  else
609 
610  adj_nbr_walk_nh4 (sw_if_index, &e->ip4_address, arp_mk_complete_walk, e);
611 
612  /* Customer(s) waiting for this address to be resolved? */
613  p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
614  if (p)
615  {
616  u32 next_index;
617  next_index = p[0];
618 
619  while (next_index != (u32) ~ 0)
620  {
621  pr = pool_elt_at_index (am->pending_resolutions, next_index);
623  pr->type_opaque, pr->data);
624  next_index = pr->next_index;
625  pool_put (am->pending_resolutions, pr);
626  }
627 
628  hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
629  }
630 
631  /* Customer(s) requesting ARP event for this address? */
632  p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
633  if (p)
634  {
635  u32 next_index;
636  next_index = p[0];
637 
638  while (next_index != (u32) ~ 0)
639  {
640  int (*fp) (u32, u8 *, u32, u32);
641  int rv = 1;
642  mc = pool_elt_at_index (am->mac_changes, next_index);
643  fp = mc->data_callback;
644 
645  /* Call the user's data callback, return 1 to suppress dup events */
646  if (fp)
647  rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
648 
649  /*
650  * Signal the resolver process, as long as the user
651  * says they want to be notified
652  */
653  if (rv == 0)
655  mc->type_opaque, mc->data);
656  next_index = mc->next_index;
657  }
658  }
659 
660  return 0;
661 }
662 
663 void
665  void *address_arg,
666  uword node_index,
667  uword type_opaque, uword data)
668 {
670  ip4_address_t *address = address_arg;
671  uword *p;
673 
674  pool_get (am->pending_resolutions, pr);
675 
676  pr->next_index = ~0;
677  pr->node_index = node_index;
678  pr->type_opaque = type_opaque;
679  pr->data = data;
680  pr->data_callback = 0;
681 
682  p = hash_get (am->pending_resolutions_by_address, address->as_u32);
683  if (p)
684  {
685  /* Insert new resolution at the head of the list */
686  pr->next_index = p[0];
688  }
689 
691  pr - am->pending_resolutions);
692 }
693 
694 int
696  void *data_callback,
697  u32 pid,
698  void *address_arg,
699  uword node_index,
700  uword type_opaque, uword data, int is_add)
701 {
703  ip4_address_t *address = address_arg;
704  uword *p;
706  void (*fp) (u32, u8 *) = data_callback;
707 
708  if (is_add)
709  {
710  pool_get (am->mac_changes, mc);
711 
712  mc->next_index = ~0;
713  mc->node_index = node_index;
714  mc->type_opaque = type_opaque;
715  mc->data = data;
716  mc->data_callback = data_callback;
717  mc->pid = pid;
718 
719  p = hash_get (am->mac_changes_by_address, address->as_u32);
720  if (p)
721  {
722  /* Insert new resolution at the head of the list */
723  mc->next_index = p[0];
724  hash_unset (am->mac_changes_by_address, address->as_u32);
725  }
726 
727  hash_set (am->mac_changes_by_address, address->as_u32,
728  mc - am->mac_changes);
729  return 0;
730  }
731  else
732  {
733  u32 index;
734  pending_resolution_t *mc_last = 0;
735 
736  p = hash_get (am->mac_changes_by_address, address->as_u32);
737  if (p == 0)
738  return VNET_API_ERROR_NO_SUCH_ENTRY;
739 
740  index = p[0];
741 
742  while (index != (u32) ~ 0)
743  {
744  mc = pool_elt_at_index (am->mac_changes, index);
745  if (mc->node_index == node_index &&
746  mc->type_opaque == type_opaque && mc->pid == pid)
747  {
748  /* Clients may need to clean up pool entries, too */
749  if (fp)
750  (*fp) (mc->data, 0 /* no new mac addrs */ );
751  if (index == p[0])
752  {
753  hash_unset (am->mac_changes_by_address, address->as_u32);
754  if (mc->next_index != ~0)
755  hash_set (am->mac_changes_by_address, address->as_u32,
756  mc->next_index);
757  pool_put (am->mac_changes, mc);
758  return 0;
759  }
760  else
761  {
762  ASSERT (mc_last);
763  mc_last->next_index = mc->next_index;
764  pool_put (am->mac_changes, mc);
765  return 0;
766  }
767  }
768  mc_last = mc;
769  index = mc->next_index;
770  }
771 
772  return VNET_API_ERROR_NO_SUCH_ENTRY;
773  }
774 }
775 
776 /* Either we drop the packet or we send a reply to the sender. */
777 typedef enum
778 {
783 
784 #define foreach_ethernet_arp_error \
785  _ (replies_sent, "ARP replies sent") \
786  _ (l2_type_not_ethernet, "L2 type not ethernet") \
787  _ (l3_type_not_ip4, "L3 type not IP4") \
788  _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
789  _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
790  _ (l3_src_address_is_local, "IP4 source address matches local interface") \
791  _ (l3_src_address_learned, "ARP request IP4 source address learned") \
792  _ (replies_received, "ARP replies received") \
793  _ (opcode_not_request, "ARP opcode not request") \
794  _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
795  _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
796  _ (missing_interface_address, "ARP missing interface address") \
797  _ (gratuitous_arp, "ARP probe or announcement dropped") \
798  _ (interface_no_table, "Interface is not mapped to an IP table") \
799  _ (interface_not_ip_enabled, "Interface is not IP enabled") \
800 
801 typedef enum
802 {
803 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
805 #undef _
808 
809 
810 static void
812 {
815  vnet_main_t *vnm = vnet_get_main ();
816  ethernet_arp_ip4_over_ethernet_address_t delme;
817  u32 index;
818 
820  am->arp_delete_rotor = index;
821 
822  /* Try again from elt 0, could happen if an intfc goes down */
823  if (index == ~0)
824  {
826  am->arp_delete_rotor = index;
827  }
828 
829  /* Nothing left in the pool */
830  if (index == ~0)
831  return;
832 
833  e = pool_elt_at_index (am->ip4_entry_pool, index);
834 
835  clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
836  delme.ip4.as_u32 = e->ip4_address.as_u32;
837 
839 }
840 
841 static int
843  u32 pi0,
844  ethernet_header_t * eth0,
845  u32 input_sw_if_index, u32 conn_sw_if_index)
846 {
848  vnet_main_t *vnm = vnet_get_main ();
852  u32 *buffers = 0;
853  vlib_buffer_t *b0;
854  int i;
855  u8 dst_mac_address[6];
856  i16 header_size;
857  ethernet_arp_header_t *arp0;
858 
859  /* verify that the input interface is unnumbered to the connected.
860  * the connected interface is the interface on which the subnet is
861  * configured */
862  si = &vim->sw_interfaces[input_sw_if_index];
863 
865  (si->unnumbered_sw_if_index == conn_sw_if_index)))
866  {
867  /* the input interface is not unnumbered to the interface on which
868  * the sub-net is configured that covers the ARP request.
869  * So this is not the case for unnumbered.. */
870  return 0;
871  }
872 
873  /* Save the dst mac address */
874  clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
875 
876  vec_insert (buffers, 1, 0);
877  buffers[0] = pi0;
878 
879  for (i = 0; i < vec_len (buffers); i++)
880  {
881  b0 = vlib_get_buffer (vm, buffers[i]);
882  arp0 = vlib_buffer_get_current (b0);
883 
884  hi = vnet_get_sup_hw_interface (vnm, input_sw_if_index);
885  si = vnet_get_sw_interface (vnm, input_sw_if_index);
886 
887  /* For decoration, most likely */
888  vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
889 
890  /* Fix ARP pkt src address */
891  clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
892 
893  /* Build L2 encaps for this swif */
894  header_size = sizeof (ethernet_header_t);
895  if (si->sub.eth.flags.one_tag)
896  header_size += 4;
897  else if (si->sub.eth.flags.two_tags)
898  header_size += 8;
899 
900  vlib_buffer_advance (b0, -header_size);
901  eth0 = vlib_buffer_get_current (b0);
902 
903  if (si->sub.eth.flags.one_tag)
904  {
905  ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
906 
907  eth0->type = si->sub.eth.flags.dot1ad ?
908  clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
909  clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
910  outer->priority_cfi_and_id =
911  clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
912  outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
913 
914  }
915  else if (si->sub.eth.flags.two_tags)
916  {
917  ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
918  ethernet_vlan_header_t *inner = (void *) (outer + 1);
919 
920  eth0->type = si->sub.eth.flags.dot1ad ?
921  clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
922  clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
923  outer->priority_cfi_and_id =
924  clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
925  outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
926  inner->priority_cfi_and_id =
927  clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
928  inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
929 
930  }
931  else
932  {
933  eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
934  }
935 
936  /* Restore the original dst address, set src address */
937  clib_memcpy (eth0->dst_address, dst_mac_address,
938  sizeof (eth0->dst_address));
939  clib_memcpy (eth0->src_address, hi->hw_address,
940  sizeof (eth0->src_address));
941 
942  /* Transmit replicas */
943  if (i > 0)
944  {
945  vlib_frame_t *f =
947  u32 *to_next = vlib_frame_vector_args (f);
948  to_next[0] = buffers[i];
949  f->n_vectors = 1;
951  }
952  }
953 
954  /* The regular path outputs the original pkt.. */
955  vnet_buffer (p0)->sw_if_index[VLIB_TX] = input_sw_if_index;
956 
957  vec_free (buffers);
958 
959  return !0;
960 }
961 
962 static u32
964  ethernet_arp_main_t * am, u32 sw_if_index, void *addr)
965 {
966  if (am->limit_arp_cache_size &&
969 
970  vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index, addr, 0, 0);
971  return (ETHERNET_ARP_ERROR_l3_src_address_learned);
972 }
973 
974 static uword
976 {
978  vnet_main_t *vnm = vnet_get_main ();
979  ip4_main_t *im4 = &ip4_main;
980  u32 n_left_from, next_index, *from, *to_next;
981  u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
982 
983  from = vlib_frame_vector_args (frame);
984  n_left_from = frame->n_vectors;
985  next_index = node->cached_next_index;
986 
987  if (node->flags & VLIB_NODE_FLAG_TRACE)
988  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
989  /* stride */ 1,
990  sizeof (ethernet_arp_input_trace_t));
991 
992  while (n_left_from > 0)
993  {
994  u32 n_left_to_next;
995 
996  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
997 
998  while (n_left_from > 0 && n_left_to_next > 0)
999  {
1000  vlib_buffer_t *p0;
1001  vnet_hw_interface_t *hw_if0;
1002  ethernet_arp_header_t *arp0;
1003  ethernet_header_t *eth0;
1004  ip4_address_t *if_addr0, proxy_src;
1005  u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
1006  u8 is_request0, dst_is_local0, is_unnum0;
1008  fib_node_index_t dst_fei, src_fei;
1009  fib_prefix_t pfx0;
1010  fib_entry_flag_t src_flags, dst_flags;
1011 
1012  pi0 = from[0];
1013  to_next[0] = pi0;
1014  from += 1;
1015  to_next += 1;
1016  n_left_from -= 1;
1017  n_left_to_next -= 1;
1018  pa = 0;
1019 
1020  p0 = vlib_get_buffer (vm, pi0);
1021  arp0 = vlib_buffer_get_current (p0);
1022 
1023  is_request0 = arp0->opcode
1024  == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
1025 
1026  error0 = ETHERNET_ARP_ERROR_replies_sent;
1027 
1028  error0 =
1029  (arp0->l2_type !=
1030  clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1031  ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1032  error0 =
1033  (arp0->l3_type !=
1034  clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
1035  ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
1036 
1037  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1038 
1039  /* not playing the ARP game if the interface is not IPv4 enabled */
1040  error0 =
1041  (im4->ip_enabled_by_sw_if_index[sw_if_index0] == 0 ?
1042  ETHERNET_ARP_ERROR_interface_not_ip_enabled : error0);
1043 
1044  if (error0)
1045  goto drop2;
1046 
1047  /* Check that IP address is local and matches incoming interface. */
1048  fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1049  if (~0 == fib_index0)
1050  {
1051  error0 = ETHERNET_ARP_ERROR_interface_no_table;
1052  goto drop2;
1053 
1054  }
1055  dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1056  &arp0->ip4_over_ethernet[1].ip4,
1057  32);
1058  dst_flags = fib_entry_get_flags (dst_fei);
1059 
1060  src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1061  &arp0->ip4_over_ethernet[0].ip4,
1062  32);
1063  src_flags = fib_entry_get_flags (src_fei);
1064 
1065  conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
1066 
1067  if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
1068  {
1069  error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1070  goto drop1;
1071  }
1072 
1073  /* Honor unnumbered interface, if any */
1074  is_unnum0 = sw_if_index0 != conn_sw_if_index0;
1075 
1076  /* Source must also be local to subnet of matching interface address. */
1077  if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
1078  (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
1079  {
1080  /*
1081  * The packet was sent from an address that is not connected nor attached
1082  * i.e. it is not from an address that is covered by a link's sub-net,
1083  * nor is it a already learned host resp.
1084  */
1085  error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
1086  goto drop2;
1087  }
1088  if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1089  {
1090  /*
1091  * The interface the ARP was received on is not the interface
1092  * on which the covering prefix is configured. Maybe this is a case
1093  * for unnumbered.
1094  */
1095  is_unnum0 = 1;
1096  }
1097 
1098  /* Reject requests/replies with our local interface address. */
1099  if (FIB_ENTRY_FLAG_LOCAL & src_flags)
1100  {
1101  error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1102  goto drop2;
1103  }
1104 
1105  dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1106  fib_entry_get_prefix (dst_fei, &pfx0);
1107  if_addr0 = &pfx0.fp_addr.ip4;
1108 
1109  /* Fill in ethernet header. */
1110  eth0 = ethernet_buffer_get_header (p0);
1111 
1112  /* Trash ARP packets whose ARP-level source addresses do not
1113  match their L2-frame-level source addresses */
1114  if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1115  sizeof (eth0->src_address)))
1116  {
1117  error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1118  goto drop2;
1119  }
1120 
1121  /* Learn or update sender's mapping only for replies to addresses
1122  * that are local to the subnet */
1123  if (arp0->opcode ==
1124  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) &&
1125  dst_is_local0)
1126  {
1127  error0 = arp_learn (vnm, am, sw_if_index0,
1128  &arp0->ip4_over_ethernet[0]);
1129  goto drop1;
1130  }
1131 
1132  /* Send a reply. */
1133  send_reply:
1134  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1135  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1136 
1137  /* Send reply back through input interface */
1138  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1139  next0 = ARP_INPUT_NEXT_REPLY_TX;
1140 
1141  arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1142 
1143  arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1144 
1145  clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1146  hw_if0->hw_address, 6);
1147  clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1148  if_addr0->data_u32;
1149 
1150  /* Hardware must be ethernet-like. */
1151  ASSERT (vec_len (hw_if0->hw_address) == 6);
1152 
1153  clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1154  clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1155 
1156  /* Figure out how much to rewind current data from adjacency. */
1157  /* get the adj from the destination's covering connected */
1158  if (NULL == pa)
1159  {
1160  if (is_unnum0)
1161  {
1162  if (!arp_unnumbered (p0, pi0, eth0,
1163  sw_if_index0, conn_sw_if_index0))
1164  goto drop2;
1165  }
1166  else
1167  {
1168  ip_adjacency_t *adj0 = NULL;
1169  adj_index_t ai;
1170 
1171  if (FIB_ENTRY_FLAG_ATTACHED & src_flags)
1172  {
1173  /*
1174  * If the source is attached use the adj from that source.
1175  */
1176  ai = fib_entry_get_adj (src_fei);
1177  if (ADJ_INDEX_INVALID != ai)
1178  {
1179  adj0 = adj_get (ai);
1180  }
1181  }
1182  else
1183  {
1184  /*
1185  * Get the glean adj from the cover. This is presumably interface
1186  * sourced, and therefre needs to be a glean adj.
1187  */
1190  (ip4_fib_get (fib_index0),
1191  &arp0->ip4_over_ethernet[1].ip4, 31),
1193 
1194  if (ADJ_INDEX_INVALID != ai)
1195  {
1196  adj0 = adj_get (ai);
1197 
1199  {
1200  adj0 = NULL;
1201  }
1202  }
1203  }
1204  if (NULL != adj0)
1205  {
1206  vlib_buffer_advance (p0,
1207  -adj0->rewrite_header.data_bytes);
1208  }
1209  else
1210  {
1211  error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1212  goto drop2;
1213  }
1214  }
1215  }
1216 
1217  /* We are going to reply to this request, so learn the sender */
1218  error0 = arp_learn (vnm, am, sw_if_index0,
1219  &arp0->ip4_over_ethernet[1]);
1220 
1221  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1222  n_left_to_next, pi0, next0);
1223 
1224  n_replies_sent += 1;
1225  continue;
1226 
1227  drop1:
1228  if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1229  (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1230  arp0->ip4_over_ethernet[1].ip4.as_u32))
1231  {
1232  error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1233  goto drop2;
1234  }
1235  /* See if proxy arp is configured for the address */
1236  if (is_request0)
1237  {
1238  vnet_sw_interface_t *si;
1239  u32 this_addr = clib_net_to_host_u32
1240  (arp0->ip4_over_ethernet[1].ip4.as_u32);
1241  u32 fib_index0;
1242 
1243  si = vnet_get_sw_interface (vnm, sw_if_index0);
1244 
1246  goto drop2;
1247 
1248  fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1249  sw_if_index0);
1250 
1251  vec_foreach (pa, am->proxy_arps)
1252  {
1253  u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1254  u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1255 
1256  /* an ARP request hit in the proxy-arp table? */
1257  if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1258  (fib_index0 == pa->fib_index))
1259  {
1260  eth0 = ethernet_buffer_get_header (p0);
1261  proxy_src.as_u32 =
1262  arp0->ip4_over_ethernet[1].ip4.data_u32;
1263 
1264  /*
1265  * Rewind buffer, direct code above not to
1266  * think too hard about it.
1267  */
1268  if_addr0 = &proxy_src;
1269  is_unnum0 = 0;
1270  i32 ethernet_start =
1271  vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1272  i32 rewind = p0->current_data - ethernet_start;
1273  vlib_buffer_advance (p0, -rewind);
1274  n_proxy_arp_replies_sent++;
1275  goto send_reply;
1276  }
1277  }
1278  }
1279 
1280  drop2:
1281 
1282  next0 = ARP_INPUT_NEXT_DROP;
1283  p0->error = node->errors[error0];
1284 
1285  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1286  n_left_to_next, pi0, next0);
1287  }
1288 
1289  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1290  }
1291 
1292  vlib_error_count (vm, node->node_index,
1293  ETHERNET_ARP_ERROR_replies_sent,
1294  n_replies_sent - n_proxy_arp_replies_sent);
1295 
1296  vlib_error_count (vm, node->node_index,
1297  ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1298  n_proxy_arp_replies_sent);
1299  return frame->n_vectors;
1300 }
1301 
1302 static char *ethernet_arp_error_strings[] = {
1303 #define _(sym,string) string,
1305 #undef _
1306 };
1307 
1308 /* *INDENT-OFF* */
1310 {
1311  .function = arp_input,
1312  .name = "arp-input",
1313  .vector_size = sizeof (u32),
1314  .n_errors = ETHERNET_ARP_N_ERROR,
1315  .error_strings = ethernet_arp_error_strings,
1316  .n_next_nodes = ARP_INPUT_N_NEXT,
1317  .next_nodes = {
1318  [ARP_INPUT_NEXT_DROP] = "error-drop",
1319  [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1320  },
1321  .format_buffer = format_ethernet_arp_header,
1322  .format_trace = format_ethernet_arp_input_trace,
1323 };
1324 /* *INDENT-ON* */
1325 
1326 static int
1327 ip4_arp_entry_sort (void *a1, void *a2)
1328 {
1329  ethernet_arp_ip4_entry_t *e1 = a1;
1330  ethernet_arp_ip4_entry_t *e2 = a2;
1331 
1332  int cmp;
1333  vnet_main_t *vnm = vnet_get_main ();
1334 
1335  cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1336  if (!cmp)
1337  cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1338  return cmp;
1339 }
1340 
1343 {
1345  ethernet_arp_ip4_entry_t *n, *ns = 0;
1346 
1347  /* *INDENT-OFF* */
1348  pool_foreach (n, am->ip4_entry_pool, ({
1349  if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1350  continue;
1351  vec_add1 (ns, n[0]);
1352  }));
1353  /* *INDENT-ON* */
1354 
1355  if (ns)
1357  return ns;
1358 }
1359 
1360 static clib_error_t *
1362  unformat_input_t * input, vlib_cli_command_t * cmd)
1363 {
1364  vnet_main_t *vnm = vnet_get_main ();
1366  ethernet_arp_ip4_entry_t *e, *es;
1368  clib_error_t *error = 0;
1369  u32 sw_if_index;
1370 
1371  /* Filter entries by interface if given. */
1372  sw_if_index = ~0;
1373  (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1374 
1375  es = ip4_neighbor_entries (sw_if_index);
1376  if (es)
1377  {
1378  vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1379  vec_foreach (e, es)
1380  {
1381  vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1382  }
1383  vec_free (es);
1384  }
1385 
1386  if (vec_len (am->proxy_arps))
1387  {
1388  vlib_cli_output (vm, "Proxy arps enabled for:");
1389  vec_foreach (pa, am->proxy_arps)
1390  {
1391  vlib_cli_output (vm, "Fib_index %d %U - %U ",
1392  pa->fib_index,
1394  format_ip4_address, &pa->hi_addr);
1395  }
1396  }
1397 
1398  return error;
1399 }
1400 
1401 /*?
1402  * Display all the IPv4 ARP entries.
1403  *
1404  * @cliexpar
1405  * Example of how to display the IPv4 ARP table:
1406  * @cliexstart{show ip arp}
1407  * Time FIB IP4 Flags Ethernet Interface
1408  * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1409  * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1410  * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1411  * Proxy arps enabled for:
1412  * Fib_index 0 6.0.0.1 - 6.0.0.11
1413  * @cliexend
1414  ?*/
1415 /* *INDENT-OFF* */
1416 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1417  .path = "show ip arp",
1418  .function = show_ip4_arp,
1419  .short_help = "show ip arp",
1420 };
1421 /* *INDENT-ON* */
1422 
1423 typedef struct
1424 {
1425  pg_edit_t l2_type, l3_type;
1426  pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1428  struct
1429  {
1432  } ip4_over_ethernet[2];
1434 
1435 static inline void
1437 {
1438  /* Initialize fields that are not bit fields in the IP header. */
1439 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1440  _(l2_type);
1441  _(l3_type);
1442  _(n_l2_address_bytes);
1443  _(n_l3_address_bytes);
1444  _(opcode);
1445  _(ip4_over_ethernet[0].ethernet);
1446  _(ip4_over_ethernet[0].ip4);
1447  _(ip4_over_ethernet[1].ethernet);
1448  _(ip4_over_ethernet[1].ip4);
1449 #undef _
1450 }
1451 
1452 uword
1453 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1454 {
1455  pg_stream_t *s = va_arg (*args, pg_stream_t *);
1457  u32 group_index;
1458 
1459  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1460  &group_index);
1462 
1463  /* Defaults. */
1464  pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1465  pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1468 
1469  if (!unformat (input, "%U: %U/%U -> %U/%U",
1480  {
1481  /* Free up any edits we may have added. */
1482  pg_free_edit_group (s);
1483  return 0;
1484  }
1485  return 1;
1486 }
1487 
1488 clib_error_t *
1490 {
1492 
1493  am->limit_arp_cache_size = arp_limit;
1494  return 0;
1495 }
1496 
1497 /**
1498  * @brief Control Plane hook to remove an ARP entry
1499  */
1500 int
1502  u32 sw_if_index, void *a_arg)
1503 {
1504  ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1506 
1507  args.sw_if_index = sw_if_index;
1509  clib_memcpy (&args.a, a, sizeof (*a));
1510 
1512  (u8 *) & args, sizeof (args));
1513  return 0;
1514 }
1515 
1516 /**
1517  * @brief Internally generated event to flush the ARP cache on an
1518  * interface state change event.
1519  * A flush will remove dynamic ARP entries, and for statics remove the MAC
1520  * address from the corresponding adjacencies.
1521  */
1522 static int
1524  u32 sw_if_index, void *a_arg)
1525 {
1526  ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1528 
1529  args.sw_if_index = sw_if_index;
1531  clib_memcpy (&args.a, a, sizeof (*a));
1532 
1534  (u8 *) & args, sizeof (args));
1535  return 0;
1536 }
1537 
1538 /**
1539  * @brief Internally generated event to populate the ARP cache on an
1540  * interface state change event.
1541  * For static entries this will re-source the adjacencies.
1542  *
1543  * @param sw_if_index The interface on which the ARP entires are acted
1544  */
1545 static int
1547  u32 sw_if_index, void *a_arg)
1548 {
1549  ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1551 
1552  args.sw_if_index = sw_if_index;
1554  clib_memcpy (&args.a, a, sizeof (*a));
1555 
1557  (u8 *) & args, sizeof (args));
1558  return 0;
1559 }
1560 
1561 /*
1562  * arp_add_del_interface_address
1563  *
1564  * callback when an interface address is added or deleted
1565  */
1566 static void
1568  uword opaque,
1569  u32 sw_if_index,
1570  ip4_address_t * address,
1571  u32 address_length,
1572  u32 if_address_index, u32 is_del)
1573 {
1574  /*
1575  * Flush the ARP cache of all entries covered by the address
1576  * that is being removed.
1577  */
1580 
1581  if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
1582  return;
1583 
1584  if (is_del)
1585  {
1587  u32 i, *to_delete = 0;
1588  hash_pair_t *pair;
1589 
1590  eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1591 
1592  /* *INDENT-OFF* */
1593  hash_foreach_pair (pair, eai->arp_entries,
1594  ({
1595  e = pool_elt_at_index(am->ip4_entry_pool,
1596  pair->value[0]);
1597  if (ip4_destination_matches_route (im, &e->ip4_address,
1598  address, address_length))
1599  {
1600  vec_add1 (to_delete, e - am->ip4_entry_pool);
1601  }
1602  }));
1603  /* *INDENT-ON* */
1604 
1605  for (i = 0; i < vec_len (to_delete); i++)
1606  {
1607  ethernet_arp_ip4_over_ethernet_address_t delme;
1608  e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1609 
1610  clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1611  delme.ip4.as_u32 = e->ip4_address.as_u32;
1612 
1614  e->sw_if_index, &delme);
1615  }
1616 
1617  vec_free (to_delete);
1618  }
1619 }
1620 
1621 static clib_error_t *
1623 {
1625  ip4_main_t *im = &ip4_main;
1626  clib_error_t *error;
1627  pg_node_t *pn;
1628 
1629  if ((error = vlib_call_init_function (vm, ethernet_init)))
1630  return error;
1631 
1632  ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1633 
1634  pn = pg_get_node (arp_input_node.index);
1636 
1637  am->opcode_by_name = hash_create_string (0, sizeof (uword));
1638 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1640 #undef _
1641 
1642  /* $$$ configurable */
1643  am->limit_arp_cache_size = 50000;
1644 
1645  am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1646  am->mac_changes_by_address = hash_create (0, sizeof (uword));
1647 
1648  /* don't trace ARP error packets */
1649  {
1650  vlib_node_runtime_t *rt =
1652 
1653 #define _(a,b) \
1654  vnet_pcap_drop_trace_filter_add_del \
1655  (rt->errors[ETHERNET_ARP_ERROR_##a], \
1656  1 /* is_add */);
1658 #undef _
1659  }
1660 
1663  cb.function_opaque = 0;
1665 
1666  return 0;
1667 }
1668 
1670 
1671 static void
1673 {
1675 
1679  pool_put (am->ip4_entry_pool, e);
1680 }
1681 
1682 static inline int
1685  * args)
1686 {
1690 
1691  eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1692 
1693  e = arp_entry_find (eai, &args->a.ip4);
1694 
1695  if (NULL != e)
1696  {
1697  arp_entry_free (eai, e);
1698 
1701  }
1702 
1703  return 0;
1704 }
1705 
1706 static int
1709  * args)
1710 {
1714 
1715  eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1716 
1717  e = arp_entry_find (eai, &args->a.ip4);
1718 
1719  if (NULL != e)
1720  {
1723 
1724  /*
1725  * The difference between flush and unset, is that an unset
1726  * means delete for static and dynamic entries. A flush
1727  * means delete only for dynamic. Flushing is what the DP
1728  * does in response to interface events. unset is only done
1729  * by the control plane.
1730  */
1732  {
1733  arp_entry_free (eai, e);
1734  }
1735  }
1736  return (0);
1737 }
1738 
1739 static int
1742  * args)
1743 {
1747 
1748  eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1749 
1750  e = arp_entry_find (eai, &args->a.ip4);
1751 
1752  if (NULL != e)
1753  {
1756  }
1757  return (0);
1758 }
1759 
1760 static void
1762  * a)
1763 {
1765  ASSERT (os_get_cpu_number () == 0);
1766 
1769  else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1771  else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1773  else
1775 }
1776 
1777 /**
1778  * @brief Invoked when the interface's admin state changes
1779  */
1780 static clib_error_t *
1782  u32 sw_if_index, u32 flags)
1783 {
1786  u32 i, *to_delete = 0;
1787 
1788  /* *INDENT-OFF* */
1789  pool_foreach (e, am->ip4_entry_pool,
1790  ({
1791  if (e->sw_if_index == sw_if_index)
1792  vec_add1 (to_delete,
1793  e - am->ip4_entry_pool);
1794  }));
1795  /* *INDENT-ON* */
1796 
1797  for (i = 0; i < vec_len (to_delete); i++)
1798  {
1799  ethernet_arp_ip4_over_ethernet_address_t delme;
1800  e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1801 
1802  clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1803  delme.ip4.as_u32 = e->ip4_address.as_u32;
1804 
1805  if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1806  {
1808  }
1809  else
1810  {
1812  }
1813 
1814  }
1815  vec_free (to_delete);
1816 
1817  return 0;
1818 }
1819 
1821 
1822 static void
1823 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1824 {
1825  u8 old;
1826  int i;
1827 
1828  for (i = 3; i >= 0; i--)
1829  {
1830  old = a->ip4.as_u8[i];
1831  a->ip4.as_u8[i] += 1;
1832  if (old < a->ip4.as_u8[i])
1833  break;
1834  }
1835 
1836  for (i = 5; i >= 0; i--)
1837  {
1838  old = a->ethernet[i];
1839  a->ethernet[i] += 1;
1840  if (old < a->ethernet[i])
1841  break;
1842  }
1843 }
1844 
1845 int
1847  u32 sw_if_index, void *a_arg,
1848  int is_static, int is_no_fib_entry)
1849 {
1850  ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1852 
1853  args.sw_if_index = sw_if_index;
1854  args.is_static = is_static;
1855  args.is_no_fib_entry = is_no_fib_entry;
1856  args.flags = 0;
1857  clib_memcpy (&args.a, a, sizeof (*a));
1858 
1860  (u8 *) & args, sizeof (args));
1861  return 0;
1862 }
1863 
1864 int
1866  ip4_address_t * hi_addr, u32 fib_index, int is_del)
1867 {
1870  u32 found_at_index = ~0;
1871 
1872  vec_foreach (pa, am->proxy_arps)
1873  {
1874  if (pa->lo_addr == lo_addr->as_u32
1875  && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1876  {
1877  found_at_index = pa - am->proxy_arps;
1878  break;
1879  }
1880  }
1881 
1882  if (found_at_index != ~0)
1883  {
1884  /* Delete, otherwise it's already in the table */
1885  if (is_del)
1886  vec_delete (am->proxy_arps, 1, found_at_index);
1887  return 0;
1888  }
1889  /* delete, no such entry */
1890  if (is_del)
1891  return VNET_API_ERROR_NO_SUCH_ENTRY;
1892 
1893  /* add, not in table */
1894  vec_add2 (am->proxy_arps, pa, 1);
1895  pa->lo_addr = lo_addr->as_u32;
1896  pa->hi_addr = hi_addr->as_u32;
1897  pa->fib_index = fib_index;
1898  return 0;
1899 }
1900 
1901 /*
1902  * Remove any proxy arp entries asdociated with the
1903  * specificed fib.
1904  */
1905 int
1907 {
1908  ip4_main_t *im = &ip4_main;
1911  u32 *entries_to_delete = 0;
1912  u32 fib_index;
1913  uword *p;
1914  int i;
1915 
1916  p = hash_get (im->fib_index_by_table_id, fib_id);
1917  if (!p)
1918  return VNET_API_ERROR_NO_SUCH_ENTRY;
1919  fib_index = p[0];
1920 
1921  vec_foreach (pa, am->proxy_arps)
1922  {
1923  if (pa->fib_index == fib_index)
1924  {
1925  vec_add1 (entries_to_delete, pa - am->proxy_arps);
1926  }
1927  }
1928 
1929  for (i = 0; i < vec_len (entries_to_delete); i++)
1930  {
1931  vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1932  }
1933 
1934  vec_free (entries_to_delete);
1935 
1936  return 0;
1937 }
1938 
1939 static clib_error_t *
1941  unformat_input_t * input, vlib_cli_command_t * cmd)
1942 {
1943  vnet_main_t *vnm = vnet_get_main ();
1944  u32 sw_if_index;
1945  ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1946  int addr_valid = 0;
1947  int is_del = 0;
1948  int count = 1;
1949  u32 fib_index = 0;
1950  u32 fib_id;
1951  int is_static = 0;
1952  int is_no_fib_entry = 0;
1953  int is_proxy = 0;
1954 
1955  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1956  {
1957  /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1958  if (unformat (input, "%U %U %U",
1959  unformat_vnet_sw_interface, vnm, &sw_if_index,
1960  unformat_ip4_address, &addr.ip4,
1961  unformat_ethernet_address, &addr.ethernet))
1962  addr_valid = 1;
1963 
1964  else if (unformat (input, "delete") || unformat (input, "del"))
1965  is_del = 1;
1966 
1967  else if (unformat (input, "static"))
1968  is_static = 1;
1969 
1970  else if (unformat (input, "no-fib-entry"))
1971  is_no_fib_entry = 1;
1972 
1973  else if (unformat (input, "count %d", &count))
1974  ;
1975 
1976  else if (unformat (input, "fib-id %d", &fib_id))
1977  {
1978  ip4_main_t *im = &ip4_main;
1979  uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1980  if (!p)
1981  return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1982  fib_index = p[0];
1983  }
1984 
1985  else if (unformat (input, "proxy %U - %U",
1986  unformat_ip4_address, &lo_addr.ip4,
1987  unformat_ip4_address, &hi_addr.ip4))
1988  is_proxy = 1;
1989  else
1990  break;
1991  }
1992 
1993  if (is_proxy)
1994  {
1995  (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1996  fib_index, is_del);
1997  return 0;
1998  }
1999 
2000  if (addr_valid)
2001  {
2002  int i;
2003 
2004  for (i = 0; i < count; i++)
2005  {
2006  if (is_del == 0)
2007  {
2008  uword event_type, *event_data = 0;
2009 
2010  /* Park the debug CLI until the arp entry is installed */
2012  (vnm, &addr.ip4, vlib_current_process (vm),
2013  1 /* type */ , 0 /* data */ );
2014 
2016  (vnm, sw_if_index, &addr, is_static, is_no_fib_entry);
2017 
2019  event_type = vlib_process_get_events (vm, &event_data);
2020  vec_reset_length (event_data);
2021  if (event_type != 1)
2022  clib_warning ("event type %d unexpected", event_type);
2023  }
2024  else
2025  vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
2026 
2028  }
2029  }
2030  else
2031  {
2032  return clib_error_return (0, "unknown input `%U'",
2033  format_unformat_error, input);
2034  }
2035 
2036  return 0;
2037 }
2038 
2039 /* *INDENT-OFF* */
2040 /*?
2041  * Add or delete IPv4 ARP cache entries.
2042  *
2043  * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
2044  * 'count <number>', 'interface ip4_addr mac_addr') can be added in
2045  * any order and combination.
2046  *
2047  * @cliexpar
2048  * @parblock
2049  * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
2050  * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
2051  * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2052  * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
2053  *
2054  * To add or delete an IPv4 ARP cache entry to or from a specific fib
2055  * table:
2056  * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2057  * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2058  *
2059  * Add or delete IPv4 static ARP cache entries as follows:
2060  * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2061  * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2062  *
2063  * For testing / debugging purposes, the 'set ip arp' command can add or
2064  * delete multiple entries. Supply the 'count N' parameter:
2065  * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2066  * @endparblock
2067  ?*/
2068 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2069  .path = "set ip arp",
2070  .short_help =
2071  "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2072  .function = ip_arp_add_del_command_fn,
2073 };
2074 /* *INDENT-ON* */
2075 
2076 static clib_error_t *
2079  input, vlib_cli_command_t * cmd)
2080 {
2081  vnet_main_t *vnm = vnet_get_main ();
2082  u32 sw_if_index;
2083  vnet_sw_interface_t *si;
2084  int enable = 0;
2085  int intfc_set = 0;
2086 
2087  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2088  {
2089  if (unformat (input, "%U", unformat_vnet_sw_interface,
2090  vnm, &sw_if_index))
2091  intfc_set = 1;
2092  else if (unformat (input, "enable") || unformat (input, "on"))
2093  enable = 1;
2094  else if (unformat (input, "disable") || unformat (input, "off"))
2095  enable = 0;
2096  else
2097  break;
2098  }
2099 
2100  if (intfc_set == 0)
2101  return clib_error_return (0, "unknown input '%U'",
2102  format_unformat_error, input);
2103 
2104  si = vnet_get_sw_interface (vnm, sw_if_index);
2105  ASSERT (si);
2106  if (enable)
2108  else
2110 
2111  return 0;
2112 }
2113 
2114 /* *INDENT-OFF* */
2115 /*?
2116  * Enable proxy-arp on an interface. The vpp stack will answer ARP
2117  * requests for the indicated address range. Multiple proxy-arp
2118  * ranges may be provisioned.
2119  *
2120  * @note Proxy ARP as a technology is infamous for blackholing traffic.
2121  * Also, the underlying implementation has not been performance-tuned.
2122  * Avoid creating an unnecessarily large set of ranges.
2123  *
2124  * @cliexpar
2125  * To enable proxy arp on a range of addresses, use:
2126  * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2127  * Append 'del' to delete a range of proxy ARP addresses:
2128  * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2129  * You must then specifically enable proxy arp on individual interfaces:
2130  * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2131  * To disable proxy arp on an individual interface:
2132  * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2133  ?*/
2134 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2135  .path = "set interface proxy-arp",
2136  .short_help =
2137  "set interface proxy-arp <intfc> [enable|disable]",
2138  .function = set_int_proxy_arp_command_fn,
2139 };
2140 /* *INDENT-ON* */
2141 
2142 
2143 /*
2144  * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2145  * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2146  */
2147 typedef enum
2148 {
2152 } arp_term_next_t;
2153 
2155 
2156 static uword
2158  vlib_node_runtime_t * node, vlib_frame_t * frame)
2159 {
2160  l2input_main_t *l2im = &l2input_main;
2161  u32 n_left_from, next_index, *from, *to_next;
2162  u32 n_replies_sent = 0;
2163  u16 last_bd_index = ~0;
2164  l2_bridge_domain_t *last_bd_config = 0;
2165  l2_input_config_t *cfg0;
2166 
2167  from = vlib_frame_vector_args (frame);
2168  n_left_from = frame->n_vectors;
2169  next_index = node->cached_next_index;
2170 
2171  while (n_left_from > 0)
2172  {
2173  u32 n_left_to_next;
2174 
2175  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2176 
2177  while (n_left_from > 0 && n_left_to_next > 0)
2178  {
2179  vlib_buffer_t *p0;
2180  ethernet_header_t *eth0;
2181  ethernet_arp_header_t *arp0;
2182  ip6_header_t *iph0;
2183  u8 *l3h0;
2184  u32 pi0, error0, next0, sw_if_index0;
2185  u16 ethertype0;
2186  u16 bd_index0;
2187  u32 ip0;
2188  u8 *macp0;
2189 
2190  pi0 = from[0];
2191  to_next[0] = pi0;
2192  from += 1;
2193  to_next += 1;
2194  n_left_from -= 1;
2195  n_left_to_next -= 1;
2196 
2197  p0 = vlib_get_buffer (vm, pi0);
2198  // Terminate only local (SHG == 0) ARP
2199  if (vnet_buffer (p0)->l2.shg != 0)
2200  goto next_l2_feature;
2201 
2202  eth0 = vlib_buffer_get_current (p0);
2203  l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2204  ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2205  arp0 = (ethernet_arp_header_t *) l3h0;
2206 
2207  if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2208  (arp0->opcode !=
2209  clib_host_to_net_u16
2210  (ETHERNET_ARP_OPCODE_request))))
2211  goto check_ip6_nd;
2212 
2213  /* Must be ARP request packet here */
2214  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2215  (p0->flags & VLIB_BUFFER_IS_TRACED)))
2216  {
2217  u8 *t0 = vlib_add_trace (vm, node, p0,
2218  sizeof (ethernet_arp_input_trace_t));
2219  clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2220  }
2221 
2222  error0 = ETHERNET_ARP_ERROR_replies_sent;
2223  error0 =
2224  (arp0->l2_type !=
2225  clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2226  ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2227  error0 =
2228  (arp0->l3_type !=
2229  clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2230  ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2231 
2232  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2233 
2234  if (error0)
2235  goto drop;
2236 
2237  /* Trash ARP packets whose ARP-level source addresses do not
2238  match their L2-frame-level source addresses */
2239  if (PREDICT_FALSE
2240  (memcmp
2241  (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2242  sizeof (eth0->src_address))))
2243  {
2244  error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2245  goto drop;
2246  }
2247 
2248  /* Check if anyone want ARP request events for L2 BDs */
2249  {
2252  uword *p = hash_get (am->mac_changes_by_address, 0);
2253  if (p)
2254  {
2255  u32 next_index = p[0];
2256  while (next_index != (u32) ~ 0)
2257  {
2258  int (*fp) (u32, u8 *, u32, u32);
2259  int rv = 1;
2260  mc = pool_elt_at_index (am->mac_changes, next_index);
2261  fp = mc->data_callback;
2262  /* Call the callback, return 1 to suppress dup events */
2263  if (fp)
2264  rv = (*fp) (mc->data,
2265  arp0->ip4_over_ethernet[0].ethernet,
2266  sw_if_index0,
2267  arp0->ip4_over_ethernet[0].ip4.as_u32);
2268  /* Signal the resolver process */
2269  if (rv == 0)
2271  mc->type_opaque, mc->data);
2272  next_index = mc->next_index;
2273  }
2274  }
2275  }
2276 
2277  /* lookup BD mac_by_ip4 hash table for MAC entry */
2278  ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2279  bd_index0 = vnet_buffer (p0)->l2.bd_index;
2280  if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2281  || (last_bd_index == (u16) ~ 0)))
2282  {
2283  last_bd_index = bd_index0;
2284  last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2285  }
2286  macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2287 
2288  if (PREDICT_FALSE (!macp0))
2289  goto next_l2_feature; /* MAC not found */
2290 
2291  /* MAC found, send ARP reply -
2292  Convert ARP request packet to ARP reply */
2293  arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2294  arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2295  arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2296  clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2297  clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2298  clib_memcpy (eth0->src_address, macp0, 6);
2299  n_replies_sent += 1;
2300 
2301  output_response:
2302  /* For BVI, need to use l2-fwd node to send ARP reply as
2303  l2-output node cannot output packet to BVI properly */
2304  cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2305  if (PREDICT_FALSE (cfg0->bvi))
2306  {
2307  vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2308  vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2309  goto next_l2_feature;
2310  }
2311 
2312  /* Send ARP/ND reply back out input interface through l2-output */
2313  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2314  next0 = ARP_TERM_NEXT_L2_OUTPUT;
2315  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2316  to_next, n_left_to_next, pi0,
2317  next0);
2318  continue;
2319 
2320  check_ip6_nd:
2321  /* IP6 ND event notification or solicitation handling to generate
2322  local response instead of flooding */
2323  iph0 = (ip6_header_t *) l3h0;
2324  if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2325  iph0->protocol == IP_PROTOCOL_ICMP6 &&
2327  (&iph0->src_address)))
2328  {
2329  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2330  if (vnet_ip6_nd_term
2331  (vm, node, p0, eth0, iph0, sw_if_index0,
2332  vnet_buffer (p0)->l2.bd_index))
2333  goto output_response;
2334  }
2335 
2336  next_l2_feature:
2337  {
2338  u32 feature_bitmap0 =
2339  vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2340  vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2341  next0 =
2343  feature_bitmap0);
2344  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2345  to_next, n_left_to_next,
2346  pi0, next0);
2347  continue;
2348  }
2349 
2350  drop:
2351  if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2352  (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2353  arp0->ip4_over_ethernet[1].ip4.as_u32))
2354  {
2355  error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2356  }
2357  next0 = ARP_TERM_NEXT_DROP;
2358  p0->error = node->errors[error0];
2359 
2360  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2361  to_next, n_left_to_next, pi0,
2362  next0);
2363  }
2364 
2365  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2366  }
2367 
2368  vlib_error_count (vm, node->node_index,
2369  ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2370  return frame->n_vectors;
2371 }
2372 
2373 /* *INDENT-OFF* */
2375  .function = arp_term_l2bd,
2376  .name = "arp-term-l2bd",
2377  .vector_size = sizeof (u32),
2378  .n_errors = ETHERNET_ARP_N_ERROR,
2379  .error_strings = ethernet_arp_error_strings,
2380  .n_next_nodes = ARP_TERM_N_NEXT,
2381  .next_nodes = {
2382  [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2383  [ARP_TERM_NEXT_DROP] = "error-drop",
2384  },
2385  .format_buffer = format_ethernet_arp_header,
2386  .format_trace = format_arp_term_input_trace,
2387 };
2388 /* *INDENT-ON* */
2389 
2390 clib_error_t *
2392 {
2393  // Initialize the feature next-node indexes
2395  arp_term_l2bd_node.index,
2399  return 0;
2400 }
2401 
2403 
2404 void
2406 {
2407  if (e->sw_if_index == sw_if_index)
2408  {
2411  }
2412 }
2413 
2414 void
2416 {
2419 
2420  /* *INDENT-OFF* */
2421  pool_foreach (e, am->ip4_entry_pool,
2422  ({
2423  change_arp_mac (sw_if_index, e);
2424  }));
2425  /* *INDENT-ON* */
2426 }
2427 
2428 /*
2429  * fd.io coding-style-patch-verification: ON
2430  *
2431  * Local Variables:
2432  * eval: (c-set-style "gnu")
2433  * End:
2434  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
This packets follow a load-balance.
Definition: lookup.h:86
fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, fib_protocol_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags)
Update the entry to have just one path.
Definition: fib_table.c:716
#define vnet_rewrite_one_header(rw0, p0, most_likely_size)
Definition: rewrite.h:283
Definition: edit.h:64
static void set_ip4_over_ethernet_rpc_callback(vnet_arp_set_ip4_over_ethernet_rpc_args_t *a)
Definition: arp.c:1761
#define VNET_SW_INTERFACE_FLAG_UNNUMBERED
Definition: interface.h:543
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
vmrglw vmrglh hi
#define pool_next_index(P, I)
Return next occupied pool index after i, useful for safe iteration.
Definition: pool.h:405
#define VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST
Definition: rewrite.h:315
static uword arp_term_l2bd(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp.c:2157
#define hash_set(h, key, value)
Definition: hash.h:254
l2_input_config_t * configs
Definition: l2_input.h:69
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
u8 * format_ethernet_arp_ip4_entry(u8 *s, va_list *va)
Definition: arp.c:239
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Functions to call when interface address changes.
Definition: ip4.h:138
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
An indication that the rewrite is incomplete, i.e.
Definition: adj_nbr.h:90
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:603
uword unformat_pg_arp_header(unformat_input_t *input, va_list *args)
Definition: arp.c:1453
static void pg_ethernet_arp_header_init(pg_ethernet_arp_header_t *p)
Definition: arp.c:1436
static int vnet_arp_unset_ip4_over_ethernet_internal(vnet_main_t *vnm, vnet_arp_set_ip4_over_ethernet_rpc_args_t *args)
Definition: arp.c:1683
static void increment_ip4_and_mac_address(ethernet_arp_ip4_over_ethernet_address_t *a)
Definition: arp.c:1823
An indication that the rewrite is complete, i.e.
Definition: adj_nbr.h:98
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
static uword vlib_current_process(vlib_main_t *vm)
Definition: node_funcs.h:410
struct ip_adjacency_t_::@138::@139 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
static void arp_add_del_interface_address(ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_del)
Definition: arp.c:1567
static void pg_edit_set_fixed(pg_edit_t *e, u64 value)
Definition: edit.h:153
static clib_error_t * show_ip4_arp(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: arp.c:1361
vnet_interface_main_t interface_main
Definition: vnet.h:57
pending_resolution_t * pending_resolutions
Definition: arp.c:77
void fib_entry_get_prefix(fib_node_index_t fib_entry_index, fib_prefix_t *pfx)
Definition: fib_entry.c:1456
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
vnet_link_t adj_get_link_type(adj_index_t ai)
Return the link type of the adjacency.
Definition: adj.c:340
#define NULL
Definition: clib.h:55
IP unicast adjacency.
Definition: lookup.h:193
struct ethernet_arp_interface_t_ ethernet_arp_interface_t
Per-interface ARP configuration and state.
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:459
void change_arp_mac(u32 sw_if_index, ethernet_arp_ip4_entry_t *e)
Definition: arp.c:2405
static u8 * format_ethernet_arp_header(u8 *s, va_list *va)
Definition: arp.c:192
u8 src_address[6]
Definition: packet.h:54
static clib_error_t * set_int_proxy_arp_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: arp.c:2077
clib_error_t * ip4_set_arp_limit(u32 arp_limit)
Definition: arp.c:1489
static uword arp_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp.c:975
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
word vnet_sw_interface_compare(vnet_main_t *vnm, uword sw_if_index0, uword sw_if_index1)
Definition: interface.c:1112
static u64 clib_cpu_time_now(void)
Definition: time.h:73
void arp_update_adjacency(vnet_main_t *vnm, u32 sw_if_index, u32 ai)
Definition: arp.c:433
static uword unformat_ethernet_arp_opcode_host_byte_order(unformat_input_t *input, va_list *args)
Definition: arp.c:151
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:982
uword unformat_pg_edit(unformat_input_t *input, va_list *args)
Definition: edit.c:106
void adj_nbr_walk_nh4(u32 sw_if_index, const ip4_address_t *addr, adj_walk_cb_t cb, void *ctx)
Walk adjacencies on a link with a given v4 next-hop.
Definition: adj_nbr.c:616
pg_edit_t l2_type
Definition: arp.c:1425
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
u32 * fib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip4.h:120
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
union ip_adjacency_t_::@138 sub_type
uword * opcode_by_name
Definition: arp.c:73
format_function_t format_vlib_cpu_time
Definition: node_funcs.h:1109
unformat_function_t unformat_vnet_sw_interface
u64 cpu_time_last_updated
Definition: arp_packet.h:159
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1327
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:418
Definition: fib_entry.h:229
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
Multicast Adjacency.
Definition: lookup.h:95
pg_edit_t ethernet
Definition: arp.c:1430
ip6_address_t src_address
Definition: ip6_packet.h:341
void * data_callback
Definition: arp.c:66
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
Adjacency to drop this packet.
Definition: lookup.h:63
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:350
vnet_link_t ia_link
Definition: lookup.h:214
static int vnet_arp_populate_ip4_over_ethernet_internal(vnet_main_t *vnm, vnet_arp_set_ip4_over_ethernet_rpc_args_t *args)
Definition: arp.c:1740
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(ethernet_arp_sw_interface_up_down)
void adj_mcast_update_rewrite(adj_index_t adj_index, u8 *rewrite)
adj_mcast_update_rewrite
Definition: adj_mcast.c:102
struct vnet_sub_interface_t::@117::@118::@120 flags
arp_input_next_t
Definition: arp.c:777
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:211
format_function_t format_ip4_address
Definition: format.h:79
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:128
pg_edit_t n_l3_address_bytes
Definition: arp.c:1426
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:67
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define VNET_SW_INTERFACE_FLAG_PROXY_ARP
Definition: interface.h:541
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:818
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
unformat_function_t unformat_ip4_address
Definition: format.h:76
ethernet_arp_ip4_over_ethernet_address_t ip4_over_ethernet[2]
Definition: arp_packet.h:136
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:526
This packets needs to go to ICMP error.
Definition: lookup.h:92
pending_resolution_t * mac_changes
Definition: arp.c:81
static uword format_get_indent(u8 *s)
Definition: format.h:72
u8 dst_address[6]
Definition: packet.h:53
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:113
static int ip4_arp_entry_sort(void *a1, void *a2)
Definition: arp.c:1327
enum adj_walk_rc_t_ adj_walk_rc_t
return codes from a adjacency walker callback function
int i32
Definition: types.h:81
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Aggregrate type for a prefix.
Definition: fib_types.h:160
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
Adjacency to punt this packet.
Definition: lookup.h:65
#define clib_error_return(e, args...)
Definition: error.h:111
ethernet_arp_hardware_type_t
Definition: arp_packet.h:89
static u8 * format_ethernet_arp_input_trace(u8 *s, va_list *va)
Definition: arp.c:278
static int vnet_arp_flush_ip4_over_ethernet(vnet_main_t *vnm, u32 sw_if_index, void *a_arg)
Internally generated event to flush the ARP cache on an interface state change event.
Definition: arp.c:1523
#define foreach_ethernet_arp_opcode
Definition: arp_packet.h:61
uword * pending_resolutions_by_address
Definition: arp.c:76
This packet is for one of our own IP addresses.
Definition: lookup.h:68
static void * pg_create_edit_group(pg_stream_t *s, int n_edit_bytes, int n_packet_bytes, u32 *group_index)
Definition: pg.h:225
u16 fp_len
The mask length.
Definition: fib_types.h:164
#define vlib_call_init_function(vm, x)
Definition: init.h:162
static ethernet_arp_ip4_entry_t * arp_entry_find(ethernet_arp_interface_t *eai, const ip4_address_t *addr)
Definition: arp.c:396
This packet matches an "interface route" and packets need to be passed to ARP to find rewrite string ...
Definition: lookup.h:78
int vnet_arp_unset_ip4_over_ethernet(vnet_main_t *vnm, u32 sw_if_index, void *a_arg)
Control Plane hook to remove an ARP entry.
Definition: arp.c:1501
#define hash_create_string(elts, value_bytes)
Definition: hash.h:652
adj_index_t fib_entry_get_adj(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:447
pg_edit_t l3_type
Definition: arp.c:1425
static adj_walk_rc_t arp_mk_complete_walk(adj_index_t ai, void *ctx)
Definition: arp.c:415
Per-interface ARP configuration and state.
Definition: arp.c:43
Definition: fib_entry.h:232
#define hash_get(h, key)
Definition: hash.h:248
format_function_t format_vnet_sw_interface_name
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:686
static ethernet_header_t * ethernet_buffer_get_header(vlib_buffer_t *b)
Definition: ethernet.h:345
vnet_sub_interface_t sub
Definition: interface.h:569
uword * fib_index_by_table_id
Hash table mapping table id to fib index.
Definition: ip4.h:130
#define foreach_ethernet_arp_error
Definition: arp.c:784
vlib_main_t * vlib_main
Definition: vnet.h:79
static void arp_mk_complete(adj_index_t ai, ethernet_arp_ip4_entry_t *e)
Definition: arp.c:372
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:930
Adjacency source.
Definition: fib_entry.h:92
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:183
uword type_opaque
Definition: arp.c:63
#define ETHERNET_ARP_ARGS_FLUSH
Definition: arp.c:106
ip4_address_t ip4_address
Definition: arp_packet.h:153
struct _unformat_input_t unformat_input_t
u32 sw_if_index
Definition: arp_packet.h:152
static u32 arp_learn(vnet_main_t *vnm, ethernet_arp_main_t *am, u32 sw_if_index, void *addr)
Definition: arp.c:963
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
u8 ethernet_address[6]
Definition: arp_packet.h:155
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
u8 * ip_enabled_by_sw_if_index
Definition: ip4.h:126
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
static void unset_random_arp_entry(void)
Definition: arp.c:811
#define PREDICT_FALSE(x)
Definition: clib.h:97
ethernet_arp_interface_t * ethernet_arp_by_sw_if_index
Per interface state.
Definition: arp.c:90
int vnet_arp_set_ip4_over_ethernet_internal(vnet_main_t *vnm, vnet_arp_set_ip4_over_ethernet_rpc_args_t *args)
Definition: arp.c:518
u32 node_index
Node index.
Definition: node.h:436
static clib_error_t * ethernet_arp_init(vlib_main_t *vm)
Definition: arp.c:1622
static u32 feat_bitmap_get_next_node_index(u32 *next_nodes, u32 bitmap)
Return the graph node index for the feature corresponding to the first set bit in the bitmap...
Definition: feat_bitmap.h:79
#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:216
#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:350
ethernet_arp_opcode_t
Definition: arp_packet.h:96
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static int arp_unnumbered(vlib_buffer_t *p0, u32 pi0, ethernet_header_t *eth0, u32 input_sw_if_index, u32 conn_sw_if_index)
Definition: arp.c:842
u32 fib_entry_get_resolving_interface(fib_node_index_t entry_index)
Definition: fib_entry.c:1321
static clib_error_t * ip_arp_add_del_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: arp.c:1940
u8 * format_ethernet_type(u8 *s, va_list *args)
Definition: format.c:58
fib_node_index_t ip4_fib_table_lookup(const ip4_fib_t *fib, const ip4_address_t *addr, u32 len)
The IPv4 FIB.
Definition: ip4_fib.c:284
ethernet_proxy_arp_t * proxy_arps
Definition: arp.c:93
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u16 n_vectors
Definition: node.h:344
static void arp_mk_incomplete(adj_index_t ai)
Definition: arp.c:382
vlib_main_t * vm
Definition: buffer.c:276
int ip4_address_compare(ip4_address_t *a1, ip4_address_t *a2)
Definition: ip46_cli.c:51
pg_edit_t n_l2_address_bytes
Definition: arp.c:1426
vec_header_t h
Definition: buffer.c:275
void fib_table_entry_delete_index(fib_node_index_t fib_entry_index, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:821
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:94
static ethernet_arp_main_t ethernet_arp_main
Definition: arp.c:96
static ip4_fib_t * ip4_fib_get(u32 index)
Get the FIB at the given index.
Definition: ip4_fib.h:80
static void feat_bitmap_init_next_nodes(vlib_main_t *vm, u32 node_index, u32 num_features, char **feat_names, u32 *next_nodes)
Initialize the feature next-node indexes of a graph node.
Definition: feat_bitmap.h:43
static char * ethernet_arp_error_strings[]
Definition: arp.c:1302
#define ETHERNET_ARP_ARGS_POPULATE
Definition: arp.c:107
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
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:88
#define clib_memcpy(a, b, c)
Definition: string.h:69
unformat_function_t * unformat_edit
Definition: pg.h:307
uword * mac_changes_by_address
Definition: arp.c:80
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
struct vnet_sub_interface_t::@117 eth
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
This packet matches an "incomplete adjacency" and packets need to be passed to ARP to find rewrite st...
Definition: lookup.h:73
void vnet_register_ip4_arp_resolution_event(vnet_main_t *vnm, void *address_arg, uword node_index, uword type_opaque, uword data)
Definition: arp.c:664
static clib_error_t * ethernet_arp_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Invoked when the interface&#39;s admin state changes.
Definition: arp.c:1781
char ** l2input_get_feat_names(void)
Return an array of strings containing graph node names of each feature.
Definition: l2_input.c:58
int vnet_proxy_arp_add_del(ip4_address_t *lo_addr, ip4_address_t *hi_addr, u32 fib_index, int is_del)
Definition: arp.c:1865
enum fib_entry_flag_t_ fib_entry_flag_t
static u8 * format_ethernet_arp_opcode(u8 *s, va_list *va)
Definition: arp.c:133
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
clib_error_t * arp_term_init(vlib_main_t *vm)
Definition: arp.c:2391
vlib_packet_template_t ip4_arp_request_packet_template
Template used to generate IP4 ARP packets.
Definition: ip4.h:141
#define hash_create(elts, value_bytes)
Definition: hash.h:658
#define ETHERNET_ARP_ARGS_REMOVE
Definition: arp.c:105
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:455
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:536
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:227
#define ASSERT(truth)
u32 arp_term_next_node_index[32]
Definition: arp.c:2154
unsigned int u32
Definition: types.h:88
adj_index_t fib_entry_get_adj_for_source(fib_node_index_t fib_entry_index, fib_source_t source)
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:785
IPv4 main type.
Definition: ip4.h:107
uword unformat_vlib_number_by_name(unformat_input_t *input, va_list *args)
Definition: format.c:157
This packets follow a mid-chain adjacency.
Definition: lookup.h:89
static void pg_free_edit_group(pg_stream_t *s)
Definition: pg.h:278
u32 arp_delete_rotor
Definition: arp.c:86
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:201
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
format_function_t format_ip6_header
Definition: format.h:98
ethernet_arp_entry_flags_t flags
Definition: arp_packet.h:157
Route added as a result of interface configuration.
Definition: fib_entry.h:50
static void arp_nbr_probe(ip_adjacency_t *adj)
Definition: arp.c:309
Definition: pg.h:96
ethernet_arp_ip4_over_ethernet_address_t a
Definition: arp.c:101
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1296
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static vlib_node_registration_t arp_term_l2bd_node
(constructor) VLIB_REGISTER_NODE (arp_term_l2bd_node)
Definition: arp.c:2374
uword * arp_entries
Hash table of ARP entries.
Definition: arp.c:49
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vec_elt(v, i)
Get vector value at index i.
Definition: defs.h:47
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:45
unsigned short u16
Definition: types.h:57
l2input_main_t l2input_main
Definition: l2_input.c:88
static vlib_node_registration_t arp_input_node
(constructor) VLIB_REGISTER_NODE (arp_input_node)
Definition: arp.c:1309
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
int vnet_proxy_arp_fib_reset(u32 fib_id)
Definition: arp.c:1906
fib_node_index_t fib_entry_index
The index of the adj-fib entry created.
Definition: arp_packet.h:164
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
ip_lookup_next_t lookup_next_index
Definition: lookup.h:204
#define hash_foreach_pair(p, v, body)
Iterate over hash pairs.
Definition: hash.h:349
Definition: fib_entry.h:228
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:960
static u8 * format_arp_term_input_trace(u8 *s, va_list *va)
Definition: arp.c:292
static int vnet_arp_flush_ip4_over_ethernet_internal(vnet_main_t *vnm, vnet_arp_set_ip4_over_ethernet_rpc_args_t *args)
Definition: arp.c:1707
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:617
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
static clib_error_t * ethernet_init(vlib_main_t *vm)
Definition: init.c:82
static u8 * format_ethernet_arp_hardware_type(u8 *s, va_list *va)
Definition: arp.c:115
u8 * ethernet_build_rewrite(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
build a rewrite string to use for sending packets of type &#39;link_type&#39; to &#39;dst_address&#39; ...
Definition: interface.c:79
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:72
static void arp_entry_free(ethernet_arp_interface_t *eai, ethernet_arp_ip4_entry_t *e)
Definition: arp.c:1672
pg_edit_t opcode
Definition: arp.c:1427
#define clib_mem_unaligned(pointer, type)
Definition: types.h:155
ethernet_arp_input_error_t
Definition: arp.c:801
arp_term_next_t
Definition: arp.c:2147
u32 limit_arp_cache_size
Definition: arp.c:87
short i16
Definition: types.h:46
#define vnet_buffer(b)
Definition: buffer.h:294
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
struct pg_ethernet_arp_header_t::@85 ip4_over_ethernet[2]
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1117
uword node_index
Definition: arp.c:62
This packet is to be rewritten and forwarded to the next processing node.
Definition: lookup.h:83
#define vec_foreach(var, vec)
Vector iterator.
static uword ip6_address_is_unspecified(ip6_address_t *a)
Definition: ip6_packet.h:277
uword * mac_by_ip4
Definition: l2_bd.h:83
u16 flags
Copy of main node flags.
Definition: node.h:449
ethernet_arp_ip4_entry_t * ip4_neighbor_entries(u32 sw_if_index)
Definition: arp.c:1342
vhost_vring_addr_t addr
Definition: vhost-user.h:84
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
int vnet_arp_set_ip4_over_ethernet(vnet_main_t *vnm, u32 sw_if_index, void *a_arg, int is_static, int is_no_fib_entry)
Definition: arp.c:1846
static int vnet_arp_populate_ip4_over_ethernet(vnet_main_t *vnm, u32 sw_if_index, void *a_arg)
Internally generated event to populate the ARP cache on an interface state change event...
Definition: arp.c:1546
u32 flags
Definition: vhost-user.h:78
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
static uword unformat_ethernet_arp_opcode_net_byte_order(unformat_input_t *input, va_list *args)
Definition: arp.c:179
void adj_nbr_update_rewrite(adj_index_t adj_index, adj_nbr_rewrite_flag_t flags, u8 *rewrite)
adj_nbr_update_rewrite
Definition: adj_nbr.c:293
void ethernet_arp_change_mac(u32 sw_if_index)
Definition: arp.c:2415
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:577
ethernet_arp_ip4_entry_t * ip4_entry_pool
Definition: arp.c:83
int vnet_add_del_ip4_arp_change_event(vnet_main_t *vnm, void *data_callback, u32 pid, void *address_arg, uword node_index, uword type_opaque, uword data, int is_add)
Definition: arp.c:695
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
Definition: pg.h:304
const u8 * ethernet_ip4_mcast_dst_addr(void)
Definition: interface.c:55
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
int vnet_ip6_nd_term(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *p0, ethernet_header_t *eth, ip6_header_t *ip, u32 sw_if_index, u16 bd_index)
Definition: defs.h:46
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
Definition: arp_packet.h:150
fib_entry_flag_t fib_entry_get_flags(fib_node_index_t fib_entry_index)
Definition: fib_entry.c:278
static adj_walk_rc_t arp_mk_incomplete_walk(adj_index_t ai, void *ctx)
Definition: arp.c:425
static ip4_address_t * ip4_interface_address_matching_destination(ip4_main_t *im, ip4_address_t *dst, u32 sw_if_index, ip_interface_address_t **result_ia)
Definition: ip4.h:224
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109