blob: d341698abfbc7caa06111918e8cd6fbe9b4326c8 [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>
Ivan Shvedunovf86b9672021-02-19 23:32:18 +030026#include <vnet/ip/ip46_address.h>
Neale Rannscbe25aa2019-09-30 10:53:31 +000027#include <vnet/fib/fib_table.h>
28#include <vnet/adj/adj_mcast.h>
29
Neale Rannsfd2417b2021-07-16 14:00:16 +000030ip_neighbor_counters_t ip_neighbor_counters[] =
31{
32 [AF_IP4] = {
33 .ipnc = {
34 [VLIB_RX] = {
35 [IP_NEIGHBOR_CTR_REPLY] = {
36 .name = "arp-rx-replies",
37 .stat_segment_name = "/net/arp/rx/replies",
38 },
39 [IP_NEIGHBOR_CTR_REQUEST] = {
40 .name = "arp-rx-requests",
41 .stat_segment_name = "/net/arp/rx/requests",
42 },
43 [IP_NEIGHBOR_CTR_GRAT] = {
44 .name = "arp-rx-gratuitous",
45 .stat_segment_name = "/net/arp/rx/gratuitous",
46 },
47 },
48 [VLIB_TX] = {
49 [IP_NEIGHBOR_CTR_REPLY] = {
50 .name = "arp-tx-replies",
51 .stat_segment_name = "/net/arp/tx/replies",
52 },
53 [IP_NEIGHBOR_CTR_REQUEST] = {
54 .name = "arp-tx-requests",
55 .stat_segment_name = "/net/arp/tx/requests",
56 },
57 [IP_NEIGHBOR_CTR_GRAT] = {
58 .name = "arp-tx-gratuitous",
59 .stat_segment_name = "/net/arp/tx/gratuitous",
60 },
61 },
62 },
63 },
64 [AF_IP6] = {
65 .ipnc = {
66 [VLIB_RX] = {
67 [IP_NEIGHBOR_CTR_REPLY] = {
68 .name = "ip6-nd-rx-replies",
69 .stat_segment_name = "/net/ip6-nd/rx/replies",
70 },
71 [IP_NEIGHBOR_CTR_REQUEST] = {
72 .name = "ip6-nd-rx-requests",
73 .stat_segment_name = "/net/ip6-nd/rx/requests",
74 },
75 [IP_NEIGHBOR_CTR_GRAT] = {
76 .name = "ip6-nd-rx-gratuitous",
77 .stat_segment_name = "/net/ip6-nd/rx/gratuitous",
78 },
79 },
80 [VLIB_TX] = {
81 [IP_NEIGHBOR_CTR_REPLY] = {
82 .name = "ip6-nd-tx-replies",
83 .stat_segment_name = "/net/ip6-nd/tx/replies",
84 },
85 [IP_NEIGHBOR_CTR_REQUEST] = {
86 .name = "ip6-nd-tx-requests",
87 .stat_segment_name = "/net/ip6-nd/tx/requests",
88 },
89 [IP_NEIGHBOR_CTR_GRAT] = {
90 .name = "ip6-nd-tx-gratuitous",
91 .stat_segment_name = "/net/ip6-nd/tx/gratuitous",
92 },
93 },
94 },
95 },
96};
97
Neale Rannscbe25aa2019-09-30 10:53:31 +000098/** Pool for All IP neighbors */
99static ip_neighbor_t *ip_neighbor_pool;
100
101/** protocol specific lists of time sorted neighbors */
Neale Rannsdc617b82020-08-20 08:22:56 +0000102index_t ip_neighbor_list_head[N_AF];
Neale Rannscbe25aa2019-09-30 10:53:31 +0000103
104typedef struct ip_neighbor_elt_t_
105{
106 clib_llist_anchor_t ipne_anchor;
107 index_t ipne_index;
108} ip_neighbor_elt_t;
109
110/** Pool of linked list elemeents */
111ip_neighbor_elt_t *ip_neighbor_elt_pool;
112
113typedef struct ip_neighbor_db_t_
114{
115 /** per interface hash */
116 uword **ipndb_hash;
117 /** per-protocol limit - max number of neighbors*/
118 u32 ipndb_limit;
119 /** max age of a neighbor before it's forcibly evicted */
120 u32 ipndb_age;
121 /** when the limit is reached and new neighbors are created, should
122 * we recycle an old one */
123 bool ipndb_recycle;
124 /** per-protocol number of elements */
125 u32 ipndb_n_elts;
126 /** per-protocol number of elements per-fib-index*/
127 u32 *ipndb_n_elts_per_fib;
128} ip_neighbor_db_t;
129
130static vlib_log_class_t ipn_logger;
131
132/* DBs of neighbours one per AF */
133/* *INDENT-OFF* */
Neale Rannsdc617b82020-08-20 08:22:56 +0000134static ip_neighbor_db_t ip_neighbor_db[N_AF] = {
135 [AF_IP4] = {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000136 .ipndb_limit = 50000,
137 /* Default to not aging and not recycling */
138 .ipndb_age = 0,
139 .ipndb_recycle = false,
140 },
Neale Rannsdc617b82020-08-20 08:22:56 +0000141 [AF_IP6] = {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000142 .ipndb_limit = 50000,
143 /* Default to not aging and not recycling */
144 .ipndb_age = 0,
145 .ipndb_recycle = false,
146 }
147};
148/* *INDENT-ON* */
149
150#define IP_NEIGHBOR_DBG(...) \
151 vlib_log_debug (ipn_logger, __VA_ARGS__);
152
153#define IP_NEIGHBOR_INFO(...) \
154 vlib_log_notice (ipn_logger, __VA_ARGS__);
155
156ip_neighbor_t *
157ip_neighbor_get (index_t ipni)
158{
159 if (pool_is_free_index (ip_neighbor_pool, ipni))
160 return (NULL);
161
162 return (pool_elt_at_index (ip_neighbor_pool, ipni));
163}
164
165static index_t
166ip_neighbor_get_index (const ip_neighbor_t * ipn)
167{
168 return (ipn - ip_neighbor_pool);
169}
170
Neale Rannsc87fbb42020-04-02 17:08:28 +0000171static void
172ip_neighbor_touch (ip_neighbor_t * ipn)
173{
174 ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_STALE;
175}
176
Neale Rannscbe25aa2019-09-30 10:53:31 +0000177static bool
178ip_neighbor_is_dynamic (const ip_neighbor_t * ipn)
179{
180 return (ipn->ipn_flags & IP_NEIGHBOR_FLAG_DYNAMIC);
181}
182
Neale Rannsdc617b82020-08-20 08:22:56 +0000183const ip_address_t *
Neale Rannscbe25aa2019-09-30 10:53:31 +0000184ip_neighbor_get_ip (const ip_neighbor_t * ipn)
185{
186 return (&ipn->ipn_key->ipnk_ip);
187}
188
Neale Rannsdc617b82020-08-20 08:22:56 +0000189ip_address_family_t
190ip_neighbor_get_af (const ip_neighbor_t * ipn)
191{
192 return (ip_addr_version (&ipn->ipn_key->ipnk_ip));
193}
194
Neale Rannscbe25aa2019-09-30 10:53:31 +0000195const mac_address_t *
196ip_neighbor_get_mac (const ip_neighbor_t * ipn)
197{
198 return (&ipn->ipn_mac);
199}
200
201const u32
202ip_neighbor_get_sw_if_index (const ip_neighbor_t * ipn)
203{
204 return (ipn->ipn_key->ipnk_sw_if_index);
205}
206
207static void
208ip_neighbor_list_remove (ip_neighbor_t * ipn)
209{
210 /* new neighbours, are added to the head of the list, since the
211 * list is time sorted, newest first */
212 ip_neighbor_elt_t *elt;
213
214 if (~0 != ipn->ipn_elt)
215 {
216 elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
217
218 clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
Vladimir Isaevb2f44bd2020-07-16 17:05:18 +0300219
220 ipn->ipn_elt = ~0;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000221 }
222}
223
224static void
225ip_neighbor_refresh (ip_neighbor_t * ipn)
226{
227 /* new neighbours, are added to the head of the list, since the
228 * list is time sorted, newest first */
229 ip_neighbor_elt_t *elt, *head;
230
Neale Rannsc87fbb42020-04-02 17:08:28 +0000231 ip_neighbor_touch (ipn);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000232 ipn->ipn_time_last_updated = vlib_time_now (vlib_get_main ());
233 ipn->ipn_n_probes = 0;
234
235 if (ip_neighbor_is_dynamic (ipn))
236 {
237 if (~0 == ipn->ipn_elt)
238 /* first time insertion */
239 pool_get_zero (ip_neighbor_elt_pool, elt);
240 else
241 {
242 /* already inserted - extract first */
243 elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
244
245 clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
246 }
247 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +0000248 ip_neighbor_list_head[ip_neighbor_get_af
249 (ipn)]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000250
251 elt->ipne_index = ip_neighbor_get_index (ipn);
252 clib_llist_add (ip_neighbor_elt_pool, ipne_anchor, elt, head);
253 ipn->ipn_elt = elt - ip_neighbor_elt_pool;
254 }
255}
256
257static void
258ip_neighbor_db_add (const ip_neighbor_t * ipn)
259{
Neale Rannsdc617b82020-08-20 08:22:56 +0000260 ip_address_family_t af;
261 u32 sw_if_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000262
Neale Rannsdc617b82020-08-20 08:22:56 +0000263 af = ip_neighbor_get_af (ipn);
264 sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
265
266 vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
267
268 if (!ip_neighbor_db[af].ipndb_hash[sw_if_index])
269 ip_neighbor_db[af].ipndb_hash[sw_if_index]
Neale Rannscbe25aa2019-09-30 10:53:31 +0000270 = hash_create_mem (0, sizeof (ip_neighbor_key_t), sizeof (index_t));
271
Neale Rannsdc617b82020-08-20 08:22:56 +0000272 hash_set_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index],
273 ipn->ipn_key, ip_neighbor_get_index (ipn));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000274
Neale Rannsdc617b82020-08-20 08:22:56 +0000275 ip_neighbor_db[af].ipndb_n_elts++;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000276}
277
278static void
Neale Rannsdc617b82020-08-20 08:22:56 +0000279ip_neighbor_db_remove (const ip_neighbor_t * ipn)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000280{
Neale Rannsdc617b82020-08-20 08:22:56 +0000281 ip_address_family_t af;
282 u32 sw_if_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000283
Neale Rannsdc617b82020-08-20 08:22:56 +0000284 af = ip_neighbor_get_af (ipn);
285 sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000286
Neale Rannsdc617b82020-08-20 08:22:56 +0000287 vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
288
289 hash_unset_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index], ipn->ipn_key);
290
291 ip_neighbor_db[af].ipndb_n_elts--;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000292}
293
294static ip_neighbor_t *
295ip_neighbor_db_find (const ip_neighbor_key_t * key)
296{
Neale Rannsdc617b82020-08-20 08:22:56 +0000297 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000298 uword *p;
299
Neale Rannsdc617b82020-08-20 08:22:56 +0000300 af = ip_addr_version (&key->ipnk_ip);
301
302 if (key->ipnk_sw_if_index >= vec_len (ip_neighbor_db[af].ipndb_hash))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000303 return NULL;
304
Neale Rannsdc617b82020-08-20 08:22:56 +0000305 p = hash_get_mem (ip_neighbor_db[af].ipndb_hash
306 [key->ipnk_sw_if_index], key);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000307
308 if (p)
309 return ip_neighbor_get (p[0]);
310
311 return (NULL);
312}
313
314static u8
Neale Rannsdc617b82020-08-20 08:22:56 +0000315ip_af_type_pfx_len (ip_address_family_t type)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000316{
Neale Rannsdc617b82020-08-20 08:22:56 +0000317 return (type == AF_IP4 ? 32 : 128);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000318}
319
320static void
321ip_neighbor_adj_fib_add (ip_neighbor_t * ipn, u32 fib_index)
322{
Neale Rannsdc617b82020-08-20 08:22:56 +0000323 ip_address_family_t af;
324
325 af = ip_neighbor_get_af (ipn);
326
327 if (af == AF_IP6 &&
328 ip6_address_is_link_local_unicast (&ip_addr_v6
329 (&ipn->ipn_key->ipnk_ip)))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000330 {
331 ip6_ll_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000332 .ilp_addr = ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000333 .ilp_sw_if_index = ipn->ipn_key->ipnk_sw_if_index,
334 };
335 ipn->ipn_fib_entry_index =
336 ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE);
337 }
338 else
339 {
340 fib_protocol_t fproto;
341
Neale Rannsdc617b82020-08-20 08:22:56 +0000342 fproto = ip_address_family_to_fib_proto (af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000343
344 fib_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000345 .fp_len = ip_af_type_pfx_len (af),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000346 .fp_proto = fproto,
Neale Rannsdc617b82020-08-20 08:22:56 +0000347 .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000348 };
349
350 ipn->ipn_fib_entry_index =
351 fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ,
352 FIB_ENTRY_FLAG_ATTACHED,
353 fib_proto_to_dpo (fproto),
354 &pfx.fp_addr,
355 ipn->ipn_key->ipnk_sw_if_index,
356 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
357
Neale Rannsdc617b82020-08-20 08:22:56 +0000358 vec_validate (ip_neighbor_db[af].ipndb_n_elts_per_fib, fib_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000359
Neale Rannsdc617b82020-08-20 08:22:56 +0000360 ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]++;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000361
Neale Rannsdc617b82020-08-20 08:22:56 +0000362 if (1 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
Neale Rannscbe25aa2019-09-30 10:53:31 +0000363 fib_table_lock (fib_index, fproto, FIB_SOURCE_ADJ);
364 }
365}
366
367static void
368ip_neighbor_adj_fib_remove (ip_neighbor_t * ipn, u32 fib_index)
369{
Neale Rannsdc617b82020-08-20 08:22:56 +0000370 ip_address_family_t af;
371
372 af = ip_neighbor_get_af (ipn);
373
Neale Rannscbe25aa2019-09-30 10:53:31 +0000374 if (FIB_NODE_INDEX_INVALID != ipn->ipn_fib_entry_index)
375 {
Neale Rannsdc617b82020-08-20 08:22:56 +0000376 if (AF_IP6 == af &&
377 ip6_address_is_link_local_unicast (&ip_addr_v6
378 (&ipn->ipn_key->ipnk_ip)))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000379 {
380 ip6_ll_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000381 .ilp_addr = ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000382 .ilp_sw_if_index = ipn->ipn_key->ipnk_sw_if_index,
383 };
384 ip6_ll_table_entry_delete (&pfx);
385 }
386 else
387 {
388 fib_protocol_t fproto;
389
Neale Rannsdc617b82020-08-20 08:22:56 +0000390 fproto = ip_address_family_to_fib_proto (af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000391
392 fib_prefix_t pfx = {
Neale Rannsdc617b82020-08-20 08:22:56 +0000393 .fp_len = ip_af_type_pfx_len (af),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000394 .fp_proto = fproto,
Neale Rannsdc617b82020-08-20 08:22:56 +0000395 .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000396 };
397
398 fib_table_entry_path_remove (fib_index,
399 &pfx,
400 FIB_SOURCE_ADJ,
401 fib_proto_to_dpo (fproto),
402 &pfx.fp_addr,
403 ipn->ipn_key->ipnk_sw_if_index,
404 ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
405
Neale Rannsdc617b82020-08-20 08:22:56 +0000406 ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]--;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000407
Neale Rannsdc617b82020-08-20 08:22:56 +0000408 if (0 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
Neale Rannscbe25aa2019-09-30 10:53:31 +0000409 fib_table_unlock (fib_index, fproto, FIB_SOURCE_ADJ);
410 }
411 }
412}
413
414static void
415ip_neighbor_mk_complete (adj_index_t ai, ip_neighbor_t * ipn)
416{
417 adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
418 ethernet_build_rewrite (vnet_get_main (),
419 ipn->
420 ipn_key->ipnk_sw_if_index,
421 adj_get_link_type (ai),
422 ipn->ipn_mac.bytes));
423}
424
425static void
426ip_neighbor_mk_incomplete (adj_index_t ai)
427{
428 ip_adjacency_t *adj = adj_get (ai);
429
430 adj_nbr_update_rewrite (ai,
431 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
432 ethernet_build_rewrite (vnet_get_main (),
433 adj->
434 rewrite_header.sw_if_index,
Neale Rannsfca3c6a2019-12-31 03:49:34 +0000435 VNET_LINK_ARP,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000436 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
437}
438
439static adj_walk_rc_t
440ip_neighbor_mk_complete_walk (adj_index_t ai, void *ctx)
441{
442 ip_neighbor_t *ipn = ctx;
443
444 ip_neighbor_mk_complete (ai, ipn);
445
446 return (ADJ_WALK_RC_CONTINUE);
447}
448
449static adj_walk_rc_t
450ip_neighbor_mk_incomplete_walk (adj_index_t ai, void *ctx)
451{
452 ip_neighbor_mk_incomplete (ai);
453
454 return (ADJ_WALK_RC_CONTINUE);
455}
456
457static void
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000458ip_neighbor_destroy (ip_neighbor_t * ipn)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000459{
Neale Rannsdc617b82020-08-20 08:22:56 +0000460 ip_address_family_t af;
461
462 af = ip_neighbor_get_af (ipn);
463
Neale Rannscbe25aa2019-09-30 10:53:31 +0000464 IP_NEIGHBOR_DBG ("free: %U", format_ip_neighbor,
465 ip_neighbor_get_index (ipn));
466
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000467 ip_neighbor_publish (ip_neighbor_get_index (ipn),
468 IP_NEIGHBOR_EVENT_REMOVED);
469
Neale Rannscbe25aa2019-09-30 10:53:31 +0000470 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +0000471 ip_address_family_to_fib_proto (af),
472 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000473 ip_neighbor_mk_incomplete_walk, ipn);
474 ip_neighbor_adj_fib_remove
475 (ipn,
476 fib_table_get_index_for_sw_if_index
Neale Rannsdc617b82020-08-20 08:22:56 +0000477 (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000478
479 ip_neighbor_list_remove (ipn);
Neale Rannsdc617b82020-08-20 08:22:56 +0000480 ip_neighbor_db_remove (ipn);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000481 clib_mem_free (ipn->ipn_key);
482
483 pool_put (ip_neighbor_pool, ipn);
484}
485
486static bool
Neale Rannsdc617b82020-08-20 08:22:56 +0000487ip_neighbor_force_reuse (ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000488{
Neale Rannsdc617b82020-08-20 08:22:56 +0000489 if (!ip_neighbor_db[af].ipndb_recycle)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000490 return false;
491
492 /* pluck the oldest entry, which is the one from the end of the list */
493 ip_neighbor_elt_t *elt, *head;
494
Neale Rannsdc617b82020-08-20 08:22:56 +0000495 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000496
497 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
498 return (false);
499
500 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000501 ip_neighbor_destroy (ip_neighbor_get (elt->ipne_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000502
503 return (true);
504}
505
506static ip_neighbor_t *
507ip_neighbor_alloc (const ip_neighbor_key_t * key,
508 const mac_address_t * mac, ip_neighbor_flags_t flags)
509{
Neale Rannsdc617b82020-08-20 08:22:56 +0000510 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000511 ip_neighbor_t *ipn;
512
Neale Rannsdc617b82020-08-20 08:22:56 +0000513 af = ip_addr_version (&key->ipnk_ip);
514
515 if (ip_neighbor_db[af].ipndb_limit &&
516 (ip_neighbor_db[af].ipndb_n_elts >= ip_neighbor_db[af].ipndb_limit))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000517 {
Neale Rannsdc617b82020-08-20 08:22:56 +0000518 if (!ip_neighbor_force_reuse (af))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000519 return (NULL);
520 }
521
522 pool_get_zero (ip_neighbor_pool, ipn);
523
524 ipn->ipn_key = clib_mem_alloc (sizeof (*ipn->ipn_key));
525 clib_memcpy (ipn->ipn_key, key, sizeof (*ipn->ipn_key));
526
527 ipn->ipn_fib_entry_index = FIB_NODE_INDEX_INVALID;
528 ipn->ipn_flags = flags;
529 ipn->ipn_elt = ~0;
530
531 mac_address_copy (&ipn->ipn_mac, mac);
532
533 ip_neighbor_db_add (ipn);
534
535 /* create the adj-fib. the entry in the FIB table for the peer's interface */
536 if (!(ipn->ipn_flags & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY))
537 ip_neighbor_adj_fib_add
538 (ipn, fib_table_get_index_for_sw_if_index
Neale Rannsdc617b82020-08-20 08:22:56 +0000539 (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000540
541 return (ipn);
542}
543
544int
Neale Rannsdc617b82020-08-20 08:22:56 +0000545ip_neighbor_add (const ip_address_t * ip,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000546 const mac_address_t * mac,
547 u32 sw_if_index,
548 ip_neighbor_flags_t flags, u32 * stats_index)
549{
550 fib_protocol_t fproto;
551 ip_neighbor_t *ipn;
552
553 /* main thread only */
554 ASSERT (0 == vlib_get_thread_index ());
555
Neale Rannsdc617b82020-08-20 08:22:56 +0000556 fproto = ip_address_family_to_fib_proto (ip_addr_version (ip));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000557
558 const ip_neighbor_key_t key = {
559 .ipnk_ip = *ip,
560 .ipnk_sw_if_index = sw_if_index,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000561 };
562
563 ipn = ip_neighbor_db_find (&key);
564
565 if (ipn)
566 {
567 IP_NEIGHBOR_DBG ("update: %U, %U",
568 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +0000569 sw_if_index, format_ip_address, ip,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000570 format_ip_neighbor_flags, flags, format_mac_address_t,
571 mac);
572
Neale Rannsc87fbb42020-04-02 17:08:28 +0000573 ip_neighbor_touch (ipn);
574
Neale Rannscbe25aa2019-09-30 10:53:31 +0000575 /* Refuse to over-write static neighbor entry. */
576 if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
577 (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
578 {
579 /* if MAC address match, still check to send event */
580 if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
581 goto check_customers;
582 return -2;
583 }
584
Vladimir Isaevb2f44bd2020-07-16 17:05:18 +0300585 /* A dynamic entry can become static, but not vice-versa.
586 * i.e. since if it was programmed by the CP then it must
587 * be removed by the CP */
588 if ((flags & IP_NEIGHBOR_FLAG_STATIC) &&
589 !(ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
590 {
591 ip_neighbor_list_remove (ipn);
592 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STATIC;
593 ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
594 }
595
Neale Rannscbe25aa2019-09-30 10:53:31 +0000596 /*
597 * prevent a DoS attack from the data-plane that
598 * spams us with no-op updates to the MAC address
599 */
600 if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
601 {
602 ip_neighbor_refresh (ipn);
603 goto check_customers;
604 }
605
606 mac_address_copy (&ipn->ipn_mac, mac);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000607 }
608 else
609 {
610 IP_NEIGHBOR_INFO ("add: %U, %U",
611 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +0000612 sw_if_index, format_ip_address, ip,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000613 format_ip_neighbor_flags, flags, format_mac_address_t,
614 mac);
615
616 ipn = ip_neighbor_alloc (&key, mac, flags);
617
618 if (NULL == ipn)
619 return VNET_API_ERROR_LIMIT_EXCEEDED;
620 }
621
622 /* Update time stamp and flags. */
623 ip_neighbor_refresh (ipn);
624
625 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +0000626 fproto, &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000627 ip_neighbor_mk_complete_walk, ipn);
628
629check_customers:
630 /* Customer(s) requesting event for this address? */
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000631 ip_neighbor_publish (ip_neighbor_get_index (ipn), IP_NEIGHBOR_EVENT_ADDED);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000632
633 if (stats_index)
634 *stats_index = adj_nbr_find (fproto,
635 fib_proto_to_link (fproto),
Neale Rannsdc617b82020-08-20 08:22:56 +0000636 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +0000637 ipn->ipn_key->ipnk_sw_if_index);
638 return 0;
639}
640
641int
Neale Rannsdc617b82020-08-20 08:22:56 +0000642ip_neighbor_del (const ip_address_t * ip, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000643{
644 ip_neighbor_t *ipn;
645
646 /* main thread only */
647 ASSERT (0 == vlib_get_thread_index ());
648
649 IP_NEIGHBOR_INFO ("delete: %U, %U",
650 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +0000651 sw_if_index, format_ip_address, ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000652
653 const ip_neighbor_key_t key = {
654 .ipnk_ip = *ip,
655 .ipnk_sw_if_index = sw_if_index,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000656 };
657
658 ipn = ip_neighbor_db_find (&key);
659
660 if (NULL == ipn)
661 return (VNET_API_ERROR_NO_SUCH_ENTRY);
662
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000663 ip_neighbor_destroy (ipn);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000664
665 return (0);
666}
667
Neale Ranns240dcb22020-04-23 09:04:59 +0000668typedef struct ip_neighbor_del_all_ctx_t_
669{
670 index_t *ipn_del;
671} ip_neighbor_del_all_ctx_t;
672
673static walk_rc_t
674ip_neighbor_del_all_walk_cb (index_t ipni, void *arg)
675{
676 ip_neighbor_del_all_ctx_t *ctx = arg;
677
678 vec_add1 (ctx->ipn_del, ipni);
679
680 return (WALK_CONTINUE);
681}
682
683void
Neale Rannsdc617b82020-08-20 08:22:56 +0000684ip_neighbor_del_all (ip_address_family_t af, u32 sw_if_index)
Neale Ranns240dcb22020-04-23 09:04:59 +0000685{
686 IP_NEIGHBOR_INFO ("delete-all: %U, %U",
Neale Rannsdc617b82020-08-20 08:22:56 +0000687 format_ip_address_family, af,
Neale Ranns240dcb22020-04-23 09:04:59 +0000688 format_vnet_sw_if_index_name, vnet_get_main (),
689 sw_if_index);
690
691 ip_neighbor_del_all_ctx_t ctx = {
692 .ipn_del = NULL,
693 };
694 index_t *ipni;
695
Neale Rannsdc617b82020-08-20 08:22:56 +0000696 ip_neighbor_walk (af, sw_if_index, ip_neighbor_del_all_walk_cb, &ctx);
Neale Ranns240dcb22020-04-23 09:04:59 +0000697
Neale Ranns4ac36bc2020-11-20 13:05:59 +0000698 vec_foreach (ipni,
699 ctx.ipn_del) ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Ranns240dcb22020-04-23 09:04:59 +0000700 vec_free (ctx.ipn_del);
701}
702
Neale Rannscbe25aa2019-09-30 10:53:31 +0000703void
704ip_neighbor_update (vnet_main_t * vnm, adj_index_t ai)
705{
706 ip_neighbor_t *ipn;
707 ip_adjacency_t *adj;
708
709 adj = adj_get (ai);
710
711 ip_neighbor_key_t key = {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000712 .ipnk_sw_if_index = adj->rewrite_header.sw_if_index,
713 };
Neale Rannsdc617b82020-08-20 08:22:56 +0000714
715 ip_address_from_46 (&adj->sub_type.nbr.next_hop,
716 adj->ia_nh_proto, &key.ipnk_ip);
717
Neale Rannscbe25aa2019-09-30 10:53:31 +0000718 ipn = ip_neighbor_db_find (&key);
719
720 switch (adj->lookup_next_index)
721 {
722 case IP_LOOKUP_NEXT_ARP:
723 if (NULL != ipn)
724 {
725 adj_nbr_walk_nh (adj->rewrite_header.sw_if_index,
726 adj->ia_nh_proto,
Neale Rannsdc617b82020-08-20 08:22:56 +0000727 &adj->sub_type.nbr.next_hop,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000728 ip_neighbor_mk_complete_walk, ipn);
729 }
730 else
731 {
732 /*
733 * no matching ARP entry.
734 * construct the rewrite required to for an ARP packet, and stick
735 * that in the adj's pipe to smoke.
736 */
737 adj_nbr_update_rewrite
738 (ai,
739 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
740 ethernet_build_rewrite
741 (vnm,
742 adj->rewrite_header.sw_if_index,
743 VNET_LINK_ARP,
744 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
745
746 /*
747 * since the FIB has added this adj for a route, it makes sense it
748 * may want to forward traffic sometime soon. Let's send a
749 * speculative ARP. just one. If we were to do periodically that
750 * wouldn't be bad either, but that's more code than i'm prepared to
751 * write at this time for relatively little reward.
752 */
Steven Luong3d5f6222020-01-30 09:11:18 -0800753 /*
754 * adj_nbr_update_rewrite may actually call fib_walk_sync.
755 * fib_walk_sync may allocate a new adjacency and potentially cause
756 * a realloc for adj_pool. When that happens, adj pointer is no
757 * longer valid here.x We refresh adj pointer accordingly.
758 */
759 adj = adj_get (ai);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000760 ip_neighbor_probe (adj);
761 }
762 break;
Neale Rannsea8adf72021-08-13 08:10:59 +0000763 case IP_LOOKUP_NEXT_REWRITE:
764 /* Update of an existing rewrite adjacency happens e.g. when the
765 * interface's MAC address changes */
766 if (NULL != ipn)
767 ip_neighbor_mk_complete (ai, ipn);
768 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000769 case IP_LOOKUP_NEXT_GLEAN:
770 case IP_LOOKUP_NEXT_BCAST:
771 case IP_LOOKUP_NEXT_MCAST:
772 case IP_LOOKUP_NEXT_DROP:
773 case IP_LOOKUP_NEXT_PUNT:
774 case IP_LOOKUP_NEXT_LOCAL:
Neale Rannscbe25aa2019-09-30 10:53:31 +0000775 case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
776 case IP_LOOKUP_NEXT_MIDCHAIN:
777 case IP_LOOKUP_NEXT_ICMP_ERROR:
778 case IP_LOOKUP_N_NEXT:
779 ASSERT (0);
780 break;
781 }
782}
783
784void
785ip_neighbor_learn (const ip_neighbor_learn_t * l)
786{
Neale Rannsdc617b82020-08-20 08:22:56 +0000787 ip_neighbor_add (&l->ip, &l->mac, l->sw_if_index,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000788 IP_NEIGHBOR_FLAG_DYNAMIC, NULL);
789}
790
791static clib_error_t *
792ip_neighbor_cmd (vlib_main_t * vm,
793 unformat_input_t * input, vlib_cli_command_t * cmd)
794{
Neale Rannsdc617b82020-08-20 08:22:56 +0000795 ip_address_t ip = IP_ADDRESS_V6_ALL_0S;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000796 mac_address_t mac = ZERO_MAC_ADDRESS;
797 vnet_main_t *vnm = vnet_get_main ();
798 ip_neighbor_flags_t flags;
799 u32 sw_if_index = ~0;
Ole Troan1fe132e2023-10-13 08:52:47 +0200800 int is_add = 1, is_flush = 0;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000801 int count = 1;
802
803 flags = IP_NEIGHBOR_FLAG_DYNAMIC;
804
805 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
806 {
807 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
808 if (unformat (input, "%U %U %U",
809 unformat_vnet_sw_interface, vnm, &sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +0000810 unformat_ip_address, &ip, unformat_mac_address_t, &mac))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000811 ;
812 else if (unformat (input, "delete") || unformat (input, "del"))
813 is_add = 0;
Ole Troan1fe132e2023-10-13 08:52:47 +0200814 else if (unformat (input, "flush"))
815 is_flush = 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000816 else if (unformat (input, "static"))
817 {
818 flags |= IP_NEIGHBOR_FLAG_STATIC;
819 flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
820 }
821 else if (unformat (input, "no-fib-entry"))
822 flags |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;
823 else if (unformat (input, "count %d", &count))
824 ;
825 else
826 break;
827 }
828
Ole Troan1fe132e2023-10-13 08:52:47 +0200829 if (is_flush)
830 {
831 ip_neighbor_del_all (AF_IP4, sw_if_index);
832 ip_neighbor_del_all (AF_IP6, sw_if_index);
833 return NULL;
834 }
835
Neale Rannscbe25aa2019-09-30 10:53:31 +0000836 if (sw_if_index == ~0 ||
Neale Rannsdc617b82020-08-20 08:22:56 +0000837 ip_address_is_zero (&ip) || mac_address_is_zero (&mac))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000838 return clib_error_return (0,
839 "specify interface, IP address and MAC: `%U'",
840 format_unformat_error, input);
841
842 while (count)
843 {
844 if (is_add)
Neale Rannsdc617b82020-08-20 08:22:56 +0000845 ip_neighbor_add (&ip, &mac, sw_if_index, flags, NULL);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000846 else
Neale Rannsdc617b82020-08-20 08:22:56 +0000847 ip_neighbor_del (&ip, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000848
Neale Rannsdc617b82020-08-20 08:22:56 +0000849 ip_address_increment (&ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000850 mac_address_increment (&mac);
851
852 --count;
853 }
854
855 return NULL;
856}
857
858/* *INDENT-OFF* */
859/*?
860 * Add or delete IPv4 ARP cache entries.
861 *
Huawei LI368dab32022-10-14 21:37:23 +0800862 * @note 'set ip neighbor' options (e.g. delete, static,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000863 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
864 * any order and combination.
865 *
866 * @cliexpar
867 * @parblock
868 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
869 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
870 * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
Huawei LI368dab32022-10-14 21:37:23 +0800871 * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3
872 * de:ad:be:ef:ba:be}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000873 *
Huawei LI368dab32022-10-14 21:37:23 +0800874 * To add or delete an IPv4 ARP cache entry
Neale Rannscbe25aa2019-09-30 10:53:31 +0000875 * table:
Huawei LI368dab32022-10-14 21:37:23 +0800876 * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
877 * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3
878 * dead.beef.babe}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000879 *
880 * Add or delete IPv4 static ARP cache entries as follows:
Huawei LI368dab32022-10-14 21:37:23 +0800881 * @cliexcmd{set ip neighbor static GigabitEthernet2/0/0 6.0.0.3
882 * dead.beef.babe}
883 * @cliexcmd{set ip neighbor static delete GigabitEthernet2/0/0 6.0.0.3
884 * dead.beef.babe}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000885 *
886 * For testing / debugging purposes, the 'set ip neighbor' command can add or
887 * delete multiple entries. Supply the 'count N' parameter:
Huawei LI368dab32022-10-14 21:37:23 +0800888 * @cliexcmd{set ip neighbor count 10 GigabitEthernet2/0/0 6.0.0.3
889 * dead.beef.babe}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000890 * @endparblock
891 ?*/
892VLIB_CLI_COMMAND (ip_neighbor_command, static) = {
893 .path = "set ip neighbor",
Huawei LI368dab32022-10-14 21:37:23 +0800894 .short_help = "set ip neighbor [del] <intfc> <ip-address> <mac-address> "
895 "[static] [no-fib-entry] [count <count>]",
Neale Rannscbe25aa2019-09-30 10:53:31 +0000896 .function = ip_neighbor_cmd,
897};
898VLIB_CLI_COMMAND (ip_neighbor_command2, static) = {
899 .path = "ip neighbor",
Ole Troan1fe132e2023-10-13 08:52:47 +0200900 .short_help = "ip neighbor [del] [flush] <intfc> <ip-address> <mac-address> "
Huawei LI368dab32022-10-14 21:37:23 +0800901 "[static] [no-fib-entry] [count <count>]",
Neale Rannscbe25aa2019-09-30 10:53:31 +0000902 .function = ip_neighbor_cmd,
903};
904/* *INDENT-ON* */
905
906static int
907ip_neighbor_sort (void *a1, void *a2)
908{
909 index_t *ipni1 = a1, *ipni2 = a2;
910 ip_neighbor_t *ipn1, *ipn2;
911 int cmp;
912
913 ipn1 = ip_neighbor_get (*ipni1);
914 ipn2 = ip_neighbor_get (*ipni2);
915
916 cmp = vnet_sw_interface_compare (vnet_get_main (),
917 ipn1->ipn_key->ipnk_sw_if_index,
918 ipn2->ipn_key->ipnk_sw_if_index);
919 if (!cmp)
Neale Rannsdc617b82020-08-20 08:22:56 +0000920 cmp = ip_address_cmp (&ipn1->ipn_key->ipnk_ip, &ipn2->ipn_key->ipnk_ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000921 return cmp;
922}
923
924static index_t *
Neale Rannsdc617b82020-08-20 08:22:56 +0000925ip_neighbor_entries (u32 sw_if_index, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000926{
927 index_t *ipnis = NULL;
928 ip_neighbor_t *ipn;
929
930 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +0100931 pool_foreach (ipn, ip_neighbor_pool)
932 {
Michael Yubedf48a2020-05-08 16:42:58 +0800933 if ((sw_if_index == ~0 ||
934 ipn->ipn_key->ipnk_sw_if_index == sw_if_index) &&
Neale Rannsdc617b82020-08-20 08:22:56 +0000935 (N_AF == af ||
936 ip_neighbor_get_af(ipn) == af))
Michael Yubedf48a2020-05-08 16:42:58 +0800937 vec_add1 (ipnis, ip_neighbor_get_index(ipn));
Damjan Marionb2c31b62020-12-13 21:47:40 +0100938 }
Neale Rannscbe25aa2019-09-30 10:53:31 +0000939
940 /* *INDENT-ON* */
941
942 if (ipnis)
943 vec_sort_with_function (ipnis, ip_neighbor_sort);
944 return ipnis;
945}
946
947static clib_error_t *
948ip_neighbor_show_sorted_i (vlib_main_t * vm,
949 unformat_input_t * input,
Neale Rannsdc617b82020-08-20 08:22:56 +0000950 vlib_cli_command_t * cmd, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000951{
952 ip_neighbor_elt_t *elt, *head;
953
Neale Rannsdc617b82020-08-20 08:22:56 +0000954 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000955
956
957 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
958 "Flags", "Ethernet", "Interface");
959
960 /* *INDENT-OFF*/
961 /* the list is time sorted, newest first, so start from the back
962 * and work forwards. Stop when we get to one that is alive */
963 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
964 ipne_anchor, head, elt,
965 ({
966 vlib_cli_output (vm, "%U", format_ip_neighbor, elt->ipne_index);
967 }));
968 /* *INDENT-ON*/
969
970 return (NULL);
971}
972
973static clib_error_t *
974ip_neighbor_show_i (vlib_main_t * vm,
975 unformat_input_t * input,
Neale Rannsdc617b82020-08-20 08:22:56 +0000976 vlib_cli_command_t * cmd, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000977{
978 index_t *ipni, *ipnis = NULL;
979 u32 sw_if_index;
980
981 /* Filter entries by interface if given. */
982 sw_if_index = ~0;
983 (void) unformat_user (input, unformat_vnet_sw_interface, vnet_get_main (),
984 &sw_if_index);
985
Neale Rannsdc617b82020-08-20 08:22:56 +0000986 ipnis = ip_neighbor_entries (sw_if_index, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000987
988 if (ipnis)
989 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
990 "Flags", "Ethernet", "Interface");
991
992 vec_foreach (ipni, ipnis)
993 {
994 vlib_cli_output (vm, "%U", format_ip_neighbor, *ipni);
995 }
996 vec_free (ipnis);
997
998 return (NULL);
999}
1000
1001static clib_error_t *
1002ip_neighbor_show (vlib_main_t * vm,
1003 unformat_input_t * input, vlib_cli_command_t * cmd)
1004{
Neale Rannsdc617b82020-08-20 08:22:56 +00001005 return (ip_neighbor_show_i (vm, input, cmd, N_AF));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001006}
1007
1008static clib_error_t *
1009ip6_neighbor_show (vlib_main_t * vm,
1010 unformat_input_t * input, vlib_cli_command_t * cmd)
1011{
Neale Rannsdc617b82020-08-20 08:22:56 +00001012 return (ip_neighbor_show_i (vm, input, cmd, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001013}
1014
1015static clib_error_t *
1016ip4_neighbor_show (vlib_main_t * vm,
1017 unformat_input_t * input, vlib_cli_command_t * cmd)
1018{
Neale Rannsdc617b82020-08-20 08:22:56 +00001019 return (ip_neighbor_show_i (vm, input, cmd, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001020}
1021
1022static clib_error_t *
1023ip6_neighbor_show_sorted (vlib_main_t * vm,
1024 unformat_input_t * input, vlib_cli_command_t * cmd)
1025{
Neale Rannsdc617b82020-08-20 08:22:56 +00001026 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001027}
1028
1029static clib_error_t *
1030ip4_neighbor_show_sorted (vlib_main_t * vm,
1031 unformat_input_t * input, vlib_cli_command_t * cmd)
1032{
Neale Rannsdc617b82020-08-20 08:22:56 +00001033 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001034}
1035
1036/*?
1037 * Display all the IP neighbor entries.
1038 *
1039 * @cliexpar
1040 * Example of how to display the IPv4 ARP table:
1041 * @cliexstart{show ip neighbor}
1042 * Time FIB IP4 Flags Ethernet Interface
1043 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1044 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1045 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1046 * Proxy arps enabled for:
1047 * Fib_index 0 6.0.0.1 - 6.0.0.11
1048 * @cliexend
1049 ?*/
1050/* *INDENT-OFF* */
1051VLIB_CLI_COMMAND (show_ip_neighbors_cmd_node, static) = {
1052 .path = "show ip neighbors",
1053 .function = ip_neighbor_show,
1054 .short_help = "show ip neighbors [interface]",
1055};
1056VLIB_CLI_COMMAND (show_ip4_neighbors_cmd_node, static) = {
1057 .path = "show ip4 neighbors",
1058 .function = ip4_neighbor_show,
1059 .short_help = "show ip4 neighbors [interface]",
1060};
1061VLIB_CLI_COMMAND (show_ip6_neighbors_cmd_node, static) = {
1062 .path = "show ip6 neighbors",
1063 .function = ip6_neighbor_show,
1064 .short_help = "show ip6 neighbors [interface]",
1065};
1066VLIB_CLI_COMMAND (show_ip_neighbor_cmd_node, static) = {
1067 .path = "show ip neighbor",
1068 .function = ip_neighbor_show,
1069 .short_help = "show ip neighbor [interface]",
1070};
1071VLIB_CLI_COMMAND (show_ip4_neighbor_cmd_node, static) = {
1072 .path = "show ip4 neighbor",
1073 .function = ip4_neighbor_show,
1074 .short_help = "show ip4 neighbor [interface]",
1075};
1076VLIB_CLI_COMMAND (show_ip6_neighbor_cmd_node, static) = {
1077 .path = "show ip6 neighbor",
1078 .function = ip6_neighbor_show,
1079 .short_help = "show ip6 neighbor [interface]",
1080};
1081VLIB_CLI_COMMAND (show_ip4_neighbor_sorted_cmd_node, static) = {
1082 .path = "show ip4 neighbor-sorted",
1083 .function = ip4_neighbor_show_sorted,
1084 .short_help = "show ip4 neighbor-sorted",
1085};
1086VLIB_CLI_COMMAND (show_ip6_neighbor_sorted_cmd_node, static) = {
1087 .path = "show ip6 neighbor-sorted",
1088 .function = ip6_neighbor_show_sorted,
1089 .short_help = "show ip6 neighbor-sorted",
1090};
1091/* *INDENT-ON* */
1092
Neale Rannsdc617b82020-08-20 08:22:56 +00001093static ip_neighbor_vft_t ip_nbr_vfts[N_AF];
Neale Rannscbe25aa2019-09-30 10:53:31 +00001094
1095void
Neale Rannsdc617b82020-08-20 08:22:56 +00001096ip_neighbor_register (ip_address_family_t af, const ip_neighbor_vft_t * vft)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001097{
Neale Rannsdc617b82020-08-20 08:22:56 +00001098 ip_nbr_vfts[af] = *vft;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001099}
1100
1101void
Neale Rannsfd2417b2021-07-16 14:00:16 +00001102ip_neighbor_probe_dst (u32 sw_if_index, u32 thread_index,
1103 ip_address_family_t af, const ip46_address_t *dst)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001104{
Neale Rannse2fe0972020-11-26 08:37:27 +00001105 if (!vnet_sw_interface_is_admin_up (vnet_get_main (), sw_if_index))
Neale Rannscbe25aa2019-09-30 10:53:31 +00001106 return;
1107
Neale Rannse2fe0972020-11-26 08:37:27 +00001108 switch (af)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001109 {
Neale Rannse2fe0972020-11-26 08:37:27 +00001110 case AF_IP6:
Neale Rannsfd2417b2021-07-16 14:00:16 +00001111 ip6_neighbor_probe_dst (sw_if_index, thread_index, &dst->ip6);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001112 break;
Neale Rannse2fe0972020-11-26 08:37:27 +00001113 case AF_IP4:
Neale Rannsfd2417b2021-07-16 14:00:16 +00001114 ip4_neighbor_probe_dst (sw_if_index, thread_index, &dst->ip4);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001115 break;
1116 }
1117}
1118
1119void
1120ip_neighbor_probe (const ip_adjacency_t * adj)
1121{
Neale Rannse2fe0972020-11-26 08:37:27 +00001122 ip_neighbor_probe_dst (adj->rewrite_header.sw_if_index,
Neale Rannsfd2417b2021-07-16 14:00:16 +00001123 vlib_get_thread_index (),
Neale Rannse2fe0972020-11-26 08:37:27 +00001124 ip_address_family_from_fib_proto (adj->ia_nh_proto),
1125 &adj->sub_type.nbr.next_hop);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001126}
1127
1128void
Neale Rannsdc617b82020-08-20 08:22:56 +00001129ip_neighbor_walk (ip_address_family_t af,
Neale Rannscbe25aa2019-09-30 10:53:31 +00001130 u32 sw_if_index, ip_neighbor_walk_cb_t cb, void *ctx)
1131{
1132 ip_neighbor_key_t *key;
1133 index_t ipni;
1134
1135 if (~0 == sw_if_index)
1136 {
1137 uword **hash;
1138
Neale Rannsdc617b82020-08-20 08:22:56 +00001139 vec_foreach (hash, ip_neighbor_db[af].ipndb_hash)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001140 {
1141 /* *INDENT-OFF* */
1142 hash_foreach (key, ipni, *hash,
1143 ({
Ruslan Babayev24b417c2020-02-02 17:30:31 -08001144 if (WALK_STOP == cb (ipni, ctx))
1145 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001146 }));
1147 /* *INDENT-ON* */
1148 }
1149 }
1150 else
1151 {
1152 uword *hash;
1153
Neale Rannsdc617b82020-08-20 08:22:56 +00001154 if (vec_len (ip_neighbor_db[af].ipndb_hash) <= sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001155 return;
Neale Rannsdc617b82020-08-20 08:22:56 +00001156 hash = ip_neighbor_db[af].ipndb_hash[sw_if_index];
Neale Rannscbe25aa2019-09-30 10:53:31 +00001157
1158 /* *INDENT-OFF* */
1159 hash_foreach (key, ipni, hash,
1160 ({
Ruslan Babayev24b417c2020-02-02 17:30:31 -08001161 if (WALK_STOP == cb (ipni, ctx))
1162 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001163 }));
1164 /* *INDENT-ON* */
1165 }
1166}
1167
1168int
1169ip4_neighbor_proxy_add (u32 fib_index,
1170 const ip4_address_t * start,
1171 const ip4_address_t * end)
1172{
Neale Rannsdc617b82020-08-20 08:22:56 +00001173 if (ip_nbr_vfts[AF_IP4].inv_proxy4_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001174 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001175 return (ip_nbr_vfts[AF_IP4].inv_proxy4_add (fib_index, start, end));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001176 }
1177
1178 return (-1);
1179}
1180
1181int
1182ip4_neighbor_proxy_delete (u32 fib_index,
1183 const ip4_address_t * start,
1184 const ip4_address_t * end)
1185{
Neale Rannsdc617b82020-08-20 08:22:56 +00001186 if (ip_nbr_vfts[AF_IP4].inv_proxy4_del)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001187 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001188 return (ip_nbr_vfts[AF_IP4].inv_proxy4_del (fib_index, start, end));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001189 }
1190 return -1;
1191}
1192
1193int
1194ip4_neighbor_proxy_enable (u32 sw_if_index)
1195{
Neale Rannsdc617b82020-08-20 08:22:56 +00001196 if (ip_nbr_vfts[AF_IP4].inv_proxy4_enable)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001197 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001198 return (ip_nbr_vfts[AF_IP4].inv_proxy4_enable (sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001199 }
1200 return -1;
1201}
1202
1203int
1204ip4_neighbor_proxy_disable (u32 sw_if_index)
1205{
Neale Rannsdc617b82020-08-20 08:22:56 +00001206 if (ip_nbr_vfts[AF_IP4].inv_proxy4_disable)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001207 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001208 return (ip_nbr_vfts[AF_IP4].inv_proxy4_disable (sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001209 }
1210 return -1;
1211}
1212
1213int
1214ip6_neighbor_proxy_add (u32 sw_if_index, const ip6_address_t * addr)
1215{
Neale Rannsdc617b82020-08-20 08:22:56 +00001216 if (ip_nbr_vfts[AF_IP6].inv_proxy6_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001217 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001218 return (ip_nbr_vfts[AF_IP6].inv_proxy6_add (sw_if_index, addr));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001219 }
1220 return -1;
1221}
1222
1223int
1224ip6_neighbor_proxy_del (u32 sw_if_index, const ip6_address_t * addr)
1225{
Neale Rannsdc617b82020-08-20 08:22:56 +00001226 if (ip_nbr_vfts[AF_IP6].inv_proxy6_del)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001227 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001228 return (ip_nbr_vfts[AF_IP6].inv_proxy6_del (sw_if_index, addr));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001229 }
1230 return -1;
1231}
1232
Neale Rannscbe25aa2019-09-30 10:53:31 +00001233void
Neale Rannsdc617b82020-08-20 08:22:56 +00001234ip_neighbor_populate (ip_address_family_t af, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001235{
1236 index_t *ipnis = NULL, *ipni;
1237 ip_neighbor_t *ipn;
1238
1239 IP_NEIGHBOR_DBG ("populate: %U %U",
1240 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001241 sw_if_index, format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001242
1243 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001244 pool_foreach (ipn, ip_neighbor_pool)
1245 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001246 if (ip_neighbor_get_af(ipn) == af &&
Neale Rannscbe25aa2019-09-30 10:53:31 +00001247 ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1248 vec_add1 (ipnis, ipn - ip_neighbor_pool);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001249 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001250 /* *INDENT-ON* */
1251
1252 vec_foreach (ipni, ipnis)
1253 {
1254 ipn = ip_neighbor_get (*ipni);
1255
1256 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +00001257 ip_address_family_to_fib_proto (ip_neighbor_get_af
1258 (ipn)),
1259 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001260 ip_neighbor_mk_complete_walk, ipn);
1261 }
1262 vec_free (ipnis);
1263}
1264
1265void
Neale Rannsdc617b82020-08-20 08:22:56 +00001266ip_neighbor_flush (ip_address_family_t af, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001267{
1268 index_t *ipnis = NULL, *ipni;
1269 ip_neighbor_t *ipn;
1270
Neale Rannsdc617b82020-08-20 08:22:56 +00001271
Neale Rannscbe25aa2019-09-30 10:53:31 +00001272 IP_NEIGHBOR_DBG ("flush: %U %U",
1273 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001274 sw_if_index, format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001275
1276 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001277 pool_foreach (ipn, ip_neighbor_pool)
1278 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001279 if (ip_neighbor_get_af(ipn) == af &&
Neale Rannscbe25aa2019-09-30 10:53:31 +00001280 ipn->ipn_key->ipnk_sw_if_index == sw_if_index &&
1281 ip_neighbor_is_dynamic (ipn))
1282 vec_add1 (ipnis, ipn - ip_neighbor_pool);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001283 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001284 /* *INDENT-ON* */
1285
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001286 vec_foreach (ipni, ipnis) ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001287 vec_free (ipnis);
1288}
1289
Stanislav Zaikin3bad8b62022-04-25 19:11:36 +02001290walk_rc_t
Neale Rannsc87fbb42020-04-02 17:08:28 +00001291ip_neighbor_mark_one (index_t ipni, void *ctx)
1292{
1293 ip_neighbor_t *ipn;
1294
1295 ipn = ip_neighbor_get (ipni);
1296
1297 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
1298
1299 return (WALK_CONTINUE);
1300}
1301
1302void
Neale Rannsdc617b82020-08-20 08:22:56 +00001303ip_neighbor_mark (ip_address_family_t af)
Neale Rannsc87fbb42020-04-02 17:08:28 +00001304{
Neale Rannsdc617b82020-08-20 08:22:56 +00001305 ip_neighbor_walk (af, ~0, ip_neighbor_mark_one, NULL);
Neale Rannsc87fbb42020-04-02 17:08:28 +00001306}
1307
1308typedef struct ip_neighbor_sweep_ctx_t_
1309{
1310 index_t *ipnsc_stale;
1311} ip_neighbor_sweep_ctx_t;
1312
1313static walk_rc_t
1314ip_neighbor_sweep_one (index_t ipni, void *arg)
1315{
1316 ip_neighbor_sweep_ctx_t *ctx = arg;
1317 ip_neighbor_t *ipn;
1318
1319 ipn = ip_neighbor_get (ipni);
1320
1321 if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
1322 {
1323 vec_add1 (ctx->ipnsc_stale, ipni);
1324 }
1325
1326 return (WALK_CONTINUE);
1327}
1328
1329void
Neale Rannsdc617b82020-08-20 08:22:56 +00001330ip_neighbor_sweep (ip_address_family_t af)
Neale Rannsc87fbb42020-04-02 17:08:28 +00001331{
1332 ip_neighbor_sweep_ctx_t ctx = { };
1333 index_t *ipni;
1334
Neale Rannsdc617b82020-08-20 08:22:56 +00001335 ip_neighbor_walk (af, ~0, ip_neighbor_sweep_one, &ctx);
Neale Rannsc87fbb42020-04-02 17:08:28 +00001336
1337 vec_foreach (ipni, ctx.ipnsc_stale)
1338 {
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001339 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannsc87fbb42020-04-02 17:08:28 +00001340 }
1341 vec_free (ctx.ipnsc_stale);
1342}
1343
Neale Rannscbe25aa2019-09-30 10:53:31 +00001344/*
1345 * Remove any arp entries associated with the specified interface
1346 */
1347static clib_error_t *
1348ip_neighbor_interface_admin_change (vnet_main_t * vnm,
1349 u32 sw_if_index, u32 flags)
1350{
Neale Rannsdc617b82020-08-20 08:22:56 +00001351 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001352
1353 IP_NEIGHBOR_DBG ("interface-admin: %U %s",
1354 format_vnet_sw_if_index_name, vnet_get_main (),
1355 sw_if_index,
1356 (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ? "up" : "down"));
1357
1358 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1359 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001360 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_populate (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001361 }
1362 else
1363 {
1364 /* admin down, flush all neighbours */
Neale Rannsdc617b82020-08-20 08:22:56 +00001365 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001366 }
1367
1368 return (NULL);
1369}
1370
1371VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip_neighbor_interface_admin_change);
1372
1373/*
1374 * Remove any arp entries associated with the specified interface
1375 */
1376static clib_error_t *
Neale Rannsfd2417b2021-07-16 14:00:16 +00001377ip_neighbor_add_del_sw_interface (vnet_main_t *vnm, u32 sw_if_index,
1378 u32 is_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001379{
1380 IP_NEIGHBOR_DBG ("interface-change: %U %s",
1381 format_vnet_sw_if_index_name, vnet_get_main (),
1382 sw_if_index, (is_add ? "add" : "del"));
1383
1384 if (!is_add && sw_if_index != ~0)
1385 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001386 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001387
Neale Rannsdc617b82020-08-20 08:22:56 +00001388 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001389 }
1390
Neale Rannsfd2417b2021-07-16 14:00:16 +00001391 if (is_add)
1392 {
1393 ip_neighbor_alloc_ctr (&ip_neighbor_counters[AF_IP4], sw_if_index);
1394 ip_neighbor_alloc_ctr (&ip_neighbor_counters[AF_IP6], sw_if_index);
1395 }
1396
Neale Rannscbe25aa2019-09-30 10:53:31 +00001397 return (NULL);
1398}
1399
Neale Rannsfd2417b2021-07-16 14:00:16 +00001400VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_neighbor_add_del_sw_interface);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001401
1402typedef struct ip_neighbor_walk_covered_ctx_t_
1403{
Neale Rannsdc617b82020-08-20 08:22:56 +00001404 ip_address_t addr;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001405 u32 length;
1406 index_t *ipnis;
1407} ip_neighbor_walk_covered_ctx_t;
1408
1409static walk_rc_t
1410ip_neighbor_walk_covered (index_t ipni, void *arg)
1411{
1412 ip_neighbor_walk_covered_ctx_t *ctx = arg;
1413 ip_neighbor_t *ipn;
1414
1415 ipn = ip_neighbor_get (ipni);
1416
Neale Rannsdc617b82020-08-20 08:22:56 +00001417 if (AF_IP4 == ip_addr_version (&ctx->addr))
Neale Rannscbe25aa2019-09-30 10:53:31 +00001418 {
1419 if (ip4_destination_matches_route (&ip4_main,
Neale Rannsdc617b82020-08-20 08:22:56 +00001420 &ip_addr_v4 (&ipn->ipn_key->ipnk_ip),
1421 &ip_addr_v4 (&ctx->addr),
1422 ctx->length) &&
1423 ip_neighbor_is_dynamic (ipn))
1424 {
1425 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1426 }
1427 }
1428 else if (AF_IP6 == ip_addr_version (&ctx->addr))
1429 {
1430 if (ip6_destination_matches_route (&ip6_main,
1431 &ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
1432 &ip_addr_v6 (&ctx->addr),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001433 ctx->length) &&
1434 ip_neighbor_is_dynamic (ipn))
1435 {
1436 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1437 }
1438 }
1439 return (WALK_CONTINUE);
1440}
1441
1442
1443/*
1444 * callback when an interface address is added or deleted
1445 */
1446static void
1447ip_neighbor_add_del_interface_address_v4 (ip4_main_t * im,
1448 uword opaque,
1449 u32 sw_if_index,
1450 ip4_address_t * address,
1451 u32 address_length,
1452 u32 if_address_index, u32 is_del)
1453{
1454 /*
1455 * Flush the ARP cache of all entries covered by the address
1456 * that is being removed.
1457 */
luoyaozub3778cc2022-09-05 22:16:01 +08001458 IP_NEIGHBOR_DBG ("addr-%s: %U, %U/%d", (is_del ? "del" : "add"),
1459 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
1460 format_ip4_address, address, address_length);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001461
1462 if (is_del)
1463 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001464 /* *INDENT-OFF* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001465 ip_neighbor_walk_covered_ctx_t ctx = {
Neale Rannsdc617b82020-08-20 08:22:56 +00001466 .addr = {
1467 .ip.ip4 = *address,
1468 .version = AF_IP4,
1469 },
Neale Rannscbe25aa2019-09-30 10:53:31 +00001470 .length = address_length,
1471 };
Neale Rannsdc617b82020-08-20 08:22:56 +00001472 /* *INDENT-ON* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001473 index_t *ipni;
1474
Neale Rannsdc617b82020-08-20 08:22:56 +00001475 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_covered, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001476
1477 vec_foreach (ipni, ctx.ipnis)
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001478 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001479
1480 vec_free (ctx.ipnis);
1481 }
1482}
1483
1484/*
1485 * callback when an interface address is added or deleted
1486 */
1487static void
1488ip_neighbor_add_del_interface_address_v6 (ip6_main_t * im,
1489 uword opaque,
1490 u32 sw_if_index,
1491 ip6_address_t * address,
1492 u32 address_length,
1493 u32 if_address_index, u32 is_del)
1494{
1495 /*
1496 * Flush the ARP cache of all entries covered by the address
1497 * that is being removed.
1498 */
1499 IP_NEIGHBOR_DBG ("addr-change: %U, %U/%d %s",
1500 format_vnet_sw_if_index_name, vnet_get_main (),
1501 sw_if_index, format_ip6_address, address, address_length,
1502 (is_del ? "del" : "add"));
1503
1504 if (is_del)
1505 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001506 /* *INDENT-OFF* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001507 ip_neighbor_walk_covered_ctx_t ctx = {
Neale Rannsdc617b82020-08-20 08:22:56 +00001508 .addr = {
1509 .ip.ip6 = *address,
1510 .version = AF_IP6,
1511 },
Neale Rannscbe25aa2019-09-30 10:53:31 +00001512 .length = address_length,
1513 };
Neale Rannsdc617b82020-08-20 08:22:56 +00001514 /* *INDENT-ON* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001515 index_t *ipni;
1516
Neale Rannsdc617b82020-08-20 08:22:56 +00001517 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_covered, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001518
1519 vec_foreach (ipni, ctx.ipnis)
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001520 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001521
1522 vec_free (ctx.ipnis);
1523 }
1524}
1525
1526typedef struct ip_neighbor_table_bind_ctx_t_
1527{
1528 u32 new_fib_index;
1529 u32 old_fib_index;
1530} ip_neighbor_table_bind_ctx_t;
1531
1532static walk_rc_t
1533ip_neighbor_walk_table_bind (index_t ipni, void *arg)
1534{
1535 ip_neighbor_table_bind_ctx_t *ctx = arg;
1536 ip_neighbor_t *ipn;
1537
1538 ipn = ip_neighbor_get (ipni);
1539 ip_neighbor_adj_fib_remove (ipn, ctx->old_fib_index);
1540 ip_neighbor_adj_fib_add (ipn, ctx->new_fib_index);
1541
1542 return (WALK_CONTINUE);
1543}
1544
1545static void
1546ip_neighbor_table_bind_v4 (ip4_main_t * im,
1547 uword opaque,
1548 u32 sw_if_index,
1549 u32 new_fib_index, u32 old_fib_index)
1550{
1551 ip_neighbor_table_bind_ctx_t ctx = {
1552 .old_fib_index = old_fib_index,
1553 .new_fib_index = new_fib_index,
1554 };
1555
Neale Rannsdc617b82020-08-20 08:22:56 +00001556 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001557}
1558
1559static void
1560ip_neighbor_table_bind_v6 (ip6_main_t * im,
1561 uword opaque,
1562 u32 sw_if_index,
1563 u32 new_fib_index, u32 old_fib_index)
1564{
1565 ip_neighbor_table_bind_ctx_t ctx = {
1566 .old_fib_index = old_fib_index,
1567 .new_fib_index = new_fib_index,
1568 };
1569
Neale Rannsdc617b82020-08-20 08:22:56 +00001570 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001571}
1572
1573typedef enum ip_neighbor_age_state_t_
1574{
1575 IP_NEIGHBOR_AGE_ALIVE,
1576 IP_NEIGHBOR_AGE_PROBE,
1577 IP_NEIGHBOR_AGE_DEAD,
1578} ip_neighbor_age_state_t;
1579
1580#define IP_NEIGHBOR_PROCESS_SLEEP_LONG (0)
1581
1582static ip_neighbor_age_state_t
1583ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
1584{
Neale Rannsdc617b82020-08-20 08:22:56 +00001585 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001586 ip_neighbor_t *ipn;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001587 u32 ipndb_age;
1588 u32 ttl;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001589
1590 ipn = ip_neighbor_get (ipni);
Neale Rannsdc617b82020-08-20 08:22:56 +00001591 af = ip_neighbor_get_af (ipn);
1592 ipndb_age = ip_neighbor_db[af].ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001593 ttl = now - ipn->ipn_time_last_updated;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001594 *wait = ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001595
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001596 if (ttl > ipndb_age)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001597 {
1598 IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d",
1599 format_ip_neighbor, ipni, now,
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001600 ipn->ipn_time_last_updated, ipndb_age);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001601 if (ipn->ipn_n_probes > 2)
1602 {
1603 /* 3 strikes and yea-re out */
1604 IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni);
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001605 *wait = 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001606 return (IP_NEIGHBOR_AGE_DEAD);
1607 }
1608 else
1609 {
Sergio Gonzalez Monroy06f12902023-05-03 14:26:44 +02001610 ip_neighbor_probe_dst (ip_neighbor_get_sw_if_index (ipn),
1611 vlib_get_thread_index (), af,
Neale Rannsfd2417b2021-07-16 14:00:16 +00001612 &ip_addr_46 (&ipn->ipn_key->ipnk_ip));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001613
1614 ipn->ipn_n_probes++;
1615 *wait = 1;
1616 }
1617 }
1618 else
1619 {
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001620 /* here we are sure that ttl <= ipndb_age */
1621 *wait = ipndb_age - ttl + 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001622 return (IP_NEIGHBOR_AGE_ALIVE);
1623 }
1624
1625 return (IP_NEIGHBOR_AGE_PROBE);
1626}
1627
1628typedef enum ip_neighbor_process_event_t_
1629{
1630 IP_NEIGHBOR_AGE_PROCESS_WAKEUP,
1631} ip_neighbor_process_event_t;
1632
1633static uword
1634ip_neighbor_age_loop (vlib_main_t * vm,
1635 vlib_node_runtime_t * rt,
Neale Rannsdc617b82020-08-20 08:22:56 +00001636 vlib_frame_t * f, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001637{
1638 uword event_type, *event_data = NULL;
1639 f64 timeout;
1640
1641 /* Set the timeout to an effectively infinite value when the process starts */
1642 timeout = IP_NEIGHBOR_PROCESS_SLEEP_LONG;
1643
1644 while (1)
1645 {
1646 f64 now;
1647
1648 if (!timeout)
1649 vlib_process_wait_for_event (vm);
1650 else
1651 vlib_process_wait_for_event_or_clock (vm, timeout);
1652
1653 event_type = vlib_process_get_events (vm, &event_data);
1654 vec_reset_length (event_data);
1655
1656 now = vlib_time_now (vm);
1657
1658 switch (event_type)
1659 {
1660 case ~0:
1661 {
1662 /* timer expired */
1663 ip_neighbor_elt_t *elt, *head;
1664 f64 wait;
1665
Neale Rannsdc617b82020-08-20 08:22:56 +00001666 timeout = ip_neighbor_db[af].ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001667 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +00001668 ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001669
1670 /* *INDENT-OFF*/
1671 /* the list is time sorted, newest first, so start from the back
1672 * and work forwards. Stop when we get to one that is alive */
1673 restart:
1674 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
1675 ipne_anchor, head, elt,
1676 ({
1677 ip_neighbor_age_state_t res;
1678
1679 res = ip_neighbour_age_out(elt->ipne_index, now, &wait);
1680
1681 if (IP_NEIGHBOR_AGE_ALIVE == res) {
1682 /* the oldest neighbor has not yet expired, go back to sleep */
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001683 timeout = clib_min (wait, timeout);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001684 break;
1685 }
1686 else if (IP_NEIGHBOR_AGE_DEAD == res) {
1687 /* the oldest neighbor is dead, pop it, then restart the walk
1688 * again from the back */
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001689 ip_neighbor_destroy (ip_neighbor_get(elt->ipne_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001690 goto restart;
1691 }
1692
1693 timeout = clib_min (wait, timeout);
1694 }));
1695 /* *INDENT-ON* */
1696 break;
1697 }
1698 case IP_NEIGHBOR_AGE_PROCESS_WAKEUP:
1699 {
1700
Neale Rannsdc617b82020-08-20 08:22:56 +00001701 if (!ip_neighbor_db[af].ipndb_age)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001702 {
1703 /* aging has been disabled */
1704 timeout = 0;
1705 break;
1706 }
1707 ip_neighbor_elt_t *elt, *head;
1708
1709 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +00001710 ip_neighbor_list_head[af]);
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001711 /* no neighbors yet */
1712 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
1713 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001714 timeout = ip_neighbor_db[af].ipndb_age;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001715 break;
1716 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001717
1718 /* poke the oldset neighbour for aging, which returns how long we sleep for */
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001719 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
1720 ip_neighbour_age_out (elt->ipne_index, now, &timeout);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001721 break;
1722 }
1723 }
1724 }
1725 return 0;
1726}
1727
1728static uword
1729ip4_neighbor_age_process (vlib_main_t * vm,
1730 vlib_node_runtime_t * rt, vlib_frame_t * f)
1731{
Neale Rannsdc617b82020-08-20 08:22:56 +00001732 return (ip_neighbor_age_loop (vm, rt, f, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001733}
1734
1735static uword
1736ip6_neighbor_age_process (vlib_main_t * vm,
1737 vlib_node_runtime_t * rt, vlib_frame_t * f)
1738{
Neale Rannsdc617b82020-08-20 08:22:56 +00001739 return (ip_neighbor_age_loop (vm, rt, f, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001740}
1741
1742/* *INDENT-OFF* */
1743VLIB_REGISTER_NODE (ip4_neighbor_age_process_node,static) = {
1744 .function = ip4_neighbor_age_process,
1745 .type = VLIB_NODE_TYPE_PROCESS,
1746 .name = "ip4-neighbor-age-process",
1747};
1748VLIB_REGISTER_NODE (ip6_neighbor_age_process_node,static) = {
1749 .function = ip6_neighbor_age_process,
1750 .type = VLIB_NODE_TYPE_PROCESS,
1751 .name = "ip6-neighbor-age-process",
1752};
1753/* *INDENT-ON* */
1754
1755int
Neale Rannsdc617b82020-08-20 08:22:56 +00001756ip_neighbor_config (ip_address_family_t af, u32 limit, u32 age, bool recycle)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001757{
Neale Rannsdc617b82020-08-20 08:22:56 +00001758 ip_neighbor_db[af].ipndb_limit = limit;
1759 ip_neighbor_db[af].ipndb_recycle = recycle;
1760 ip_neighbor_db[af].ipndb_age = age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001761
1762 vlib_process_signal_event (vlib_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001763 (AF_IP4 == af ?
Neale Rannscbe25aa2019-09-30 10:53:31 +00001764 ip4_neighbor_age_process_node.index :
1765 ip6_neighbor_age_process_node.index),
1766 IP_NEIGHBOR_AGE_PROCESS_WAKEUP, 0);
1767
1768 return (0);
1769}
1770
Alexander Chernavine1cc8752023-06-26 15:57:57 +00001771int
1772ip_neighbor_get_config (ip_address_family_t af, u32 *limit, u32 *age,
1773 bool *recycle)
1774{
1775 *limit = ip_neighbor_db[af].ipndb_limit;
1776 *age = ip_neighbor_db[af].ipndb_age;
1777 *recycle = ip_neighbor_db[af].ipndb_recycle;
1778
1779 return (0);
1780}
1781
Neale Rannscbe25aa2019-09-30 10:53:31 +00001782static clib_error_t *
1783ip_neighbor_config_show (vlib_main_t * vm,
1784 unformat_input_t * input, vlib_cli_command_t * cmd)
1785{
Neale Rannsdc617b82020-08-20 08:22:56 +00001786 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001787
1788 /* *INDENT-OFF* */
Neale Rannsdc617b82020-08-20 08:22:56 +00001789 FOR_EACH_IP_ADDRESS_FAMILY(af) {
1790 vlib_cli_output (vm, "%U:", format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001791 vlib_cli_output (vm, " limit:%d, age:%d, recycle:%d",
Neale Rannsdc617b82020-08-20 08:22:56 +00001792 ip_neighbor_db[af].ipndb_limit,
1793 ip_neighbor_db[af].ipndb_age,
1794 ip_neighbor_db[af].ipndb_recycle);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001795 }
1796
1797 /* *INDENT-ON* */
1798 return (NULL);
1799}
1800
Ivan Shvedunovf86b9672021-02-19 23:32:18 +03001801static clib_error_t *
1802ip_neighbor_config_set (vlib_main_t *vm, unformat_input_t *input,
1803 vlib_cli_command_t *cmd)
1804{
1805 unformat_input_t _line_input, *line_input = &_line_input;
1806 clib_error_t *error = NULL;
1807 ip_address_family_t af;
1808 u32 limit, age;
1809 bool recycle;
1810
1811 if (!unformat_user (input, unformat_line_input, line_input))
1812 return 0;
1813
1814 if (!unformat (line_input, "%U", unformat_ip_address_family, &af))
1815 {
1816 error = unformat_parse_error (line_input);
1817 goto done;
1818 }
1819
1820 limit = ip_neighbor_db[af].ipndb_limit;
1821 age = ip_neighbor_db[af].ipndb_age;
1822 recycle = ip_neighbor_db[af].ipndb_recycle;
1823
1824 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1825 {
1826 if (unformat (line_input, "limit %u", &limit))
1827 ;
1828 else if (unformat (line_input, "age %u", &age))
1829 ;
1830 else if (unformat (line_input, "recycle"))
1831 recycle = true;
1832 else if (unformat (line_input, "norecycle"))
1833 recycle = false;
1834 else
1835 {
1836 error = unformat_parse_error (line_input);
1837 goto done;
1838 }
1839 }
1840
1841 ip_neighbor_config (af, limit, age, recycle);
1842
1843done:
1844 unformat_free (line_input);
1845 return error;
1846}
1847
Neale Rannsfd2417b2021-07-16 14:00:16 +00001848static void
1849ip_neighbor_stats_show_one (vlib_main_t *vm, vnet_main_t *vnm, u32 sw_if_index)
1850{
1851 vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm, sw_if_index);
1852 vlib_cli_output (vm, " arp:%U", format_ip_neighbor_counters,
1853 &ip_neighbor_counters[AF_IP4], sw_if_index);
1854 vlib_cli_output (vm, " nd: %U", format_ip_neighbor_counters,
1855 &ip_neighbor_counters[AF_IP6], sw_if_index);
1856}
1857
1858static walk_rc_t
1859ip_neighbor_stats_show_cb (vnet_main_t *vnm, vnet_sw_interface_t *si,
1860 void *ctx)
1861{
1862 ip_neighbor_stats_show_one (ctx, vnm, si->sw_if_index);
1863
1864 return (WALK_CONTINUE);
1865}
1866
1867static clib_error_t *
1868ip_neighbor_stats_show (vlib_main_t *vm, unformat_input_t *input,
1869 vlib_cli_command_t *cmd)
1870{
1871 vnet_main_t *vnm;
1872 u32 sw_if_index;
1873
1874 vnm = vnet_get_main ();
1875 sw_if_index = ~0;
1876 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1877
1878 if (~0 == sw_if_index)
1879 {
1880 vnet_sw_interface_walk (vnm, ip_neighbor_stats_show_cb, vm);
1881 }
1882 else
1883 {
1884 ip_neighbor_stats_show_one (vm, vnm, sw_if_index);
1885 }
1886 return (NULL);
1887}
1888
Neale Rannscbe25aa2019-09-30 10:53:31 +00001889/* *INDENT-OFF* */
1890VLIB_CLI_COMMAND (show_ip_neighbor_cfg_cmd_node, static) = {
1891 .path = "show ip neighbor-config",
1892 .function = ip_neighbor_config_show,
1893 .short_help = "show ip neighbor-config",
1894};
Ivan Shvedunovf86b9672021-02-19 23:32:18 +03001895VLIB_CLI_COMMAND (set_ip_neighbor_cfg_cmd_node, static) = {
1896 .path = "set ip neighbor-config",
1897 .function = ip_neighbor_config_set,
1898 .short_help = "set ip neighbor-config ip4|ip6 [limit <limit>] [age <age>] "
1899 "[recycle|norecycle]",
1900};
Neale Rannsfd2417b2021-07-16 14:00:16 +00001901VLIB_CLI_COMMAND (show_ip_neighbor_stats_cmd_node, static) = {
1902 .path = "show ip neighbor-stats",
1903 .function = ip_neighbor_stats_show,
1904 .short_help = "show ip neighbor-stats [interface]",
1905};
Neale Rannscbe25aa2019-09-30 10:53:31 +00001906/* *INDENT-ON* */
1907
1908static clib_error_t *
1909ip_neighbor_init (vlib_main_t * vm)
1910{
1911 {
1912 ip4_add_del_interface_address_callback_t cb = {
1913 .function = ip_neighbor_add_del_interface_address_v4,
1914 };
1915 vec_add1 (ip4_main.add_del_interface_address_callbacks, cb);
1916 }
1917 {
1918 ip6_add_del_interface_address_callback_t cb = {
1919 .function = ip_neighbor_add_del_interface_address_v6,
1920 };
1921 vec_add1 (ip6_main.add_del_interface_address_callbacks, cb);
1922 }
1923 {
1924 ip4_table_bind_callback_t cb = {
1925 .function = ip_neighbor_table_bind_v4,
1926 };
1927 vec_add1 (ip4_main.table_bind_callbacks, cb);
1928 }
1929 {
1930 ip6_table_bind_callback_t cb = {
1931 .function = ip_neighbor_table_bind_v6,
1932 };
1933 vec_add1 (ip6_main.table_bind_callbacks, cb);
1934 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001935 ipn_logger = vlib_log_register_class ("ip", "neighbor");
1936
Neale Rannsdc617b82020-08-20 08:22:56 +00001937 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001938
Neale Rannsdc617b82020-08-20 08:22:56 +00001939 FOR_EACH_IP_ADDRESS_FAMILY (af)
1940 ip_neighbor_list_head[af] =
Neale Rannscbe25aa2019-09-30 10:53:31 +00001941 clib_llist_make_head (ip_neighbor_elt_pool, ipne_anchor);
1942
1943 return (NULL);
1944}
1945
1946/* *INDENT-OFF* */
1947VLIB_INIT_FUNCTION (ip_neighbor_init) =
1948{
1949 .runs_after = VLIB_INITS("ip_main_init"),
1950};
1951/* *INDENT-ON* */
1952
1953/*
1954 * fd.io coding-style-patch-verification: ON
1955 *
1956 * Local Variables:
1957 * eval: (c-set-style "gnu")
1958 * End:
1959 */