blob: b388e778ac8aa2d7a256ba1a8e732bed306163e7 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * ethernet/arp.c: IP v4 ARP node
3 *
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:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18#include <vnet/ip/ip.h>
John Lo1edfba92016-08-27 01:11:57 -040019#include <vnet/ip/ip6.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070020#include <vnet/ethernet/ethernet.h>
21#include <vnet/ethernet/arp_packet.h>
22#include <vnet/l2/l2_input.h>
23#include <vppinfra/mhash.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010024#include <vnet/fib/ip4_fib.h>
Neale Rannsb80c5362016-10-08 13:03:40 +010025#include <vnet/adj/adj_nbr.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010026#include <vnet/mpls/mpls.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070027
Billy McFall2d085d92016-09-13 21:47:55 -040028/**
29 * @file
30 * @brief IPv4 ARP.
31 *
32 * This file contains code to manage the IPv4 ARP tables (IP Address
33 * to MAC Address lookup).
34 */
35
36
Dave Barachf9bd6202015-12-14 13:22:11 -050037void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
38
Neale Ranns0bfe5d82016-08-25 15:29:12 +010039/**
40 * @brief Per-interface ARP configuration and state
41 */
42typedef struct ethernet_arp_interface_t_
43{
Neale Rannsb80c5362016-10-08 13:03:40 +010044 /**
45 * Hash table of ARP entries.
46 * Since this hash table is per-interface, the key is only the IPv4 address.
47 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010048 uword *arp_entries;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010049} ethernet_arp_interface_t;
50
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070051typedef struct
52{
Ed Warnickecb9cada2015-12-08 15:45:58 -070053 u32 lo_addr;
54 u32 hi_addr;
55 u32 fib_index;
56} ethernet_proxy_arp_t;
57
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070058typedef struct
59{
Ed Warnickecb9cada2015-12-08 15:45:58 -070060 u32 next_index;
61 uword node_index;
62 uword type_opaque;
63 uword data;
64 /* Used for arp event notification only */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070065 void *data_callback;
Ed Warnickecb9cada2015-12-08 15:45:58 -070066 u32 pid;
67} pending_resolution_t;
68
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070069typedef struct
70{
Ed Warnickecb9cada2015-12-08 15:45:58 -070071 /* Hash tables mapping name to opcode. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070072 uword *opcode_by_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -070073
74 /* lite beer "glean" adjacency handling */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070075 uword *pending_resolutions_by_address;
76 pending_resolution_t *pending_resolutions;
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
78 /* Mac address change notification */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070079 uword *mac_changes_by_address;
80 pending_resolution_t *mac_changes;
Ed Warnickecb9cada2015-12-08 15:45:58 -070081
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070082 ethernet_arp_ip4_entry_t *ip4_entry_pool;
Ed Warnickecb9cada2015-12-08 15:45:58 -070083
Ed Warnickecb9cada2015-12-08 15:45:58 -070084 /* ARP attack mitigation */
85 u32 arp_delete_rotor;
86 u32 limit_arp_cache_size;
87
Neale Ranns0bfe5d82016-08-25 15:29:12 +010088 /** Per interface state */
89 ethernet_arp_interface_t *ethernet_arp_by_sw_if_index;
90
Ed Warnickecb9cada2015-12-08 15:45:58 -070091 /* Proxy arp vector */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070092 ethernet_proxy_arp_t *proxy_arps;
Ed Warnickecb9cada2015-12-08 15:45:58 -070093} ethernet_arp_main_t;
94
95static ethernet_arp_main_t ethernet_arp_main;
96
Neale Ranns0bfe5d82016-08-25 15:29:12 +010097typedef struct
98{
99 u32 sw_if_index;
100 ethernet_arp_ip4_over_ethernet_address_t a;
101 int is_static;
102 int flags;
103#define ETHERNET_ARP_ARGS_REMOVE (1<<0)
104#define ETHERNET_ARP_ARGS_FLUSH (1<<1)
105#define ETHERNET_ARP_ARGS_POPULATE (1<<2)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100106} vnet_arp_set_ip4_over_ethernet_rpc_args_t;
107
108static void
109set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
110 * a);
111
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700112static u8 *
113format_ethernet_arp_hardware_type (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114{
115 ethernet_arp_hardware_type_t h = va_arg (*va, ethernet_arp_hardware_type_t);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700116 char *t = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117 switch (h)
118 {
119#define _(n,f) case n: t = #f; break;
120 foreach_ethernet_arp_hardware_type;
121#undef _
122
123 default:
124 return format (s, "unknown 0x%x", h);
125 }
126
127 return format (s, "%s", t);
128}
129
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700130static u8 *
131format_ethernet_arp_opcode (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132{
133 ethernet_arp_opcode_t o = va_arg (*va, ethernet_arp_opcode_t);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700134 char *t = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135 switch (o)
136 {
137#define _(f) case ETHERNET_ARP_OPCODE_##f: t = #f; break;
138 foreach_ethernet_arp_opcode;
139#undef _
140
141 default:
142 return format (s, "unknown 0x%x", o);
143 }
144
145 return format (s, "%s", t);
146}
147
148static uword
149unformat_ethernet_arp_opcode_host_byte_order (unformat_input_t * input,
150 va_list * args)
151{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700152 int *result = va_arg (*args, int *);
153 ethernet_arp_main_t *am = &ethernet_arp_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 int x, i;
155
156 /* Numeric opcode. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700157 if (unformat (input, "0x%x", &x) || unformat (input, "%d", &x))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 {
159 if (x >= (1 << 16))
160 return 0;
161 *result = x;
162 return 1;
163 }
164
165 /* Named type. */
166 if (unformat_user (input, unformat_vlib_number_by_name,
167 am->opcode_by_name, &i))
168 {
169 *result = i;
170 return 1;
171 }
172
173 return 0;
174}
175
176static uword
177unformat_ethernet_arp_opcode_net_byte_order (unformat_input_t * input,
178 va_list * args)
179{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700180 int *result = va_arg (*args, int *);
181 if (!unformat_user
182 (input, unformat_ethernet_arp_opcode_host_byte_order, result))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 return 0;
184
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700185 *result = clib_host_to_net_u16 ((u16) * result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 return 1;
187}
188
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700189static u8 *
190format_ethernet_arp_header (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700192 ethernet_arp_header_t *a = va_arg (*va, ethernet_arp_header_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 u32 max_header_bytes = va_arg (*va, u32);
194 uword indent;
195 u16 l2_type, l3_type;
196
197 if (max_header_bytes != 0 && sizeof (a[0]) > max_header_bytes)
198 return format (s, "ARP header truncated");
199
200 l2_type = clib_net_to_host_u16 (a->l2_type);
201 l3_type = clib_net_to_host_u16 (a->l3_type);
202
203 indent = format_get_indent (s);
204
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);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700210
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 if (l2_type == ETHERNET_ARP_HARDWARE_TYPE_ethernet
212 && l3_type == ETHERNET_TYPE_IP4)
213 {
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);
220 }
221 else
222 {
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,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700227 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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231 }
232
233 return s;
234}
235
Pavel Kotucek3e046ea2016-12-05 08:27:37 +0100236u8 *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700237format_ethernet_arp_ip4_entry (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700239 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;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700242 u8 *flags = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700244 if (!e)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100245 return format (s, "%=12s%=16s%=6s%=20s%=24s", "Time", "IP4",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700246 "Flags", "Ethernet", "Interface");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 si = vnet_get_sw_interface (vnm, e->sw_if_index);
Damjan Marion102ec522016-03-29 13:18:17 +0200249
250 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700251 flags = format (flags, "S");
Damjan Marion102ec522016-03-29 13:18:17 +0200252
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100253 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
254 flags = format (flags, "D");
255
256 s = format (s, "%=12U%=16U%=6s%=20U%=24U",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 format_vlib_cpu_time, vnm->vlib_main, e->cpu_time_last_updated,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100258 format_ip4_address, &e->ip4_address,
Damjan Marion102ec522016-03-29 13:18:17 +0200259 flags ? (char *) flags : "",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 format_ethernet_address, e->ethernet_address,
261 format_vnet_sw_interface_name, vnm, si);
262
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700263 vec_free (flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264 return s;
265}
266
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700267typedef struct
268{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 u8 packet_data[64];
270} ethernet_arp_input_trace_t;
271
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700272static u8 *
273format_ethernet_arp_input_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274{
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 *);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700277 ethernet_arp_input_trace_t *t = va_arg (*va, ethernet_arp_input_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278
279 s = format (s, "%U",
280 format_ethernet_arp_header,
281 t->packet_data, sizeof (t->packet_data));
282
283 return s;
284}
285
John Lo1edfba92016-08-27 01:11:57 -0400286static u8 *
287format_arp_term_input_trace (u8 * s, va_list * va)
288{
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 *);
292
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));
299
300 return s;
301}
302
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100303static void
Neale Rannsb80c5362016-10-08 13:03:40 +0100304arp_nbr_probe (ip_adjacency_t * adj)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305{
Neale Rannsb80c5362016-10-08 13:03:40 +0100306 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;
312 ip4_address_t *src;
313 vlib_buffer_t *b;
314 vlib_main_t *vm;
315 u32 bi = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316
Neale Rannsb80c5362016-10-08 13:03:40 +0100317 vm = vlib_get_main ();
John Locbec1a12016-07-05 18:34:40 -0400318
Neale Rannsb80c5362016-10-08 13:03:40 +0100319 si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
320
321 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100323 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 }
Neale Rannsb80c5362016-10-08 13:03:40 +0100325
326 src =
327 ip4_interface_address_matching_destination (im,
328 &adj->sub_type.nbr.next_hop.
329 ip4,
330 adj->rewrite_header.
331 sw_if_index, &ia);
332 if (!src)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100333 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100334 return;
335 }
336
337 h =
338 vlib_packet_template_get_packet (vm, &im->ip4_arp_request_packet_template,
339 &bi);
340
341 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
342
343 clib_memcpy (h->ip4_over_ethernet[0].ethernet,
344 hi->hw_address, sizeof (h->ip4_over_ethernet[0].ethernet));
345
346 h->ip4_over_ethernet[0].ip4 = src[0];
347 h->ip4_over_ethernet[1].ip4 = adj->sub_type.nbr.next_hop.ip4;
348
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;
352
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);
356
357 {
358 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
359 u32 *to_next = vlib_frame_vector_args (f);
360 to_next[0] = bi;
361 f->n_vectors = 1;
362 vlib_put_frame_to_node (vm, hi->output_node_index, f);
363 }
364}
365
366static void
367arp_mk_complete (adj_index_t ai, ethernet_arp_ip4_entry_t * e)
368{
369 adj_nbr_update_rewrite
370 (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
371 ethernet_build_rewrite (vnet_get_main (),
372 e->sw_if_index,
373 adj_get_link_type (ai), e->ethernet_address));
374}
375
376static void
Neale Ranns19c68d22016-12-07 15:38:14 +0000377arp_mk_incomplete (adj_index_t ai)
Neale Rannsb80c5362016-10-08 13:03:40 +0100378{
Neale Ranns19c68d22016-12-07 15:38:14 +0000379 ip_adjacency_t *adj = adj_get (ai);
380
Neale Rannsb80c5362016-10-08 13:03:40 +0100381 adj_nbr_update_rewrite
382 (ai,
383 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
384 ethernet_build_rewrite (vnet_get_main (),
Neale Ranns19c68d22016-12-07 15:38:14 +0000385 adj->rewrite_header.sw_if_index,
Neale Rannsb80c5362016-10-08 13:03:40 +0100386 VNET_LINK_ARP,
387 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
388}
389
390static ethernet_arp_ip4_entry_t *
391arp_entry_find (ethernet_arp_interface_t * eai, const ip4_address_t * addr)
392{
393 ethernet_arp_main_t *am = &ethernet_arp_main;
394 ethernet_arp_ip4_entry_t *e = NULL;
395 uword *p;
396
397 if (NULL != eai->arp_entries)
398 {
399 p = hash_get (eai->arp_entries, addr->as_u32);
400 if (!p)
401 return (NULL);
402
403 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
404 }
405
406 return (e);
407}
408
409static adj_walk_rc_t
410arp_mk_complete_walk (adj_index_t ai, void *ctx)
411{
412 ethernet_arp_ip4_entry_t *e = ctx;
413
414 arp_mk_complete (ai, e);
415
416 return (ADJ_WALK_RC_CONTINUE);
417}
418
419static adj_walk_rc_t
420arp_mk_incomplete_walk (adj_index_t ai, void *ctx)
421{
Neale Ranns19c68d22016-12-07 15:38:14 +0000422 arp_mk_incomplete (ai);
Neale Rannsb80c5362016-10-08 13:03:40 +0100423
424 return (ADJ_WALK_RC_CONTINUE);
425}
426
427void
428arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
429{
430 ethernet_arp_main_t *am = &ethernet_arp_main;
431 ethernet_arp_interface_t *arp_int;
432 ethernet_arp_ip4_entry_t *e;
433 ip_adjacency_t *adj;
434
435 adj = adj_get (ai);
436
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);
440
441 if (NULL != e)
442 {
443 adj_nbr_walk_nh4 (sw_if_index,
444 &e->ip4_address, arp_mk_complete_walk, e);
445 }
446 else
447 {
448 /*
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.
452 */
453 adj_nbr_update_rewrite (ai,
454 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
455 ethernet_build_rewrite (vnm,
456 sw_if_index,
457 VNET_LINK_ARP,
458 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
459
460 /*
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.
466 */
467 arp_nbr_probe (adj);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100468 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469}
470
471int
472vnet_arp_set_ip4_over_ethernet_internal (vnet_main_t * vnm,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100473 vnet_arp_set_ip4_over_ethernet_rpc_args_t
474 * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700476 ethernet_arp_ip4_entry_t *e = 0;
477 ethernet_arp_main_t *am = &ethernet_arp_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100478 ethernet_arp_ip4_over_ethernet_address_t *a = &args->a;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700479 vlib_main_t *vm = vlib_get_main ();
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700480 int make_new_arp_cache_entry = 1;
481 uword *p;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700482 pending_resolution_t *pr, *mc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100483 ethernet_arp_interface_t *arp_int;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484 int is_static = args->is_static;
485 u32 sw_if_index = args->sw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700486
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100487 vec_validate (am->ethernet_arp_by_sw_if_index, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100489 arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100491 if (NULL != arp_int->arp_entries)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100493 p = hash_get (arp_int->arp_entries, a->ip4.as_u32);
494 if (p)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700495 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100496 e = pool_elt_at_index (am->ip4_entry_pool, p[0]);
497
498 /* Refuse to over-write static arp. */
499 if (!is_static && (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC))
500 return -2;
501 make_new_arp_cache_entry = 0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700502 }
Damjan Marion102ec522016-03-29 13:18:17 +0200503 }
504
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505 if (make_new_arp_cache_entry)
506 {
Neale Rannsb80c5362016-10-08 13:03:40 +0100507 fib_prefix_t pfx = {
508 .fp_len = 32,
509 .fp_proto = FIB_PROTOCOL_IP4,
510 .fp_addr = {
511 .ip4 = a->ip4,
512 }
513 ,
514 };
515 u32 fib_index;
516
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517 pool_get (am->ip4_entry_pool, e);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100518
519 if (NULL == arp_int->arp_entries)
520 {
521 arp_int->arp_entries = hash_create (0, sizeof (u32));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100522 }
523
524 hash_set (arp_int->arp_entries, a->ip4.as_u32, e - am->ip4_entry_pool);
525
526 e->sw_if_index = sw_if_index;
527 e->ip4_address = a->ip4;
Neale Rannsb80c5362016-10-08 13:03:40 +0100528 clib_memcpy (e->ethernet_address,
529 a->ethernet, sizeof (e->ethernet_address));
530
531 fib_index = ip4_fib_table_get_index_for_sw_if_index (e->sw_if_index);
532 e->fib_entry_index =
533 fib_table_entry_update_one_path (fib_index,
534 &pfx,
535 FIB_SOURCE_ADJ,
536 FIB_ENTRY_FLAG_ATTACHED,
537 FIB_PROTOCOL_IP4,
538 &pfx.fp_addr,
539 e->sw_if_index,
540 ~0,
Neale Rannsad422ed2016-11-02 14:20:04 +0000541 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542 }
Neale Ranns33a7dd52016-10-07 15:14:33 +0100543 else
544 {
545 /*
546 * prevent a DoS attack from the data-plane that
547 * spams us with no-op updates to the MAC address
548 */
549 if (0 == memcmp (e->ethernet_address,
550 a->ethernet, sizeof (e->ethernet_address)))
551 return -1;
Neale Rannsb80c5362016-10-08 13:03:40 +0100552
553 /* Update time stamp and ethernet address. */
554 clib_memcpy (e->ethernet_address, a->ethernet,
555 sizeof (e->ethernet_address));
Neale Ranns33a7dd52016-10-07 15:14:33 +0100556 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700557
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 e->cpu_time_last_updated = clib_cpu_time_now ();
559 if (is_static)
560 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_STATIC;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100561 else
562 e->flags |= ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC;
563
Neale Rannsb80c5362016-10-08 13:03:40 +0100564 adj_nbr_walk_nh4 (sw_if_index, &e->ip4_address, arp_mk_complete_walk, e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565
566 /* Customer(s) waiting for this address to be resolved? */
567 p = hash_get (am->pending_resolutions_by_address, a->ip4.as_u32);
568 if (p)
569 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100570 u32 next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700571 next_index = p[0];
572
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700573 while (next_index != (u32) ~ 0)
574 {
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);
580 }
581
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582 hash_unset (am->pending_resolutions_by_address, a->ip4.as_u32);
583 }
584
585 /* Customer(s) requesting ARP event for this address? */
586 p = hash_get (am->mac_changes_by_address, a->ip4.as_u32);
587 if (p)
588 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100589 u32 next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590 next_index = p[0];
591
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700592 while (next_index != (u32) ~ 0)
593 {
594 int (*fp) (u32, u8 *, u32, u32);
595 int rv = 1;
596 mc = pool_elt_at_index (am->mac_changes, next_index);
597 fp = mc->data_callback;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700599 /* Call the user's data callback, return 1 to suppress dup events */
600 if (fp)
601 rv = (*fp) (mc->data, a->ethernet, sw_if_index, 0);
602
Damjan Marion607de1a2016-08-16 22:53:54 +0200603 /*
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700604 * Signal the resolver process, as long as the user
605 * says they want to be notified
606 */
607 if (rv == 0)
608 vlib_process_signal_event (vm, mc->node_index,
609 mc->type_opaque, mc->data);
610 next_index = mc->next_index;
611 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612 }
613
614 return 0;
615}
616
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700617void
618vnet_register_ip4_arp_resolution_event (vnet_main_t * vnm,
619 void *address_arg,
620 uword node_index,
621 uword type_opaque, uword data)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700623 ethernet_arp_main_t *am = &ethernet_arp_main;
624 ip4_address_t *address = address_arg;
625 uword *p;
626 pending_resolution_t *pr;
627
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 pool_get (am->pending_resolutions, pr);
629
630 pr->next_index = ~0;
631 pr->node_index = node_index;
632 pr->type_opaque = type_opaque;
633 pr->data = data;
634 pr->data_callback = 0;
635
636 p = hash_get (am->pending_resolutions_by_address, address->as_u32);
637 if (p)
638 {
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);
642 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700643
644 hash_set (am->pending_resolutions_by_address, address->as_u32,
645 pr - am->pending_resolutions);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646}
647
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700648int
649vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
650 void *data_callback,
651 u32 pid,
652 void *address_arg,
653 uword node_index,
654 uword type_opaque, uword data, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700656 ethernet_arp_main_t *am = &ethernet_arp_main;
657 ip4_address_t *address = address_arg;
658 uword *p;
659 pending_resolution_t *mc;
660 void (*fp) (u32, u8 *) = data_callback;
661
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662 if (is_add)
663 {
664 pool_get (am->mac_changes, mc);
665
666 mc->next_index = ~0;
667 mc->node_index = node_index;
668 mc->type_opaque = type_opaque;
669 mc->data = data;
670 mc->data_callback = data_callback;
671 mc->pid = pid;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700672
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 p = hash_get (am->mac_changes_by_address, address->as_u32);
674 if (p)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700675 {
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);
679 }
680
681 hash_set (am->mac_changes_by_address, address->as_u32,
682 mc - am->mac_changes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683 return 0;
684 }
685 else
686 {
687 u32 index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700688 pending_resolution_t *mc_last = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700689
690 p = hash_get (am->mac_changes_by_address, address->as_u32);
691 if (p == 0)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700692 return VNET_API_ERROR_NO_SUCH_ENTRY;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693
694 index = p[0];
695
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700696 while (index != (u32) ~ 0)
697 {
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)
701 {
702 /* Clients may need to clean up pool entries, too */
703 if (fp)
704 (*fp) (mc->data, 0 /* no new mac addrs */ );
705 if (index == p[0])
706 {
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,
710 mc->next_index);
711 pool_put (am->mac_changes, mc);
712 return 0;
713 }
714 else
715 {
716 ASSERT (mc_last);
717 mc_last->next_index = mc->next_index;
718 pool_put (am->mac_changes, mc);
719 return 0;
720 }
721 }
722 mc_last = mc;
723 index = mc->next_index;
724 }
725
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726 return VNET_API_ERROR_NO_SUCH_ENTRY;
727 }
728}
729
730/* Either we drop the packet or we send a reply to the sender. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700731typedef enum
732{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 ARP_INPUT_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -0400734 ARP_INPUT_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735 ARP_INPUT_N_NEXT,
736} arp_input_next_t;
737
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") \
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100752 _ (interface_no_table, "Interface is not mapped to an IP table") \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700754typedef enum
755{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756#define _(sym,string) ETHERNET_ARP_ERROR_##sym,
757 foreach_ethernet_arp_error
758#undef _
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700759 ETHERNET_ARP_N_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760} ethernet_arp_input_error_t;
761
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700763static void
764unset_random_arp_entry (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700766 ethernet_arp_main_t *am = &ethernet_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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700770 u32 index;
771
772 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
773 am->arp_delete_rotor = index;
774
775 /* Try again from elt 0, could happen if an intfc goes down */
776 if (index == ~0)
777 {
778 index = pool_next_index (am->ip4_entry_pool, am->arp_delete_rotor);
779 am->arp_delete_rotor = index;
780 }
781
782 /* Nothing left in the pool */
783 if (index == ~0)
784 return;
785
786 e = pool_elt_at_index (am->ip4_entry_pool, index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700787
Damjan Marionf1213b82016-03-13 02:22:06 +0100788 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100789 delme.ip4.as_u32 = e->ip4_address.as_u32;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700790
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100791 vnet_arp_unset_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792}
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700793
Neale Ranns436d06b2016-11-30 07:41:53 -0800794static int
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700795arp_unnumbered (vlib_buffer_t * p0,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100796 u32 pi0, ethernet_header_t * eth0, u32 sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700797{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700798 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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 u32 unnum_src_sw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700804 u32 *broadcast_swifs = 0;
805 u32 *buffers = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806 u32 n_alloc = 0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700807 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808 int i;
809 u8 dst_mac_address[6];
810 i16 header_size;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700811 ethernet_arp_header_t *arp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812
813 /* Save the dst mac address */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700814 clib_memcpy (dst_mac_address, eth0->dst_address, sizeof (dst_mac_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
816 /* Figure out which sw_if_index supplied the address */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100817 unnum_src_sw_if_index = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700818
819 /* Track down all users of the unnumbered source */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700820 /* *INDENT-OFF* */
821 pool_foreach (si, vim->sw_interfaces,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822 ({
823 if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700824 (si->unnumbered_sw_if_index == unnum_src_sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700826 vec_add1 (broadcast_swifs, si->sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827 }
828 }));
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700829 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Neale Ranns436d06b2016-11-30 07:41:53 -0800831 /* If there are no interfaces un-unmbered to this interface,
832 we are done here. */
833 if (0 == vec_len (broadcast_swifs))
834 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700835
836 /* Allocate buffering if we need it */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700837 if (vec_len (broadcast_swifs) > 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700839 vec_validate (buffers, vec_len (broadcast_swifs) - 2);
840 n_alloc = vlib_buffer_alloc (vm, buffers, vec_len (buffers));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700841 _vec_len (buffers) = n_alloc;
842 for (i = 0; i < n_alloc; i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700843 {
844 b0 = vlib_get_buffer (vm, buffers[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700845
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700846 /* 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];
853 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854 }
855
856 vec_insert (buffers, 1, 0);
857 buffers[0] = pi0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700858
859 for (i = 0; i < vec_len (buffers); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700860 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700861 b0 = vlib_get_buffer (vm, buffers[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862 arp0 = vlib_buffer_get_current (b0);
863
864 hi = vnet_get_sup_hw_interface (vnm, broadcast_swifs[i]);
865 si = vnet_get_sw_interface (vnm, broadcast_swifs[i]);
866
867 /* For decoration, most likely */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700868 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hi->sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869
870 /* Fix ARP pkt src address */
Damjan Marionf1213b82016-03-13 02:22:06 +0100871 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, hi->hw_address, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872
873 /* Build L2 encaps for this swif */
874 header_size = sizeof (ethernet_header_t);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700875 if (si->sub.eth.flags.one_tag)
876 header_size += 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700877 else if (si->sub.eth.flags.two_tags)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700878 header_size += 8;
879
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880 vlib_buffer_advance (b0, -header_size);
881 eth0 = vlib_buffer_get_current (b0);
882
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700883 if (si->sub.eth.flags.one_tag)
884 {
885 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
886
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);
893
894 }
895 else if (si->sub.eth.flags.two_tags)
896 {
897 ethernet_vlan_header_t *outer = (void *) (eth0 + 1);
898 ethernet_vlan_header_t *inner = (void *) (outer + 1);
899
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);
909
910 }
911 else
912 {
913 eth0->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
914 }
915
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916 /* Restore the original dst address, set src address */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700917 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));
921
Ed Warnickecb9cada2015-12-08 15:45:58 -0700922 /* Transmit replicas */
923 if (i > 0)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700924 {
925 vlib_frame_t *f =
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];
929 f->n_vectors = 1;
930 vlib_put_frame_to_node (vm, hi->output_node_index, f);
931 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932 }
933
John Lod1f5d042016-04-12 18:20:39 -0400934 /* The regular path outputs the original pkt.. */
935 vnet_buffer (p0)->sw_if_index[VLIB_TX] = broadcast_swifs[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936
937 vec_free (broadcast_swifs);
938 vec_free (buffers);
Neale Ranns436d06b2016-11-30 07:41:53 -0800939
940 return !0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941}
942
943static uword
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700944arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700945{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700946 ethernet_arp_main_t *am = &ethernet_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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700950 u32 n_replies_sent = 0, n_proxy_arp_replies_sent = 0;
951
952 from = vlib_frame_vector_args (frame);
953 n_left_from = frame->n_vectors;
954 next_index = node->cached_next_index;
955
956 if (node->flags & VLIB_NODE_FLAG_TRACE)
957 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
958 /* stride */ 1,
959 sizeof (ethernet_arp_input_trace_t));
960
961 while (n_left_from > 0)
962 {
963 u32 n_left_to_next;
964
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700965 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966
967 while (n_left_from > 0 && n_left_to_next > 0)
968 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700969 vlib_buffer_t *p0;
970 vnet_hw_interface_t *hw_if0;
971 ethernet_arp_header_t *arp0;
972 ethernet_header_t *eth0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700973 ip_adjacency_t *adj0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100974 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;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700977 ethernet_proxy_arp_t *pa;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100978 fib_node_index_t dst_fei, src_fei;
979 fib_prefix_t pfx0;
980 fib_entry_flag_t src_flags, dst_flags;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981
982 pi0 = from[0];
983 to_next[0] = pi0;
984 from += 1;
985 to_next += 1;
986 n_left_from -= 1;
987 n_left_to_next -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100988 pa = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989
990 p0 = vlib_get_buffer (vm, pi0);
991 arp0 = vlib_buffer_get_current (p0);
992
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700993 is_request0 = arp0->opcode
994 == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995
996 error0 = ETHERNET_ARP_ERROR_replies_sent;
997
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700998 error0 =
999 (arp0->l2_type !=
1000 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet) ?
1001 ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
1002 error0 =
1003 (arp0->l3_type !=
1004 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
1005 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006
1007 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1008
1009 if (error0)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001010 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011
1012 /* Check that IP address is local and matches incoming interface. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001013 fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
1014 if (~0 == fib_index0)
1015 {
1016 error0 = ETHERNET_ARP_ERROR_interface_no_table;
1017 goto drop2;
1018
1019 }
1020 dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1021 &arp0->ip4_over_ethernet[1].ip4,
1022 32);
Neale Rannsdf089a82016-10-02 16:39:06 +01001023 dst_flags = fib_entry_get_flags_for_source (dst_fei,
1024 FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001025
Neale Rannsdf089a82016-10-02 16:39:06 +01001026 conn_sw_if_index0 =
1027 fib_entry_get_resolving_interface_for_source (dst_fei,
1028 FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001029
1030 if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 {
1032 error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
1033 goto drop1;
1034 }
1035
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001036 /* Honor unnumbered interface, if any */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001037 is_unnum0 = sw_if_index0 != conn_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038
1039 /* Source must also be local to subnet of matching interface address. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001040 src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
1041 &arp0->ip4_over_ethernet[0].ip4,
1042 32);
1043 src_flags = fib_entry_get_flags (src_fei);
1044
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))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 {
1049 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001050 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 }
1052
1053 /* Reject requests/replies with our local interface address. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001054 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055 {
1056 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001057 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058 }
1059
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001060 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1061 fib_entry_get_prefix (dst_fei, &pfx0);
1062 if_addr0 = &pfx0.fp_addr.ip4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063
1064 /* Fill in ethernet header. */
1065 eth0 = ethernet_buffer_get_header (p0);
1066
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001067 /* 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)))
1071 {
1072 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1073 goto drop2;
1074 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075
1076 /* Learn or update sender's mapping only for requests or unicasts
1077 that don't match local interface address. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001078 if (ethernet_address_cast (eth0->dst_address) ==
1079 ETHERNET_ADDRESS_UNICAST || is_request0)
1080 {
1081 if (am->limit_arp_cache_size &&
1082 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1083 unset_random_arp_entry ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001085 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001086 &arp0->ip4_over_ethernet[0],
1087 0 /* is_static */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001089 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001090
1091 /* Only send a reply for requests sent which match a local interface. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001092 if (!(is_request0 && dst_is_local0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001094 error0 =
1095 (arp0->opcode ==
1096 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1097 ETHERNET_ARP_ERROR_replies_received : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098 goto drop1;
1099 }
1100
1101 /* Send a reply. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001102 send_reply:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1104 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1105
John Lod1f5d042016-04-12 18:20:39 -04001106 /* 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;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109
1110 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1111
1112 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1113
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001114 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) =
1117 if_addr0->data_u32;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118
1119 /* Hardware must be ethernet-like. */
1120 ASSERT (vec_len (hw_if0->hw_address) == 6);
1121
Damjan Marionf1213b82016-03-13 02:22:06 +01001122 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1123 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124
1125 /* Figure out how much to rewind current data from adjacency. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001126 /* get the adj from the destination's covering connected */
1127 if (NULL == pa)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001128 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001129 adj0 =
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)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001136 {
1137 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1138 goto drop2;
1139 }
1140 if (is_unnum0)
Neale Ranns436d06b2016-11-30 07:41:53 -08001141 {
1142 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1143 goto drop2;
1144 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001145 else
1146 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1147 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001148 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1149 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150
1151 n_replies_sent += 1;
1152 continue;
1153
1154 drop1:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001155 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))
1158 {
1159 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1160 goto drop2;
1161 }
1162 /* See if proxy arp is configured for the address */
1163 if (is_request0)
1164 {
1165 vnet_sw_interface_t *si;
1166 u32 this_addr = clib_net_to_host_u32
1167 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1168 u32 fib_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001170 si = vnet_get_sw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001171
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001172 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1173 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001175 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1176 sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001178 vec_foreach (pa, am->proxy_arps)
1179 {
1180 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1181 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001183 /* 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))
1186 {
1187 eth0 = ethernet_buffer_get_header (p0);
1188 proxy_src.as_u32 =
1189 arp0->ip4_over_ethernet[1].ip4.data_u32;
1190
Damjan Marion607de1a2016-08-16 22:53:54 +02001191 /*
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001192 * Rewind buffer, direct code above not to
Damjan Marion607de1a2016-08-16 22:53:54 +02001193 * think too hard about it.
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001194 */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001195 if_addr0 = &proxy_src;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001196 is_unnum0 = 0;
David Hotham62f88d82016-09-20 13:34:00 +00001197 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);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001201 n_proxy_arp_replies_sent++;
1202 goto send_reply;
1203 }
1204 }
1205 }
1206
1207 drop2:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208
1209 next0 = ARP_INPUT_NEXT_DROP;
1210 p0->error = node->errors[error0];
1211
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001212 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1213 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214 }
1215
1216 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1217 }
1218
1219 vlib_error_count (vm, node->node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001220 ETHERNET_ARP_ERROR_replies_sent,
1221 n_replies_sent - n_proxy_arp_replies_sent);
1222
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223 vlib_error_count (vm, node->node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001224 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1225 n_proxy_arp_replies_sent);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001226 return frame->n_vectors;
1227}
1228
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001229static char *ethernet_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001230#define _(sym,string) string,
1231 foreach_ethernet_arp_error
1232#undef _
1233};
1234
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001235/* *INDENT-OFF* */
1236VLIB_REGISTER_NODE (arp_input_node, static) =
1237{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238 .function = arp_input,
1239 .name = "arp-input",
1240 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241 .n_errors = ETHERNET_ARP_N_ERROR,
1242 .error_strings = ethernet_arp_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243 .n_next_nodes = ARP_INPUT_N_NEXT,
1244 .next_nodes = {
1245 [ARP_INPUT_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001246 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07001248 .format_buffer = format_ethernet_arp_header,
1249 .format_trace = format_ethernet_arp_input_trace,
1250};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001251/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001252
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253static int
1254ip4_arp_entry_sort (void *a1, void *a2)
1255{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001256 ethernet_arp_ip4_entry_t *e1 = a1;
1257 ethernet_arp_ip4_entry_t *e2 = a2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258
1259 int cmp;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001260 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001261
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001262 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001263 if (!cmp)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001264 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001265 return cmp;
1266}
1267
Pavel Kotucek3e046ea2016-12-05 08:27:37 +01001268ethernet_arp_ip4_entry_t *
1269ip4_neighbor_entries (u32 sw_if_index)
1270{
1271 ethernet_arp_main_t *am = &ethernet_arp_main;
1272 ethernet_arp_ip4_entry_t *n, *ns = 0;
1273
1274 /* *INDENT-OFF* */
1275 pool_foreach (n, am->ip4_entry_pool, ({
1276 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1277 continue;
1278 vec_add1 (ns, n[0]);
1279 }));
1280 /* *INDENT-ON* */
1281
1282 if (ns)
1283 vec_sort_with_function (ns, ip4_arp_entry_sort);
1284 return ns;
1285}
1286
Ed Warnickecb9cada2015-12-08 15:45:58 -07001287static clib_error_t *
1288show_ip4_arp (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001289 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001291 vnet_main_t *vnm = vnet_get_main ();
1292 ethernet_arp_main_t *am = &ethernet_arp_main;
1293 ethernet_arp_ip4_entry_t *e, *es;
1294 ethernet_proxy_arp_t *pa;
1295 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296 u32 sw_if_index;
1297
1298 /* Filter entries by interface if given. */
1299 sw_if_index = ~0;
1300 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1301
Pavel Kotucek3e046ea2016-12-05 08:27:37 +01001302 es = ip4_neighbor_entries (sw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001303 if (es)
Keith Wilescb466842016-02-11 19:21:10 -06001304 {
Keith Wilescb466842016-02-11 19:21:10 -06001305 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001306 vec_foreach (e, es)
1307 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001308 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
Keith Wilescb466842016-02-11 19:21:10 -06001309 }
1310 vec_free (es);
1311 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001312
1313 if (vec_len (am->proxy_arps))
1314 {
1315 vlib_cli_output (vm, "Proxy arps enabled for:");
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001316 vec_foreach (pa, am->proxy_arps)
1317 {
1318 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1319 pa->fib_index,
1320 format_ip4_address, &pa->lo_addr,
1321 format_ip4_address, &pa->hi_addr);
1322 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001324
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325 return error;
1326}
1327
Billy McFall2d085d92016-09-13 21:47:55 -04001328/*?
1329 * Display all the IPv4 ARP entries.
1330 *
1331 * @cliexpar
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
1340 * @cliexend
1341 ?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001342/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1344 .path = "show ip arp",
1345 .function = show_ip4_arp,
Billy McFall2d085d92016-09-13 21:47:55 -04001346 .short_help = "show ip arp",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001348/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001350typedef struct
1351{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001352 pg_edit_t l2_type, l3_type;
1353 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1354 pg_edit_t opcode;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001355 struct
1356 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357 pg_edit_t ethernet;
1358 pg_edit_t ip4;
1359 } ip4_over_ethernet[2];
1360} pg_ethernet_arp_header_t;
1361
1362static inline void
1363pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1364{
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);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001367 _(l2_type);
1368 _(l3_type);
1369 _(n_l2_address_bytes);
1370 _(n_l3_address_bytes);
1371 _(opcode);
1372 _(ip4_over_ethernet[0].ethernet);
1373 _(ip4_over_ethernet[0].ip4);
1374 _(ip4_over_ethernet[1].ethernet);
1375 _(ip4_over_ethernet[1].ip4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376#undef _
1377}
1378
1379uword
1380unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1381{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001382 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1383 pg_ethernet_arp_header_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001384 u32 group_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001385
Ed Warnickecb9cada2015-12-08 15:45:58 -07001386 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1387 &group_index);
1388 pg_ethernet_arp_header_init (p);
1389
1390 /* Defaults. */
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);
1395
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001396 if (!unformat (input, "%U: %U/%U -> %U/%U",
1397 unformat_pg_edit,
1398 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1399 unformat_pg_edit,
1400 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1401 unformat_pg_edit,
1402 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1403 unformat_pg_edit,
1404 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1405 unformat_pg_edit,
1406 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 {
1408 /* Free up any edits we may have added. */
1409 pg_free_edit_group (s);
1410 return 0;
1411 }
1412 return 1;
1413}
1414
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001415clib_error_t *
1416ip4_set_arp_limit (u32 arp_limit)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001418 ethernet_arp_main_t *am = &ethernet_arp_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419
1420 am->limit_arp_cache_size = arp_limit;
1421 return 0;
1422}
1423
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001424/**
1425 * @brief Control Plane hook to remove an ARP entry
1426 */
1427int
1428vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1429 u32 sw_if_index, void *a_arg)
Damjan Marion102ec522016-03-29 13:18:17 +02001430{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001431 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1432 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
Damjan Marion102ec522016-03-29 13:18:17 +02001433
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001434 args.sw_if_index = sw_if_index;
1435 args.flags = ETHERNET_ARP_ARGS_REMOVE;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001436 clib_memcpy (&args.a, a, sizeof (*a));
1437
1438 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1439 (u8 *) & args, sizeof (args));
1440 return 0;
1441}
1442
1443/**
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.
1448 */
1449static int
1450vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
Neale Rannsb80c5362016-10-08 13:03:40 +01001451 u32 sw_if_index, void *a_arg)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001452{
1453 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1454 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1455
1456 args.sw_if_index = sw_if_index;
1457 args.flags = ETHERNET_ARP_ARGS_FLUSH;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001458 clib_memcpy (&args.a, a, sizeof (*a));
1459
1460 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1461 (u8 *) & args, sizeof (args));
1462 return 0;
1463}
1464
1465/**
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.
1469 *
1470 * @param sw_if_index The interface on which the ARP entires are acted
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001471 */
1472static int
1473vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
Neale Rannsb80c5362016-10-08 13:03:40 +01001474 u32 sw_if_index, void *a_arg)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001475{
1476 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1477 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1478
1479 args.sw_if_index = sw_if_index;
1480 args.flags = ETHERNET_ARP_ARGS_POPULATE;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001481 clib_memcpy (&args.a, a, sizeof (*a));
1482
1483 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1484 (u8 *) & args, sizeof (args));
1485 return 0;
1486}
1487
1488/*
1489 * arp_add_del_interface_address
1490 *
1491 * callback when an interface address is added or deleted
1492 */
1493static void
1494arp_add_del_interface_address (ip4_main_t * im,
1495 uword opaque,
1496 u32 sw_if_index,
1497 ip4_address_t * address,
1498 u32 address_length,
1499 u32 if_address_index, u32 is_del)
1500{
1501 /*
1502 * Flush the ARP cache of all entries covered by the address
1503 * that is being removed.
1504 */
1505 ethernet_arp_main_t *am = &ethernet_arp_main;
1506 ethernet_arp_ip4_entry_t *e;
1507
Neale Ranns177bbdc2016-11-15 09:46:51 +00001508 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001509 return;
1510
1511 if (is_del)
Damjan Marion102ec522016-03-29 13:18:17 +02001512 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001513 ethernet_arp_interface_t *eai;
1514 u32 i, *to_delete = 0;
1515 hash_pair_t *pair;
1516
1517 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1518
Neale Rannsb80c5362016-10-08 13:03:40 +01001519 /* *INDENT-OFF* */
1520 hash_foreach_pair (pair, eai->arp_entries,
1521 ({
1522 e = pool_elt_at_index(am->ip4_entry_pool,
1523 pair->value[0]);
1524 if (ip4_destination_matches_route (im, &e->ip4_address,
1525 address, address_length))
1526 {
1527 vec_add1 (to_delete, e - am->ip4_entry_pool);
1528 }
1529 }));
1530 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001531
1532 for (i = 0; i < vec_len (to_delete); i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001533 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001534 ethernet_arp_ip4_over_ethernet_address_t delme;
1535 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1536
1537 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1538 delme.ip4.as_u32 = e->ip4_address.as_u32;
1539
1540 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
Neale Rannsb80c5362016-10-08 13:03:40 +01001541 e->sw_if_index, &delme);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001542 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001543
1544 vec_free (to_delete);
Damjan Marion102ec522016-03-29 13:18:17 +02001545 }
1546}
1547
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001548static clib_error_t *
1549ethernet_arp_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001550{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001551 ethernet_arp_main_t *am = &ethernet_arp_main;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001552 ip4_main_t *im = &ip4_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001553 clib_error_t *error;
1554 pg_node_t *pn;
Dave Barach1f49ed62016-02-24 11:29:06 -05001555
1556 if ((error = vlib_call_init_function (vm, ethernet_init)))
1557 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001558
1559 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1560
1561 pn = pg_get_node (arp_input_node.index);
1562 pn->unformat_edit = unformat_pg_arp_header;
1563
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;
1567#undef _
1568
Ed Warnickecb9cada2015-12-08 15:45:58 -07001569 /* $$$ configurable */
1570 am->limit_arp_cache_size = 50000;
1571
1572 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1573 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1574
1575 /* don't trace ARP error packets */
1576 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001577 vlib_node_runtime_t *rt =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001578 vlib_node_get_runtime (vm, arp_input_node.index);
1579
1580#define _(a,b) \
1581 vnet_pcap_drop_trace_filter_add_del \
1582 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1583 1 /* is_add */);
1584 foreach_ethernet_arp_error
1585#undef _
1586 }
Damjan Marion102ec522016-03-29 13:18:17 +02001587
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001588 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);
1592
Ed Warnickecb9cada2015-12-08 15:45:58 -07001593 return 0;
1594}
1595
1596VLIB_INIT_FUNCTION (ethernet_arp_init);
1597
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001598static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001599arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1600{
1601 ethernet_arp_main_t *am = &ethernet_arp_main;
1602
Neale Rannsb80c5362016-10-08 13:03:40 +01001603 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001604 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1605 pool_put (am->ip4_entry_pool, e);
1606}
1607
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001608static inline int
Ed Warnickecb9cada2015-12-08 15:45:58 -07001609vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001610 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1611 * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001613 ethernet_arp_main_t *am = &ethernet_arp_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001614 ethernet_arp_ip4_entry_t *e;
1615 ethernet_arp_interface_t *eai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001617 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001619 e = arp_entry_find (eai, &args->a.ip4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001621 if (NULL != e)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001622 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001623 arp_entry_free (eai, e);
Neale Ranns19c68d22016-12-07 15:38:14 +00001624
1625 adj_nbr_walk_nh4 (e->sw_if_index,
1626 &e->ip4_address, arp_mk_incomplete_walk, NULL);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001627 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001628
Ed Warnickecb9cada2015-12-08 15:45:58 -07001629 return 0;
1630}
1631
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001632static int
1633vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1634 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1635 * args)
1636{
1637 ethernet_arp_main_t *am = &ethernet_arp_main;
1638 ethernet_arp_ip4_entry_t *e;
1639 ethernet_arp_interface_t *eai;
1640
1641 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1642
1643 e = arp_entry_find (eai, &args->a.ip4);
1644
1645 if (NULL != e)
1646 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001647 adj_nbr_walk_nh4 (e->sw_if_index,
1648 &e->ip4_address, arp_mk_incomplete_walk, e);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001649
1650 /*
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.
1656 */
Neale Rannsb80c5362016-10-08 13:03:40 +01001657 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001658 {
1659 arp_entry_free (eai, e);
1660 }
1661 }
1662 return (0);
1663}
1664
1665static int
1666vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1667 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1668 * args)
1669{
1670 ethernet_arp_main_t *am = &ethernet_arp_main;
1671 ethernet_arp_ip4_entry_t *e;
1672 ethernet_arp_interface_t *eai;
1673
1674 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1675
1676 e = arp_entry_find (eai, &args->a.ip4);
1677
1678 if (NULL != e)
1679 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001680 adj_nbr_walk_nh4 (e->sw_if_index,
1681 &e->ip4_address, arp_mk_complete_walk, e);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001682 }
1683 return (0);
1684}
1685
1686static void
1687set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1688 * a)
1689{
1690 vnet_main_t *vm = vnet_get_main ();
1691 ASSERT (os_get_cpu_number () == 0);
1692
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);
1699 else
1700 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1701}
1702
1703/**
1704 * @brief Invoked when the interface's admin state changes
1705 */
1706static clib_error_t *
1707ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1708 u32 sw_if_index, u32 flags)
1709{
1710 ethernet_arp_main_t *am = &ethernet_arp_main;
1711 ethernet_arp_ip4_entry_t *e;
1712 u32 i, *to_delete = 0;
1713
1714 /* *INDENT-OFF* */
1715 pool_foreach (e, am->ip4_entry_pool,
1716 ({
1717 if (e->sw_if_index == sw_if_index)
Neale Rannsb80c5362016-10-08 13:03:40 +01001718 vec_add1 (to_delete,
1719 e - am->ip4_entry_pool);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001720 }));
1721 /* *INDENT-ON* */
1722
1723 for (i = 0; i < vec_len (to_delete); i++)
1724 {
1725 ethernet_arp_ip4_over_ethernet_address_t delme;
1726 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1727
1728 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1729 delme.ip4.as_u32 = e->ip4_address.as_u32;
1730
1731 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1732 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001733 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001734 }
1735 else
1736 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001737 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001738 }
1739
1740 }
1741 vec_free (to_delete);
1742
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001743 return 0;
1744}
1745
1746VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1747
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001748static void
1749increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750{
1751 u8 old;
1752 int i;
1753
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001754 for (i = 3; i >= 0; i--)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001755 {
1756 old = a->ip4.as_u8[i];
1757 a->ip4.as_u8[i] += 1;
1758 if (old < a->ip4.as_u8[i])
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001759 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001760 }
1761
1762 for (i = 5; i >= 0; i--)
1763 {
1764 old = a->ethernet[i];
1765 a->ethernet[i] += 1;
1766 if (old < a->ethernet[i])
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001767 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768 }
1769}
1770
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001771int
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001772vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1773 u32 sw_if_index, void *a_arg, int is_static)
1774{
1775 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1776 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1777
1778 args.sw_if_index = sw_if_index;
1779 args.is_static = is_static;
1780 args.flags = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001781 clib_memcpy (&args.a, a, sizeof (*a));
1782
1783 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1784 (u8 *) & args, sizeof (args));
1785 return 0;
1786}
1787
1788int
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001789vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1790 ip4_address_t * hi_addr, u32 fib_index, int is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001791{
1792 ethernet_arp_main_t *am = &ethernet_arp_main;
1793 ethernet_proxy_arp_t *pa;
1794 u32 found_at_index = ~0;
1795
1796 vec_foreach (pa, am->proxy_arps)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001797 {
1798 if (pa->lo_addr == lo_addr->as_u32
1799 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1800 {
1801 found_at_index = pa - am->proxy_arps;
1802 break;
1803 }
1804 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001805
1806 if (found_at_index != ~0)
1807 {
1808 /* Delete, otherwise it's already in the table */
1809 if (is_del)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001810 vec_delete (am->proxy_arps, 1, found_at_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811 return 0;
1812 }
1813 /* delete, no such entry */
1814 if (is_del)
1815 return VNET_API_ERROR_NO_SUCH_ENTRY;
1816
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;
1822 return 0;
1823}
1824
1825/*
Damjan Marion607de1a2016-08-16 22:53:54 +02001826 * Remove any proxy arp entries asdociated with the
Ed Warnickecb9cada2015-12-08 15:45:58 -07001827 * specificed fib.
1828 */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001829int
1830vnet_proxy_arp_fib_reset (u32 fib_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001831{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001832 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833 ethernet_arp_main_t *am = &ethernet_arp_main;
1834 ethernet_proxy_arp_t *pa;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001835 u32 *entries_to_delete = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836 u32 fib_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001837 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001838 int i;
1839
1840 p = hash_get (im->fib_index_by_table_id, fib_id);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001841 if (!p)
1842 return VNET_API_ERROR_NO_SUCH_ENTRY;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843 fib_index = p[0];
1844
1845 vec_foreach (pa, am->proxy_arps)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001846 {
1847 if (pa->fib_index == fib_index)
1848 {
1849 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1850 }
1851 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001853 for (i = 0; i < vec_len (entries_to_delete); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001854 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001855 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1856 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857
1858 vec_free (entries_to_delete);
1859
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001860 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861}
1862
1863static clib_error_t *
1864ip_arp_add_del_command_fn (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001865 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001867 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868 u32 sw_if_index;
1869 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1870 int addr_valid = 0;
1871 int is_del = 0;
1872 int count = 1;
1873 u32 fib_index = 0;
1874 u32 fib_id;
1875 int is_static = 0;
1876 int is_proxy = 0;
1877
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001878 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879 {
1880 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1881 if (unformat (input, "%U %U %U",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001882 unformat_vnet_sw_interface, vnm, &sw_if_index,
1883 unformat_ip4_address, &addr.ip4,
1884 unformat_ethernet_address, &addr.ethernet))
1885 addr_valid = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886
1887 else if (unformat (input, "delete") || unformat (input, "del"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001888 is_del = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001889
1890 else if (unformat (input, "static"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001891 is_static = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001892
1893 else if (unformat (input, "count %d", &count))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001894 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001895
1896 else if (unformat (input, "fib-id %d", &fib_id))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001897 {
1898 ip4_main_t *im = &ip4_main;
1899 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1900 if (!p)
1901 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1902 fib_index = p[0];
1903 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001904
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001905 else if (unformat (input, "proxy %U - %U",
1906 unformat_ip4_address, &lo_addr.ip4,
1907 unformat_ip4_address, &hi_addr.ip4))
1908 is_proxy = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001910 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001911 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001912
Ed Warnickecb9cada2015-12-08 15:45:58 -07001913 if (is_proxy)
1914 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001915 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1916 fib_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001917 return 0;
1918 }
1919
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001920 if (addr_valid)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921 {
1922 int i;
1923
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001924 for (i = 0; i < count; i++)
1925 {
1926 if (is_del == 0)
1927 {
1928 uword event_type, *event_data = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001929
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001930 /* 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 */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001934
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001935 vnet_arp_set_ip4_over_ethernet
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001936 (vnm, sw_if_index, &addr, is_static);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001937
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);
1943 }
1944 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001945 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001946
1947 increment_ip4_and_mac_address (&addr);
1948 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949 }
1950 else
1951 {
1952 return clib_error_return (0, "unknown input `%U'",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001953 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001954 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001955
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956 return 0;
1957}
1958
Neale Rannsb80c5362016-10-08 13:03:40 +01001959/* *INDENT-OFF* */
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07001960/*?
Billy McFall2d085d92016-09-13 21:47:55 -04001961 * Add or delete IPv4 ARP cache entries.
1962 *
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.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07001966 *
1967 * @cliexpar
Billy McFall2d085d92016-09-13 21:47:55 -04001968 * @parblock
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}
1973 *
1974 * To add or delete an IPv4 ARP cache entry to or from a specific fib
1975 * table:
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}
1978 *
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}
1982 *
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}
1986 * @endparblock
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07001987 ?*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07001988VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001989 .path = "set ip arp",
1990 .short_help =
Neale Rannsb80c5362016-10-08 13:03:40 +01001991 "set ip arp [del] <intfc> <ip-address> <mac-address> [static] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001992 .function = ip_arp_add_del_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001993};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001994/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995
1996static clib_error_t *
1997set_int_proxy_arp_command_fn (vlib_main_t * vm,
Neale Rannsb80c5362016-10-08 13:03:40 +01001998 unformat_input_t *
1999 input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002000{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002001 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002 u32 sw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002003 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004 int enable = 0;
2005 int intfc_set = 0;
2006
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002007 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002008 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002009 if (unformat (input, "%U", unformat_vnet_sw_interface,
2010 vnm, &sw_if_index))
2011 intfc_set = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 else if (unformat (input, "enable") || unformat (input, "on"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002013 enable = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002014 else if (unformat (input, "disable") || unformat (input, "off"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002015 enable = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002017 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 }
2019
2020 if (intfc_set == 0)
2021 return clib_error_return (0, "unknown input '%U'",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002022 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002023
2024 si = vnet_get_sw_interface (vnm, sw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002025 ASSERT (si);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002026 if (enable)
2027 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002028 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07002029 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002030
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 return 0;
2032}
2033
Neale Rannsb80c5362016-10-08 13:03:40 +01002034/* *INDENT-OFF* */
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002035/*?
Billy McFall2d085d92016-09-13 21:47:55 -04002036 * 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.
2039 *
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.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002043 *
2044 * @cliexpar
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002045 * To enable proxy arp on a range of addresses, use:
Billy McFall2d085d92016-09-13 21:47:55 -04002046 * @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}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002053 ?*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002055 .path = "set interface proxy-arp",
2056 .short_help =
Neale Rannsb80c5362016-10-08 13:03:40 +01002057 "set interface proxy-arp <intfc> [enable|disable]",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002058 .function = set_int_proxy_arp_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002059};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002060/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002061
2062
2063/*
John Lo1edfba92016-08-27 01:11:57 -04002064 * 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.
Ed Warnickecb9cada2015-12-08 15:45:58 -07002066 */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002067typedef enum
2068{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069 ARP_TERM_NEXT_L2_OUTPUT,
2070 ARP_TERM_NEXT_DROP,
2071 ARP_TERM_N_NEXT,
2072} arp_term_next_t;
2073
2074u32 arp_term_next_node_index[32];
2075
2076static uword
2077arp_term_l2bd (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002078 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002079{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002080 l2input_main_t *l2im = &l2input_main;
2081 u32 n_left_from, next_index, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002082 u32 n_replies_sent = 0;
2083 u16 last_bd_index = ~0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002084 l2_bridge_domain_t *last_bd_config = 0;
2085 l2_input_config_t *cfg0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002086
2087 from = vlib_frame_vector_args (frame);
2088 n_left_from = frame->n_vectors;
2089 next_index = node->cached_next_index;
2090
2091 while (n_left_from > 0)
2092 {
2093 u32 n_left_to_next;
2094
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002095 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002096
2097 while (n_left_from > 0 && n_left_to_next > 0)
2098 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002099 vlib_buffer_t *p0;
2100 ethernet_header_t *eth0;
2101 ethernet_arp_header_t *arp0;
John Lo1edfba92016-08-27 01:11:57 -04002102 ip6_header_t *iph0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002103 u8 *l3h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104 u32 pi0, error0, next0, sw_if_index0;
2105 u16 ethertype0;
2106 u16 bd_index0;
2107 u32 ip0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002108 u8 *macp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002109
2110 pi0 = from[0];
2111 to_next[0] = pi0;
2112 from += 1;
2113 to_next += 1;
2114 n_left_from -= 1;
2115 n_left_to_next -= 1;
2116
2117 p0 = vlib_get_buffer (vm, pi0);
2118 eth0 = vlib_buffer_get_current (p0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002119 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2120 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002121 arp0 = (ethernet_arp_header_t *) l3h0;
2122
John Lo1edfba92016-08-27 01:11:57 -04002123 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2124 (arp0->opcode !=
2125 clib_host_to_net_u16
2126 (ETHERNET_ARP_OPCODE_request))))
2127 goto check_ip6_nd;
2128
2129 /* Must be ARP request packet here */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002130 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2131 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2132 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002133 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));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002136 }
2137
Ed Warnickecb9cada2015-12-08 15:45:58 -07002138 error0 = ETHERNET_ARP_ERROR_replies_sent;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002139 error0 =
2140 (arp0->l2_type !=
Neale Rannsb80c5362016-10-08 13:03:40 +01002141 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2142 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002143 error0 =
2144 (arp0->l3_type !=
2145 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2146 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002147
2148 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2149
2150 if (error0)
2151 goto drop;
2152
John Lo1edfba92016-08-27 01:11:57 -04002153 /* Trash ARP packets whose ARP-level source addresses do not
2154 match their L2-frame-level source addresses */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002155 if (PREDICT_FALSE
2156 (memcmp
2157 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2158 sizeof (eth0->src_address))))
2159 {
2160 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2161 goto drop;
2162 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163
John Lo1edfba92016-08-27 01:11:57 -04002164 /* Check if anyone want ARP request events for L2 BDs */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002166 pending_resolution_t *mc;
2167 ethernet_arp_main_t *am = &ethernet_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)
2173 {
2174 int (*fp) (u32, u8 *, u32, u32);
2175 int rv = 1;
2176 mc = pool_elt_at_index (am->mac_changes, next_index);
2177 fp = mc->data_callback;
John Lo1edfba92016-08-27 01:11:57 -04002178 /* Call the callback, return 1 to suppress dup events */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002179 if (fp)
2180 rv = (*fp) (mc->data,
2181 arp0->ip4_over_ethernet[0].ethernet,
2182 sw_if_index0,
2183 arp0->ip4_over_ethernet[0].ip4.as_u32);
John Lo1edfba92016-08-27 01:11:57 -04002184 /* Signal the resolver process */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002185 if (rv == 0)
2186 vlib_process_signal_event (vm, mc->node_index,
2187 mc->type_opaque, mc->data);
2188 next_index = mc->next_index;
2189 }
2190 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002191 }
2192
John Lo1edfba92016-08-27 01:11:57 -04002193 /* lookup BD mac_by_ip4 hash table for MAC entry */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002195 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2196 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2197 || (last_bd_index == (u16) ~ 0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198 {
2199 last_bd_index = bd_index0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002200 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002201 }
2202 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2203
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002204 if (PREDICT_FALSE (!macp0))
John Lo1edfba92016-08-27 01:11:57 -04002205 goto next_l2_feature; /* MAC not found */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002206
John Lo1edfba92016-08-27 01:11:57 -04002207 /* MAC found, send ARP reply -
2208 Convert ARP request packet to ARP reply */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209 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;
Damjan Marionf1213b82016-03-13 02:22:06 +01002212 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);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002215 n_replies_sent += 1;
2216
John Lo1edfba92016-08-27 01:11:57 -04002217 output_response:
2218 /* For BVI, need to use l2-fwd node to send ARP reply as
2219 l2-output node cannot output packet to BVI properly */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002220 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002221 if (PREDICT_FALSE (cfg0->bvi))
2222 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002223 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002224 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2225 goto next_l2_feature;
2226 }
2227
John Lo1edfba92016-08-27 01:11:57 -04002228 /* Send ARP/ND reply back out input interface through l2-output */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002229 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2230 next0 = ARP_TERM_NEXT_L2_OUTPUT;
John Lo1edfba92016-08-27 01:11:57 -04002231 /* 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; */
Neale Rannsb80c5362016-10-08 13:03:40 +01002236 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2237 to_next, n_left_to_next, pi0,
2238 next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002239 continue;
2240
John Lo1edfba92016-08-27 01:11:57 -04002241 check_ip6_nd:
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 &&
John Lo1edfba92016-08-27 01:11:57 -04002247 !ip6_address_is_unspecified
2248 (&iph0->src_address)))
2249 {
2250 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
Neale Rannsb80c5362016-10-08 13:03:40 +01002251 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))
John Lo1edfba92016-08-27 01:11:57 -04002254 goto output_response;
2255 }
2256
Ed Warnickecb9cada2015-12-08 15:45:58 -07002257 next_l2_feature:
2258 {
2259 u32 feature_bitmap0 =
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002260 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2261 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
Neale Rannsb80c5362016-10-08 13:03:40 +01002262 next0 =
2263 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2264 feature_bitmap0);
2265 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2266 to_next, n_left_to_next,
2267 pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002268 continue;
2269 }
2270
2271 drop:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002272 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))
2275 {
2276 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2277 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 next0 = ARP_TERM_NEXT_DROP;
2279 p0->error = node->errors[error0];
2280
Neale Rannsb80c5362016-10-08 13:03:40 +01002281 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2282 to_next, n_left_to_next, pi0,
2283 next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002284 }
2285
2286 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2287 }
2288
2289 vlib_error_count (vm, node->node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002290 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002291 return frame->n_vectors;
2292}
2293
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002294/* *INDENT-OFF* */
2295VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002296 .function = arp_term_l2bd,
2297 .name = "arp-term-l2bd",
2298 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 .n_errors = ETHERNET_ARP_N_ERROR,
2300 .error_strings = ethernet_arp_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301 .n_next_nodes = ARP_TERM_N_NEXT,
2302 .next_nodes = {
2303 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2304 [ARP_TERM_NEXT_DROP] = "error-drop",
2305 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 .format_buffer = format_ethernet_arp_header,
John Lo1edfba92016-08-27 01:11:57 -04002307 .format_trace = format_arp_term_input_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002308};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002309/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002311clib_error_t *
2312arp_term_init (vlib_main_t * vm)
Neale Rannsb80c5362016-10-08 13:03:40 +01002313{
2314 // Initialize the feature next-node indexes
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002315 feat_bitmap_init_next_nodes (vm,
2316 arp_term_l2bd_node.index,
2317 L2INPUT_N_FEAT,
2318 l2input_get_feat_names (),
2319 arp_term_next_node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002320 return 0;
2321}
2322
2323VLIB_INIT_FUNCTION (arp_term_init);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002324
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002325void
2326change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2327{
2328 if (e->sw_if_index == sw_if_index)
2329 {
Neale Rannsb80c5362016-10-08 13:03:40 +01002330 adj_nbr_walk_nh4 (e->sw_if_index,
2331 &e->ip4_address, arp_mk_complete_walk, e);
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002332 }
2333}
2334
2335void
Neale Ranns3be6b282016-12-20 14:24:01 +00002336ethernet_arp_change_mac (u32 sw_if_index)
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002337{
2338 ethernet_arp_main_t *am = &ethernet_arp_main;
2339 ethernet_arp_ip4_entry_t *e;
2340
2341 /* *INDENT-OFF* */
2342 pool_foreach (e, am->ip4_entry_pool,
Neale Rannsb80c5362016-10-08 13:03:40 +01002343 ({
2344 change_arp_mac (sw_if_index, e);
2345 }));
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002346 /* *INDENT-ON* */
2347}
2348
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002349/*
2350 * fd.io coding-style-patch-verification: ON
2351 *
2352 * Local Variables:
2353 * eval: (c-set-style "gnu")
2354 * End:
2355 */