2 * ethernet/arp.c: IP v4 ARP node
4 * Copyright (c) 2010 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/ip/ip.h>
19 #include <vnet/ip/ip6.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vnet/ethernet/arp_packet.h>
22 #include <vnet/l2/l2_input.h>
23 #include <vppinfra/mhash.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vnet/adj/adj_nbr.h>
26 #include <vnet/adj/adj_mcast.h>
27 #include <vnet/mpls/mpls.h>
33 * This file contains code to manage the IPv4 ARP tables (IP Address
34 * to MAC Address lookup).
38 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
41 * @brief Per-interface ARP configuration and state
43 typedef struct ethernet_arp_interface_t_
46 * Hash table of ARP entries.
47 * Since this hash table is per-interface, the key is only the IPv4 address.
50 } ethernet_arp_interface_t;
57 } ethernet_proxy_arp_t;
65 /* Used for arp event notification only */
68 } pending_resolution_t;
72 /* Hash tables mapping name to opcode. */
73 uword *opcode_by_name;
75 /* lite beer "glean" adjacency handling */
76 uword *pending_resolutions_by_address;
77 pending_resolution_t *pending_resolutions;
79 /* Mac address change notification */
80 uword *mac_changes_by_address;
81 pending_resolution_t *mac_changes;
83 ethernet_arp_ip4_entry_t *ip4_entry_pool;
85 /* ARP attack mitigation */
87 u32 limit_arp_cache_size;
89 /** Per interface state */
90 ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
92 /* Proxy arp vector */
93 ethernet_proxy_arp_t *proxy_arps;
94 } ethernet_arp_main_t;
96 static ethernet_arp_main_t ethernet_arp_main;
101 ethernet_arp_ip4_over_ethernet_address_t a;
105 #define ETHERNET_ARP_ARGS_REMOVE (1<<0)
106 #define ETHERNET_ARP_ARGS_FLUSH (1<<1)
107 #define ETHERNET_ARP_ARGS_POPULATE (1<<2)
108 } vnet_arp_set_ip4_over_ethernet_rpc_args_t;
111 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
115 format_ethernet_arp_hardware_type (u8 * s, va_list * va)
117 ethernet_arp_hardware_type_t h = va_arg (*va, ethernet_arp_hardware_type_t);
121 #define _(n,f) case n: t = #f; break;
122 foreach_ethernet_arp_hardware_type;
126 return format (s, "unknown 0x%x", h);
129 return format (s, "%s", t);
133 format_ethernet_arp_opcode (u8 * s, va_list * va)
135 ethernet_arp_opcode_t o = va_arg (*va, ethernet_arp_opcode_t);
139 #define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
140 foreach_ethernet_arp_opcode;
144 return format (s, "unknown 0x%x", o);
147 return format (s, "%s", t);
151 unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
154 int *result = va_arg (*args, int *);
155 ethernet_arp_main_t *am = ðernet_arp_main;
158 /* Numeric opcode. */
159 if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
168 if (unformat_user (input, unformat_vlib_number_by_name,
169 am->opcode_by_name, &i))
179 unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
182 int *result = va_arg (*args, int *);
184 (input, unformat_ethernet_arp_opcode_host_byte_order, result))
187 *result = clib_host_to_net_u16 ((u16) * result);
192 format_ethernet_arp_header (u8 * s, va_list * va)
194 ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
195 u32 max_header_bytes = va_arg (*va, u32);
197 u16 l2_type, l3_type;
199 if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
200 return format (s, "ARP header truncated");
202 l2_type = clib_net_to_host_u16 (a->l2_type);
203 l3_type = clib_net_to_host_u16 (a->l3_type);
205 indent = format_get_indent (s);
207 s = format (s, "%U, type %U/%U, address size %d/%d",
208 format_ethernet_arp_opcode, clib_net_to_host_u16 (a->opcode),
209 format_ethernet_arp_hardware_type, l2_type,
210 format_ethernet_type, l3_type,
211 a->n_l2_address_bytes, a->n_l3_address_bytes);
213 if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
214 && l3_type == ETHERNET_TYPE_IP4)
216 s = format (s, "\n%U%U/%U -> %U/%U",
217 format_white_space, indent,
218 format_ethernet_address, a->ip4_over_ethernet[0].ethernet,
219 format_ip4_address, &a->ip4_over_ethernet[0].ip4,
220 format_ethernet_address, a->ip4_over_ethernet[1].ethernet,
221 format_ip4_address, &a->ip4_over_ethernet[1].ip4);
225 uword n2 = a->n_l2_address_bytes;
226 uword n3 = a->n_l3_address_bytes;
227 s = format (s, "\n%U%U/%U -> %U/%U",
228 format_white_space, indent,
229 format_hex_bytes, a->data + 0 * n2 + 0 * n3, n2,
230 format_hex_bytes, a->data + 1 * n2 + 0 * n3, n3,
231 format_hex_bytes, a->data + 1 * n2 + 1 * n3, n2,
232 format_hex_bytes, a->data + 2 * n2 + 1 * n3, n3);
239 format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
241 vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
242 ethernet_arp_ip4_entry_t *e = va_arg (*va, ethernet_arp_ip4_entry_t *);
243 vnet_sw_interface_t *si;
247 return format (s, "%=12s%=16s%=6s%=20s%=24s", "Time", "IP4",
248 "Flags", "Ethernet", "Interface");
250 si = vnet_get_sw_interface (vnm, e->sw_if_index);
252 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
253 flags = format (flags, "S");
255 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
256 flags = format (flags, "D");
258 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY)
259 flags = format (flags, "N");
261 s = format (s, "%=12U%=16U%=6s%=20U%=24U",
262 format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
263 format_ip4_address, &e->ip4_address,
264 flags ? (char *) flags : "",
265 format_ethernet_address, e->ethernet_address,
266 format_vnet_sw_interface_name, vnm, si);
275 } ethernet_arp_input_trace_t;
278 format_ethernet_arp_input_trace (u8 * s, va_list * va)
280 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
281 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
282 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
285 format_ethernet_arp_header,
286 t->packet_data, sizeof (t->packet_data));
292 format_arp_term_input_trace (u8 * s, va_list * va)
294 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
295 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
296 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
298 /* arp-term trace data saved is either arp or ip6/icmp6 packet:
299 - for arp, the 1st 16-bit field is hw type of value of 0x0001.
300 - for ip6, the first nibble has value of 6. */
301 s = format (s, "%U", t->packet_data[0] == 0 ?
302 format_ethernet_arp_header : format_ip6_header,
303 t->packet_data, sizeof (t->packet_data));
309 arp_nbr_probe (ip_adjacency_t * adj)
311 vnet_main_t *vnm = vnet_get_main ();
312 ip4_main_t *im = &ip4_main;
313 ip_interface_address_t *ia;
314 ethernet_arp_header_t *h;
315 vnet_hw_interface_t *hi;
316 vnet_sw_interface_t *si;
322 vm = vlib_get_main ();
324 si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
326 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
332 ip4_interface_address_matching_destination (im,
333 &adj->sub_type.nbr.next_hop.
343 vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template,
346 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
348 clib_memcpy (h->ip4_over_ethernet[0].ethernet,
349 hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
351 h->ip4_over_ethernet[0].ip4 = src[0];
352 h->ip4_over_ethernet[1].ip4 = adj->sub_type.nbr.next_hop.ip4;
354 b = vlib_get_buffer (vm, bi);
355 vnet_buffer (b)->sw_if_index[VLIB_RX] =
356 vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
358 /* Add encapsulation string for software interface (e.g. ethernet header). */
359 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
360 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
363 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
364 u32 *to_next = vlib_frame_vector_args (f);
367 vlib_put_frame_to_node (vm, hi->output_node_index, f);
372 arp_mk_complete (adj_index_t ai, ethernet_arp_ip4_entry_t * e)
374 adj_nbr_update_rewrite
375 (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
376 ethernet_build_rewrite (vnet_get_main (),
378 adj_get_link_type (ai), e->ethernet_address));
382 arp_mk_incomplete (adj_index_t ai)
384 ip_adjacency_t *adj = adj_get (ai);
386 adj_nbr_update_rewrite
388 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
389 ethernet_build_rewrite (vnet_get_main (),
390 adj->rewrite_header.sw_if_index,
392 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
395 static ethernet_arp_ip4_entry_t *
396 arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
398 ethernet_arp_main_t *am = ðernet_arp_main;
399 ethernet_arp_ip4_entry_t *e = NULL;
402 if (NULL != eai->arp_entries)
404 p = hash_get (eai->arp_entries, addr->as_u32);
408 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
415 arp_mk_complete_walk (adj_index_t ai, void *ctx)
417 ethernet_arp_ip4_entry_t *e = ctx;
419 arp_mk_complete (ai, e);
421 return (ADJ_WALK_RC_CONTINUE);
425 arp_mk_incomplete_walk (adj_index_t ai, void *ctx)
427 arp_mk_incomplete (ai);
429 return (ADJ_WALK_RC_CONTINUE);
433 arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
435 ethernet_arp_main_t *am = ðernet_arp_main;
436 ethernet_arp_interface_t *arp_int;
437 ethernet_arp_ip4_entry_t *e;
442 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
443 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
444 e = arp_entry_find (arp_int, &adj->sub_type.nbr.next_hop.ip4);
446 switch (adj->lookup_next_index)
448 case IP_LOOKUP_NEXT_ARP:
449 case IP_LOOKUP_NEXT_GLEAN:
452 adj_nbr_walk_nh4 (sw_if_index,
453 &e->ip4_address, arp_mk_complete_walk, e);
458 * no matching ARP entry.
459 * construct the rewrite required to for an ARP packet, and stick
460 * that in the adj's pipe to smoke.
462 adj_nbr_update_rewrite
464 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
465 ethernet_build_rewrite
469 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
472 * since the FIB has added this adj for a route, it makes sense it
473 * may want to forward traffic sometime soon. Let's send a
474 * speculative ARP. just one. If we were to do periodically that
475 * wouldn't be bad either, but that's more code than i'm prepared to
476 * write at this time for relatively little reward.
481 case IP_LOOKUP_NEXT_MCAST:
484 * Construct a partial rewrite from the known ethernet mcast dest MAC
489 rewrite = ethernet_build_rewrite (vnm,
492 ethernet_ip4_mcast_dst_addr ());
493 offset = vec_len (rewrite) - 2;
496 * Complete the remaining fields of the adj's rewrite to direct the
497 * complete of the rewrite at switch time by copying in the IP
498 * dst address's bytes.
499 * Ofset is 2 bytes into the MAC desintation address. And we copy 23 bits
502 adj_mcast_update_rewrite (ai, rewrite, offset, 0x007fffff);
506 case IP_LOOKUP_NEXT_DROP:
507 case IP_LOOKUP_NEXT_PUNT:
508 case IP_LOOKUP_NEXT_LOCAL:
509 case IP_LOOKUP_NEXT_REWRITE:
510 case IP_LOOKUP_NEXT_LOAD_BALANCE:
511 case IP_LOOKUP_NEXT_MIDCHAIN:
512 case IP_LOOKUP_NEXT_ICMP_ERROR:
513 case IP_LOOKUP_N_NEXT:
520 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
521 vnet_arp_set_ip4_over_ethernet_rpc_args_t
524 ethernet_arp_ip4_entry_t *e = 0;
525 ethernet_arp_main_t *am = ðernet_arp_main;
526 ethernet_arp_ip4_over_ethernet_address_t *a = &args->a;
527 vlib_main_t *vm = vlib_get_main ();
528 int make_new_arp_cache_entry = 1;
530 pending_resolution_t *pr, *mc;
531 ethernet_arp_interface_t *arp_int;
532 int is_static = args->is_static;
533 u32 sw_if_index = args->sw_if_index;
534 int is_no_fib_entry = args->is_no_fib_entry;
536 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
538 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
540 if (NULL != arp_int->arp_entries)
542 p = hash_get (arp_int->arp_entries, a->ip4.as_u32);
545 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
547 /* Refuse to over-write static arp. */
548 if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
550 make_new_arp_cache_entry = 0;
554 if (make_new_arp_cache_entry)
556 pool_get (am->ip4_entry_pool, e);
558 if (NULL == arp_int->arp_entries)
560 arp_int->arp_entries = hash_create (0, sizeof (u32));
563 hash_set (arp_int->arp_entries, a->ip4.as_u32, e - am->ip4_entry_pool);
565 e->sw_if_index = sw_if_index;
566 e->ip4_address = a->ip4;
567 clib_memcpy (e->ethernet_address,
568 a->ethernet, sizeof (e->ethernet_address));
570 if (!is_no_fib_entry)
574 .fp_proto = FIB_PROTOCOL_IP4,
575 .fp_addr.ip4 = a->ip4,
580 ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
582 fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_ADJ,
583 FIB_ENTRY_FLAG_ATTACHED,
584 FIB_PROTOCOL_IP4, &pfx.fp_addr,
585 e->sw_if_index, ~0, 1, NULL,
586 FIB_ROUTE_PATH_FLAG_NONE);
587 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_NO_FIB_ENTRY;
593 * prevent a DoS attack from the data-plane that
594 * spams us with no-op updates to the MAC address
596 if (0 == memcmp (e->ethernet_address,
597 a->ethernet, sizeof (e->ethernet_address)))
600 /* Update time stamp and ethernet address. */
601 clib_memcpy (e->ethernet_address, a->ethernet,
602 sizeof (e->ethernet_address));
605 e->cpu_time_last_updated = clib_cpu_time_now ();
607 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
609 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC;
611 adj_nbr_walk_nh4 (sw_if_index, &e->ip4_address, arp_mk_complete_walk, e);
613 /* Customer(s) waiting for this address to be resolved? */
614 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
620 while (next_index != (u32) ~ 0)
622 pr = pool_elt_at_index (am->pending_resolutions, next_index);
623 vlib_process_signal_event (vm, pr->node_index,
624 pr->type_opaque, pr->data);
625 next_index = pr->next_index;
626 pool_put (am->pending_resolutions, pr);
629 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
632 /* Customer(s) requesting ARP event for this address? */
633 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
639 while (next_index != (u32) ~ 0)
641 int (*fp) (u32, u8 *, u32, u32);
643 mc = pool_elt_at_index (am->mac_changes, next_index);
644 fp = mc->data_callback;
646 /* Call the user's data callback, return 1 to suppress dup events */
648 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
651 * Signal the resolver process, as long as the user
652 * says they want to be notified
655 vlib_process_signal_event (vm, mc->node_index,
656 mc->type_opaque, mc->data);
657 next_index = mc->next_index;
665 vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
668 uword type_opaque, uword data)
670 ethernet_arp_main_t *am = ðernet_arp_main;
671 ip4_address_t *address = address_arg;
673 pending_resolution_t *pr;
675 pool_get (am->pending_resolutions, pr);
678 pr->node_index = node_index;
679 pr->type_opaque = type_opaque;
681 pr->data_callback = 0;
683 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
686 /* Insert new resolution at the head of the list */
687 pr->next_index = p[0];
688 hash_unset (am->pending_resolutions_by_address, address->as_u32);
691 hash_set (am->pending_resolutions_by_address, address->as_u32,
692 pr - am->pending_resolutions);
696 vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
701 uword type_opaque, uword data, int is_add)
703 ethernet_arp_main_t *am = ðernet_arp_main;
704 ip4_address_t *address = address_arg;
706 pending_resolution_t *mc;
707 void (*fp) (u32, u8 *) = data_callback;
711 pool_get (am->mac_changes, mc);
714 mc->node_index = node_index;
715 mc->type_opaque = type_opaque;
717 mc->data_callback = data_callback;
720 p = hash_get (am->mac_changes_by_address, address->as_u32);
723 /* Insert new resolution at the head of the list */
724 mc->next_index = p[0];
725 hash_unset (am->mac_changes_by_address, address->as_u32);
728 hash_set (am->mac_changes_by_address, address->as_u32,
729 mc - am->mac_changes);
735 pending_resolution_t *mc_last = 0;
737 p = hash_get (am->mac_changes_by_address, address->as_u32);
739 return VNET_API_ERROR_NO_SUCH_ENTRY;
743 while (index != (u32) ~ 0)
745 mc = pool_elt_at_index (am->mac_changes, index);
746 if (mc->node_index == node_index &&
747 mc->type_opaque == type_opaque && mc->pid == pid)
749 /* Clients may need to clean up pool entries, too */
751 (*fp) (mc->data, 0 /* no new mac addrs */ );
754 hash_unset (am->mac_changes_by_address, address->as_u32);
755 if (mc->next_index != ~0)
756 hash_set (am->mac_changes_by_address, address->as_u32,
758 pool_put (am->mac_changes, mc);
764 mc_last->next_index = mc->next_index;
765 pool_put (am->mac_changes, mc);
770 index = mc->next_index;
773 return VNET_API_ERROR_NO_SUCH_ENTRY;
777 /* Either we drop the packet or we send a reply to the sender. */
781 ARP_INPUT_NEXT_REPLY_TX,
785 #define foreach_ethernet_arp_error \
786 _ (replies_sent, "ARP replies sent") \
787 _ (l2_type_not_ethernet, "L2 type not ethernet") \
788 _ (l3_type_not_ip4, "L3 type not IP4") \
789 _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
790 _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
791 _ (l3_src_address_is_local, "IP4 source address matches local interface") \
792 _ (l3_src_address_learned, "ARP request IP4 source address learned") \
793 _ (replies_received, "ARP replies received") \
794 _ (opcode_not_request, "ARP opcode not request") \
795 _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
796 _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
797 _ (missing_interface_address, "ARP missing interface address") \
798 _ (gratuitous_arp, "ARP probe or announcement dropped") \
799 _ (interface_no_table, "Interface is not mapped to an IP table") \
800 _ (interface_not_ip_enabled, "Interface is not IP enabled") \
804 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
805 foreach_ethernet_arp_error
807 ETHERNET_ARP_N_ERROR,
808 } ethernet_arp_input_error_t;
812 unset_random_arp_entry (void)
814 ethernet_arp_main_t *am = ðernet_arp_main;
815 ethernet_arp_ip4_entry_t *e;
816 vnet_main_t *vnm = vnet_get_main ();
817 ethernet_arp_ip4_over_ethernet_address_t delme;
820 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
821 am->arp_delete_rotor = index;
823 /* Try again from elt 0, could happen if an intfc goes down */
826 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
827 am->arp_delete_rotor = index;
830 /* Nothing left in the pool */
834 e = pool_elt_at_index (am->ip4_entry_pool, index);
836 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
837 delme.ip4.as_u32 = e->ip4_address.as_u32;
839 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
843 arp_unnumbered (vlib_buffer_t * p0,
844 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
846 vlib_main_t *vm = vlib_get_main ();
847 vnet_main_t *vnm = vnet_get_main ();
848 vnet_interface_main_t *vim = &vnm->interface_main;
849 vnet_sw_interface_t *si;
850 vnet_hw_interface_t *hi;
851 u32 unnum_src_sw_if_index;
852 u32 *broadcast_swifs = 0;
857 u8 dst_mac_address[6];
859 ethernet_arp_header_t *arp0;
861 /* Save the dst mac address */
862 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
864 /* Figure out which sw_if_index supplied the address */
865 unnum_src_sw_if_index = sw_if_index;
867 /* Track down all users of the unnumbered source */
869 pool_foreach (si, vim->sw_interfaces,
871 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
872 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
874 vec_add1 (broadcast_swifs, si->sw_if_index);
879 /* If there are no interfaces un-unmbered to this interface,
881 if (0 == vec_len (broadcast_swifs))
884 /* Allocate buffering if we need it */
885 if (vec_len (broadcast_swifs) > 1)
887 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
888 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
889 _vec_len (buffers) = n_alloc;
890 for (i = 0; i < n_alloc; i++)
892 b0 = vlib_get_buffer (vm, buffers[i]);
894 /* xerox (partially built) ARP pkt */
895 clib_memcpy (b0->data, p0->data,
896 p0->current_length + p0->current_data);
897 b0->current_data = p0->current_data;
898 b0->current_length = p0->current_length;
899 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
900 vnet_buffer (p0)->sw_if_index[VLIB_RX];
904 vec_insert (buffers, 1, 0);
907 for (i = 0; i < vec_len (buffers); i++)
909 b0 = vlib_get_buffer (vm, buffers[i]);
910 arp0 = vlib_buffer_get_current (b0);
912 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
913 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
915 /* For decoration, most likely */
916 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
918 /* Fix ARP pkt src address */
919 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
921 /* Build L2 encaps for this swif */
922 header_size = sizeof (ethernet_header_t);
923 if (si->sub.eth.flags.one_tag)
925 else if (si->sub.eth.flags.two_tags)
928 vlib_buffer_advance (b0, -header_size);
929 eth0 = vlib_buffer_get_current (b0);
931 if (si->sub.eth.flags.one_tag)
933 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
935 eth0->type = si->sub.eth.flags.dot1ad ?
936 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
937 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
938 outer->priority_cfi_and_id =
939 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
940 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
943 else if (si->sub.eth.flags.two_tags)
945 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
946 ethernet_vlan_header_t *inner = (void *) (outer + 1);
948 eth0->type = si->sub.eth.flags.dot1ad ?
949 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
950 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
951 outer->priority_cfi_and_id =
952 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
953 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
954 inner->priority_cfi_and_id =
955 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
956 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
961 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
964 /* Restore the original dst address, set src address */
965 clib_memcpy (eth0->dst_address, dst_mac_address,
966 sizeof (eth0->dst_address));
967 clib_memcpy (eth0->src_address, hi->hw_address,
968 sizeof (eth0->src_address));
970 /* Transmit replicas */
974 vlib_get_frame_to_node (vm, hi->output_node_index);
975 u32 *to_next = vlib_frame_vector_args (f);
976 to_next[0] = buffers[i];
978 vlib_put_frame_to_node (vm, hi->output_node_index, f);
982 /* The regular path outputs the original pkt.. */
983 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
985 vec_free (broadcast_swifs);
992 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
994 ethernet_arp_main_t *am = ðernet_arp_main;
995 vnet_main_t *vnm = vnet_get_main ();
996 ip4_main_t *im4 = &ip4_main;
997 u32 n_left_from, next_index, *from, *to_next;
998 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
1000 from = vlib_frame_vector_args (frame);
1001 n_left_from = frame->n_vectors;
1002 next_index = node->cached_next_index;
1004 if (node->flags & VLIB_NODE_FLAG_TRACE)
1005 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1007 sizeof (ethernet_arp_input_trace_t));
1009 while (n_left_from > 0)
1013 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1015 while (n_left_from > 0 && n_left_to_next > 0)
1018 vnet_hw_interface_t *hw_if0;
1019 ethernet_arp_header_t *arp0;
1020 ethernet_header_t *eth0;
1021 ip4_address_t *if_addr0, proxy_src;
1022 u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
1023 u8 is_request0, dst_is_local0, is_unnum0;
1024 ethernet_proxy_arp_t *pa;
1025 fib_node_index_t dst_fei, src_fei;
1027 fib_entry_flag_t src_flags, dst_flags;
1034 n_left_to_next -= 1;
1037 p0 = vlib_get_buffer (vm, pi0);
1038 arp0 = vlib_buffer_get_current (p0);
1040 is_request0 = arp0->opcode
1041 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
1043 error0 = ETHERNET_ARP_ERROR_replies_sent;
1047 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1048 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1051 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
1052 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
1054 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1056 /* not playing the ARP game if the interface is not IPv4 enabled */
1058 (im4->ip_enabled_by_sw_if_index[sw_if_index0] == 0 ?
1059 ETHERNET_ARP_ERROR_interface_not_ip_enabled : error0);
1064 /* Check that IP address is local and matches incoming interface. */
1065 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1066 if (~0 == fib_index0)
1068 error0 = ETHERNET_ARP_ERROR_interface_no_table;
1072 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1073 &arp0->ip4_over_ethernet[1].ip4,
1075 dst_flags = fib_entry_get_flags (dst_fei);
1077 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1078 &arp0->ip4_over_ethernet[0].ip4,
1080 src_flags = fib_entry_get_flags (src_fei);
1082 conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
1084 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
1086 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1090 /* Honor unnumbered interface, if any */
1091 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
1093 /* Source must also be local to subnet of matching interface address. */
1094 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
1095 (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
1098 * The packet was sent from an address that is not connected nor attached
1099 * i.e. it is not from an address that is covered by a link's sub-net,
1100 * nor is it a already learned host resp.
1102 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
1105 if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1108 * The interface the ARP was received on is not the interface
1109 * on which the covering prefix is configured. Maybe this is a case
1115 /* Reject requests/replies with our local interface address. */
1116 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
1118 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1122 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1123 fib_entry_get_prefix (dst_fei, &pfx0);
1124 if_addr0 = &pfx0.fp_addr.ip4;
1126 /* Fill in ethernet header. */
1127 eth0 = ethernet_buffer_get_header (p0);
1129 /* Trash ARP packets whose ARP-level source addresses do not
1130 match their L2-frame-level source addresses */
1131 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1132 sizeof (eth0->src_address)))
1134 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1138 /* Learn or update sender's mapping only for requests or unicasts
1139 that don't match local interface address. */
1140 if (ethernet_address_cast (eth0->dst_address) ==
1141 ETHERNET_ADDRESS_UNICAST || is_request0)
1143 if (am->limit_arp_cache_size &&
1144 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1145 unset_random_arp_entry ();
1147 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
1148 &arp0->ip4_over_ethernet[0],
1149 0 /* is_static */ , 0);
1150 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1153 /* Only send a reply for requests sent which match a local interface. */
1154 if (!(is_request0 && dst_is_local0))
1158 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1159 ETHERNET_ARP_ERROR_replies_received : error0);
1165 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1166 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1168 /* Send reply back through input interface */
1169 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1170 next0 = ARP_INPUT_NEXT_REPLY_TX;
1172 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1174 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1176 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1177 hw_if0->hw_address, 6);
1178 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1181 /* Hardware must be ethernet-like. */
1182 ASSERT (vec_len (hw_if0->hw_address) == 6);
1184 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1185 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1187 /* Figure out how much to rewind current data from adjacency. */
1188 /* get the adj from the destination's covering connected */
1193 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1198 ip_adjacency_t *adj0 = NULL;
1201 if (FIB_ENTRY_FLAG_ATTACHED & src_flags)
1204 * If the source is attached use the adj from that source.
1206 ai = fib_entry_get_adj (src_fei);
1207 if (ADJ_INDEX_INVALID != ai)
1209 adj0 = adj_get (ai);
1215 * Get the glean adj from the cover. This is presumably interface
1216 * sourced, and therefre needs to be a glean adj.
1218 ai = fib_entry_get_adj_for_source
1219 (ip4_fib_table_lookup
1220 (ip4_fib_get (fib_index0),
1221 &arp0->ip4_over_ethernet[1].ip4, 31),
1222 FIB_SOURCE_INTERFACE);
1224 if (ADJ_INDEX_INVALID != ai)
1226 adj0 = adj_get (ai);
1228 if (adj0->lookup_next_index == IP_LOOKUP_NEXT_GLEAN)
1236 vlib_buffer_advance (p0,
1237 -adj0->rewrite_header.data_bytes);
1241 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1247 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1248 n_left_to_next, pi0, next0);
1250 n_replies_sent += 1;
1254 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1255 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1256 arp0->ip4_over_ethernet[1].ip4.as_u32))
1258 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1261 /* See if proxy arp is configured for the address */
1264 vnet_sw_interface_t *si;
1265 u32 this_addr = clib_net_to_host_u32
1266 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1269 si = vnet_get_sw_interface (vnm, sw_if_index0);
1271 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1274 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1277 vec_foreach (pa, am->proxy_arps)
1279 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1280 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1282 /* an ARP request hit in the proxy-arp table? */
1283 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1284 (fib_index0 == pa->fib_index))
1286 eth0 = ethernet_buffer_get_header (p0);
1288 arp0->ip4_over_ethernet[1].ip4.data_u32;
1291 * Rewind buffer, direct code above not to
1292 * think too hard about it.
1294 if_addr0 = &proxy_src;
1296 i32 ethernet_start =
1297 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1298 i32 rewind = p0->current_data - ethernet_start;
1299 vlib_buffer_advance (p0, -rewind);
1300 n_proxy_arp_replies_sent++;
1308 next0 = ARP_INPUT_NEXT_DROP;
1309 p0->error = node->errors[error0];
1311 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1312 n_left_to_next, pi0, next0);
1315 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1318 vlib_error_count (vm, node->node_index,
1319 ETHERNET_ARP_ERROR_replies_sent,
1320 n_replies_sent - n_proxy_arp_replies_sent);
1322 vlib_error_count (vm, node->node_index,
1323 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1324 n_proxy_arp_replies_sent);
1325 return frame->n_vectors;
1328 static char *ethernet_arp_error_strings[] = {
1329 #define _(sym,string) string,
1330 foreach_ethernet_arp_error
1335 VLIB_REGISTER_NODE (arp_input_node, static) =
1337 .function = arp_input,
1338 .name = "arp-input",
1339 .vector_size = sizeof (u32),
1340 .n_errors = ETHERNET_ARP_N_ERROR,
1341 .error_strings = ethernet_arp_error_strings,
1342 .n_next_nodes = ARP_INPUT_N_NEXT,
1344 [ARP_INPUT_NEXT_DROP] = "error-drop",
1345 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1347 .format_buffer = format_ethernet_arp_header,
1348 .format_trace = format_ethernet_arp_input_trace,
1353 ip4_arp_entry_sort (void *a1, void *a2)
1355 ethernet_arp_ip4_entry_t *e1 = a1;
1356 ethernet_arp_ip4_entry_t *e2 = a2;
1359 vnet_main_t *vnm = vnet_get_main ();
1361 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1363 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1367 ethernet_arp_ip4_entry_t *
1368 ip4_neighbor_entries (u32 sw_if_index)
1370 ethernet_arp_main_t *am = ðernet_arp_main;
1371 ethernet_arp_ip4_entry_t *n, *ns = 0;
1374 pool_foreach (n, am->ip4_entry_pool, ({
1375 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1377 vec_add1 (ns, n[0]);
1382 vec_sort_with_function (ns, ip4_arp_entry_sort);
1386 static clib_error_t *
1387 show_ip4_arp (vlib_main_t * vm,
1388 unformat_input_t * input, vlib_cli_command_t * cmd)
1390 vnet_main_t *vnm = vnet_get_main ();
1391 ethernet_arp_main_t *am = ðernet_arp_main;
1392 ethernet_arp_ip4_entry_t *e, *es;
1393 ethernet_proxy_arp_t *pa;
1394 clib_error_t *error = 0;
1397 /* Filter entries by interface if given. */
1399 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1401 es = ip4_neighbor_entries (sw_if_index);
1404 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1407 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1412 if (vec_len (am->proxy_arps))
1414 vlib_cli_output (vm, "Proxy arps enabled for:");
1415 vec_foreach (pa, am->proxy_arps)
1417 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1419 format_ip4_address, &pa->lo_addr,
1420 format_ip4_address, &pa->hi_addr);
1428 * Display all the IPv4 ARP entries.
1431 * Example of how to display the IPv4 ARP table:
1432 * @cliexstart{show ip arp}
1433 * Time FIB IP4 Flags Ethernet Interface
1434 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1435 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1436 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1437 * Proxy arps enabled for:
1438 * Fib_index 0 6.0.0.1 - 6.0.0.11
1442 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1443 .path = "show ip arp",
1444 .function = show_ip4_arp,
1445 .short_help = "show ip arp",
1451 pg_edit_t l2_type, l3_type;
1452 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1458 } ip4_over_ethernet[2];
1459 } pg_ethernet_arp_header_t;
1462 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1464 /* Initialize fields that are not bit fields in the IP header. */
1465 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1468 _(n_l2_address_bytes);
1469 _(n_l3_address_bytes);
1471 _(ip4_over_ethernet[0].ethernet);
1472 _(ip4_over_ethernet[0].ip4);
1473 _(ip4_over_ethernet[1].ethernet);
1474 _(ip4_over_ethernet[1].ip4);
1479 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1481 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1482 pg_ethernet_arp_header_t *p;
1485 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1487 pg_ethernet_arp_header_init (p);
1490 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1491 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1492 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1493 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1495 if (!unformat (input, "%U: %U/%U -> %U/%U",
1497 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1499 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1501 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1503 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1505 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1507 /* Free up any edits we may have added. */
1508 pg_free_edit_group (s);
1515 ip4_set_arp_limit (u32 arp_limit)
1517 ethernet_arp_main_t *am = ðernet_arp_main;
1519 am->limit_arp_cache_size = arp_limit;
1524 * @brief Control Plane hook to remove an ARP entry
1527 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1528 u32 sw_if_index, void *a_arg)
1530 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1531 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1533 args.sw_if_index = sw_if_index;
1534 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1535 clib_memcpy (&args.a, a, sizeof (*a));
1537 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1538 (u8 *) & args, sizeof (args));
1543 * @brief Internally generated event to flush the ARP cache on an
1544 * interface state change event.
1545 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1546 * address from the corresponding adjacencies.
1549 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1550 u32 sw_if_index, void *a_arg)
1552 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1553 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1555 args.sw_if_index = sw_if_index;
1556 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1557 clib_memcpy (&args.a, a, sizeof (*a));
1559 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1560 (u8 *) & args, sizeof (args));
1565 * @brief Internally generated event to populate the ARP cache on an
1566 * interface state change event.
1567 * For static entries this will re-source the adjacencies.
1569 * @param sw_if_index The interface on which the ARP entires are acted
1572 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1573 u32 sw_if_index, void *a_arg)
1575 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1576 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1578 args.sw_if_index = sw_if_index;
1579 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1580 clib_memcpy (&args.a, a, sizeof (*a));
1582 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1583 (u8 *) & args, sizeof (args));
1588 * arp_add_del_interface_address
1590 * callback when an interface address is added or deleted
1593 arp_add_del_interface_address (ip4_main_t * im,
1596 ip4_address_t * address,
1598 u32 if_address_index, u32 is_del)
1601 * Flush the ARP cache of all entries covered by the address
1602 * that is being removed.
1604 ethernet_arp_main_t *am = ðernet_arp_main;
1605 ethernet_arp_ip4_entry_t *e;
1607 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
1612 ethernet_arp_interface_t *eai;
1613 u32 i, *to_delete = 0;
1616 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1619 hash_foreach_pair (pair, eai->arp_entries,
1621 e = pool_elt_at_index(am->ip4_entry_pool,
1623 if (ip4_destination_matches_route (im, &e->ip4_address,
1624 address, address_length))
1626 vec_add1 (to_delete, e - am->ip4_entry_pool);
1631 for (i = 0; i < vec_len (to_delete); i++)
1633 ethernet_arp_ip4_over_ethernet_address_t delme;
1634 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1636 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1637 delme.ip4.as_u32 = e->ip4_address.as_u32;
1639 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1640 e->sw_if_index, &delme);
1643 vec_free (to_delete);
1647 static clib_error_t *
1648 ethernet_arp_init (vlib_main_t * vm)
1650 ethernet_arp_main_t *am = ðernet_arp_main;
1651 ip4_main_t *im = &ip4_main;
1652 clib_error_t *error;
1655 if ((error = vlib_call_init_function (vm, ethernet_init)))
1658 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1660 pn = pg_get_node (arp_input_node.index);
1661 pn->unformat_edit = unformat_pg_arp_header;
1663 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1664 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1665 foreach_ethernet_arp_opcode;
1668 /* $$$ configurable */
1669 am->limit_arp_cache_size = 50000;
1671 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1672 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1674 /* don't trace ARP error packets */
1676 vlib_node_runtime_t *rt =
1677 vlib_node_get_runtime (vm, arp_input_node.index);
1680 vnet_pcap_drop_trace_filter_add_del \
1681 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1683 foreach_ethernet_arp_error
1687 ip4_add_del_interface_address_callback_t cb;
1688 cb.function = arp_add_del_interface_address;
1689 cb.function_opaque = 0;
1690 vec_add1 (im->add_del_interface_address_callbacks, cb);
1695 VLIB_INIT_FUNCTION (ethernet_arp_init);
1698 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1700 ethernet_arp_main_t *am = ðernet_arp_main;
1702 /* it's safe to delete the ADJ source on the FIB entry, even if it
1704 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
1705 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1706 pool_put (am->ip4_entry_pool, e);
1710 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1711 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1714 ethernet_arp_main_t *am = ðernet_arp_main;
1715 ethernet_arp_ip4_entry_t *e;
1716 ethernet_arp_interface_t *eai;
1718 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1720 e = arp_entry_find (eai, &args->a.ip4);
1724 arp_entry_free (eai, e);
1726 adj_nbr_walk_nh4 (e->sw_if_index,
1727 &e->ip4_address, arp_mk_incomplete_walk, NULL);
1734 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1735 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1738 ethernet_arp_main_t *am = ðernet_arp_main;
1739 ethernet_arp_ip4_entry_t *e;
1740 ethernet_arp_interface_t *eai;
1742 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1744 e = arp_entry_find (eai, &args->a.ip4);
1748 adj_nbr_walk_nh4 (e->sw_if_index,
1749 &e->ip4_address, arp_mk_incomplete_walk, e);
1752 * The difference between flush and unset, is that an unset
1753 * means delete for static and dynamic entries. A flush
1754 * means delete only for dynamic. Flushing is what the DP
1755 * does in response to interface events. unset is only done
1756 * by the control plane.
1758 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
1760 arp_entry_free (eai, e);
1767 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1768 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1771 ethernet_arp_main_t *am = ðernet_arp_main;
1772 ethernet_arp_ip4_entry_t *e;
1773 ethernet_arp_interface_t *eai;
1775 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1777 e = arp_entry_find (eai, &args->a.ip4);
1781 adj_nbr_walk_nh4 (e->sw_if_index,
1782 &e->ip4_address, arp_mk_complete_walk, e);
1788 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1791 vnet_main_t *vm = vnet_get_main ();
1792 ASSERT (os_get_cpu_number () == 0);
1794 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1795 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1796 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1797 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1798 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1799 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1801 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1805 * @brief Invoked when the interface's admin state changes
1807 static clib_error_t *
1808 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1809 u32 sw_if_index, u32 flags)
1811 ethernet_arp_main_t *am = ðernet_arp_main;
1812 ethernet_arp_ip4_entry_t *e;
1813 u32 i, *to_delete = 0;
1816 pool_foreach (e, am->ip4_entry_pool,
1818 if (e->sw_if_index == sw_if_index)
1819 vec_add1 (to_delete,
1820 e - am->ip4_entry_pool);
1824 for (i = 0; i < vec_len (to_delete); i++)
1826 ethernet_arp_ip4_over_ethernet_address_t delme;
1827 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1829 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1830 delme.ip4.as_u32 = e->ip4_address.as_u32;
1832 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1834 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1838 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1842 vec_free (to_delete);
1847 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1850 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1855 for (i = 3; i >= 0; i--)
1857 old = a->ip4.as_u8[i];
1858 a->ip4.as_u8[i] += 1;
1859 if (old < a->ip4.as_u8[i])
1863 for (i = 5; i >= 0; i--)
1865 old = a->ethernet[i];
1866 a->ethernet[i] += 1;
1867 if (old < a->ethernet[i])
1873 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1874 u32 sw_if_index, void *a_arg,
1875 int is_static, int is_no_fib_entry)
1877 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1878 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1880 args.sw_if_index = sw_if_index;
1881 args.is_static = is_static;
1882 args.is_no_fib_entry = is_no_fib_entry;
1884 clib_memcpy (&args.a, a, sizeof (*a));
1886 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1887 (u8 *) & args, sizeof (args));
1892 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1893 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1895 ethernet_arp_main_t *am = ðernet_arp_main;
1896 ethernet_proxy_arp_t *pa;
1897 u32 found_at_index = ~0;
1899 vec_foreach (pa, am->proxy_arps)
1901 if (pa->lo_addr == lo_addr->as_u32
1902 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1904 found_at_index = pa - am->proxy_arps;
1909 if (found_at_index != ~0)
1911 /* Delete, otherwise it's already in the table */
1913 vec_delete (am->proxy_arps, 1, found_at_index);
1916 /* delete, no such entry */
1918 return VNET_API_ERROR_NO_SUCH_ENTRY;
1920 /* add, not in table */
1921 vec_add2 (am->proxy_arps, pa, 1);
1922 pa->lo_addr = lo_addr->as_u32;
1923 pa->hi_addr = hi_addr->as_u32;
1924 pa->fib_index = fib_index;
1929 * Remove any proxy arp entries asdociated with the
1933 vnet_proxy_arp_fib_reset (u32 fib_id)
1935 ip4_main_t *im = &ip4_main;
1936 ethernet_arp_main_t *am = ðernet_arp_main;
1937 ethernet_proxy_arp_t *pa;
1938 u32 *entries_to_delete = 0;
1943 p = hash_get (im->fib_index_by_table_id, fib_id);
1945 return VNET_API_ERROR_NO_SUCH_ENTRY;
1948 vec_foreach (pa, am->proxy_arps)
1950 if (pa->fib_index == fib_index)
1952 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1956 for (i = 0; i < vec_len (entries_to_delete); i++)
1958 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1961 vec_free (entries_to_delete);
1966 static clib_error_t *
1967 ip_arp_add_del_command_fn (vlib_main_t * vm,
1968 unformat_input_t * input, vlib_cli_command_t * cmd)
1970 vnet_main_t *vnm = vnet_get_main ();
1972 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1979 int is_no_fib_entry = 0;
1982 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1984 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1985 if (unformat (input, "%U %U %U",
1986 unformat_vnet_sw_interface, vnm, &sw_if_index,
1987 unformat_ip4_address, &addr.ip4,
1988 unformat_ethernet_address, &addr.ethernet))
1991 else if (unformat (input, "delete") || unformat (input, "del"))
1994 else if (unformat (input, "static"))
1997 else if (unformat (input, "no-fib-entry"))
1998 is_no_fib_entry = 1;
2000 else if (unformat (input, "count %d", &count))
2003 else if (unformat (input, "fib-id %d", &fib_id))
2005 ip4_main_t *im = &ip4_main;
2006 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
2008 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
2012 else if (unformat (input, "proxy %U - %U",
2013 unformat_ip4_address, &lo_addr.ip4,
2014 unformat_ip4_address, &hi_addr.ip4))
2022 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
2031 for (i = 0; i < count; i++)
2035 uword event_type, *event_data = 0;
2037 /* Park the debug CLI until the arp entry is installed */
2038 vnet_register_ip4_arp_resolution_event
2039 (vnm, &addr.ip4, vlib_current_process (vm),
2040 1 /* type */ , 0 /* data */ );
2042 vnet_arp_set_ip4_over_ethernet
2043 (vnm, sw_if_index, &addr, is_static, is_no_fib_entry);
2045 vlib_process_wait_for_event (vm);
2046 event_type = vlib_process_get_events (vm, &event_data);
2047 vec_reset_length (event_data);
2048 if (event_type != 1)
2049 clib_warning ("event type %d unexpected", event_type);
2052 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
2054 increment_ip4_and_mac_address (&addr);
2059 return clib_error_return (0, "unknown input `%U'",
2060 format_unformat_error, input);
2068 * Add or delete IPv4 ARP cache entries.
2070 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
2071 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
2072 * any order and combination.
2076 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
2077 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
2078 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2079 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
2081 * To add or delete an IPv4 ARP cache entry to or from a specific fib
2083 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2084 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2086 * Add or delete IPv4 static ARP cache entries as follows:
2087 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2088 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2090 * For testing / debugging purposes, the 'set ip arp' command can add or
2091 * delete multiple entries. Supply the 'count N' parameter:
2092 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
2095 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
2096 .path = "set ip arp",
2098 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
2099 .function = ip_arp_add_del_command_fn,
2103 static clib_error_t *
2104 set_int_proxy_arp_command_fn (vlib_main_t * vm,
2106 input, vlib_cli_command_t * cmd)
2108 vnet_main_t *vnm = vnet_get_main ();
2110 vnet_sw_interface_t *si;
2114 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2116 if (unformat (input, "%U", unformat_vnet_sw_interface,
2119 else if (unformat (input, "enable") || unformat (input, "on"))
2121 else if (unformat (input, "disable") || unformat (input, "off"))
2128 return clib_error_return (0, "unknown input '%U'",
2129 format_unformat_error, input);
2131 si = vnet_get_sw_interface (vnm, sw_if_index);
2134 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2136 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2143 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2144 * requests for the indicated address range. Multiple proxy-arp
2145 * ranges may be provisioned.
2147 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2148 * Also, the underlying implementation has not been performance-tuned.
2149 * Avoid creating an unnecessarily large set of ranges.
2152 * To enable proxy arp on a range of addresses, use:
2153 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2154 * Append 'del' to delete a range of proxy ARP addresses:
2155 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2156 * You must then specifically enable proxy arp on individual interfaces:
2157 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2158 * To disable proxy arp on an individual interface:
2159 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2161 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2162 .path = "set interface proxy-arp",
2164 "set interface proxy-arp <intfc> [enable|disable]",
2165 .function = set_int_proxy_arp_command_fn,
2171 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2172 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2176 ARP_TERM_NEXT_L2_OUTPUT,
2181 u32 arp_term_next_node_index[32];
2184 arp_term_l2bd (vlib_main_t * vm,
2185 vlib_node_runtime_t * node, vlib_frame_t * frame)
2187 l2input_main_t *l2im = &l2input_main;
2188 u32 n_left_from, next_index, *from, *to_next;
2189 u32 n_replies_sent = 0;
2190 u16 last_bd_index = ~0;
2191 l2_bridge_domain_t *last_bd_config = 0;
2192 l2_input_config_t *cfg0;
2194 from = vlib_frame_vector_args (frame);
2195 n_left_from = frame->n_vectors;
2196 next_index = node->cached_next_index;
2198 while (n_left_from > 0)
2202 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2204 while (n_left_from > 0 && n_left_to_next > 0)
2207 ethernet_header_t *eth0;
2208 ethernet_arp_header_t *arp0;
2211 u32 pi0, error0, next0, sw_if_index0;
2222 n_left_to_next -= 1;
2224 p0 = vlib_get_buffer (vm, pi0);
2225 eth0 = vlib_buffer_get_current (p0);
2226 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2227 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2228 arp0 = (ethernet_arp_header_t *) l3h0;
2230 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2232 clib_host_to_net_u16
2233 (ETHERNET_ARP_OPCODE_request))))
2236 /* Must be ARP request packet here */
2237 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2238 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2240 u8 *t0 = vlib_add_trace (vm, node, p0,
2241 sizeof (ethernet_arp_input_trace_t));
2242 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2245 error0 = ETHERNET_ARP_ERROR_replies_sent;
2248 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2249 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2252 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2253 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2255 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2260 /* Trash ARP packets whose ARP-level source addresses do not
2261 match their L2-frame-level source addresses */
2264 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2265 sizeof (eth0->src_address))))
2267 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2271 /* Check if anyone want ARP request events for L2 BDs */
2273 pending_resolution_t *mc;
2274 ethernet_arp_main_t *am = ðernet_arp_main;
2275 uword *p = hash_get (am->mac_changes_by_address, 0);
2276 if (p && (vnet_buffer (p0)->l2.shg == 0))
2277 { // Only SHG 0 interface which is more likely local
2278 u32 next_index = p[0];
2279 while (next_index != (u32) ~ 0)
2281 int (*fp) (u32, u8 *, u32, u32);
2283 mc = pool_elt_at_index (am->mac_changes, next_index);
2284 fp = mc->data_callback;
2285 /* Call the callback, return 1 to suppress dup events */
2287 rv = (*fp) (mc->data,
2288 arp0->ip4_over_ethernet[0].ethernet,
2290 arp0->ip4_over_ethernet[0].ip4.as_u32);
2291 /* Signal the resolver process */
2293 vlib_process_signal_event (vm, mc->node_index,
2294 mc->type_opaque, mc->data);
2295 next_index = mc->next_index;
2300 /* lookup BD mac_by_ip4 hash table for MAC entry */
2301 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2302 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2303 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2304 || (last_bd_index == (u16) ~ 0)))
2306 last_bd_index = bd_index0;
2307 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2309 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2311 if (PREDICT_FALSE (!macp0))
2312 goto next_l2_feature; /* MAC not found */
2314 /* MAC found, send ARP reply -
2315 Convert ARP request packet to ARP reply */
2316 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2317 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2318 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2319 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2320 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2321 clib_memcpy (eth0->src_address, macp0, 6);
2322 n_replies_sent += 1;
2325 /* For BVI, need to use l2-fwd node to send ARP reply as
2326 l2-output node cannot output packet to BVI properly */
2327 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2328 if (PREDICT_FALSE (cfg0->bvi))
2330 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2331 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2332 goto next_l2_feature;
2335 /* Send ARP/ND reply back out input interface through l2-output */
2336 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2337 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2338 /* Note that output to VXLAN tunnel will fail due to SHG which
2339 is probably desireable since ARP termination is not intended
2340 for ARP requests from other hosts. If output to VXLAN tunnel is
2341 required, however, can just clear the SHG in packet as follows:
2342 vnet_buffer(p0)->l2.shg = 0; */
2343 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2344 to_next, n_left_to_next, pi0,
2349 /* IP6 ND event notification or solicitation handling to generate
2350 local response instead of flooding */
2351 iph0 = (ip6_header_t *) l3h0;
2352 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2353 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2354 !ip6_address_is_unspecified
2355 (&iph0->src_address)))
2357 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2358 if (vnet_ip6_nd_term
2359 (vm, node, p0, eth0, iph0, sw_if_index0,
2360 vnet_buffer (p0)->l2.bd_index, vnet_buffer (p0)->l2.shg))
2361 goto output_response;
2366 u32 feature_bitmap0 =
2367 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2368 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2370 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2372 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2373 to_next, n_left_to_next,
2379 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2380 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2381 arp0->ip4_over_ethernet[1].ip4.as_u32))
2383 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2385 next0 = ARP_TERM_NEXT_DROP;
2386 p0->error = node->errors[error0];
2388 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2389 to_next, n_left_to_next, pi0,
2393 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2396 vlib_error_count (vm, node->node_index,
2397 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2398 return frame->n_vectors;
2402 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2403 .function = arp_term_l2bd,
2404 .name = "arp-term-l2bd",
2405 .vector_size = sizeof (u32),
2406 .n_errors = ETHERNET_ARP_N_ERROR,
2407 .error_strings = ethernet_arp_error_strings,
2408 .n_next_nodes = ARP_TERM_N_NEXT,
2410 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2411 [ARP_TERM_NEXT_DROP] = "error-drop",
2413 .format_buffer = format_ethernet_arp_header,
2414 .format_trace = format_arp_term_input_trace,
2419 arp_term_init (vlib_main_t * vm)
2421 // Initialize the feature next-node indexes
2422 feat_bitmap_init_next_nodes (vm,
2423 arp_term_l2bd_node.index,
2425 l2input_get_feat_names (),
2426 arp_term_next_node_index);
2430 VLIB_INIT_FUNCTION (arp_term_init);
2433 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2435 if (e->sw_if_index == sw_if_index)
2437 adj_nbr_walk_nh4 (e->sw_if_index,
2438 &e->ip4_address, arp_mk_complete_walk, e);
2443 ethernet_arp_change_mac (u32 sw_if_index)
2445 ethernet_arp_main_t *am = ðernet_arp_main;
2446 ethernet_arp_ip4_entry_t *e;
2449 pool_foreach (e, am->ip4_entry_pool,
2451 change_arp_mac (sw_if_index, e);
2457 * fd.io coding-style-patch-verification: ON
2460 * eval: (c-set-style "gnu")