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>
29 * This file contains code to manage the IPv4 ARP tables (IP Address
30 * to MAC Address lookup).
34 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
40 ip4_address_t ip4_address;
41 } ethernet_arp_ip4_key_t;
45 ethernet_arp_ip4_key_t key;
46 u8 ethernet_address[6];
49 #define ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC (1 << 0)
50 #define ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN (2 << 0)
52 u64 cpu_time_last_updated;
55 } ethernet_arp_ip4_entry_t;
62 } ethernet_proxy_arp_t;
70 /* Used for arp event notification only */
73 } pending_resolution_t;
77 /* Hash tables mapping name to opcode. */
78 uword *opcode_by_name;
80 /* lite beer "glean" adjacency handling */
81 uword *pending_resolutions_by_address;
82 pending_resolution_t *pending_resolutions;
84 /* Mac address change notification */
85 uword *mac_changes_by_address;
86 pending_resolution_t *mac_changes;
88 ethernet_arp_ip4_entry_t *ip4_entry_pool;
90 mhash_t ip4_entry_by_key;
92 /* ARP attack mitigation */
94 u32 limit_arp_cache_size;
96 /* Proxy arp vector */
97 ethernet_proxy_arp_t *proxy_arps;
98 } ethernet_arp_main_t;
100 static ethernet_arp_main_t ethernet_arp_main;
103 format_ethernet_arp_hardware_type (u8 * s, va_list * va)
105 ethernet_arp_hardware_type_t h = va_arg (*va, ethernet_arp_hardware_type_t);
109 #define _(n,f) case n: t = #f; break;
110 foreach_ethernet_arp_hardware_type;
114 return format (s, "unknown 0x%x", h);
117 return format (s, "%s", t);
121 format_ethernet_arp_opcode (u8 * s, va_list * va)
123 ethernet_arp_opcode_t o = va_arg (*va, ethernet_arp_opcode_t);
127 #define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
128 foreach_ethernet_arp_opcode;
132 return format (s, "unknown 0x%x", o);
135 return format (s, "%s", t);
139 unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
142 int *result = va_arg (*args, int *);
143 ethernet_arp_main_t *am = ðernet_arp_main;
146 /* Numeric opcode. */
147 if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
156 if (unformat_user (input, unformat_vlib_number_by_name,
157 am->opcode_by_name, &i))
167 unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
170 int *result = va_arg (*args, int *);
172 (input, unformat_ethernet_arp_opcode_host_byte_order, result))
175 *result = clib_host_to_net_u16 ((u16) * result);
180 format_ethernet_arp_header (u8 * s, va_list * va)
182 ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
183 u32 max_header_bytes = va_arg (*va, u32);
185 u16 l2_type, l3_type;
187 if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
188 return format (s, "ARP header truncated");
190 l2_type = clib_net_to_host_u16 (a->l2_type);
191 l3_type = clib_net_to_host_u16 (a->l3_type);
193 indent = format_get_indent (s);
195 s = format (s, "%U, type %U/%U, address size %d/%d",
196 format_ethernet_arp_opcode, clib_net_to_host_u16 (a->opcode),
197 format_ethernet_arp_hardware_type, l2_type,
198 format_ethernet_type, l3_type,
199 a->n_l2_address_bytes, a->n_l3_address_bytes);
201 if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
202 && l3_type == ETHERNET_TYPE_IP4)
204 s = format (s, "\n%U%U/%U -> %U/%U",
205 format_white_space, indent,
206 format_ethernet_address, a->ip4_over_ethernet[0].ethernet,
207 format_ip4_address, &a->ip4_over_ethernet[0].ip4,
208 format_ethernet_address, a->ip4_over_ethernet[1].ethernet,
209 format_ip4_address, &a->ip4_over_ethernet[1].ip4);
213 uword n2 = a->n_l2_address_bytes;
214 uword n3 = a->n_l3_address_bytes;
215 s = format (s, "\n%U%U/%U -> %U/%U",
216 format_white_space, indent,
217 format_hex_bytes, a->data + 0 * n2 + 0 * n3, n2,
218 format_hex_bytes, a->data + 1 * n2 + 0 * n3, n3,
219 format_hex_bytes, a->data + 1 * n2 + 1 * n3, n2,
220 format_hex_bytes, a->data + 2 * n2 + 1 * n3, n3);
227 format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
229 vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
230 ethernet_arp_ip4_entry_t *e = va_arg (*va, ethernet_arp_ip4_entry_t *);
231 vnet_sw_interface_t *si;
236 return format (s, "%=12s%=6s%=16s%=6s%=20s%=24s", "Time", "FIB", "IP4",
237 "Flags", "Ethernet", "Interface");
239 fib = find_ip4_fib_by_table_index_or_id (&ip4_main, e->key.fib_index,
240 IP4_ROUTE_FLAG_FIB_INDEX);
241 si = vnet_get_sw_interface (vnm, e->key.sw_if_index);
243 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN)
244 flags = format (flags, "G");
246 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
247 flags = format (flags, "S");
249 s = format (s, "%=12U%=6u%=16U%=6s%=20U%=24U",
250 format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
252 format_ip4_address, &e->key.ip4_address,
253 flags ? (char *) flags : "",
254 format_ethernet_address, e->ethernet_address,
255 format_vnet_sw_interface_name, vnm, si);
264 } ethernet_arp_input_trace_t;
267 format_ethernet_arp_input_trace (u8 * s, va_list * va)
269 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
270 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
271 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
274 format_ethernet_arp_header,
275 t->packet_data, sizeof (t->packet_data));
281 format_arp_term_input_trace (u8 * s, va_list * va)
283 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
284 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
285 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
287 /* arp-term trace data saved is either arp or ip6/icmp6 packet:
288 - for arp, the 1st 16-bit field is hw type of value of 0x0001.
289 - for ip6, the first nibble has value of 6. */
290 s = format (s, "%U", t->packet_data[0] == 0 ?
291 format_ethernet_arp_header : format_ip6_header,
292 t->packet_data, sizeof (t->packet_data));
298 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
299 u32 sw_if_index, u32 flags)
301 ethernet_arp_main_t *am = ðernet_arp_main;
302 ethernet_arp_ip4_entry_t *e;
307 pool_foreach (e, am->ip4_entry_pool, ({
308 if (e->key.sw_if_index == sw_if_index)
309 vec_add1 (to_add_del, e - am->ip4_entry_pool);
313 for (i = 0; i < vec_len (to_add_del); i++)
315 ethernet_arp_ip4_over_ethernet_address_t arp_add;
316 e = pool_elt_at_index (am->ip4_entry_pool, to_add_del[i]);
318 clib_memcpy (&arp_add.ethernet, e->ethernet_address, 6);
319 arp_add.ip4.as_u32 = e->key.ip4_address.as_u32;
321 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
323 vnet_arp_set_ip4_over_ethernet (vnm,
325 e->key.fib_index, &arp_add,
327 ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC);
329 else if ((e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC) == 0)
331 vnet_arp_unset_ip4_over_ethernet (vnm,
333 e->key.fib_index, &arp_add);
337 vec_free (to_add_del);
341 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
344 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
347 void *a_arg, int is_static);
350 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
352 u32 fib_index, void *a_arg);
358 ethernet_arp_ip4_over_ethernet_address_t a;
360 int is_remove; /* set is_remove=1 to clear arp entry */
361 } vnet_arp_set_ip4_over_ethernet_rpc_args_t;
363 static void set_ip4_over_ethernet_rpc_callback
364 (vnet_arp_set_ip4_over_ethernet_rpc_args_t * a)
366 vnet_main_t *vm = vnet_get_main ();
367 ASSERT (os_get_cpu_number () == 0);
370 vnet_arp_unset_ip4_over_ethernet_internal (vm,
372 a->fib_index, &(a->a));
374 vnet_arp_set_ip4_over_ethernet_internal (vm,
377 &(a->a), a->is_static);
381 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
383 u32 fib_index, void *a_arg, int is_static)
385 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
386 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
388 args.sw_if_index = sw_if_index;
389 args.fib_index = fib_index;
390 args.is_static = is_static;
392 clib_memcpy (&args.a, a, sizeof (*a));
394 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
395 (u8 *) & args, sizeof (args));
400 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
403 void *a_arg, int is_static)
405 ethernet_arp_ip4_key_t k;
406 ethernet_arp_ip4_entry_t *e = 0;
407 ethernet_arp_main_t *am = ðernet_arp_main;
408 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
409 vlib_main_t *vm = vlib_get_main ();
410 ip4_main_t *im = &ip4_main;
411 ip_lookup_main_t *lm = &im->lookup_main;
412 int make_new_arp_cache_entry = 1;
414 ip4_add_del_route_args_t args;
415 ip_adjacency_t adj, *existing_adj;
416 pending_resolution_t *pr, *mc;
421 fib_index = (fib_index != (u32) ~ 0)
422 ? fib_index : im->fib_index_by_sw_if_index[sw_if_index];
424 k.sw_if_index = sw_if_index;
425 k.ip4_address = a->ip4;
426 k.fib_index = fib_index;
428 p = mhash_get (&am->ip4_entry_by_key, &k);
431 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
433 /* Refuse to over-write static arp. */
434 if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
436 make_new_arp_cache_entry = 0;
439 /* Note: always install the route. It might have been deleted */
440 memset (&adj, 0, sizeof (adj));
441 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
442 adj.n_adj = 1; /* otherwise signature compare fails */
444 vnet_rewrite_for_sw_interface (vnm, VNET_L3_PACKET_TYPE_IP4, sw_if_index, ip4_rewrite_node.index, a->ethernet, /* destination address */
446 sizeof (adj.rewrite_data));
448 /* result of this lookup should be next-hop adjacency */
449 adj_index = ip4_fib_lookup_with_table (im, fib_index, &a->ip4, 0);
450 existing_adj = ip_get_adjacency (lm, adj_index);
452 if (existing_adj->lookup_next_index == IP_LOOKUP_NEXT_ARP &&
453 existing_adj->arp.next_hop.ip4.as_u32 == a->ip4.as_u32)
456 u32 *adjs = vec_dup (e->adjacencies);
457 /* Update all adj assigned to this arp entry */
458 vec_foreach (ai, adjs)
461 ip_adjacency_t *uadj = ip_get_adjacency (lm, *ai);
462 for (i = 0; i < uadj->n_adj; i++)
463 if (uadj[i].lookup_next_index == IP_LOOKUP_NEXT_ARP &&
464 uadj[i].arp.next_hop.ip4.as_u32 == a->ip4.as_u32)
465 ip_update_adjacency (lm, *ai + i, &adj);
471 /* Check that new adjacency actually isn't exactly the same as
472 * what is already there. If we over-write the adjacency with
473 * exactly the same info, its technically a new adjacency with
474 * new counters, but to user it appears as counters reset.
476 if (vnet_ip_adjacency_share_compare (&adj, existing_adj) == 0)
479 args.table_index_or_table_id = fib_index;
481 IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD |
482 IP4_ROUTE_FLAG_NEIGHBOR;
483 args.dst_address = a->ip4;
484 args.dst_address_length = 32;
488 ip4_add_del_route (im, &args);
492 if (make_new_arp_cache_entry)
494 pool_get (am->ip4_entry_pool, e);
495 mhash_set (&am->ip4_entry_by_key, &k, e - am->ip4_entry_pool,
500 /* Update time stamp and ethernet address. */
501 clib_memcpy (e->ethernet_address, a->ethernet,
502 sizeof (e->ethernet_address));
503 e->cpu_time_last_updated = clib_cpu_time_now ();
505 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
507 /* Customer(s) waiting for this address to be resolved? */
508 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
513 while (next_index != (u32) ~ 0)
515 pr = pool_elt_at_index (am->pending_resolutions, next_index);
516 vlib_process_signal_event (vm, pr->node_index,
517 pr->type_opaque, pr->data);
518 next_index = pr->next_index;
519 pool_put (am->pending_resolutions, pr);
522 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
525 /* Customer(s) requesting ARP event for this address? */
526 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
531 while (next_index != (u32) ~ 0)
533 int (*fp) (u32, u8 *, u32, u32);
535 mc = pool_elt_at_index (am->mac_changes, next_index);
536 fp = mc->data_callback;
538 /* Call the user's data callback, return 1 to suppress dup events */
540 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
543 * Signal the resolver process, as long as the user
544 * says they want to be notified
547 vlib_process_signal_event (vm, mc->node_index,
548 mc->type_opaque, mc->data);
549 next_index = mc->next_index;
557 vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
560 uword type_opaque, uword data)
562 ethernet_arp_main_t *am = ðernet_arp_main;
563 ip4_address_t *address = address_arg;
565 pending_resolution_t *pr;
567 pool_get (am->pending_resolutions, pr);
570 pr->node_index = node_index;
571 pr->type_opaque = type_opaque;
573 pr->data_callback = 0;
575 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
578 /* Insert new resolution at the head of the list */
579 pr->next_index = p[0];
580 hash_unset (am->pending_resolutions_by_address, address->as_u32);
583 hash_set (am->pending_resolutions_by_address, address->as_u32,
584 pr - am->pending_resolutions);
588 vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
593 uword type_opaque, uword data, int is_add)
595 ethernet_arp_main_t *am = ðernet_arp_main;
596 ip4_address_t *address = address_arg;
598 pending_resolution_t *mc;
599 void (*fp) (u32, u8 *) = data_callback;
603 pool_get (am->mac_changes, mc);
606 mc->node_index = node_index;
607 mc->type_opaque = type_opaque;
609 mc->data_callback = data_callback;
612 p = hash_get (am->mac_changes_by_address, address->as_u32);
615 /* Insert new resolution at the head of the list */
616 mc->next_index = p[0];
617 hash_unset (am->mac_changes_by_address, address->as_u32);
620 hash_set (am->mac_changes_by_address, address->as_u32,
621 mc - am->mac_changes);
627 pending_resolution_t *mc_last = 0;
629 p = hash_get (am->mac_changes_by_address, address->as_u32);
631 return VNET_API_ERROR_NO_SUCH_ENTRY;
635 while (index != (u32) ~ 0)
637 mc = pool_elt_at_index (am->mac_changes, index);
638 if (mc->node_index == node_index &&
639 mc->type_opaque == type_opaque && mc->pid == pid)
641 /* Clients may need to clean up pool entries, too */
643 (*fp) (mc->data, 0 /* no new mac addrs */ );
646 hash_unset (am->mac_changes_by_address, address->as_u32);
647 if (mc->next_index != ~0)
648 hash_set (am->mac_changes_by_address, address->as_u32,
650 pool_put (am->mac_changes, mc);
656 mc_last->next_index = mc->next_index;
657 pool_put (am->mac_changes, mc);
662 index = mc->next_index;
665 return VNET_API_ERROR_NO_SUCH_ENTRY;
669 /* Either we drop the packet or we send a reply to the sender. */
673 ARP_INPUT_NEXT_REPLY_TX,
677 #define foreach_ethernet_arp_error \
678 _ (replies_sent, "ARP replies sent") \
679 _ (l2_type_not_ethernet, "L2 type not ethernet") \
680 _ (l3_type_not_ip4, "L3 type not IP4") \
681 _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
682 _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
683 _ (l3_src_address_is_local, "IP4 source address matches local interface") \
684 _ (l3_src_address_learned, "ARP request IP4 source address learned") \
685 _ (replies_received, "ARP replies received") \
686 _ (opcode_not_request, "ARP opcode not request") \
687 _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
688 _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
689 _ (missing_interface_address, "ARP missing interface address") \
690 _ (gratuitous_arp, "ARP probe or announcement dropped") \
694 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
695 foreach_ethernet_arp_error
697 ETHERNET_ARP_N_ERROR,
698 } ethernet_arp_input_error_t;
700 /* get first interface address */
702 ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
703 ip_interface_address_t ** result_ia)
705 ip_lookup_main_t *lm = &im->lookup_main;
706 ip_interface_address_t *ia = 0;
707 ip4_address_t *result = 0;
710 foreach_ip_interface_address (lm, ia, sw_if_index,
711 1 /* honor unnumbered */ ,
714 ip_interface_address_get_address (lm, ia);
720 *result_ia = result ? ia : 0;
725 unset_random_arp_entry (void)
727 ethernet_arp_main_t *am = ðernet_arp_main;
728 ethernet_arp_ip4_entry_t *e;
729 vnet_main_t *vnm = vnet_get_main ();
730 ethernet_arp_ip4_over_ethernet_address_t delme;
733 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
734 am->arp_delete_rotor = index;
736 /* Try again from elt 0, could happen if an intfc goes down */
739 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
740 am->arp_delete_rotor = index;
743 /* Nothing left in the pool */
747 e = pool_elt_at_index (am->ip4_entry_pool, index);
749 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
750 delme.ip4.as_u32 = e->key.ip4_address.as_u32;
752 vnet_arp_unset_ip4_over_ethernet (vnm, e->key.sw_if_index,
753 e->key.fib_index, &delme);
757 arp_unnumbered (vlib_buffer_t * p0,
759 ethernet_header_t * eth0, ip_interface_address_t * ifa0)
761 vlib_main_t *vm = vlib_get_main ();
762 vnet_main_t *vnm = vnet_get_main ();
763 vnet_interface_main_t *vim = &vnm->interface_main;
764 vnet_sw_interface_t *si;
765 vnet_hw_interface_t *hi;
766 u32 unnum_src_sw_if_index;
767 u32 *broadcast_swifs = 0;
772 u8 dst_mac_address[6];
774 ethernet_arp_header_t *arp0;
776 /* Save the dst mac address */
777 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
779 /* Figure out which sw_if_index supplied the address */
780 unnum_src_sw_if_index = ifa0->sw_if_index;
782 /* Track down all users of the unnumbered source */
784 pool_foreach (si, vim->sw_interfaces,
786 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
787 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
789 vec_add1 (broadcast_swifs, si->sw_if_index);
794 ASSERT (vec_len (broadcast_swifs));
796 /* Allocate buffering if we need it */
797 if (vec_len (broadcast_swifs) > 1)
799 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
800 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
801 _vec_len (buffers) = n_alloc;
802 for (i = 0; i < n_alloc; i++)
804 b0 = vlib_get_buffer (vm, buffers[i]);
806 /* xerox (partially built) ARP pkt */
807 clib_memcpy (b0->data, p0->data,
808 p0->current_length + p0->current_data);
809 b0->current_data = p0->current_data;
810 b0->current_length = p0->current_length;
811 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
812 vnet_buffer (p0)->sw_if_index[VLIB_RX];
816 vec_insert (buffers, 1, 0);
819 for (i = 0; i < vec_len (buffers); i++)
821 b0 = vlib_get_buffer (vm, buffers[i]);
822 arp0 = vlib_buffer_get_current (b0);
824 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
825 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
827 /* For decoration, most likely */
828 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
830 /* Fix ARP pkt src address */
831 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
833 /* Build L2 encaps for this swif */
834 header_size = sizeof (ethernet_header_t);
835 if (si->sub.eth.flags.one_tag)
837 else if (si->sub.eth.flags.two_tags)
840 vlib_buffer_advance (b0, -header_size);
841 eth0 = vlib_buffer_get_current (b0);
843 if (si->sub.eth.flags.one_tag)
845 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
847 eth0->type = si->sub.eth.flags.dot1ad ?
848 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
849 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
850 outer->priority_cfi_and_id =
851 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
852 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
855 else if (si->sub.eth.flags.two_tags)
857 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
858 ethernet_vlan_header_t *inner = (void *) (outer + 1);
860 eth0->type = si->sub.eth.flags.dot1ad ?
861 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
862 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
863 outer->priority_cfi_and_id =
864 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
865 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
866 inner->priority_cfi_and_id =
867 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
868 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
873 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
876 /* Restore the original dst address, set src address */
877 clib_memcpy (eth0->dst_address, dst_mac_address,
878 sizeof (eth0->dst_address));
879 clib_memcpy (eth0->src_address, hi->hw_address,
880 sizeof (eth0->src_address));
882 /* Transmit replicas */
886 vlib_get_frame_to_node (vm, hi->output_node_index);
887 u32 *to_next = vlib_frame_vector_args (f);
888 to_next[0] = buffers[i];
890 vlib_put_frame_to_node (vm, hi->output_node_index, f);
894 /* The regular path outputs the original pkt.. */
895 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
897 vec_free (broadcast_swifs);
902 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
904 ethernet_arp_main_t *am = ðernet_arp_main;
905 vnet_main_t *vnm = vnet_get_main ();
906 ip4_main_t *im4 = &ip4_main;
907 u32 n_left_from, next_index, *from, *to_next;
908 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
910 from = vlib_frame_vector_args (frame);
911 n_left_from = frame->n_vectors;
912 next_index = node->cached_next_index;
914 if (node->flags & VLIB_NODE_FLAG_TRACE)
915 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
917 sizeof (ethernet_arp_input_trace_t));
919 while (n_left_from > 0)
923 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
925 while (n_left_from > 0 && n_left_to_next > 0)
928 vnet_hw_interface_t *hw_if0;
929 ethernet_arp_header_t *arp0;
930 ethernet_header_t *eth0;
931 ip_interface_address_t *ifa0;
932 ip_adjacency_t *adj0;
933 ip4_address_t *if_addr0;
934 ip4_address_t proxy_src;
935 u32 pi0, error0, next0, sw_if_index0;
936 u8 is_request0, src_is_local0, dst_is_local0, is_unnum0;
937 ethernet_proxy_arp_t *pa;
946 p0 = vlib_get_buffer (vm, pi0);
947 arp0 = vlib_buffer_get_current (p0);
949 is_request0 = arp0->opcode
950 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
952 error0 = ETHERNET_ARP_ERROR_replies_sent;
956 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
957 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
960 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
961 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
963 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
968 /* Check that IP address is local and matches incoming interface. */
970 ip4_interface_address_matching_destination (im4,
972 ip4_over_ethernet[1].
977 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
981 /* Honor unnumbered interface, if any */
982 is_unnum0 = sw_if_index0 != ifa0->sw_if_index;
984 /* Source must also be local to subnet of matching interface address. */
985 if (!ip4_destination_matches_interface
986 (im4, &arp0->ip4_over_ethernet[0].ip4, ifa0))
988 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
992 /* Reject requests/replies with our local interface address. */
994 if_addr0->as_u32 == arp0->ip4_over_ethernet[0].ip4.as_u32;
997 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1002 if_addr0->as_u32 == arp0->ip4_over_ethernet[1].ip4.as_u32;
1004 /* Fill in ethernet header. */
1005 eth0 = ethernet_buffer_get_header (p0);
1007 /* Trash ARP packets whose ARP-level source addresses do not
1008 match their L2-frame-level source addresses */
1009 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1010 sizeof (eth0->src_address)))
1012 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1016 /* Learn or update sender's mapping only for requests or unicasts
1017 that don't match local interface address. */
1018 if (ethernet_address_cast (eth0->dst_address) ==
1019 ETHERNET_ADDRESS_UNICAST || is_request0)
1021 if (am->limit_arp_cache_size &&
1022 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1023 unset_random_arp_entry ();
1025 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
1026 (u32) ~ 0 /* default fib */ ,
1027 &arp0->ip4_over_ethernet[0],
1028 0 /* is_static */ );
1029 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1032 /* Only send a reply for requests sent which match a local interface. */
1033 if (!(is_request0 && dst_is_local0))
1037 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1038 ETHERNET_ARP_ERROR_replies_received : error0);
1044 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1045 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1047 /* Send reply back through input interface */
1048 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1049 next0 = ARP_INPUT_NEXT_REPLY_TX;
1051 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1053 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1055 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1056 hw_if0->hw_address, 6);
1057 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1060 /* Hardware must be ethernet-like. */
1061 ASSERT (vec_len (hw_if0->hw_address) == 6);
1063 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1064 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1066 /* Figure out how much to rewind current data from adjacency. */
1069 adj0 = ip_get_adjacency (&ip4_main.lookup_main,
1070 ifa0->neighbor_probe_adj_index);
1071 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP)
1073 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1077 arp_unnumbered (p0, pi0, eth0, ifa0);
1079 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1082 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1083 n_left_to_next, pi0, next0);
1085 n_replies_sent += 1;
1089 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1090 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1091 arp0->ip4_over_ethernet[1].ip4.as_u32))
1093 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1096 /* See if proxy arp is configured for the address */
1099 vnet_sw_interface_t *si;
1100 u32 this_addr = clib_net_to_host_u32
1101 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1104 si = vnet_get_sw_interface (vnm, sw_if_index0);
1106 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1109 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1112 vec_foreach (pa, am->proxy_arps)
1114 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1115 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1117 /* an ARP request hit in the proxy-arp table? */
1118 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1119 (fib_index0 == pa->fib_index))
1121 eth0 = ethernet_buffer_get_header (p0);
1123 arp0->ip4_over_ethernet[1].ip4.data_u32;
1126 * Rewind buffer, direct code above not to
1127 * think too hard about it.
1128 * $$$ is the answer ever anything other than
1129 * vlib_buffer_reset(..)?
1132 if_addr0 = &proxy_src;
1133 vlib_buffer_reset (p0);
1134 n_proxy_arp_replies_sent++;
1142 next0 = ARP_INPUT_NEXT_DROP;
1143 p0->error = node->errors[error0];
1145 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1146 n_left_to_next, pi0, next0);
1149 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1152 vlib_error_count (vm, node->node_index,
1153 ETHERNET_ARP_ERROR_replies_sent,
1154 n_replies_sent - n_proxy_arp_replies_sent);
1156 vlib_error_count (vm, node->node_index,
1157 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1158 n_proxy_arp_replies_sent);
1159 return frame->n_vectors;
1162 static char *ethernet_arp_error_strings[] = {
1163 #define _(sym,string) string,
1164 foreach_ethernet_arp_error
1169 VLIB_REGISTER_NODE (arp_input_node, static) =
1171 .function = arp_input,
1172 .name = "arp-input",
1173 .vector_size = sizeof (u32),
1174 .n_errors = ETHERNET_ARP_N_ERROR,
1175 .error_strings = ethernet_arp_error_strings,
1176 .n_next_nodes = ARP_INPUT_N_NEXT,
1178 [ARP_INPUT_NEXT_DROP] = "error-drop",
1179 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1181 .format_buffer = format_ethernet_arp_header,
1182 .format_trace = format_ethernet_arp_input_trace,
1187 ip4_arp_entry_sort (void *a1, void *a2)
1189 ethernet_arp_ip4_entry_t *e1 = a1;
1190 ethernet_arp_ip4_entry_t *e2 = a2;
1193 vnet_main_t *vnm = vnet_get_main ();
1195 cmp = vnet_sw_interface_compare
1196 (vnm, e1->key.sw_if_index, e2->key.sw_if_index);
1198 cmp = ip4_address_compare (&e1->key.ip4_address, &e2->key.ip4_address);
1202 static clib_error_t *
1203 show_ip4_arp (vlib_main_t * vm,
1204 unformat_input_t * input, vlib_cli_command_t * cmd)
1206 vnet_main_t *vnm = vnet_get_main ();
1207 ethernet_arp_main_t *am = ðernet_arp_main;
1208 ethernet_arp_ip4_entry_t *e, *es;
1209 ethernet_proxy_arp_t *pa;
1210 clib_error_t *error = 0;
1213 /* Filter entries by interface if given. */
1215 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1219 pool_foreach (e, am->ip4_entry_pool,
1221 vec_add1 (es, e[0]);
1227 vec_sort_with_function (es, ip4_arp_entry_sort);
1228 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1231 if (sw_if_index != ~0 && e->key.sw_if_index != sw_if_index)
1233 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1238 if (vec_len (am->proxy_arps))
1240 vlib_cli_output (vm, "Proxy arps enabled for:");
1241 vec_foreach (pa, am->proxy_arps)
1243 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1245 format_ip4_address, &pa->lo_addr,
1246 format_ip4_address, &pa->hi_addr);
1254 * Display all the IPv4 ARP entries.
1257 * Example of how to display the IPv4 ARP table:
1258 * @cliexstart{show ip arp}
1259 * Time FIB IP4 Flags Ethernet Interface
1260 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1261 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1262 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1263 * Proxy arps enabled for:
1264 * Fib_index 0 6.0.0.1 - 6.0.0.11
1268 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1269 .path = "show ip arp",
1270 .function = show_ip4_arp,
1271 .short_help = "show ip arp",
1277 pg_edit_t l2_type, l3_type;
1278 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1284 } ip4_over_ethernet[2];
1285 } pg_ethernet_arp_header_t;
1288 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1290 /* Initialize fields that are not bit fields in the IP header. */
1291 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1294 _(n_l2_address_bytes);
1295 _(n_l3_address_bytes);
1297 _(ip4_over_ethernet[0].ethernet);
1298 _(ip4_over_ethernet[0].ip4);
1299 _(ip4_over_ethernet[1].ethernet);
1300 _(ip4_over_ethernet[1].ip4);
1305 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1307 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1308 pg_ethernet_arp_header_t *p;
1311 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1313 pg_ethernet_arp_header_init (p);
1316 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1317 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1318 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1319 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1321 if (!unformat (input, "%U: %U/%U -> %U/%U",
1323 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1325 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1327 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1329 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1331 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1333 /* Free up any edits we may have added. */
1334 pg_free_edit_group (s);
1341 ip4_set_arp_limit (u32 arp_limit)
1343 ethernet_arp_main_t *am = ðernet_arp_main;
1345 am->limit_arp_cache_size = arp_limit;
1350 arp_ip4_entry_del_adj (ethernet_arp_ip4_entry_t * e, u32 adj_index)
1357 vec_foreach_index (i, e->adjacencies)
1358 if (vec_elt (e->adjacencies, i) == adj_index)
1360 vec_del1 (e->adjacencies, i);
1368 arp_ip4_entry_add_adj (ethernet_arp_ip4_entry_t * e, u32 adj_index)
1371 vec_foreach_index (i, e->adjacencies)
1372 if (vec_elt (e->adjacencies, i) == adj_index)
1374 vec_add1 (e->adjacencies, adj_index);
1378 arp_add_del_adj_cb (struct ip_lookup_main_t *lm,
1379 u32 adj_index, ip_adjacency_t * adj, u32 is_del)
1381 ethernet_arp_main_t *am = ðernet_arp_main;
1382 ip4_main_t *im = &ip4_main;
1383 ethernet_arp_ip4_key_t k;
1384 ethernet_arp_ip4_entry_t *e = 0;
1388 for (ai = adj->heap_handle; ai < adj->heap_handle + adj->n_adj; ai++)
1390 adj = ip_get_adjacency (lm, ai);
1391 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP
1392 && adj->arp.next_hop.ip4.as_u32)
1394 k.sw_if_index = adj->rewrite_header.sw_if_index;
1395 k.ip4_address.as_u32 = adj->arp.next_hop.ip4.as_u32;
1397 im->fib_index_by_sw_if_index[adj->rewrite_header.sw_if_index];
1398 p = mhash_get (&am->ip4_entry_by_key, &k);
1400 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
1408 clib_warning ("Adjacency contains unknown ARP next hop %U (del)",
1409 format_ip46_address, &adj->arp.next_hop,
1412 arp_ip4_entry_del_adj (e, adj->heap_handle);
1417 clib_warning ("Adjacency contains unknown ARP next hop %U (add)",
1418 format_ip46_address, &adj->arp.next_hop,
1421 arp_ip4_entry_add_adj (e, adj->heap_handle);
1426 static clib_error_t *
1427 ethernet_arp_init (vlib_main_t * vm)
1429 ethernet_arp_main_t *am = ðernet_arp_main;
1431 clib_error_t *error;
1432 ip4_main_t *im = &ip4_main;
1433 ip_lookup_main_t *lm = &im->lookup_main;
1435 if ((error = vlib_call_init_function (vm, ethernet_init)))
1438 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1440 pn = pg_get_node (arp_input_node.index);
1441 pn->unformat_edit = unformat_pg_arp_header;
1443 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1444 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1445 foreach_ethernet_arp_opcode;
1448 mhash_init (&am->ip4_entry_by_key,
1449 /* value size */ sizeof (uword),
1450 /* key size */ sizeof (ethernet_arp_ip4_key_t));
1452 /* $$$ configurable */
1453 am->limit_arp_cache_size = 50000;
1455 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1456 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1458 /* don't trace ARP error packets */
1460 vlib_node_runtime_t *rt =
1461 vlib_node_get_runtime (vm, arp_input_node.index);
1464 vnet_pcap_drop_trace_filter_add_del \
1465 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1467 foreach_ethernet_arp_error
1471 ip_register_add_del_adjacency_callback (lm, arp_add_del_adj_cb);
1476 VLIB_INIT_FUNCTION (ethernet_arp_init);
1479 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1480 u32 sw_if_index, u32 fib_index, void *a_arg)
1482 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1483 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1485 args.sw_if_index = sw_if_index;
1486 args.fib_index = fib_index;
1488 clib_memcpy (&args.a, a, sizeof (*a));
1490 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1491 (u8 *) & args, sizeof (args));
1496 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1498 u32 fib_index, void *a_arg)
1500 ethernet_arp_ip4_entry_t *e;
1501 ethernet_arp_main_t *am = ðernet_arp_main;
1502 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1503 ethernet_arp_ip4_key_t k;
1505 ip4_add_del_route_args_t args;
1506 ip4_main_t *im = &ip4_main;
1507 ip_lookup_main_t *lm = &im->lookup_main;
1509 ip_adjacency_t *adj;
1511 k.sw_if_index = sw_if_index;
1512 k.ip4_address = a->ip4;
1513 k.fib_index = fib_index;
1514 p = mhash_get (&am->ip4_entry_by_key, &k);
1518 memset (&args, 0, sizeof (args));
1521 * Make sure that the route actually exists before we try to delete it,
1522 * and make sure that it's a rewrite adjacency.
1524 * If we point 1-N unnumbered interfaces at a loopback interface and
1525 * shut down the loopback before shutting down 1-N unnumbered
1526 * interfaces, the ARP cache will still have an entry,
1527 * but the route will have disappeared.
1529 * See also ip4_del_interface_routes (...)
1530 * -> ip4_delete_matching_routes (...).
1533 adj_index = ip4_fib_lookup_with_table
1534 (im, fib_index, &a->ip4, 1 /* disable default route */ );
1536 /* Miss adj? Forget it... */
1537 if (adj_index != lm->miss_adj_index)
1539 adj = ip_get_adjacency (lm, adj_index);
1541 * Stupid control-plane trick:
1542 * admin down an interface (removes arp routes from fib),
1543 * bring the interface back up (does not reinstall them)
1544 * then remove the arp cache entry (yuck). When that happens,
1545 * the adj we find here will be the interface subnet ARP adj.
1547 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1549 args.table_index_or_table_id = fib_index;
1550 args.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL
1551 | IP4_ROUTE_FLAG_NEIGHBOR;
1552 args.dst_address = a->ip4;
1553 args.dst_address_length = 32;
1554 ip4_add_del_route (im, &args);
1555 ip4_maybe_remap_adjacencies (im, fib_index, args.flags);
1559 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
1560 mhash_unset (&am->ip4_entry_by_key, &e->key, 0);
1561 pool_put (am->ip4_entry_pool, e);
1566 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1571 for (i = 3; i >= 0; i--)
1573 old = a->ip4.as_u8[i];
1574 a->ip4.as_u8[i] += 1;
1575 if (old < a->ip4.as_u8[i])
1579 for (i = 5; i >= 0; i--)
1581 old = a->ethernet[i];
1582 a->ethernet[i] += 1;
1583 if (old < a->ethernet[i])
1589 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1590 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1592 ethernet_arp_main_t *am = ðernet_arp_main;
1593 ethernet_proxy_arp_t *pa;
1594 u32 found_at_index = ~0;
1596 vec_foreach (pa, am->proxy_arps)
1598 if (pa->lo_addr == lo_addr->as_u32
1599 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1601 found_at_index = pa - am->proxy_arps;
1606 if (found_at_index != ~0)
1608 /* Delete, otherwise it's already in the table */
1610 vec_delete (am->proxy_arps, 1, found_at_index);
1613 /* delete, no such entry */
1615 return VNET_API_ERROR_NO_SUCH_ENTRY;
1617 /* add, not in table */
1618 vec_add2 (am->proxy_arps, pa, 1);
1619 pa->lo_addr = lo_addr->as_u32;
1620 pa->hi_addr = hi_addr->as_u32;
1621 pa->fib_index = fib_index;
1626 * Remove any proxy arp entries asdociated with the
1630 vnet_proxy_arp_fib_reset (u32 fib_id)
1632 ip4_main_t *im = &ip4_main;
1633 ethernet_arp_main_t *am = ðernet_arp_main;
1634 ethernet_proxy_arp_t *pa;
1635 u32 *entries_to_delete = 0;
1640 p = hash_get (im->fib_index_by_table_id, fib_id);
1642 return VNET_API_ERROR_NO_SUCH_ENTRY;
1645 vec_foreach (pa, am->proxy_arps)
1647 if (pa->fib_index == fib_index)
1649 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1653 for (i = 0; i < vec_len (entries_to_delete); i++)
1655 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1658 vec_free (entries_to_delete);
1664 vnet_arp_glean_add (u32 fib_index, void *next_hop_arg)
1666 ethernet_arp_main_t *am = ðernet_arp_main;
1667 ip4_main_t *im = &ip4_main;
1668 ip_lookup_main_t *lm = &im->lookup_main;
1669 ip4_address_t *next_hop = next_hop_arg;
1670 ip_adjacency_t add_adj, *adj;
1671 ip4_add_del_route_args_t args;
1672 ethernet_arp_ip4_entry_t *e;
1673 ethernet_arp_ip4_key_t k;
1676 adj_index = ip4_fib_lookup_with_table (im, fib_index, next_hop, 0);
1677 adj = ip_get_adjacency (lm, adj_index);
1679 if (!adj || adj->lookup_next_index != IP_LOOKUP_NEXT_ARP)
1682 if (adj->arp.next_hop.ip4.as_u32 != 0)
1685 k.sw_if_index = adj->rewrite_header.sw_if_index;
1686 k.fib_index = fib_index;
1687 k.ip4_address.as_u32 = next_hop->as_u32;
1689 if (mhash_get (&am->ip4_entry_by_key, &k))
1692 pool_get (am->ip4_entry_pool, e);
1693 mhash_set (&am->ip4_entry_by_key, &k, e - am->ip4_entry_pool,
1696 e->cpu_time_last_updated = clib_cpu_time_now ();
1697 e->flags = ETHERNET_ARP_IP4_ENTRY_FLAG_GLEAN;
1699 memset (&args, 0, sizeof (args));
1700 clib_memcpy (&add_adj, adj, sizeof (add_adj));
1701 ip46_address_set_ip4 (&add_adj.arp.next_hop, next_hop); /* install neighbor /32 route */
1702 args.table_index_or_table_id = fib_index;
1704 IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_ADD | IP4_ROUTE_FLAG_NEIGHBOR;
1705 args.dst_address.as_u32 = next_hop->as_u32;
1706 args.dst_address_length = 32;
1707 args.adj_index = ~0;
1708 args.add_adj = &add_adj;
1710 ip4_add_del_route (im, &args);
1711 return ip4_fib_lookup_with_table (im, fib_index, next_hop, 0);
1714 static clib_error_t *
1715 ip_arp_add_del_command_fn (vlib_main_t * vm,
1716 unformat_input_t * input, vlib_cli_command_t * cmd)
1718 vnet_main_t *vnm = vnet_get_main ();
1720 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1729 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1731 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1732 if (unformat (input, "%U %U %U",
1733 unformat_vnet_sw_interface, vnm, &sw_if_index,
1734 unformat_ip4_address, &addr.ip4,
1735 unformat_ethernet_address, &addr.ethernet))
1738 else if (unformat (input, "delete") || unformat (input, "del"))
1741 else if (unformat (input, "static"))
1744 else if (unformat (input, "count %d", &count))
1747 else if (unformat (input, "fib-id %d", &fib_id))
1749 ip4_main_t *im = &ip4_main;
1750 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1752 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1756 else if (unformat (input, "proxy %U - %U",
1757 unformat_ip4_address, &lo_addr.ip4,
1758 unformat_ip4_address, &hi_addr.ip4))
1766 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1775 for (i = 0; i < count; i++)
1779 uword event_type, *event_data = 0;
1781 /* Park the debug CLI until the arp entry is installed */
1782 vnet_register_ip4_arp_resolution_event
1783 (vnm, &addr.ip4, vlib_current_process (vm),
1784 1 /* type */ , 0 /* data */ );
1786 vnet_arp_set_ip4_over_ethernet
1787 (vnm, sw_if_index, fib_index, &addr, is_static);
1789 vlib_process_wait_for_event (vm);
1790 event_type = vlib_process_get_events (vm, &event_data);
1791 vec_reset_length (event_data);
1792 if (event_type != 1)
1793 clib_warning ("event type %d unexpected", event_type);
1796 vnet_arp_unset_ip4_over_ethernet
1797 (vnm, sw_if_index, fib_index, &addr);
1799 increment_ip4_and_mac_address (&addr);
1804 return clib_error_return (0, "unknown input `%U'",
1805 format_unformat_error, input);
1813 * Add or delete IPv4 ARP cache entries.
1815 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
1816 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
1817 * any order and combination.
1821 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
1822 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
1823 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1824 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
1826 * To add or delete an IPv4 ARP cache entry to or from a specific fib
1828 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1829 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1831 * Add or delete IPv4 static ARP cache entries as follows:
1832 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1833 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1835 * For testing / debugging purposes, the 'set ip arp' command can add or
1836 * delete multiple entries. Supply the 'count N' parameter:
1837 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1841 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
1842 .path = "set ip arp",
1844 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
1845 .function = ip_arp_add_del_command_fn,
1849 static clib_error_t *
1850 set_int_proxy_arp_command_fn (vlib_main_t * vm,
1851 unformat_input_t * input,
1852 vlib_cli_command_t * cmd)
1854 vnet_main_t *vnm = vnet_get_main ();
1856 vnet_sw_interface_t *si;
1860 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1862 if (unformat (input, "%U", unformat_vnet_sw_interface,
1865 else if (unformat (input, "enable") || unformat (input, "on"))
1867 else if (unformat (input, "disable") || unformat (input, "off"))
1874 return clib_error_return (0, "unknown input '%U'",
1875 format_unformat_error, input);
1877 si = vnet_get_sw_interface (vnm, sw_if_index);
1880 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
1882 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
1889 * Enable proxy-arp on an interface. The vpp stack will answer ARP
1890 * requests for the indicated address range. Multiple proxy-arp
1891 * ranges may be provisioned.
1893 * @note Proxy ARP as a technology is infamous for blackholing traffic.
1894 * Also, the underlying implementation has not been performance-tuned.
1895 * Avoid creating an unnecessarily large set of ranges.
1898 * To enable proxy arp on a range of addresses, use:
1899 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
1900 * Append 'del' to delete a range of proxy ARP addresses:
1901 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
1902 * You must then specifically enable proxy arp on individual interfaces:
1903 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
1904 * To disable proxy arp on an individual interface:
1905 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
1908 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
1909 .path = "set interface proxy-arp",
1911 "set interface proxy-arp <intfc> [enable|disable]",
1912 .function = set_int_proxy_arp_command_fn,
1918 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
1919 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
1923 ARP_TERM_NEXT_L2_OUTPUT,
1928 u32 arp_term_next_node_index[32];
1931 arp_term_l2bd (vlib_main_t * vm,
1932 vlib_node_runtime_t * node, vlib_frame_t * frame)
1934 l2input_main_t *l2im = &l2input_main;
1935 u32 n_left_from, next_index, *from, *to_next;
1936 u32 n_replies_sent = 0;
1937 u16 last_bd_index = ~0;
1938 l2_bridge_domain_t *last_bd_config = 0;
1939 l2_input_config_t *cfg0;
1941 from = vlib_frame_vector_args (frame);
1942 n_left_from = frame->n_vectors;
1943 next_index = node->cached_next_index;
1945 while (n_left_from > 0)
1949 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1951 while (n_left_from > 0 && n_left_to_next > 0)
1954 ethernet_header_t *eth0;
1955 ethernet_arp_header_t *arp0;
1958 u32 pi0, error0, next0, sw_if_index0;
1969 n_left_to_next -= 1;
1971 p0 = vlib_get_buffer (vm, pi0);
1972 eth0 = vlib_buffer_get_current (p0);
1973 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
1974 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
1975 arp0 = (ethernet_arp_header_t *) l3h0;
1977 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
1979 clib_host_to_net_u16
1980 (ETHERNET_ARP_OPCODE_request))))
1983 /* Must be ARP request packet here */
1984 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
1985 (p0->flags & VLIB_BUFFER_IS_TRACED)))
1987 u8 *t0 = vlib_add_trace (vm, node, p0,
1988 sizeof (ethernet_arp_input_trace_t));
1989 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
1992 error0 = ETHERNET_ARP_ERROR_replies_sent;
1995 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1996 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1999 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2000 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2002 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2007 /* Trash ARP packets whose ARP-level source addresses do not
2008 match their L2-frame-level source addresses */
2011 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2012 sizeof (eth0->src_address))))
2014 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2018 /* Check if anyone want ARP request events for L2 BDs */
2020 pending_resolution_t *mc;
2021 ethernet_arp_main_t *am = ðernet_arp_main;
2022 uword *p = hash_get (am->mac_changes_by_address, 0);
2023 if (p && (vnet_buffer (p0)->l2.shg == 0))
2024 { // Only SHG 0 interface which is more likely local
2025 u32 next_index = p[0];
2026 while (next_index != (u32) ~ 0)
2028 int (*fp) (u32, u8 *, u32, u32);
2030 mc = pool_elt_at_index (am->mac_changes, next_index);
2031 fp = mc->data_callback;
2032 /* Call the callback, return 1 to suppress dup events */
2034 rv = (*fp) (mc->data,
2035 arp0->ip4_over_ethernet[0].ethernet,
2037 arp0->ip4_over_ethernet[0].ip4.as_u32);
2038 /* Signal the resolver process */
2040 vlib_process_signal_event (vm, mc->node_index,
2041 mc->type_opaque, mc->data);
2042 next_index = mc->next_index;
2047 /* lookup BD mac_by_ip4 hash table for MAC entry */
2048 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2049 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2050 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2051 || (last_bd_index == (u16) ~ 0)))
2053 last_bd_index = bd_index0;
2054 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2056 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2058 if (PREDICT_FALSE (!macp0))
2059 goto next_l2_feature; /* MAC not found */
2061 /* MAC found, send ARP reply -
2062 Convert ARP request packet to ARP reply */
2063 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2064 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2065 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2066 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2067 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2068 clib_memcpy (eth0->src_address, macp0, 6);
2069 n_replies_sent += 1;
2072 /* For BVI, need to use l2-fwd node to send ARP reply as
2073 l2-output node cannot output packet to BVI properly */
2074 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2075 if (PREDICT_FALSE (cfg0->bvi))
2077 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2078 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2079 goto next_l2_feature;
2082 /* Send ARP/ND reply back out input interface through l2-output */
2083 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2084 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2085 /* Note that output to VXLAN tunnel will fail due to SHG which
2086 is probably desireable since ARP termination is not intended
2087 for ARP requests from other hosts. If output to VXLAN tunnel is
2088 required, however, can just clear the SHG in packet as follows:
2089 vnet_buffer(p0)->l2.shg = 0; */
2090 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2091 n_left_to_next, pi0, next0);
2095 /* IP6 ND event notification or solicitation handling to generate
2096 local response instead of flooding */
2097 iph0 = (ip6_header_t *) l3h0;
2098 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2099 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2100 !ip6_address_is_link_local_unicast
2101 (&iph0->src_address)
2103 !ip6_address_is_unspecified
2104 (&iph0->src_address)))
2106 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2107 if (vnet_ip6_nd_term (vm, node, p0, eth0, iph0, sw_if_index0,
2108 vnet_buffer (p0)->l2.bd_index,
2109 vnet_buffer (p0)->l2.shg))
2110 goto output_response;
2115 u32 feature_bitmap0 =
2116 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2117 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2118 next0 = feat_bitmap_get_next_node_index (arp_term_next_node_index,
2120 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2121 n_left_to_next, pi0, next0);
2126 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2127 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2128 arp0->ip4_over_ethernet[1].ip4.as_u32))
2130 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2132 next0 = ARP_TERM_NEXT_DROP;
2133 p0->error = node->errors[error0];
2135 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2136 n_left_to_next, pi0, next0);
2139 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2142 vlib_error_count (vm, node->node_index,
2143 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2144 return frame->n_vectors;
2148 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2149 .function = arp_term_l2bd,
2150 .name = "arp-term-l2bd",
2151 .vector_size = sizeof (u32),
2152 .n_errors = ETHERNET_ARP_N_ERROR,
2153 .error_strings = ethernet_arp_error_strings,
2154 .n_next_nodes = ARP_TERM_N_NEXT,
2156 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2157 [ARP_TERM_NEXT_DROP] = "error-drop",
2159 .format_buffer = format_ethernet_arp_header,
2160 .format_trace = format_arp_term_input_trace,
2165 arp_term_init (vlib_main_t * vm)
2166 { // Initialize the feature next-node indexes
2167 feat_bitmap_init_next_nodes (vm,
2168 arp_term_l2bd_node.index,
2170 l2input_get_feat_names (),
2171 arp_term_next_node_index);
2175 VLIB_INIT_FUNCTION (arp_term_init);
2178 * fd.io coding-style-patch-verification: ON
2181 * eval: (c-set-style "gnu")