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/mpls/mpls.h>
32 * This file contains code to manage the IPv4 ARP tables (IP Address
33 * to MAC Address lookup).
37 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
40 * @brief Per-interface ARP configuration and state
42 typedef struct ethernet_arp_interface_t_
45 * Hash table of ARP entries.
46 * Since this hash table is per-interface, the key is only the IPv4 address.
49 } ethernet_arp_interface_t;
56 } ethernet_proxy_arp_t;
64 /* Used for arp event notification only */
67 } pending_resolution_t;
71 /* Hash tables mapping name to opcode. */
72 uword *opcode_by_name;
74 /* lite beer "glean" adjacency handling */
75 uword *pending_resolutions_by_address;
76 pending_resolution_t *pending_resolutions;
78 /* Mac address change notification */
79 uword *mac_changes_by_address;
80 pending_resolution_t *mac_changes;
82 ethernet_arp_ip4_entry_t *ip4_entry_pool;
84 /* ARP attack mitigation */
86 u32 limit_arp_cache_size;
88 /** Per interface state */
89 ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
91 /* Proxy arp vector */
92 ethernet_proxy_arp_t *proxy_arps;
93 } ethernet_arp_main_t;
95 static ethernet_arp_main_t ethernet_arp_main;
100 ethernet_arp_ip4_over_ethernet_address_t a;
103 #define ETHERNET_ARP_ARGS_REMOVE (1<<0)
104 #define ETHERNET_ARP_ARGS_FLUSH (1<<1)
105 #define ETHERNET_ARP_ARGS_POPULATE (1<<2)
106 } vnet_arp_set_ip4_over_ethernet_rpc_args_t;
109 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
113 format_ethernet_arp_hardware_type (u8 * s, va_list * va)
115 ethernet_arp_hardware_type_t h = va_arg (*va, ethernet_arp_hardware_type_t);
119 #define _(n,f) case n: t = #f; break;
120 foreach_ethernet_arp_hardware_type;
124 return format (s, "unknown 0x%x", h);
127 return format (s, "%s", t);
131 format_ethernet_arp_opcode (u8 * s, va_list * va)
133 ethernet_arp_opcode_t o = va_arg (*va, ethernet_arp_opcode_t);
137 #define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
138 foreach_ethernet_arp_opcode;
142 return format (s, "unknown 0x%x", o);
145 return format (s, "%s", t);
149 unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
152 int *result = va_arg (*args, int *);
153 ethernet_arp_main_t *am = ðernet_arp_main;
156 /* Numeric opcode. */
157 if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
166 if (unformat_user (input, unformat_vlib_number_by_name,
167 am->opcode_by_name, &i))
177 unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
180 int *result = va_arg (*args, int *);
182 (input, unformat_ethernet_arp_opcode_host_byte_order, result))
185 *result = clib_host_to_net_u16 ((u16) * result);
190 format_ethernet_arp_header (u8 * s, va_list * va)
192 ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
193 u32 max_header_bytes = va_arg (*va, u32);
195 u16 l2_type, l3_type;
197 if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
198 return format (s, "ARP header truncated");
200 l2_type = clib_net_to_host_u16 (a->l2_type);
201 l3_type = clib_net_to_host_u16 (a->l3_type);
203 indent = format_get_indent (s);
205 s = format (s, "%U, type %U/%U, address size %d/%d",
206 format_ethernet_arp_opcode, clib_net_to_host_u16 (a->opcode),
207 format_ethernet_arp_hardware_type, l2_type,
208 format_ethernet_type, l3_type,
209 a->n_l2_address_bytes, a->n_l3_address_bytes);
211 if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
212 && l3_type == ETHERNET_TYPE_IP4)
214 s = format (s, "\n%U%U/%U -> %U/%U",
215 format_white_space, indent,
216 format_ethernet_address, a->ip4_over_ethernet[0].ethernet,
217 format_ip4_address, &a->ip4_over_ethernet[0].ip4,
218 format_ethernet_address, a->ip4_over_ethernet[1].ethernet,
219 format_ip4_address, &a->ip4_over_ethernet[1].ip4);
223 uword n2 = a->n_l2_address_bytes;
224 uword n3 = a->n_l3_address_bytes;
225 s = format (s, "\n%U%U/%U -> %U/%U",
226 format_white_space, indent,
227 format_hex_bytes, a->data + 0 * n2 + 0 * n3, n2,
228 format_hex_bytes, a->data + 1 * n2 + 0 * n3, n3,
229 format_hex_bytes, a->data + 1 * n2 + 1 * n3, n2,
230 format_hex_bytes, a->data + 2 * n2 + 1 * n3, n3);
237 format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
239 vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
240 ethernet_arp_ip4_entry_t *e = va_arg (*va, ethernet_arp_ip4_entry_t *);
241 vnet_sw_interface_t *si;
245 return format (s, "%=12s%=16s%=6s%=20s%=24s", "Time", "IP4",
246 "Flags", "Ethernet", "Interface");
248 si = vnet_get_sw_interface (vnm, e->sw_if_index);
250 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
251 flags = format (flags, "S");
253 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
254 flags = format (flags, "D");
256 s = format (s, "%=12U%=16U%=6s%=20U%=24U",
257 format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
258 format_ip4_address, &e->ip4_address,
259 flags ? (char *) flags : "",
260 format_ethernet_address, e->ethernet_address,
261 format_vnet_sw_interface_name, vnm, si);
270 } ethernet_arp_input_trace_t;
273 format_ethernet_arp_input_trace (u8 * s, va_list * va)
275 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
276 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
277 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
280 format_ethernet_arp_header,
281 t->packet_data, sizeof (t->packet_data));
287 format_arp_term_input_trace (u8 * s, va_list * va)
289 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
290 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
291 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
293 /* arp-term trace data saved is either arp or ip6/icmp6 packet:
294 - for arp, the 1st 16-bit field is hw type of value of 0x0001.
295 - for ip6, the first nibble has value of 6. */
296 s = format (s, "%U", t->packet_data[0] == 0 ?
297 format_ethernet_arp_header : format_ip6_header,
298 t->packet_data, sizeof (t->packet_data));
304 arp_nbr_probe (ip_adjacency_t * adj)
306 vnet_main_t *vnm = vnet_get_main ();
307 ip4_main_t *im = &ip4_main;
308 ip_interface_address_t *ia;
309 ethernet_arp_header_t *h;
310 vnet_hw_interface_t *hi;
311 vnet_sw_interface_t *si;
317 vm = vlib_get_main ();
319 si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
321 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
327 ip4_interface_address_matching_destination (im,
328 &adj->sub_type.nbr.next_hop.
338 vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template,
341 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
343 clib_memcpy (h->ip4_over_ethernet[0].ethernet,
344 hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
346 h->ip4_over_ethernet[0].ip4 = src[0];
347 h->ip4_over_ethernet[1].ip4 = adj->sub_type.nbr.next_hop.ip4;
349 b = vlib_get_buffer (vm, bi);
350 vnet_buffer (b)->sw_if_index[VLIB_RX] =
351 vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
353 /* Add encapsulation string for software interface (e.g. ethernet header). */
354 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
355 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
358 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
359 u32 *to_next = vlib_frame_vector_args (f);
362 vlib_put_frame_to_node (vm, hi->output_node_index, f);
367 arp_mk_complete (adj_index_t ai, ethernet_arp_ip4_entry_t * e)
369 adj_nbr_update_rewrite
370 (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
371 ethernet_build_rewrite (vnet_get_main (),
373 adj_get_link_type (ai), e->ethernet_address));
377 arp_mk_incomplete (adj_index_t ai)
379 ip_adjacency_t *adj = adj_get (ai);
381 adj_nbr_update_rewrite
383 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
384 ethernet_build_rewrite (vnet_get_main (),
385 adj->rewrite_header.sw_if_index,
387 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
390 static ethernet_arp_ip4_entry_t *
391 arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
393 ethernet_arp_main_t *am = ðernet_arp_main;
394 ethernet_arp_ip4_entry_t *e = NULL;
397 if (NULL != eai->arp_entries)
399 p = hash_get (eai->arp_entries, addr->as_u32);
403 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
410 arp_mk_complete_walk (adj_index_t ai, void *ctx)
412 ethernet_arp_ip4_entry_t *e = ctx;
414 arp_mk_complete (ai, e);
416 return (ADJ_WALK_RC_CONTINUE);
420 arp_mk_incomplete_walk (adj_index_t ai, void *ctx)
422 arp_mk_incomplete (ai);
424 return (ADJ_WALK_RC_CONTINUE);
428 arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
430 ethernet_arp_main_t *am = ðernet_arp_main;
431 ethernet_arp_interface_t *arp_int;
432 ethernet_arp_ip4_entry_t *e;
437 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
438 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
439 e = arp_entry_find (arp_int, &adj->sub_type.nbr.next_hop.ip4);
443 adj_nbr_walk_nh4 (sw_if_index,
444 &e->ip4_address, arp_mk_complete_walk, e);
449 * no matching ARP entry.
450 * construct the rewire required to for an ARP packet, and stick
451 * that in the adj's pipe to smoke.
453 adj_nbr_update_rewrite (ai,
454 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
455 ethernet_build_rewrite (vnm,
458 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
461 * since the FIB has added this adj for a route, it makes sense it may
462 * want to forward traffic sometime soon. Let's send a speculative ARP.
463 * just one. If we were to do periodically that wouldn't be bad either,
464 * but that's more code than i'm prepared to write at this time for
465 * relatively little reward.
472 vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
473 vnet_arp_set_ip4_over_ethernet_rpc_args_t
476 ethernet_arp_ip4_entry_t *e = 0;
477 ethernet_arp_main_t *am = ðernet_arp_main;
478 ethernet_arp_ip4_over_ethernet_address_t *a = &args->a;
479 vlib_main_t *vm = vlib_get_main ();
480 int make_new_arp_cache_entry = 1;
482 pending_resolution_t *pr, *mc;
483 ethernet_arp_interface_t *arp_int;
484 int is_static = args->is_static;
485 u32 sw_if_index = args->sw_if_index;
487 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
489 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
491 if (NULL != arp_int->arp_entries)
493 p = hash_get (arp_int->arp_entries, a->ip4.as_u32);
496 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
498 /* Refuse to over-write static arp. */
499 if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
501 make_new_arp_cache_entry = 0;
505 if (make_new_arp_cache_entry)
509 .fp_proto = FIB_PROTOCOL_IP4,
517 pool_get (am->ip4_entry_pool, e);
519 if (NULL == arp_int->arp_entries)
521 arp_int->arp_entries = hash_create (0, sizeof (u32));
524 hash_set (arp_int->arp_entries, a->ip4.as_u32, e - am->ip4_entry_pool);
526 e->sw_if_index = sw_if_index;
527 e->ip4_address = a->ip4;
528 clib_memcpy (e->ethernet_address,
529 a->ethernet, sizeof (e->ethernet_address));
531 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
533 fib_table_entry_update_one_path (fib_index,
536 FIB_ENTRY_FLAG_ATTACHED,
541 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
546 * prevent a DoS attack from the data-plane that
547 * spams us with no-op updates to the MAC address
549 if (0 == memcmp (e->ethernet_address,
550 a->ethernet, sizeof (e->ethernet_address)))
553 /* Update time stamp and ethernet address. */
554 clib_memcpy (e->ethernet_address, a->ethernet,
555 sizeof (e->ethernet_address));
558 e->cpu_time_last_updated = clib_cpu_time_now ();
560 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
562 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC;
564 adj_nbr_walk_nh4 (sw_if_index, &e->ip4_address, arp_mk_complete_walk, e);
566 /* Customer(s) waiting for this address to be resolved? */
567 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
573 while (next_index != (u32) ~ 0)
575 pr = pool_elt_at_index (am->pending_resolutions, next_index);
576 vlib_process_signal_event (vm, pr->node_index,
577 pr->type_opaque, pr->data);
578 next_index = pr->next_index;
579 pool_put (am->pending_resolutions, pr);
582 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
585 /* Customer(s) requesting ARP event for this address? */
586 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
592 while (next_index != (u32) ~ 0)
594 int (*fp) (u32, u8 *, u32, u32);
596 mc = pool_elt_at_index (am->mac_changes, next_index);
597 fp = mc->data_callback;
599 /* Call the user's data callback, return 1 to suppress dup events */
601 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
604 * Signal the resolver process, as long as the user
605 * says they want to be notified
608 vlib_process_signal_event (vm, mc->node_index,
609 mc->type_opaque, mc->data);
610 next_index = mc->next_index;
618 vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
621 uword type_opaque, uword data)
623 ethernet_arp_main_t *am = ðernet_arp_main;
624 ip4_address_t *address = address_arg;
626 pending_resolution_t *pr;
628 pool_get (am->pending_resolutions, pr);
631 pr->node_index = node_index;
632 pr->type_opaque = type_opaque;
634 pr->data_callback = 0;
636 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
639 /* Insert new resolution at the head of the list */
640 pr->next_index = p[0];
641 hash_unset (am->pending_resolutions_by_address, address->as_u32);
644 hash_set (am->pending_resolutions_by_address, address->as_u32,
645 pr - am->pending_resolutions);
649 vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
654 uword type_opaque, uword data, int is_add)
656 ethernet_arp_main_t *am = ðernet_arp_main;
657 ip4_address_t *address = address_arg;
659 pending_resolution_t *mc;
660 void (*fp) (u32, u8 *) = data_callback;
664 pool_get (am->mac_changes, mc);
667 mc->node_index = node_index;
668 mc->type_opaque = type_opaque;
670 mc->data_callback = data_callback;
673 p = hash_get (am->mac_changes_by_address, address->as_u32);
676 /* Insert new resolution at the head of the list */
677 mc->next_index = p[0];
678 hash_unset (am->mac_changes_by_address, address->as_u32);
681 hash_set (am->mac_changes_by_address, address->as_u32,
682 mc - am->mac_changes);
688 pending_resolution_t *mc_last = 0;
690 p = hash_get (am->mac_changes_by_address, address->as_u32);
692 return VNET_API_ERROR_NO_SUCH_ENTRY;
696 while (index != (u32) ~ 0)
698 mc = pool_elt_at_index (am->mac_changes, index);
699 if (mc->node_index == node_index &&
700 mc->type_opaque == type_opaque && mc->pid == pid)
702 /* Clients may need to clean up pool entries, too */
704 (*fp) (mc->data, 0 /* no new mac addrs */ );
707 hash_unset (am->mac_changes_by_address, address->as_u32);
708 if (mc->next_index != ~0)
709 hash_set (am->mac_changes_by_address, address->as_u32,
711 pool_put (am->mac_changes, mc);
717 mc_last->next_index = mc->next_index;
718 pool_put (am->mac_changes, mc);
723 index = mc->next_index;
726 return VNET_API_ERROR_NO_SUCH_ENTRY;
730 /* Either we drop the packet or we send a reply to the sender. */
734 ARP_INPUT_NEXT_REPLY_TX,
738 #define foreach_ethernet_arp_error \
739 _ (replies_sent, "ARP replies sent") \
740 _ (l2_type_not_ethernet, "L2 type not ethernet") \
741 _ (l3_type_not_ip4, "L3 type not IP4") \
742 _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
743 _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
744 _ (l3_src_address_is_local, "IP4 source address matches local interface") \
745 _ (l3_src_address_learned, "ARP request IP4 source address learned") \
746 _ (replies_received, "ARP replies received") \
747 _ (opcode_not_request, "ARP opcode not request") \
748 _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
749 _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
750 _ (missing_interface_address, "ARP missing interface address") \
751 _ (gratuitous_arp, "ARP probe or announcement dropped") \
752 _ (interface_no_table, "Interface is not mapped to an IP table") \
756 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
757 foreach_ethernet_arp_error
759 ETHERNET_ARP_N_ERROR,
760 } ethernet_arp_input_error_t;
764 unset_random_arp_entry (void)
766 ethernet_arp_main_t *am = ðernet_arp_main;
767 ethernet_arp_ip4_entry_t *e;
768 vnet_main_t *vnm = vnet_get_main ();
769 ethernet_arp_ip4_over_ethernet_address_t delme;
772 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
773 am->arp_delete_rotor = index;
775 /* Try again from elt 0, could happen if an intfc goes down */
778 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
779 am->arp_delete_rotor = index;
782 /* Nothing left in the pool */
786 e = pool_elt_at_index (am->ip4_entry_pool, index);
788 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
789 delme.ip4.as_u32 = e->ip4_address.as_u32;
791 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
795 arp_unnumbered (vlib_buffer_t * p0,
796 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
798 vlib_main_t *vm = vlib_get_main ();
799 vnet_main_t *vnm = vnet_get_main ();
800 vnet_interface_main_t *vim = &vnm->interface_main;
801 vnet_sw_interface_t *si;
802 vnet_hw_interface_t *hi;
803 u32 unnum_src_sw_if_index;
804 u32 *broadcast_swifs = 0;
809 u8 dst_mac_address[6];
811 ethernet_arp_header_t *arp0;
813 /* Save the dst mac address */
814 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
816 /* Figure out which sw_if_index supplied the address */
817 unnum_src_sw_if_index = sw_if_index;
819 /* Track down all users of the unnumbered source */
821 pool_foreach (si, vim->sw_interfaces,
823 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
824 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
826 vec_add1 (broadcast_swifs, si->sw_if_index);
831 /* If there are no interfaces un-unmbered to this interface,
833 if (0 == vec_len (broadcast_swifs))
836 /* Allocate buffering if we need it */
837 if (vec_len (broadcast_swifs) > 1)
839 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
840 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
841 _vec_len (buffers) = n_alloc;
842 for (i = 0; i < n_alloc; i++)
844 b0 = vlib_get_buffer (vm, buffers[i]);
846 /* xerox (partially built) ARP pkt */
847 clib_memcpy (b0->data, p0->data,
848 p0->current_length + p0->current_data);
849 b0->current_data = p0->current_data;
850 b0->current_length = p0->current_length;
851 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
852 vnet_buffer (p0)->sw_if_index[VLIB_RX];
856 vec_insert (buffers, 1, 0);
859 for (i = 0; i < vec_len (buffers); i++)
861 b0 = vlib_get_buffer (vm, buffers[i]);
862 arp0 = vlib_buffer_get_current (b0);
864 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
865 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
867 /* For decoration, most likely */
868 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
870 /* Fix ARP pkt src address */
871 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
873 /* Build L2 encaps for this swif */
874 header_size = sizeof (ethernet_header_t);
875 if (si->sub.eth.flags.one_tag)
877 else if (si->sub.eth.flags.two_tags)
880 vlib_buffer_advance (b0, -header_size);
881 eth0 = vlib_buffer_get_current (b0);
883 if (si->sub.eth.flags.one_tag)
885 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
887 eth0->type = si->sub.eth.flags.dot1ad ?
888 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
889 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
890 outer->priority_cfi_and_id =
891 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
892 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
895 else if (si->sub.eth.flags.two_tags)
897 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
898 ethernet_vlan_header_t *inner = (void *) (outer + 1);
900 eth0->type = si->sub.eth.flags.dot1ad ?
901 clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
902 clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
903 outer->priority_cfi_and_id =
904 clib_host_to_net_u16 (si->sub.eth.outer_vlan_id);
905 outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
906 inner->priority_cfi_and_id =
907 clib_host_to_net_u16 (si->sub.eth.inner_vlan_id);
908 inner->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
913 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
916 /* Restore the original dst address, set src address */
917 clib_memcpy (eth0->dst_address, dst_mac_address,
918 sizeof (eth0->dst_address));
919 clib_memcpy (eth0->src_address, hi->hw_address,
920 sizeof (eth0->src_address));
922 /* Transmit replicas */
926 vlib_get_frame_to_node (vm, hi->output_node_index);
927 u32 *to_next = vlib_frame_vector_args (f);
928 to_next[0] = buffers[i];
930 vlib_put_frame_to_node (vm, hi->output_node_index, f);
934 /* The regular path outputs the original pkt.. */
935 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
937 vec_free (broadcast_swifs);
944 arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
946 ethernet_arp_main_t *am = ðernet_arp_main;
947 vnet_main_t *vnm = vnet_get_main ();
948 ip4_main_t *im4 = &ip4_main;
949 u32 n_left_from, next_index, *from, *to_next;
950 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
952 from = vlib_frame_vector_args (frame);
953 n_left_from = frame->n_vectors;
954 next_index = node->cached_next_index;
956 if (node->flags & VLIB_NODE_FLAG_TRACE)
957 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
959 sizeof (ethernet_arp_input_trace_t));
961 while (n_left_from > 0)
965 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
967 while (n_left_from > 0 && n_left_to_next > 0)
970 vnet_hw_interface_t *hw_if0;
971 ethernet_arp_header_t *arp0;
972 ethernet_header_t *eth0;
973 ip_adjacency_t *adj0;
974 ip4_address_t *if_addr0, proxy_src;
975 u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
976 u8 is_request0, dst_is_local0, is_unnum0;
977 ethernet_proxy_arp_t *pa;
978 fib_node_index_t dst_fei, src_fei;
980 fib_entry_flag_t src_flags, dst_flags;
990 p0 = vlib_get_buffer (vm, pi0);
991 arp0 = vlib_buffer_get_current (p0);
993 is_request0 = arp0->opcode
994 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
996 error0 = ETHERNET_ARP_ERROR_replies_sent;
1000 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1001 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1004 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
1005 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
1007 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1012 /* Check that IP address is local and matches incoming interface. */
1013 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1014 if (~0 == fib_index0)
1016 error0 = ETHERNET_ARP_ERROR_interface_no_table;
1020 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1021 &arp0->ip4_over_ethernet[1].ip4,
1023 dst_flags = fib_entry_get_flags_for_source (dst_fei,
1024 FIB_SOURCE_INTERFACE);
1027 fib_entry_get_resolving_interface_for_source (dst_fei,
1028 FIB_SOURCE_INTERFACE);
1030 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
1032 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1036 /* Honor unnumbered interface, if any */
1037 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
1039 /* Source must also be local to subnet of matching interface address. */
1040 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1041 &arp0->ip4_over_ethernet[0].ip4,
1043 src_flags = fib_entry_get_flags (src_fei);
1045 if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
1046 (FIB_ENTRY_FLAG_CONNECTED & src_flags)) ||
1047 sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1049 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
1053 /* Reject requests/replies with our local interface address. */
1054 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
1056 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
1060 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1061 fib_entry_get_prefix (dst_fei, &pfx0);
1062 if_addr0 = &pfx0.fp_addr.ip4;
1064 /* Fill in ethernet header. */
1065 eth0 = ethernet_buffer_get_header (p0);
1067 /* Trash ARP packets whose ARP-level source addresses do not
1068 match their L2-frame-level source addresses */
1069 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1070 sizeof (eth0->src_address)))
1072 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1076 /* Learn or update sender's mapping only for requests or unicasts
1077 that don't match local interface address. */
1078 if (ethernet_address_cast (eth0->dst_address) ==
1079 ETHERNET_ADDRESS_UNICAST || is_request0)
1081 if (am->limit_arp_cache_size &&
1082 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1083 unset_random_arp_entry ();
1085 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
1086 &arp0->ip4_over_ethernet[0],
1087 0 /* is_static */ );
1088 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
1091 /* Only send a reply for requests sent which match a local interface. */
1092 if (!(is_request0 && dst_is_local0))
1096 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1097 ETHERNET_ARP_ERROR_replies_received : error0);
1103 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1104 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1106 /* Send reply back through input interface */
1107 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1108 next0 = ARP_INPUT_NEXT_REPLY_TX;
1110 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1112 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1114 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1115 hw_if0->hw_address, 6);
1116 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1119 /* Hardware must be ethernet-like. */
1120 ASSERT (vec_len (hw_if0->hw_address) == 6);
1122 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1123 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
1125 /* Figure out how much to rewind current data from adjacency. */
1126 /* get the adj from the destination's covering connected */
1130 adj_get (fib_entry_get_adj_for_source
1131 (ip4_fib_table_lookup
1132 (ip4_fib_get (fib_index0),
1133 &arp0->ip4_over_ethernet[1].ip4, 31),
1134 FIB_SOURCE_INTERFACE));
1135 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
1137 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1142 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1146 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1148 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1149 n_left_to_next, pi0, next0);
1151 n_replies_sent += 1;
1155 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1156 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1157 arp0->ip4_over_ethernet[1].ip4.as_u32))
1159 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1162 /* See if proxy arp is configured for the address */
1165 vnet_sw_interface_t *si;
1166 u32 this_addr = clib_net_to_host_u32
1167 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1170 si = vnet_get_sw_interface (vnm, sw_if_index0);
1172 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1175 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1178 vec_foreach (pa, am->proxy_arps)
1180 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1181 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
1183 /* an ARP request hit in the proxy-arp table? */
1184 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1185 (fib_index0 == pa->fib_index))
1187 eth0 = ethernet_buffer_get_header (p0);
1189 arp0->ip4_over_ethernet[1].ip4.data_u32;
1192 * Rewind buffer, direct code above not to
1193 * think too hard about it.
1195 if_addr0 = &proxy_src;
1197 i32 ethernet_start =
1198 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1199 i32 rewind = p0->current_data - ethernet_start;
1200 vlib_buffer_advance (p0, -rewind);
1201 n_proxy_arp_replies_sent++;
1209 next0 = ARP_INPUT_NEXT_DROP;
1210 p0->error = node->errors[error0];
1212 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1213 n_left_to_next, pi0, next0);
1216 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1219 vlib_error_count (vm, node->node_index,
1220 ETHERNET_ARP_ERROR_replies_sent,
1221 n_replies_sent - n_proxy_arp_replies_sent);
1223 vlib_error_count (vm, node->node_index,
1224 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1225 n_proxy_arp_replies_sent);
1226 return frame->n_vectors;
1229 static char *ethernet_arp_error_strings[] = {
1230 #define _(sym,string) string,
1231 foreach_ethernet_arp_error
1236 VLIB_REGISTER_NODE (arp_input_node, static) =
1238 .function = arp_input,
1239 .name = "arp-input",
1240 .vector_size = sizeof (u32),
1241 .n_errors = ETHERNET_ARP_N_ERROR,
1242 .error_strings = ethernet_arp_error_strings,
1243 .n_next_nodes = ARP_INPUT_N_NEXT,
1245 [ARP_INPUT_NEXT_DROP] = "error-drop",
1246 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
1248 .format_buffer = format_ethernet_arp_header,
1249 .format_trace = format_ethernet_arp_input_trace,
1254 ip4_arp_entry_sort (void *a1, void *a2)
1256 ethernet_arp_ip4_entry_t *e1 = a1;
1257 ethernet_arp_ip4_entry_t *e2 = a2;
1260 vnet_main_t *vnm = vnet_get_main ();
1262 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
1264 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
1268 ethernet_arp_ip4_entry_t *
1269 ip4_neighbor_entries (u32 sw_if_index)
1271 ethernet_arp_main_t *am = ðernet_arp_main;
1272 ethernet_arp_ip4_entry_t *n, *ns = 0;
1275 pool_foreach (n, am->ip4_entry_pool, ({
1276 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1278 vec_add1 (ns, n[0]);
1283 vec_sort_with_function (ns, ip4_arp_entry_sort);
1287 static clib_error_t *
1288 show_ip4_arp (vlib_main_t * vm,
1289 unformat_input_t * input, vlib_cli_command_t * cmd)
1291 vnet_main_t *vnm = vnet_get_main ();
1292 ethernet_arp_main_t *am = ðernet_arp_main;
1293 ethernet_arp_ip4_entry_t *e, *es;
1294 ethernet_proxy_arp_t *pa;
1295 clib_error_t *error = 0;
1298 /* Filter entries by interface if given. */
1300 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1302 es = ip4_neighbor_entries (sw_if_index);
1305 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
1308 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
1313 if (vec_len (am->proxy_arps))
1315 vlib_cli_output (vm, "Proxy arps enabled for:");
1316 vec_foreach (pa, am->proxy_arps)
1318 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1320 format_ip4_address, &pa->lo_addr,
1321 format_ip4_address, &pa->hi_addr);
1329 * Display all the IPv4 ARP entries.
1332 * Example of how to display the IPv4 ARP table:
1333 * @cliexstart{show ip arp}
1334 * Time FIB IP4 Flags Ethernet Interface
1335 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1336 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1337 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1338 * Proxy arps enabled for:
1339 * Fib_index 0 6.0.0.1 - 6.0.0.11
1343 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1344 .path = "show ip arp",
1345 .function = show_ip4_arp,
1346 .short_help = "show ip arp",
1352 pg_edit_t l2_type, l3_type;
1353 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1359 } ip4_over_ethernet[2];
1360 } pg_ethernet_arp_header_t;
1363 pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1365 /* Initialize fields that are not bit fields in the IP header. */
1366 #define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
1369 _(n_l2_address_bytes);
1370 _(n_l3_address_bytes);
1372 _(ip4_over_ethernet[0].ethernet);
1373 _(ip4_over_ethernet[0].ip4);
1374 _(ip4_over_ethernet[1].ethernet);
1375 _(ip4_over_ethernet[1].ip4);
1380 unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1382 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1383 pg_ethernet_arp_header_t *p;
1386 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1388 pg_ethernet_arp_header_init (p);
1391 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1392 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1393 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1394 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1396 if (!unformat (input, "%U: %U/%U -> %U/%U",
1398 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1400 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1402 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1404 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1406 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
1408 /* Free up any edits we may have added. */
1409 pg_free_edit_group (s);
1416 ip4_set_arp_limit (u32 arp_limit)
1418 ethernet_arp_main_t *am = ðernet_arp_main;
1420 am->limit_arp_cache_size = arp_limit;
1425 * @brief Control Plane hook to remove an ARP entry
1428 vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1429 u32 sw_if_index, void *a_arg)
1431 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1432 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1434 args.sw_if_index = sw_if_index;
1435 args.flags = ETHERNET_ARP_ARGS_REMOVE;
1436 clib_memcpy (&args.a, a, sizeof (*a));
1438 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1439 (u8 *) & args, sizeof (args));
1444 * @brief Internally generated event to flush the ARP cache on an
1445 * interface state change event.
1446 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1447 * address from the corresponding adjacencies.
1450 vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
1451 u32 sw_if_index, void *a_arg)
1453 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1454 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1456 args.sw_if_index = sw_if_index;
1457 args.flags = ETHERNET_ARP_ARGS_FLUSH;
1458 clib_memcpy (&args.a, a, sizeof (*a));
1460 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1461 (u8 *) & args, sizeof (args));
1466 * @brief Internally generated event to populate the ARP cache on an
1467 * interface state change event.
1468 * For static entries this will re-source the adjacencies.
1470 * @param sw_if_index The interface on which the ARP entires are acted
1473 vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
1474 u32 sw_if_index, void *a_arg)
1476 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1477 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1479 args.sw_if_index = sw_if_index;
1480 args.flags = ETHERNET_ARP_ARGS_POPULATE;
1481 clib_memcpy (&args.a, a, sizeof (*a));
1483 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1484 (u8 *) & args, sizeof (args));
1489 * arp_add_del_interface_address
1491 * callback when an interface address is added or deleted
1494 arp_add_del_interface_address (ip4_main_t * im,
1497 ip4_address_t * address,
1499 u32 if_address_index, u32 is_del)
1502 * Flush the ARP cache of all entries covered by the address
1503 * that is being removed.
1505 ethernet_arp_main_t *am = ðernet_arp_main;
1506 ethernet_arp_ip4_entry_t *e;
1508 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
1513 ethernet_arp_interface_t *eai;
1514 u32 i, *to_delete = 0;
1517 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1520 hash_foreach_pair (pair, eai->arp_entries,
1522 e = pool_elt_at_index(am->ip4_entry_pool,
1524 if (ip4_destination_matches_route (im, &e->ip4_address,
1525 address, address_length))
1527 vec_add1 (to_delete, e - am->ip4_entry_pool);
1532 for (i = 0; i < vec_len (to_delete); i++)
1534 ethernet_arp_ip4_over_ethernet_address_t delme;
1535 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1537 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1538 delme.ip4.as_u32 = e->ip4_address.as_u32;
1540 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
1541 e->sw_if_index, &delme);
1544 vec_free (to_delete);
1548 static clib_error_t *
1549 ethernet_arp_init (vlib_main_t * vm)
1551 ethernet_arp_main_t *am = ðernet_arp_main;
1552 ip4_main_t *im = &ip4_main;
1553 clib_error_t *error;
1556 if ((error = vlib_call_init_function (vm, ethernet_init)))
1559 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1561 pn = pg_get_node (arp_input_node.index);
1562 pn->unformat_edit = unformat_pg_arp_header;
1564 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1565 #define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1566 foreach_ethernet_arp_opcode;
1569 /* $$$ configurable */
1570 am->limit_arp_cache_size = 50000;
1572 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1573 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1575 /* don't trace ARP error packets */
1577 vlib_node_runtime_t *rt =
1578 vlib_node_get_runtime (vm, arp_input_node.index);
1581 vnet_pcap_drop_trace_filter_add_del \
1582 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1584 foreach_ethernet_arp_error
1588 ip4_add_del_interface_address_callback_t cb;
1589 cb.function = arp_add_del_interface_address;
1590 cb.function_opaque = 0;
1591 vec_add1 (im->add_del_interface_address_callbacks, cb);
1596 VLIB_INIT_FUNCTION (ethernet_arp_init);
1599 arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1601 ethernet_arp_main_t *am = ðernet_arp_main;
1603 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
1604 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1605 pool_put (am->ip4_entry_pool, e);
1609 vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
1610 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1613 ethernet_arp_main_t *am = ðernet_arp_main;
1614 ethernet_arp_ip4_entry_t *e;
1615 ethernet_arp_interface_t *eai;
1617 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1619 e = arp_entry_find (eai, &args->a.ip4);
1623 arp_entry_free (eai, e);
1625 adj_nbr_walk_nh4 (e->sw_if_index,
1626 &e->ip4_address, arp_mk_incomplete_walk, NULL);
1633 vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1634 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1637 ethernet_arp_main_t *am = ðernet_arp_main;
1638 ethernet_arp_ip4_entry_t *e;
1639 ethernet_arp_interface_t *eai;
1641 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1643 e = arp_entry_find (eai, &args->a.ip4);
1647 adj_nbr_walk_nh4 (e->sw_if_index,
1648 &e->ip4_address, arp_mk_incomplete_walk, e);
1651 * The difference between flush and unset, is that an unset
1652 * means delete for static and dynamic entries. A flush
1653 * means delete only for dynamic. Flushing is what the DP
1654 * does in response to interface events. unset is only done
1655 * by the control plane.
1657 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
1659 arp_entry_free (eai, e);
1666 vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1667 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1670 ethernet_arp_main_t *am = ðernet_arp_main;
1671 ethernet_arp_ip4_entry_t *e;
1672 ethernet_arp_interface_t *eai;
1674 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1676 e = arp_entry_find (eai, &args->a.ip4);
1680 adj_nbr_walk_nh4 (e->sw_if_index,
1681 &e->ip4_address, arp_mk_complete_walk, e);
1687 set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1690 vnet_main_t *vm = vnet_get_main ();
1691 ASSERT (os_get_cpu_number () == 0);
1693 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1694 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1695 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1696 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1697 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1698 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1700 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1704 * @brief Invoked when the interface's admin state changes
1706 static clib_error_t *
1707 ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1708 u32 sw_if_index, u32 flags)
1710 ethernet_arp_main_t *am = ðernet_arp_main;
1711 ethernet_arp_ip4_entry_t *e;
1712 u32 i, *to_delete = 0;
1715 pool_foreach (e, am->ip4_entry_pool,
1717 if (e->sw_if_index == sw_if_index)
1718 vec_add1 (to_delete,
1719 e - am->ip4_entry_pool);
1723 for (i = 0; i < vec_len (to_delete); i++)
1725 ethernet_arp_ip4_over_ethernet_address_t delme;
1726 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1728 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1729 delme.ip4.as_u32 = e->ip4_address.as_u32;
1731 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1733 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1737 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
1741 vec_free (to_delete);
1746 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1749 increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
1754 for (i = 3; i >= 0; i--)
1756 old = a->ip4.as_u8[i];
1757 a->ip4.as_u8[i] += 1;
1758 if (old < a->ip4.as_u8[i])
1762 for (i = 5; i >= 0; i--)
1764 old = a->ethernet[i];
1765 a->ethernet[i] += 1;
1766 if (old < a->ethernet[i])
1772 vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1773 u32 sw_if_index, void *a_arg, int is_static)
1775 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1776 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1778 args.sw_if_index = sw_if_index;
1779 args.is_static = is_static;
1781 clib_memcpy (&args.a, a, sizeof (*a));
1783 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1784 (u8 *) & args, sizeof (args));
1789 vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1790 ip4_address_t * hi_addr, u32 fib_index, int is_del)
1792 ethernet_arp_main_t *am = ðernet_arp_main;
1793 ethernet_proxy_arp_t *pa;
1794 u32 found_at_index = ~0;
1796 vec_foreach (pa, am->proxy_arps)
1798 if (pa->lo_addr == lo_addr->as_u32
1799 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1801 found_at_index = pa - am->proxy_arps;
1806 if (found_at_index != ~0)
1808 /* Delete, otherwise it's already in the table */
1810 vec_delete (am->proxy_arps, 1, found_at_index);
1813 /* delete, no such entry */
1815 return VNET_API_ERROR_NO_SUCH_ENTRY;
1817 /* add, not in table */
1818 vec_add2 (am->proxy_arps, pa, 1);
1819 pa->lo_addr = lo_addr->as_u32;
1820 pa->hi_addr = hi_addr->as_u32;
1821 pa->fib_index = fib_index;
1826 * Remove any proxy arp entries asdociated with the
1830 vnet_proxy_arp_fib_reset (u32 fib_id)
1832 ip4_main_t *im = &ip4_main;
1833 ethernet_arp_main_t *am = ðernet_arp_main;
1834 ethernet_proxy_arp_t *pa;
1835 u32 *entries_to_delete = 0;
1840 p = hash_get (im->fib_index_by_table_id, fib_id);
1842 return VNET_API_ERROR_NO_SUCH_ENTRY;
1845 vec_foreach (pa, am->proxy_arps)
1847 if (pa->fib_index == fib_index)
1849 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1853 for (i = 0; i < vec_len (entries_to_delete); i++)
1855 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1858 vec_free (entries_to_delete);
1863 static clib_error_t *
1864 ip_arp_add_del_command_fn (vlib_main_t * vm,
1865 unformat_input_t * input, vlib_cli_command_t * cmd)
1867 vnet_main_t *vnm = vnet_get_main ();
1869 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1878 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1880 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1881 if (unformat (input, "%U %U %U",
1882 unformat_vnet_sw_interface, vnm, &sw_if_index,
1883 unformat_ip4_address, &addr.ip4,
1884 unformat_ethernet_address, &addr.ethernet))
1887 else if (unformat (input, "delete") || unformat (input, "del"))
1890 else if (unformat (input, "static"))
1893 else if (unformat (input, "count %d", &count))
1896 else if (unformat (input, "fib-id %d", &fib_id))
1898 ip4_main_t *im = &ip4_main;
1899 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1901 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1905 else if (unformat (input, "proxy %U - %U",
1906 unformat_ip4_address, &lo_addr.ip4,
1907 unformat_ip4_address, &hi_addr.ip4))
1915 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1924 for (i = 0; i < count; i++)
1928 uword event_type, *event_data = 0;
1930 /* Park the debug CLI until the arp entry is installed */
1931 vnet_register_ip4_arp_resolution_event
1932 (vnm, &addr.ip4, vlib_current_process (vm),
1933 1 /* type */ , 0 /* data */ );
1935 vnet_arp_set_ip4_over_ethernet
1936 (vnm, sw_if_index, &addr, is_static);
1938 vlib_process_wait_for_event (vm);
1939 event_type = vlib_process_get_events (vm, &event_data);
1940 vec_reset_length (event_data);
1941 if (event_type != 1)
1942 clib_warning ("event type %d unexpected", event_type);
1945 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
1947 increment_ip4_and_mac_address (&addr);
1952 return clib_error_return (0, "unknown input `%U'",
1953 format_unformat_error, input);
1961 * Add or delete IPv4 ARP cache entries.
1963 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
1964 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
1965 * any order and combination.
1969 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
1970 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
1971 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1972 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
1974 * To add or delete an IPv4 ARP cache entry to or from a specific fib
1976 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1977 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1979 * Add or delete IPv4 static ARP cache entries as follows:
1980 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1981 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1983 * For testing / debugging purposes, the 'set ip arp' command can add or
1984 * delete multiple entries. Supply the 'count N' parameter:
1985 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1988 VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
1989 .path = "set ip arp",
1991 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
1992 .function = ip_arp_add_del_command_fn,
1996 static clib_error_t *
1997 set_int_proxy_arp_command_fn (vlib_main_t * vm,
1999 input, vlib_cli_command_t * cmd)
2001 vnet_main_t *vnm = vnet_get_main ();
2003 vnet_sw_interface_t *si;
2007 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2009 if (unformat (input, "%U", unformat_vnet_sw_interface,
2012 else if (unformat (input, "enable") || unformat (input, "on"))
2014 else if (unformat (input, "disable") || unformat (input, "off"))
2021 return clib_error_return (0, "unknown input '%U'",
2022 format_unformat_error, input);
2024 si = vnet_get_sw_interface (vnm, sw_if_index);
2027 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2029 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
2036 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2037 * requests for the indicated address range. Multiple proxy-arp
2038 * ranges may be provisioned.
2040 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2041 * Also, the underlying implementation has not been performance-tuned.
2042 * Avoid creating an unnecessarily large set of ranges.
2045 * To enable proxy arp on a range of addresses, use:
2046 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2047 * Append 'del' to delete a range of proxy ARP addresses:
2048 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2049 * You must then specifically enable proxy arp on individual interfaces:
2050 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2051 * To disable proxy arp on an individual interface:
2052 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
2054 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
2055 .path = "set interface proxy-arp",
2057 "set interface proxy-arp <intfc> [enable|disable]",
2058 .function = set_int_proxy_arp_command_fn,
2064 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2065 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
2069 ARP_TERM_NEXT_L2_OUTPUT,
2074 u32 arp_term_next_node_index[32];
2077 arp_term_l2bd (vlib_main_t * vm,
2078 vlib_node_runtime_t * node, vlib_frame_t * frame)
2080 l2input_main_t *l2im = &l2input_main;
2081 u32 n_left_from, next_index, *from, *to_next;
2082 u32 n_replies_sent = 0;
2083 u16 last_bd_index = ~0;
2084 l2_bridge_domain_t *last_bd_config = 0;
2085 l2_input_config_t *cfg0;
2087 from = vlib_frame_vector_args (frame);
2088 n_left_from = frame->n_vectors;
2089 next_index = node->cached_next_index;
2091 while (n_left_from > 0)
2095 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2097 while (n_left_from > 0 && n_left_to_next > 0)
2100 ethernet_header_t *eth0;
2101 ethernet_arp_header_t *arp0;
2104 u32 pi0, error0, next0, sw_if_index0;
2115 n_left_to_next -= 1;
2117 p0 = vlib_get_buffer (vm, pi0);
2118 eth0 = vlib_buffer_get_current (p0);
2119 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2120 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
2121 arp0 = (ethernet_arp_header_t *) l3h0;
2123 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2125 clib_host_to_net_u16
2126 (ETHERNET_ARP_OPCODE_request))))
2129 /* Must be ARP request packet here */
2130 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2131 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2133 u8 *t0 = vlib_add_trace (vm, node, p0,
2134 sizeof (ethernet_arp_input_trace_t));
2135 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
2138 error0 = ETHERNET_ARP_ERROR_replies_sent;
2141 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2142 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
2145 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2146 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
2148 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2153 /* Trash ARP packets whose ARP-level source addresses do not
2154 match their L2-frame-level source addresses */
2157 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2158 sizeof (eth0->src_address))))
2160 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2164 /* Check if anyone want ARP request events for L2 BDs */
2166 pending_resolution_t *mc;
2167 ethernet_arp_main_t *am = ðernet_arp_main;
2168 uword *p = hash_get (am->mac_changes_by_address, 0);
2169 if (p && (vnet_buffer (p0)->l2.shg == 0))
2170 { // Only SHG 0 interface which is more likely local
2171 u32 next_index = p[0];
2172 while (next_index != (u32) ~ 0)
2174 int (*fp) (u32, u8 *, u32, u32);
2176 mc = pool_elt_at_index (am->mac_changes, next_index);
2177 fp = mc->data_callback;
2178 /* Call the callback, return 1 to suppress dup events */
2180 rv = (*fp) (mc->data,
2181 arp0->ip4_over_ethernet[0].ethernet,
2183 arp0->ip4_over_ethernet[0].ip4.as_u32);
2184 /* Signal the resolver process */
2186 vlib_process_signal_event (vm, mc->node_index,
2187 mc->type_opaque, mc->data);
2188 next_index = mc->next_index;
2193 /* lookup BD mac_by_ip4 hash table for MAC entry */
2194 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
2195 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2196 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2197 || (last_bd_index == (u16) ~ 0)))
2199 last_bd_index = bd_index0;
2200 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
2202 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2204 if (PREDICT_FALSE (!macp0))
2205 goto next_l2_feature; /* MAC not found */
2207 /* MAC found, send ARP reply -
2208 Convert ARP request packet to ARP reply */
2209 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2210 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2211 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
2212 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2213 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2214 clib_memcpy (eth0->src_address, macp0, 6);
2215 n_replies_sent += 1;
2218 /* For BVI, need to use l2-fwd node to send ARP reply as
2219 l2-output node cannot output packet to BVI properly */
2220 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
2221 if (PREDICT_FALSE (cfg0->bvi))
2223 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
2224 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2225 goto next_l2_feature;
2228 /* Send ARP/ND reply back out input interface through l2-output */
2229 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2230 next0 = ARP_TERM_NEXT_L2_OUTPUT;
2231 /* Note that output to VXLAN tunnel will fail due to SHG which
2232 is probably desireable since ARP termination is not intended
2233 for ARP requests from other hosts. If output to VXLAN tunnel is
2234 required, however, can just clear the SHG in packet as follows:
2235 vnet_buffer(p0)->l2.shg = 0; */
2236 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2237 to_next, n_left_to_next, pi0,
2242 /* IP6 ND event notification or solicitation handling to generate
2243 local response instead of flooding */
2244 iph0 = (ip6_header_t *) l3h0;
2245 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2246 iph0->protocol == IP_PROTOCOL_ICMP6 &&
2247 !ip6_address_is_unspecified
2248 (&iph0->src_address)))
2250 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2251 if (vnet_ip6_nd_term
2252 (vm, node, p0, eth0, iph0, sw_if_index0,
2253 vnet_buffer (p0)->l2.bd_index, vnet_buffer (p0)->l2.shg))
2254 goto output_response;
2259 u32 feature_bitmap0 =
2260 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2261 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
2263 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2265 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2266 to_next, n_left_to_next,
2272 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2273 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2274 arp0->ip4_over_ethernet[1].ip4.as_u32))
2276 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2278 next0 = ARP_TERM_NEXT_DROP;
2279 p0->error = node->errors[error0];
2281 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2282 to_next, n_left_to_next, pi0,
2286 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2289 vlib_error_count (vm, node->node_index,
2290 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
2291 return frame->n_vectors;
2295 VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
2296 .function = arp_term_l2bd,
2297 .name = "arp-term-l2bd",
2298 .vector_size = sizeof (u32),
2299 .n_errors = ETHERNET_ARP_N_ERROR,
2300 .error_strings = ethernet_arp_error_strings,
2301 .n_next_nodes = ARP_TERM_N_NEXT,
2303 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2304 [ARP_TERM_NEXT_DROP] = "error-drop",
2306 .format_buffer = format_ethernet_arp_header,
2307 .format_trace = format_arp_term_input_trace,
2312 arp_term_init (vlib_main_t * vm)
2314 // Initialize the feature next-node indexes
2315 feat_bitmap_init_next_nodes (vm,
2316 arp_term_l2bd_node.index,
2318 l2input_get_feat_names (),
2319 arp_term_next_node_index);
2323 VLIB_INIT_FUNCTION (arp_term_init);
2326 change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2328 if (e->sw_if_index == sw_if_index)
2330 adj_nbr_walk_nh4 (e->sw_if_index,
2331 &e->ip4_address, arp_mk_complete_walk, e);
2336 ethernet_arp_change_mac (u32 sw_if_index)
2338 ethernet_arp_main_t *am = ðernet_arp_main;
2339 ethernet_arp_ip4_entry_t *e;
2342 pool_foreach (e, am->ip4_entry_pool,
2344 change_arp_mac (sw_if_index, e);
2350 * fd.io coding-style-patch-verification: ON
2353 * eval: (c-set-style "gnu")