blob: 2dd8e748be62fc901738b2dd3c95ff38dd921b23 [file] [log] [blame]
Neale Rannscbe25aa2019-09-30 10:53:31 +00001/*
2 * src/vnet/ip/ip_neighboor.c: ip neighbor generic handling
3 *
4 * Copyright (c) 2018 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 <vppinfra/llist.h>
19
20#include <vnet/ip-neighbor/ip_neighbor.h>
21#include <vnet/ip-neighbor/ip4_neighbor.h>
22#include <vnet/ip-neighbor/ip6_neighbor.h>
23#include <vnet/ip-neighbor/ip_neighbor_watch.h>
24
25#include <vnet/ip/ip6_ll_table.h>
26#include <vnet/fib/fib_table.h>
27#include <vnet/adj/adj_mcast.h>
28
29/** Pool for All IP neighbors */
30static ip_neighbor_t *ip_neighbor_pool;
31
32/** protocol specific lists of time sorted neighbors */
Neale Rannsdc617b82020-08-20 08:22:56 +000033index_t ip_neighbor_list_head[N_AF];
Neale Rannscbe25aa2019-09-30 10:53:31 +000034
35typedef struct ip_neighbor_elt_t_
36{
37 clib_llist_anchor_t ipne_anchor;
38 index_t ipne_index;
39} ip_neighbor_elt_t;
40
41/** Pool of linked list elemeents */
42ip_neighbor_elt_t *ip_neighbor_elt_pool;
43
44typedef struct ip_neighbor_db_t_
45{
46 /** per interface hash */
47 uword **ipndb_hash;
48 /** per-protocol limit - max number of neighbors*/
49 u32 ipndb_limit;
50 /** max age of a neighbor before it's forcibly evicted */
51 u32 ipndb_age;
52 /** when the limit is reached and new neighbors are created, should
53 * we recycle an old one */
54 bool ipndb_recycle;
55 /** per-protocol number of elements */
56 u32 ipndb_n_elts;
57 /** per-protocol number of elements per-fib-index*/
58 u32 *ipndb_n_elts_per_fib;
59} ip_neighbor_db_t;
60
61static vlib_log_class_t ipn_logger;
62
63/* DBs of neighbours one per AF */
64/* *INDENT-OFF* */
Neale Rannsdc617b82020-08-20 08:22:56 +000065static ip_neighbor_db_t ip_neighbor_db[N_AF] = {
66 [AF_IP4] = {
Neale Rannscbe25aa2019-09-30 10:53:31 +000067 .ipndb_limit = 50000,
68 /* Default to not aging and not recycling */
69 .ipndb_age = 0,
70 .ipndb_recycle = false,
71 },
Neale Rannsdc617b82020-08-20 08:22:56 +000072 [AF_IP6] = {
Neale Rannscbe25aa2019-09-30 10:53:31 +000073 .ipndb_limit = 50000,
74 /* Default to not aging and not recycling */
75 .ipndb_age = 0,
76 .ipndb_recycle = false,
77 }
78};
79/* *INDENT-ON* */
80
81#define IP_NEIGHBOR_DBG(...) \
82 vlib_log_debug (ipn_logger, __VA_ARGS__);
83
84#define IP_NEIGHBOR_INFO(...) \
85 vlib_log_notice (ipn_logger, __VA_ARGS__);
86
87ip_neighbor_t *
88ip_neighbor_get (index_t ipni)
89{
90 if (pool_is_free_index (ip_neighbor_pool, ipni))
91 return (NULL);
92
93 return (pool_elt_at_index (ip_neighbor_pool, ipni));
94}
95
96static index_t
97ip_neighbor_get_index (const ip_neighbor_t * ipn)
98{
99 return (ipn - ip_neighbor_pool);
100}
101
Neale Rannsc87fbb42020-04-02 17:08:28 +0000102static void
103ip_neighbor_touch (ip_neighbor_t * ipn)
104{
105 ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_STALE;
106}
107
Neale Rannscbe25aa2019-09-30 10:53:31 +0000108static bool
109ip_neighbor_is_dynamic (const ip_neighbor_t * ipn)
110{
111 return (ipn->ipn_flags & IP_NEIGHBOR_FLAG_DYNAMIC);
112}
113
Neale Rannsdc617b82020-08-20 08:22:56 +0000114const ip_address_t *
Neale Rannscbe25aa2019-09-30 10:53:31 +0000115ip_neighbor_get_ip (const ip_neighbor_t * ipn)
116{
117 return (&ipn->ipn_key->ipnk_ip);
118}
119
Neale Rannsdc617b82020-08-20 08:22:56 +0000120ip_address_family_t
121ip_neighbor_get_af (const ip_neighbor_t * ipn)
122{
123 return (ip_addr_version (&ipn->ipn_key->ipnk_ip));
124}
125
Neale Rannscbe25aa2019-09-30 10:53:31 +0000126const mac_address_t *
127ip_neighbor_get_mac (const ip_neighbor_t * ipn)
128{
129 return (&ipn->ipn_mac);
130}
131
132const u32
133ip_neighbor_get_sw_if_index (const ip_neighbor_t * ipn)
134{
135 return (ipn->ipn_key->ipnk_sw_if_index);
136}
137
138static void
139ip_neighbor_list_remove (ip_neighbor_t * ipn)
140{
141 /* new neighbours, are added to the head of the list, since the
142 * list is time sorted, newest first */
143 ip_neighbor_elt_t *elt;
144
145 if (~0 != ipn->ipn_elt)
146 {
147 elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
148
149 clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
Vladimir Isaevb2f44bd2020-07-16 17:05:18 +0300150
151 ipn->ipn_elt = ~0;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000152 }
153}
154
155static void
156ip_neighbor_refresh (ip_neighbor_t * ipn)
157{
158 /* new neighbours, are added to the head of the list, since the
159 * list is time sorted, newest first */
160 ip_neighbor_elt_t *elt, *head;
161
Neale Rannsc87fbb42020-04-02 17:08:28 +0000162 ip_neighbor_touch (ipn);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000163 ipn->ipn_time_last_updated = vlib_time_now (vlib_get_main ());
164 ipn->ipn_n_probes = 0;
165
166 if (ip_neighbor_is_dynamic (ipn))
167 {
168 if (~0 == ipn->ipn_elt)
169 /* first time insertion */
170 pool_get_zero (ip_neighbor_elt_pool, elt);
171 else
172 {
173 /* already inserted - extract first */
174 elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
175
176 clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
177 }
178 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +0000179 ip_neighbor_list_head[ip_neighbor_get_af
180 (ipn)]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000181
182 elt->ipne_index = ip_neighbor_get_index (ipn);
183 clib_llist_add (ip_neighbor_elt_pool, ipne_anchor, elt, head);
184 ipn->ipn_elt = elt - ip_neighbor_elt_pool;
185 }
186}
187
188static void
189ip_neighbor_db_add (const ip_neighbor_t * ipn)
190{
Neale Rannsdc617b82020-08-20 08:22:56 +0000191 ip_address_family_t af;
192 u32 sw_if_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000193
Neale Rannsdc617b82020-08-20 08:22:56 +0000194 af = ip_neighbor_get_af (ipn);
195 sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
196
197 vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
198
199 if (!ip_neighbor_db[af].ipndb_hash[sw_if_index])
200 ip_neighbor_db[af].ipndb_hash[sw_if_index]
Neale Rannscbe25aa2019-09-30 10:53:31 +0000201 = hash_create_mem (0, sizeof (ip_neighbor_key_t), sizeof (index_t));
202
Neale Rannsdc617b82020-08-20 08:22:56 +0000203 hash_set_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index],
204 ipn->ipn_key, ip_neighbor_get_index (ipn));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000205
Neale Rannsdc617b82020-08-20 08:22:56 +0000206 ip_neighbor_db[af].ipndb_n_elts++;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000207}
208
209static void
Neale Rannsdc617b82020-08-20 08:22:56 +0000210ip_neighbor_db_remove (const ip_neighbor_t * ipn)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000211{
Neale Rannsdc617b82020-08-20 08:22:56 +0000212 ip_address_family_t af;
213 u32 sw_if_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000214
Neale Rannsdc617b82020-08-20 08:22:56 +0000215 af = ip_neighbor_get_af (ipn);
216 sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000217
Neale Rannsdc617b82020-08-20 08:22:56 +0000218 vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
219
220 hash_unset_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index], ipn->ipn_key);
221
222 ip_neighbor_db[af].ipndb_n_elts--;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000223}
224
225static ip_neighbor_t *
226ip_neighbor_db_find (const ip_neighbor_key_t * key)
227{
Neale Rannsdc617b82020-08-20 08:22:56 +0000228 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000229 uword *p;
230
Neale Rannsdc617b82020-08-20 08:22:56 +0000231 af = ip_addr_version (&key->ipnk_ip);
232
233 if (key->ipnk_sw_if_index >= vec_len (ip_neighbor_db[af].ipndb_hash))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000234 return NULL;
235
Neale Rannsdc617b82020-08-20 08:22:56 +0000236 p = hash_get_mem (ip_neighbor_db[af].ipndb_hash
237 [key->ipnk_sw_if_index], key);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000238
239 if (p)
240 return ip_neighbor_get (p[0]);
241
242 return (NULL);
243}
244
245static u8
Neale Rannsdc617b82020-08-20 08:22:56 +0000246ip_af_type_pfx_len (ip_address_family_t type)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000247{
Neale Rannsdc617b82020-08-20 08:22:56 +0000248 return (type == AF_IP4 ? 32 : 128);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000249}
250
251static void
252ip_neighbor_adj_fib_add (ip_neighbor_t * ipn, u32 fib_index)
253{
Neale Rannsdc617b82020-08-20 08:22:56 +0000254 ip_address_family_t af;
255
256 af = ip_neighbor_get_af (ipn);
257
258 if (af == AF_IP6 &&
259 ip6_address_is_link_local_unicast (&ip_addr_v6
260 (&ipn->ipn_key->ipnk_ip)))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000261 {
262 ip6_ll_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000263 .ilp_addr = ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000264 .ilp_sw_if_index = ipn->ipn_key->ipnk_sw_if_index,
265 };
266 ipn->ipn_fib_entry_index =
267 ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE);
268 }
269 else
270 {
271 fib_protocol_t fproto;
272
Neale Rannsdc617b82020-08-20 08:22:56 +0000273 fproto = ip_address_family_to_fib_proto (af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000274
275 fib_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000276 .fp_len = ip_af_type_pfx_len (af),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000277 .fp_proto = fproto,
Neale Rannsdc617b82020-08-20 08:22:56 +0000278 .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000279 };
280
281 ipn->ipn_fib_entry_index =
282 fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ,
283 FIB_ENTRY_FLAG_ATTACHED,
284 fib_proto_to_dpo (fproto),
285 &pfx.fp_addr,
286 ipn->ipn_key->ipnk_sw_if_index,
287 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
288
Neale Rannsdc617b82020-08-20 08:22:56 +0000289 vec_validate (ip_neighbor_db[af].ipndb_n_elts_per_fib, fib_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000290
Neale Rannsdc617b82020-08-20 08:22:56 +0000291 ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]++;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000292
Neale Rannsdc617b82020-08-20 08:22:56 +0000293 if (1 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
Neale Rannscbe25aa2019-09-30 10:53:31 +0000294 fib_table_lock (fib_index, fproto, FIB_SOURCE_ADJ);
295 }
296}
297
298static void
299ip_neighbor_adj_fib_remove (ip_neighbor_t * ipn, u32 fib_index)
300{
Neale Rannsdc617b82020-08-20 08:22:56 +0000301 ip_address_family_t af;
302
303 af = ip_neighbor_get_af (ipn);
304
Neale Rannscbe25aa2019-09-30 10:53:31 +0000305 if (FIB_NODE_INDEX_INVALID != ipn->ipn_fib_entry_index)
306 {
Neale Rannsdc617b82020-08-20 08:22:56 +0000307 if (AF_IP6 == af &&
308 ip6_address_is_link_local_unicast (&ip_addr_v6
309 (&ipn->ipn_key->ipnk_ip)))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000310 {
311 ip6_ll_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000312 .ilp_addr = ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000313 .ilp_sw_if_index = ipn->ipn_key->ipnk_sw_if_index,
314 };
315 ip6_ll_table_entry_delete (&pfx);
316 }
317 else
318 {
319 fib_protocol_t fproto;
320
Neale Rannsdc617b82020-08-20 08:22:56 +0000321 fproto = ip_address_family_to_fib_proto (af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000322
323 fib_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000324 .fp_len = ip_af_type_pfx_len (af),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000325 .fp_proto = fproto,
Neale Rannsdc617b82020-08-20 08:22:56 +0000326 .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000327 };
328
329 fib_table_entry_path_remove (fib_index,
330 &pfx,
331 FIB_SOURCE_ADJ,
332 fib_proto_to_dpo (fproto),
333 &pfx.fp_addr,
334 ipn->ipn_key->ipnk_sw_if_index,
335 ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
336
Neale Rannsdc617b82020-08-20 08:22:56 +0000337 ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]--;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000338
Neale Rannsdc617b82020-08-20 08:22:56 +0000339 if (0 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
Neale Rannscbe25aa2019-09-30 10:53:31 +0000340 fib_table_unlock (fib_index, fproto, FIB_SOURCE_ADJ);
341 }
342 }
343}
344
345static void
346ip_neighbor_mk_complete (adj_index_t ai, ip_neighbor_t * ipn)
347{
348 adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
349 ethernet_build_rewrite (vnet_get_main (),
350 ipn->
351 ipn_key->ipnk_sw_if_index,
352 adj_get_link_type (ai),
353 ipn->ipn_mac.bytes));
354}
355
356static void
357ip_neighbor_mk_incomplete (adj_index_t ai)
358{
359 ip_adjacency_t *adj = adj_get (ai);
360
361 adj_nbr_update_rewrite (ai,
362 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
363 ethernet_build_rewrite (vnet_get_main (),
364 adj->
365 rewrite_header.sw_if_index,
Neale Rannsfca3c6a2019-12-31 03:49:34 +0000366 VNET_LINK_ARP,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000367 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
368}
369
370static adj_walk_rc_t
371ip_neighbor_mk_complete_walk (adj_index_t ai, void *ctx)
372{
373 ip_neighbor_t *ipn = ctx;
374
375 ip_neighbor_mk_complete (ai, ipn);
376
377 return (ADJ_WALK_RC_CONTINUE);
378}
379
380static adj_walk_rc_t
381ip_neighbor_mk_incomplete_walk (adj_index_t ai, void *ctx)
382{
383 ip_neighbor_mk_incomplete (ai);
384
385 return (ADJ_WALK_RC_CONTINUE);
386}
387
388static void
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000389ip_neighbor_destroy (ip_neighbor_t * ipn)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000390{
Neale Rannsdc617b82020-08-20 08:22:56 +0000391 ip_address_family_t af;
392
393 af = ip_neighbor_get_af (ipn);
394
Neale Rannscbe25aa2019-09-30 10:53:31 +0000395 IP_NEIGHBOR_DBG ("free: %U", format_ip_neighbor,
396 ip_neighbor_get_index (ipn));
397
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000398 ip_neighbor_publish (ip_neighbor_get_index (ipn),
399 IP_NEIGHBOR_EVENT_REMOVED);
400
Neale Rannscbe25aa2019-09-30 10:53:31 +0000401 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +0000402 ip_address_family_to_fib_proto (af),
403 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000404 ip_neighbor_mk_incomplete_walk, ipn);
405 ip_neighbor_adj_fib_remove
406 (ipn,
407 fib_table_get_index_for_sw_if_index
Neale Rannsdc617b82020-08-20 08:22:56 +0000408 (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000409
410 ip_neighbor_list_remove (ipn);
Neale Rannsdc617b82020-08-20 08:22:56 +0000411 ip_neighbor_db_remove (ipn);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000412 clib_mem_free (ipn->ipn_key);
413
414 pool_put (ip_neighbor_pool, ipn);
415}
416
417static bool
Neale Rannsdc617b82020-08-20 08:22:56 +0000418ip_neighbor_force_reuse (ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000419{
Neale Rannsdc617b82020-08-20 08:22:56 +0000420 if (!ip_neighbor_db[af].ipndb_recycle)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000421 return false;
422
423 /* pluck the oldest entry, which is the one from the end of the list */
424 ip_neighbor_elt_t *elt, *head;
425
Neale Rannsdc617b82020-08-20 08:22:56 +0000426 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000427
428 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
429 return (false);
430
431 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000432 ip_neighbor_destroy (ip_neighbor_get (elt->ipne_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000433
434 return (true);
435}
436
437static ip_neighbor_t *
438ip_neighbor_alloc (const ip_neighbor_key_t * key,
439 const mac_address_t * mac, ip_neighbor_flags_t flags)
440{
Neale Rannsdc617b82020-08-20 08:22:56 +0000441 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000442 ip_neighbor_t *ipn;
443
Neale Rannsdc617b82020-08-20 08:22:56 +0000444 af = ip_addr_version (&key->ipnk_ip);
445
446 if (ip_neighbor_db[af].ipndb_limit &&
447 (ip_neighbor_db[af].ipndb_n_elts >= ip_neighbor_db[af].ipndb_limit))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000448 {
Neale Rannsdc617b82020-08-20 08:22:56 +0000449 if (!ip_neighbor_force_reuse (af))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000450 return (NULL);
451 }
452
453 pool_get_zero (ip_neighbor_pool, ipn);
454
455 ipn->ipn_key = clib_mem_alloc (sizeof (*ipn->ipn_key));
456 clib_memcpy (ipn->ipn_key, key, sizeof (*ipn->ipn_key));
457
458 ipn->ipn_fib_entry_index = FIB_NODE_INDEX_INVALID;
459 ipn->ipn_flags = flags;
460 ipn->ipn_elt = ~0;
461
462 mac_address_copy (&ipn->ipn_mac, mac);
463
464 ip_neighbor_db_add (ipn);
465
466 /* create the adj-fib. the entry in the FIB table for the peer's interface */
467 if (!(ipn->ipn_flags & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY))
468 ip_neighbor_adj_fib_add
469 (ipn, fib_table_get_index_for_sw_if_index
Neale Rannsdc617b82020-08-20 08:22:56 +0000470 (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000471
472 return (ipn);
473}
474
475int
Neale Rannsdc617b82020-08-20 08:22:56 +0000476ip_neighbor_add (const ip_address_t * ip,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000477 const mac_address_t * mac,
478 u32 sw_if_index,
479 ip_neighbor_flags_t flags, u32 * stats_index)
480{
481 fib_protocol_t fproto;
482 ip_neighbor_t *ipn;
483
484 /* main thread only */
485 ASSERT (0 == vlib_get_thread_index ());
486
Neale Rannsdc617b82020-08-20 08:22:56 +0000487 fproto = ip_address_family_to_fib_proto (ip_addr_version (ip));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000488
489 const ip_neighbor_key_t key = {
490 .ipnk_ip = *ip,
491 .ipnk_sw_if_index = sw_if_index,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000492 };
493
494 ipn = ip_neighbor_db_find (&key);
495
496 if (ipn)
497 {
498 IP_NEIGHBOR_DBG ("update: %U, %U",
499 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +0000500 sw_if_index, format_ip_address, ip,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000501 format_ip_neighbor_flags, flags, format_mac_address_t,
502 mac);
503
Neale Rannsc87fbb42020-04-02 17:08:28 +0000504 ip_neighbor_touch (ipn);
505
Neale Rannscbe25aa2019-09-30 10:53:31 +0000506 /* Refuse to over-write static neighbor entry. */
507 if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
508 (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
509 {
510 /* if MAC address match, still check to send event */
511 if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
512 goto check_customers;
513 return -2;
514 }
515
Vladimir Isaevb2f44bd2020-07-16 17:05:18 +0300516 /* A dynamic entry can become static, but not vice-versa.
517 * i.e. since if it was programmed by the CP then it must
518 * be removed by the CP */
519 if ((flags & IP_NEIGHBOR_FLAG_STATIC) &&
520 !(ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
521 {
522 ip_neighbor_list_remove (ipn);
523 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STATIC;
524 ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
525 }
526
Neale Rannscbe25aa2019-09-30 10:53:31 +0000527 /*
528 * prevent a DoS attack from the data-plane that
529 * spams us with no-op updates to the MAC address
530 */
531 if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
532 {
533 ip_neighbor_refresh (ipn);
534 goto check_customers;
535 }
536
537 mac_address_copy (&ipn->ipn_mac, mac);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000538 }
539 else
540 {
541 IP_NEIGHBOR_INFO ("add: %U, %U",
542 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +0000543 sw_if_index, format_ip_address, ip,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000544 format_ip_neighbor_flags, flags, format_mac_address_t,
545 mac);
546
547 ipn = ip_neighbor_alloc (&key, mac, flags);
548
549 if (NULL == ipn)
550 return VNET_API_ERROR_LIMIT_EXCEEDED;
551 }
552
553 /* Update time stamp and flags. */
554 ip_neighbor_refresh (ipn);
555
556 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +0000557 fproto, &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000558 ip_neighbor_mk_complete_walk, ipn);
559
560check_customers:
561 /* Customer(s) requesting event for this address? */
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000562 ip_neighbor_publish (ip_neighbor_get_index (ipn), IP_NEIGHBOR_EVENT_ADDED);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000563
564 if (stats_index)
565 *stats_index = adj_nbr_find (fproto,
566 fib_proto_to_link (fproto),
Neale Rannsdc617b82020-08-20 08:22:56 +0000567 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000568 ipn->ipn_key->ipnk_sw_if_index);
569 return 0;
570}
571
572int
Neale Rannsdc617b82020-08-20 08:22:56 +0000573ip_neighbor_del (const ip_address_t * ip, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000574{
575 ip_neighbor_t *ipn;
576
577 /* main thread only */
578 ASSERT (0 == vlib_get_thread_index ());
579
580 IP_NEIGHBOR_INFO ("delete: %U, %U",
581 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +0000582 sw_if_index, format_ip_address, ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000583
584 const ip_neighbor_key_t key = {
585 .ipnk_ip = *ip,
586 .ipnk_sw_if_index = sw_if_index,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000587 };
588
589 ipn = ip_neighbor_db_find (&key);
590
591 if (NULL == ipn)
592 return (VNET_API_ERROR_NO_SUCH_ENTRY);
593
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000594 ip_neighbor_destroy (ipn);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000595
596 return (0);
597}
598
Neale Ranns240dcb22020-04-23 09:04:59 +0000599typedef struct ip_neighbor_del_all_ctx_t_
600{
601 index_t *ipn_del;
602} ip_neighbor_del_all_ctx_t;
603
604static walk_rc_t
605ip_neighbor_del_all_walk_cb (index_t ipni, void *arg)
606{
607 ip_neighbor_del_all_ctx_t *ctx = arg;
608
609 vec_add1 (ctx->ipn_del, ipni);
610
611 return (WALK_CONTINUE);
612}
613
614void
Neale Rannsdc617b82020-08-20 08:22:56 +0000615ip_neighbor_del_all (ip_address_family_t af, u32 sw_if_index)
Neale Ranns240dcb22020-04-23 09:04:59 +0000616{
617 IP_NEIGHBOR_INFO ("delete-all: %U, %U",
Neale Rannsdc617b82020-08-20 08:22:56 +0000618 format_ip_address_family, af,
Neale Ranns240dcb22020-04-23 09:04:59 +0000619 format_vnet_sw_if_index_name, vnet_get_main (),
620 sw_if_index);
621
622 ip_neighbor_del_all_ctx_t ctx = {
623 .ipn_del = NULL,
624 };
625 index_t *ipni;
626
Neale Rannsdc617b82020-08-20 08:22:56 +0000627 ip_neighbor_walk (af, sw_if_index, ip_neighbor_del_all_walk_cb, &ctx);
Neale Ranns240dcb22020-04-23 09:04:59 +0000628
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000629 vec_foreach (ipni,
630 ctx.ipn_del) ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Ranns240dcb22020-04-23 09:04:59 +0000631 vec_free (ctx.ipn_del);
632}
633
Neale Rannscbe25aa2019-09-30 10:53:31 +0000634void
635ip_neighbor_update (vnet_main_t * vnm, adj_index_t ai)
636{
637 ip_neighbor_t *ipn;
638 ip_adjacency_t *adj;
639
640 adj = adj_get (ai);
641
642 ip_neighbor_key_t key = {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000643 .ipnk_sw_if_index = adj->rewrite_header.sw_if_index,
644 };
Neale Rannsdc617b82020-08-20 08:22:56 +0000645
646 ip_address_from_46 (&adj->sub_type.nbr.next_hop,
647 adj->ia_nh_proto, &key.ipnk_ip);
648
Neale Rannscbe25aa2019-09-30 10:53:31 +0000649 ipn = ip_neighbor_db_find (&key);
650
651 switch (adj->lookup_next_index)
652 {
653 case IP_LOOKUP_NEXT_ARP:
654 if (NULL != ipn)
655 {
656 adj_nbr_walk_nh (adj->rewrite_header.sw_if_index,
657 adj->ia_nh_proto,
Neale Rannsdc617b82020-08-20 08:22:56 +0000658 &adj->sub_type.nbr.next_hop,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000659 ip_neighbor_mk_complete_walk, ipn);
660 }
661 else
662 {
663 /*
664 * no matching ARP entry.
665 * construct the rewrite required to for an ARP packet, and stick
666 * that in the adj's pipe to smoke.
667 */
668 adj_nbr_update_rewrite
669 (ai,
670 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
671 ethernet_build_rewrite
672 (vnm,
673 adj->rewrite_header.sw_if_index,
674 VNET_LINK_ARP,
675 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
676
677 /*
678 * since the FIB has added this adj for a route, it makes sense it
679 * may want to forward traffic sometime soon. Let's send a
680 * speculative ARP. just one. If we were to do periodically that
681 * wouldn't be bad either, but that's more code than i'm prepared to
682 * write at this time for relatively little reward.
683 */
Steven Luong3d5f6222020-01-30 09:11:18 -0800684 /*
685 * adj_nbr_update_rewrite may actually call fib_walk_sync.
686 * fib_walk_sync may allocate a new adjacency and potentially cause
687 * a realloc for adj_pool. When that happens, adj pointer is no
688 * longer valid here.x We refresh adj pointer accordingly.
689 */
690 adj = adj_get (ai);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000691 ip_neighbor_probe (adj);
692 }
693 break;
694 case IP_LOOKUP_NEXT_GLEAN:
695 case IP_LOOKUP_NEXT_BCAST:
696 case IP_LOOKUP_NEXT_MCAST:
697 case IP_LOOKUP_NEXT_DROP:
698 case IP_LOOKUP_NEXT_PUNT:
699 case IP_LOOKUP_NEXT_LOCAL:
700 case IP_LOOKUP_NEXT_REWRITE:
701 case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
702 case IP_LOOKUP_NEXT_MIDCHAIN:
703 case IP_LOOKUP_NEXT_ICMP_ERROR:
704 case IP_LOOKUP_N_NEXT:
705 ASSERT (0);
706 break;
707 }
708}
709
710void
711ip_neighbor_learn (const ip_neighbor_learn_t * l)
712{
Neale Rannsdc617b82020-08-20 08:22:56 +0000713 ip_neighbor_add (&l->ip, &l->mac, l->sw_if_index,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000714 IP_NEIGHBOR_FLAG_DYNAMIC, NULL);
715}
716
717static clib_error_t *
718ip_neighbor_cmd (vlib_main_t * vm,
719 unformat_input_t * input, vlib_cli_command_t * cmd)
720{
Neale Rannsdc617b82020-08-20 08:22:56 +0000721 ip_address_t ip = IP_ADDRESS_V6_ALL_0S;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000722 mac_address_t mac = ZERO_MAC_ADDRESS;
723 vnet_main_t *vnm = vnet_get_main ();
724 ip_neighbor_flags_t flags;
725 u32 sw_if_index = ~0;
726 int is_add = 1;
727 int count = 1;
728
729 flags = IP_NEIGHBOR_FLAG_DYNAMIC;
730
731 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
732 {
733 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
734 if (unformat (input, "%U %U %U",
735 unformat_vnet_sw_interface, vnm, &sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +0000736 unformat_ip_address, &ip, unformat_mac_address_t, &mac))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000737 ;
738 else if (unformat (input, "delete") || unformat (input, "del"))
739 is_add = 0;
740 else if (unformat (input, "static"))
741 {
742 flags |= IP_NEIGHBOR_FLAG_STATIC;
743 flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
744 }
745 else if (unformat (input, "no-fib-entry"))
746 flags |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;
747 else if (unformat (input, "count %d", &count))
748 ;
749 else
750 break;
751 }
752
753 if (sw_if_index == ~0 ||
Neale Rannsdc617b82020-08-20 08:22:56 +0000754 ip_address_is_zero (&ip) || mac_address_is_zero (&mac))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000755 return clib_error_return (0,
756 "specify interface, IP address and MAC: `%U'",
757 format_unformat_error, input);
758
759 while (count)
760 {
761 if (is_add)
Neale Rannsdc617b82020-08-20 08:22:56 +0000762 ip_neighbor_add (&ip, &mac, sw_if_index, flags, NULL);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000763 else
Neale Rannsdc617b82020-08-20 08:22:56 +0000764 ip_neighbor_del (&ip, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000765
Neale Rannsdc617b82020-08-20 08:22:56 +0000766 ip_address_increment (&ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000767 mac_address_increment (&mac);
768
769 --count;
770 }
771
772 return NULL;
773}
774
775/* *INDENT-OFF* */
776/*?
777 * Add or delete IPv4 ARP cache entries.
778 *
779 * @note 'set ip neighbor' options (e.g. delete, static, 'fib-id <id>',
780 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
781 * any order and combination.
782 *
783 * @cliexpar
784 * @parblock
785 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
786 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
787 * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
788 * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
789 *
790 * To add or delete an IPv4 ARP cache entry to or from a specific fib
791 * table:
792 * @cliexcmd{set ip neighbor fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
793 * @cliexcmd{set ip neighbor fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
794 *
795 * Add or delete IPv4 static ARP cache entries as follows:
796 * @cliexcmd{set ip neighbor static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
797 * @cliexcmd{set ip neighbor static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
798 *
799 * For testing / debugging purposes, the 'set ip neighbor' command can add or
800 * delete multiple entries. Supply the 'count N' parameter:
801 * @cliexcmd{set ip neighbor count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
802 * @endparblock
803 ?*/
804VLIB_CLI_COMMAND (ip_neighbor_command, static) = {
805 .path = "set ip neighbor",
806 .short_help =
807 "set ip neighbor [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
808 .function = ip_neighbor_cmd,
809};
810VLIB_CLI_COMMAND (ip_neighbor_command2, static) = {
811 .path = "ip neighbor",
812 .short_help =
813 "ip neighbor [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
814 .function = ip_neighbor_cmd,
815};
816/* *INDENT-ON* */
817
818static int
819ip_neighbor_sort (void *a1, void *a2)
820{
821 index_t *ipni1 = a1, *ipni2 = a2;
822 ip_neighbor_t *ipn1, *ipn2;
823 int cmp;
824
825 ipn1 = ip_neighbor_get (*ipni1);
826 ipn2 = ip_neighbor_get (*ipni2);
827
828 cmp = vnet_sw_interface_compare (vnet_get_main (),
829 ipn1->ipn_key->ipnk_sw_if_index,
830 ipn2->ipn_key->ipnk_sw_if_index);
831 if (!cmp)
Neale Rannsdc617b82020-08-20 08:22:56 +0000832 cmp = ip_address_cmp (&ipn1->ipn_key->ipnk_ip, &ipn2->ipn_key->ipnk_ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000833 return cmp;
834}
835
836static index_t *
Neale Rannsdc617b82020-08-20 08:22:56 +0000837ip_neighbor_entries (u32 sw_if_index, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000838{
839 index_t *ipnis = NULL;
840 ip_neighbor_t *ipn;
841
842 /* *INDENT-OFF* */
843 pool_foreach (ipn, ip_neighbor_pool,
844 ({
Michael Yubedf48a2020-05-08 16:42:58 +0800845 if ((sw_if_index == ~0 ||
846 ipn->ipn_key->ipnk_sw_if_index == sw_if_index) &&
Neale Rannsdc617b82020-08-20 08:22:56 +0000847 (N_AF == af ||
848 ip_neighbor_get_af(ipn) == af))
Michael Yubedf48a2020-05-08 16:42:58 +0800849 vec_add1 (ipnis, ip_neighbor_get_index(ipn));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000850 }));
851
852 /* *INDENT-ON* */
853
854 if (ipnis)
855 vec_sort_with_function (ipnis, ip_neighbor_sort);
856 return ipnis;
857}
858
859static clib_error_t *
860ip_neighbor_show_sorted_i (vlib_main_t * vm,
861 unformat_input_t * input,
Neale Rannsdc617b82020-08-20 08:22:56 +0000862 vlib_cli_command_t * cmd, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000863{
864 ip_neighbor_elt_t *elt, *head;
865
Neale Rannsdc617b82020-08-20 08:22:56 +0000866 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000867
868
869 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
870 "Flags", "Ethernet", "Interface");
871
872 /* *INDENT-OFF*/
873 /* the list is time sorted, newest first, so start from the back
874 * and work forwards. Stop when we get to one that is alive */
875 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
876 ipne_anchor, head, elt,
877 ({
878 vlib_cli_output (vm, "%U", format_ip_neighbor, elt->ipne_index);
879 }));
880 /* *INDENT-ON*/
881
882 return (NULL);
883}
884
885static clib_error_t *
886ip_neighbor_show_i (vlib_main_t * vm,
887 unformat_input_t * input,
Neale Rannsdc617b82020-08-20 08:22:56 +0000888 vlib_cli_command_t * cmd, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000889{
890 index_t *ipni, *ipnis = NULL;
891 u32 sw_if_index;
892
893 /* Filter entries by interface if given. */
894 sw_if_index = ~0;
895 (void) unformat_user (input, unformat_vnet_sw_interface, vnet_get_main (),
896 &sw_if_index);
897
Neale Rannsdc617b82020-08-20 08:22:56 +0000898 ipnis = ip_neighbor_entries (sw_if_index, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000899
900 if (ipnis)
901 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
902 "Flags", "Ethernet", "Interface");
903
904 vec_foreach (ipni, ipnis)
905 {
906 vlib_cli_output (vm, "%U", format_ip_neighbor, *ipni);
907 }
908 vec_free (ipnis);
909
910 return (NULL);
911}
912
913static clib_error_t *
914ip_neighbor_show (vlib_main_t * vm,
915 unformat_input_t * input, vlib_cli_command_t * cmd)
916{
Neale Rannsdc617b82020-08-20 08:22:56 +0000917 return (ip_neighbor_show_i (vm, input, cmd, N_AF));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000918}
919
920static clib_error_t *
921ip6_neighbor_show (vlib_main_t * vm,
922 unformat_input_t * input, vlib_cli_command_t * cmd)
923{
Neale Rannsdc617b82020-08-20 08:22:56 +0000924 return (ip_neighbor_show_i (vm, input, cmd, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000925}
926
927static clib_error_t *
928ip4_neighbor_show (vlib_main_t * vm,
929 unformat_input_t * input, vlib_cli_command_t * cmd)
930{
Neale Rannsdc617b82020-08-20 08:22:56 +0000931 return (ip_neighbor_show_i (vm, input, cmd, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000932}
933
934static clib_error_t *
935ip6_neighbor_show_sorted (vlib_main_t * vm,
936 unformat_input_t * input, vlib_cli_command_t * cmd)
937{
Neale Rannsdc617b82020-08-20 08:22:56 +0000938 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000939}
940
941static clib_error_t *
942ip4_neighbor_show_sorted (vlib_main_t * vm,
943 unformat_input_t * input, vlib_cli_command_t * cmd)
944{
Neale Rannsdc617b82020-08-20 08:22:56 +0000945 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000946}
947
948/*?
949 * Display all the IP neighbor entries.
950 *
951 * @cliexpar
952 * Example of how to display the IPv4 ARP table:
953 * @cliexstart{show ip neighbor}
954 * Time FIB IP4 Flags Ethernet Interface
955 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
956 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
957 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
958 * Proxy arps enabled for:
959 * Fib_index 0 6.0.0.1 - 6.0.0.11
960 * @cliexend
961 ?*/
962/* *INDENT-OFF* */
963VLIB_CLI_COMMAND (show_ip_neighbors_cmd_node, static) = {
964 .path = "show ip neighbors",
965 .function = ip_neighbor_show,
966 .short_help = "show ip neighbors [interface]",
967};
968VLIB_CLI_COMMAND (show_ip4_neighbors_cmd_node, static) = {
969 .path = "show ip4 neighbors",
970 .function = ip4_neighbor_show,
971 .short_help = "show ip4 neighbors [interface]",
972};
973VLIB_CLI_COMMAND (show_ip6_neighbors_cmd_node, static) = {
974 .path = "show ip6 neighbors",
975 .function = ip6_neighbor_show,
976 .short_help = "show ip6 neighbors [interface]",
977};
978VLIB_CLI_COMMAND (show_ip_neighbor_cmd_node, static) = {
979 .path = "show ip neighbor",
980 .function = ip_neighbor_show,
981 .short_help = "show ip neighbor [interface]",
982};
983VLIB_CLI_COMMAND (show_ip4_neighbor_cmd_node, static) = {
984 .path = "show ip4 neighbor",
985 .function = ip4_neighbor_show,
986 .short_help = "show ip4 neighbor [interface]",
987};
988VLIB_CLI_COMMAND (show_ip6_neighbor_cmd_node, static) = {
989 .path = "show ip6 neighbor",
990 .function = ip6_neighbor_show,
991 .short_help = "show ip6 neighbor [interface]",
992};
993VLIB_CLI_COMMAND (show_ip4_neighbor_sorted_cmd_node, static) = {
994 .path = "show ip4 neighbor-sorted",
995 .function = ip4_neighbor_show_sorted,
996 .short_help = "show ip4 neighbor-sorted",
997};
998VLIB_CLI_COMMAND (show_ip6_neighbor_sorted_cmd_node, static) = {
999 .path = "show ip6 neighbor-sorted",
1000 .function = ip6_neighbor_show_sorted,
1001 .short_help = "show ip6 neighbor-sorted",
1002};
1003/* *INDENT-ON* */
1004
Neale Rannsdc617b82020-08-20 08:22:56 +00001005static ip_neighbor_vft_t ip_nbr_vfts[N_AF];
Neale Rannscbe25aa2019-09-30 10:53:31 +00001006
1007void
Neale Rannsdc617b82020-08-20 08:22:56 +00001008ip_neighbor_register (ip_address_family_t af, const ip_neighbor_vft_t * vft)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001009{
Neale Rannsdc617b82020-08-20 08:22:56 +00001010 ip_nbr_vfts[af] = *vft;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001011}
1012
1013void
Neale Rannse2fe0972020-11-26 08:37:27 +00001014ip_neighbor_probe_dst (u32 sw_if_index,
1015 ip_address_family_t af, const ip46_address_t * dst)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001016{
Neale Rannse2fe0972020-11-26 08:37:27 +00001017 if (!vnet_sw_interface_is_admin_up (vnet_get_main (), sw_if_index))
Neale Rannscbe25aa2019-09-30 10:53:31 +00001018 return;
1019
Neale Rannse2fe0972020-11-26 08:37:27 +00001020 switch (af)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001021 {
Neale Rannse2fe0972020-11-26 08:37:27 +00001022 case AF_IP6:
1023 ip6_neighbor_probe_dst (sw_if_index, &dst->ip6);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001024 break;
Neale Rannse2fe0972020-11-26 08:37:27 +00001025 case AF_IP4:
1026 ip4_neighbor_probe_dst (sw_if_index, &dst->ip4);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001027 break;
1028 }
1029}
1030
1031void
1032ip_neighbor_probe (const ip_adjacency_t * adj)
1033{
Neale Rannse2fe0972020-11-26 08:37:27 +00001034 ip_neighbor_probe_dst (adj->rewrite_header.sw_if_index,
1035 ip_address_family_from_fib_proto (adj->ia_nh_proto),
1036 &adj->sub_type.nbr.next_hop);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001037}
1038
1039void
Neale Rannsdc617b82020-08-20 08:22:56 +00001040ip_neighbor_walk (ip_address_family_t af,
Neale Rannscbe25aa2019-09-30 10:53:31 +00001041 u32 sw_if_index, ip_neighbor_walk_cb_t cb, void *ctx)
1042{
1043 ip_neighbor_key_t *key;
1044 index_t ipni;
1045
1046 if (~0 == sw_if_index)
1047 {
1048 uword **hash;
1049
Neale Rannsdc617b82020-08-20 08:22:56 +00001050 vec_foreach (hash, ip_neighbor_db[af].ipndb_hash)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001051 {
1052 /* *INDENT-OFF* */
1053 hash_foreach (key, ipni, *hash,
1054 ({
Ruslan Babayev24b417c2020-02-02 17:30:31 -08001055 if (WALK_STOP == cb (ipni, ctx))
1056 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001057 }));
1058 /* *INDENT-ON* */
1059 }
1060 }
1061 else
1062 {
1063 uword *hash;
1064
Neale Rannsdc617b82020-08-20 08:22:56 +00001065 if (vec_len (ip_neighbor_db[af].ipndb_hash) <= sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001066 return;
Neale Rannsdc617b82020-08-20 08:22:56 +00001067 hash = ip_neighbor_db[af].ipndb_hash[sw_if_index];
Neale Rannscbe25aa2019-09-30 10:53:31 +00001068
1069 /* *INDENT-OFF* */
1070 hash_foreach (key, ipni, hash,
1071 ({
Ruslan Babayev24b417c2020-02-02 17:30:31 -08001072 if (WALK_STOP == cb (ipni, ctx))
1073 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001074 }));
1075 /* *INDENT-ON* */
1076 }
1077}
1078
1079int
1080ip4_neighbor_proxy_add (u32 fib_index,
1081 const ip4_address_t * start,
1082 const ip4_address_t * end)
1083{
Neale Rannsdc617b82020-08-20 08:22:56 +00001084 if (ip_nbr_vfts[AF_IP4].inv_proxy4_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001085 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001086 return (ip_nbr_vfts[AF_IP4].inv_proxy4_add (fib_index, start, end));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001087 }
1088
1089 return (-1);
1090}
1091
1092int
1093ip4_neighbor_proxy_delete (u32 fib_index,
1094 const ip4_address_t * start,
1095 const ip4_address_t * end)
1096{
Neale Rannsdc617b82020-08-20 08:22:56 +00001097 if (ip_nbr_vfts[AF_IP4].inv_proxy4_del)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001098 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001099 return (ip_nbr_vfts[AF_IP4].inv_proxy4_del (fib_index, start, end));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001100 }
1101 return -1;
1102}
1103
1104int
1105ip4_neighbor_proxy_enable (u32 sw_if_index)
1106{
Neale Rannsdc617b82020-08-20 08:22:56 +00001107 if (ip_nbr_vfts[AF_IP4].inv_proxy4_enable)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001108 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001109 return (ip_nbr_vfts[AF_IP4].inv_proxy4_enable (sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001110 }
1111 return -1;
1112}
1113
1114int
1115ip4_neighbor_proxy_disable (u32 sw_if_index)
1116{
Neale Rannsdc617b82020-08-20 08:22:56 +00001117 if (ip_nbr_vfts[AF_IP4].inv_proxy4_disable)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001118 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001119 return (ip_nbr_vfts[AF_IP4].inv_proxy4_disable (sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001120 }
1121 return -1;
1122}
1123
1124int
1125ip6_neighbor_proxy_add (u32 sw_if_index, const ip6_address_t * addr)
1126{
Neale Rannsdc617b82020-08-20 08:22:56 +00001127 if (ip_nbr_vfts[AF_IP6].inv_proxy6_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001128 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001129 return (ip_nbr_vfts[AF_IP6].inv_proxy6_add (sw_if_index, addr));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001130 }
1131 return -1;
1132}
1133
1134int
1135ip6_neighbor_proxy_del (u32 sw_if_index, const ip6_address_t * addr)
1136{
Neale Rannsdc617b82020-08-20 08:22:56 +00001137 if (ip_nbr_vfts[AF_IP6].inv_proxy6_del)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001138 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001139 return (ip_nbr_vfts[AF_IP6].inv_proxy6_del (sw_if_index, addr));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001140 }
1141 return -1;
1142}
1143
1144static void
1145ip_neighbor_ethernet_change_mac (ethernet_main_t * em,
1146 u32 sw_if_index, uword opaque)
1147{
1148 ip_neighbor_t *ipn;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001149
1150 IP_NEIGHBOR_DBG ("mac-change: %U",
1151 format_vnet_sw_if_index_name, vnet_get_main (),
1152 sw_if_index);
1153
1154 /* *INDENT-OFF* */
1155 pool_foreach (ipn, ip_neighbor_pool,
1156 ({
1157 if (ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1158 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +00001159 ip_address_family_to_fib_proto(ip_neighbor_get_af(ipn)),
1160 &ip_addr_46(&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001161 ip_neighbor_mk_complete_walk,
1162 ipn);
1163 }));
1164 /* *INDENT-ON* */
1165
Neale Rannse2fe0972020-11-26 08:37:27 +00001166 adj_glean_update_rewrite_itf (sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001167}
1168
1169void
Neale Rannsdc617b82020-08-20 08:22:56 +00001170ip_neighbor_populate (ip_address_family_t af, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001171{
1172 index_t *ipnis = NULL, *ipni;
1173 ip_neighbor_t *ipn;
1174
1175 IP_NEIGHBOR_DBG ("populate: %U %U",
1176 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001177 sw_if_index, format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001178
1179 /* *INDENT-OFF* */
1180 pool_foreach (ipn, ip_neighbor_pool,
1181 ({
Neale Rannsdc617b82020-08-20 08:22:56 +00001182 if (ip_neighbor_get_af(ipn) == af &&
Neale Rannscbe25aa2019-09-30 10:53:31 +00001183 ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1184 vec_add1 (ipnis, ipn - ip_neighbor_pool);
1185 }));
1186 /* *INDENT-ON* */
1187
1188 vec_foreach (ipni, ipnis)
1189 {
1190 ipn = ip_neighbor_get (*ipni);
1191
1192 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +00001193 ip_address_family_to_fib_proto (ip_neighbor_get_af
1194 (ipn)),
1195 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001196 ip_neighbor_mk_complete_walk, ipn);
1197 }
1198 vec_free (ipnis);
1199}
1200
1201void
Neale Rannsdc617b82020-08-20 08:22:56 +00001202ip_neighbor_flush (ip_address_family_t af, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001203{
1204 index_t *ipnis = NULL, *ipni;
1205 ip_neighbor_t *ipn;
1206
Neale Rannsdc617b82020-08-20 08:22:56 +00001207
Neale Rannscbe25aa2019-09-30 10:53:31 +00001208 IP_NEIGHBOR_DBG ("flush: %U %U",
1209 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001210 sw_if_index, format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001211
1212 /* *INDENT-OFF* */
1213 pool_foreach (ipn, ip_neighbor_pool,
1214 ({
Neale Rannsdc617b82020-08-20 08:22:56 +00001215 if (ip_neighbor_get_af(ipn) == af &&
Neale Rannscbe25aa2019-09-30 10:53:31 +00001216 ipn->ipn_key->ipnk_sw_if_index == sw_if_index &&
1217 ip_neighbor_is_dynamic (ipn))
1218 vec_add1 (ipnis, ipn - ip_neighbor_pool);
1219 }));
1220 /* *INDENT-ON* */
1221
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001222 vec_foreach (ipni, ipnis) ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001223 vec_free (ipnis);
1224}
1225
Neale Rannsc87fbb42020-04-02 17:08:28 +00001226static walk_rc_t
1227ip_neighbor_mark_one (index_t ipni, void *ctx)
1228{
1229 ip_neighbor_t *ipn;
1230
1231 ipn = ip_neighbor_get (ipni);
1232
1233 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
1234
1235 return (WALK_CONTINUE);
1236}
1237
1238void
Neale Rannsdc617b82020-08-20 08:22:56 +00001239ip_neighbor_mark (ip_address_family_t af)
Neale Rannsc87fbb42020-04-02 17:08:28 +00001240{
Neale Rannsdc617b82020-08-20 08:22:56 +00001241 ip_neighbor_walk (af, ~0, ip_neighbor_mark_one, NULL);
Neale Rannsc87fbb42020-04-02 17:08:28 +00001242}
1243
1244typedef struct ip_neighbor_sweep_ctx_t_
1245{
1246 index_t *ipnsc_stale;
1247} ip_neighbor_sweep_ctx_t;
1248
1249static walk_rc_t
1250ip_neighbor_sweep_one (index_t ipni, void *arg)
1251{
1252 ip_neighbor_sweep_ctx_t *ctx = arg;
1253 ip_neighbor_t *ipn;
1254
1255 ipn = ip_neighbor_get (ipni);
1256
1257 if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
1258 {
1259 vec_add1 (ctx->ipnsc_stale, ipni);
1260 }
1261
1262 return (WALK_CONTINUE);
1263}
1264
1265void
Neale Rannsdc617b82020-08-20 08:22:56 +00001266ip_neighbor_sweep (ip_address_family_t af)
Neale Rannsc87fbb42020-04-02 17:08:28 +00001267{
1268 ip_neighbor_sweep_ctx_t ctx = { };
1269 index_t *ipni;
1270
Neale Rannsdc617b82020-08-20 08:22:56 +00001271 ip_neighbor_walk (af, ~0, ip_neighbor_sweep_one, &ctx);
Neale Rannsc87fbb42020-04-02 17:08:28 +00001272
1273 vec_foreach (ipni, ctx.ipnsc_stale)
1274 {
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001275 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannsc87fbb42020-04-02 17:08:28 +00001276 }
1277 vec_free (ctx.ipnsc_stale);
1278}
1279
Neale Rannscbe25aa2019-09-30 10:53:31 +00001280/*
1281 * Remove any arp entries associated with the specified interface
1282 */
1283static clib_error_t *
1284ip_neighbor_interface_admin_change (vnet_main_t * vnm,
1285 u32 sw_if_index, u32 flags)
1286{
Neale Rannsdc617b82020-08-20 08:22:56 +00001287 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001288
1289 IP_NEIGHBOR_DBG ("interface-admin: %U %s",
1290 format_vnet_sw_if_index_name, vnet_get_main (),
1291 sw_if_index,
1292 (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ? "up" : "down"));
1293
1294 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1295 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001296 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_populate (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001297 }
1298 else
1299 {
1300 /* admin down, flush all neighbours */
Neale Rannsdc617b82020-08-20 08:22:56 +00001301 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001302 }
1303
1304 return (NULL);
1305}
1306
1307VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip_neighbor_interface_admin_change);
1308
1309/*
1310 * Remove any arp entries associated with the specified interface
1311 */
1312static clib_error_t *
1313ip_neighbor_delete_sw_interface (vnet_main_t * vnm,
1314 u32 sw_if_index, u32 is_add)
1315{
1316 IP_NEIGHBOR_DBG ("interface-change: %U %s",
1317 format_vnet_sw_if_index_name, vnet_get_main (),
1318 sw_if_index, (is_add ? "add" : "del"));
1319
1320 if (!is_add && sw_if_index != ~0)
1321 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001322 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001323
Neale Rannsdc617b82020-08-20 08:22:56 +00001324 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001325 }
1326
1327 return (NULL);
1328}
1329
1330VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_neighbor_delete_sw_interface);
1331
1332typedef struct ip_neighbor_walk_covered_ctx_t_
1333{
Neale Rannsdc617b82020-08-20 08:22:56 +00001334 ip_address_t addr;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001335 u32 length;
1336 index_t *ipnis;
1337} ip_neighbor_walk_covered_ctx_t;
1338
1339static walk_rc_t
1340ip_neighbor_walk_covered (index_t ipni, void *arg)
1341{
1342 ip_neighbor_walk_covered_ctx_t *ctx = arg;
1343 ip_neighbor_t *ipn;
1344
1345 ipn = ip_neighbor_get (ipni);
1346
Neale Rannsdc617b82020-08-20 08:22:56 +00001347 if (AF_IP4 == ip_addr_version (&ctx->addr))
Neale Rannscbe25aa2019-09-30 10:53:31 +00001348 {
1349 if (ip4_destination_matches_route (&ip4_main,
Neale Rannsdc617b82020-08-20 08:22:56 +00001350 &ip_addr_v4 (&ipn->ipn_key->ipnk_ip),
1351 &ip_addr_v4 (&ctx->addr),
1352 ctx->length) &&
1353 ip_neighbor_is_dynamic (ipn))
1354 {
1355 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1356 }
1357 }
1358 else if (AF_IP6 == ip_addr_version (&ctx->addr))
1359 {
1360 if (ip6_destination_matches_route (&ip6_main,
1361 &ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
1362 &ip_addr_v6 (&ctx->addr),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001363 ctx->length) &&
1364 ip_neighbor_is_dynamic (ipn))
1365 {
1366 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1367 }
1368 }
1369 return (WALK_CONTINUE);
1370}
1371
1372
1373/*
1374 * callback when an interface address is added or deleted
1375 */
1376static void
1377ip_neighbor_add_del_interface_address_v4 (ip4_main_t * im,
1378 uword opaque,
1379 u32 sw_if_index,
1380 ip4_address_t * address,
1381 u32 address_length,
1382 u32 if_address_index, u32 is_del)
1383{
1384 /*
1385 * Flush the ARP cache of all entries covered by the address
1386 * that is being removed.
1387 */
1388 IP_NEIGHBOR_DBG ("addr-%d: %U, %U/%d",
1389 (is_del ? "del" : "add"),
1390 format_vnet_sw_if_index_name, vnet_get_main (),
1391 sw_if_index, format_ip4_address, address, address_length);
1392
1393 if (is_del)
1394 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001395 /* *INDENT-OFF* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001396 ip_neighbor_walk_covered_ctx_t ctx = {
Neale Rannsdc617b82020-08-20 08:22:56 +00001397 .addr = {
1398 .ip.ip4 = *address,
1399 .version = AF_IP4,
1400 },
Neale Rannscbe25aa2019-09-30 10:53:31 +00001401 .length = address_length,
1402 };
Neale Rannsdc617b82020-08-20 08:22:56 +00001403 /* *INDENT-ON* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001404 index_t *ipni;
1405
Neale Rannsdc617b82020-08-20 08:22:56 +00001406 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_covered, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001407
1408 vec_foreach (ipni, ctx.ipnis)
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001409 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001410
1411 vec_free (ctx.ipnis);
1412 }
1413}
1414
1415/*
1416 * callback when an interface address is added or deleted
1417 */
1418static void
1419ip_neighbor_add_del_interface_address_v6 (ip6_main_t * im,
1420 uword opaque,
1421 u32 sw_if_index,
1422 ip6_address_t * address,
1423 u32 address_length,
1424 u32 if_address_index, u32 is_del)
1425{
1426 /*
1427 * Flush the ARP cache of all entries covered by the address
1428 * that is being removed.
1429 */
1430 IP_NEIGHBOR_DBG ("addr-change: %U, %U/%d %s",
1431 format_vnet_sw_if_index_name, vnet_get_main (),
1432 sw_if_index, format_ip6_address, address, address_length,
1433 (is_del ? "del" : "add"));
1434
1435 if (is_del)
1436 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001437 /* *INDENT-OFF* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001438 ip_neighbor_walk_covered_ctx_t ctx = {
Neale Rannsdc617b82020-08-20 08:22:56 +00001439 .addr = {
1440 .ip.ip6 = *address,
1441 .version = AF_IP6,
1442 },
Neale Rannscbe25aa2019-09-30 10:53:31 +00001443 .length = address_length,
1444 };
Neale Rannsdc617b82020-08-20 08:22:56 +00001445 /* *INDENT-ON* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001446 index_t *ipni;
1447
Neale Rannsdc617b82020-08-20 08:22:56 +00001448 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_covered, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001449
1450 vec_foreach (ipni, ctx.ipnis)
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001451 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001452
1453 vec_free (ctx.ipnis);
1454 }
1455}
1456
1457typedef struct ip_neighbor_table_bind_ctx_t_
1458{
1459 u32 new_fib_index;
1460 u32 old_fib_index;
1461} ip_neighbor_table_bind_ctx_t;
1462
1463static walk_rc_t
1464ip_neighbor_walk_table_bind (index_t ipni, void *arg)
1465{
1466 ip_neighbor_table_bind_ctx_t *ctx = arg;
1467 ip_neighbor_t *ipn;
1468
1469 ipn = ip_neighbor_get (ipni);
1470 ip_neighbor_adj_fib_remove (ipn, ctx->old_fib_index);
1471 ip_neighbor_adj_fib_add (ipn, ctx->new_fib_index);
1472
1473 return (WALK_CONTINUE);
1474}
1475
1476static void
1477ip_neighbor_table_bind_v4 (ip4_main_t * im,
1478 uword opaque,
1479 u32 sw_if_index,
1480 u32 new_fib_index, u32 old_fib_index)
1481{
1482 ip_neighbor_table_bind_ctx_t ctx = {
1483 .old_fib_index = old_fib_index,
1484 .new_fib_index = new_fib_index,
1485 };
1486
Neale Rannsdc617b82020-08-20 08:22:56 +00001487 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001488}
1489
1490static void
1491ip_neighbor_table_bind_v6 (ip6_main_t * im,
1492 uword opaque,
1493 u32 sw_if_index,
1494 u32 new_fib_index, u32 old_fib_index)
1495{
1496 ip_neighbor_table_bind_ctx_t ctx = {
1497 .old_fib_index = old_fib_index,
1498 .new_fib_index = new_fib_index,
1499 };
1500
Neale Rannsdc617b82020-08-20 08:22:56 +00001501 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001502}
1503
1504typedef enum ip_neighbor_age_state_t_
1505{
1506 IP_NEIGHBOR_AGE_ALIVE,
1507 IP_NEIGHBOR_AGE_PROBE,
1508 IP_NEIGHBOR_AGE_DEAD,
1509} ip_neighbor_age_state_t;
1510
1511#define IP_NEIGHBOR_PROCESS_SLEEP_LONG (0)
1512
1513static ip_neighbor_age_state_t
1514ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
1515{
Neale Rannsdc617b82020-08-20 08:22:56 +00001516 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001517 ip_neighbor_t *ipn;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001518 u32 ipndb_age;
1519 u32 ttl;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001520
1521 ipn = ip_neighbor_get (ipni);
Neale Rannsdc617b82020-08-20 08:22:56 +00001522 af = ip_neighbor_get_af (ipn);
1523 ipndb_age = ip_neighbor_db[af].ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001524 ttl = now - ipn->ipn_time_last_updated;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001525 *wait = ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001526
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001527 if (ttl > ipndb_age)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001528 {
1529 IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d",
1530 format_ip_neighbor, ipni, now,
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001531 ipn->ipn_time_last_updated, ipndb_age);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001532 if (ipn->ipn_n_probes > 2)
1533 {
1534 /* 3 strikes and yea-re out */
1535 IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni);
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001536 *wait = 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001537 return (IP_NEIGHBOR_AGE_DEAD);
1538 }
1539 else
1540 {
Neale Rannse2fe0972020-11-26 08:37:27 +00001541 ip_neighbor_probe_dst (ip_neighbor_get_sw_if_index (ipn),
1542 af, &ip_addr_46 (&ipn->ipn_key->ipnk_ip));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001543
1544 ipn->ipn_n_probes++;
1545 *wait = 1;
1546 }
1547 }
1548 else
1549 {
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001550 /* here we are sure that ttl <= ipndb_age */
1551 *wait = ipndb_age - ttl + 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001552 return (IP_NEIGHBOR_AGE_ALIVE);
1553 }
1554
1555 return (IP_NEIGHBOR_AGE_PROBE);
1556}
1557
1558typedef enum ip_neighbor_process_event_t_
1559{
1560 IP_NEIGHBOR_AGE_PROCESS_WAKEUP,
1561} ip_neighbor_process_event_t;
1562
1563static uword
1564ip_neighbor_age_loop (vlib_main_t * vm,
1565 vlib_node_runtime_t * rt,
Neale Rannsdc617b82020-08-20 08:22:56 +00001566 vlib_frame_t * f, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001567{
1568 uword event_type, *event_data = NULL;
1569 f64 timeout;
1570
1571 /* Set the timeout to an effectively infinite value when the process starts */
1572 timeout = IP_NEIGHBOR_PROCESS_SLEEP_LONG;
1573
1574 while (1)
1575 {
1576 f64 now;
1577
1578 if (!timeout)
1579 vlib_process_wait_for_event (vm);
1580 else
1581 vlib_process_wait_for_event_or_clock (vm, timeout);
1582
1583 event_type = vlib_process_get_events (vm, &event_data);
1584 vec_reset_length (event_data);
1585
1586 now = vlib_time_now (vm);
1587
1588 switch (event_type)
1589 {
1590 case ~0:
1591 {
1592 /* timer expired */
1593 ip_neighbor_elt_t *elt, *head;
1594 f64 wait;
1595
Neale Rannsdc617b82020-08-20 08:22:56 +00001596 timeout = ip_neighbor_db[af].ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001597 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +00001598 ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001599
1600 /* *INDENT-OFF*/
1601 /* the list is time sorted, newest first, so start from the back
1602 * and work forwards. Stop when we get to one that is alive */
1603 restart:
1604 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
1605 ipne_anchor, head, elt,
1606 ({
1607 ip_neighbor_age_state_t res;
1608
1609 res = ip_neighbour_age_out(elt->ipne_index, now, &wait);
1610
1611 if (IP_NEIGHBOR_AGE_ALIVE == res) {
1612 /* the oldest neighbor has not yet expired, go back to sleep */
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001613 timeout = clib_min (wait, timeout);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001614 break;
1615 }
1616 else if (IP_NEIGHBOR_AGE_DEAD == res) {
1617 /* the oldest neighbor is dead, pop it, then restart the walk
1618 * again from the back */
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001619 ip_neighbor_destroy (ip_neighbor_get(elt->ipne_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001620 goto restart;
1621 }
1622
1623 timeout = clib_min (wait, timeout);
1624 }));
1625 /* *INDENT-ON* */
1626 break;
1627 }
1628 case IP_NEIGHBOR_AGE_PROCESS_WAKEUP:
1629 {
1630
Neale Rannsdc617b82020-08-20 08:22:56 +00001631 if (!ip_neighbor_db[af].ipndb_age)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001632 {
1633 /* aging has been disabled */
1634 timeout = 0;
1635 break;
1636 }
1637 ip_neighbor_elt_t *elt, *head;
1638
1639 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +00001640 ip_neighbor_list_head[af]);
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001641 /* no neighbors yet */
1642 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
1643 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001644 timeout = ip_neighbor_db[af].ipndb_age;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001645 break;
1646 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001647
1648 /* poke the oldset neighbour for aging, which returns how long we sleep for */
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001649 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
1650 ip_neighbour_age_out (elt->ipne_index, now, &timeout);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001651 break;
1652 }
1653 }
1654 }
1655 return 0;
1656}
1657
1658static uword
1659ip4_neighbor_age_process (vlib_main_t * vm,
1660 vlib_node_runtime_t * rt, vlib_frame_t * f)
1661{
Neale Rannsdc617b82020-08-20 08:22:56 +00001662 return (ip_neighbor_age_loop (vm, rt, f, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001663}
1664
1665static uword
1666ip6_neighbor_age_process (vlib_main_t * vm,
1667 vlib_node_runtime_t * rt, vlib_frame_t * f)
1668{
Neale Rannsdc617b82020-08-20 08:22:56 +00001669 return (ip_neighbor_age_loop (vm, rt, f, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001670}
1671
1672/* *INDENT-OFF* */
1673VLIB_REGISTER_NODE (ip4_neighbor_age_process_node,static) = {
1674 .function = ip4_neighbor_age_process,
1675 .type = VLIB_NODE_TYPE_PROCESS,
1676 .name = "ip4-neighbor-age-process",
1677};
1678VLIB_REGISTER_NODE (ip6_neighbor_age_process_node,static) = {
1679 .function = ip6_neighbor_age_process,
1680 .type = VLIB_NODE_TYPE_PROCESS,
1681 .name = "ip6-neighbor-age-process",
1682};
1683/* *INDENT-ON* */
1684
1685int
Neale Rannsdc617b82020-08-20 08:22:56 +00001686ip_neighbor_config (ip_address_family_t af, u32 limit, u32 age, bool recycle)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001687{
Neale Rannsdc617b82020-08-20 08:22:56 +00001688 ip_neighbor_db[af].ipndb_limit = limit;
1689 ip_neighbor_db[af].ipndb_recycle = recycle;
1690 ip_neighbor_db[af].ipndb_age = age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001691
1692 vlib_process_signal_event (vlib_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001693 (AF_IP4 == af ?
Neale Rannscbe25aa2019-09-30 10:53:31 +00001694 ip4_neighbor_age_process_node.index :
1695 ip6_neighbor_age_process_node.index),
1696 IP_NEIGHBOR_AGE_PROCESS_WAKEUP, 0);
1697
1698 return (0);
1699}
1700
1701static clib_error_t *
1702ip_neighbor_config_show (vlib_main_t * vm,
1703 unformat_input_t * input, vlib_cli_command_t * cmd)
1704{
Neale Rannsdc617b82020-08-20 08:22:56 +00001705 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001706
1707 /* *INDENT-OFF* */
Neale Rannsdc617b82020-08-20 08:22:56 +00001708 FOR_EACH_IP_ADDRESS_FAMILY(af) {
1709 vlib_cli_output (vm, "%U:", format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001710 vlib_cli_output (vm, " limit:%d, age:%d, recycle:%d",
Neale Rannsdc617b82020-08-20 08:22:56 +00001711 ip_neighbor_db[af].ipndb_limit,
1712 ip_neighbor_db[af].ipndb_age,
1713 ip_neighbor_db[af].ipndb_recycle);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001714 }
1715
1716 /* *INDENT-ON* */
1717 return (NULL);
1718}
1719
1720/* *INDENT-OFF* */
1721VLIB_CLI_COMMAND (show_ip_neighbor_cfg_cmd_node, static) = {
1722 .path = "show ip neighbor-config",
1723 .function = ip_neighbor_config_show,
1724 .short_help = "show ip neighbor-config",
1725};
1726/* *INDENT-ON* */
1727
1728static clib_error_t *
1729ip_neighbor_init (vlib_main_t * vm)
1730{
1731 {
1732 ip4_add_del_interface_address_callback_t cb = {
1733 .function = ip_neighbor_add_del_interface_address_v4,
1734 };
1735 vec_add1 (ip4_main.add_del_interface_address_callbacks, cb);
1736 }
1737 {
1738 ip6_add_del_interface_address_callback_t cb = {
1739 .function = ip_neighbor_add_del_interface_address_v6,
1740 };
1741 vec_add1 (ip6_main.add_del_interface_address_callbacks, cb);
1742 }
1743 {
1744 ip4_table_bind_callback_t cb = {
1745 .function = ip_neighbor_table_bind_v4,
1746 };
1747 vec_add1 (ip4_main.table_bind_callbacks, cb);
1748 }
1749 {
1750 ip6_table_bind_callback_t cb = {
1751 .function = ip_neighbor_table_bind_v6,
1752 };
1753 vec_add1 (ip6_main.table_bind_callbacks, cb);
1754 }
1755 {
1756 ethernet_address_change_ctx_t ctx = {
1757 .function = ip_neighbor_ethernet_change_mac,
1758 .function_opaque = 0,
1759 };
1760 vec_add1 (ethernet_main.address_change_callbacks, ctx);
1761 }
1762
1763 ipn_logger = vlib_log_register_class ("ip", "neighbor");
1764
Neale Rannsdc617b82020-08-20 08:22:56 +00001765 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001766
Neale Rannsdc617b82020-08-20 08:22:56 +00001767 FOR_EACH_IP_ADDRESS_FAMILY (af)
1768 ip_neighbor_list_head[af] =
Neale Rannscbe25aa2019-09-30 10:53:31 +00001769 clib_llist_make_head (ip_neighbor_elt_pool, ipne_anchor);
1770
1771 return (NULL);
1772}
1773
1774/* *INDENT-OFF* */
1775VLIB_INIT_FUNCTION (ip_neighbor_init) =
1776{
1777 .runs_after = VLIB_INITS("ip_main_init"),
1778};
1779/* *INDENT-ON* */
1780
1781/*
1782 * fd.io coding-style-patch-verification: ON
1783 *
1784 * Local Variables:
1785 * eval: (c-set-style "gnu")
1786 * End:
1787 */