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;
465 * prevent a DoS attack from the data-plane that
466 * spams us with no-op updates to the MAC address
468 if (0 == memcmp (e->ethernet_address,
469 a->ethernet, sizeof (e->ethernet_address)))
473 /* Update time stamp and ethernet address. */
474 clib_memcpy (e->ethernet_address, a->ethernet,
475 sizeof (e->ethernet_address));
476 e->cpu_time_last_updated = clib_cpu_time_now ();
478 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
480 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC;
482 arp_mk_complete (arp_int, e, ARP_ETHER_TYPE_BOTH);
484 /* Customer(s) waiting for this address to be resolved? */
485 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
491 while (next_index != (u32) ~ 0)
493 pr = pool_elt_at_index (am->pending_resolutions, next_index);
494 vlib_process_signal_event (vm, pr->node_index,
495 pr->type_opaque, pr->data);
496 next_index = pr->next_index;
497 pool_put (am->pending_resolutions, pr);
500 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
503 /* Customer(s) requesting ARP event for this address? */
504 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
510 while (next_index != (u32) ~ 0)
512 int (*fp) (u32, u8 *, u32, u32);
514 mc = pool_elt_at_index (am->mac_changes, next_index);
515 fp = mc->data_callback;
517 /* Call the user's data callback, return 1 to suppress dup events */
519 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
522 * Signal the resolver process, as long as the user
523 * says they want to be notified
526 vlib_process_signal_event (vm, mc->node_index,
527 mc->type_opaque, mc->data);
528 next_index = mc->next_index;
536 vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
539 uword type_opaque, uword data)
541 ethernet_arp_main_t *am = ðernet_arp_main;
542 ip4_address_t *address = address_arg;
544 pending_resolution_t *pr;
546 pool_get (am->pending_resolutions, pr);
549 pr->node_index = node_index;
550 pr->type_opaque = type_opaque;
552 pr->data_callback = 0;
554 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
557 /* Insert new resolution at the head of the list */
558 pr->next_index = p[0];
559 hash_unset (am->pending_resolutions_by_address, address->as_u32);
562 hash_set (am->pending_resolutions_by_address, address->as_u32,
563 pr - am->pending_resolutions);
567 vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
572 uword type_opaque, uword data, int is_add)
574 ethernet_arp_main_t *am = ðernet_arp_main;
575 ip4_address_t *address = address_arg;
577 pending_resolution_t *mc;
578 void (*fp) (u32, u8 *) = data_callback;
582 pool_get (am->mac_changes, mc);
585 mc->node_index = node_index;
586 mc->type_opaque = type_opaque;
588 mc->data_callback = data_callback;
591 p = hash_get (am->mac_changes_by_address, address->as_u32);
594 /* Insert new resolution at the head of the list */
595 mc->next_index = p[0];
596 hash_unset (am->mac_changes_by_address, address->as_u32);
599 hash_set (am->mac_changes_by_address, address->as_u32,
600 mc - am->mac_changes);
606 pending_resolution_t *mc_last = 0;
608 p = hash_get (am->mac_changes_by_address, address->as_u32);
610 return VNET_API_ERROR_NO_SUCH_ENTRY;
614 while (index != (u32) ~ 0)
616 mc = pool_elt_at_index (am->mac_changes, index);
617 if (mc->node_index == node_index &&
618 mc->type_opaque == type_opaque && mc->pid == pid)
620 /* Clients may need to clean up pool entries, too */
622 (*fp) (mc->data, 0 /* no new mac addrs */ );
625 hash_unset (am->mac_changes_by_address, address->as_u32);
626 if (mc->next_index != ~0)
627 hash_set (am->mac_changes_by_address, address->as_u32,
629 pool_put (am->mac_changes, mc);
635 mc_last->next_index = mc->next_index;
636 pool_put (am->mac_changes, mc);
641 index = mc->next_index;
644 return VNET_API_ERROR_NO_SUCH_ENTRY;
648 /* Either we drop the packet or we send a reply to the sender. */
652 ARP_INPUT_NEXT_REPLY_TX,
656 #define foreach_ethernet_arp_error \
657 _ (replies_sent, "ARP replies sent") \
658 _ (l2_type_not_ethernet, "L2 type not ethernet") \
659 _ (l3_type_not_ip4, "L3 type not IP4") \
660 _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
661 _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
662 _ (l3_src_address_is_local, "IP4 source address matches local interface") \
663 _ (l3_src_address_learned, "ARP request IP4 source address learned") \
664 _ (replies_received, "ARP replies received") \
665 _ (opcode_not_request, "ARP opcode not request") \
666 _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
667 _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
668 _ (missing_interface_address, "ARP missing interface address") \
669 _ (gratuitous_arp, "ARP probe or announcement dropped") \
670 _ (interface_no_table, "Interface is not mapped to an IP table") \
674 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
675 foreach_ethernet_arp_error
677 ETHERNET_ARP_N_ERROR,
678 } ethernet_arp_input_error_t;
682 unset_random_arp_entry (void)
684 ethernet_arp_main_t *am = ðernet_arp_main;
685 ethernet_arp_ip4_entry_t *e;
686 vnet_main_t *vnm = vnet_get_main ();
687 ethernet_arp_ip4_over_ethernet_address_t delme;
690 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
691 am->arp_delete_rotor = index;
693 /* Try again from elt 0, could happen if an intfc goes down */
696 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
697 am->arp_delete_rotor = index;
700 /* Nothing left in the pool */
704 e = pool_elt_at_index (am->ip4_entry_pool, index);
706 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
707 delme.ip4.as_u32 = e->ip4_address.as_u32;
709 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
713 arp_unnumbered (vlib_buffer_t * p0,
714 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
716 vlib_main_t *vm = vlib_get_main ();
717 vnet_main_t *vnm = vnet_get_main ();
718 vnet_interface_main_t *vim = &vnm->interface_main;
719 vnet_sw_interface_t *si;
720 vnet_hw_interface_t *hi;
721 u32 unnum_src_sw_if_index;
722 u32 *broadcast_swifs = 0;
727 u8 dst_mac_address[6];
729 ethernet_arp_header_t *arp0;
731 /* Save the dst mac address */
732 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
734 /* Figure out which sw_if_index supplied the address */
735 unnum_src_sw_if_index = sw_if_index;
737 /* Track down all users of the unnumbered source */
739 pool_foreach (si, vim->sw_interfaces,
741 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
742 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
744 vec_add1 (broadcast_swifs, si->sw_if_index);
749 ASSERT (vec_len (broadcast_swifs));
751 /* Allocate buffering if we need it */
752 if (vec_len (broadcast_swifs) > 1)
754 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
755 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
756 _vec_len (buffers) = n_alloc;
757 for (i = 0; i < n_alloc; i++)
759 b0 = vlib_get_buffer (vm, buffers[i]);
761 /* xerox (partially built) ARP pkt */
762 clib_memcpy (b0->data, p0->data,
763 p0->current_length + p0->current_data);
764 b0->current_data = p0->current_data;
765 b0->current_length = p0->current_length;
766 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
767 vnet_buffer (p0)->sw_if_index[VLIB_RX];
771 vec_insert (buffers, 1, 0);
774 for (i = 0; i < vec_len (buffers); i++)
776 b0 = vlib_get_buffer (vm, buffers[i]);
777 arp0 = vlib_buffer_get_current (b0);
779 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
780 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
782 /* For decoration, most likely */
783 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
785 /* Fix ARP pkt src address */
786 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
788 /* Build L2 encaps for this swif */
789 header_size = sizeof (ethernet_header_t);
790 if (si->sub.eth.flags.one_tag)
792 else if (si->sub.eth.flags.two_tags)
795 vlib_buffer_advance (b0, -header_size);
796 eth0 = vlib_buffer_get_current (b0);
798 if (si->sub.eth.flags.one_tag)
800 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
802 eth0->type = si->sub.eth.flags.dot1ad ?
803 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
804 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
805 outer->priority_cfi_and_id =
806 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
807 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
810 else if (si->sub.eth.flags.two_tags)
812 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
813 ethernet_vlan_header_t *inner = (void *) (outer + 1);
815 eth0->type = si->sub.eth.flags.dot1ad ?
816 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
817 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
818 outer->priority_cfi_and_id =
819 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
820 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
821 inner->priority_cfi_and_id =
822 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
823 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
828 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
831 /* Restore the original dst address, set src address */
832 clib_memcpy (eth0->dst_address, dst_mac_address,
833 sizeof (eth0->dst_address));
834 clib_memcpy (eth0->src_address, hi->hw_address,
835 sizeof (eth0->src_address));
837 /* Transmit replicas */
841 vlib_get_frame_to_node (vm, hi->output_node_index);
842 u32 *to_next = vlib_frame_vector_args (f);
843 to_next[0] = buffers[i];
845 vlib_put_frame_to_node (vm, hi->output_node_index, f);
849 /* The regular path outputs the original pkt.. */
850 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
852 vec_free (broadcast_swifs);
857 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
859 ethernet_arp_main_t *am = ðernet_arp_main;
860 vnet_main_t *vnm = vnet_get_main ();
861 ip4_main_t *im4 = &ip4_main;
862 u32 n_left_from, next_index, *from, *to_next;
863 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
865 from = vlib_frame_vector_args (frame);
866 n_left_from = frame->n_vectors;
867 next_index = node->cached_next_index;
869 if (node->flags & VLIB_NODE_FLAG_TRACE)
870 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
872 sizeof (ethernet_arp_input_trace_t));
874 while (n_left_from > 0)
878 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
880 while (n_left_from > 0 && n_left_to_next > 0)
883 vnet_hw_interface_t *hw_if0;
884 ethernet_arp_header_t *arp0;
885 ethernet_header_t *eth0;
886 ip_adjacency_t *adj0;
887 ip4_address_t *if_addr0, proxy_src;
888 u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
889 u8 is_request0, dst_is_local0, is_unnum0;
890 ethernet_proxy_arp_t *pa;
891 fib_node_index_t dst_fei, src_fei;
893 fib_entry_flag_t src_flags, dst_flags;
903 p0 = vlib_get_buffer (vm, pi0);
904 arp0 = vlib_buffer_get_current (p0);
906 is_request0 = arp0->opcode
907 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
909 error0 = ETHERNET_ARP_ERROR_replies_sent;
913 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
914 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
917 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
918 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
920 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
925 /* Check that IP address is local and matches incoming interface. */
926 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
927 if (~0 == fib_index0)
929 error0 = ETHERNET_ARP_ERROR_interface_no_table;
933 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
934 &arp0->ip4_over_ethernet[1].ip4,
936 dst_flags = fib_entry_get_flags_for_source (dst_fei,
937 FIB_SOURCE_INTERFACE);
940 fib_entry_get_resolving_interface_for_source (dst_fei,
941 FIB_SOURCE_INTERFACE);
943 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
945 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
949 /* Honor unnumbered interface, if any */
950 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
952 /* Source must also be local to subnet of matching interface address. */
953 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
954 &arp0->ip4_over_ethernet[0].ip4,
956 src_flags = fib_entry_get_flags (src_fei);
958 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
959 (FIB_ENTRY_FLAG_CONNECTED & src_flags)) ||
960 sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
962 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
966 /* Reject requests/replies with our local interface address. */
967 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
969 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
973 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
974 fib_entry_get_prefix (dst_fei, &pfx0);
975 if_addr0 = &pfx0.fp_addr.ip4;
977 /* Fill in ethernet header. */
978 eth0 = ethernet_buffer_get_header (p0);
980 /* Trash ARP packets whose ARP-level source addresses do not
981 match their L2-frame-level source addresses */
982 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
983 sizeof (eth0->src_address)))
985 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
989 /* Learn or update sender's mapping only for requests or unicasts
990 that don't match local interface address. */
991 if (ethernet_address_cast (eth0->dst_address) ==
992 ETHERNET_ADDRESS_UNICAST || is_request0)
994 if (am->limit_arp_cache_size &&
995 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
996 unset_random_arp_entry ();
998 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
999 &arp0->ip4_over_ethernet[0],
1000 0 /* is_static */ );
1001 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1004 /* Only send a reply for requests sent which match a local interface. */
1005 if (!(is_request0 && dst_is_local0))
1009 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1010 ETHERNET_ARP_ERROR_replies_received : error0);
1016 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1017 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1019 /* Send reply back through input interface */
1020 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1021 next0 = ARP_INPUT_NEXT_REPLY_TX;
1023 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1025 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1027 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1028 hw_if0->hw_address, 6);
1029 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1032 /* Hardware must be ethernet-like. */
1033 ASSERT (vec_len (hw_if0->hw_address) == 6);
1035 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1036 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1038 /* Figure out how much to rewind current data from adjacency. */
1039 /* get the adj from the destination's covering connected */
1043 adj_get (fib_entry_get_adj_for_source
1044 (ip4_fib_table_lookup
1045 (ip4_fib_get (fib_index0),
1046 &arp0->ip4_over_ethernet[1].ip4, 31),
1047 FIB_SOURCE_INTERFACE));
1048 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1050 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1054 arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0);
1056 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1058 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1059 n_left_to_next, pi0, next0);
1061 n_replies_sent += 1;
1065 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1066 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1067 arp0->ip4_over_ethernet[1].ip4.as_u32))
1069 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1072 /* See if proxy arp is configured for the address */
1075 vnet_sw_interface_t *si;
1076 u32 this_addr = clib_net_to_host_u32
1077 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1080 si = vnet_get_sw_interface (vnm, sw_if_index0);
1082 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1085 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1088 vec_foreach (pa, am->proxy_arps)
1090 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1091 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1093 /* an ARP request hit in the proxy-arp table? */
1094 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1095 (fib_index0 == pa->fib_index))
1097 eth0 = ethernet_buffer_get_header (p0);
1099 arp0->ip4_over_ethernet[1].ip4.data_u32;
1102 * Rewind buffer, direct code above not to
1103 * think too hard about it.
1105 if_addr0 = &proxy_src;
1107 i32 ethernet_start =
1108 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1109 i32 rewind = p0->current_data - ethernet_start;
1110 vlib_buffer_advance (p0, -rewind);
1111 n_proxy_arp_replies_sent++;
1119 next0 = ARP_INPUT_NEXT_DROP;
1120 p0->error = node->errors[error0];
1122 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1123 n_left_to_next, pi0, next0);
1126 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1129 vlib_error_count (vm, node->node_index,
1130 ETHERNET_ARP_ERROR_replies_sent,
1131 n_replies_sent - n_proxy_arp_replies_sent);
1133 vlib_error_count (vm, node->node_index,
1134 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1135 n_proxy_arp_replies_sent);
1136 return frame->n_vectors;
1139 static char *ethernet_arp_error_strings[] = {
1140 #define _(sym,string) string,
1141 foreach_ethernet_arp_error
1146 VLIB_REGISTER_NODE (arp_input_node, static) =
1148 .function = arp_input,
1149 .name = "arp-input",
1150 .vector_size = sizeof (u32),
1151 .n_errors = ETHERNET_ARP_N_ERROR,
1152 .error_strings = ethernet_arp_error_strings,
1153 .n_next_nodes = ARP_INPUT_N_NEXT,
1155 [ARP_INPUT_NEXT_DROP] = "error-drop",
1156 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1158 .format_buffer = format_ethernet_arp_header,
1159 .format_trace = format_ethernet_arp_input_trace,
1164 ip4_arp_entry_sort (void *a1, void *a2)
1166 ethernet_arp_ip4_entry_t *e1 = a1;
1167 ethernet_arp_ip4_entry_t *e2 = a2;
1170 vnet_main_t *vnm = vnet_get_main ();
1172 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1174 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1178 static clib_error_t *
1179 show_ip4_arp (vlib_main_t * vm,
1180 unformat_input_t * input, vlib_cli_command_t * cmd)
1182 vnet_main_t *vnm = vnet_get_main ();
1183 ethernet_arp_main_t *am = ðernet_arp_main;
1184 ethernet_arp_ip4_entry_t *e, *es;
1185 ethernet_proxy_arp_t *pa;
1186 clib_error_t *error = 0;
1189 /* Filter entries by interface if given. */
1191 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1195 pool_foreach (e, am->ip4_entry_pool,
1197 vec_add1 (es, e[0]);
1203 vec_sort_with_function (es, ip4_arp_entry_sort);
1204 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1207 if (sw_if_index != ~0 && e->sw_if_index != sw_if_index)
1209 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1214 if (vec_len (am->proxy_arps))
1216 vlib_cli_output (vm, "Proxy arps enabled for:");
1217 vec_foreach (pa, am->proxy_arps)
1219 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1221 format_ip4_address, &pa->lo_addr,
1222 format_ip4_address, &pa->hi_addr);
1230 * Display all the IPv4 ARP entries.
1233 * Example of how to display the IPv4 ARP table:
1234 * @cliexstart{show ip arp}
1235 * Time FIB IP4 Flags Ethernet Interface
1236 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1237 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1238 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1239 * Proxy arps enabled for:
1240 * Fib_index 0 6.0.0.1 - 6.0.0.11
1244 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1245 .path = "show ip arp",
1246 .function = show_ip4_arp,
1247 .short_help = "show ip arp",
1253 pg_edit_t l2_type, l3_type;
1254 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1260 } ip4_over_ethernet[2];
1261 } pg_ethernet_arp_header_t;
1264 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1266 /* Initialize fields that are not bit fields in the IP header. */
1267 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1270 _(n_l2_address_bytes);
1271 _(n_l3_address_bytes);
1273 _(ip4_over_ethernet[0].ethernet);
1274 _(ip4_over_ethernet[0].ip4);
1275 _(ip4_over_ethernet[1].ethernet);
1276 _(ip4_over_ethernet[1].ip4);
1281 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1283 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1284 pg_ethernet_arp_header_t *p;
1287 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1289 pg_ethernet_arp_header_init (p);
1292 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1293 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1294 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1295 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1297 if (!unformat (input, "%U: %U/%U -> %U/%U",
1299 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1301 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1303 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1305 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1307 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1309 /* Free up any edits we may have added. */
1310 pg_free_edit_group (s);
1317 ip4_set_arp_limit (u32 arp_limit)
1319 ethernet_arp_main_t *am = ðernet_arp_main;
1321 am->limit_arp_cache_size = arp_limit;
1326 * @brief Control Plane hook to remove an ARP entry
1329 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1330 u32 sw_if_index, void *a_arg)
1332 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1333 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1335 args.sw_if_index = sw_if_index;
1336 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1337 args.ether_type = ARP_ETHER_TYPE_IP4;
1338 clib_memcpy (&args.a, a, sizeof (*a));
1340 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1341 (u8 *) & args, sizeof (args));
1346 * @brief Internally generated event to flush the ARP cache on an
1347 * interface state change event.
1348 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1349 * address from the corresponding adjacencies.
1352 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1354 arp_ether_type_t et, void *a_arg)
1356 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1357 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1359 args.sw_if_index = sw_if_index;
1360 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1361 args.ether_type = et;
1362 clib_memcpy (&args.a, a, sizeof (*a));
1364 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1365 (u8 *) & args, sizeof (args));
1370 * @brief Internally generated event to populate the ARP cache on an
1371 * interface state change event.
1372 * For static entries this will re-source the adjacencies.
1374 * @param sw_if_index The interface on which the ARP entires are acted
1375 * @param et The ether type of those ARP entries.
1378 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1380 arp_ether_type_t et, void *a_arg)
1382 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1383 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1385 args.sw_if_index = sw_if_index;
1386 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1387 args.ether_type = et;
1388 clib_memcpy (&args.a, a, sizeof (*a));
1390 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1391 (u8 *) & args, sizeof (args));
1396 * arp_add_del_interface_address
1398 * callback when an interface address is added or deleted
1401 arp_add_del_interface_address (ip4_main_t * im,
1404 ip4_address_t * address,
1406 u32 if_address_index, u32 is_del)
1409 * Flush the ARP cache of all entries covered by the address
1410 * that is being removed.
1412 ethernet_arp_main_t *am = ðernet_arp_main;
1413 ethernet_arp_ip4_entry_t *e;
1415 if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
1420 ethernet_arp_interface_t *eai;
1421 u32 i, *to_delete = 0;
1424 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1426 hash_foreach_pair (pair, eai->arp_entries, (
1430 (am->ip4_entry_pool,
1433 (ip4_destination_matches_route
1434 (im, &e->ip4_address,
1435 address, address_length))
1437 vec_add1 (to_delete,
1439 am->ip4_entry_pool);}
1443 for (i = 0; i < vec_len (to_delete); i++)
1445 ethernet_arp_ip4_over_ethernet_address_t delme;
1446 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1448 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1449 delme.ip4.as_u32 = e->ip4_address.as_u32;
1451 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1453 ARP_ETHER_TYPE_BOTH, &delme);
1456 vec_free (to_delete);
1461 ethernet_arp_sw_interface_mpls_state_change (u32 sw_if_index, u32 is_enable)
1463 ethernet_arp_main_t *am = ðernet_arp_main;
1464 ethernet_arp_ip4_entry_t *e;
1465 ethernet_arp_interface_t *eai;
1466 u32 i, *to_update = 0;
1469 if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
1472 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1475 eai->flags |= ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
1477 eai->flags &= ~ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
1479 hash_foreach_pair (pair, eai->arp_entries, (
1481 vec_add1 (to_update,
1486 for (i = 0; i < vec_len (to_update); i++)
1488 ethernet_arp_ip4_over_ethernet_address_t updateme;
1489 e = pool_elt_at_index (am->ip4_entry_pool, to_update[i]);
1491 clib_memcpy (&updateme.ethernet, e->ethernet_address, 6);
1492 updateme.ip4.as_u32 = e->ip4_address.as_u32;
1496 vnet_arp_populate_ip4_over_ethernet (vnet_get_main (),
1498 ARP_ETHER_TYPE_MPLS,
1505 vec_free (to_update);
1508 static clib_error_t *
1509 ethernet_arp_init (vlib_main_t * vm)
1511 ethernet_arp_main_t *am = ðernet_arp_main;
1512 ip4_main_t *im = &ip4_main;
1513 clib_error_t *error;
1516 if ((error = vlib_call_init_function (vm, ethernet_init)))
1519 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1521 pn = pg_get_node (arp_input_node.index);
1522 pn->unformat_edit = unformat_pg_arp_header;
1524 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1525 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1526 foreach_ethernet_arp_opcode;
1529 /* $$$ configurable */
1530 am->limit_arp_cache_size = 50000;
1532 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1533 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1535 /* don't trace ARP error packets */
1537 vlib_node_runtime_t *rt =
1538 vlib_node_get_runtime (vm, arp_input_node.index);
1541 vnet_pcap_drop_trace_filter_add_del \
1542 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1544 foreach_ethernet_arp_error
1548 ip4_add_del_interface_address_callback_t cb;
1549 cb.function = arp_add_del_interface_address;
1550 cb.function_opaque = 0;
1551 vec_add1 (im->add_del_interface_address_callbacks, cb);
1553 vec_add1 (mpls_main.mpls_interface_state_change_callbacks,
1554 ethernet_arp_sw_interface_mpls_state_change);
1559 VLIB_INIT_FUNCTION (ethernet_arp_init);
1562 arp_mk_incomplete (ethernet_arp_interface_t * eai,
1563 ethernet_arp_ip4_entry_t * e, arp_ether_type_t et)
1565 fib_prefix_t pfx = {
1567 .fp_proto = FIB_PROTOCOL_IP4,
1569 .ip4 = e->ip4_address,
1574 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
1576 if ((ARP_ETHER_TYPE_IP4 & et) &&
1577 (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4]))
1580 * revert the adj this ARP entry sourced to incomplete
1582 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4], NULL);
1585 * remove the FIB erntry the ARP entry sourced
1587 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_ADJ);
1590 * Unlock the adj now that the ARP entry is no longer a source
1592 adj_unlock (e->adj_index[FIB_LINK_IP4]);
1593 e->adj_index[FIB_LINK_IP4] = ADJ_INDEX_INVALID;
1595 if ((ARP_ETHER_TYPE_MPLS & et) &&
1596 (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS]))
1599 * revert the adj this ARP entry sourced to incomplete
1601 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS], NULL);
1604 * Unlock the adj now that the ARP entry is no longer a source
1606 adj_unlock (e->adj_index[FIB_LINK_MPLS]);
1607 e->adj_index[FIB_LINK_MPLS] = ADJ_INDEX_INVALID;
1612 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1614 ethernet_arp_main_t *am = ðernet_arp_main;
1616 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1617 pool_put (am->ip4_entry_pool, e);
1620 static ethernet_arp_ip4_entry_t *
1621 arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
1623 ethernet_arp_main_t *am = ðernet_arp_main;
1624 ethernet_arp_ip4_entry_t *e = NULL;
1627 if (NULL != eai->arp_entries)
1629 p = hash_get (eai->arp_entries, addr->as_u32);
1633 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
1640 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1641 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1644 ethernet_arp_main_t *am = ðernet_arp_main;
1645 ethernet_arp_ip4_entry_t *e;
1646 ethernet_arp_interface_t *eai;
1648 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1650 e = arp_entry_find (eai, &args->a.ip4);
1654 arp_mk_incomplete (eai, e, ARP_ETHER_TYPE_BOTH);
1655 arp_entry_free (eai, e);
1662 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1663 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1666 ethernet_arp_main_t *am = ðernet_arp_main;
1667 ethernet_arp_ip4_entry_t *e;
1668 ethernet_arp_interface_t *eai;
1670 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1672 e = arp_entry_find (eai, &args->a.ip4);
1676 arp_mk_incomplete (eai, e, args->ether_type);
1679 * The difference between flush and unset, is that an unset
1680 * means delete for static and dynamic entries. A flush
1681 * means delete only for dynamic. Flushing is what the DP
1682 * does in response to interface events. unset is only done
1683 * by the control plane.
1685 if ((e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC) &&
1686 (args->ether_type & ARP_ETHER_TYPE_IP4))
1688 arp_entry_free (eai, e);
1695 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1696 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1699 ethernet_arp_main_t *am = ðernet_arp_main;
1700 ethernet_arp_ip4_entry_t *e;
1701 ethernet_arp_interface_t *eai;
1703 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1705 e = arp_entry_find (eai, &args->a.ip4);
1709 arp_mk_complete (eai, e, args->ether_type);
1715 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1718 vnet_main_t *vm = vnet_get_main ();
1719 ASSERT (os_get_cpu_number () == 0);
1721 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1722 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1723 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1724 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1725 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1726 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1728 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1732 * @brief Invoked when the interface's admin state changes
1734 static clib_error_t *
1735 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1736 u32 sw_if_index, u32 flags)
1738 ethernet_arp_main_t *am = ðernet_arp_main;
1739 ethernet_arp_ip4_entry_t *e;
1740 u32 i, *to_delete = 0;
1743 pool_foreach (e, am->ip4_entry_pool,
1745 if (e->sw_if_index == sw_if_index)
1747 vec_add1 (to_delete, e - am->ip4_entry_pool);
1752 for (i = 0; i < vec_len (to_delete); i++)
1754 ethernet_arp_ip4_over_ethernet_address_t delme;
1755 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1757 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1758 delme.ip4.as_u32 = e->ip4_address.as_u32;
1760 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1762 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index,
1763 ARP_ETHER_TYPE_BOTH, &delme);
1767 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index,
1768 ARP_ETHER_TYPE_BOTH, &delme);
1772 vec_free (to_delete);
1778 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1782 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1787 for (i = 3; i >= 0; i--)
1789 old = a->ip4.as_u8[i];
1790 a->ip4.as_u8[i] += 1;
1791 if (old < a->ip4.as_u8[i])
1795 for (i = 5; i >= 0; i--)
1797 old = a->ethernet[i];
1798 a->ethernet[i] += 1;
1799 if (old < a->ethernet[i])
1805 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1806 u32 sw_if_index, void *a_arg, int is_static)
1808 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1809 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1811 args.sw_if_index = sw_if_index;
1812 args.is_static = is_static;
1814 args.ether_type = ARP_ETHER_TYPE_IP4;
1815 clib_memcpy (&args.a, a, sizeof (*a));
1817 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1818 (u8 *) & args, sizeof (args));
1823 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1824 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1826 ethernet_arp_main_t *am = ðernet_arp_main;
1827 ethernet_proxy_arp_t *pa;
1828 u32 found_at_index = ~0;
1830 vec_foreach (pa, am->proxy_arps)
1832 if (pa->lo_addr == lo_addr->as_u32
1833 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1835 found_at_index = pa - am->proxy_arps;
1840 if (found_at_index != ~0)
1842 /* Delete, otherwise it's already in the table */
1844 vec_delete (am->proxy_arps, 1, found_at_index);
1847 /* delete, no such entry */
1849 return VNET_API_ERROR_NO_SUCH_ENTRY;
1851 /* add, not in table */
1852 vec_add2 (am->proxy_arps, pa, 1);
1853 pa->lo_addr = lo_addr->as_u32;
1854 pa->hi_addr = hi_addr->as_u32;
1855 pa->fib_index = fib_index;
1860 * Remove any proxy arp entries asdociated with the
1864 vnet_proxy_arp_fib_reset (u32 fib_id)
1866 ip4_main_t *im = &ip4_main;
1867 ethernet_arp_main_t *am = ðernet_arp_main;
1868 ethernet_proxy_arp_t *pa;
1869 u32 *entries_to_delete = 0;
1874 p = hash_get (im->fib_index_by_table_id, fib_id);
1876 return VNET_API_ERROR_NO_SUCH_ENTRY;
1879 vec_foreach (pa, am->proxy_arps)
1881 if (pa->fib_index == fib_index)
1883 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1887 for (i = 0; i < vec_len (entries_to_delete); i++)
1889 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1892 vec_free (entries_to_delete);
1897 static clib_error_t *
1898 ip_arp_add_del_command_fn (vlib_main_t * vm,
1899 unformat_input_t * input, vlib_cli_command_t * cmd)
1901 vnet_main_t *vnm = vnet_get_main ();
1903 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1912 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1914 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1915 if (unformat (input, "%U %U %U",
1916 unformat_vnet_sw_interface, vnm, &sw_if_index,
1917 unformat_ip4_address, &addr.ip4,
1918 unformat_ethernet_address, &addr.ethernet))
1921 else if (unformat (input, "delete") || unformat (input, "del"))
1924 else if (unformat (input, "static"))
1927 else if (unformat (input, "count %d", &count))
1930 else if (unformat (input, "fib-id %d", &fib_id))
1932 ip4_main_t *im = &ip4_main;
1933 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1935 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1939 else if (unformat (input, "proxy %U - %U",
1940 unformat_ip4_address, &lo_addr.ip4,
1941 unformat_ip4_address, &hi_addr.ip4))
1949 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1958 for (i = 0; i < count; i++)
1962 uword event_type, *event_data = 0;
1964 /* Park the debug CLI until the arp entry is installed */
1965 vnet_register_ip4_arp_resolution_event
1966 (vnm, &addr.ip4, vlib_current_process (vm),
1967 1 /* type */ , 0 /* data */ );
1969 vnet_arp_set_ip4_over_ethernet
1970 (vnm, sw_if_index, &addr, is_static);
1972 vlib_process_wait_for_event (vm);
1973 event_type = vlib_process_get_events (vm, &event_data);
1974 vec_reset_length (event_data);
1975 if (event_type != 1)
1976 clib_warning ("event type %d unexpected", event_type);
1979 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
1981 increment_ip4_and_mac_address (&addr);
1986 return clib_error_return (0, "unknown input `%U'",
1987 format_unformat_error, input);
1995 * Add or delete IPv4 ARP cache entries.
1997 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
1998 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
1999 * any order and combination.
2003 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
2004 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
2005 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2006 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
2008 * To add or delete an IPv4 ARP cache entry to or from a specific fib
2010 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2011 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2013 * Add or delete IPv4 static ARP cache entries as follows:
2014 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2015 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2017 * For testing / debugging purposes, the 'set ip arp' command can add or
2018 * delete multiple entries. Supply the 'count N' parameter:
2019 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2023 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2024 .path = "set ip arp",
2026 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2027 .function = ip_arp_add_del_command_fn,
2031 static clib_error_t *
2032 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2033 unformat_input_t * input,
2034 vlib_cli_command_t * cmd)
2036 vnet_main_t *vnm = vnet_get_main ();
2038 vnet_sw_interface_t *si;
2042 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2044 if (unformat (input, "%U", unformat_vnet_sw_interface,
2047 else if (unformat (input, "enable") || unformat (input, "on"))
2049 else if (unformat (input, "disable") || unformat (input, "off"))
2056 return clib_error_return (0, "unknown input '%U'",
2057 format_unformat_error, input);
2059 si = vnet_get_sw_interface (vnm, sw_if_index);
2062 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2064 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2071 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2072 * requests for the indicated address range. Multiple proxy-arp
2073 * ranges may be provisioned.
2075 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2076 * Also, the underlying implementation has not been performance-tuned.
2077 * Avoid creating an unnecessarily large set of ranges.
2080 * To enable proxy arp on a range of addresses, use:
2081 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2082 * Append 'del' to delete a range of proxy ARP addresses:
2083 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2084 * You must then specifically enable proxy arp on individual interfaces:
2085 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2086 * To disable proxy arp on an individual interface:
2087 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2090 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2091 .path = "set interface proxy-arp",
2093 "set interface proxy-arp <intfc> [enable|disable]",
2094 .function = set_int_proxy_arp_command_fn,
2100 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2101 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2105 ARP_TERM_NEXT_L2_OUTPUT,
2110 u32 arp_term_next_node_index[32];
2113 arp_term_l2bd (vlib_main_t * vm,
2114 vlib_node_runtime_t * node, vlib_frame_t * frame)
2116 l2input_main_t *l2im = &l2input_main;
2117 u32 n_left_from, next_index, *from, *to_next;
2118 u32 n_replies_sent = 0;
2119 u16 last_bd_index = ~0;
2120 l2_bridge_domain_t *last_bd_config = 0;
2121 l2_input_config_t *cfg0;
2123 from = vlib_frame_vector_args (frame);
2124 n_left_from = frame->n_vectors;
2125 next_index = node->cached_next_index;
2127 while (n_left_from > 0)
2131 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2133 while (n_left_from > 0 && n_left_to_next > 0)
2136 ethernet_header_t *eth0;
2137 ethernet_arp_header_t *arp0;
2140 u32 pi0, error0, next0, sw_if_index0;
2151 n_left_to_next -= 1;
2153 p0 = vlib_get_buffer (vm, pi0);
2154 eth0 = vlib_buffer_get_current (p0);
2155 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2156 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2157 arp0 = (ethernet_arp_header_t *) l3h0;
2159 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2161 clib_host_to_net_u16
2162 (ETHERNET_ARP_OPCODE_request))))
2165 /* Must be ARP request packet here */
2166 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2167 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2169 u8 *t0 = vlib_add_trace (vm, node, p0,
2170 sizeof (ethernet_arp_input_trace_t));
2171 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2174 error0 = ETHERNET_ARP_ERROR_replies_sent;
2177 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
2178 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2181 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2182 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2184 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2189 /* Trash ARP packets whose ARP-level source addresses do not
2190 match their L2-frame-level source addresses */
2193 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2194 sizeof (eth0->src_address))))
2196 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2200 /* Check if anyone want ARP request events for L2 BDs */
2202 pending_resolution_t *mc;
2203 ethernet_arp_main_t *am = ðernet_arp_main;
2204 uword *p = hash_get (am->mac_changes_by_address, 0);
2205 if (p && (vnet_buffer (p0)->l2.shg == 0))
2206 { // Only SHG 0 interface which is more likely local
2207 u32 next_index = p[0];
2208 while (next_index != (u32) ~ 0)
2210 int (*fp) (u32, u8 *, u32, u32);
2212 mc = pool_elt_at_index (am->mac_changes, next_index);
2213 fp = mc->data_callback;
2214 /* Call the callback, return 1 to suppress dup events */
2216 rv = (*fp) (mc->data,
2217 arp0->ip4_over_ethernet[0].ethernet,
2219 arp0->ip4_over_ethernet[0].ip4.as_u32);
2220 /* Signal the resolver process */
2222 vlib_process_signal_event (vm, mc->node_index,
2223 mc->type_opaque, mc->data);
2224 next_index = mc->next_index;
2229 /* lookup BD mac_by_ip4 hash table for MAC entry */
2230 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2231 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2232 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2233 || (last_bd_index == (u16) ~ 0)))
2235 last_bd_index = bd_index0;
2236 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2238 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2240 if (PREDICT_FALSE (!macp0))
2241 goto next_l2_feature; /* MAC not found */
2243 /* MAC found, send ARP reply -
2244 Convert ARP request packet to ARP reply */
2245 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2246 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2247 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2248 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2249 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2250 clib_memcpy (eth0->src_address, macp0, 6);
2251 n_replies_sent += 1;
2254 /* For BVI, need to use l2-fwd node to send ARP reply as
2255 l2-output node cannot output packet to BVI properly */
2256 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2257 if (PREDICT_FALSE (cfg0->bvi))
2259 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2260 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2261 goto next_l2_feature;
2264 /* Send ARP/ND reply back out input interface through l2-output */
2265 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2266 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2267 /* Note that output to VXLAN tunnel will fail due to SHG which
2268 is probably desireable since ARP termination is not intended
2269 for ARP requests from other hosts. If output to VXLAN tunnel is
2270 required, however, can just clear the SHG in packet as follows:
2271 vnet_buffer(p0)->l2.shg = 0; */
2272 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2273 n_left_to_next, pi0, next0);
2277 /* IP6 ND event notification or solicitation handling to generate
2278 local response instead of flooding */
2279 iph0 = (ip6_header_t *) l3h0;
2280 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2281 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2282 !ip6_address_is_unspecified
2283 (&iph0->src_address)))
2285 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2286 if (vnet_ip6_nd_term (vm, node, p0, eth0, iph0, sw_if_index0,
2287 vnet_buffer (p0)->l2.bd_index,
2288 vnet_buffer (p0)->l2.shg))
2289 goto output_response;
2294 u32 feature_bitmap0 =
2295 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2296 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2297 next0 = feat_bitmap_get_next_node_index (arp_term_next_node_index,
2299 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2300 n_left_to_next, pi0, next0);
2305 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2306 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2307 arp0->ip4_over_ethernet[1].ip4.as_u32))
2309 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2311 next0 = ARP_TERM_NEXT_DROP;
2312 p0->error = node->errors[error0];
2314 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2315 n_left_to_next, pi0, next0);
2318 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2321 vlib_error_count (vm, node->node_index,
2322 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2323 return frame->n_vectors;
2327 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2328 .function = arp_term_l2bd,
2329 .name = "arp-term-l2bd",
2330 .vector_size = sizeof (u32),
2331 .n_errors = ETHERNET_ARP_N_ERROR,
2332 .error_strings = ethernet_arp_error_strings,
2333 .n_next_nodes = ARP_TERM_N_NEXT,
2335 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2336 [ARP_TERM_NEXT_DROP] = "error-drop",
2338 .format_buffer = format_ethernet_arp_header,
2339 .format_trace = format_arp_term_input_trace,
2344 arp_term_init (vlib_main_t * vm)
2345 { // Initialize the feature next-node indexes
2346 feat_bitmap_init_next_nodes (vm,
2347 arp_term_l2bd_node.index,
2349 l2input_get_feat_names (),
2350 arp_term_next_node_index);
2354 VLIB_INIT_FUNCTION (arp_term_init);
2357 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2359 if (e->sw_if_index == sw_if_index)
2362 if (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4])
2364 // the update rewrite function takes the dst mac (which is not changing)
2365 // the new source mac will be retrieved from the interface
2366 // when the full rewrite is constructed.
2367 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4],
2368 e->ethernet_address);
2370 if (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS])
2372 adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS],
2373 e->ethernet_address);
2380 ethernet_arp_change_mac (vnet_main_t * vnm, u32 sw_if_index)
2382 ethernet_arp_main_t *am = ðernet_arp_main;
2383 ethernet_arp_ip4_entry_t *e;
2386 pool_foreach (e, am->ip4_entry_pool,
2388 change_arp_mac (sw_if_index, e);
2394 * fd.io coding-style-patch-verification: ON
2397 * eval: (c-set-style "gnu")