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 (dst_fei);
928 conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
930 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
932 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
936 /* Honor unnumbered interface, if any */
937 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
939 /* Source must also be local to subnet of matching interface address. */
940 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
941 &arp0->ip4_over_ethernet[0].ip4,
943 src_flags = fib_entry_get_flags (src_fei);
945 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
946 (FIB_ENTRY_FLAG_CONNECTED & src_flags)) ||
947 sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
949 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
953 /* Reject requests/replies with our local interface address. */
954 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
956 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
960 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
961 fib_entry_get_prefix (dst_fei, &pfx0);
962 if_addr0 = &pfx0.fp_addr.ip4;
964 /* Fill in ethernet header. */
965 eth0 = ethernet_buffer_get_header (p0);
967 /* Trash ARP packets whose ARP-level source addresses do not
968 match their L2-frame-level source addresses */
969 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
970 sizeof (eth0->src_address)))
972 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
976 /* Learn or update sender's mapping only for requests or unicasts
977 that don't match local interface address. */
978 if (ethernet_address_cast (eth0->dst_address) ==
979 ETHERNET_ADDRESS_UNICAST || is_request0)
981 if (am->limit_arp_cache_size &&
982 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
983 unset_random_arp_entry ();
985 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
986 &arp0->ip4_over_ethernet[0],
988 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
991 /* Only send a reply for requests sent which match a local interface. */
992 if (!(is_request0 && dst_is_local0))
996 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
997 ETHERNET_ARP_ERROR_replies_received : error0);
1003 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1004 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1006 /* Send reply back through input interface */
1007 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1008 next0 = ARP_INPUT_NEXT_REPLY_TX;
1010 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1012 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1014 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1015 hw_if0->hw_address, 6);
1016 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1019 /* Hardware must be ethernet-like. */
1020 ASSERT (vec_len (hw_if0->hw_address) == 6);
1022 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1023 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1025 /* Figure out how much to rewind current data from adjacency. */
1026 /* get the adj from the destination's covering connected */
1030 adj_get (fib_entry_get_adj_for_source
1031 (ip4_fib_table_lookup
1032 (ip4_fib_get (fib_index0),
1033 &arp0->ip4_over_ethernet[1].ip4, 31),
1034 FIB_SOURCE_INTERFACE));
1035 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1037 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1041 arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0);
1043 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1045 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1046 n_left_to_next, pi0, next0);
1048 n_replies_sent += 1;
1052 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1053 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1054 arp0->ip4_over_ethernet[1].ip4.as_u32))
1056 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1059 /* See if proxy arp is configured for the address */
1062 vnet_sw_interface_t *si;
1063 u32 this_addr = clib_net_to_host_u32
1064 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1067 si = vnet_get_sw_interface (vnm, sw_if_index0);
1069 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1072 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1075 vec_foreach (pa, am->proxy_arps)
1077 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1078 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1080 /* an ARP request hit in the proxy-arp table? */
1081 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1082 (fib_index0 == pa->fib_index))
1084 eth0 = ethernet_buffer_get_header (p0);
1086 arp0->ip4_over_ethernet[1].ip4.data_u32;
1089 * Rewind buffer, direct code above not to
1090 * think too hard about it.
1092 if_addr0 = &proxy_src;
1094 i32 ethernet_start =
1095 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1096 i32 rewind = p0->current_data - ethernet_start;
1097 vlib_buffer_advance (p0, -rewind);
1098 n_proxy_arp_replies_sent++;
1106 next0 = ARP_INPUT_NEXT_DROP;
1107 p0->error = node->errors[error0];
1109 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1110 n_left_to_next, pi0, next0);
1113 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1116 vlib_error_count (vm, node->node_index,
1117 ETHERNET_ARP_ERROR_replies_sent,
1118 n_replies_sent - n_proxy_arp_replies_sent);
1120 vlib_error_count (vm, node->node_index,
1121 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1122 n_proxy_arp_replies_sent);
1123 return frame->n_vectors;
1126 static char *ethernet_arp_error_strings[] = {
1127 #define _(sym,string) string,
1128 foreach_ethernet_arp_error
1133 VLIB_REGISTER_NODE (arp_input_node, static) =
1135 .function = arp_input,
1136 .name = "arp-input",
1137 .vector_size = sizeof (u32),
1138 .n_errors = ETHERNET_ARP_N_ERROR,
1139 .error_strings = ethernet_arp_error_strings,
1140 .n_next_nodes = ARP_INPUT_N_NEXT,
1142 [ARP_INPUT_NEXT_DROP] = "error-drop",
1143 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1145 .format_buffer = format_ethernet_arp_header,
1146 .format_trace = format_ethernet_arp_input_trace,
1151 ip4_arp_entry_sort (void *a1, void *a2)
1153 ethernet_arp_ip4_entry_t *e1 = a1;
1154 ethernet_arp_ip4_entry_t *e2 = a2;
1157 vnet_main_t *vnm = vnet_get_main ();
1159 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1161 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1165 static clib_error_t *
1166 show_ip4_arp (vlib_main_t * vm,
1167 unformat_input_t * input, vlib_cli_command_t * cmd)
1169 vnet_main_t *vnm = vnet_get_main ();
1170 ethernet_arp_main_t *am = ðernet_arp_main;
1171 ethernet_arp_ip4_entry_t *e, *es;
1172 ethernet_proxy_arp_t *pa;
1173 clib_error_t *error = 0;
1176 /* Filter entries by interface if given. */
1178 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1182 pool_foreach (e, am->ip4_entry_pool,
1184 vec_add1 (es, e[0]);
1190 vec_sort_with_function (es, ip4_arp_entry_sort);
1191 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1194 if (sw_if_index != ~0 && e->sw_if_index != sw_if_index)
1196 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1201 if (vec_len (am->proxy_arps))
1203 vlib_cli_output (vm, "Proxy arps enabled for:");
1204 vec_foreach (pa, am->proxy_arps)
1206 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1208 format_ip4_address, &pa->lo_addr,
1209 format_ip4_address, &pa->hi_addr);
1217 * Display all the IPv4 ARP entries.
1220 * Example of how to display the IPv4 ARP table:
1221 * @cliexstart{show ip arp}
1222 * Time FIB IP4 Flags Ethernet Interface
1223 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1224 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1225 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1226 * Proxy arps enabled for:
1227 * Fib_index 0 6.0.0.1 - 6.0.0.11
1231 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1232 .path = "show ip arp",
1233 .function = show_ip4_arp,
1234 .short_help = "show ip arp",
1240 pg_edit_t l2_type, l3_type;
1241 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1247 } ip4_over_ethernet[2];
1248 } pg_ethernet_arp_header_t;
1251 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1253 /* Initialize fields that are not bit fields in the IP header. */
1254 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1257 _(n_l2_address_bytes);
1258 _(n_l3_address_bytes);
1260 _(ip4_over_ethernet[0].ethernet);
1261 _(ip4_over_ethernet[0].ip4);
1262 _(ip4_over_ethernet[1].ethernet);
1263 _(ip4_over_ethernet[1].ip4);
1268 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1270 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1271 pg_ethernet_arp_header_t *p;
1274 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1276 pg_ethernet_arp_header_init (p);
1279 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1280 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1281 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1282 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1284 if (!unformat (input, "%U: %U/%U -> %U/%U",
1286 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1288 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1290 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1292 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1294 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1296 /* Free up any edits we may have added. */
1297 pg_free_edit_group (s);
1304 ip4_set_arp_limit (u32 arp_limit)
1306 ethernet_arp_main_t *am = ðernet_arp_main;
1308 am->limit_arp_cache_size = arp_limit;
1313 * @brief Control Plane hook to remove an ARP entry
1316 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1317 u32 sw_if_index, void *a_arg)
1319 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1320 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1322 args.sw_if_index = sw_if_index;
1323 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1324 args.ether_type = ARP_ETHER_TYPE_IP4;
1325 clib_memcpy (&args.a, a, sizeof (*a));
1327 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1328 (u8 *) & args, sizeof (args));
1333 * @brief Internally generated event to flush the ARP cache on an
1334 * interface state change event.
1335 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1336 * address from the corresponding adjacencies.
1339 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1341 arp_ether_type_t et, void *a_arg)
1343 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1344 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1346 args.sw_if_index = sw_if_index;
1347 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1348 args.ether_type = et;
1349 clib_memcpy (&args.a, a, sizeof (*a));
1351 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1352 (u8 *) & args, sizeof (args));
1357 * @brief Internally generated event to populate the ARP cache on an
1358 * interface state change event.
1359 * For static entries this will re-source the adjacencies.
1361 * @param sw_if_index The interface on which the ARP entires are acted
1362 * @param et The ether type of those ARP entries.
1365 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1367 arp_ether_type_t et, void *a_arg)
1369 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1370 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1372 args.sw_if_index = sw_if_index;
1373 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1374 args.ether_type = et;
1375 clib_memcpy (&args.a, a, sizeof (*a));
1377 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1378 (u8 *) & args, sizeof (args));
1383 * arp_add_del_interface_address
1385 * callback when an interface address is added or deleted
1388 arp_add_del_interface_address (ip4_main_t * im,
1391 ip4_address_t * address,
1393 u32 if_address_index, u32 is_del)
1396 * Flush the ARP cache of all entries covered by the address
1397 * that is being removed.
1399 ethernet_arp_main_t *am = ðernet_arp_main;
1400 ethernet_arp_ip4_entry_t *e;
1402 if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
1407 ethernet_arp_interface_t *eai;
1408 u32 i, *to_delete = 0;
1411 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1413 hash_foreach_pair (pair, eai->arp_entries, (
1417 (am->ip4_entry_pool,
1420 (ip4_destination_matches_route
1421 (im, &e->ip4_address,
1422 address, address_length))
1424 vec_add1 (to_delete,
1426 am->ip4_entry_pool);}
1430 for (i = 0; i < vec_len (to_delete); i++)
1432 ethernet_arp_ip4_over_ethernet_address_t delme;
1433 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1435 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1436 delme.ip4.as_u32 = e->ip4_address.as_u32;
1438 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1440 ARP_ETHER_TYPE_BOTH, &delme);
1443 vec_free (to_delete);
1448 ethernet_arp_sw_interface_mpls_state_change (u32 sw_if_index, u32 is_enable)
1450 ethernet_arp_main_t *am = ðernet_arp_main;
1451 ethernet_arp_ip4_entry_t *e;
1452 ethernet_arp_interface_t *eai;
1453 u32 i, *to_update = 0;
1456 if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
1459 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1462 eai->flags |= ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
1464 eai->flags &= ~ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
1466 hash_foreach_pair (pair, eai->arp_entries, (
1468 vec_add1 (to_update,
1473 for (i = 0; i < vec_len (to_update); i++)
1475 ethernet_arp_ip4_over_ethernet_address_t updateme;
1476 e = pool_elt_at_index (am->ip4_entry_pool, to_update[i]);
1478 clib_memcpy (&updateme.ethernet, e->ethernet_address, 6);
1479 updateme.ip4.as_u32 = e->ip4_address.as_u32;
1483 vnet_arp_populate_ip4_over_ethernet (vnet_get_main (),
1485 ARP_ETHER_TYPE_MPLS,
1492 vec_free (to_update);
1495 static clib_error_t *
1496 ethernet_arp_init (vlib_main_t * vm)
1498 ethernet_arp_main_t *am = ðernet_arp_main;
1499 ip4_main_t *im = &ip4_main;
1500 clib_error_t *error;
1503 if ((error = vlib_call_init_function (vm, ethernet_init)))
1506 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1508 pn = pg_get_node (arp_input_node.index);
1509 pn->unformat_edit = unformat_pg_arp_header;
1511 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1512 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1513 foreach_ethernet_arp_opcode;
1516 /* $$$ configurable */
1517 am->limit_arp_cache_size = 50000;
1519 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1520 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1522 /* don't trace ARP error packets */
1524 vlib_node_runtime_t *rt =
1525 vlib_node_get_runtime (vm, arp_input_node.index);
1528 vnet_pcap_drop_trace_filter_add_del \
1529 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1531 foreach_ethernet_arp_error
1535 ip4_add_del_interface_address_callback_t cb;
1536 cb.function = arp_add_del_interface_address;
1537 cb.function_opaque = 0;
1538 vec_add1 (im->add_del_interface_address_callbacks, cb);
1540 vec_add1 (mpls_main.mpls_interface_state_change_callbacks,
1541 ethernet_arp_sw_interface_mpls_state_change);
1546 VLIB_INIT_FUNCTION (ethernet_arp_init);
1549 arp_mk_incomplete (ethernet_arp_interface_t * eai,
1550 ethernet_arp_ip4_entry_t * e, arp_ether_type_t et)
1552 fib_prefix_t pfx = {
1554 .fp_proto = FIB_PROTOCOL_IP4,
1556 .ip4 = e->ip4_address,
1561 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
1563 if ((ARP_ETHER_TYPE_IP4 & et) &&
1564 (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4]))
1567 * revert the adj this ARP entry sourced to incomplete
1569 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4], NULL);
1572 * remove the FIB erntry the ARP entry sourced
1574 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_ADJ);
1577 * Unlock the adj now that the ARP entry is no longer a source
1579 adj_unlock (e->adj_index[FIB_LINK_IP4]);
1580 e->adj_index[FIB_LINK_IP4] = ADJ_INDEX_INVALID;
1582 if ((ARP_ETHER_TYPE_MPLS & et) &&
1583 (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS]))
1586 * revert the adj this ARP entry sourced to incomplete
1588 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS], NULL);
1591 * Unlock the adj now that the ARP entry is no longer a source
1593 adj_unlock (e->adj_index[FIB_LINK_MPLS]);
1594 e->adj_index[FIB_LINK_MPLS] = ADJ_INDEX_INVALID;
1599 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1601 ethernet_arp_main_t *am = ðernet_arp_main;
1603 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1604 pool_put (am->ip4_entry_pool, e);
1607 static ethernet_arp_ip4_entry_t *
1608 arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
1610 ethernet_arp_main_t *am = ðernet_arp_main;
1611 ethernet_arp_ip4_entry_t *e = NULL;
1614 if (NULL != eai->arp_entries)
1616 p = hash_get (eai->arp_entries, addr->as_u32);
1620 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
1627 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1628 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1631 ethernet_arp_main_t *am = ðernet_arp_main;
1632 ethernet_arp_ip4_entry_t *e;
1633 ethernet_arp_interface_t *eai;
1635 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1637 e = arp_entry_find (eai, &args->a.ip4);
1641 arp_mk_incomplete (eai, e, ARP_ETHER_TYPE_BOTH);
1642 arp_entry_free (eai, e);
1649 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1650 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1653 ethernet_arp_main_t *am = ðernet_arp_main;
1654 ethernet_arp_ip4_entry_t *e;
1655 ethernet_arp_interface_t *eai;
1657 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1659 e = arp_entry_find (eai, &args->a.ip4);
1663 arp_mk_incomplete (eai, e, args->ether_type);
1666 * The difference between flush and unset, is that an unset
1667 * means delete for static and dynamic entries. A flush
1668 * means delete only for dynamic. Flushing is what the DP
1669 * does in response to interface events. unset is only done
1670 * by the control plane.
1672 if ((e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC) &&
1673 (args->ether_type & ARP_ETHER_TYPE_IP4))
1675 arp_entry_free (eai, e);
1682 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1683 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1686 ethernet_arp_main_t *am = ðernet_arp_main;
1687 ethernet_arp_ip4_entry_t *e;
1688 ethernet_arp_interface_t *eai;
1690 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1692 e = arp_entry_find (eai, &args->a.ip4);
1696 arp_mk_complete (eai, e, args->ether_type);
1702 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1705 vnet_main_t *vm = vnet_get_main ();
1706 ASSERT (os_get_cpu_number () == 0);
1708 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1709 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1710 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1711 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1712 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1713 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1715 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1719 * @brief Invoked when the interface's admin state changes
1721 static clib_error_t *
1722 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1723 u32 sw_if_index, u32 flags)
1725 ethernet_arp_main_t *am = ðernet_arp_main;
1726 ethernet_arp_ip4_entry_t *e;
1727 u32 i, *to_delete = 0;
1730 pool_foreach (e, am->ip4_entry_pool,
1732 if (e->sw_if_index == sw_if_index)
1734 vec_add1 (to_delete, e - am->ip4_entry_pool);
1739 for (i = 0; i < vec_len (to_delete); i++)
1741 ethernet_arp_ip4_over_ethernet_address_t delme;
1742 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1744 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1745 delme.ip4.as_u32 = e->ip4_address.as_u32;
1747 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1749 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index,
1750 ARP_ETHER_TYPE_BOTH, &delme);
1754 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index,
1755 ARP_ETHER_TYPE_BOTH, &delme);
1759 vec_free (to_delete);
1765 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1769 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1774 for (i = 3; i >= 0; i--)
1776 old = a->ip4.as_u8[i];
1777 a->ip4.as_u8[i] += 1;
1778 if (old < a->ip4.as_u8[i])
1782 for (i = 5; i >= 0; i--)
1784 old = a->ethernet[i];
1785 a->ethernet[i] += 1;
1786 if (old < a->ethernet[i])
1792 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1793 u32 sw_if_index, void *a_arg, int is_static)
1795 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1796 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1798 args.sw_if_index = sw_if_index;
1799 args.is_static = is_static;
1801 args.ether_type = ARP_ETHER_TYPE_IP4;
1802 clib_memcpy (&args.a, a, sizeof (*a));
1804 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1805 (u8 *) & args, sizeof (args));
1810 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1811 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1813 ethernet_arp_main_t *am = ðernet_arp_main;
1814 ethernet_proxy_arp_t *pa;
1815 u32 found_at_index = ~0;
1817 vec_foreach (pa, am->proxy_arps)
1819 if (pa->lo_addr == lo_addr->as_u32
1820 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1822 found_at_index = pa - am->proxy_arps;
1827 if (found_at_index != ~0)
1829 /* Delete, otherwise it's already in the table */
1831 vec_delete (am->proxy_arps, 1, found_at_index);
1834 /* delete, no such entry */
1836 return VNET_API_ERROR_NO_SUCH_ENTRY;
1838 /* add, not in table */
1839 vec_add2 (am->proxy_arps, pa, 1);
1840 pa->lo_addr = lo_addr->as_u32;
1841 pa->hi_addr = hi_addr->as_u32;
1842 pa->fib_index = fib_index;
1847 * Remove any proxy arp entries asdociated with the
1851 vnet_proxy_arp_fib_reset (u32 fib_id)
1853 ip4_main_t *im = &ip4_main;
1854 ethernet_arp_main_t *am = ðernet_arp_main;
1855 ethernet_proxy_arp_t *pa;
1856 u32 *entries_to_delete = 0;
1861 p = hash_get (im->fib_index_by_table_id, fib_id);
1863 return VNET_API_ERROR_NO_SUCH_ENTRY;
1866 vec_foreach (pa, am->proxy_arps)
1868 if (pa->fib_index == fib_index)
1870 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1874 for (i = 0; i < vec_len (entries_to_delete); i++)
1876 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1879 vec_free (entries_to_delete);
1884 static clib_error_t *
1885 ip_arp_add_del_command_fn (vlib_main_t * vm,
1886 unformat_input_t * input, vlib_cli_command_t * cmd)
1888 vnet_main_t *vnm = vnet_get_main ();
1890 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1899 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1901 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1902 if (unformat (input, "%U %U %U",
1903 unformat_vnet_sw_interface, vnm, &sw_if_index,
1904 unformat_ip4_address, &addr.ip4,
1905 unformat_ethernet_address, &addr.ethernet))
1908 else if (unformat (input, "delete") || unformat (input, "del"))
1911 else if (unformat (input, "static"))
1914 else if (unformat (input, "count %d", &count))
1917 else if (unformat (input, "fib-id %d", &fib_id))
1919 ip4_main_t *im = &ip4_main;
1920 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1922 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1926 else if (unformat (input, "proxy %U - %U",
1927 unformat_ip4_address, &lo_addr.ip4,
1928 unformat_ip4_address, &hi_addr.ip4))
1936 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1945 for (i = 0; i < count; i++)
1949 uword event_type, *event_data = 0;
1951 /* Park the debug CLI until the arp entry is installed */
1952 vnet_register_ip4_arp_resolution_event
1953 (vnm, &addr.ip4, vlib_current_process (vm),
1954 1 /* type */ , 0 /* data */ );
1956 vnet_arp_set_ip4_over_ethernet
1957 (vnm, sw_if_index, &addr, is_static);
1959 vlib_process_wait_for_event (vm);
1960 event_type = vlib_process_get_events (vm, &event_data);
1961 vec_reset_length (event_data);
1962 if (event_type != 1)
1963 clib_warning ("event type %d unexpected", event_type);
1966 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
1968 increment_ip4_and_mac_address (&addr);
1973 return clib_error_return (0, "unknown input `%U'",
1974 format_unformat_error, input);
1982 * Add or delete IPv4 ARP cache entries.
1984 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
1985 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
1986 * any order and combination.
1990 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
1991 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
1992 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1993 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
1995 * To add or delete an IPv4 ARP cache entry to or from a specific fib
1997 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1998 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2000 * Add or delete IPv4 static ARP cache entries as follows:
2001 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2002 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2004 * For testing / debugging purposes, the 'set ip arp' command can add or
2005 * delete multiple entries. Supply the 'count N' parameter:
2006 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2010 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2011 .path = "set ip arp",
2013 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2014 .function = ip_arp_add_del_command_fn,
2018 static clib_error_t *
2019 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2020 unformat_input_t * input,
2021 vlib_cli_command_t * cmd)
2023 vnet_main_t *vnm = vnet_get_main ();
2025 vnet_sw_interface_t *si;
2029 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2031 if (unformat (input, "%U", unformat_vnet_sw_interface,
2034 else if (unformat (input, "enable") || unformat (input, "on"))
2036 else if (unformat (input, "disable") || unformat (input, "off"))
2043 return clib_error_return (0, "unknown input '%U'",
2044 format_unformat_error, input);
2046 si = vnet_get_sw_interface (vnm, sw_if_index);
2049 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2051 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2058 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2059 * requests for the indicated address range. Multiple proxy-arp
2060 * ranges may be provisioned.
2062 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2063 * Also, the underlying implementation has not been performance-tuned.
2064 * Avoid creating an unnecessarily large set of ranges.
2067 * To enable proxy arp on a range of addresses, use:
2068 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2069 * Append 'del' to delete a range of proxy ARP addresses:
2070 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2071 * You must then specifically enable proxy arp on individual interfaces:
2072 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2073 * To disable proxy arp on an individual interface:
2074 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2077 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2078 .path = "set interface proxy-arp",
2080 "set interface proxy-arp <intfc> [enable|disable]",
2081 .function = set_int_proxy_arp_command_fn,
2087 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2088 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2092 ARP_TERM_NEXT_L2_OUTPUT,
2097 u32 arp_term_next_node_index[32];
2100 arp_term_l2bd (vlib_main_t * vm,
2101 vlib_node_runtime_t * node, vlib_frame_t * frame)
2103 l2input_main_t *l2im = &l2input_main;
2104 u32 n_left_from, next_index, *from, *to_next;
2105 u32 n_replies_sent = 0;
2106 u16 last_bd_index = ~0;
2107 l2_bridge_domain_t *last_bd_config = 0;
2108 l2_input_config_t *cfg0;
2110 from = vlib_frame_vector_args (frame);
2111 n_left_from = frame->n_vectors;
2112 next_index = node->cached_next_index;
2114 while (n_left_from > 0)
2118 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2120 while (n_left_from > 0 && n_left_to_next > 0)
2123 ethernet_header_t *eth0;
2124 ethernet_arp_header_t *arp0;
2127 u32 pi0, error0, next0, sw_if_index0;
2138 n_left_to_next -= 1;
2140 p0 = vlib_get_buffer (vm, pi0);
2141 eth0 = vlib_buffer_get_current (p0);
2142 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2143 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2144 arp0 = (ethernet_arp_header_t *) l3h0;
2146 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2148 clib_host_to_net_u16
2149 (ETHERNET_ARP_OPCODE_request))))
2152 /* Must be ARP request packet here */
2153 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2154 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2156 u8 *t0 = vlib_add_trace (vm, node, p0,
2157 sizeof (ethernet_arp_input_trace_t));
2158 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2161 error0 = ETHERNET_ARP_ERROR_replies_sent;
2164 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
2165 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2168 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2169 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2171 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2176 /* Trash ARP packets whose ARP-level source addresses do not
2177 match their L2-frame-level source addresses */
2180 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2181 sizeof (eth0->src_address))))
2183 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2187 /* Check if anyone want ARP request events for L2 BDs */
2189 pending_resolution_t *mc;
2190 ethernet_arp_main_t *am = ðernet_arp_main;
2191 uword *p = hash_get (am->mac_changes_by_address, 0);
2192 if (p && (vnet_buffer (p0)->l2.shg == 0))
2193 { // Only SHG 0 interface which is more likely local
2194 u32 next_index = p[0];
2195 while (next_index != (u32) ~ 0)
2197 int (*fp) (u32, u8 *, u32, u32);
2199 mc = pool_elt_at_index (am->mac_changes, next_index);
2200 fp = mc->data_callback;
2201 /* Call the callback, return 1 to suppress dup events */
2203 rv = (*fp) (mc->data,
2204 arp0->ip4_over_ethernet[0].ethernet,
2206 arp0->ip4_over_ethernet[0].ip4.as_u32);
2207 /* Signal the resolver process */
2209 vlib_process_signal_event (vm, mc->node_index,
2210 mc->type_opaque, mc->data);
2211 next_index = mc->next_index;
2216 /* lookup BD mac_by_ip4 hash table for MAC entry */
2217 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2218 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2219 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2220 || (last_bd_index == (u16) ~ 0)))
2222 last_bd_index = bd_index0;
2223 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2225 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2227 if (PREDICT_FALSE (!macp0))
2228 goto next_l2_feature; /* MAC not found */
2230 /* MAC found, send ARP reply -
2231 Convert ARP request packet to ARP reply */
2232 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2233 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2234 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2235 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2236 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2237 clib_memcpy (eth0->src_address, macp0, 6);
2238 n_replies_sent += 1;
2241 /* For BVI, need to use l2-fwd node to send ARP reply as
2242 l2-output node cannot output packet to BVI properly */
2243 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2244 if (PREDICT_FALSE (cfg0->bvi))
2246 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2247 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2248 goto next_l2_feature;
2251 /* Send ARP/ND reply back out input interface through l2-output */
2252 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2253 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2254 /* Note that output to VXLAN tunnel will fail due to SHG which
2255 is probably desireable since ARP termination is not intended
2256 for ARP requests from other hosts. If output to VXLAN tunnel is
2257 required, however, can just clear the SHG in packet as follows:
2258 vnet_buffer(p0)->l2.shg = 0; */
2259 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2260 n_left_to_next, pi0, next0);
2264 /* IP6 ND event notification or solicitation handling to generate
2265 local response instead of flooding */
2266 iph0 = (ip6_header_t *) l3h0;
2267 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2268 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2269 !ip6_address_is_link_local_unicast
2270 (&iph0->src_address)
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")