blob: 0298541bb46e0c4b0ab0d94a5f091356dbecd7ae [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) ||
Neale Ranns797235a2017-01-09 14:33:38 +01001046 (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 {
Neale Ranns797235a2017-01-09 14:33:38 +01001048 /*
1049 * The packet was sent from an address that is not connected nor attached
1050 * i.e. it is not from an address that is covered by a link's sub-net,
1051 * nor is it a already learned host resp.
1052 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053 error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001054 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055 }
Neale Ranns797235a2017-01-09 14:33:38 +01001056 if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
1057 {
1058 /*
1059 * The interface the ARP was received on is not the interface
1060 * on which the covering prefix is configured. Maybe this is a case
1061 * for unnumbered.
1062 */
1063 is_unnum0 = 1;
1064 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065
1066 /* Reject requests/replies with our local interface address. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001067 if (FIB_ENTRY_FLAG_LOCAL & src_flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 {
1069 error0 = ETHERNET_ARP_ERROR_l3_src_address_is_local;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001070 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 }
1072
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001073 dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
1074 fib_entry_get_prefix (dst_fei, &pfx0);
1075 if_addr0 = &pfx0.fp_addr.ip4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076
1077 /* Fill in ethernet header. */
1078 eth0 = ethernet_buffer_get_header (p0);
1079
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001080 /* Trash ARP packets whose ARP-level source addresses do not
1081 match their L2-frame-level source addresses */
1082 if (memcmp (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
1083 sizeof (eth0->src_address)))
1084 {
1085 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
1086 goto drop2;
1087 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088
1089 /* Learn or update sender's mapping only for requests or unicasts
1090 that don't match local interface address. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001091 if (ethernet_address_cast (eth0->dst_address) ==
1092 ETHERNET_ADDRESS_UNICAST || is_request0)
1093 {
1094 if (am->limit_arp_cache_size &&
1095 pool_elts (am->ip4_entry_pool) >= am->limit_arp_cache_size)
1096 unset_random_arp_entry ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001098 vnet_arp_set_ip4_over_ethernet (vnm, sw_if_index0,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001099 &arp0->ip4_over_ethernet[0],
1100 0 /* is_static */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101 error0 = ETHERNET_ARP_ERROR_l3_src_address_learned;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001102 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103
1104 /* Only send a reply for requests sent which match a local interface. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001105 if (!(is_request0 && dst_is_local0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001107 error0 =
1108 (arp0->opcode ==
1109 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply) ?
1110 ETHERNET_ARP_ERROR_replies_received : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 goto drop1;
1112 }
1113
1114 /* Send a reply. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001115 send_reply:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1117 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1118
John Lod1f5d042016-04-12 18:20:39 -04001119 /* Send reply back through input interface */
1120 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1121 next0 = ARP_INPUT_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122
1123 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
1124
1125 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
1126
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001127 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
1128 hw_if0->hw_address, 6);
1129 clib_mem_unaligned (&arp0->ip4_over_ethernet[0].ip4.data_u32, u32) =
1130 if_addr0->data_u32;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001131
1132 /* Hardware must be ethernet-like. */
1133 ASSERT (vec_len (hw_if0->hw_address) == 6);
1134
Damjan Marionf1213b82016-03-13 02:22:06 +01001135 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1136 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137
1138 /* Figure out how much to rewind current data from adjacency. */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001139 /* get the adj from the destination's covering connected */
1140 if (NULL == pa)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001141 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001142 adj0 =
1143 adj_get (fib_entry_get_adj_for_source
1144 (ip4_fib_table_lookup
1145 (ip4_fib_get (fib_index0),
1146 &arp0->ip4_over_ethernet[1].ip4, 31),
1147 FIB_SOURCE_INTERFACE));
1148 if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001149 {
1150 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
1151 goto drop2;
1152 }
1153 if (is_unnum0)
Neale Ranns436d06b2016-11-30 07:41:53 -08001154 {
1155 if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
1156 goto drop2;
1157 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001158 else
1159 vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
1160 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001161 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1162 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163
1164 n_replies_sent += 1;
1165 continue;
1166
1167 drop1:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001168 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
1169 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
1170 arp0->ip4_over_ethernet[1].ip4.as_u32))
1171 {
1172 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
1173 goto drop2;
1174 }
1175 /* See if proxy arp is configured for the address */
1176 if (is_request0)
1177 {
1178 vnet_sw_interface_t *si;
1179 u32 this_addr = clib_net_to_host_u32
1180 (arp0->ip4_over_ethernet[1].ip4.as_u32);
1181 u32 fib_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001183 si = vnet_get_sw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001185 if (!(si->flags & VNET_SW_INTERFACE_FLAG_PROXY_ARP))
1186 goto drop2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001188 fib_index0 = vec_elt (im4->fib_index_by_sw_if_index,
1189 sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001191 vec_foreach (pa, am->proxy_arps)
1192 {
1193 u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr);
1194 u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001196 /* an ARP request hit in the proxy-arp table? */
1197 if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
1198 (fib_index0 == pa->fib_index))
1199 {
1200 eth0 = ethernet_buffer_get_header (p0);
1201 proxy_src.as_u32 =
1202 arp0->ip4_over_ethernet[1].ip4.data_u32;
1203
Damjan Marion607de1a2016-08-16 22:53:54 +02001204 /*
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001205 * Rewind buffer, direct code above not to
Damjan Marion607de1a2016-08-16 22:53:54 +02001206 * think too hard about it.
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001207 */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001208 if_addr0 = &proxy_src;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001209 is_unnum0 = 0;
David Hotham62f88d82016-09-20 13:34:00 +00001210 i32 ethernet_start =
1211 vnet_buffer (p0)->ethernet.start_of_ethernet_header;
1212 i32 rewind = p0->current_data - ethernet_start;
1213 vlib_buffer_advance (p0, -rewind);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001214 n_proxy_arp_replies_sent++;
1215 goto send_reply;
1216 }
1217 }
1218 }
1219
1220 drop2:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221
1222 next0 = ARP_INPUT_NEXT_DROP;
1223 p0->error = node->errors[error0];
1224
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001225 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1226 n_left_to_next, pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227 }
1228
1229 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1230 }
1231
1232 vlib_error_count (vm, node->node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001233 ETHERNET_ARP_ERROR_replies_sent,
1234 n_replies_sent - n_proxy_arp_replies_sent);
1235
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236 vlib_error_count (vm, node->node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001237 ETHERNET_ARP_ERROR_proxy_arp_replies_sent,
1238 n_proxy_arp_replies_sent);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239 return frame->n_vectors;
1240}
1241
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001242static char *ethernet_arp_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243#define _(sym,string) string,
1244 foreach_ethernet_arp_error
1245#undef _
1246};
1247
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001248/* *INDENT-OFF* */
1249VLIB_REGISTER_NODE (arp_input_node, static) =
1250{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001251 .function = arp_input,
1252 .name = "arp-input",
1253 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254 .n_errors = ETHERNET_ARP_N_ERROR,
1255 .error_strings = ethernet_arp_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256 .n_next_nodes = ARP_INPUT_N_NEXT,
1257 .next_nodes = {
1258 [ARP_INPUT_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001259 [ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001260 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07001261 .format_buffer = format_ethernet_arp_header,
1262 .format_trace = format_ethernet_arp_input_trace,
1263};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001264/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001265
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266static int
1267ip4_arp_entry_sort (void *a1, void *a2)
1268{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001269 ethernet_arp_ip4_entry_t *e1 = a1;
1270 ethernet_arp_ip4_entry_t *e2 = a2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271
1272 int cmp;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001273 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001274
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001275 cmp = vnet_sw_interface_compare (vnm, e1->sw_if_index, e2->sw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001276 if (!cmp)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001277 cmp = ip4_address_compare (&e1->ip4_address, &e2->ip4_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001278 return cmp;
1279}
1280
Pavel Kotucek3e046ea2016-12-05 08:27:37 +01001281ethernet_arp_ip4_entry_t *
1282ip4_neighbor_entries (u32 sw_if_index)
1283{
1284 ethernet_arp_main_t *am = &ethernet_arp_main;
1285 ethernet_arp_ip4_entry_t *n, *ns = 0;
1286
1287 /* *INDENT-OFF* */
1288 pool_foreach (n, am->ip4_entry_pool, ({
1289 if (sw_if_index != ~0 && n->sw_if_index != sw_if_index)
1290 continue;
1291 vec_add1 (ns, n[0]);
1292 }));
1293 /* *INDENT-ON* */
1294
1295 if (ns)
1296 vec_sort_with_function (ns, ip4_arp_entry_sort);
1297 return ns;
1298}
1299
Ed Warnickecb9cada2015-12-08 15:45:58 -07001300static clib_error_t *
1301show_ip4_arp (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001302 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001304 vnet_main_t *vnm = vnet_get_main ();
1305 ethernet_arp_main_t *am = &ethernet_arp_main;
1306 ethernet_arp_ip4_entry_t *e, *es;
1307 ethernet_proxy_arp_t *pa;
1308 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309 u32 sw_if_index;
1310
1311 /* Filter entries by interface if given. */
1312 sw_if_index = ~0;
1313 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1314
Pavel Kotucek3e046ea2016-12-05 08:27:37 +01001315 es = ip4_neighbor_entries (sw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001316 if (es)
Keith Wilescb466842016-02-11 19:21:10 -06001317 {
Keith Wilescb466842016-02-11 19:21:10 -06001318 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, 0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001319 vec_foreach (e, es)
1320 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001321 vlib_cli_output (vm, "%U", format_ethernet_arp_ip4_entry, vnm, e);
Keith Wilescb466842016-02-11 19:21:10 -06001322 }
1323 vec_free (es);
1324 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325
1326 if (vec_len (am->proxy_arps))
1327 {
1328 vlib_cli_output (vm, "Proxy arps enabled for:");
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001329 vec_foreach (pa, am->proxy_arps)
1330 {
1331 vlib_cli_output (vm, "Fib_index %d %U - %U ",
1332 pa->fib_index,
1333 format_ip4_address, &pa->lo_addr,
1334 format_ip4_address, &pa->hi_addr);
1335 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001336 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001337
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338 return error;
1339}
1340
Billy McFall2d085d92016-09-13 21:47:55 -04001341/*?
1342 * Display all the IPv4 ARP entries.
1343 *
1344 * @cliexpar
1345 * Example of how to display the IPv4 ARP table:
1346 * @cliexstart{show ip arp}
1347 * Time FIB IP4 Flags Ethernet Interface
1348 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1349 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1350 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1351 * Proxy arps enabled for:
1352 * Fib_index 0 6.0.0.1 - 6.0.0.11
1353 * @cliexend
1354 ?*/
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001355/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001356VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
1357 .path = "show ip arp",
1358 .function = show_ip4_arp,
Billy McFall2d085d92016-09-13 21:47:55 -04001359 .short_help = "show ip arp",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001360};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001361/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001363typedef struct
1364{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365 pg_edit_t l2_type, l3_type;
1366 pg_edit_t n_l2_address_bytes, n_l3_address_bytes;
1367 pg_edit_t opcode;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001368 struct
1369 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001370 pg_edit_t ethernet;
1371 pg_edit_t ip4;
1372 } ip4_over_ethernet[2];
1373} pg_ethernet_arp_header_t;
1374
1375static inline void
1376pg_ethernet_arp_header_init (pg_ethernet_arp_header_t * p)
1377{
1378 /* Initialize fields that are not bit fields in the IP header. */
1379#define _(f) pg_edit_init (&p->f, ethernet_arp_header_t, f);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001380 _(l2_type);
1381 _(l3_type);
1382 _(n_l2_address_bytes);
1383 _(n_l3_address_bytes);
1384 _(opcode);
1385 _(ip4_over_ethernet[0].ethernet);
1386 _(ip4_over_ethernet[0].ip4);
1387 _(ip4_over_ethernet[1].ethernet);
1388 _(ip4_over_ethernet[1].ip4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389#undef _
1390}
1391
1392uword
1393unformat_pg_arp_header (unformat_input_t * input, va_list * args)
1394{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001395 pg_stream_t *s = va_arg (*args, pg_stream_t *);
1396 pg_ethernet_arp_header_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 u32 group_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001398
Ed Warnickecb9cada2015-12-08 15:45:58 -07001399 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ethernet_arp_header_t),
1400 &group_index);
1401 pg_ethernet_arp_header_init (p);
1402
1403 /* Defaults. */
1404 pg_edit_set_fixed (&p->l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1405 pg_edit_set_fixed (&p->l3_type, ETHERNET_TYPE_IP4);
1406 pg_edit_set_fixed (&p->n_l2_address_bytes, 6);
1407 pg_edit_set_fixed (&p->n_l3_address_bytes, 4);
1408
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001409 if (!unformat (input, "%U: %U/%U -> %U/%U",
1410 unformat_pg_edit,
1411 unformat_ethernet_arp_opcode_net_byte_order, &p->opcode,
1412 unformat_pg_edit,
1413 unformat_ethernet_address, &p->ip4_over_ethernet[0].ethernet,
1414 unformat_pg_edit,
1415 unformat_ip4_address, &p->ip4_over_ethernet[0].ip4,
1416 unformat_pg_edit,
1417 unformat_ethernet_address, &p->ip4_over_ethernet[1].ethernet,
1418 unformat_pg_edit,
1419 unformat_ip4_address, &p->ip4_over_ethernet[1].ip4))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001420 {
1421 /* Free up any edits we may have added. */
1422 pg_free_edit_group (s);
1423 return 0;
1424 }
1425 return 1;
1426}
1427
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001428clib_error_t *
1429ip4_set_arp_limit (u32 arp_limit)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001431 ethernet_arp_main_t *am = &ethernet_arp_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432
1433 am->limit_arp_cache_size = arp_limit;
1434 return 0;
1435}
1436
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001437/**
1438 * @brief Control Plane hook to remove an ARP entry
1439 */
1440int
1441vnet_arp_unset_ip4_over_ethernet (vnet_main_t * vnm,
1442 u32 sw_if_index, void *a_arg)
Damjan Marion102ec522016-03-29 13:18:17 +02001443{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001444 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1445 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
Damjan Marion102ec522016-03-29 13:18:17 +02001446
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001447 args.sw_if_index = sw_if_index;
1448 args.flags = ETHERNET_ARP_ARGS_REMOVE;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001449 clib_memcpy (&args.a, a, sizeof (*a));
1450
1451 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1452 (u8 *) & args, sizeof (args));
1453 return 0;
1454}
1455
1456/**
1457 * @brief Internally generated event to flush the ARP cache on an
1458 * interface state change event.
1459 * A flush will remove dynamic ARP entries, and for statics remove the MAC
1460 * address from the corresponding adjacencies.
1461 */
1462static int
1463vnet_arp_flush_ip4_over_ethernet (vnet_main_t * vnm,
Neale Rannsb80c5362016-10-08 13:03:40 +01001464 u32 sw_if_index, void *a_arg)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001465{
1466 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1467 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1468
1469 args.sw_if_index = sw_if_index;
1470 args.flags = ETHERNET_ARP_ARGS_FLUSH;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001471 clib_memcpy (&args.a, a, sizeof (*a));
1472
1473 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1474 (u8 *) & args, sizeof (args));
1475 return 0;
1476}
1477
1478/**
1479 * @brief Internally generated event to populate the ARP cache on an
1480 * interface state change event.
1481 * For static entries this will re-source the adjacencies.
1482 *
1483 * @param sw_if_index The interface on which the ARP entires are acted
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001484 */
1485static int
1486vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
Neale Rannsb80c5362016-10-08 13:03:40 +01001487 u32 sw_if_index, void *a_arg)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001488{
1489 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1490 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1491
1492 args.sw_if_index = sw_if_index;
1493 args.flags = ETHERNET_ARP_ARGS_POPULATE;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001494 clib_memcpy (&args.a, a, sizeof (*a));
1495
1496 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1497 (u8 *) & args, sizeof (args));
1498 return 0;
1499}
1500
1501/*
1502 * arp_add_del_interface_address
1503 *
1504 * callback when an interface address is added or deleted
1505 */
1506static void
1507arp_add_del_interface_address (ip4_main_t * im,
1508 uword opaque,
1509 u32 sw_if_index,
1510 ip4_address_t * address,
1511 u32 address_length,
1512 u32 if_address_index, u32 is_del)
1513{
1514 /*
1515 * Flush the ARP cache of all entries covered by the address
1516 * that is being removed.
1517 */
1518 ethernet_arp_main_t *am = &ethernet_arp_main;
1519 ethernet_arp_ip4_entry_t *e;
1520
Neale Ranns177bbdc2016-11-15 09:46:51 +00001521 if (vec_len (am->ethernet_arp_by_sw_if_index) <= sw_if_index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001522 return;
1523
1524 if (is_del)
Damjan Marion102ec522016-03-29 13:18:17 +02001525 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001526 ethernet_arp_interface_t *eai;
1527 u32 i, *to_delete = 0;
1528 hash_pair_t *pair;
1529
1530 eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
1531
Neale Rannsb80c5362016-10-08 13:03:40 +01001532 /* *INDENT-OFF* */
1533 hash_foreach_pair (pair, eai->arp_entries,
1534 ({
1535 e = pool_elt_at_index(am->ip4_entry_pool,
1536 pair->value[0]);
1537 if (ip4_destination_matches_route (im, &e->ip4_address,
1538 address, address_length))
1539 {
1540 vec_add1 (to_delete, e - am->ip4_entry_pool);
1541 }
1542 }));
1543 /* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001544
1545 for (i = 0; i < vec_len (to_delete); i++)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001546 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001547 ethernet_arp_ip4_over_ethernet_address_t delme;
1548 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1549
1550 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1551 delme.ip4.as_u32 = e->ip4_address.as_u32;
1552
1553 vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
Neale Rannsb80c5362016-10-08 13:03:40 +01001554 e->sw_if_index, &delme);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001555 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001556
1557 vec_free (to_delete);
Damjan Marion102ec522016-03-29 13:18:17 +02001558 }
1559}
1560
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001561static clib_error_t *
1562ethernet_arp_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001563{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001564 ethernet_arp_main_t *am = &ethernet_arp_main;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001565 ip4_main_t *im = &ip4_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001566 clib_error_t *error;
1567 pg_node_t *pn;
Dave Barach1f49ed62016-02-24 11:29:06 -05001568
1569 if ((error = vlib_call_init_function (vm, ethernet_init)))
1570 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001571
1572 ethernet_register_input_type (vm, ETHERNET_TYPE_ARP, arp_input_node.index);
1573
1574 pn = pg_get_node (arp_input_node.index);
1575 pn->unformat_edit = unformat_pg_arp_header;
1576
1577 am->opcode_by_name = hash_create_string (0, sizeof (uword));
1578#define _(o) hash_set_mem (am->opcode_by_name, #o, ETHERNET_ARP_OPCODE_##o);
1579 foreach_ethernet_arp_opcode;
1580#undef _
1581
Ed Warnickecb9cada2015-12-08 15:45:58 -07001582 /* $$$ configurable */
1583 am->limit_arp_cache_size = 50000;
1584
1585 am->pending_resolutions_by_address = hash_create (0, sizeof (uword));
1586 am->mac_changes_by_address = hash_create (0, sizeof (uword));
1587
1588 /* don't trace ARP error packets */
1589 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001590 vlib_node_runtime_t *rt =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001591 vlib_node_get_runtime (vm, arp_input_node.index);
1592
1593#define _(a,b) \
1594 vnet_pcap_drop_trace_filter_add_del \
1595 (rt->errors[ETHERNET_ARP_ERROR_##a], \
1596 1 /* is_add */);
1597 foreach_ethernet_arp_error
1598#undef _
1599 }
Damjan Marion102ec522016-03-29 13:18:17 +02001600
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001601 ip4_add_del_interface_address_callback_t cb;
1602 cb.function = arp_add_del_interface_address;
1603 cb.function_opaque = 0;
1604 vec_add1 (im->add_del_interface_address_callbacks, cb);
1605
Ed Warnickecb9cada2015-12-08 15:45:58 -07001606 return 0;
1607}
1608
1609VLIB_INIT_FUNCTION (ethernet_arp_init);
1610
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001611static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001612arp_entry_free (ethernet_arp_interface_t * eai, ethernet_arp_ip4_entry_t * e)
1613{
1614 ethernet_arp_main_t *am = &ethernet_arp_main;
1615
Neale Rannsb80c5362016-10-08 13:03:40 +01001616 fib_table_entry_delete_index (e->fib_entry_index, FIB_SOURCE_ADJ);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001617 hash_unset (eai->arp_entries, e->ip4_address.as_u32);
1618 pool_put (am->ip4_entry_pool, e);
1619}
1620
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001621static inline int
Ed Warnickecb9cada2015-12-08 15:45:58 -07001622vnet_arp_unset_ip4_over_ethernet_internal (vnet_main_t * vnm,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001623 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1624 * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001626 ethernet_arp_main_t *am = &ethernet_arp_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001627 ethernet_arp_ip4_entry_t *e;
1628 ethernet_arp_interface_t *eai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001629
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001630 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001631
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001632 e = arp_entry_find (eai, &args->a.ip4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001634 if (NULL != e)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001635 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001636 arp_entry_free (eai, e);
Neale Ranns19c68d22016-12-07 15:38:14 +00001637
1638 adj_nbr_walk_nh4 (e->sw_if_index,
1639 &e->ip4_address, arp_mk_incomplete_walk, NULL);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001640 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641
Ed Warnickecb9cada2015-12-08 15:45:58 -07001642 return 0;
1643}
1644
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001645static int
1646vnet_arp_flush_ip4_over_ethernet_internal (vnet_main_t * vnm,
1647 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1648 * args)
1649{
1650 ethernet_arp_main_t *am = &ethernet_arp_main;
1651 ethernet_arp_ip4_entry_t *e;
1652 ethernet_arp_interface_t *eai;
1653
1654 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1655
1656 e = arp_entry_find (eai, &args->a.ip4);
1657
1658 if (NULL != e)
1659 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001660 adj_nbr_walk_nh4 (e->sw_if_index,
1661 &e->ip4_address, arp_mk_incomplete_walk, e);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001662
1663 /*
1664 * The difference between flush and unset, is that an unset
1665 * means delete for static and dynamic entries. A flush
1666 * means delete only for dynamic. Flushing is what the DP
1667 * does in response to interface events. unset is only done
1668 * by the control plane.
1669 */
Neale Rannsb80c5362016-10-08 13:03:40 +01001670 if (e->flags & ETHERNET_ARP_IP4_ENTRY_FLAG_DYNAMIC)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001671 {
1672 arp_entry_free (eai, e);
1673 }
1674 }
1675 return (0);
1676}
1677
1678static int
1679vnet_arp_populate_ip4_over_ethernet_internal (vnet_main_t * vnm,
1680 vnet_arp_set_ip4_over_ethernet_rpc_args_t
1681 * args)
1682{
1683 ethernet_arp_main_t *am = &ethernet_arp_main;
1684 ethernet_arp_ip4_entry_t *e;
1685 ethernet_arp_interface_t *eai;
1686
1687 eai = &am->ethernet_arp_by_sw_if_index[args->sw_if_index];
1688
1689 e = arp_entry_find (eai, &args->a.ip4);
1690
1691 if (NULL != e)
1692 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001693 adj_nbr_walk_nh4 (e->sw_if_index,
1694 &e->ip4_address, arp_mk_complete_walk, e);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001695 }
1696 return (0);
1697}
1698
1699static void
1700set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t
1701 * a)
1702{
1703 vnet_main_t *vm = vnet_get_main ();
1704 ASSERT (os_get_cpu_number () == 0);
1705
1706 if (a->flags & ETHERNET_ARP_ARGS_REMOVE)
1707 vnet_arp_unset_ip4_over_ethernet_internal (vm, a);
1708 else if (a->flags & ETHERNET_ARP_ARGS_FLUSH)
1709 vnet_arp_flush_ip4_over_ethernet_internal (vm, a);
1710 else if (a->flags & ETHERNET_ARP_ARGS_POPULATE)
1711 vnet_arp_populate_ip4_over_ethernet_internal (vm, a);
1712 else
1713 vnet_arp_set_ip4_over_ethernet_internal (vm, a);
1714}
1715
1716/**
1717 * @brief Invoked when the interface's admin state changes
1718 */
1719static clib_error_t *
1720ethernet_arp_sw_interface_up_down (vnet_main_t * vnm,
1721 u32 sw_if_index, u32 flags)
1722{
1723 ethernet_arp_main_t *am = &ethernet_arp_main;
1724 ethernet_arp_ip4_entry_t *e;
1725 u32 i, *to_delete = 0;
1726
1727 /* *INDENT-OFF* */
1728 pool_foreach (e, am->ip4_entry_pool,
1729 ({
1730 if (e->sw_if_index == sw_if_index)
Neale Rannsb80c5362016-10-08 13:03:40 +01001731 vec_add1 (to_delete,
1732 e - am->ip4_entry_pool);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001733 }));
1734 /* *INDENT-ON* */
1735
1736 for (i = 0; i < vec_len (to_delete); i++)
1737 {
1738 ethernet_arp_ip4_over_ethernet_address_t delme;
1739 e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
1740
1741 clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
1742 delme.ip4.as_u32 = e->ip4_address.as_u32;
1743
1744 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1745 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001746 vnet_arp_populate_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001747 }
1748 else
1749 {
Neale Rannsb80c5362016-10-08 13:03:40 +01001750 vnet_arp_flush_ip4_over_ethernet (vnm, e->sw_if_index, &delme);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001751 }
1752
1753 }
1754 vec_free (to_delete);
1755
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001756 return 0;
1757}
1758
1759VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ethernet_arp_sw_interface_up_down);
1760
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001761static void
1762increment_ip4_and_mac_address (ethernet_arp_ip4_over_ethernet_address_t * a)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001763{
1764 u8 old;
1765 int i;
1766
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001767 for (i = 3; i >= 0; i--)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768 {
1769 old = a->ip4.as_u8[i];
1770 a->ip4.as_u8[i] += 1;
1771 if (old < a->ip4.as_u8[i])
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001772 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 }
1774
1775 for (i = 5; i >= 0; i--)
1776 {
1777 old = a->ethernet[i];
1778 a->ethernet[i] += 1;
1779 if (old < a->ethernet[i])
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001780 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001781 }
1782}
1783
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001784int
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001785vnet_arp_set_ip4_over_ethernet (vnet_main_t * vnm,
1786 u32 sw_if_index, void *a_arg, int is_static)
1787{
1788 ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
1789 vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
1790
1791 args.sw_if_index = sw_if_index;
1792 args.is_static = is_static;
1793 args.flags = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001794 clib_memcpy (&args.a, a, sizeof (*a));
1795
1796 vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
1797 (u8 *) & args, sizeof (args));
1798 return 0;
1799}
1800
1801int
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001802vnet_proxy_arp_add_del (ip4_address_t * lo_addr,
1803 ip4_address_t * hi_addr, u32 fib_index, int is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804{
1805 ethernet_arp_main_t *am = &ethernet_arp_main;
1806 ethernet_proxy_arp_t *pa;
1807 u32 found_at_index = ~0;
1808
1809 vec_foreach (pa, am->proxy_arps)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001810 {
1811 if (pa->lo_addr == lo_addr->as_u32
1812 && pa->hi_addr == hi_addr->as_u32 && pa->fib_index == fib_index)
1813 {
1814 found_at_index = pa - am->proxy_arps;
1815 break;
1816 }
1817 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818
1819 if (found_at_index != ~0)
1820 {
1821 /* Delete, otherwise it's already in the table */
1822 if (is_del)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001823 vec_delete (am->proxy_arps, 1, found_at_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824 return 0;
1825 }
1826 /* delete, no such entry */
1827 if (is_del)
1828 return VNET_API_ERROR_NO_SUCH_ENTRY;
1829
1830 /* add, not in table */
1831 vec_add2 (am->proxy_arps, pa, 1);
1832 pa->lo_addr = lo_addr->as_u32;
1833 pa->hi_addr = hi_addr->as_u32;
1834 pa->fib_index = fib_index;
1835 return 0;
1836}
1837
1838/*
Damjan Marion607de1a2016-08-16 22:53:54 +02001839 * Remove any proxy arp entries asdociated with the
Ed Warnickecb9cada2015-12-08 15:45:58 -07001840 * specificed fib.
1841 */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001842int
1843vnet_proxy_arp_fib_reset (u32 fib_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001844{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001845 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001846 ethernet_arp_main_t *am = &ethernet_arp_main;
1847 ethernet_proxy_arp_t *pa;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001848 u32 *entries_to_delete = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001849 u32 fib_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001850 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851 int i;
1852
1853 p = hash_get (im->fib_index_by_table_id, fib_id);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001854 if (!p)
1855 return VNET_API_ERROR_NO_SUCH_ENTRY;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856 fib_index = p[0];
1857
1858 vec_foreach (pa, am->proxy_arps)
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001859 {
1860 if (pa->fib_index == fib_index)
1861 {
1862 vec_add1 (entries_to_delete, pa - am->proxy_arps);
1863 }
1864 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001866 for (i = 0; i < vec_len (entries_to_delete); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001867 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001868 vec_delete (am->proxy_arps, 1, entries_to_delete[i]);
1869 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870
1871 vec_free (entries_to_delete);
1872
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001873 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001874}
1875
1876static clib_error_t *
1877ip_arp_add_del_command_fn (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001878 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001880 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001881 u32 sw_if_index;
1882 ethernet_arp_ip4_over_ethernet_address_t lo_addr, hi_addr, addr;
1883 int addr_valid = 0;
1884 int is_del = 0;
1885 int count = 1;
1886 u32 fib_index = 0;
1887 u32 fib_id;
1888 int is_static = 0;
1889 int is_proxy = 0;
1890
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001891 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001892 {
1893 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
1894 if (unformat (input, "%U %U %U",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001895 unformat_vnet_sw_interface, vnm, &sw_if_index,
1896 unformat_ip4_address, &addr.ip4,
1897 unformat_ethernet_address, &addr.ethernet))
1898 addr_valid = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001899
1900 else if (unformat (input, "delete") || unformat (input, "del"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001901 is_del = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902
1903 else if (unformat (input, "static"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001904 is_static = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905
1906 else if (unformat (input, "count %d", &count))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001907 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001908
1909 else if (unformat (input, "fib-id %d", &fib_id))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001910 {
1911 ip4_main_t *im = &ip4_main;
1912 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
1913 if (!p)
1914 return clib_error_return (0, "fib ID %d doesn't exist\n", fib_id);
1915 fib_index = p[0];
1916 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001917
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001918 else if (unformat (input, "proxy %U - %U",
1919 unformat_ip4_address, &lo_addr.ip4,
1920 unformat_ip4_address, &hi_addr.ip4))
1921 is_proxy = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001922 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001923 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001924 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001925
Ed Warnickecb9cada2015-12-08 15:45:58 -07001926 if (is_proxy)
1927 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001928 (void) vnet_proxy_arp_add_del (&lo_addr.ip4, &hi_addr.ip4,
1929 fib_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001930 return 0;
1931 }
1932
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001933 if (addr_valid)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001934 {
1935 int i;
1936
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001937 for (i = 0; i < count; i++)
1938 {
1939 if (is_del == 0)
1940 {
1941 uword event_type, *event_data = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001943 /* Park the debug CLI until the arp entry is installed */
1944 vnet_register_ip4_arp_resolution_event
1945 (vnm, &addr.ip4, vlib_current_process (vm),
1946 1 /* type */ , 0 /* data */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001947
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001948 vnet_arp_set_ip4_over_ethernet
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001949 (vnm, sw_if_index, &addr, is_static);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001950
1951 vlib_process_wait_for_event (vm);
1952 event_type = vlib_process_get_events (vm, &event_data);
1953 vec_reset_length (event_data);
1954 if (event_type != 1)
1955 clib_warning ("event type %d unexpected", event_type);
1956 }
1957 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001958 vnet_arp_unset_ip4_over_ethernet (vnm, sw_if_index, &addr);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001959
1960 increment_ip4_and_mac_address (&addr);
1961 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962 }
1963 else
1964 {
1965 return clib_error_return (0, "unknown input `%U'",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001966 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001967 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07001968
Ed Warnickecb9cada2015-12-08 15:45:58 -07001969 return 0;
1970}
1971
Neale Rannsb80c5362016-10-08 13:03:40 +01001972/* *INDENT-OFF* */
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07001973/*?
Billy McFall2d085d92016-09-13 21:47:55 -04001974 * Add or delete IPv4 ARP cache entries.
1975 *
1976 * @note 'set ip arp' options (e.g. delete, static, 'fib-id <id>',
1977 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
1978 * any order and combination.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07001979 *
1980 * @cliexpar
Billy McFall2d085d92016-09-13 21:47:55 -04001981 * @parblock
1982 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
1983 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
1984 * @cliexcmd{set ip arp GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1985 * @cliexcmd{set ip arp delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
1986 *
1987 * To add or delete an IPv4 ARP cache entry to or from a specific fib
1988 * table:
1989 * @cliexcmd{set ip arp fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1990 * @cliexcmd{set ip arp fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1991 *
1992 * Add or delete IPv4 static ARP cache entries as follows:
1993 * @cliexcmd{set ip arp static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1994 * @cliexcmd{set ip arp static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1995 *
1996 * For testing / debugging purposes, the 'set ip arp' command can add or
1997 * delete multiple entries. Supply the 'count N' parameter:
1998 * @cliexcmd{set ip arp count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
1999 * @endparblock
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002000 ?*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002001VLIB_CLI_COMMAND (ip_arp_add_del_command, static) = {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002002 .path = "set ip arp",
2003 .short_help =
Neale Rannsb80c5362016-10-08 13:03:40 +01002004 "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 -07002005 .function = ip_arp_add_del_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002007/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002008
2009static clib_error_t *
2010set_int_proxy_arp_command_fn (vlib_main_t * vm,
Neale Rannsb80c5362016-10-08 13:03:40 +01002011 unformat_input_t *
2012 input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002014 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07002015 u32 sw_if_index;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002016 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002017 int enable = 0;
2018 int intfc_set = 0;
2019
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002020 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002021 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002022 if (unformat (input, "%U", unformat_vnet_sw_interface,
2023 vnm, &sw_if_index))
2024 intfc_set = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002025 else if (unformat (input, "enable") || unformat (input, "on"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002026 enable = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027 else if (unformat (input, "disable") || unformat (input, "off"))
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002028 enable = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002029 else
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002030 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 }
2032
2033 if (intfc_set == 0)
2034 return clib_error_return (0, "unknown input '%U'",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002035 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002036
2037 si = vnet_get_sw_interface (vnm, sw_if_index);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002038 ASSERT (si);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002039 if (enable)
2040 si->flags |= VNET_SW_INTERFACE_FLAG_PROXY_ARP;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002041 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07002042 si->flags &= ~VNET_SW_INTERFACE_FLAG_PROXY_ARP;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002043
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044 return 0;
2045}
2046
Neale Rannsb80c5362016-10-08 13:03:40 +01002047/* *INDENT-OFF* */
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002048/*?
Billy McFall2d085d92016-09-13 21:47:55 -04002049 * Enable proxy-arp on an interface. The vpp stack will answer ARP
2050 * requests for the indicated address range. Multiple proxy-arp
2051 * ranges may be provisioned.
2052 *
2053 * @note Proxy ARP as a technology is infamous for blackholing traffic.
2054 * Also, the underlying implementation has not been performance-tuned.
2055 * Avoid creating an unnecessarily large set of ranges.
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002056 *
2057 * @cliexpar
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002058 * To enable proxy arp on a range of addresses, use:
Billy McFall2d085d92016-09-13 21:47:55 -04002059 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
2060 * Append 'del' to delete a range of proxy ARP addresses:
2061 * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
2062 * You must then specifically enable proxy arp on individual interfaces:
2063 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
2064 * To disable proxy arp on an individual interface:
2065 * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
Keith Burns (alagalah)6ef7bb92016-09-10 14:55:04 -07002066 ?*/
Ed Warnickecb9cada2015-12-08 15:45:58 -07002067VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002068 .path = "set interface proxy-arp",
2069 .short_help =
Neale Rannsb80c5362016-10-08 13:03:40 +01002070 "set interface proxy-arp <intfc> [enable|disable]",
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002071 .function = set_int_proxy_arp_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002072};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002073/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002074
2075
2076/*
John Lo1edfba92016-08-27 01:11:57 -04002077 * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
2078 * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
Ed Warnickecb9cada2015-12-08 15:45:58 -07002079 */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002080typedef enum
2081{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002082 ARP_TERM_NEXT_L2_OUTPUT,
2083 ARP_TERM_NEXT_DROP,
2084 ARP_TERM_N_NEXT,
2085} arp_term_next_t;
2086
2087u32 arp_term_next_node_index[32];
2088
2089static uword
2090arp_term_l2bd (vlib_main_t * vm,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002091 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002092{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002093 l2input_main_t *l2im = &l2input_main;
2094 u32 n_left_from, next_index, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002095 u32 n_replies_sent = 0;
2096 u16 last_bd_index = ~0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002097 l2_bridge_domain_t *last_bd_config = 0;
2098 l2_input_config_t *cfg0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099
2100 from = vlib_frame_vector_args (frame);
2101 n_left_from = frame->n_vectors;
2102 next_index = node->cached_next_index;
2103
2104 while (n_left_from > 0)
2105 {
2106 u32 n_left_to_next;
2107
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002108 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002109
2110 while (n_left_from > 0 && n_left_to_next > 0)
2111 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002112 vlib_buffer_t *p0;
2113 ethernet_header_t *eth0;
2114 ethernet_arp_header_t *arp0;
John Lo1edfba92016-08-27 01:11:57 -04002115 ip6_header_t *iph0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002116 u8 *l3h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002117 u32 pi0, error0, next0, sw_if_index0;
2118 u16 ethertype0;
2119 u16 bd_index0;
2120 u32 ip0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002121 u8 *macp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002122
2123 pi0 = from[0];
2124 to_next[0] = pi0;
2125 from += 1;
2126 to_next += 1;
2127 n_left_from -= 1;
2128 n_left_to_next -= 1;
2129
2130 p0 = vlib_get_buffer (vm, pi0);
2131 eth0 = vlib_buffer_get_current (p0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002132 l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
2133 ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002134 arp0 = (ethernet_arp_header_t *) l3h0;
2135
John Lo1edfba92016-08-27 01:11:57 -04002136 if (PREDICT_FALSE ((ethertype0 != ETHERNET_TYPE_ARP) ||
2137 (arp0->opcode !=
2138 clib_host_to_net_u16
2139 (ETHERNET_ARP_OPCODE_request))))
2140 goto check_ip6_nd;
2141
2142 /* Must be ARP request packet here */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002143 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
2144 (p0->flags & VLIB_BUFFER_IS_TRACED)))
2145 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002146 u8 *t0 = vlib_add_trace (vm, node, p0,
2147 sizeof (ethernet_arp_input_trace_t));
2148 clib_memcpy (t0, l3h0, sizeof (ethernet_arp_input_trace_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149 }
2150
Ed Warnickecb9cada2015-12-08 15:45:58 -07002151 error0 = ETHERNET_ARP_ERROR_replies_sent;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002152 error0 =
2153 (arp0->l2_type !=
Neale Rannsb80c5362016-10-08 13:03:40 +01002154 clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
2155 ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002156 error0 =
2157 (arp0->l3_type !=
2158 clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
2159 ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002160
2161 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
2162
2163 if (error0)
2164 goto drop;
2165
John Lo1edfba92016-08-27 01:11:57 -04002166 /* Trash ARP packets whose ARP-level source addresses do not
2167 match their L2-frame-level source addresses */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002168 if (PREDICT_FALSE
2169 (memcmp
2170 (eth0->src_address, arp0->ip4_over_ethernet[0].ethernet,
2171 sizeof (eth0->src_address))))
2172 {
2173 error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
2174 goto drop;
2175 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002176
John Lo1edfba92016-08-27 01:11:57 -04002177 /* Check if anyone want ARP request events for L2 BDs */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002178 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002179 pending_resolution_t *mc;
2180 ethernet_arp_main_t *am = &ethernet_arp_main;
2181 uword *p = hash_get (am->mac_changes_by_address, 0);
2182 if (p && (vnet_buffer (p0)->l2.shg == 0))
2183 { // Only SHG 0 interface which is more likely local
2184 u32 next_index = p[0];
2185 while (next_index != (u32) ~ 0)
2186 {
2187 int (*fp) (u32, u8 *, u32, u32);
2188 int rv = 1;
2189 mc = pool_elt_at_index (am->mac_changes, next_index);
2190 fp = mc->data_callback;
John Lo1edfba92016-08-27 01:11:57 -04002191 /* Call the callback, return 1 to suppress dup events */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002192 if (fp)
2193 rv = (*fp) (mc->data,
2194 arp0->ip4_over_ethernet[0].ethernet,
2195 sw_if_index0,
2196 arp0->ip4_over_ethernet[0].ip4.as_u32);
John Lo1edfba92016-08-27 01:11:57 -04002197 /* Signal the resolver process */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002198 if (rv == 0)
2199 vlib_process_signal_event (vm, mc->node_index,
2200 mc->type_opaque, mc->data);
2201 next_index = mc->next_index;
2202 }
2203 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204 }
2205
John Lo1edfba92016-08-27 01:11:57 -04002206 /* lookup BD mac_by_ip4 hash table for MAC entry */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002207 ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002208 bd_index0 = vnet_buffer (p0)->l2.bd_index;
2209 if (PREDICT_FALSE ((bd_index0 != last_bd_index)
2210 || (last_bd_index == (u16) ~ 0)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002211 {
2212 last_bd_index = bd_index0;
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002213 last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214 }
2215 macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
2216
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002217 if (PREDICT_FALSE (!macp0))
John Lo1edfba92016-08-27 01:11:57 -04002218 goto next_l2_feature; /* MAC not found */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002219
John Lo1edfba92016-08-27 01:11:57 -04002220 /* MAC found, send ARP reply -
2221 Convert ARP request packet to ARP reply */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222 arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
2223 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
2224 arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
Damjan Marionf1213b82016-03-13 02:22:06 +01002225 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, macp0, 6);
2226 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
2227 clib_memcpy (eth0->src_address, macp0, 6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228 n_replies_sent += 1;
2229
John Lo1edfba92016-08-27 01:11:57 -04002230 output_response:
2231 /* For BVI, need to use l2-fwd node to send ARP reply as
2232 l2-output node cannot output packet to BVI properly */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002233 cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002234 if (PREDICT_FALSE (cfg0->bvi))
2235 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002236 vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002237 vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
2238 goto next_l2_feature;
2239 }
2240
John Lo1edfba92016-08-27 01:11:57 -04002241 /* Send ARP/ND reply back out input interface through l2-output */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002242 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
2243 next0 = ARP_TERM_NEXT_L2_OUTPUT;
John Lo1edfba92016-08-27 01:11:57 -04002244 /* Note that output to VXLAN tunnel will fail due to SHG which
2245 is probably desireable since ARP termination is not intended
2246 for ARP requests from other hosts. If output to VXLAN tunnel is
2247 required, however, can just clear the SHG in packet as follows:
2248 vnet_buffer(p0)->l2.shg = 0; */
Neale Rannsb80c5362016-10-08 13:03:40 +01002249 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2250 to_next, n_left_to_next, pi0,
2251 next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002252 continue;
2253
John Lo1edfba92016-08-27 01:11:57 -04002254 check_ip6_nd:
2255 /* IP6 ND event notification or solicitation handling to generate
2256 local response instead of flooding */
2257 iph0 = (ip6_header_t *) l3h0;
2258 if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
2259 iph0->protocol == IP_PROTOCOL_ICMP6 &&
John Lo1edfba92016-08-27 01:11:57 -04002260 !ip6_address_is_unspecified
2261 (&iph0->src_address)))
2262 {
2263 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
Neale Rannsb80c5362016-10-08 13:03:40 +01002264 if (vnet_ip6_nd_term
2265 (vm, node, p0, eth0, iph0, sw_if_index0,
2266 vnet_buffer (p0)->l2.bd_index, vnet_buffer (p0)->l2.shg))
John Lo1edfba92016-08-27 01:11:57 -04002267 goto output_response;
2268 }
2269
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270 next_l2_feature:
2271 {
2272 u32 feature_bitmap0 =
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002273 vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM;
2274 vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0;
Neale Rannsb80c5362016-10-08 13:03:40 +01002275 next0 =
2276 feat_bitmap_get_next_node_index (arp_term_next_node_index,
2277 feature_bitmap0);
2278 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2279 to_next, n_left_to_next,
2280 pi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281 continue;
2282 }
2283
2284 drop:
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002285 if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
2286 (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
2287 arp0->ip4_over_ethernet[1].ip4.as_u32))
2288 {
2289 error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
2290 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002291 next0 = ARP_TERM_NEXT_DROP;
2292 p0->error = node->errors[error0];
2293
Neale Rannsb80c5362016-10-08 13:03:40 +01002294 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2295 to_next, n_left_to_next, pi0,
2296 next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 }
2298
2299 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2300 }
2301
2302 vlib_error_count (vm, node->node_index,
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002303 ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 return frame->n_vectors;
2305}
2306
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002307/* *INDENT-OFF* */
2308VLIB_REGISTER_NODE (arp_term_l2bd_node, static) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002309 .function = arp_term_l2bd,
2310 .name = "arp-term-l2bd",
2311 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002312 .n_errors = ETHERNET_ARP_N_ERROR,
2313 .error_strings = ethernet_arp_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002314 .n_next_nodes = ARP_TERM_N_NEXT,
2315 .next_nodes = {
2316 [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
2317 [ARP_TERM_NEXT_DROP] = "error-drop",
2318 },
Ed Warnickecb9cada2015-12-08 15:45:58 -07002319 .format_buffer = format_ethernet_arp_header,
John Lo1edfba92016-08-27 01:11:57 -04002320 .format_trace = format_arp_term_input_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002321};
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002322/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002323
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002324clib_error_t *
2325arp_term_init (vlib_main_t * vm)
Neale Rannsb80c5362016-10-08 13:03:40 +01002326{
2327 // Initialize the feature next-node indexes
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002328 feat_bitmap_init_next_nodes (vm,
2329 arp_term_l2bd_node.index,
2330 L2INPUT_N_FEAT,
2331 l2input_get_feat_names (),
2332 arp_term_next_node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002333 return 0;
2334}
2335
2336VLIB_INIT_FUNCTION (arp_term_init);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002337
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002338void
2339change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
2340{
2341 if (e->sw_if_index == sw_if_index)
2342 {
Neale Rannsb80c5362016-10-08 13:03:40 +01002343 adj_nbr_walk_nh4 (e->sw_if_index,
2344 &e->ip4_address, arp_mk_complete_walk, e);
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002345 }
2346}
2347
2348void
Neale Ranns3be6b282016-12-20 14:24:01 +00002349ethernet_arp_change_mac (u32 sw_if_index)
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002350{
2351 ethernet_arp_main_t *am = &ethernet_arp_main;
2352 ethernet_arp_ip4_entry_t *e;
2353
2354 /* *INDENT-OFF* */
2355 pool_foreach (e, am->ip4_entry_pool,
Neale Rannsb80c5362016-10-08 13:03:40 +01002356 ({
2357 change_arp_mac (sw_if_index, e);
2358 }));
Pavel Kotucekc631f2d2016-09-26 10:40:02 +02002359 /* *INDENT-ON* */
2360}
2361
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -07002362/*
2363 * fd.io coding-style-patch-verification: ON
2364 *
2365 * Local Variables:
2366 * eval: (c-set-style "gnu")
2367 * End:
2368 */