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.h>
26 #include <vnet/mpls/mpls.h>
32 * This file contains code to manage the IPv4 ARP tables (IP Address
33 * to MAC Address lookup).
37 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
42 ip4_address_t ip4_address;
44 u8 ethernet_address[6];
47 #define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0)
48 #define ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC (1 << 1)
50 u64 cpu_time_last_updated;
51 adj_index_t adj_index[FIB_LINK_NUM];
52 } ethernet_arp_ip4_entry_t;
55 * @brief administrative and operational state falgs on an interface
57 typedef enum ethernet_arp_interface_flags_t_
59 ETHERNET_ARP_INTERFACE_UP = (0 << 1),
60 ETHERNET_ARP_INTERFACE_MPLS_ENABLE = (1 << 0),
61 } ethernet_arp_interface_flags_t;
64 * @brief Per-interface ARP configuration and state
66 typedef struct ethernet_arp_interface_t_
69 * Hash table of ARP entries.
70 * Since this hash table is per-interface, the key is only the IPv4 address.
75 * Flags for administrative and operational state
77 ethernet_arp_interface_flags_t flags;
78 } ethernet_arp_interface_t;
85 } ethernet_proxy_arp_t;
93 /* Used for arp event notification only */
96 } pending_resolution_t;
100 /* Hash tables mapping name to opcode. */
101 uword *opcode_by_name;
103 /* lite beer "glean" adjacency handling */
104 uword *pending_resolutions_by_address;
105 pending_resolution_t *pending_resolutions;
107 /* Mac address change notification */
108 uword *mac_changes_by_address;
109 pending_resolution_t *mac_changes;
111 ethernet_arp_ip4_entry_t *ip4_entry_pool;
113 /* ARP attack mitigation */
114 u32 arp_delete_rotor;
115 u32 limit_arp_cache_size;
117 /** Per interface state */
118 ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
120 /* Proxy arp vector */
121 ethernet_proxy_arp_t *proxy_arps;
122 } ethernet_arp_main_t;
124 static ethernet_arp_main_t ethernet_arp_main;
127 typedef enum arp_ether_type_t_
129 ARP_ETHER_TYPE_IP4 = (1 << 0),
130 ARP_ETHER_TYPE_MPLS = (1 << 1),
132 #define ARP_ETHER_TYPE_BOTH (ARP_ETHER_TYPE_MPLS | ARP_ETHER_TYPE_IP4)
137 ethernet_arp_ip4_over_ethernet_address_t a;
140 #define ETHERNET_ARP_ARGS_REMOVE (1<<0)
141 #define ETHERNET_ARP_ARGS_FLUSH (1<<1)
142 #define ETHERNET_ARP_ARGS_POPULATE (1<<2)
143 arp_ether_type_t ether_type;
144 } vnet_arp_set_ip4_over_ethernet_rpc_args_t;
147 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
151 format_ethernet_arp_hardware_type (u8 * s, va_list * va)
153 ethernet_arp_hardware_type_t h = va_arg (*va, ethernet_arp_hardware_type_t);
157 #define _(n,f) case n: t = #f; break;
158 foreach_ethernet_arp_hardware_type;
162 return format (s, "unknown 0x%x", h);
165 return format (s, "%s", t);
169 format_ethernet_arp_opcode (u8 * s, va_list * va)
171 ethernet_arp_opcode_t o = va_arg (*va, ethernet_arp_opcode_t);
175 #define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
176 foreach_ethernet_arp_opcode;
180 return format (s, "unknown 0x%x", o);
183 return format (s, "%s", t);
187 unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
190 int *result = va_arg (*args, int *);
191 ethernet_arp_main_t *am = ðernet_arp_main;
194 /* Numeric opcode. */
195 if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
204 if (unformat_user (input, unformat_vlib_number_by_name,
205 am->opcode_by_name, &i))
215 unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
218 int *result = va_arg (*args, int *);
220 (input, unformat_ethernet_arp_opcode_host_byte_order, result))
223 *result = clib_host_to_net_u16 ((u16) * result);
228 format_ethernet_arp_header (u8 * s, va_list * va)
230 ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
231 u32 max_header_bytes = va_arg (*va, u32);
233 u16 l2_type, l3_type;
235 if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
236 return format (s, "ARP header truncated");
238 l2_type = clib_net_to_host_u16 (a->l2_type);
239 l3_type = clib_net_to_host_u16 (a->l3_type);
241 indent = format_get_indent (s);
243 s = format (s, "%U, type %U/%U, address size %d/%d",
244 format_ethernet_arp_opcode, clib_net_to_host_u16 (a->opcode),
245 format_ethernet_arp_hardware_type, l2_type,
246 format_ethernet_type, l3_type,
247 a->n_l2_address_bytes, a->n_l3_address_bytes);
249 if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
250 && l3_type == ETHERNET_TYPE_IP4)
252 s = format (s, "\n%U%U/%U -> %U/%U",
253 format_white_space, indent,
254 format_ethernet_address, a->ip4_over_ethernet[0].ethernet,
255 format_ip4_address, &a->ip4_over_ethernet[0].ip4,
256 format_ethernet_address, a->ip4_over_ethernet[1].ethernet,
257 format_ip4_address, &a->ip4_over_ethernet[1].ip4);
261 uword n2 = a->n_l2_address_bytes;
262 uword n3 = a->n_l3_address_bytes;
263 s = format (s, "\n%U%U/%U -> %U/%U",
264 format_white_space, indent,
265 format_hex_bytes, a->data + 0 * n2 + 0 * n3, n2,
266 format_hex_bytes, a->data + 1 * n2 + 0 * n3, n3,
267 format_hex_bytes, a->data + 1 * n2 + 1 * n3, n2,
268 format_hex_bytes, a->data + 2 * n2 + 1 * n3, n3);
275 format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
277 vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
278 ethernet_arp_ip4_entry_t *e = va_arg (*va, ethernet_arp_ip4_entry_t *);
279 vnet_sw_interface_t *si;
283 return format (s, "%=12s%=16s%=6s%=20s%=24s", "Time", "IP4",
284 "Flags", "Ethernet", "Interface");
286 si = vnet_get_sw_interface (vnm, e->sw_if_index);
288 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
289 flags = format (flags, "S");
291 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
292 flags = format (flags, "D");
294 s = format (s, "%=12U%=16U%=6s%=20U%=24U",
295 format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
296 format_ip4_address, &e->ip4_address,
297 flags ? (char *) flags : "",
298 format_ethernet_address, e->ethernet_address,
299 format_vnet_sw_interface_name, vnm, si);
308 } ethernet_arp_input_trace_t;
311 format_ethernet_arp_input_trace (u8 * s, va_list * va)
313 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
314 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
315 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
318 format_ethernet_arp_header,
319 t->packet_data, sizeof (t->packet_data));
325 format_arp_term_input_trace (u8 * s, va_list * va)
327 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
328 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
329 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
331 /* arp-term trace data saved is either arp or ip6/icmp6 packet:
332 - for arp, the 1st 16-bit field is hw type of value of 0x0001.
333 - for ip6, the first nibble has value of 6. */
334 s = format (s, "%U", t->packet_data[0] == 0 ?
335 format_ethernet_arp_header : format_ip6_header,
336 t->packet_data, sizeof (t->packet_data));
342 arp_mk_complete (ethernet_arp_interface_t * eai,
343 ethernet_arp_ip4_entry_t * e, arp_ether_type_t et)
347 .fp_proto = FIB_PROTOCOL_IP4,
349 .ip4 = e->ip4_address,
354 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
356 if (et & ARP_ETHER_TYPE_IP4)
358 if (ADJ_INDEX_INVALID == e->adj_index[FIB_LINK_IP4])
360 e->adj_index[FIB_LINK_IP4] =
361 adj_nbr_add_or_lock_w_rewrite (FIB_PROTOCOL_IP4,
365 e->ethernet_address);
366 ASSERT (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4]);
368 fib_table_entry_update_one_path (fib_index,
371 FIB_ENTRY_FLAG_ATTACHED,
378 FIB_ROUTE_PATH_FLAG_NONE);
382 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4],
383 e->ethernet_address);
386 if ((et & ARP_ETHER_TYPE_MPLS) &&
387 eai->flags & ETHERNET_ARP_INTERFACE_MPLS_ENABLE)
389 if (ADJ_INDEX_INVALID == e->adj_index[FIB_LINK_MPLS])
391 e->adj_index[FIB_LINK_MPLS] =
392 adj_nbr_add_or_lock_w_rewrite (FIB_PROTOCOL_IP4,
396 e->ethernet_address);
397 ASSERT (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS]);
401 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS],
402 e->ethernet_address);
408 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
409 vnet_arp_set_ip4_over_ethernet_rpc_args_t
412 ethernet_arp_ip4_entry_t *e = 0;
413 ethernet_arp_main_t *am = ðernet_arp_main;
414 ethernet_arp_ip4_over_ethernet_address_t *a = &args->a;
415 vlib_main_t *vm = vlib_get_main ();
416 int make_new_arp_cache_entry = 1;
418 pending_resolution_t *pr, *mc;
419 ethernet_arp_interface_t *arp_int;
421 int is_static = args->is_static;
422 u32 sw_if_index = args->sw_if_index;
424 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
426 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
428 if (NULL != arp_int->arp_entries)
430 p = hash_get (arp_int->arp_entries, a->ip4.as_u32);
433 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
435 /* Refuse to over-write static arp. */
436 if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
438 make_new_arp_cache_entry = 0;
442 if (make_new_arp_cache_entry)
444 pool_get (am->ip4_entry_pool, e);
446 if (NULL == arp_int->arp_entries)
448 arp_int->arp_entries = hash_create (0, sizeof (u32));
449 if (mpls_sw_interface_is_enabled (sw_if_index))
450 arp_int->flags |= ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
453 hash_set (arp_int->arp_entries, a->ip4.as_u32, e - am->ip4_entry_pool);
455 e->sw_if_index = sw_if_index;
456 e->ip4_address = a->ip4;
457 FOR_EACH_FIB_LINK (link)
459 e->adj_index[link] = ADJ_INDEX_INVALID;
463 /* Update time stamp and ethernet address. */
464 clib_memcpy (e->ethernet_address, a->ethernet,
465 sizeof (e->ethernet_address));
466 e->cpu_time_last_updated = clib_cpu_time_now ();
468 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
470 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC;
472 arp_mk_complete (arp_int, e, ARP_ETHER_TYPE_BOTH);
474 /* Customer(s) waiting for this address to be resolved? */
475 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
481 while (next_index != (u32) ~ 0)
483 pr = pool_elt_at_index (am->pending_resolutions, next_index);
484 vlib_process_signal_event (vm, pr->node_index,
485 pr->type_opaque, pr->data);
486 next_index = pr->next_index;
487 pool_put (am->pending_resolutions, pr);
490 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
493 /* Customer(s) requesting ARP event for this address? */
494 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
500 while (next_index != (u32) ~ 0)
502 int (*fp) (u32, u8 *, u32, u32);
504 mc = pool_elt_at_index (am->mac_changes, next_index);
505 fp = mc->data_callback;
507 /* Call the user's data callback, return 1 to suppress dup events */
509 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
512 * Signal the resolver process, as long as the user
513 * says they want to be notified
516 vlib_process_signal_event (vm, mc->node_index,
517 mc->type_opaque, mc->data);
518 next_index = mc->next_index;
526 vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
529 uword type_opaque, uword data)
531 ethernet_arp_main_t *am = ðernet_arp_main;
532 ip4_address_t *address = address_arg;
534 pending_resolution_t *pr;
536 pool_get (am->pending_resolutions, pr);
539 pr->node_index = node_index;
540 pr->type_opaque = type_opaque;
542 pr->data_callback = 0;
544 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
547 /* Insert new resolution at the head of the list */
548 pr->next_index = p[0];
549 hash_unset (am->pending_resolutions_by_address, address->as_u32);
552 hash_set (am->pending_resolutions_by_address, address->as_u32,
553 pr - am->pending_resolutions);
557 vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
562 uword type_opaque, uword data, int is_add)
564 ethernet_arp_main_t *am = ðernet_arp_main;
565 ip4_address_t *address = address_arg;
567 pending_resolution_t *mc;
568 void (*fp) (u32, u8 *) = data_callback;
572 pool_get (am->mac_changes, mc);
575 mc->node_index = node_index;
576 mc->type_opaque = type_opaque;
578 mc->data_callback = data_callback;
581 p = hash_get (am->mac_changes_by_address, address->as_u32);
584 /* Insert new resolution at the head of the list */
585 mc->next_index = p[0];
586 hash_unset (am->mac_changes_by_address, address->as_u32);
589 hash_set (am->mac_changes_by_address, address->as_u32,
590 mc - am->mac_changes);
596 pending_resolution_t *mc_last = 0;
598 p = hash_get (am->mac_changes_by_address, address->as_u32);
600 return VNET_API_ERROR_NO_SUCH_ENTRY;
604 while (index != (u32) ~ 0)
606 mc = pool_elt_at_index (am->mac_changes, index);
607 if (mc->node_index == node_index &&
608 mc->type_opaque == type_opaque && mc->pid == pid)
610 /* Clients may need to clean up pool entries, too */
612 (*fp) (mc->data, 0 /* no new mac addrs */ );
615 hash_unset (am->mac_changes_by_address, address->as_u32);
616 if (mc->next_index != ~0)
617 hash_set (am->mac_changes_by_address, address->as_u32,
619 pool_put (am->mac_changes, mc);
625 mc_last->next_index = mc->next_index;
626 pool_put (am->mac_changes, mc);
631 index = mc->next_index;
634 return VNET_API_ERROR_NO_SUCH_ENTRY;
638 /* Either we drop the packet or we send a reply to the sender. */
642 ARP_INPUT_NEXT_REPLY_TX,
646 #define foreach_ethernet_arp_error \
647 _ (replies_sent, "ARP replies sent") \
648 _ (l2_type_not_ethernet, "L2 type not ethernet") \
649 _ (l3_type_not_ip4, "L3 type not IP4") \
650 _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
651 _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
652 _ (l3_src_address_is_local, "IP4 source address matches local interface") \
653 _ (l3_src_address_learned, "ARP request IP4 source address learned") \
654 _ (replies_received, "ARP replies received") \
655 _ (opcode_not_request, "ARP opcode not request") \
656 _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
657 _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
658 _ (missing_interface_address, "ARP missing interface address") \
659 _ (gratuitous_arp, "ARP probe or announcement dropped") \
660 _ (interface_no_table, "Interface is not mapped to an IP table") \
664 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
665 foreach_ethernet_arp_error
667 ETHERNET_ARP_N_ERROR,
668 } ethernet_arp_input_error_t;
672 unset_random_arp_entry (void)
674 ethernet_arp_main_t *am = ðernet_arp_main;
675 ethernet_arp_ip4_entry_t *e;
676 vnet_main_t *vnm = vnet_get_main ();
677 ethernet_arp_ip4_over_ethernet_address_t delme;
680 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
681 am->arp_delete_rotor = index;
683 /* Try again from elt 0, could happen if an intfc goes down */
686 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
687 am->arp_delete_rotor = index;
690 /* Nothing left in the pool */
694 e = pool_elt_at_index (am->ip4_entry_pool, index);
696 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
697 delme.ip4.as_u32 = e->ip4_address.as_u32;
699 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
703 arp_unnumbered (vlib_buffer_t * p0,
704 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
706 vlib_main_t *vm = vlib_get_main ();
707 vnet_main_t *vnm = vnet_get_main ();
708 vnet_interface_main_t *vim = &vnm->interface_main;
709 vnet_sw_interface_t *si;
710 vnet_hw_interface_t *hi;
711 u32 unnum_src_sw_if_index;
712 u32 *broadcast_swifs = 0;
717 u8 dst_mac_address[6];
719 ethernet_arp_header_t *arp0;
721 /* Save the dst mac address */
722 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
724 /* Figure out which sw_if_index supplied the address */
725 unnum_src_sw_if_index = sw_if_index;
727 /* Track down all users of the unnumbered source */
729 pool_foreach (si, vim->sw_interfaces,
731 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
732 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
734 vec_add1 (broadcast_swifs, si->sw_if_index);
739 ASSERT (vec_len (broadcast_swifs));
741 /* Allocate buffering if we need it */
742 if (vec_len (broadcast_swifs) > 1)
744 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
745 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
746 _vec_len (buffers) = n_alloc;
747 for (i = 0; i < n_alloc; i++)
749 b0 = vlib_get_buffer (vm, buffers[i]);
751 /* xerox (partially built) ARP pkt */
752 clib_memcpy (b0->data, p0->data,
753 p0->current_length + p0->current_data);
754 b0->current_data = p0->current_data;
755 b0->current_length = p0->current_length;
756 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
757 vnet_buffer (p0)->sw_if_index[VLIB_RX];
761 vec_insert (buffers, 1, 0);
764 for (i = 0; i < vec_len (buffers); i++)
766 b0 = vlib_get_buffer (vm, buffers[i]);
767 arp0 = vlib_buffer_get_current (b0);
769 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
770 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
772 /* For decoration, most likely */
773 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
775 /* Fix ARP pkt src address */
776 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
778 /* Build L2 encaps for this swif */
779 header_size = sizeof (ethernet_header_t);
780 if (si->sub.eth.flags.one_tag)
782 else if (si->sub.eth.flags.two_tags)
785 vlib_buffer_advance (b0, -header_size);
786 eth0 = vlib_buffer_get_current (b0);
788 if (si->sub.eth.flags.one_tag)
790 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
792 eth0->type = si->sub.eth.flags.dot1ad ?
793 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
794 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
795 outer->priority_cfi_and_id =
796 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
797 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
800 else if (si->sub.eth.flags.two_tags)
802 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
803 ethernet_vlan_header_t *inner = (void *) (outer + 1);
805 eth0->type = si->sub.eth.flags.dot1ad ?
806 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
807 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
808 outer->priority_cfi_and_id =
809 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
810 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
811 inner->priority_cfi_and_id =
812 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
813 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
818 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
821 /* Restore the original dst address, set src address */
822 clib_memcpy (eth0->dst_address, dst_mac_address,
823 sizeof (eth0->dst_address));
824 clib_memcpy (eth0->src_address, hi->hw_address,
825 sizeof (eth0->src_address));
827 /* Transmit replicas */
831 vlib_get_frame_to_node (vm, hi->output_node_index);
832 u32 *to_next = vlib_frame_vector_args (f);
833 to_next[0] = buffers[i];
835 vlib_put_frame_to_node (vm, hi->output_node_index, f);
839 /* The regular path outputs the original pkt.. */
840 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
842 vec_free (broadcast_swifs);
847 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
849 ethernet_arp_main_t *am = ðernet_arp_main;
850 vnet_main_t *vnm = vnet_get_main ();
851 ip4_main_t *im4 = &ip4_main;
852 u32 n_left_from, next_index, *from, *to_next;
853 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
855 from = vlib_frame_vector_args (frame);
856 n_left_from = frame->n_vectors;
857 next_index = node->cached_next_index;
859 if (node->flags & VLIB_NODE_FLAG_TRACE)
860 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
862 sizeof (ethernet_arp_input_trace_t));
864 while (n_left_from > 0)
868 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
870 while (n_left_from > 0 && n_left_to_next > 0)
873 vnet_hw_interface_t *hw_if0;
874 ethernet_arp_header_t *arp0;
875 ethernet_header_t *eth0;
876 ip_adjacency_t *adj0;
877 ip4_address_t *if_addr0, proxy_src;
878 u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
879 u8 is_request0, dst_is_local0, is_unnum0;
880 ethernet_proxy_arp_t *pa;
881 fib_node_index_t dst_fei, src_fei;
883 fib_entry_flag_t src_flags, dst_flags;
893 p0 = vlib_get_buffer (vm, pi0);
894 arp0 = vlib_buffer_get_current (p0);
896 is_request0 = arp0->opcode
897 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
899 error0 = ETHERNET_ARP_ERROR_replies_sent;
903 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
904 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
907 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
908 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
910 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
915 /* Check that IP address is local and matches incoming interface. */
916 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
917 if (~0 == fib_index0)
919 error0 = ETHERNET_ARP_ERROR_interface_no_table;
923 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
924 &arp0->ip4_over_ethernet[1].ip4,
926 dst_flags = fib_entry_get_flags_for_source (dst_fei,
927 FIB_SOURCE_INTERFACE);
930 fib_entry_get_resolving_interface_for_source (dst_fei,
931 FIB_SOURCE_INTERFACE);
933 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
935 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
939 /* Honor unnumbered interface, if any */
940 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
942 /* Source must also be local to subnet of matching interface address. */
943 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
944 &arp0->ip4_over_ethernet[0].ip4,
946 src_flags = fib_entry_get_flags (src_fei);
948 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
949 (FIB_ENTRY_FLAG_CONNECTED & src_flags)) ||
950 sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
952 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
956 /* Reject requests/replies with our local interface address. */
957 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
959 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
963 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
964 fib_entry_get_prefix (dst_fei, &pfx0);
965 if_addr0 = &pfx0.fp_addr.ip4;
967 /* Fill in ethernet header. */
968 eth0 = ethernet_buffer_get_header (p0);
970 /* Trash ARP packets whose ARP-level source addresses do not
971 match their L2-frame-level source addresses */
972 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
973 sizeof (eth0->src_address)))
975 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
979 /* Learn or update sender's mapping only for requests or unicasts
980 that don't match local interface address. */
981 if (ethernet_address_cast (eth0->dst_address) ==
982 ETHERNET_ADDRESS_UNICAST || is_request0)
984 if (am->limit_arp_cache_size &&
985 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
986 unset_random_arp_entry ();
988 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
989 &arp0->ip4_over_ethernet[0],
991 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
994 /* Only send a reply for requests sent which match a local interface. */
995 if (!(is_request0 && dst_is_local0))
999 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1000 ETHERNET_ARP_ERROR_replies_received : error0);
1006 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1007 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1009 /* Send reply back through input interface */
1010 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1011 next0 = ARP_INPUT_NEXT_REPLY_TX;
1013 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1015 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1017 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1018 hw_if0->hw_address, 6);
1019 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1022 /* Hardware must be ethernet-like. */
1023 ASSERT (vec_len (hw_if0->hw_address) == 6);
1025 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1026 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1028 /* Figure out how much to rewind current data from adjacency. */
1029 /* get the adj from the destination's covering connected */
1033 adj_get (fib_entry_get_adj_for_source
1034 (ip4_fib_table_lookup
1035 (ip4_fib_get (fib_index0),
1036 &arp0->ip4_over_ethernet[1].ip4, 31),
1037 FIB_SOURCE_INTERFACE));
1038 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1040 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1044 arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0);
1046 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1048 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1049 n_left_to_next, pi0, next0);
1051 n_replies_sent += 1;
1055 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1056 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1057 arp0->ip4_over_ethernet[1].ip4.as_u32))
1059 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1062 /* See if proxy arp is configured for the address */
1065 vnet_sw_interface_t *si;
1066 u32 this_addr = clib_net_to_host_u32
1067 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1070 si = vnet_get_sw_interface (vnm, sw_if_index0);
1072 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1075 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1078 vec_foreach (pa, am->proxy_arps)
1080 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1081 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1083 /* an ARP request hit in the proxy-arp table? */
1084 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1085 (fib_index0 == pa->fib_index))
1087 eth0 = ethernet_buffer_get_header (p0);
1089 arp0->ip4_over_ethernet[1].ip4.data_u32;
1092 * Rewind buffer, direct code above not to
1093 * think too hard about it.
1095 if_addr0 = &proxy_src;
1097 i32 ethernet_start =
1098 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1099 i32 rewind = p0->current_data - ethernet_start;
1100 vlib_buffer_advance (p0, -rewind);
1101 n_proxy_arp_replies_sent++;
1109 next0 = ARP_INPUT_NEXT_DROP;
1110 p0->error = node->errors[error0];
1112 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1113 n_left_to_next, pi0, next0);
1116 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1119 vlib_error_count (vm, node->node_index,
1120 ETHERNET_ARP_ERROR_replies_sent,
1121 n_replies_sent - n_proxy_arp_replies_sent);
1123 vlib_error_count (vm, node->node_index,
1124 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1125 n_proxy_arp_replies_sent);
1126 return frame->n_vectors;
1129 static char *ethernet_arp_error_strings[] = {
1130 #define _(sym,string) string,
1131 foreach_ethernet_arp_error
1136 VLIB_REGISTER_NODE (arp_input_node, static) =
1138 .function = arp_input,
1139 .name = "arp-input",
1140 .vector_size = sizeof (u32),
1141 .n_errors = ETHERNET_ARP_N_ERROR,
1142 .error_strings = ethernet_arp_error_strings,
1143 .n_next_nodes = ARP_INPUT_N_NEXT,
1145 [ARP_INPUT_NEXT_DROP] = "error-drop",
1146 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1148 .format_buffer = format_ethernet_arp_header,
1149 .format_trace = format_ethernet_arp_input_trace,
1154 ip4_arp_entry_sort (void *a1, void *a2)
1156 ethernet_arp_ip4_entry_t *e1 = a1;
1157 ethernet_arp_ip4_entry_t *e2 = a2;
1160 vnet_main_t *vnm = vnet_get_main ();
1162 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1164 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1168 static clib_error_t *
1169 show_ip4_arp (vlib_main_t * vm,
1170 unformat_input_t * input, vlib_cli_command_t * cmd)
1172 vnet_main_t *vnm = vnet_get_main ();
1173 ethernet_arp_main_t *am = ðernet_arp_main;
1174 ethernet_arp_ip4_entry_t *e, *es;
1175 ethernet_proxy_arp_t *pa;
1176 clib_error_t *error = 0;
1179 /* Filter entries by interface if given. */
1181 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1185 pool_foreach (e, am->ip4_entry_pool,
1187 vec_add1 (es, e[0]);
1193 vec_sort_with_function (es, ip4_arp_entry_sort);
1194 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1197 if (sw_if_index != ~0 && e->sw_if_index != sw_if_index)
1199 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1204 if (vec_len (am->proxy_arps))
1206 vlib_cli_output (vm, "Proxy arps enabled for:");
1207 vec_foreach (pa, am->proxy_arps)
1209 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1211 format_ip4_address, &pa->lo_addr,
1212 format_ip4_address, &pa->hi_addr);
1220 * Display all the IPv4 ARP entries.
1223 * Example of how to display the IPv4 ARP table:
1224 * @cliexstart{show ip arp}
1225 * Time FIB IP4 Flags Ethernet Interface
1226 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1227 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1228 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1229 * Proxy arps enabled for:
1230 * Fib_index 0 6.0.0.1 - 6.0.0.11
1234 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1235 .path = "show ip arp",
1236 .function = show_ip4_arp,
1237 .short_help = "show ip arp",
1243 pg_edit_t l2_type, l3_type;
1244 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1250 } ip4_over_ethernet[2];
1251 } pg_ethernet_arp_header_t;
1254 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1256 /* Initialize fields that are not bit fields in the IP header. */
1257 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1260 _(n_l2_address_bytes);
1261 _(n_l3_address_bytes);
1263 _(ip4_over_ethernet[0].ethernet);
1264 _(ip4_over_ethernet[0].ip4);
1265 _(ip4_over_ethernet[1].ethernet);
1266 _(ip4_over_ethernet[1].ip4);
1271 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1273 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1274 pg_ethernet_arp_header_t *p;
1277 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1279 pg_ethernet_arp_header_init (p);
1282 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1283 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1284 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1285 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1287 if (!unformat (input, "%U: %U/%U -> %U/%U",
1289 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1291 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1293 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1295 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1297 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1299 /* Free up any edits we may have added. */
1300 pg_free_edit_group (s);
1307 ip4_set_arp_limit (u32 arp_limit)
1309 ethernet_arp_main_t *am = ðernet_arp_main;
1311 am->limit_arp_cache_size = arp_limit;
1316 * @brief Control Plane hook to remove an ARP entry
1319 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1320 u32 sw_if_index, void *a_arg)
1322 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1323 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1325 args.sw_if_index = sw_if_index;
1326 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1327 args.ether_type = ARP_ETHER_TYPE_IP4;
1328 clib_memcpy (&args.a, a, sizeof (*a));
1330 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1331 (u8 *) & args, sizeof (args));
1336 * @brief Internally generated event to flush the ARP cache on an
1337 * interface state change event.
1338 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1339 * address from the corresponding adjacencies.
1342 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1344 arp_ether_type_t et, void *a_arg)
1346 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1347 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1349 args.sw_if_index = sw_if_index;
1350 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1351 args.ether_type = et;
1352 clib_memcpy (&args.a, a, sizeof (*a));
1354 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1355 (u8 *) & args, sizeof (args));
1360 * @brief Internally generated event to populate the ARP cache on an
1361 * interface state change event.
1362 * For static entries this will re-source the adjacencies.
1364 * @param sw_if_index The interface on which the ARP entires are acted
1365 * @param et The ether type of those ARP entries.
1368 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1370 arp_ether_type_t et, void *a_arg)
1372 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1373 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1375 args.sw_if_index = sw_if_index;
1376 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1377 args.ether_type = et;
1378 clib_memcpy (&args.a, a, sizeof (*a));
1380 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1381 (u8 *) & args, sizeof (args));
1386 * arp_add_del_interface_address
1388 * callback when an interface address is added or deleted
1391 arp_add_del_interface_address (ip4_main_t * im,
1394 ip4_address_t * address,
1396 u32 if_address_index, u32 is_del)
1399 * Flush the ARP cache of all entries covered by the address
1400 * that is being removed.
1402 ethernet_arp_main_t *am = ðernet_arp_main;
1403 ethernet_arp_ip4_entry_t *e;
1405 if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
1410 ethernet_arp_interface_t *eai;
1411 u32 i, *to_delete = 0;
1414 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1416 hash_foreach_pair (pair, eai->arp_entries, (
1420 (am->ip4_entry_pool,
1423 (ip4_destination_matches_route
1424 (im, &e->ip4_address,
1425 address, address_length))
1427 vec_add1 (to_delete,
1429 am->ip4_entry_pool);}
1433 for (i = 0; i < vec_len (to_delete); i++)
1435 ethernet_arp_ip4_over_ethernet_address_t delme;
1436 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1438 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1439 delme.ip4.as_u32 = e->ip4_address.as_u32;
1441 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1443 ARP_ETHER_TYPE_BOTH, &delme);
1446 vec_free (to_delete);
1451 ethernet_arp_sw_interface_mpls_state_change (u32 sw_if_index, u32 is_enable)
1453 ethernet_arp_main_t *am = ðernet_arp_main;
1454 ethernet_arp_ip4_entry_t *e;
1455 ethernet_arp_interface_t *eai;
1456 u32 i, *to_update = 0;
1459 if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
1462 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1465 eai->flags |= ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
1467 eai->flags &= ~ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
1469 hash_foreach_pair (pair, eai->arp_entries, (
1471 vec_add1 (to_update,
1476 for (i = 0; i < vec_len (to_update); i++)
1478 ethernet_arp_ip4_over_ethernet_address_t updateme;
1479 e = pool_elt_at_index (am->ip4_entry_pool, to_update[i]);
1481 clib_memcpy (&updateme.ethernet, e->ethernet_address, 6);
1482 updateme.ip4.as_u32 = e->ip4_address.as_u32;
1486 vnet_arp_populate_ip4_over_ethernet (vnet_get_main (),
1488 ARP_ETHER_TYPE_MPLS,
1495 vec_free (to_update);
1498 static clib_error_t *
1499 ethernet_arp_init (vlib_main_t * vm)
1501 ethernet_arp_main_t *am = ðernet_arp_main;
1502 ip4_main_t *im = &ip4_main;
1503 clib_error_t *error;
1506 if ((error = vlib_call_init_function (vm, ethernet_init)))
1509 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1511 pn = pg_get_node (arp_input_node.index);
1512 pn->unformat_edit = unformat_pg_arp_header;
1514 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1515 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1516 foreach_ethernet_arp_opcode;
1519 /* $$$ configurable */
1520 am->limit_arp_cache_size = 50000;
1522 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1523 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1525 /* don't trace ARP error packets */
1527 vlib_node_runtime_t *rt =
1528 vlib_node_get_runtime (vm, arp_input_node.index);
1531 vnet_pcap_drop_trace_filter_add_del \
1532 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1534 foreach_ethernet_arp_error
1538 ip4_add_del_interface_address_callback_t cb;
1539 cb.function = arp_add_del_interface_address;
1540 cb.function_opaque = 0;
1541 vec_add1 (im->add_del_interface_address_callbacks, cb);
1543 vec_add1 (mpls_main.mpls_interface_state_change_callbacks,
1544 ethernet_arp_sw_interface_mpls_state_change);
1549 VLIB_INIT_FUNCTION (ethernet_arp_init);
1552 arp_mk_incomplete (ethernet_arp_interface_t * eai,
1553 ethernet_arp_ip4_entry_t * e, arp_ether_type_t et)
1555 fib_prefix_t pfx = {
1557 .fp_proto = FIB_PROTOCOL_IP4,
1559 .ip4 = e->ip4_address,
1564 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
1566 if ((ARP_ETHER_TYPE_IP4 & et) &&
1567 (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4]))
1570 * revert the adj this ARP entry sourced to incomplete
1572 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4], NULL);
1575 * remove the FIB erntry the ARP entry sourced
1577 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_ADJ);
1580 * Unlock the adj now that the ARP entry is no longer a source
1582 adj_unlock (e->adj_index[FIB_LINK_IP4]);
1583 e->adj_index[FIB_LINK_IP4] = ADJ_INDEX_INVALID;
1585 if ((ARP_ETHER_TYPE_MPLS & et) &&
1586 (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS]))
1589 * revert the adj this ARP entry sourced to incomplete
1591 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS], NULL);
1594 * Unlock the adj now that the ARP entry is no longer a source
1596 adj_unlock (e->adj_index[FIB_LINK_MPLS]);
1597 e->adj_index[FIB_LINK_MPLS] = ADJ_INDEX_INVALID;
1602 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1604 ethernet_arp_main_t *am = ðernet_arp_main;
1606 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1607 pool_put (am->ip4_entry_pool, e);
1610 static ethernet_arp_ip4_entry_t *
1611 arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
1613 ethernet_arp_main_t *am = ðernet_arp_main;
1614 ethernet_arp_ip4_entry_t *e = NULL;
1617 if (NULL != eai->arp_entries)
1619 p = hash_get (eai->arp_entries, addr->as_u32);
1623 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
1630 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1631 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1634 ethernet_arp_main_t *am = ðernet_arp_main;
1635 ethernet_arp_ip4_entry_t *e;
1636 ethernet_arp_interface_t *eai;
1638 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1640 e = arp_entry_find (eai, &args->a.ip4);
1644 arp_mk_incomplete (eai, e, ARP_ETHER_TYPE_BOTH);
1645 arp_entry_free (eai, e);
1652 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1653 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1656 ethernet_arp_main_t *am = ðernet_arp_main;
1657 ethernet_arp_ip4_entry_t *e;
1658 ethernet_arp_interface_t *eai;
1660 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1662 e = arp_entry_find (eai, &args->a.ip4);
1666 arp_mk_incomplete (eai, e, args->ether_type);
1669 * The difference between flush and unset, is that an unset
1670 * means delete for static and dynamic entries. A flush
1671 * means delete only for dynamic. Flushing is what the DP
1672 * does in response to interface events. unset is only done
1673 * by the control plane.
1675 if ((e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC) &&
1676 (args->ether_type & ARP_ETHER_TYPE_IP4))
1678 arp_entry_free (eai, e);
1685 vnet_arp_populate_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 arp_mk_complete (eai, e, args->ether_type);
1705 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1708 vnet_main_t *vm = vnet_get_main ();
1709 ASSERT (os_get_cpu_number () == 0);
1711 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1712 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1713 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1714 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1715 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1716 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1718 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1722 * @brief Invoked when the interface's admin state changes
1724 static clib_error_t *
1725 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1726 u32 sw_if_index, u32 flags)
1728 ethernet_arp_main_t *am = ðernet_arp_main;
1729 ethernet_arp_ip4_entry_t *e;
1730 u32 i, *to_delete = 0;
1733 pool_foreach (e, am->ip4_entry_pool,
1735 if (e->sw_if_index == sw_if_index)
1737 vec_add1 (to_delete, e - am->ip4_entry_pool);
1742 for (i = 0; i < vec_len (to_delete); i++)
1744 ethernet_arp_ip4_over_ethernet_address_t delme;
1745 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1747 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1748 delme.ip4.as_u32 = e->ip4_address.as_u32;
1750 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1752 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index,
1753 ARP_ETHER_TYPE_BOTH, &delme);
1757 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index,
1758 ARP_ETHER_TYPE_BOTH, &delme);
1762 vec_free (to_delete);
1768 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1772 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1777 for (i = 3; i >= 0; i--)
1779 old = a->ip4.as_u8[i];
1780 a->ip4.as_u8[i] += 1;
1781 if (old < a->ip4.as_u8[i])
1785 for (i = 5; i >= 0; i--)
1787 old = a->ethernet[i];
1788 a->ethernet[i] += 1;
1789 if (old < a->ethernet[i])
1795 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1796 u32 sw_if_index, void *a_arg, int is_static)
1798 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1799 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1801 args.sw_if_index = sw_if_index;
1802 args.is_static = is_static;
1804 args.ether_type = ARP_ETHER_TYPE_IP4;
1805 clib_memcpy (&args.a, a, sizeof (*a));
1807 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1808 (u8 *) & args, sizeof (args));
1813 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1814 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1816 ethernet_arp_main_t *am = ðernet_arp_main;
1817 ethernet_proxy_arp_t *pa;
1818 u32 found_at_index = ~0;
1820 vec_foreach (pa, am->proxy_arps)
1822 if (pa->lo_addr == lo_addr->as_u32
1823 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1825 found_at_index = pa - am->proxy_arps;
1830 if (found_at_index != ~0)
1832 /* Delete, otherwise it's already in the table */
1834 vec_delete (am->proxy_arps, 1, found_at_index);
1837 /* delete, no such entry */
1839 return VNET_API_ERROR_NO_SUCH_ENTRY;
1841 /* add, not in table */
1842 vec_add2 (am->proxy_arps, pa, 1);
1843 pa->lo_addr = lo_addr->as_u32;
1844 pa->hi_addr = hi_addr->as_u32;
1845 pa->fib_index = fib_index;
1850 * Remove any proxy arp entries asdociated with the
1854 vnet_proxy_arp_fib_reset (u32 fib_id)
1856 ip4_main_t *im = &ip4_main;
1857 ethernet_arp_main_t *am = ðernet_arp_main;
1858 ethernet_proxy_arp_t *pa;
1859 u32 *entries_to_delete = 0;
1864 p = hash_get (im->fib_index_by_table_id, fib_id);
1866 return VNET_API_ERROR_NO_SUCH_ENTRY;
1869 vec_foreach (pa, am->proxy_arps)
1871 if (pa->fib_index == fib_index)
1873 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1877 for (i = 0; i < vec_len (entries_to_delete); i++)
1879 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1882 vec_free (entries_to_delete);
1887 static clib_error_t *
1888 ip_arp_add_del_command_fn (vlib_main_t * vm,
1889 unformat_input_t * input, vlib_cli_command_t * cmd)
1891 vnet_main_t *vnm = vnet_get_main ();
1893 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1902 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1904 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1905 if (unformat (input, "%U %U %U",
1906 unformat_vnet_sw_interface, vnm, &sw_if_index,
1907 unformat_ip4_address, &addr.ip4,
1908 unformat_ethernet_address, &addr.ethernet))
1911 else if (unformat (input, "delete") || unformat (input, "del"))
1914 else if (unformat (input, "static"))
1917 else if (unformat (input, "count %d", &count))
1920 else if (unformat (input, "fib-id %d", &fib_id))
1922 ip4_main_t *im = &ip4_main;
1923 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1925 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1929 else if (unformat (input, "proxy %U - %U",
1930 unformat_ip4_address, &lo_addr.ip4,
1931 unformat_ip4_address, &hi_addr.ip4))
1939 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1948 for (i = 0; i < count; i++)
1952 uword event_type, *event_data = 0;
1954 /* Park the debug CLI until the arp entry is installed */
1955 vnet_register_ip4_arp_resolution_event
1956 (vnm, &addr.ip4, vlib_current_process (vm),
1957 1 /* type */ , 0 /* data */ );
1959 vnet_arp_set_ip4_over_ethernet
1960 (vnm, sw_if_index, &addr, is_static);
1962 vlib_process_wait_for_event (vm);
1963 event_type = vlib_process_get_events (vm, &event_data);
1964 vec_reset_length (event_data);
1965 if (event_type != 1)
1966 clib_warning ("event type %d unexpected", event_type);
1969 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
1971 increment_ip4_and_mac_address (&addr);
1976 return clib_error_return (0, "unknown input `%U'",
1977 format_unformat_error, input);
1985 * Add or delete IPv4 ARP cache entries.
1987 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
1988 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
1989 * any order and combination.
1993 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
1994 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
1995 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1996 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
1998 * To add or delete an IPv4 ARP cache entry to or from a specific fib
2000 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2001 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2003 * Add or delete IPv4 static ARP cache entries as follows:
2004 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2005 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2007 * For testing / debugging purposes, the 'set ip arp' command can add or
2008 * delete multiple entries. Supply the 'count N' parameter:
2009 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2013 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2014 .path = "set ip arp",
2016 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2017 .function = ip_arp_add_del_command_fn,
2021 static clib_error_t *
2022 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2023 unformat_input_t * input,
2024 vlib_cli_command_t * cmd)
2026 vnet_main_t *vnm = vnet_get_main ();
2028 vnet_sw_interface_t *si;
2032 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2034 if (unformat (input, "%U", unformat_vnet_sw_interface,
2037 else if (unformat (input, "enable") || unformat (input, "on"))
2039 else if (unformat (input, "disable") || unformat (input, "off"))
2046 return clib_error_return (0, "unknown input '%U'",
2047 format_unformat_error, input);
2049 si = vnet_get_sw_interface (vnm, sw_if_index);
2052 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2054 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2061 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2062 * requests for the indicated address range. Multiple proxy-arp
2063 * ranges may be provisioned.
2065 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2066 * Also, the underlying implementation has not been performance-tuned.
2067 * Avoid creating an unnecessarily large set of ranges.
2070 * To enable proxy arp on a range of addresses, use:
2071 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2072 * Append 'del' to delete a range of proxy ARP addresses:
2073 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2074 * You must then specifically enable proxy arp on individual interfaces:
2075 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2076 * To disable proxy arp on an individual interface:
2077 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2080 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2081 .path = "set interface proxy-arp",
2083 "set interface proxy-arp <intfc> [enable|disable]",
2084 .function = set_int_proxy_arp_command_fn,
2090 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2091 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2095 ARP_TERM_NEXT_L2_OUTPUT,
2100 u32 arp_term_next_node_index[32];
2103 arp_term_l2bd (vlib_main_t * vm,
2104 vlib_node_runtime_t * node, vlib_frame_t * frame)
2106 l2input_main_t *l2im = &l2input_main;
2107 u32 n_left_from, next_index, *from, *to_next;
2108 u32 n_replies_sent = 0;
2109 u16 last_bd_index = ~0;
2110 l2_bridge_domain_t *last_bd_config = 0;
2111 l2_input_config_t *cfg0;
2113 from = vlib_frame_vector_args (frame);
2114 n_left_from = frame->n_vectors;
2115 next_index = node->cached_next_index;
2117 while (n_left_from > 0)
2121 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2123 while (n_left_from > 0 && n_left_to_next > 0)
2126 ethernet_header_t *eth0;
2127 ethernet_arp_header_t *arp0;
2130 u32 pi0, error0, next0, sw_if_index0;
2141 n_left_to_next -= 1;
2143 p0 = vlib_get_buffer (vm, pi0);
2144 eth0 = vlib_buffer_get_current (p0);
2145 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2146 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2147 arp0 = (ethernet_arp_header_t *) l3h0;
2149 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2151 clib_host_to_net_u16
2152 (ETHERNET_ARP_OPCODE_request))))
2155 /* Must be ARP request packet here */
2156 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2157 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2159 u8 *t0 = vlib_add_trace (vm, node, p0,
2160 sizeof (ethernet_arp_input_trace_t));
2161 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2164 error0 = ETHERNET_ARP_ERROR_replies_sent;
2167 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
2168 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2171 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2172 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2174 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2179 /* Trash ARP packets whose ARP-level source addresses do not
2180 match their L2-frame-level source addresses */
2183 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2184 sizeof (eth0->src_address))))
2186 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2190 /* Check if anyone want ARP request events for L2 BDs */
2192 pending_resolution_t *mc;
2193 ethernet_arp_main_t *am = ðernet_arp_main;
2194 uword *p = hash_get (am->mac_changes_by_address, 0);
2195 if (p && (vnet_buffer (p0)->l2.shg == 0))
2196 { // Only SHG 0 interface which is more likely local
2197 u32 next_index = p[0];
2198 while (next_index != (u32) ~ 0)
2200 int (*fp) (u32, u8 *, u32, u32);
2202 mc = pool_elt_at_index (am->mac_changes, next_index);
2203 fp = mc->data_callback;
2204 /* Call the callback, return 1 to suppress dup events */
2206 rv = (*fp) (mc->data,
2207 arp0->ip4_over_ethernet[0].ethernet,
2209 arp0->ip4_over_ethernet[0].ip4.as_u32);
2210 /* Signal the resolver process */
2212 vlib_process_signal_event (vm, mc->node_index,
2213 mc->type_opaque, mc->data);
2214 next_index = mc->next_index;
2219 /* lookup BD mac_by_ip4 hash table for MAC entry */
2220 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2221 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2222 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2223 || (last_bd_index == (u16) ~ 0)))
2225 last_bd_index = bd_index0;
2226 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2228 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2230 if (PREDICT_FALSE (!macp0))
2231 goto next_l2_feature; /* MAC not found */
2233 /* MAC found, send ARP reply -
2234 Convert ARP request packet to ARP reply */
2235 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2236 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2237 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2238 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2239 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2240 clib_memcpy (eth0->src_address, macp0, 6);
2241 n_replies_sent += 1;
2244 /* For BVI, need to use l2-fwd node to send ARP reply as
2245 l2-output node cannot output packet to BVI properly */
2246 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2247 if (PREDICT_FALSE (cfg0->bvi))
2249 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2250 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2251 goto next_l2_feature;
2254 /* Send ARP/ND reply back out input interface through l2-output */
2255 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2256 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2257 /* Note that output to VXLAN tunnel will fail due to SHG which
2258 is probably desireable since ARP termination is not intended
2259 for ARP requests from other hosts. If output to VXLAN tunnel is
2260 required, however, can just clear the SHG in packet as follows:
2261 vnet_buffer(p0)->l2.shg = 0; */
2262 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2263 n_left_to_next, pi0, next0);
2267 /* IP6 ND event notification or solicitation handling to generate
2268 local response instead of flooding */
2269 iph0 = (ip6_header_t *) l3h0;
2270 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2271 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2272 !ip6_address_is_unspecified
2273 (&iph0->src_address)))
2275 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2276 if (vnet_ip6_nd_term (vm, node, p0, eth0, iph0, sw_if_index0,
2277 vnet_buffer (p0)->l2.bd_index,
2278 vnet_buffer (p0)->l2.shg))
2279 goto output_response;
2284 u32 feature_bitmap0 =
2285 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2286 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2287 next0 = feat_bitmap_get_next_node_index (arp_term_next_node_index,
2289 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2290 n_left_to_next, pi0, next0);
2295 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2296 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2297 arp0->ip4_over_ethernet[1].ip4.as_u32))
2299 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2301 next0 = ARP_TERM_NEXT_DROP;
2302 p0->error = node->errors[error0];
2304 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2305 n_left_to_next, pi0, next0);
2308 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2311 vlib_error_count (vm, node->node_index,
2312 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2313 return frame->n_vectors;
2317 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2318 .function = arp_term_l2bd,
2319 .name = "arp-term-l2bd",
2320 .vector_size = sizeof (u32),
2321 .n_errors = ETHERNET_ARP_N_ERROR,
2322 .error_strings = ethernet_arp_error_strings,
2323 .n_next_nodes = ARP_TERM_N_NEXT,
2325 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2326 [ARP_TERM_NEXT_DROP] = "error-drop",
2328 .format_buffer = format_ethernet_arp_header,
2329 .format_trace = format_arp_term_input_trace,
2334 arp_term_init (vlib_main_t * vm)
2335 { // Initialize the feature next-node indexes
2336 feat_bitmap_init_next_nodes (vm,
2337 arp_term_l2bd_node.index,
2339 l2input_get_feat_names (),
2340 arp_term_next_node_index);
2344 VLIB_INIT_FUNCTION (arp_term_init);
2347 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2349 if (e->sw_if_index == sw_if_index)
2352 if (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4])
2354 // the update rewrite function takes the dst mac (which is not changing)
2355 // the new source mac will be retrieved from the interface
2356 // when the full rewrite is constructed.
2357 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4],
2358 e->ethernet_address);
2360 if (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS])
2362 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS],
2363 e->ethernet_address);
2370 ethernet_arp_change_mac (vnet_main_t * vnm, u32 sw_if_index)
2372 ethernet_arp_main_t *am = ðernet_arp_main;
2373 ethernet_arp_ip4_entry_t *e;
2376 pool_foreach (e, am->ip4_entry_pool,
2378 change_arp_mac (sw_if_index, e);
2384 * fd.io coding-style-patch-verification: ON
2387 * eval: (c-set-style "gnu")