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 (dst_fei);
1067 conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
1069 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
1071 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1075 /* Honor unnumbered interface, if any */
1076 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
1078 /* Source must also be local to subnet of matching interface address. */
1079 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1080 &arp0->ip4_over_ethernet[0].ip4,
1082 src_flags = fib_entry_get_flags (src_fei);
1084 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
1085 (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
1088 * The packet was sent from an address that is not connected nor attached
1089 * i.e. it is not from an address that is covered by a link's sub-net,
1090 * nor is it a already learned host resp.
1092 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
1095 if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1098 * The interface the ARP was received on is not the interface
1099 * on which the covering prefix is configured. Maybe this is a case
1105 /* Reject requests/replies with our local interface address. */
1106 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
1108 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1112 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1113 fib_entry_get_prefix (dst_fei, &pfx0);
1114 if_addr0 = &pfx0.fp_addr.ip4;
1116 /* Fill in ethernet header. */
1117 eth0 = ethernet_buffer_get_header (p0);
1119 /* Trash ARP packets whose ARP-level source addresses do not
1120 match their L2-frame-level source addresses */
1121 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1122 sizeof (eth0->src_address)))
1124 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1128 /* Learn or update sender's mapping only for requests or unicasts
1129 that don't match local interface address. */
1130 if (ethernet_address_cast (eth0->dst_address) ==
1131 ETHERNET_ADDRESS_UNICAST || is_request0)
1133 if (am->limit_arp_cache_size &&
1134 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1135 unset_random_arp_entry ();
1137 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
1138 &arp0->ip4_over_ethernet[0],
1139 0 /* is_static */ );
1140 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1143 /* Only send a reply for requests sent which match a local interface. */
1144 if (!(is_request0 && dst_is_local0))
1148 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1149 ETHERNET_ARP_ERROR_replies_received : error0);
1155 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1156 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1158 /* Send reply back through input interface */
1159 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1160 next0 = ARP_INPUT_NEXT_REPLY_TX;
1162 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1164 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1166 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1167 hw_if0->hw_address, 6);
1168 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1171 /* Hardware must be ethernet-like. */
1172 ASSERT (vec_len (hw_if0->hw_address) == 6);
1174 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1175 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1177 /* Figure out how much to rewind current data from adjacency. */
1178 /* get the adj from the destination's covering connected */
1182 adj_get (fib_entry_get_adj_for_source
1183 (ip4_fib_table_lookup
1184 (ip4_fib_get (fib_index0),
1185 &arp0->ip4_over_ethernet[1].ip4, 31),
1186 FIB_SOURCE_INTERFACE));
1187 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1189 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1194 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1198 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1200 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1201 n_left_to_next, pi0, next0);
1203 n_replies_sent += 1;
1207 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1208 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1209 arp0->ip4_over_ethernet[1].ip4.as_u32))
1211 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1214 /* See if proxy arp is configured for the address */
1217 vnet_sw_interface_t *si;
1218 u32 this_addr = clib_net_to_host_u32
1219 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1222 si = vnet_get_sw_interface (vnm, sw_if_index0);
1224 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1227 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1230 vec_foreach (pa, am->proxy_arps)
1232 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1233 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1235 /* an ARP request hit in the proxy-arp table? */
1236 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1237 (fib_index0 == pa->fib_index))
1239 eth0 = ethernet_buffer_get_header (p0);
1241 arp0->ip4_over_ethernet[1].ip4.data_u32;
1244 * Rewind buffer, direct code above not to
1245 * think too hard about it.
1247 if_addr0 = &proxy_src;
1249 i32 ethernet_start =
1250 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1251 i32 rewind = p0->current_data - ethernet_start;
1252 vlib_buffer_advance (p0, -rewind);
1253 n_proxy_arp_replies_sent++;
1261 next0 = ARP_INPUT_NEXT_DROP;
1262 p0->error = node->errors[error0];
1264 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1265 n_left_to_next, pi0, next0);
1268 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1271 vlib_error_count (vm, node->node_index,
1272 ETHERNET_ARP_ERROR_replies_sent,
1273 n_replies_sent - n_proxy_arp_replies_sent);
1275 vlib_error_count (vm, node->node_index,
1276 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1277 n_proxy_arp_replies_sent);
1278 return frame->n_vectors;
1281 static char *ethernet_arp_error_strings[] = {
1282 #define _(sym,string) string,
1283 foreach_ethernet_arp_error
1288 VLIB_REGISTER_NODE (arp_input_node, static) =
1290 .function = arp_input,
1291 .name = "arp-input",
1292 .vector_size = sizeof (u32),
1293 .n_errors = ETHERNET_ARP_N_ERROR,
1294 .error_strings = ethernet_arp_error_strings,
1295 .n_next_nodes = ARP_INPUT_N_NEXT,
1297 [ARP_INPUT_NEXT_DROP] = "error-drop",
1298 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1300 .format_buffer = format_ethernet_arp_header,
1301 .format_trace = format_ethernet_arp_input_trace,
1306 ip4_arp_entry_sort (void *a1, void *a2)
1308 ethernet_arp_ip4_entry_t *e1 = a1;
1309 ethernet_arp_ip4_entry_t *e2 = a2;
1312 vnet_main_t *vnm = vnet_get_main ();
1314 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1316 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1320 ethernet_arp_ip4_entry_t *
1321 ip4_neighbor_entries (u32 sw_if_index)
1323 ethernet_arp_main_t *am = ðernet_arp_main;
1324 ethernet_arp_ip4_entry_t *n, *ns = 0;
1327 pool_foreach (n, am->ip4_entry_pool, ({
1328 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1330 vec_add1 (ns, n[0]);
1335 vec_sort_with_function (ns, ip4_arp_entry_sort);
1339 static clib_error_t *
1340 show_ip4_arp (vlib_main_t * vm,
1341 unformat_input_t * input, vlib_cli_command_t * cmd)
1343 vnet_main_t *vnm = vnet_get_main ();
1344 ethernet_arp_main_t *am = ðernet_arp_main;
1345 ethernet_arp_ip4_entry_t *e, *es;
1346 ethernet_proxy_arp_t *pa;
1347 clib_error_t *error = 0;
1350 /* Filter entries by interface if given. */
1352 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1354 es = ip4_neighbor_entries (sw_if_index);
1357 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1360 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1365 if (vec_len (am->proxy_arps))
1367 vlib_cli_output (vm, "Proxy arps enabled for:");
1368 vec_foreach (pa, am->proxy_arps)
1370 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1372 format_ip4_address, &pa->lo_addr,
1373 format_ip4_address, &pa->hi_addr);
1381 * Display all the IPv4 ARP entries.
1384 * Example of how to display the IPv4 ARP table:
1385 * @cliexstart{show ip arp}
1386 * Time FIB IP4 Flags Ethernet Interface
1387 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1388 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1389 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1390 * Proxy arps enabled for:
1391 * Fib_index 0 6.0.0.1 - 6.0.0.11
1395 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1396 .path = "show ip arp",
1397 .function = show_ip4_arp,
1398 .short_help = "show ip arp",
1404 pg_edit_t l2_type, l3_type;
1405 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1411 } ip4_over_ethernet[2];
1412 } pg_ethernet_arp_header_t;
1415 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1417 /* Initialize fields that are not bit fields in the IP header. */
1418 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1421 _(n_l2_address_bytes);
1422 _(n_l3_address_bytes);
1424 _(ip4_over_ethernet[0].ethernet);
1425 _(ip4_over_ethernet[0].ip4);
1426 _(ip4_over_ethernet[1].ethernet);
1427 _(ip4_over_ethernet[1].ip4);
1432 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1434 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1435 pg_ethernet_arp_header_t *p;
1438 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1440 pg_ethernet_arp_header_init (p);
1443 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1444 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1445 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1446 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1448 if (!unformat (input, "%U: %U/%U -> %U/%U",
1450 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1452 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1454 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1456 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1458 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1460 /* Free up any edits we may have added. */
1461 pg_free_edit_group (s);
1468 ip4_set_arp_limit (u32 arp_limit)
1470 ethernet_arp_main_t *am = ðernet_arp_main;
1472 am->limit_arp_cache_size = arp_limit;
1477 * @brief Control Plane hook to remove an ARP entry
1480 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1481 u32 sw_if_index, void *a_arg)
1483 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1484 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1486 args.sw_if_index = sw_if_index;
1487 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1488 clib_memcpy (&args.a, a, sizeof (*a));
1490 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1491 (u8 *) & args, sizeof (args));
1496 * @brief Internally generated event to flush the ARP cache on an
1497 * interface state change event.
1498 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1499 * address from the corresponding adjacencies.
1502 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1503 u32 sw_if_index, void *a_arg)
1505 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1506 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1508 args.sw_if_index = sw_if_index;
1509 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1510 clib_memcpy (&args.a, a, sizeof (*a));
1512 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1513 (u8 *) & args, sizeof (args));
1518 * @brief Internally generated event to populate the ARP cache on an
1519 * interface state change event.
1520 * For static entries this will re-source the adjacencies.
1522 * @param sw_if_index The interface on which the ARP entires are acted
1525 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1526 u32 sw_if_index, void *a_arg)
1528 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1529 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1531 args.sw_if_index = sw_if_index;
1532 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1533 clib_memcpy (&args.a, a, sizeof (*a));
1535 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1536 (u8 *) & args, sizeof (args));
1541 * arp_add_del_interface_address
1543 * callback when an interface address is added or deleted
1546 arp_add_del_interface_address (ip4_main_t * im,
1549 ip4_address_t * address,
1551 u32 if_address_index, u32 is_del)
1554 * Flush the ARP cache of all entries covered by the address
1555 * that is being removed.
1557 ethernet_arp_main_t *am = ðernet_arp_main;
1558 ethernet_arp_ip4_entry_t *e;
1560 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
1565 ethernet_arp_interface_t *eai;
1566 u32 i, *to_delete = 0;
1569 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1572 hash_foreach_pair (pair, eai->arp_entries,
1574 e = pool_elt_at_index(am->ip4_entry_pool,
1576 if (ip4_destination_matches_route (im, &e->ip4_address,
1577 address, address_length))
1579 vec_add1 (to_delete, e - am->ip4_entry_pool);
1584 for (i = 0; i < vec_len (to_delete); i++)
1586 ethernet_arp_ip4_over_ethernet_address_t delme;
1587 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1589 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1590 delme.ip4.as_u32 = e->ip4_address.as_u32;
1592 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1593 e->sw_if_index, &delme);
1596 vec_free (to_delete);
1600 static clib_error_t *
1601 ethernet_arp_init (vlib_main_t * vm)
1603 ethernet_arp_main_t *am = ðernet_arp_main;
1604 ip4_main_t *im = &ip4_main;
1605 clib_error_t *error;
1608 if ((error = vlib_call_init_function (vm, ethernet_init)))
1611 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1613 pn = pg_get_node (arp_input_node.index);
1614 pn->unformat_edit = unformat_pg_arp_header;
1616 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1617 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1618 foreach_ethernet_arp_opcode;
1621 /* $$$ configurable */
1622 am->limit_arp_cache_size = 50000;
1624 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1625 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1627 /* don't trace ARP error packets */
1629 vlib_node_runtime_t *rt =
1630 vlib_node_get_runtime (vm, arp_input_node.index);
1633 vnet_pcap_drop_trace_filter_add_del \
1634 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1636 foreach_ethernet_arp_error
1640 ip4_add_del_interface_address_callback_t cb;
1641 cb.function = arp_add_del_interface_address;
1642 cb.function_opaque = 0;
1643 vec_add1 (im->add_del_interface_address_callbacks, cb);
1648 VLIB_INIT_FUNCTION (ethernet_arp_init);
1651 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1653 ethernet_arp_main_t *am = ðernet_arp_main;
1655 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
1656 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1657 pool_put (am->ip4_entry_pool, e);
1661 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1662 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1665 ethernet_arp_main_t *am = ðernet_arp_main;
1666 ethernet_arp_ip4_entry_t *e;
1667 ethernet_arp_interface_t *eai;
1669 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1671 e = arp_entry_find (eai, &args->a.ip4);
1675 arp_entry_free (eai, e);
1677 adj_nbr_walk_nh4 (e->sw_if_index,
1678 &e->ip4_address, arp_mk_incomplete_walk, NULL);
1685 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1686 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1689 ethernet_arp_main_t *am = ðernet_arp_main;
1690 ethernet_arp_ip4_entry_t *e;
1691 ethernet_arp_interface_t *eai;
1693 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1695 e = arp_entry_find (eai, &args->a.ip4);
1699 adj_nbr_walk_nh4 (e->sw_if_index,
1700 &e->ip4_address, arp_mk_incomplete_walk, e);
1703 * The difference between flush and unset, is that an unset
1704 * means delete for static and dynamic entries. A flush
1705 * means delete only for dynamic. Flushing is what the DP
1706 * does in response to interface events. unset is only done
1707 * by the control plane.
1709 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
1711 arp_entry_free (eai, e);
1718 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1719 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1722 ethernet_arp_main_t *am = ðernet_arp_main;
1723 ethernet_arp_ip4_entry_t *e;
1724 ethernet_arp_interface_t *eai;
1726 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1728 e = arp_entry_find (eai, &args->a.ip4);
1732 adj_nbr_walk_nh4 (e->sw_if_index,
1733 &e->ip4_address, arp_mk_complete_walk, e);
1739 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1742 vnet_main_t *vm = vnet_get_main ();
1743 ASSERT (os_get_cpu_number () == 0);
1745 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1746 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1747 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1748 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1749 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1750 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1752 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1756 * @brief Invoked when the interface's admin state changes
1758 static clib_error_t *
1759 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1760 u32 sw_if_index, u32 flags)
1762 ethernet_arp_main_t *am = ðernet_arp_main;
1763 ethernet_arp_ip4_entry_t *e;
1764 u32 i, *to_delete = 0;
1767 pool_foreach (e, am->ip4_entry_pool,
1769 if (e->sw_if_index == sw_if_index)
1770 vec_add1 (to_delete,
1771 e - am->ip4_entry_pool);
1775 for (i = 0; i < vec_len (to_delete); i++)
1777 ethernet_arp_ip4_over_ethernet_address_t delme;
1778 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1780 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1781 delme.ip4.as_u32 = e->ip4_address.as_u32;
1783 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1785 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1789 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1793 vec_free (to_delete);
1798 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1801 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1806 for (i = 3; i >= 0; i--)
1808 old = a->ip4.as_u8[i];
1809 a->ip4.as_u8[i] += 1;
1810 if (old < a->ip4.as_u8[i])
1814 for (i = 5; i >= 0; i--)
1816 old = a->ethernet[i];
1817 a->ethernet[i] += 1;
1818 if (old < a->ethernet[i])
1824 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1825 u32 sw_if_index, void *a_arg, int is_static)
1827 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1828 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1830 args.sw_if_index = sw_if_index;
1831 args.is_static = is_static;
1833 clib_memcpy (&args.a, a, sizeof (*a));
1835 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1836 (u8 *) & args, sizeof (args));
1841 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1842 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1844 ethernet_arp_main_t *am = ðernet_arp_main;
1845 ethernet_proxy_arp_t *pa;
1846 u32 found_at_index = ~0;
1848 vec_foreach (pa, am->proxy_arps)
1850 if (pa->lo_addr == lo_addr->as_u32
1851 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1853 found_at_index = pa - am->proxy_arps;
1858 if (found_at_index != ~0)
1860 /* Delete, otherwise it's already in the table */
1862 vec_delete (am->proxy_arps, 1, found_at_index);
1865 /* delete, no such entry */
1867 return VNET_API_ERROR_NO_SUCH_ENTRY;
1869 /* add, not in table */
1870 vec_add2 (am->proxy_arps, pa, 1);
1871 pa->lo_addr = lo_addr->as_u32;
1872 pa->hi_addr = hi_addr->as_u32;
1873 pa->fib_index = fib_index;
1878 * Remove any proxy arp entries asdociated with the
1882 vnet_proxy_arp_fib_reset (u32 fib_id)
1884 ip4_main_t *im = &ip4_main;
1885 ethernet_arp_main_t *am = ðernet_arp_main;
1886 ethernet_proxy_arp_t *pa;
1887 u32 *entries_to_delete = 0;
1892 p = hash_get (im->fib_index_by_table_id, fib_id);
1894 return VNET_API_ERROR_NO_SUCH_ENTRY;
1897 vec_foreach (pa, am->proxy_arps)
1899 if (pa->fib_index == fib_index)
1901 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1905 for (i = 0; i < vec_len (entries_to_delete); i++)
1907 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1910 vec_free (entries_to_delete);
1915 static clib_error_t *
1916 ip_arp_add_del_command_fn (vlib_main_t * vm,
1917 unformat_input_t * input, vlib_cli_command_t * cmd)
1919 vnet_main_t *vnm = vnet_get_main ();
1921 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1930 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1932 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1933 if (unformat (input, "%U %U %U",
1934 unformat_vnet_sw_interface, vnm, &sw_if_index,
1935 unformat_ip4_address, &addr.ip4,
1936 unformat_ethernet_address, &addr.ethernet))
1939 else if (unformat (input, "delete") || unformat (input, "del"))
1942 else if (unformat (input, "static"))
1945 else if (unformat (input, "count %d", &count))
1948 else if (unformat (input, "fib-id %d", &fib_id))
1950 ip4_main_t *im = &ip4_main;
1951 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1953 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1957 else if (unformat (input, "proxy %U - %U",
1958 unformat_ip4_address, &lo_addr.ip4,
1959 unformat_ip4_address, &hi_addr.ip4))
1967 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1976 for (i = 0; i < count; i++)
1980 uword event_type, *event_data = 0;
1982 /* Park the debug CLI until the arp entry is installed */
1983 vnet_register_ip4_arp_resolution_event
1984 (vnm, &addr.ip4, vlib_current_process (vm),
1985 1 /* type */ , 0 /* data */ );
1987 vnet_arp_set_ip4_over_ethernet
1988 (vnm, sw_if_index, &addr, is_static);
1990 vlib_process_wait_for_event (vm);
1991 event_type = vlib_process_get_events (vm, &event_data);
1992 vec_reset_length (event_data);
1993 if (event_type != 1)
1994 clib_warning ("event type %d unexpected", event_type);
1997 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
1999 increment_ip4_and_mac_address (&addr);
2004 return clib_error_return (0, "unknown input `%U'",
2005 format_unformat_error, input);
2013 * Add or delete IPv4 ARP cache entries.
2015 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
2016 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
2017 * any order and combination.
2021 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
2022 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
2023 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2024 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
2026 * To add or delete an IPv4 ARP cache entry to or from a specific fib
2028 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2029 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2031 * Add or delete IPv4 static ARP cache entries as follows:
2032 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2033 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2035 * For testing / debugging purposes, the 'set ip arp' command can add or
2036 * delete multiple entries. Supply the 'count N' parameter:
2037 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2040 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2041 .path = "set ip arp",
2043 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2044 .function = ip_arp_add_del_command_fn,
2048 static clib_error_t *
2049 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2051 input, vlib_cli_command_t * cmd)
2053 vnet_main_t *vnm = vnet_get_main ();
2055 vnet_sw_interface_t *si;
2059 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2061 if (unformat (input, "%U", unformat_vnet_sw_interface,
2064 else if (unformat (input, "enable") || unformat (input, "on"))
2066 else if (unformat (input, "disable") || unformat (input, "off"))
2073 return clib_error_return (0, "unknown input '%U'",
2074 format_unformat_error, input);
2076 si = vnet_get_sw_interface (vnm, sw_if_index);
2079 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2081 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2088 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2089 * requests for the indicated address range. Multiple proxy-arp
2090 * ranges may be provisioned.
2092 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2093 * Also, the underlying implementation has not been performance-tuned.
2094 * Avoid creating an unnecessarily large set of ranges.
2097 * To enable proxy arp on a range of addresses, use:
2098 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2099 * Append 'del' to delete a range of proxy ARP addresses:
2100 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2101 * You must then specifically enable proxy arp on individual interfaces:
2102 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2103 * To disable proxy arp on an individual interface:
2104 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2106 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2107 .path = "set interface proxy-arp",
2109 "set interface proxy-arp <intfc> [enable|disable]",
2110 .function = set_int_proxy_arp_command_fn,
2116 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2117 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2121 ARP_TERM_NEXT_L2_OUTPUT,
2126 u32 arp_term_next_node_index[32];
2129 arp_term_l2bd (vlib_main_t * vm,
2130 vlib_node_runtime_t * node, vlib_frame_t * frame)
2132 l2input_main_t *l2im = &l2input_main;
2133 u32 n_left_from, next_index, *from, *to_next;
2134 u32 n_replies_sent = 0;
2135 u16 last_bd_index = ~0;
2136 l2_bridge_domain_t *last_bd_config = 0;
2137 l2_input_config_t *cfg0;
2139 from = vlib_frame_vector_args (frame);
2140 n_left_from = frame->n_vectors;
2141 next_index = node->cached_next_index;
2143 while (n_left_from > 0)
2147 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2149 while (n_left_from > 0 && n_left_to_next > 0)
2152 ethernet_header_t *eth0;
2153 ethernet_arp_header_t *arp0;
2156 u32 pi0, error0, next0, sw_if_index0;
2167 n_left_to_next -= 1;
2169 p0 = vlib_get_buffer (vm, pi0);
2170 eth0 = vlib_buffer_get_current (p0);
2171 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2172 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2173 arp0 = (ethernet_arp_header_t *) l3h0;
2175 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2177 clib_host_to_net_u16
2178 (ETHERNET_ARP_OPCODE_request))))
2181 /* Must be ARP request packet here */
2182 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2183 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2185 u8 *t0 = vlib_add_trace (vm, node, p0,
2186 sizeof (ethernet_arp_input_trace_t));
2187 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2190 error0 = ETHERNET_ARP_ERROR_replies_sent;
2193 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2194 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2197 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2198 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2200 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2205 /* Trash ARP packets whose ARP-level source addresses do not
2206 match their L2-frame-level source addresses */
2209 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2210 sizeof (eth0->src_address))))
2212 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2216 /* Check if anyone want ARP request events for L2 BDs */
2218 pending_resolution_t *mc;
2219 ethernet_arp_main_t *am = ðernet_arp_main;
2220 uword *p = hash_get (am->mac_changes_by_address, 0);
2221 if (p && (vnet_buffer (p0)->l2.shg == 0))
2222 { // Only SHG 0 interface which is more likely local
2223 u32 next_index = p[0];
2224 while (next_index != (u32) ~ 0)
2226 int (*fp) (u32, u8 *, u32, u32);
2228 mc = pool_elt_at_index (am->mac_changes, next_index);
2229 fp = mc->data_callback;
2230 /* Call the callback, return 1 to suppress dup events */
2232 rv = (*fp) (mc->data,
2233 arp0->ip4_over_ethernet[0].ethernet,
2235 arp0->ip4_over_ethernet[0].ip4.as_u32);
2236 /* Signal the resolver process */
2238 vlib_process_signal_event (vm, mc->node_index,
2239 mc->type_opaque, mc->data);
2240 next_index = mc->next_index;
2245 /* lookup BD mac_by_ip4 hash table for MAC entry */
2246 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2247 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2248 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2249 || (last_bd_index == (u16) ~ 0)))
2251 last_bd_index = bd_index0;
2252 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2254 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2256 if (PREDICT_FALSE (!macp0))
2257 goto next_l2_feature; /* MAC not found */
2259 /* MAC found, send ARP reply -
2260 Convert ARP request packet to ARP reply */
2261 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2262 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2263 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2264 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2265 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2266 clib_memcpy (eth0->src_address, macp0, 6);
2267 n_replies_sent += 1;
2270 /* For BVI, need to use l2-fwd node to send ARP reply as
2271 l2-output node cannot output packet to BVI properly */
2272 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2273 if (PREDICT_FALSE (cfg0->bvi))
2275 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2276 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2277 goto next_l2_feature;
2280 /* Send ARP/ND reply back out input interface through l2-output */
2281 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2282 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2283 /* Note that output to VXLAN tunnel will fail due to SHG which
2284 is probably desireable since ARP termination is not intended
2285 for ARP requests from other hosts. If output to VXLAN tunnel is
2286 required, however, can just clear the SHG in packet as follows:
2287 vnet_buffer(p0)->l2.shg = 0; */
2288 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2289 to_next, n_left_to_next, pi0,
2294 /* IP6 ND event notification or solicitation handling to generate
2295 local response instead of flooding */
2296 iph0 = (ip6_header_t *) l3h0;
2297 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2298 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2299 !ip6_address_is_unspecified
2300 (&iph0->src_address)))
2302 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2303 if (vnet_ip6_nd_term
2304 (vm, node, p0, eth0, iph0, sw_if_index0,
2305 vnet_buffer (p0)->l2.bd_index, vnet_buffer (p0)->l2.shg))
2306 goto output_response;
2311 u32 feature_bitmap0 =
2312 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2313 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2315 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2317 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2318 to_next, n_left_to_next,
2324 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2325 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2326 arp0->ip4_over_ethernet[1].ip4.as_u32))
2328 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2330 next0 = ARP_TERM_NEXT_DROP;
2331 p0->error = node->errors[error0];
2333 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2334 to_next, n_left_to_next, pi0,
2338 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2341 vlib_error_count (vm, node->node_index,
2342 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2343 return frame->n_vectors;
2347 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2348 .function = arp_term_l2bd,
2349 .name = "arp-term-l2bd",
2350 .vector_size = sizeof (u32),
2351 .n_errors = ETHERNET_ARP_N_ERROR,
2352 .error_strings = ethernet_arp_error_strings,
2353 .n_next_nodes = ARP_TERM_N_NEXT,
2355 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2356 [ARP_TERM_NEXT_DROP] = "error-drop",
2358 .format_buffer = format_ethernet_arp_header,
2359 .format_trace = format_arp_term_input_trace,
2364 arp_term_init (vlib_main_t * vm)
2366 // Initialize the feature next-node indexes
2367 feat_bitmap_init_next_nodes (vm,
2368 arp_term_l2bd_node.index,
2370 l2input_get_feat_names (),
2371 arp_term_next_node_index);
2375 VLIB_INIT_FUNCTION (arp_term_init);
2378 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2380 if (e->sw_if_index == sw_if_index)
2382 adj_nbr_walk_nh4 (e->sw_if_index,
2383 &e->ip4_address, arp_mk_complete_walk, e);
2388 ethernet_arp_change_mac (u32 sw_if_index)
2390 ethernet_arp_main_t *am = ðernet_arp_main;
2391 ethernet_arp_ip4_entry_t *e;
2394 pool_foreach (e, am->ip4_entry_pool,
2396 change_arp_mac (sw_if_index, e);
2402 * fd.io coding-style-patch-verification: ON
2405 * eval: (c-set-style "gnu")