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") \
795 _ (interface_not_ip_enabled, "Interface is not IP enabled") \
799 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
800 foreach_ethernet_arp_error
802 ETHERNET_ARP_N_ERROR,
803 } ethernet_arp_input_error_t;
807 unset_random_arp_entry (void)
809 ethernet_arp_main_t *am = ðernet_arp_main;
810 ethernet_arp_ip4_entry_t *e;
811 vnet_main_t *vnm = vnet_get_main ();
812 ethernet_arp_ip4_over_ethernet_address_t delme;
815 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
816 am->arp_delete_rotor = index;
818 /* Try again from elt 0, could happen if an intfc goes down */
821 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
822 am->arp_delete_rotor = index;
825 /* Nothing left in the pool */
829 e = pool_elt_at_index (am->ip4_entry_pool, index);
831 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
832 delme.ip4.as_u32 = e->ip4_address.as_u32;
834 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
838 arp_unnumbered (vlib_buffer_t * p0,
839 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
841 vlib_main_t *vm = vlib_get_main ();
842 vnet_main_t *vnm = vnet_get_main ();
843 vnet_interface_main_t *vim = &vnm->interface_main;
844 vnet_sw_interface_t *si;
845 vnet_hw_interface_t *hi;
846 u32 unnum_src_sw_if_index;
847 u32 *broadcast_swifs = 0;
852 u8 dst_mac_address[6];
854 ethernet_arp_header_t *arp0;
856 /* Save the dst mac address */
857 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
859 /* Figure out which sw_if_index supplied the address */
860 unnum_src_sw_if_index = sw_if_index;
862 /* Track down all users of the unnumbered source */
864 pool_foreach (si, vim->sw_interfaces,
866 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
867 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
869 vec_add1 (broadcast_swifs, si->sw_if_index);
874 /* If there are no interfaces un-unmbered to this interface,
876 if (0 == vec_len (broadcast_swifs))
879 /* Allocate buffering if we need it */
880 if (vec_len (broadcast_swifs) > 1)
882 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
883 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
884 _vec_len (buffers) = n_alloc;
885 for (i = 0; i < n_alloc; i++)
887 b0 = vlib_get_buffer (vm, buffers[i]);
889 /* xerox (partially built) ARP pkt */
890 clib_memcpy (b0->data, p0->data,
891 p0->current_length + p0->current_data);
892 b0->current_data = p0->current_data;
893 b0->current_length = p0->current_length;
894 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
895 vnet_buffer (p0)->sw_if_index[VLIB_RX];
899 vec_insert (buffers, 1, 0);
902 for (i = 0; i < vec_len (buffers); i++)
904 b0 = vlib_get_buffer (vm, buffers[i]);
905 arp0 = vlib_buffer_get_current (b0);
907 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
908 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
910 /* For decoration, most likely */
911 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
913 /* Fix ARP pkt src address */
914 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
916 /* Build L2 encaps for this swif */
917 header_size = sizeof (ethernet_header_t);
918 if (si->sub.eth.flags.one_tag)
920 else if (si->sub.eth.flags.two_tags)
923 vlib_buffer_advance (b0, -header_size);
924 eth0 = vlib_buffer_get_current (b0);
926 if (si->sub.eth.flags.one_tag)
928 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
930 eth0->type = si->sub.eth.flags.dot1ad ?
931 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
932 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
933 outer->priority_cfi_and_id =
934 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
935 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
938 else if (si->sub.eth.flags.two_tags)
940 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
941 ethernet_vlan_header_t *inner = (void *) (outer + 1);
943 eth0->type = si->sub.eth.flags.dot1ad ?
944 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
945 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
946 outer->priority_cfi_and_id =
947 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
948 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
949 inner->priority_cfi_and_id =
950 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
951 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
956 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
959 /* Restore the original dst address, set src address */
960 clib_memcpy (eth0->dst_address, dst_mac_address,
961 sizeof (eth0->dst_address));
962 clib_memcpy (eth0->src_address, hi->hw_address,
963 sizeof (eth0->src_address));
965 /* Transmit replicas */
969 vlib_get_frame_to_node (vm, hi->output_node_index);
970 u32 *to_next = vlib_frame_vector_args (f);
971 to_next[0] = buffers[i];
973 vlib_put_frame_to_node (vm, hi->output_node_index, f);
977 /* The regular path outputs the original pkt.. */
978 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
980 vec_free (broadcast_swifs);
987 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
989 ethernet_arp_main_t *am = ðernet_arp_main;
990 vnet_main_t *vnm = vnet_get_main ();
991 ip4_main_t *im4 = &ip4_main;
992 u32 n_left_from, next_index, *from, *to_next;
993 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
995 from = vlib_frame_vector_args (frame);
996 n_left_from = frame->n_vectors;
997 next_index = node->cached_next_index;
999 if (node->flags & VLIB_NODE_FLAG_TRACE)
1000 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1002 sizeof (ethernet_arp_input_trace_t));
1004 while (n_left_from > 0)
1008 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1010 while (n_left_from > 0 && n_left_to_next > 0)
1013 vnet_hw_interface_t *hw_if0;
1014 ethernet_arp_header_t *arp0;
1015 ethernet_header_t *eth0;
1016 ip_adjacency_t *adj0;
1017 ip4_address_t *if_addr0, proxy_src;
1018 u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
1019 u8 is_request0, dst_is_local0, is_unnum0;
1020 ethernet_proxy_arp_t *pa;
1021 fib_node_index_t dst_fei, src_fei;
1023 fib_entry_flag_t src_flags, dst_flags;
1030 n_left_to_next -= 1;
1033 p0 = vlib_get_buffer (vm, pi0);
1034 arp0 = vlib_buffer_get_current (p0);
1036 is_request0 = arp0->opcode
1037 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
1039 error0 = ETHERNET_ARP_ERROR_replies_sent;
1043 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1044 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1047 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
1048 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
1050 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1052 /* not playing the ARP game if the interface is not IPv4 enabled */
1054 (im4->ip_enabled_by_sw_if_index[sw_if_index0] == 0 ?
1055 ETHERNET_ARP_ERROR_interface_not_ip_enabled : error0);
1060 /* Check that IP address is local and matches incoming interface. */
1061 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1062 if (~0 == fib_index0)
1064 error0 = ETHERNET_ARP_ERROR_interface_no_table;
1068 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1069 &arp0->ip4_over_ethernet[1].ip4,
1071 dst_flags = fib_entry_get_flags (dst_fei);
1073 conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
1075 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
1077 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1081 /* Honor unnumbered interface, if any */
1082 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
1084 /* Source must also be local to subnet of matching interface address. */
1085 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1086 &arp0->ip4_over_ethernet[0].ip4,
1088 src_flags = fib_entry_get_flags (src_fei);
1090 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
1091 (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
1094 * The packet was sent from an address that is not connected nor attached
1095 * i.e. it is not from an address that is covered by a link's sub-net,
1096 * nor is it a already learned host resp.
1098 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
1101 if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1104 * The interface the ARP was received on is not the interface
1105 * on which the covering prefix is configured. Maybe this is a case
1111 /* Reject requests/replies with our local interface address. */
1112 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
1114 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1118 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1119 fib_entry_get_prefix (dst_fei, &pfx0);
1120 if_addr0 = &pfx0.fp_addr.ip4;
1122 /* Fill in ethernet header. */
1123 eth0 = ethernet_buffer_get_header (p0);
1125 /* Trash ARP packets whose ARP-level source addresses do not
1126 match their L2-frame-level source addresses */
1127 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1128 sizeof (eth0->src_address)))
1130 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1134 /* Learn or update sender's mapping only for requests or unicasts
1135 that don't match local interface address. */
1136 if (ethernet_address_cast (eth0->dst_address) ==
1137 ETHERNET_ADDRESS_UNICAST || is_request0)
1139 if (am->limit_arp_cache_size &&
1140 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1141 unset_random_arp_entry ();
1143 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
1144 &arp0->ip4_over_ethernet[0],
1145 0 /* is_static */ );
1146 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1149 /* Only send a reply for requests sent which match a local interface. */
1150 if (!(is_request0 && dst_is_local0))
1154 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1155 ETHERNET_ARP_ERROR_replies_received : error0);
1161 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1162 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1164 /* Send reply back through input interface */
1165 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1166 next0 = ARP_INPUT_NEXT_REPLY_TX;
1168 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1170 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1172 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1173 hw_if0->hw_address, 6);
1174 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1177 /* Hardware must be ethernet-like. */
1178 ASSERT (vec_len (hw_if0->hw_address) == 6);
1180 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1181 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1183 /* Figure out how much to rewind current data from adjacency. */
1184 /* get the adj from the destination's covering connected */
1188 adj_get (fib_entry_get_adj_for_source
1189 (ip4_fib_table_lookup
1190 (ip4_fib_get (fib_index0),
1191 &arp0->ip4_over_ethernet[1].ip4, 31),
1192 FIB_SOURCE_INTERFACE));
1193 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1195 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1200 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1204 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1206 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1207 n_left_to_next, pi0, next0);
1209 n_replies_sent += 1;
1213 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1214 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1215 arp0->ip4_over_ethernet[1].ip4.as_u32))
1217 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1220 /* See if proxy arp is configured for the address */
1223 vnet_sw_interface_t *si;
1224 u32 this_addr = clib_net_to_host_u32
1225 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1228 si = vnet_get_sw_interface (vnm, sw_if_index0);
1230 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1233 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1236 vec_foreach (pa, am->proxy_arps)
1238 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1239 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1241 /* an ARP request hit in the proxy-arp table? */
1242 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1243 (fib_index0 == pa->fib_index))
1245 eth0 = ethernet_buffer_get_header (p0);
1247 arp0->ip4_over_ethernet[1].ip4.data_u32;
1250 * Rewind buffer, direct code above not to
1251 * think too hard about it.
1253 if_addr0 = &proxy_src;
1255 i32 ethernet_start =
1256 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1257 i32 rewind = p0->current_data - ethernet_start;
1258 vlib_buffer_advance (p0, -rewind);
1259 n_proxy_arp_replies_sent++;
1267 next0 = ARP_INPUT_NEXT_DROP;
1268 p0->error = node->errors[error0];
1270 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1271 n_left_to_next, pi0, next0);
1274 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1277 vlib_error_count (vm, node->node_index,
1278 ETHERNET_ARP_ERROR_replies_sent,
1279 n_replies_sent - n_proxy_arp_replies_sent);
1281 vlib_error_count (vm, node->node_index,
1282 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1283 n_proxy_arp_replies_sent);
1284 return frame->n_vectors;
1287 static char *ethernet_arp_error_strings[] = {
1288 #define _(sym,string) string,
1289 foreach_ethernet_arp_error
1294 VLIB_REGISTER_NODE (arp_input_node, static) =
1296 .function = arp_input,
1297 .name = "arp-input",
1298 .vector_size = sizeof (u32),
1299 .n_errors = ETHERNET_ARP_N_ERROR,
1300 .error_strings = ethernet_arp_error_strings,
1301 .n_next_nodes = ARP_INPUT_N_NEXT,
1303 [ARP_INPUT_NEXT_DROP] = "error-drop",
1304 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1306 .format_buffer = format_ethernet_arp_header,
1307 .format_trace = format_ethernet_arp_input_trace,
1312 ip4_arp_entry_sort (void *a1, void *a2)
1314 ethernet_arp_ip4_entry_t *e1 = a1;
1315 ethernet_arp_ip4_entry_t *e2 = a2;
1318 vnet_main_t *vnm = vnet_get_main ();
1320 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1322 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1326 ethernet_arp_ip4_entry_t *
1327 ip4_neighbor_entries (u32 sw_if_index)
1329 ethernet_arp_main_t *am = ðernet_arp_main;
1330 ethernet_arp_ip4_entry_t *n, *ns = 0;
1333 pool_foreach (n, am->ip4_entry_pool, ({
1334 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1336 vec_add1 (ns, n[0]);
1341 vec_sort_with_function (ns, ip4_arp_entry_sort);
1345 static clib_error_t *
1346 show_ip4_arp (vlib_main_t * vm,
1347 unformat_input_t * input, vlib_cli_command_t * cmd)
1349 vnet_main_t *vnm = vnet_get_main ();
1350 ethernet_arp_main_t *am = ðernet_arp_main;
1351 ethernet_arp_ip4_entry_t *e, *es;
1352 ethernet_proxy_arp_t *pa;
1353 clib_error_t *error = 0;
1356 /* Filter entries by interface if given. */
1358 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1360 es = ip4_neighbor_entries (sw_if_index);
1363 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1366 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1371 if (vec_len (am->proxy_arps))
1373 vlib_cli_output (vm, "Proxy arps enabled for:");
1374 vec_foreach (pa, am->proxy_arps)
1376 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1378 format_ip4_address, &pa->lo_addr,
1379 format_ip4_address, &pa->hi_addr);
1387 * Display all the IPv4 ARP entries.
1390 * Example of how to display the IPv4 ARP table:
1391 * @cliexstart{show ip arp}
1392 * Time FIB IP4 Flags Ethernet Interface
1393 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1394 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1395 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1396 * Proxy arps enabled for:
1397 * Fib_index 0 6.0.0.1 - 6.0.0.11
1401 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1402 .path = "show ip arp",
1403 .function = show_ip4_arp,
1404 .short_help = "show ip arp",
1410 pg_edit_t l2_type, l3_type;
1411 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1417 } ip4_over_ethernet[2];
1418 } pg_ethernet_arp_header_t;
1421 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1423 /* Initialize fields that are not bit fields in the IP header. */
1424 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1427 _(n_l2_address_bytes);
1428 _(n_l3_address_bytes);
1430 _(ip4_over_ethernet[0].ethernet);
1431 _(ip4_over_ethernet[0].ip4);
1432 _(ip4_over_ethernet[1].ethernet);
1433 _(ip4_over_ethernet[1].ip4);
1438 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1440 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1441 pg_ethernet_arp_header_t *p;
1444 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1446 pg_ethernet_arp_header_init (p);
1449 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1450 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1451 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1452 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1454 if (!unformat (input, "%U: %U/%U -> %U/%U",
1456 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1458 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1460 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1462 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1464 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1466 /* Free up any edits we may have added. */
1467 pg_free_edit_group (s);
1474 ip4_set_arp_limit (u32 arp_limit)
1476 ethernet_arp_main_t *am = ðernet_arp_main;
1478 am->limit_arp_cache_size = arp_limit;
1483 * @brief Control Plane hook to remove an ARP entry
1486 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1487 u32 sw_if_index, void *a_arg)
1489 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1490 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1492 args.sw_if_index = sw_if_index;
1493 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1494 clib_memcpy (&args.a, a, sizeof (*a));
1496 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1497 (u8 *) & args, sizeof (args));
1502 * @brief Internally generated event to flush the ARP cache on an
1503 * interface state change event.
1504 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1505 * address from the corresponding adjacencies.
1508 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1509 u32 sw_if_index, void *a_arg)
1511 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1512 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1514 args.sw_if_index = sw_if_index;
1515 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1516 clib_memcpy (&args.a, a, sizeof (*a));
1518 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1519 (u8 *) & args, sizeof (args));
1524 * @brief Internally generated event to populate the ARP cache on an
1525 * interface state change event.
1526 * For static entries this will re-source the adjacencies.
1528 * @param sw_if_index The interface on which the ARP entires are acted
1531 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1532 u32 sw_if_index, void *a_arg)
1534 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1535 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1537 args.sw_if_index = sw_if_index;
1538 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1539 clib_memcpy (&args.a, a, sizeof (*a));
1541 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1542 (u8 *) & args, sizeof (args));
1547 * arp_add_del_interface_address
1549 * callback when an interface address is added or deleted
1552 arp_add_del_interface_address (ip4_main_t * im,
1555 ip4_address_t * address,
1557 u32 if_address_index, u32 is_del)
1560 * Flush the ARP cache of all entries covered by the address
1561 * that is being removed.
1563 ethernet_arp_main_t *am = ðernet_arp_main;
1564 ethernet_arp_ip4_entry_t *e;
1566 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
1571 ethernet_arp_interface_t *eai;
1572 u32 i, *to_delete = 0;
1575 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1578 hash_foreach_pair (pair, eai->arp_entries,
1580 e = pool_elt_at_index(am->ip4_entry_pool,
1582 if (ip4_destination_matches_route (im, &e->ip4_address,
1583 address, address_length))
1585 vec_add1 (to_delete, e - am->ip4_entry_pool);
1590 for (i = 0; i < vec_len (to_delete); i++)
1592 ethernet_arp_ip4_over_ethernet_address_t delme;
1593 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1595 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1596 delme.ip4.as_u32 = e->ip4_address.as_u32;
1598 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1599 e->sw_if_index, &delme);
1602 vec_free (to_delete);
1606 static clib_error_t *
1607 ethernet_arp_init (vlib_main_t * vm)
1609 ethernet_arp_main_t *am = ðernet_arp_main;
1610 ip4_main_t *im = &ip4_main;
1611 clib_error_t *error;
1614 if ((error = vlib_call_init_function (vm, ethernet_init)))
1617 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1619 pn = pg_get_node (arp_input_node.index);
1620 pn->unformat_edit = unformat_pg_arp_header;
1622 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1623 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1624 foreach_ethernet_arp_opcode;
1627 /* $$$ configurable */
1628 am->limit_arp_cache_size = 50000;
1630 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1631 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1633 /* don't trace ARP error packets */
1635 vlib_node_runtime_t *rt =
1636 vlib_node_get_runtime (vm, arp_input_node.index);
1639 vnet_pcap_drop_trace_filter_add_del \
1640 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1642 foreach_ethernet_arp_error
1646 ip4_add_del_interface_address_callback_t cb;
1647 cb.function = arp_add_del_interface_address;
1648 cb.function_opaque = 0;
1649 vec_add1 (im->add_del_interface_address_callbacks, cb);
1654 VLIB_INIT_FUNCTION (ethernet_arp_init);
1657 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1659 ethernet_arp_main_t *am = ðernet_arp_main;
1661 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
1662 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1663 pool_put (am->ip4_entry_pool, e);
1667 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1668 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1671 ethernet_arp_main_t *am = ðernet_arp_main;
1672 ethernet_arp_ip4_entry_t *e;
1673 ethernet_arp_interface_t *eai;
1675 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1677 e = arp_entry_find (eai, &args->a.ip4);
1681 arp_entry_free (eai, e);
1683 adj_nbr_walk_nh4 (e->sw_if_index,
1684 &e->ip4_address, arp_mk_incomplete_walk, NULL);
1691 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1692 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1695 ethernet_arp_main_t *am = ðernet_arp_main;
1696 ethernet_arp_ip4_entry_t *e;
1697 ethernet_arp_interface_t *eai;
1699 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1701 e = arp_entry_find (eai, &args->a.ip4);
1705 adj_nbr_walk_nh4 (e->sw_if_index,
1706 &e->ip4_address, arp_mk_incomplete_walk, e);
1709 * The difference between flush and unset, is that an unset
1710 * means delete for static and dynamic entries. A flush
1711 * means delete only for dynamic. Flushing is what the DP
1712 * does in response to interface events. unset is only done
1713 * by the control plane.
1715 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
1717 arp_entry_free (eai, e);
1724 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1725 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1728 ethernet_arp_main_t *am = ðernet_arp_main;
1729 ethernet_arp_ip4_entry_t *e;
1730 ethernet_arp_interface_t *eai;
1732 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1734 e = arp_entry_find (eai, &args->a.ip4);
1738 adj_nbr_walk_nh4 (e->sw_if_index,
1739 &e->ip4_address, arp_mk_complete_walk, e);
1745 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1748 vnet_main_t *vm = vnet_get_main ();
1749 ASSERT (os_get_cpu_number () == 0);
1751 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1752 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1753 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1754 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1755 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1756 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1758 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1762 * @brief Invoked when the interface's admin state changes
1764 static clib_error_t *
1765 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1766 u32 sw_if_index, u32 flags)
1768 ethernet_arp_main_t *am = ðernet_arp_main;
1769 ethernet_arp_ip4_entry_t *e;
1770 u32 i, *to_delete = 0;
1773 pool_foreach (e, am->ip4_entry_pool,
1775 if (e->sw_if_index == sw_if_index)
1776 vec_add1 (to_delete,
1777 e - am->ip4_entry_pool);
1781 for (i = 0; i < vec_len (to_delete); i++)
1783 ethernet_arp_ip4_over_ethernet_address_t delme;
1784 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1786 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1787 delme.ip4.as_u32 = e->ip4_address.as_u32;
1789 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1791 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1795 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1799 vec_free (to_delete);
1804 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1807 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1812 for (i = 3; i >= 0; i--)
1814 old = a->ip4.as_u8[i];
1815 a->ip4.as_u8[i] += 1;
1816 if (old < a->ip4.as_u8[i])
1820 for (i = 5; i >= 0; i--)
1822 old = a->ethernet[i];
1823 a->ethernet[i] += 1;
1824 if (old < a->ethernet[i])
1830 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1831 u32 sw_if_index, void *a_arg, int is_static)
1833 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1834 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1836 args.sw_if_index = sw_if_index;
1837 args.is_static = is_static;
1839 clib_memcpy (&args.a, a, sizeof (*a));
1841 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1842 (u8 *) & args, sizeof (args));
1847 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1848 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1850 ethernet_arp_main_t *am = ðernet_arp_main;
1851 ethernet_proxy_arp_t *pa;
1852 u32 found_at_index = ~0;
1854 vec_foreach (pa, am->proxy_arps)
1856 if (pa->lo_addr == lo_addr->as_u32
1857 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1859 found_at_index = pa - am->proxy_arps;
1864 if (found_at_index != ~0)
1866 /* Delete, otherwise it's already in the table */
1868 vec_delete (am->proxy_arps, 1, found_at_index);
1871 /* delete, no such entry */
1873 return VNET_API_ERROR_NO_SUCH_ENTRY;
1875 /* add, not in table */
1876 vec_add2 (am->proxy_arps, pa, 1);
1877 pa->lo_addr = lo_addr->as_u32;
1878 pa->hi_addr = hi_addr->as_u32;
1879 pa->fib_index = fib_index;
1884 * Remove any proxy arp entries asdociated with the
1888 vnet_proxy_arp_fib_reset (u32 fib_id)
1890 ip4_main_t *im = &ip4_main;
1891 ethernet_arp_main_t *am = ðernet_arp_main;
1892 ethernet_proxy_arp_t *pa;
1893 u32 *entries_to_delete = 0;
1898 p = hash_get (im->fib_index_by_table_id, fib_id);
1900 return VNET_API_ERROR_NO_SUCH_ENTRY;
1903 vec_foreach (pa, am->proxy_arps)
1905 if (pa->fib_index == fib_index)
1907 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1911 for (i = 0; i < vec_len (entries_to_delete); i++)
1913 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1916 vec_free (entries_to_delete);
1921 static clib_error_t *
1922 ip_arp_add_del_command_fn (vlib_main_t * vm,
1923 unformat_input_t * input, vlib_cli_command_t * cmd)
1925 vnet_main_t *vnm = vnet_get_main ();
1927 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1936 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1938 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1939 if (unformat (input, "%U %U %U",
1940 unformat_vnet_sw_interface, vnm, &sw_if_index,
1941 unformat_ip4_address, &addr.ip4,
1942 unformat_ethernet_address, &addr.ethernet))
1945 else if (unformat (input, "delete") || unformat (input, "del"))
1948 else if (unformat (input, "static"))
1951 else if (unformat (input, "count %d", &count))
1954 else if (unformat (input, "fib-id %d", &fib_id))
1956 ip4_main_t *im = &ip4_main;
1957 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1959 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1963 else if (unformat (input, "proxy %U - %U",
1964 unformat_ip4_address, &lo_addr.ip4,
1965 unformat_ip4_address, &hi_addr.ip4))
1973 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1982 for (i = 0; i < count; i++)
1986 uword event_type, *event_data = 0;
1988 /* Park the debug CLI until the arp entry is installed */
1989 vnet_register_ip4_arp_resolution_event
1990 (vnm, &addr.ip4, vlib_current_process (vm),
1991 1 /* type */ , 0 /* data */ );
1993 vnet_arp_set_ip4_over_ethernet
1994 (vnm, sw_if_index, &addr, is_static);
1996 vlib_process_wait_for_event (vm);
1997 event_type = vlib_process_get_events (vm, &event_data);
1998 vec_reset_length (event_data);
1999 if (event_type != 1)
2000 clib_warning ("event type %d unexpected", event_type);
2003 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
2005 increment_ip4_and_mac_address (&addr);
2010 return clib_error_return (0, "unknown input `%U'",
2011 format_unformat_error, input);
2019 * Add or delete IPv4 ARP cache entries.
2021 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
2022 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
2023 * any order and combination.
2027 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
2028 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
2029 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2030 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
2032 * To add or delete an IPv4 ARP cache entry to or from a specific fib
2034 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2035 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2037 * Add or delete IPv4 static ARP cache entries as follows:
2038 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2039 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2041 * For testing / debugging purposes, the 'set ip arp' command can add or
2042 * delete multiple entries. Supply the 'count N' parameter:
2043 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2046 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2047 .path = "set ip arp",
2049 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2050 .function = ip_arp_add_del_command_fn,
2054 static clib_error_t *
2055 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2057 input, vlib_cli_command_t * cmd)
2059 vnet_main_t *vnm = vnet_get_main ();
2061 vnet_sw_interface_t *si;
2065 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2067 if (unformat (input, "%U", unformat_vnet_sw_interface,
2070 else if (unformat (input, "enable") || unformat (input, "on"))
2072 else if (unformat (input, "disable") || unformat (input, "off"))
2079 return clib_error_return (0, "unknown input '%U'",
2080 format_unformat_error, input);
2082 si = vnet_get_sw_interface (vnm, sw_if_index);
2085 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2087 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2094 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2095 * requests for the indicated address range. Multiple proxy-arp
2096 * ranges may be provisioned.
2098 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2099 * Also, the underlying implementation has not been performance-tuned.
2100 * Avoid creating an unnecessarily large set of ranges.
2103 * To enable proxy arp on a range of addresses, use:
2104 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2105 * Append 'del' to delete a range of proxy ARP addresses:
2106 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2107 * You must then specifically enable proxy arp on individual interfaces:
2108 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2109 * To disable proxy arp on an individual interface:
2110 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2112 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2113 .path = "set interface proxy-arp",
2115 "set interface proxy-arp <intfc> [enable|disable]",
2116 .function = set_int_proxy_arp_command_fn,
2122 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2123 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2127 ARP_TERM_NEXT_L2_OUTPUT,
2132 u32 arp_term_next_node_index[32];
2135 arp_term_l2bd (vlib_main_t * vm,
2136 vlib_node_runtime_t * node, vlib_frame_t * frame)
2138 l2input_main_t *l2im = &l2input_main;
2139 u32 n_left_from, next_index, *from, *to_next;
2140 u32 n_replies_sent = 0;
2141 u16 last_bd_index = ~0;
2142 l2_bridge_domain_t *last_bd_config = 0;
2143 l2_input_config_t *cfg0;
2145 from = vlib_frame_vector_args (frame);
2146 n_left_from = frame->n_vectors;
2147 next_index = node->cached_next_index;
2149 while (n_left_from > 0)
2153 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2155 while (n_left_from > 0 && n_left_to_next > 0)
2158 ethernet_header_t *eth0;
2159 ethernet_arp_header_t *arp0;
2162 u32 pi0, error0, next0, sw_if_index0;
2173 n_left_to_next -= 1;
2175 p0 = vlib_get_buffer (vm, pi0);
2176 eth0 = vlib_buffer_get_current (p0);
2177 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2178 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2179 arp0 = (ethernet_arp_header_t *) l3h0;
2181 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2183 clib_host_to_net_u16
2184 (ETHERNET_ARP_OPCODE_request))))
2187 /* Must be ARP request packet here */
2188 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2189 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2191 u8 *t0 = vlib_add_trace (vm, node, p0,
2192 sizeof (ethernet_arp_input_trace_t));
2193 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2196 error0 = ETHERNET_ARP_ERROR_replies_sent;
2199 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2200 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2203 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2204 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2206 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2211 /* Trash ARP packets whose ARP-level source addresses do not
2212 match their L2-frame-level source addresses */
2215 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2216 sizeof (eth0->src_address))))
2218 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2222 /* Check if anyone want ARP request events for L2 BDs */
2224 pending_resolution_t *mc;
2225 ethernet_arp_main_t *am = ðernet_arp_main;
2226 uword *p = hash_get (am->mac_changes_by_address, 0);
2227 if (p && (vnet_buffer (p0)->l2.shg == 0))
2228 { // Only SHG 0 interface which is more likely local
2229 u32 next_index = p[0];
2230 while (next_index != (u32) ~ 0)
2232 int (*fp) (u32, u8 *, u32, u32);
2234 mc = pool_elt_at_index (am->mac_changes, next_index);
2235 fp = mc->data_callback;
2236 /* Call the callback, return 1 to suppress dup events */
2238 rv = (*fp) (mc->data,
2239 arp0->ip4_over_ethernet[0].ethernet,
2241 arp0->ip4_over_ethernet[0].ip4.as_u32);
2242 /* Signal the resolver process */
2244 vlib_process_signal_event (vm, mc->node_index,
2245 mc->type_opaque, mc->data);
2246 next_index = mc->next_index;
2251 /* lookup BD mac_by_ip4 hash table for MAC entry */
2252 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2253 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2254 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2255 || (last_bd_index == (u16) ~ 0)))
2257 last_bd_index = bd_index0;
2258 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2260 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2262 if (PREDICT_FALSE (!macp0))
2263 goto next_l2_feature; /* MAC not found */
2265 /* MAC found, send ARP reply -
2266 Convert ARP request packet to ARP reply */
2267 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2268 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2269 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2270 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2271 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2272 clib_memcpy (eth0->src_address, macp0, 6);
2273 n_replies_sent += 1;
2276 /* For BVI, need to use l2-fwd node to send ARP reply as
2277 l2-output node cannot output packet to BVI properly */
2278 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2279 if (PREDICT_FALSE (cfg0->bvi))
2281 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2282 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2283 goto next_l2_feature;
2286 /* Send ARP/ND reply back out input interface through l2-output */
2287 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2288 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2289 /* Note that output to VXLAN tunnel will fail due to SHG which
2290 is probably desireable since ARP termination is not intended
2291 for ARP requests from other hosts. If output to VXLAN tunnel is
2292 required, however, can just clear the SHG in packet as follows:
2293 vnet_buffer(p0)->l2.shg = 0; */
2294 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2295 to_next, n_left_to_next, pi0,
2300 /* IP6 ND event notification or solicitation handling to generate
2301 local response instead of flooding */
2302 iph0 = (ip6_header_t *) l3h0;
2303 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2304 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2305 !ip6_address_is_unspecified
2306 (&iph0->src_address)))
2308 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2309 if (vnet_ip6_nd_term
2310 (vm, node, p0, eth0, iph0, sw_if_index0,
2311 vnet_buffer (p0)->l2.bd_index, vnet_buffer (p0)->l2.shg))
2312 goto output_response;
2317 u32 feature_bitmap0 =
2318 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2319 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2321 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2323 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2324 to_next, n_left_to_next,
2330 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2331 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2332 arp0->ip4_over_ethernet[1].ip4.as_u32))
2334 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2336 next0 = ARP_TERM_NEXT_DROP;
2337 p0->error = node->errors[error0];
2339 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2340 to_next, n_left_to_next, pi0,
2344 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2347 vlib_error_count (vm, node->node_index,
2348 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2349 return frame->n_vectors;
2353 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2354 .function = arp_term_l2bd,
2355 .name = "arp-term-l2bd",
2356 .vector_size = sizeof (u32),
2357 .n_errors = ETHERNET_ARP_N_ERROR,
2358 .error_strings = ethernet_arp_error_strings,
2359 .n_next_nodes = ARP_TERM_N_NEXT,
2361 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2362 [ARP_TERM_NEXT_DROP] = "error-drop",
2364 .format_buffer = format_ethernet_arp_header,
2365 .format_trace = format_arp_term_input_trace,
2370 arp_term_init (vlib_main_t * vm)
2372 // Initialize the feature next-node indexes
2373 feat_bitmap_init_next_nodes (vm,
2374 arp_term_l2bd_node.index,
2376 l2input_get_feat_names (),
2377 arp_term_next_node_index);
2381 VLIB_INIT_FUNCTION (arp_term_init);
2384 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2386 if (e->sw_if_index == sw_if_index)
2388 adj_nbr_walk_nh4 (e->sw_if_index,
2389 &e->ip4_address, arp_mk_complete_walk, e);
2394 ethernet_arp_change_mac (u32 sw_if_index)
2396 ethernet_arp_main_t *am = ðernet_arp_main;
2397 ethernet_arp_ip4_entry_t *e;
2400 pool_foreach (e, am->ip4_entry_pool,
2402 change_arp_mac (sw_if_index, e);
2408 * fd.io coding-style-patch-verification: ON
2411 * eval: (c-set-style "gnu")