2 * ethernet/arp.c: IP v4 ARP node
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/ip/ip.h>
19 #include <vnet/ip/ip6.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vnet/ethernet/arp_packet.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>
33 * This file contains code to manage the IPv4 ARP tables (IP Address
34 * to MAC Address lookup).
38 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
41 * @brief Per-interface ARP configuration and state
43 typedef struct ethernet_arp_interface_t_
46 * Hash table of ARP entries.
47 * Since this hash table is per-interface, the key is only the IPv4 address.
50 } ethernet_arp_interface_t;
57 } ethernet_proxy_arp_t;
65 /* Used for arp event notification only */
68 } pending_resolution_t;
72 /* Hash tables mapping name to opcode. */
73 uword *opcode_by_name;
75 /* lite beer "glean" adjacency handling */
76 uword *pending_resolutions_by_address;
77 pending_resolution_t *pending_resolutions;
79 /* Mac address change notification */
80 uword *mac_changes_by_address;
81 pending_resolution_t *mac_changes;
83 ethernet_arp_ip4_entry_t *ip4_entry_pool;
85 /* ARP attack mitigation */
87 u32 limit_arp_cache_size;
89 /** Per interface state */
90 ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
92 /* Proxy arp vector */
93 ethernet_proxy_arp_t *proxy_arps;
94 } ethernet_arp_main_t;
96 static ethernet_arp_main_t ethernet_arp_main;
101 ethernet_arp_ip4_over_ethernet_address_t a;
104 #define ETHERNET_ARP_ARGS_REMOVE (1<<0)
105 #define ETHERNET_ARP_ARGS_FLUSH (1<<1)
106 #define ETHERNET_ARP_ARGS_POPULATE (1<<2)
107 } vnet_arp_set_ip4_over_ethernet_rpc_args_t;
110 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
114 format_ethernet_arp_hardware_type (u8 * s, va_list * va)
116 ethernet_arp_hardware_type_t h = va_arg (*va, ethernet_arp_hardware_type_t);
120 #define _(n,f) case n: t = #f; break;
121 foreach_ethernet_arp_hardware_type;
125 return format (s, "unknown 0x%x", h);
128 return format (s, "%s", t);
132 format_ethernet_arp_opcode (u8 * s, va_list * va)
134 ethernet_arp_opcode_t o = va_arg (*va, ethernet_arp_opcode_t);
138 #define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
139 foreach_ethernet_arp_opcode;
143 return format (s, "unknown 0x%x", o);
146 return format (s, "%s", t);
150 unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
153 int *result = va_arg (*args, int *);
154 ethernet_arp_main_t *am = ðernet_arp_main;
157 /* Numeric opcode. */
158 if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
167 if (unformat_user (input, unformat_vlib_number_by_name,
168 am->opcode_by_name, &i))
178 unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
181 int *result = va_arg (*args, int *);
183 (input, unformat_ethernet_arp_opcode_host_byte_order, result))
186 *result = clib_host_to_net_u16 ((u16) * result);
191 format_ethernet_arp_header (u8 * s, va_list * va)
193 ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
194 u32 max_header_bytes = va_arg (*va, u32);
196 u16 l2_type, l3_type;
198 if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
199 return format (s, "ARP header truncated");
201 l2_type = clib_net_to_host_u16 (a->l2_type);
202 l3_type = clib_net_to_host_u16 (a->l3_type);
204 indent = format_get_indent (s);
206 s = format (s, "%U, type %U/%U, address size %d/%d",
207 format_ethernet_arp_opcode, clib_net_to_host_u16 (a->opcode),
208 format_ethernet_arp_hardware_type, l2_type,
209 format_ethernet_type, l3_type,
210 a->n_l2_address_bytes, a->n_l3_address_bytes);
212 if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
213 && l3_type == ETHERNET_TYPE_IP4)
215 s = format (s, "\n%U%U/%U -> %U/%U",
216 format_white_space, indent,
217 format_ethernet_address, a->ip4_over_ethernet[0].ethernet,
218 format_ip4_address, &a->ip4_over_ethernet[0].ip4,
219 format_ethernet_address, a->ip4_over_ethernet[1].ethernet,
220 format_ip4_address, &a->ip4_over_ethernet[1].ip4);
224 uword n2 = a->n_l2_address_bytes;
225 uword n3 = a->n_l3_address_bytes;
226 s = format (s, "\n%U%U/%U -> %U/%U",
227 format_white_space, indent,
228 format_hex_bytes, a->data + 0 * n2 + 0 * n3, n2,
229 format_hex_bytes, a->data + 1 * n2 + 0 * n3, n3,
230 format_hex_bytes, a->data + 1 * n2 + 1 * n3, n2,
231 format_hex_bytes, a->data + 2 * n2 + 1 * n3, n3);
238 format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
240 vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
241 ethernet_arp_ip4_entry_t *e = va_arg (*va, ethernet_arp_ip4_entry_t *);
242 vnet_sw_interface_t *si;
246 return format (s, "%=12s%=16s%=6s%=20s%=24s", "Time", "IP4",
247 "Flags", "Ethernet", "Interface");
249 si = vnet_get_sw_interface (vnm, e->sw_if_index);
251 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
252 flags = format (flags, "S");
254 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
255 flags = format (flags, "D");
257 s = format (s, "%=12U%=16U%=6s%=20U%=24U",
258 format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
259 format_ip4_address, &e->ip4_address,
260 flags ? (char *) flags : "",
261 format_ethernet_address, e->ethernet_address,
262 format_vnet_sw_interface_name, vnm, si);
271 } ethernet_arp_input_trace_t;
274 format_ethernet_arp_input_trace (u8 * s, va_list * va)
276 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
277 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
278 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
281 format_ethernet_arp_header,
282 t->packet_data, sizeof (t->packet_data));
288 format_arp_term_input_trace (u8 * s, va_list * va)
290 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
291 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
292 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
294 /* arp-term trace data saved is either arp or ip6/icmp6 packet:
295 - for arp, the 1st 16-bit field is hw type of value of 0x0001.
296 - for ip6, the first nibble has value of 6. */
297 s = format (s, "%U", t->packet_data[0] == 0 ?
298 format_ethernet_arp_header : format_ip6_header,
299 t->packet_data, sizeof (t->packet_data));
305 arp_nbr_probe (ip_adjacency_t * adj)
307 vnet_main_t *vnm = vnet_get_main ();
308 ip4_main_t *im = &ip4_main;
309 ip_interface_address_t *ia;
310 ethernet_arp_header_t *h;
311 vnet_hw_interface_t *hi;
312 vnet_sw_interface_t *si;
318 vm = vlib_get_main ();
320 si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
322 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
328 ip4_interface_address_matching_destination (im,
329 &adj->sub_type.nbr.next_hop.
339 vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template,
342 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
344 clib_memcpy (h->ip4_over_ethernet[0].ethernet,
345 hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
347 h->ip4_over_ethernet[0].ip4 = src[0];
348 h->ip4_over_ethernet[1].ip4 = adj->sub_type.nbr.next_hop.ip4;
350 b = vlib_get_buffer (vm, bi);
351 vnet_buffer (b)->sw_if_index[VLIB_RX] =
352 vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
354 /* Add encapsulation string for software interface (e.g. ethernet header). */
355 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
356 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
359 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
360 u32 *to_next = vlib_frame_vector_args (f);
363 vlib_put_frame_to_node (vm, hi->output_node_index, f);
368 arp_mk_complete (adj_index_t ai, ethernet_arp_ip4_entry_t * e)
370 adj_nbr_update_rewrite
371 (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
372 ethernet_build_rewrite (vnet_get_main (),
374 adj_get_link_type (ai), e->ethernet_address));
378 arp_mk_incomplete (adj_index_t ai)
380 ip_adjacency_t *adj = adj_get (ai);
382 adj_nbr_update_rewrite
384 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
385 ethernet_build_rewrite (vnet_get_main (),
386 adj->rewrite_header.sw_if_index,
388 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
391 static ethernet_arp_ip4_entry_t *
392 arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
394 ethernet_arp_main_t *am = ðernet_arp_main;
395 ethernet_arp_ip4_entry_t *e = NULL;
398 if (NULL != eai->arp_entries)
400 p = hash_get (eai->arp_entries, addr->as_u32);
404 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
411 arp_mk_complete_walk (adj_index_t ai, void *ctx)
413 ethernet_arp_ip4_entry_t *e = ctx;
415 arp_mk_complete (ai, e);
417 return (ADJ_WALK_RC_CONTINUE);
421 arp_mk_incomplete_walk (adj_index_t ai, void *ctx)
423 arp_mk_incomplete (ai);
425 return (ADJ_WALK_RC_CONTINUE);
429 arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
431 ethernet_arp_main_t *am = ðernet_arp_main;
432 ethernet_arp_interface_t *arp_int;
433 ethernet_arp_ip4_entry_t *e;
438 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
439 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
440 e = arp_entry_find (arp_int, &adj->sub_type.nbr.next_hop.ip4);
442 switch (adj->lookup_next_index)
444 case IP_LOOKUP_NEXT_ARP:
445 case IP_LOOKUP_NEXT_GLEAN:
448 adj_nbr_walk_nh4 (sw_if_index,
449 &e->ip4_address, arp_mk_complete_walk, e);
454 * no matching ARP entry.
455 * construct the rewrite required to for an ARP packet, and stick
456 * that in the adj's pipe to smoke.
458 adj_nbr_update_rewrite
460 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
461 ethernet_build_rewrite
465 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
468 * since the FIB has added this adj for a route, it makes sense it
469 * may want to forward traffic sometime soon. Let's send a
470 * speculative ARP. just one. If we were to do periodically that
471 * wouldn't be bad either, but that's more code than i'm prepared to
472 * write at this time for relatively little reward.
477 case IP_LOOKUP_NEXT_MCAST:
479 * Construct a partial rewrite from the known ethernet mcast dest MAC
481 adj_mcast_update_rewrite
483 ethernet_build_rewrite (vnm,
486 ethernet_ip4_mcast_dst_addr ()));
489 * Complete the remaining fields of the adj's rewrite to direct the
490 * complete of the rewrite at switch time by copying in the IP
491 * dst address's bytes.
492 * Ofset is 11 bytes from the end of the MAC header - which is three
493 * bytes into the desintation address. And we write 3 bytes.
495 adj->rewrite_header.dst_mcast_offset = 11;
496 adj->rewrite_header.dst_mcast_n_bytes = 3;
500 case IP_LOOKUP_NEXT_DROP:
501 case IP_LOOKUP_NEXT_PUNT:
502 case IP_LOOKUP_NEXT_LOCAL:
503 case IP_LOOKUP_NEXT_REWRITE:
504 case IP_LOOKUP_NEXT_LOAD_BALANCE:
505 case IP_LOOKUP_NEXT_MIDCHAIN:
506 case IP_LOOKUP_NEXT_ICMP_ERROR:
507 case IP_LOOKUP_N_NEXT:
514 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
515 vnet_arp_set_ip4_over_ethernet_rpc_args_t
518 ethernet_arp_ip4_entry_t *e = 0;
519 ethernet_arp_main_t *am = ðernet_arp_main;
520 ethernet_arp_ip4_over_ethernet_address_t *a = &args->a;
521 vlib_main_t *vm = vlib_get_main ();
522 int make_new_arp_cache_entry = 1;
524 pending_resolution_t *pr, *mc;
525 ethernet_arp_interface_t *arp_int;
526 int is_static = args->is_static;
527 u32 sw_if_index = args->sw_if_index;
529 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
531 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
533 if (NULL != arp_int->arp_entries)
535 p = hash_get (arp_int->arp_entries, a->ip4.as_u32);
538 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
540 /* Refuse to over-write static arp. */
541 if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
543 make_new_arp_cache_entry = 0;
547 if (make_new_arp_cache_entry)
551 .fp_proto = FIB_PROTOCOL_IP4,
559 pool_get (am->ip4_entry_pool, e);
561 if (NULL == arp_int->arp_entries)
563 arp_int->arp_entries = hash_create (0, sizeof (u32));
566 hash_set (arp_int->arp_entries, a->ip4.as_u32, e - am->ip4_entry_pool);
568 e->sw_if_index = sw_if_index;
569 e->ip4_address = a->ip4;
570 clib_memcpy (e->ethernet_address,
571 a->ethernet, sizeof (e->ethernet_address));
573 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
575 fib_table_entry_update_one_path (fib_index,
578 FIB_ENTRY_FLAG_ATTACHED,
583 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
588 * prevent a DoS attack from the data-plane that
589 * spams us with no-op updates to the MAC address
591 if (0 == memcmp (e->ethernet_address,
592 a->ethernet, sizeof (e->ethernet_address)))
595 /* Update time stamp and ethernet address. */
596 clib_memcpy (e->ethernet_address, a->ethernet,
597 sizeof (e->ethernet_address));
600 e->cpu_time_last_updated = clib_cpu_time_now ();
602 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
604 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC;
606 adj_nbr_walk_nh4 (sw_if_index, &e->ip4_address, arp_mk_complete_walk, e);
608 /* Customer(s) waiting for this address to be resolved? */
609 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
615 while (next_index != (u32) ~ 0)
617 pr = pool_elt_at_index (am->pending_resolutions, next_index);
618 vlib_process_signal_event (vm, pr->node_index,
619 pr->type_opaque, pr->data);
620 next_index = pr->next_index;
621 pool_put (am->pending_resolutions, pr);
624 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
627 /* Customer(s) requesting ARP event for this address? */
628 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
634 while (next_index != (u32) ~ 0)
636 int (*fp) (u32, u8 *, u32, u32);
638 mc = pool_elt_at_index (am->mac_changes, next_index);
639 fp = mc->data_callback;
641 /* Call the user's data callback, return 1 to suppress dup events */
643 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
646 * Signal the resolver process, as long as the user
647 * says they want to be notified
650 vlib_process_signal_event (vm, mc->node_index,
651 mc->type_opaque, mc->data);
652 next_index = mc->next_index;
660 vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
663 uword type_opaque, uword data)
665 ethernet_arp_main_t *am = ðernet_arp_main;
666 ip4_address_t *address = address_arg;
668 pending_resolution_t *pr;
670 pool_get (am->pending_resolutions, pr);
673 pr->node_index = node_index;
674 pr->type_opaque = type_opaque;
676 pr->data_callback = 0;
678 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
681 /* Insert new resolution at the head of the list */
682 pr->next_index = p[0];
683 hash_unset (am->pending_resolutions_by_address, address->as_u32);
686 hash_set (am->pending_resolutions_by_address, address->as_u32,
687 pr - am->pending_resolutions);
691 vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
696 uword type_opaque, uword data, int is_add)
698 ethernet_arp_main_t *am = ðernet_arp_main;
699 ip4_address_t *address = address_arg;
701 pending_resolution_t *mc;
702 void (*fp) (u32, u8 *) = data_callback;
706 pool_get (am->mac_changes, mc);
709 mc->node_index = node_index;
710 mc->type_opaque = type_opaque;
712 mc->data_callback = data_callback;
715 p = hash_get (am->mac_changes_by_address, address->as_u32);
718 /* Insert new resolution at the head of the list */
719 mc->next_index = p[0];
720 hash_unset (am->mac_changes_by_address, address->as_u32);
723 hash_set (am->mac_changes_by_address, address->as_u32,
724 mc - am->mac_changes);
730 pending_resolution_t *mc_last = 0;
732 p = hash_get (am->mac_changes_by_address, address->as_u32);
734 return VNET_API_ERROR_NO_SUCH_ENTRY;
738 while (index != (u32) ~ 0)
740 mc = pool_elt_at_index (am->mac_changes, index);
741 if (mc->node_index == node_index &&
742 mc->type_opaque == type_opaque && mc->pid == pid)
744 /* Clients may need to clean up pool entries, too */
746 (*fp) (mc->data, 0 /* no new mac addrs */ );
749 hash_unset (am->mac_changes_by_address, address->as_u32);
750 if (mc->next_index != ~0)
751 hash_set (am->mac_changes_by_address, address->as_u32,
753 pool_put (am->mac_changes, mc);
759 mc_last->next_index = mc->next_index;
760 pool_put (am->mac_changes, mc);
765 index = mc->next_index;
768 return VNET_API_ERROR_NO_SUCH_ENTRY;
772 /* Either we drop the packet or we send a reply to the sender. */
776 ARP_INPUT_NEXT_REPLY_TX,
780 #define foreach_ethernet_arp_error \
781 _ (replies_sent, "ARP replies sent") \
782 _ (l2_type_not_ethernet, "L2 type not ethernet") \
783 _ (l3_type_not_ip4, "L3 type not IP4") \
784 _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
785 _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
786 _ (l3_src_address_is_local, "IP4 source address matches local interface") \
787 _ (l3_src_address_learned, "ARP request IP4 source address learned") \
788 _ (replies_received, "ARP replies received") \
789 _ (opcode_not_request, "ARP opcode not request") \
790 _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
791 _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
792 _ (missing_interface_address, "ARP missing interface address") \
793 _ (gratuitous_arp, "ARP probe or announcement dropped") \
794 _ (interface_no_table, "Interface is not mapped to an IP table") \
798 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
799 foreach_ethernet_arp_error
801 ETHERNET_ARP_N_ERROR,
802 } ethernet_arp_input_error_t;
806 unset_random_arp_entry (void)
808 ethernet_arp_main_t *am = ðernet_arp_main;
809 ethernet_arp_ip4_entry_t *e;
810 vnet_main_t *vnm = vnet_get_main ();
811 ethernet_arp_ip4_over_ethernet_address_t delme;
814 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
815 am->arp_delete_rotor = index;
817 /* Try again from elt 0, could happen if an intfc goes down */
820 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
821 am->arp_delete_rotor = index;
824 /* Nothing left in the pool */
828 e = pool_elt_at_index (am->ip4_entry_pool, index);
830 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
831 delme.ip4.as_u32 = e->ip4_address.as_u32;
833 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
837 arp_unnumbered (vlib_buffer_t * p0,
838 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
840 vlib_main_t *vm = vlib_get_main ();
841 vnet_main_t *vnm = vnet_get_main ();
842 vnet_interface_main_t *vim = &vnm->interface_main;
843 vnet_sw_interface_t *si;
844 vnet_hw_interface_t *hi;
845 u32 unnum_src_sw_if_index;
846 u32 *broadcast_swifs = 0;
851 u8 dst_mac_address[6];
853 ethernet_arp_header_t *arp0;
855 /* Save the dst mac address */
856 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
858 /* Figure out which sw_if_index supplied the address */
859 unnum_src_sw_if_index = sw_if_index;
861 /* Track down all users of the unnumbered source */
863 pool_foreach (si, vim->sw_interfaces,
865 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
866 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
868 vec_add1 (broadcast_swifs, si->sw_if_index);
873 /* If there are no interfaces un-unmbered to this interface,
875 if (0 == vec_len (broadcast_swifs))
878 /* Allocate buffering if we need it */
879 if (vec_len (broadcast_swifs) > 1)
881 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
882 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
883 _vec_len (buffers) = n_alloc;
884 for (i = 0; i < n_alloc; i++)
886 b0 = vlib_get_buffer (vm, buffers[i]);
888 /* xerox (partially built) ARP pkt */
889 clib_memcpy (b0->data, p0->data,
890 p0->current_length + p0->current_data);
891 b0->current_data = p0->current_data;
892 b0->current_length = p0->current_length;
893 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
894 vnet_buffer (p0)->sw_if_index[VLIB_RX];
898 vec_insert (buffers, 1, 0);
901 for (i = 0; i < vec_len (buffers); i++)
903 b0 = vlib_get_buffer (vm, buffers[i]);
904 arp0 = vlib_buffer_get_current (b0);
906 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
907 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
909 /* For decoration, most likely */
910 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
912 /* Fix ARP pkt src address */
913 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
915 /* Build L2 encaps for this swif */
916 header_size = sizeof (ethernet_header_t);
917 if (si->sub.eth.flags.one_tag)
919 else if (si->sub.eth.flags.two_tags)
922 vlib_buffer_advance (b0, -header_size);
923 eth0 = vlib_buffer_get_current (b0);
925 if (si->sub.eth.flags.one_tag)
927 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
929 eth0->type = si->sub.eth.flags.dot1ad ?
930 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
931 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
932 outer->priority_cfi_and_id =
933 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
934 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
937 else if (si->sub.eth.flags.two_tags)
939 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
940 ethernet_vlan_header_t *inner = (void *) (outer + 1);
942 eth0->type = si->sub.eth.flags.dot1ad ?
943 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
944 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
945 outer->priority_cfi_and_id =
946 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
947 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
948 inner->priority_cfi_and_id =
949 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
950 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
955 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
958 /* Restore the original dst address, set src address */
959 clib_memcpy (eth0->dst_address, dst_mac_address,
960 sizeof (eth0->dst_address));
961 clib_memcpy (eth0->src_address, hi->hw_address,
962 sizeof (eth0->src_address));
964 /* Transmit replicas */
968 vlib_get_frame_to_node (vm, hi->output_node_index);
969 u32 *to_next = vlib_frame_vector_args (f);
970 to_next[0] = buffers[i];
972 vlib_put_frame_to_node (vm, hi->output_node_index, f);
976 /* The regular path outputs the original pkt.. */
977 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
979 vec_free (broadcast_swifs);
986 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
988 ethernet_arp_main_t *am = ðernet_arp_main;
989 vnet_main_t *vnm = vnet_get_main ();
990 ip4_main_t *im4 = &ip4_main;
991 u32 n_left_from, next_index, *from, *to_next;
992 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
994 from = vlib_frame_vector_args (frame);
995 n_left_from = frame->n_vectors;
996 next_index = node->cached_next_index;
998 if (node->flags & VLIB_NODE_FLAG_TRACE)
999 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1001 sizeof (ethernet_arp_input_trace_t));
1003 while (n_left_from > 0)
1007 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1009 while (n_left_from > 0 && n_left_to_next > 0)
1012 vnet_hw_interface_t *hw_if0;
1013 ethernet_arp_header_t *arp0;
1014 ethernet_header_t *eth0;
1015 ip_adjacency_t *adj0;
1016 ip4_address_t *if_addr0, proxy_src;
1017 u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
1018 u8 is_request0, dst_is_local0, is_unnum0;
1019 ethernet_proxy_arp_t *pa;
1020 fib_node_index_t dst_fei, src_fei;
1022 fib_entry_flag_t src_flags, dst_flags;
1029 n_left_to_next -= 1;
1032 p0 = vlib_get_buffer (vm, pi0);
1033 arp0 = vlib_buffer_get_current (p0);
1035 is_request0 = arp0->opcode
1036 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
1038 error0 = ETHERNET_ARP_ERROR_replies_sent;
1042 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1043 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1046 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
1047 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
1049 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1054 /* Check that IP address is local and matches incoming interface. */
1055 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1056 if (~0 == fib_index0)
1058 error0 = ETHERNET_ARP_ERROR_interface_no_table;
1062 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1063 &arp0->ip4_over_ethernet[1].ip4,
1065 dst_flags = fib_entry_get_flags_for_source (dst_fei,
1066 FIB_SOURCE_INTERFACE);
1069 fib_entry_get_resolving_interface_for_source (dst_fei,
1070 FIB_SOURCE_INTERFACE);
1072 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
1074 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1078 /* Honor unnumbered interface, if any */
1079 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
1081 /* Source must also be local to subnet of matching interface address. */
1082 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1083 &arp0->ip4_over_ethernet[0].ip4,
1085 src_flags = fib_entry_get_flags (src_fei);
1087 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
1088 (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
1091 * The packet was sent from an address that is not connected nor attached
1092 * i.e. it is not from an address that is covered by a link's sub-net,
1093 * nor is it a already learned host resp.
1095 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
1098 if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1101 * The interface the ARP was received on is not the interface
1102 * on which the covering prefix is configured. Maybe this is a case
1108 /* Reject requests/replies with our local interface address. */
1109 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
1111 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1115 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1116 fib_entry_get_prefix (dst_fei, &pfx0);
1117 if_addr0 = &pfx0.fp_addr.ip4;
1119 /* Fill in ethernet header. */
1120 eth0 = ethernet_buffer_get_header (p0);
1122 /* Trash ARP packets whose ARP-level source addresses do not
1123 match their L2-frame-level source addresses */
1124 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1125 sizeof (eth0->src_address)))
1127 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1131 /* Learn or update sender's mapping only for requests or unicasts
1132 that don't match local interface address. */
1133 if (ethernet_address_cast (eth0->dst_address) ==
1134 ETHERNET_ADDRESS_UNICAST || is_request0)
1136 if (am->limit_arp_cache_size &&
1137 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1138 unset_random_arp_entry ();
1140 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
1141 &arp0->ip4_over_ethernet[0],
1142 0 /* is_static */ );
1143 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1146 /* Only send a reply for requests sent which match a local interface. */
1147 if (!(is_request0 && dst_is_local0))
1151 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1152 ETHERNET_ARP_ERROR_replies_received : error0);
1158 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1159 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1161 /* Send reply back through input interface */
1162 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1163 next0 = ARP_INPUT_NEXT_REPLY_TX;
1165 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1167 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1169 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1170 hw_if0->hw_address, 6);
1171 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1174 /* Hardware must be ethernet-like. */
1175 ASSERT (vec_len (hw_if0->hw_address) == 6);
1177 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1178 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1180 /* Figure out how much to rewind current data from adjacency. */
1181 /* get the adj from the destination's covering connected */
1185 adj_get (fib_entry_get_adj_for_source
1186 (ip4_fib_table_lookup
1187 (ip4_fib_get (fib_index0),
1188 &arp0->ip4_over_ethernet[1].ip4, 31),
1189 FIB_SOURCE_INTERFACE));
1190 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1192 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1197 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1201 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1203 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1204 n_left_to_next, pi0, next0);
1206 n_replies_sent += 1;
1210 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1211 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1212 arp0->ip4_over_ethernet[1].ip4.as_u32))
1214 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1217 /* See if proxy arp is configured for the address */
1220 vnet_sw_interface_t *si;
1221 u32 this_addr = clib_net_to_host_u32
1222 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1225 si = vnet_get_sw_interface (vnm, sw_if_index0);
1227 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1230 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1233 vec_foreach (pa, am->proxy_arps)
1235 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1236 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1238 /* an ARP request hit in the proxy-arp table? */
1239 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1240 (fib_index0 == pa->fib_index))
1242 eth0 = ethernet_buffer_get_header (p0);
1244 arp0->ip4_over_ethernet[1].ip4.data_u32;
1247 * Rewind buffer, direct code above not to
1248 * think too hard about it.
1250 if_addr0 = &proxy_src;
1252 i32 ethernet_start =
1253 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1254 i32 rewind = p0->current_data - ethernet_start;
1255 vlib_buffer_advance (p0, -rewind);
1256 n_proxy_arp_replies_sent++;
1264 next0 = ARP_INPUT_NEXT_DROP;
1265 p0->error = node->errors[error0];
1267 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1268 n_left_to_next, pi0, next0);
1271 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1274 vlib_error_count (vm, node->node_index,
1275 ETHERNET_ARP_ERROR_replies_sent,
1276 n_replies_sent - n_proxy_arp_replies_sent);
1278 vlib_error_count (vm, node->node_index,
1279 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1280 n_proxy_arp_replies_sent);
1281 return frame->n_vectors;
1284 static char *ethernet_arp_error_strings[] = {
1285 #define _(sym,string) string,
1286 foreach_ethernet_arp_error
1291 VLIB_REGISTER_NODE (arp_input_node, static) =
1293 .function = arp_input,
1294 .name = "arp-input",
1295 .vector_size = sizeof (u32),
1296 .n_errors = ETHERNET_ARP_N_ERROR,
1297 .error_strings = ethernet_arp_error_strings,
1298 .n_next_nodes = ARP_INPUT_N_NEXT,
1300 [ARP_INPUT_NEXT_DROP] = "error-drop",
1301 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1303 .format_buffer = format_ethernet_arp_header,
1304 .format_trace = format_ethernet_arp_input_trace,
1309 ip4_arp_entry_sort (void *a1, void *a2)
1311 ethernet_arp_ip4_entry_t *e1 = a1;
1312 ethernet_arp_ip4_entry_t *e2 = a2;
1315 vnet_main_t *vnm = vnet_get_main ();
1317 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1319 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1323 ethernet_arp_ip4_entry_t *
1324 ip4_neighbor_entries (u32 sw_if_index)
1326 ethernet_arp_main_t *am = ðernet_arp_main;
1327 ethernet_arp_ip4_entry_t *n, *ns = 0;
1330 pool_foreach (n, am->ip4_entry_pool, ({
1331 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1333 vec_add1 (ns, n[0]);
1338 vec_sort_with_function (ns, ip4_arp_entry_sort);
1342 static clib_error_t *
1343 show_ip4_arp (vlib_main_t * vm,
1344 unformat_input_t * input, vlib_cli_command_t * cmd)
1346 vnet_main_t *vnm = vnet_get_main ();
1347 ethernet_arp_main_t *am = ðernet_arp_main;
1348 ethernet_arp_ip4_entry_t *e, *es;
1349 ethernet_proxy_arp_t *pa;
1350 clib_error_t *error = 0;
1353 /* Filter entries by interface if given. */
1355 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1357 es = ip4_neighbor_entries (sw_if_index);
1360 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1363 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1368 if (vec_len (am->proxy_arps))
1370 vlib_cli_output (vm, "Proxy arps enabled for:");
1371 vec_foreach (pa, am->proxy_arps)
1373 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1375 format_ip4_address, &pa->lo_addr,
1376 format_ip4_address, &pa->hi_addr);
1384 * Display all the IPv4 ARP entries.
1387 * Example of how to display the IPv4 ARP table:
1388 * @cliexstart{show ip arp}
1389 * Time FIB IP4 Flags Ethernet Interface
1390 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1391 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1392 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1393 * Proxy arps enabled for:
1394 * Fib_index 0 6.0.0.1 - 6.0.0.11
1398 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1399 .path = "show ip arp",
1400 .function = show_ip4_arp,
1401 .short_help = "show ip arp",
1407 pg_edit_t l2_type, l3_type;
1408 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1414 } ip4_over_ethernet[2];
1415 } pg_ethernet_arp_header_t;
1418 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1420 /* Initialize fields that are not bit fields in the IP header. */
1421 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1424 _(n_l2_address_bytes);
1425 _(n_l3_address_bytes);
1427 _(ip4_over_ethernet[0].ethernet);
1428 _(ip4_over_ethernet[0].ip4);
1429 _(ip4_over_ethernet[1].ethernet);
1430 _(ip4_over_ethernet[1].ip4);
1435 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1437 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1438 pg_ethernet_arp_header_t *p;
1441 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1443 pg_ethernet_arp_header_init (p);
1446 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1447 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1448 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1449 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1451 if (!unformat (input, "%U: %U/%U -> %U/%U",
1453 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1455 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1457 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1459 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1461 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1463 /* Free up any edits we may have added. */
1464 pg_free_edit_group (s);
1471 ip4_set_arp_limit (u32 arp_limit)
1473 ethernet_arp_main_t *am = ðernet_arp_main;
1475 am->limit_arp_cache_size = arp_limit;
1480 * @brief Control Plane hook to remove an ARP entry
1483 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1484 u32 sw_if_index, void *a_arg)
1486 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1487 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1489 args.sw_if_index = sw_if_index;
1490 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1491 clib_memcpy (&args.a, a, sizeof (*a));
1493 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1494 (u8 *) & args, sizeof (args));
1499 * @brief Internally generated event to flush the ARP cache on an
1500 * interface state change event.
1501 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1502 * address from the corresponding adjacencies.
1505 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1506 u32 sw_if_index, void *a_arg)
1508 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1509 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1511 args.sw_if_index = sw_if_index;
1512 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1513 clib_memcpy (&args.a, a, sizeof (*a));
1515 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1516 (u8 *) & args, sizeof (args));
1521 * @brief Internally generated event to populate the ARP cache on an
1522 * interface state change event.
1523 * For static entries this will re-source the adjacencies.
1525 * @param sw_if_index The interface on which the ARP entires are acted
1528 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1529 u32 sw_if_index, void *a_arg)
1531 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1532 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1534 args.sw_if_index = sw_if_index;
1535 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1536 clib_memcpy (&args.a, a, sizeof (*a));
1538 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1539 (u8 *) & args, sizeof (args));
1544 * arp_add_del_interface_address
1546 * callback when an interface address is added or deleted
1549 arp_add_del_interface_address (ip4_main_t * im,
1552 ip4_address_t * address,
1554 u32 if_address_index, u32 is_del)
1557 * Flush the ARP cache of all entries covered by the address
1558 * that is being removed.
1560 ethernet_arp_main_t *am = ðernet_arp_main;
1561 ethernet_arp_ip4_entry_t *e;
1563 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
1568 ethernet_arp_interface_t *eai;
1569 u32 i, *to_delete = 0;
1572 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1575 hash_foreach_pair (pair, eai->arp_entries,
1577 e = pool_elt_at_index(am->ip4_entry_pool,
1579 if (ip4_destination_matches_route (im, &e->ip4_address,
1580 address, address_length))
1582 vec_add1 (to_delete, e - am->ip4_entry_pool);
1587 for (i = 0; i < vec_len (to_delete); i++)
1589 ethernet_arp_ip4_over_ethernet_address_t delme;
1590 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1592 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1593 delme.ip4.as_u32 = e->ip4_address.as_u32;
1595 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1596 e->sw_if_index, &delme);
1599 vec_free (to_delete);
1603 static clib_error_t *
1604 ethernet_arp_init (vlib_main_t * vm)
1606 ethernet_arp_main_t *am = ðernet_arp_main;
1607 ip4_main_t *im = &ip4_main;
1608 clib_error_t *error;
1611 if ((error = vlib_call_init_function (vm, ethernet_init)))
1614 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1616 pn = pg_get_node (arp_input_node.index);
1617 pn->unformat_edit = unformat_pg_arp_header;
1619 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1620 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1621 foreach_ethernet_arp_opcode;
1624 /* $$$ configurable */
1625 am->limit_arp_cache_size = 50000;
1627 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1628 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1630 /* don't trace ARP error packets */
1632 vlib_node_runtime_t *rt =
1633 vlib_node_get_runtime (vm, arp_input_node.index);
1636 vnet_pcap_drop_trace_filter_add_del \
1637 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1639 foreach_ethernet_arp_error
1643 ip4_add_del_interface_address_callback_t cb;
1644 cb.function = arp_add_del_interface_address;
1645 cb.function_opaque = 0;
1646 vec_add1 (im->add_del_interface_address_callbacks, cb);
1651 VLIB_INIT_FUNCTION (ethernet_arp_init);
1654 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1656 ethernet_arp_main_t *am = ðernet_arp_main;
1658 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
1659 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1660 pool_put (am->ip4_entry_pool, e);
1664 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1665 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1668 ethernet_arp_main_t *am = ðernet_arp_main;
1669 ethernet_arp_ip4_entry_t *e;
1670 ethernet_arp_interface_t *eai;
1672 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1674 e = arp_entry_find (eai, &args->a.ip4);
1678 arp_entry_free (eai, e);
1680 adj_nbr_walk_nh4 (e->sw_if_index,
1681 &e->ip4_address, arp_mk_incomplete_walk, NULL);
1688 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1689 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1692 ethernet_arp_main_t *am = ðernet_arp_main;
1693 ethernet_arp_ip4_entry_t *e;
1694 ethernet_arp_interface_t *eai;
1696 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1698 e = arp_entry_find (eai, &args->a.ip4);
1702 adj_nbr_walk_nh4 (e->sw_if_index,
1703 &e->ip4_address, arp_mk_incomplete_walk, e);
1706 * The difference between flush and unset, is that an unset
1707 * means delete for static and dynamic entries. A flush
1708 * means delete only for dynamic. Flushing is what the DP
1709 * does in response to interface events. unset is only done
1710 * by the control plane.
1712 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
1714 arp_entry_free (eai, e);
1721 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1722 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1725 ethernet_arp_main_t *am = ðernet_arp_main;
1726 ethernet_arp_ip4_entry_t *e;
1727 ethernet_arp_interface_t *eai;
1729 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1731 e = arp_entry_find (eai, &args->a.ip4);
1735 adj_nbr_walk_nh4 (e->sw_if_index,
1736 &e->ip4_address, arp_mk_complete_walk, e);
1742 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1745 vnet_main_t *vm = vnet_get_main ();
1746 ASSERT (os_get_cpu_number () == 0);
1748 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1749 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1750 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1751 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1752 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1753 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1755 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1759 * @brief Invoked when the interface's admin state changes
1761 static clib_error_t *
1762 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1763 u32 sw_if_index, u32 flags)
1765 ethernet_arp_main_t *am = ðernet_arp_main;
1766 ethernet_arp_ip4_entry_t *e;
1767 u32 i, *to_delete = 0;
1770 pool_foreach (e, am->ip4_entry_pool,
1772 if (e->sw_if_index == sw_if_index)
1773 vec_add1 (to_delete,
1774 e - am->ip4_entry_pool);
1778 for (i = 0; i < vec_len (to_delete); i++)
1780 ethernet_arp_ip4_over_ethernet_address_t delme;
1781 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1783 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1784 delme.ip4.as_u32 = e->ip4_address.as_u32;
1786 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1788 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1792 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1796 vec_free (to_delete);
1801 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1804 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1809 for (i = 3; i >= 0; i--)
1811 old = a->ip4.as_u8[i];
1812 a->ip4.as_u8[i] += 1;
1813 if (old < a->ip4.as_u8[i])
1817 for (i = 5; i >= 0; i--)
1819 old = a->ethernet[i];
1820 a->ethernet[i] += 1;
1821 if (old < a->ethernet[i])
1827 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1828 u32 sw_if_index, void *a_arg, int is_static)
1830 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1831 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1833 args.sw_if_index = sw_if_index;
1834 args.is_static = is_static;
1836 clib_memcpy (&args.a, a, sizeof (*a));
1838 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1839 (u8 *) & args, sizeof (args));
1844 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1845 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1847 ethernet_arp_main_t *am = ðernet_arp_main;
1848 ethernet_proxy_arp_t *pa;
1849 u32 found_at_index = ~0;
1851 vec_foreach (pa, am->proxy_arps)
1853 if (pa->lo_addr == lo_addr->as_u32
1854 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1856 found_at_index = pa - am->proxy_arps;
1861 if (found_at_index != ~0)
1863 /* Delete, otherwise it's already in the table */
1865 vec_delete (am->proxy_arps, 1, found_at_index);
1868 /* delete, no such entry */
1870 return VNET_API_ERROR_NO_SUCH_ENTRY;
1872 /* add, not in table */
1873 vec_add2 (am->proxy_arps, pa, 1);
1874 pa->lo_addr = lo_addr->as_u32;
1875 pa->hi_addr = hi_addr->as_u32;
1876 pa->fib_index = fib_index;
1881 * Remove any proxy arp entries asdociated with the
1885 vnet_proxy_arp_fib_reset (u32 fib_id)
1887 ip4_main_t *im = &ip4_main;
1888 ethernet_arp_main_t *am = ðernet_arp_main;
1889 ethernet_proxy_arp_t *pa;
1890 u32 *entries_to_delete = 0;
1895 p = hash_get (im->fib_index_by_table_id, fib_id);
1897 return VNET_API_ERROR_NO_SUCH_ENTRY;
1900 vec_foreach (pa, am->proxy_arps)
1902 if (pa->fib_index == fib_index)
1904 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1908 for (i = 0; i < vec_len (entries_to_delete); i++)
1910 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1913 vec_free (entries_to_delete);
1918 static clib_error_t *
1919 ip_arp_add_del_command_fn (vlib_main_t * vm,
1920 unformat_input_t * input, vlib_cli_command_t * cmd)
1922 vnet_main_t *vnm = vnet_get_main ();
1924 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1933 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1935 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1936 if (unformat (input, "%U %U %U",
1937 unformat_vnet_sw_interface, vnm, &sw_if_index,
1938 unformat_ip4_address, &addr.ip4,
1939 unformat_ethernet_address, &addr.ethernet))
1942 else if (unformat (input, "delete") || unformat (input, "del"))
1945 else if (unformat (input, "static"))
1948 else if (unformat (input, "count %d", &count))
1951 else if (unformat (input, "fib-id %d", &fib_id))
1953 ip4_main_t *im = &ip4_main;
1954 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1956 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1960 else if (unformat (input, "proxy %U - %U",
1961 unformat_ip4_address, &lo_addr.ip4,
1962 unformat_ip4_address, &hi_addr.ip4))
1970 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1979 for (i = 0; i < count; i++)
1983 uword event_type, *event_data = 0;
1985 /* Park the debug CLI until the arp entry is installed */
1986 vnet_register_ip4_arp_resolution_event
1987 (vnm, &addr.ip4, vlib_current_process (vm),
1988 1 /* type */ , 0 /* data */ );
1990 vnet_arp_set_ip4_over_ethernet
1991 (vnm, sw_if_index, &addr, is_static);
1993 vlib_process_wait_for_event (vm);
1994 event_type = vlib_process_get_events (vm, &event_data);
1995 vec_reset_length (event_data);
1996 if (event_type != 1)
1997 clib_warning ("event type %d unexpected", event_type);
2000 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
2002 increment_ip4_and_mac_address (&addr);
2007 return clib_error_return (0, "unknown input `%U'",
2008 format_unformat_error, input);
2016 * Add or delete IPv4 ARP cache entries.
2018 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
2019 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
2020 * any order and combination.
2024 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
2025 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
2026 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2027 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
2029 * To add or delete an IPv4 ARP cache entry to or from a specific fib
2031 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2032 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2034 * Add or delete IPv4 static ARP cache entries as follows:
2035 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2036 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2038 * For testing / debugging purposes, the 'set ip arp' command can add or
2039 * delete multiple entries. Supply the 'count N' parameter:
2040 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2043 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2044 .path = "set ip arp",
2046 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2047 .function = ip_arp_add_del_command_fn,
2051 static clib_error_t *
2052 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2054 input, vlib_cli_command_t * cmd)
2056 vnet_main_t *vnm = vnet_get_main ();
2058 vnet_sw_interface_t *si;
2062 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2064 if (unformat (input, "%U", unformat_vnet_sw_interface,
2067 else if (unformat (input, "enable") || unformat (input, "on"))
2069 else if (unformat (input, "disable") || unformat (input, "off"))
2076 return clib_error_return (0, "unknown input '%U'",
2077 format_unformat_error, input);
2079 si = vnet_get_sw_interface (vnm, sw_if_index);
2082 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2084 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2091 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2092 * requests for the indicated address range. Multiple proxy-arp
2093 * ranges may be provisioned.
2095 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2096 * Also, the underlying implementation has not been performance-tuned.
2097 * Avoid creating an unnecessarily large set of ranges.
2100 * To enable proxy arp on a range of addresses, use:
2101 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2102 * Append 'del' to delete a range of proxy ARP addresses:
2103 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2104 * You must then specifically enable proxy arp on individual interfaces:
2105 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2106 * To disable proxy arp on an individual interface:
2107 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2109 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2110 .path = "set interface proxy-arp",
2112 "set interface proxy-arp <intfc> [enable|disable]",
2113 .function = set_int_proxy_arp_command_fn,
2119 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2120 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2124 ARP_TERM_NEXT_L2_OUTPUT,
2129 u32 arp_term_next_node_index[32];
2132 arp_term_l2bd (vlib_main_t * vm,
2133 vlib_node_runtime_t * node, vlib_frame_t * frame)
2135 l2input_main_t *l2im = &l2input_main;
2136 u32 n_left_from, next_index, *from, *to_next;
2137 u32 n_replies_sent = 0;
2138 u16 last_bd_index = ~0;
2139 l2_bridge_domain_t *last_bd_config = 0;
2140 l2_input_config_t *cfg0;
2142 from = vlib_frame_vector_args (frame);
2143 n_left_from = frame->n_vectors;
2144 next_index = node->cached_next_index;
2146 while (n_left_from > 0)
2150 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2152 while (n_left_from > 0 && n_left_to_next > 0)
2155 ethernet_header_t *eth0;
2156 ethernet_arp_header_t *arp0;
2159 u32 pi0, error0, next0, sw_if_index0;
2170 n_left_to_next -= 1;
2172 p0 = vlib_get_buffer (vm, pi0);
2173 eth0 = vlib_buffer_get_current (p0);
2174 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2175 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2176 arp0 = (ethernet_arp_header_t *) l3h0;
2178 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2180 clib_host_to_net_u16
2181 (ETHERNET_ARP_OPCODE_request))))
2184 /* Must be ARP request packet here */
2185 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2186 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2188 u8 *t0 = vlib_add_trace (vm, node, p0,
2189 sizeof (ethernet_arp_input_trace_t));
2190 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2193 error0 = ETHERNET_ARP_ERROR_replies_sent;
2196 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2197 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2200 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2201 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2203 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2208 /* Trash ARP packets whose ARP-level source addresses do not
2209 match their L2-frame-level source addresses */
2212 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2213 sizeof (eth0->src_address))))
2215 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2219 /* Check if anyone want ARP request events for L2 BDs */
2221 pending_resolution_t *mc;
2222 ethernet_arp_main_t *am = ðernet_arp_main;
2223 uword *p = hash_get (am->mac_changes_by_address, 0);
2224 if (p && (vnet_buffer (p0)->l2.shg == 0))
2225 { // Only SHG 0 interface which is more likely local
2226 u32 next_index = p[0];
2227 while (next_index != (u32) ~ 0)
2229 int (*fp) (u32, u8 *, u32, u32);
2231 mc = pool_elt_at_index (am->mac_changes, next_index);
2232 fp = mc->data_callback;
2233 /* Call the callback, return 1 to suppress dup events */
2235 rv = (*fp) (mc->data,
2236 arp0->ip4_over_ethernet[0].ethernet,
2238 arp0->ip4_over_ethernet[0].ip4.as_u32);
2239 /* Signal the resolver process */
2241 vlib_process_signal_event (vm, mc->node_index,
2242 mc->type_opaque, mc->data);
2243 next_index = mc->next_index;
2248 /* lookup BD mac_by_ip4 hash table for MAC entry */
2249 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2250 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2251 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2252 || (last_bd_index == (u16) ~ 0)))
2254 last_bd_index = bd_index0;
2255 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2257 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2259 if (PREDICT_FALSE (!macp0))
2260 goto next_l2_feature; /* MAC not found */
2262 /* MAC found, send ARP reply -
2263 Convert ARP request packet to ARP reply */
2264 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2265 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2266 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2267 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2268 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2269 clib_memcpy (eth0->src_address, macp0, 6);
2270 n_replies_sent += 1;
2273 /* For BVI, need to use l2-fwd node to send ARP reply as
2274 l2-output node cannot output packet to BVI properly */
2275 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2276 if (PREDICT_FALSE (cfg0->bvi))
2278 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2279 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2280 goto next_l2_feature;
2283 /* Send ARP/ND reply back out input interface through l2-output */
2284 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2285 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2286 /* Note that output to VXLAN tunnel will fail due to SHG which
2287 is probably desireable since ARP termination is not intended
2288 for ARP requests from other hosts. If output to VXLAN tunnel is
2289 required, however, can just clear the SHG in packet as follows:
2290 vnet_buffer(p0)->l2.shg = 0; */
2291 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2292 to_next, n_left_to_next, pi0,
2297 /* IP6 ND event notification or solicitation handling to generate
2298 local response instead of flooding */
2299 iph0 = (ip6_header_t *) l3h0;
2300 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2301 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2302 !ip6_address_is_unspecified
2303 (&iph0->src_address)))
2305 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2306 if (vnet_ip6_nd_term
2307 (vm, node, p0, eth0, iph0, sw_if_index0,
2308 vnet_buffer (p0)->l2.bd_index, vnet_buffer (p0)->l2.shg))
2309 goto output_response;
2314 u32 feature_bitmap0 =
2315 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2316 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2318 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2320 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2321 to_next, n_left_to_next,
2327 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2328 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2329 arp0->ip4_over_ethernet[1].ip4.as_u32))
2331 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2333 next0 = ARP_TERM_NEXT_DROP;
2334 p0->error = node->errors[error0];
2336 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2337 to_next, n_left_to_next, pi0,
2341 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2344 vlib_error_count (vm, node->node_index,
2345 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2346 return frame->n_vectors;
2350 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2351 .function = arp_term_l2bd,
2352 .name = "arp-term-l2bd",
2353 .vector_size = sizeof (u32),
2354 .n_errors = ETHERNET_ARP_N_ERROR,
2355 .error_strings = ethernet_arp_error_strings,
2356 .n_next_nodes = ARP_TERM_N_NEXT,
2358 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2359 [ARP_TERM_NEXT_DROP] = "error-drop",
2361 .format_buffer = format_ethernet_arp_header,
2362 .format_trace = format_arp_term_input_trace,
2367 arp_term_init (vlib_main_t * vm)
2369 // Initialize the feature next-node indexes
2370 feat_bitmap_init_next_nodes (vm,
2371 arp_term_l2bd_node.index,
2373 l2input_get_feat_names (),
2374 arp_term_next_node_index);
2378 VLIB_INIT_FUNCTION (arp_term_init);
2381 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2383 if (e->sw_if_index == sw_if_index)
2385 adj_nbr_walk_nh4 (e->sw_if_index,
2386 &e->ip4_address, arp_mk_complete_walk, e);
2391 ethernet_arp_change_mac (u32 sw_if_index)
2393 ethernet_arp_main_t *am = ðernet_arp_main;
2394 ethernet_arp_ip4_entry_t *e;
2397 pool_foreach (e, am->ip4_entry_pool,
2399 change_arp_mac (sw_if_index, e);
2405 * fd.io coding-style-patch-verification: ON
2408 * eval: (c-set-style "gnu")