blob: a177da97c396ef73c4ae7ca191402863bac4f089 [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;
800 int is_add = 1;
801 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;
814 else if (unformat (input, "static"))
815 {
816 flags |= IP_NEIGHBOR_FLAG_STATIC;
817 flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
818 }
819 else if (unformat (input, "no-fib-entry"))
820 flags |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;
821 else if (unformat (input, "count %d", &count))
822 ;
823 else
824 break;
825 }
826
827 if (sw_if_index == ~0 ||
Neale Rannsdc617b82020-08-20 08:22:56 +0000828 ip_address_is_zero (&ip) || mac_address_is_zero (&mac))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000829 return clib_error_return (0,
830 "specify interface, IP address and MAC: `%U'",
831 format_unformat_error, input);
832
833 while (count)
834 {
835 if (is_add)
Neale Rannsdc617b82020-08-20 08:22:56 +0000836 ip_neighbor_add (&ip, &mac, sw_if_index, flags, NULL);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000837 else
Neale Rannsdc617b82020-08-20 08:22:56 +0000838 ip_neighbor_del (&ip, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000839
Neale Rannsdc617b82020-08-20 08:22:56 +0000840 ip_address_increment (&ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000841 mac_address_increment (&mac);
842
843 --count;
844 }
845
846 return NULL;
847}
848
849/* *INDENT-OFF* */
850/*?
851 * Add or delete IPv4 ARP cache entries.
852 *
Huawei LI368dab32022-10-14 21:37:23 +0800853 * @note 'set ip neighbor' options (e.g. delete, static,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000854 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
855 * any order and combination.
856 *
857 * @cliexpar
858 * @parblock
859 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
860 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
861 * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
Huawei LI368dab32022-10-14 21:37:23 +0800862 * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3
863 * de:ad:be:ef:ba:be}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000864 *
Huawei LI368dab32022-10-14 21:37:23 +0800865 * To add or delete an IPv4 ARP cache entry
Neale Rannscbe25aa2019-09-30 10:53:31 +0000866 * table:
Huawei LI368dab32022-10-14 21:37:23 +0800867 * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
868 * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3
869 * dead.beef.babe}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000870 *
871 * Add or delete IPv4 static ARP cache entries as follows:
Huawei LI368dab32022-10-14 21:37:23 +0800872 * @cliexcmd{set ip neighbor static GigabitEthernet2/0/0 6.0.0.3
873 * dead.beef.babe}
874 * @cliexcmd{set ip neighbor static delete GigabitEthernet2/0/0 6.0.0.3
875 * dead.beef.babe}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000876 *
877 * For testing / debugging purposes, the 'set ip neighbor' command can add or
878 * delete multiple entries. Supply the 'count N' parameter:
Huawei LI368dab32022-10-14 21:37:23 +0800879 * @cliexcmd{set ip neighbor count 10 GigabitEthernet2/0/0 6.0.0.3
880 * dead.beef.babe}
Neale Rannscbe25aa2019-09-30 10:53:31 +0000881 * @endparblock
882 ?*/
883VLIB_CLI_COMMAND (ip_neighbor_command, static) = {
884 .path = "set ip neighbor",
Huawei LI368dab32022-10-14 21:37:23 +0800885 .short_help = "set ip neighbor [del] <intfc> <ip-address> <mac-address> "
886 "[static] [no-fib-entry] [count <count>]",
Neale Rannscbe25aa2019-09-30 10:53:31 +0000887 .function = ip_neighbor_cmd,
888};
889VLIB_CLI_COMMAND (ip_neighbor_command2, static) = {
890 .path = "ip neighbor",
Huawei LI368dab32022-10-14 21:37:23 +0800891 .short_help = "ip neighbor [del] <intfc> <ip-address> <mac-address> "
892 "[static] [no-fib-entry] [count <count>]",
Neale Rannscbe25aa2019-09-30 10:53:31 +0000893 .function = ip_neighbor_cmd,
894};
895/* *INDENT-ON* */
896
897static int
898ip_neighbor_sort (void *a1, void *a2)
899{
900 index_t *ipni1 = a1, *ipni2 = a2;
901 ip_neighbor_t *ipn1, *ipn2;
902 int cmp;
903
904 ipn1 = ip_neighbor_get (*ipni1);
905 ipn2 = ip_neighbor_get (*ipni2);
906
907 cmp = vnet_sw_interface_compare (vnet_get_main (),
908 ipn1->ipn_key->ipnk_sw_if_index,
909 ipn2->ipn_key->ipnk_sw_if_index);
910 if (!cmp)
Neale Rannsdc617b82020-08-20 08:22:56 +0000911 cmp = ip_address_cmp (&ipn1->ipn_key->ipnk_ip, &ipn2->ipn_key->ipnk_ip);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000912 return cmp;
913}
914
915static index_t *
Neale Rannsdc617b82020-08-20 08:22:56 +0000916ip_neighbor_entries (u32 sw_if_index, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000917{
918 index_t *ipnis = NULL;
919 ip_neighbor_t *ipn;
920
921 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +0100922 pool_foreach (ipn, ip_neighbor_pool)
923 {
Michael Yubedf48a2020-05-08 16:42:58 +0800924 if ((sw_if_index == ~0 ||
925 ipn->ipn_key->ipnk_sw_if_index == sw_if_index) &&
Neale Rannsdc617b82020-08-20 08:22:56 +0000926 (N_AF == af ||
927 ip_neighbor_get_af(ipn) == af))
Michael Yubedf48a2020-05-08 16:42:58 +0800928 vec_add1 (ipnis, ip_neighbor_get_index(ipn));
Damjan Marionb2c31b62020-12-13 21:47:40 +0100929 }
Neale Rannscbe25aa2019-09-30 10:53:31 +0000930
931 /* *INDENT-ON* */
932
933 if (ipnis)
934 vec_sort_with_function (ipnis, ip_neighbor_sort);
935 return ipnis;
936}
937
938static clib_error_t *
939ip_neighbor_show_sorted_i (vlib_main_t * vm,
940 unformat_input_t * input,
Neale Rannsdc617b82020-08-20 08:22:56 +0000941 vlib_cli_command_t * cmd, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000942{
943 ip_neighbor_elt_t *elt, *head;
944
Neale Rannsdc617b82020-08-20 08:22:56 +0000945 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000946
947
948 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
949 "Flags", "Ethernet", "Interface");
950
951 /* *INDENT-OFF*/
952 /* the list is time sorted, newest first, so start from the back
953 * and work forwards. Stop when we get to one that is alive */
954 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
955 ipne_anchor, head, elt,
956 ({
957 vlib_cli_output (vm, "%U", format_ip_neighbor, elt->ipne_index);
958 }));
959 /* *INDENT-ON*/
960
961 return (NULL);
962}
963
964static clib_error_t *
965ip_neighbor_show_i (vlib_main_t * vm,
966 unformat_input_t * input,
Neale Rannsdc617b82020-08-20 08:22:56 +0000967 vlib_cli_command_t * cmd, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +0000968{
969 index_t *ipni, *ipnis = NULL;
970 u32 sw_if_index;
971
972 /* Filter entries by interface if given. */
973 sw_if_index = ~0;
974 (void) unformat_user (input, unformat_vnet_sw_interface, vnet_get_main (),
975 &sw_if_index);
976
Neale Rannsdc617b82020-08-20 08:22:56 +0000977 ipnis = ip_neighbor_entries (sw_if_index, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000978
979 if (ipnis)
980 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
981 "Flags", "Ethernet", "Interface");
982
983 vec_foreach (ipni, ipnis)
984 {
985 vlib_cli_output (vm, "%U", format_ip_neighbor, *ipni);
986 }
987 vec_free (ipnis);
988
989 return (NULL);
990}
991
992static clib_error_t *
993ip_neighbor_show (vlib_main_t * vm,
994 unformat_input_t * input, vlib_cli_command_t * cmd)
995{
Neale Rannsdc617b82020-08-20 08:22:56 +0000996 return (ip_neighbor_show_i (vm, input, cmd, N_AF));
Neale Rannscbe25aa2019-09-30 10:53:31 +0000997}
998
999static clib_error_t *
1000ip6_neighbor_show (vlib_main_t * vm,
1001 unformat_input_t * input, vlib_cli_command_t * cmd)
1002{
Neale Rannsdc617b82020-08-20 08:22:56 +00001003 return (ip_neighbor_show_i (vm, input, cmd, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001004}
1005
1006static clib_error_t *
1007ip4_neighbor_show (vlib_main_t * vm,
1008 unformat_input_t * input, vlib_cli_command_t * cmd)
1009{
Neale Rannsdc617b82020-08-20 08:22:56 +00001010 return (ip_neighbor_show_i (vm, input, cmd, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001011}
1012
1013static clib_error_t *
1014ip6_neighbor_show_sorted (vlib_main_t * vm,
1015 unformat_input_t * input, vlib_cli_command_t * cmd)
1016{
Neale Rannsdc617b82020-08-20 08:22:56 +00001017 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001018}
1019
1020static clib_error_t *
1021ip4_neighbor_show_sorted (vlib_main_t * vm,
1022 unformat_input_t * input, vlib_cli_command_t * cmd)
1023{
Neale Rannsdc617b82020-08-20 08:22:56 +00001024 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001025}
1026
1027/*?
1028 * Display all the IP neighbor entries.
1029 *
1030 * @cliexpar
1031 * Example of how to display the IPv4 ARP table:
1032 * @cliexstart{show ip neighbor}
1033 * Time FIB IP4 Flags Ethernet Interface
1034 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
1035 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
1036 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
1037 * Proxy arps enabled for:
1038 * Fib_index 0 6.0.0.1 - 6.0.0.11
1039 * @cliexend
1040 ?*/
1041/* *INDENT-OFF* */
1042VLIB_CLI_COMMAND (show_ip_neighbors_cmd_node, static) = {
1043 .path = "show ip neighbors",
1044 .function = ip_neighbor_show,
1045 .short_help = "show ip neighbors [interface]",
1046};
1047VLIB_CLI_COMMAND (show_ip4_neighbors_cmd_node, static) = {
1048 .path = "show ip4 neighbors",
1049 .function = ip4_neighbor_show,
1050 .short_help = "show ip4 neighbors [interface]",
1051};
1052VLIB_CLI_COMMAND (show_ip6_neighbors_cmd_node, static) = {
1053 .path = "show ip6 neighbors",
1054 .function = ip6_neighbor_show,
1055 .short_help = "show ip6 neighbors [interface]",
1056};
1057VLIB_CLI_COMMAND (show_ip_neighbor_cmd_node, static) = {
1058 .path = "show ip neighbor",
1059 .function = ip_neighbor_show,
1060 .short_help = "show ip neighbor [interface]",
1061};
1062VLIB_CLI_COMMAND (show_ip4_neighbor_cmd_node, static) = {
1063 .path = "show ip4 neighbor",
1064 .function = ip4_neighbor_show,
1065 .short_help = "show ip4 neighbor [interface]",
1066};
1067VLIB_CLI_COMMAND (show_ip6_neighbor_cmd_node, static) = {
1068 .path = "show ip6 neighbor",
1069 .function = ip6_neighbor_show,
1070 .short_help = "show ip6 neighbor [interface]",
1071};
1072VLIB_CLI_COMMAND (show_ip4_neighbor_sorted_cmd_node, static) = {
1073 .path = "show ip4 neighbor-sorted",
1074 .function = ip4_neighbor_show_sorted,
1075 .short_help = "show ip4 neighbor-sorted",
1076};
1077VLIB_CLI_COMMAND (show_ip6_neighbor_sorted_cmd_node, static) = {
1078 .path = "show ip6 neighbor-sorted",
1079 .function = ip6_neighbor_show_sorted,
1080 .short_help = "show ip6 neighbor-sorted",
1081};
1082/* *INDENT-ON* */
1083
Neale Rannsdc617b82020-08-20 08:22:56 +00001084static ip_neighbor_vft_t ip_nbr_vfts[N_AF];
Neale Rannscbe25aa2019-09-30 10:53:31 +00001085
1086void
Neale Rannsdc617b82020-08-20 08:22:56 +00001087ip_neighbor_register (ip_address_family_t af, const ip_neighbor_vft_t * vft)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001088{
Neale Rannsdc617b82020-08-20 08:22:56 +00001089 ip_nbr_vfts[af] = *vft;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001090}
1091
1092void
Neale Rannsfd2417b2021-07-16 14:00:16 +00001093ip_neighbor_probe_dst (u32 sw_if_index, u32 thread_index,
1094 ip_address_family_t af, const ip46_address_t *dst)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001095{
Neale Rannse2fe0972020-11-26 08:37:27 +00001096 if (!vnet_sw_interface_is_admin_up (vnet_get_main (), sw_if_index))
Neale Rannscbe25aa2019-09-30 10:53:31 +00001097 return;
1098
Neale Rannse2fe0972020-11-26 08:37:27 +00001099 switch (af)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001100 {
Neale Rannse2fe0972020-11-26 08:37:27 +00001101 case AF_IP6:
Neale Rannsfd2417b2021-07-16 14:00:16 +00001102 ip6_neighbor_probe_dst (sw_if_index, thread_index, &dst->ip6);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001103 break;
Neale Rannse2fe0972020-11-26 08:37:27 +00001104 case AF_IP4:
Neale Rannsfd2417b2021-07-16 14:00:16 +00001105 ip4_neighbor_probe_dst (sw_if_index, thread_index, &dst->ip4);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001106 break;
1107 }
1108}
1109
1110void
1111ip_neighbor_probe (const ip_adjacency_t * adj)
1112{
Neale Rannse2fe0972020-11-26 08:37:27 +00001113 ip_neighbor_probe_dst (adj->rewrite_header.sw_if_index,
Neale Rannsfd2417b2021-07-16 14:00:16 +00001114 vlib_get_thread_index (),
Neale Rannse2fe0972020-11-26 08:37:27 +00001115 ip_address_family_from_fib_proto (adj->ia_nh_proto),
1116 &adj->sub_type.nbr.next_hop);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001117}
1118
1119void
Neale Rannsdc617b82020-08-20 08:22:56 +00001120ip_neighbor_walk (ip_address_family_t af,
Neale Rannscbe25aa2019-09-30 10:53:31 +00001121 u32 sw_if_index, ip_neighbor_walk_cb_t cb, void *ctx)
1122{
1123 ip_neighbor_key_t *key;
1124 index_t ipni;
1125
1126 if (~0 == sw_if_index)
1127 {
1128 uword **hash;
1129
Neale Rannsdc617b82020-08-20 08:22:56 +00001130 vec_foreach (hash, ip_neighbor_db[af].ipndb_hash)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001131 {
1132 /* *INDENT-OFF* */
1133 hash_foreach (key, ipni, *hash,
1134 ({
Ruslan Babayev24b417c2020-02-02 17:30:31 -08001135 if (WALK_STOP == cb (ipni, ctx))
1136 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001137 }));
1138 /* *INDENT-ON* */
1139 }
1140 }
1141 else
1142 {
1143 uword *hash;
1144
Neale Rannsdc617b82020-08-20 08:22:56 +00001145 if (vec_len (ip_neighbor_db[af].ipndb_hash) <= sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001146 return;
Neale Rannsdc617b82020-08-20 08:22:56 +00001147 hash = ip_neighbor_db[af].ipndb_hash[sw_if_index];
Neale Rannscbe25aa2019-09-30 10:53:31 +00001148
1149 /* *INDENT-OFF* */
1150 hash_foreach (key, ipni, hash,
1151 ({
Ruslan Babayev24b417c2020-02-02 17:30:31 -08001152 if (WALK_STOP == cb (ipni, ctx))
1153 break;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001154 }));
1155 /* *INDENT-ON* */
1156 }
1157}
1158
1159int
1160ip4_neighbor_proxy_add (u32 fib_index,
1161 const ip4_address_t * start,
1162 const ip4_address_t * end)
1163{
Neale Rannsdc617b82020-08-20 08:22:56 +00001164 if (ip_nbr_vfts[AF_IP4].inv_proxy4_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001165 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001166 return (ip_nbr_vfts[AF_IP4].inv_proxy4_add (fib_index, start, end));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001167 }
1168
1169 return (-1);
1170}
1171
1172int
1173ip4_neighbor_proxy_delete (u32 fib_index,
1174 const ip4_address_t * start,
1175 const ip4_address_t * end)
1176{
Neale Rannsdc617b82020-08-20 08:22:56 +00001177 if (ip_nbr_vfts[AF_IP4].inv_proxy4_del)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001178 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001179 return (ip_nbr_vfts[AF_IP4].inv_proxy4_del (fib_index, start, end));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001180 }
1181 return -1;
1182}
1183
1184int
1185ip4_neighbor_proxy_enable (u32 sw_if_index)
1186{
Neale Rannsdc617b82020-08-20 08:22:56 +00001187 if (ip_nbr_vfts[AF_IP4].inv_proxy4_enable)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001188 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001189 return (ip_nbr_vfts[AF_IP4].inv_proxy4_enable (sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001190 }
1191 return -1;
1192}
1193
1194int
1195ip4_neighbor_proxy_disable (u32 sw_if_index)
1196{
Neale Rannsdc617b82020-08-20 08:22:56 +00001197 if (ip_nbr_vfts[AF_IP4].inv_proxy4_disable)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001198 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001199 return (ip_nbr_vfts[AF_IP4].inv_proxy4_disable (sw_if_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001200 }
1201 return -1;
1202}
1203
1204int
1205ip6_neighbor_proxy_add (u32 sw_if_index, const ip6_address_t * addr)
1206{
Neale Rannsdc617b82020-08-20 08:22:56 +00001207 if (ip_nbr_vfts[AF_IP6].inv_proxy6_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001208 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001209 return (ip_nbr_vfts[AF_IP6].inv_proxy6_add (sw_if_index, addr));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001210 }
1211 return -1;
1212}
1213
1214int
1215ip6_neighbor_proxy_del (u32 sw_if_index, const ip6_address_t * addr)
1216{
Neale Rannsdc617b82020-08-20 08:22:56 +00001217 if (ip_nbr_vfts[AF_IP6].inv_proxy6_del)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001218 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001219 return (ip_nbr_vfts[AF_IP6].inv_proxy6_del (sw_if_index, addr));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001220 }
1221 return -1;
1222}
1223
Neale Rannscbe25aa2019-09-30 10:53:31 +00001224void
Neale Rannsdc617b82020-08-20 08:22:56 +00001225ip_neighbor_populate (ip_address_family_t af, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001226{
1227 index_t *ipnis = NULL, *ipni;
1228 ip_neighbor_t *ipn;
1229
1230 IP_NEIGHBOR_DBG ("populate: %U %U",
1231 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001232 sw_if_index, format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001233
1234 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001235 pool_foreach (ipn, ip_neighbor_pool)
1236 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001237 if (ip_neighbor_get_af(ipn) == af &&
Neale Rannscbe25aa2019-09-30 10:53:31 +00001238 ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1239 vec_add1 (ipnis, ipn - ip_neighbor_pool);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001240 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001241 /* *INDENT-ON* */
1242
1243 vec_foreach (ipni, ipnis)
1244 {
1245 ipn = ip_neighbor_get (*ipni);
1246
1247 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
Neale Rannsdc617b82020-08-20 08:22:56 +00001248 ip_address_family_to_fib_proto (ip_neighbor_get_af
1249 (ipn)),
1250 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001251 ip_neighbor_mk_complete_walk, ipn);
1252 }
1253 vec_free (ipnis);
1254}
1255
1256void
Neale Rannsdc617b82020-08-20 08:22:56 +00001257ip_neighbor_flush (ip_address_family_t af, u32 sw_if_index)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001258{
1259 index_t *ipnis = NULL, *ipni;
1260 ip_neighbor_t *ipn;
1261
Neale Rannsdc617b82020-08-20 08:22:56 +00001262
Neale Rannscbe25aa2019-09-30 10:53:31 +00001263 IP_NEIGHBOR_DBG ("flush: %U %U",
1264 format_vnet_sw_if_index_name, vnet_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001265 sw_if_index, format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001266
1267 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +01001268 pool_foreach (ipn, ip_neighbor_pool)
1269 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001270 if (ip_neighbor_get_af(ipn) == af &&
Neale Rannscbe25aa2019-09-30 10:53:31 +00001271 ipn->ipn_key->ipnk_sw_if_index == sw_if_index &&
1272 ip_neighbor_is_dynamic (ipn))
1273 vec_add1 (ipnis, ipn - ip_neighbor_pool);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001274 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001275 /* *INDENT-ON* */
1276
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001277 vec_foreach (ipni, ipnis) ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001278 vec_free (ipnis);
1279}
1280
Stanislav Zaikin3bad8b62022-04-25 19:11:36 +02001281walk_rc_t
Neale Rannsc87fbb42020-04-02 17:08:28 +00001282ip_neighbor_mark_one (index_t ipni, void *ctx)
1283{
1284 ip_neighbor_t *ipn;
1285
1286 ipn = ip_neighbor_get (ipni);
1287
1288 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
1289
1290 return (WALK_CONTINUE);
1291}
1292
1293void
Neale Rannsdc617b82020-08-20 08:22:56 +00001294ip_neighbor_mark (ip_address_family_t af)
Neale Rannsc87fbb42020-04-02 17:08:28 +00001295{
Neale Rannsdc617b82020-08-20 08:22:56 +00001296 ip_neighbor_walk (af, ~0, ip_neighbor_mark_one, NULL);
Neale Rannsc87fbb42020-04-02 17:08:28 +00001297}
1298
1299typedef struct ip_neighbor_sweep_ctx_t_
1300{
1301 index_t *ipnsc_stale;
1302} ip_neighbor_sweep_ctx_t;
1303
1304static walk_rc_t
1305ip_neighbor_sweep_one (index_t ipni, void *arg)
1306{
1307 ip_neighbor_sweep_ctx_t *ctx = arg;
1308 ip_neighbor_t *ipn;
1309
1310 ipn = ip_neighbor_get (ipni);
1311
1312 if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
1313 {
1314 vec_add1 (ctx->ipnsc_stale, ipni);
1315 }
1316
1317 return (WALK_CONTINUE);
1318}
1319
1320void
Neale Rannsdc617b82020-08-20 08:22:56 +00001321ip_neighbor_sweep (ip_address_family_t af)
Neale Rannsc87fbb42020-04-02 17:08:28 +00001322{
1323 ip_neighbor_sweep_ctx_t ctx = { };
1324 index_t *ipni;
1325
Neale Rannsdc617b82020-08-20 08:22:56 +00001326 ip_neighbor_walk (af, ~0, ip_neighbor_sweep_one, &ctx);
Neale Rannsc87fbb42020-04-02 17:08:28 +00001327
1328 vec_foreach (ipni, ctx.ipnsc_stale)
1329 {
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001330 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannsc87fbb42020-04-02 17:08:28 +00001331 }
1332 vec_free (ctx.ipnsc_stale);
1333}
1334
Neale Rannscbe25aa2019-09-30 10:53:31 +00001335/*
1336 * Remove any arp entries associated with the specified interface
1337 */
1338static clib_error_t *
1339ip_neighbor_interface_admin_change (vnet_main_t * vnm,
1340 u32 sw_if_index, u32 flags)
1341{
Neale Rannsdc617b82020-08-20 08:22:56 +00001342 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001343
1344 IP_NEIGHBOR_DBG ("interface-admin: %U %s",
1345 format_vnet_sw_if_index_name, vnet_get_main (),
1346 sw_if_index,
1347 (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ? "up" : "down"));
1348
1349 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1350 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001351 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_populate (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001352 }
1353 else
1354 {
1355 /* admin down, flush all neighbours */
Neale Rannsdc617b82020-08-20 08:22:56 +00001356 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001357 }
1358
1359 return (NULL);
1360}
1361
1362VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip_neighbor_interface_admin_change);
1363
1364/*
1365 * Remove any arp entries associated with the specified interface
1366 */
1367static clib_error_t *
Neale Rannsfd2417b2021-07-16 14:00:16 +00001368ip_neighbor_add_del_sw_interface (vnet_main_t *vnm, u32 sw_if_index,
1369 u32 is_add)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001370{
1371 IP_NEIGHBOR_DBG ("interface-change: %U %s",
1372 format_vnet_sw_if_index_name, vnet_get_main (),
1373 sw_if_index, (is_add ? "add" : "del"));
1374
1375 if (!is_add && sw_if_index != ~0)
1376 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001377 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001378
Neale Rannsdc617b82020-08-20 08:22:56 +00001379 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001380 }
1381
Neale Rannsfd2417b2021-07-16 14:00:16 +00001382 if (is_add)
1383 {
1384 ip_neighbor_alloc_ctr (&ip_neighbor_counters[AF_IP4], sw_if_index);
1385 ip_neighbor_alloc_ctr (&ip_neighbor_counters[AF_IP6], sw_if_index);
1386 }
1387
Neale Rannscbe25aa2019-09-30 10:53:31 +00001388 return (NULL);
1389}
1390
Neale Rannsfd2417b2021-07-16 14:00:16 +00001391VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_neighbor_add_del_sw_interface);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001392
1393typedef struct ip_neighbor_walk_covered_ctx_t_
1394{
Neale Rannsdc617b82020-08-20 08:22:56 +00001395 ip_address_t addr;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001396 u32 length;
1397 index_t *ipnis;
1398} ip_neighbor_walk_covered_ctx_t;
1399
1400static walk_rc_t
1401ip_neighbor_walk_covered (index_t ipni, void *arg)
1402{
1403 ip_neighbor_walk_covered_ctx_t *ctx = arg;
1404 ip_neighbor_t *ipn;
1405
1406 ipn = ip_neighbor_get (ipni);
1407
Neale Rannsdc617b82020-08-20 08:22:56 +00001408 if (AF_IP4 == ip_addr_version (&ctx->addr))
Neale Rannscbe25aa2019-09-30 10:53:31 +00001409 {
1410 if (ip4_destination_matches_route (&ip4_main,
Neale Rannsdc617b82020-08-20 08:22:56 +00001411 &ip_addr_v4 (&ipn->ipn_key->ipnk_ip),
1412 &ip_addr_v4 (&ctx->addr),
1413 ctx->length) &&
1414 ip_neighbor_is_dynamic (ipn))
1415 {
1416 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1417 }
1418 }
1419 else if (AF_IP6 == ip_addr_version (&ctx->addr))
1420 {
1421 if (ip6_destination_matches_route (&ip6_main,
1422 &ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
1423 &ip_addr_v6 (&ctx->addr),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001424 ctx->length) &&
1425 ip_neighbor_is_dynamic (ipn))
1426 {
1427 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1428 }
1429 }
1430 return (WALK_CONTINUE);
1431}
1432
1433
1434/*
1435 * callback when an interface address is added or deleted
1436 */
1437static void
1438ip_neighbor_add_del_interface_address_v4 (ip4_main_t * im,
1439 uword opaque,
1440 u32 sw_if_index,
1441 ip4_address_t * address,
1442 u32 address_length,
1443 u32 if_address_index, u32 is_del)
1444{
1445 /*
1446 * Flush the ARP cache of all entries covered by the address
1447 * that is being removed.
1448 */
luoyaozub3778cc2022-09-05 22:16:01 +08001449 IP_NEIGHBOR_DBG ("addr-%s: %U, %U/%d", (is_del ? "del" : "add"),
1450 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
1451 format_ip4_address, address, address_length);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001452
1453 if (is_del)
1454 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001455 /* *INDENT-OFF* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001456 ip_neighbor_walk_covered_ctx_t ctx = {
Neale Rannsdc617b82020-08-20 08:22:56 +00001457 .addr = {
1458 .ip.ip4 = *address,
1459 .version = AF_IP4,
1460 },
Neale Rannscbe25aa2019-09-30 10:53:31 +00001461 .length = address_length,
1462 };
Neale Rannsdc617b82020-08-20 08:22:56 +00001463 /* *INDENT-ON* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001464 index_t *ipni;
1465
Neale Rannsdc617b82020-08-20 08:22:56 +00001466 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_covered, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001467
1468 vec_foreach (ipni, ctx.ipnis)
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001469 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001470
1471 vec_free (ctx.ipnis);
1472 }
1473}
1474
1475/*
1476 * callback when an interface address is added or deleted
1477 */
1478static void
1479ip_neighbor_add_del_interface_address_v6 (ip6_main_t * im,
1480 uword opaque,
1481 u32 sw_if_index,
1482 ip6_address_t * address,
1483 u32 address_length,
1484 u32 if_address_index, u32 is_del)
1485{
1486 /*
1487 * Flush the ARP cache of all entries covered by the address
1488 * that is being removed.
1489 */
1490 IP_NEIGHBOR_DBG ("addr-change: %U, %U/%d %s",
1491 format_vnet_sw_if_index_name, vnet_get_main (),
1492 sw_if_index, format_ip6_address, address, address_length,
1493 (is_del ? "del" : "add"));
1494
1495 if (is_del)
1496 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001497 /* *INDENT-OFF* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001498 ip_neighbor_walk_covered_ctx_t ctx = {
Neale Rannsdc617b82020-08-20 08:22:56 +00001499 .addr = {
1500 .ip.ip6 = *address,
1501 .version = AF_IP6,
1502 },
Neale Rannscbe25aa2019-09-30 10:53:31 +00001503 .length = address_length,
1504 };
Neale Rannsdc617b82020-08-20 08:22:56 +00001505 /* *INDENT-ON* */
Neale Rannscbe25aa2019-09-30 10:53:31 +00001506 index_t *ipni;
1507
Neale Rannsdc617b82020-08-20 08:22:56 +00001508 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_covered, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001509
1510 vec_foreach (ipni, ctx.ipnis)
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001511 ip_neighbor_destroy (ip_neighbor_get (*ipni));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001512
1513 vec_free (ctx.ipnis);
1514 }
1515}
1516
1517typedef struct ip_neighbor_table_bind_ctx_t_
1518{
1519 u32 new_fib_index;
1520 u32 old_fib_index;
1521} ip_neighbor_table_bind_ctx_t;
1522
1523static walk_rc_t
1524ip_neighbor_walk_table_bind (index_t ipni, void *arg)
1525{
1526 ip_neighbor_table_bind_ctx_t *ctx = arg;
1527 ip_neighbor_t *ipn;
1528
1529 ipn = ip_neighbor_get (ipni);
1530 ip_neighbor_adj_fib_remove (ipn, ctx->old_fib_index);
1531 ip_neighbor_adj_fib_add (ipn, ctx->new_fib_index);
1532
1533 return (WALK_CONTINUE);
1534}
1535
1536static void
1537ip_neighbor_table_bind_v4 (ip4_main_t * im,
1538 uword opaque,
1539 u32 sw_if_index,
1540 u32 new_fib_index, u32 old_fib_index)
1541{
1542 ip_neighbor_table_bind_ctx_t ctx = {
1543 .old_fib_index = old_fib_index,
1544 .new_fib_index = new_fib_index,
1545 };
1546
Neale Rannsdc617b82020-08-20 08:22:56 +00001547 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001548}
1549
1550static void
1551ip_neighbor_table_bind_v6 (ip6_main_t * im,
1552 uword opaque,
1553 u32 sw_if_index,
1554 u32 new_fib_index, u32 old_fib_index)
1555{
1556 ip_neighbor_table_bind_ctx_t ctx = {
1557 .old_fib_index = old_fib_index,
1558 .new_fib_index = new_fib_index,
1559 };
1560
Neale Rannsdc617b82020-08-20 08:22:56 +00001561 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001562}
1563
1564typedef enum ip_neighbor_age_state_t_
1565{
1566 IP_NEIGHBOR_AGE_ALIVE,
1567 IP_NEIGHBOR_AGE_PROBE,
1568 IP_NEIGHBOR_AGE_DEAD,
1569} ip_neighbor_age_state_t;
1570
1571#define IP_NEIGHBOR_PROCESS_SLEEP_LONG (0)
1572
1573static ip_neighbor_age_state_t
1574ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
1575{
Neale Rannsdc617b82020-08-20 08:22:56 +00001576 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001577 ip_neighbor_t *ipn;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001578 u32 ipndb_age;
1579 u32 ttl;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001580
1581 ipn = ip_neighbor_get (ipni);
Neale Rannsdc617b82020-08-20 08:22:56 +00001582 af = ip_neighbor_get_af (ipn);
1583 ipndb_age = ip_neighbor_db[af].ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001584 ttl = now - ipn->ipn_time_last_updated;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001585 *wait = ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001586
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001587 if (ttl > ipndb_age)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001588 {
1589 IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d",
1590 format_ip_neighbor, ipni, now,
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001591 ipn->ipn_time_last_updated, ipndb_age);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001592 if (ipn->ipn_n_probes > 2)
1593 {
1594 /* 3 strikes and yea-re out */
1595 IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni);
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001596 *wait = 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001597 return (IP_NEIGHBOR_AGE_DEAD);
1598 }
1599 else
1600 {
Neale Rannsfd2417b2021-07-16 14:00:16 +00001601 ip_neighbor_probe_dst (ip_neighbor_get_sw_if_index (ipn), af,
1602 vlib_get_thread_index (),
1603 &ip_addr_46 (&ipn->ipn_key->ipnk_ip));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001604
1605 ipn->ipn_n_probes++;
1606 *wait = 1;
1607 }
1608 }
1609 else
1610 {
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001611 /* here we are sure that ttl <= ipndb_age */
1612 *wait = ipndb_age - ttl + 1;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001613 return (IP_NEIGHBOR_AGE_ALIVE);
1614 }
1615
1616 return (IP_NEIGHBOR_AGE_PROBE);
1617}
1618
1619typedef enum ip_neighbor_process_event_t_
1620{
1621 IP_NEIGHBOR_AGE_PROCESS_WAKEUP,
1622} ip_neighbor_process_event_t;
1623
1624static uword
1625ip_neighbor_age_loop (vlib_main_t * vm,
1626 vlib_node_runtime_t * rt,
Neale Rannsdc617b82020-08-20 08:22:56 +00001627 vlib_frame_t * f, ip_address_family_t af)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001628{
1629 uword event_type, *event_data = NULL;
1630 f64 timeout;
1631
1632 /* Set the timeout to an effectively infinite value when the process starts */
1633 timeout = IP_NEIGHBOR_PROCESS_SLEEP_LONG;
1634
1635 while (1)
1636 {
1637 f64 now;
1638
1639 if (!timeout)
1640 vlib_process_wait_for_event (vm);
1641 else
1642 vlib_process_wait_for_event_or_clock (vm, timeout);
1643
1644 event_type = vlib_process_get_events (vm, &event_data);
1645 vec_reset_length (event_data);
1646
1647 now = vlib_time_now (vm);
1648
1649 switch (event_type)
1650 {
1651 case ~0:
1652 {
1653 /* timer expired */
1654 ip_neighbor_elt_t *elt, *head;
1655 f64 wait;
1656
Neale Rannsdc617b82020-08-20 08:22:56 +00001657 timeout = ip_neighbor_db[af].ipndb_age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001658 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +00001659 ip_neighbor_list_head[af]);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001660
1661 /* *INDENT-OFF*/
1662 /* the list is time sorted, newest first, so start from the back
1663 * and work forwards. Stop when we get to one that is alive */
1664 restart:
1665 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
1666 ipne_anchor, head, elt,
1667 ({
1668 ip_neighbor_age_state_t res;
1669
1670 res = ip_neighbour_age_out(elt->ipne_index, now, &wait);
1671
1672 if (IP_NEIGHBOR_AGE_ALIVE == res) {
1673 /* the oldest neighbor has not yet expired, go back to sleep */
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001674 timeout = clib_min (wait, timeout);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001675 break;
1676 }
1677 else if (IP_NEIGHBOR_AGE_DEAD == res) {
1678 /* the oldest neighbor is dead, pop it, then restart the walk
1679 * again from the back */
Neale Ranns4ac36bc2020-11-20 13:05:59 +00001680 ip_neighbor_destroy (ip_neighbor_get(elt->ipne_index));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001681 goto restart;
1682 }
1683
1684 timeout = clib_min (wait, timeout);
1685 }));
1686 /* *INDENT-ON* */
1687 break;
1688 }
1689 case IP_NEIGHBOR_AGE_PROCESS_WAKEUP:
1690 {
1691
Neale Rannsdc617b82020-08-20 08:22:56 +00001692 if (!ip_neighbor_db[af].ipndb_age)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001693 {
1694 /* aging has been disabled */
1695 timeout = 0;
1696 break;
1697 }
1698 ip_neighbor_elt_t *elt, *head;
1699
1700 head = pool_elt_at_index (ip_neighbor_elt_pool,
Neale Rannsdc617b82020-08-20 08:22:56 +00001701 ip_neighbor_list_head[af]);
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001702 /* no neighbors yet */
1703 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
1704 {
Neale Rannsdc617b82020-08-20 08:22:56 +00001705 timeout = ip_neighbor_db[af].ipndb_age;
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001706 break;
1707 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001708
1709 /* poke the oldset neighbour for aging, which returns how long we sleep for */
Vladimir Isaev1284f8c2020-02-18 15:26:12 +03001710 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
1711 ip_neighbour_age_out (elt->ipne_index, now, &timeout);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001712 break;
1713 }
1714 }
1715 }
1716 return 0;
1717}
1718
1719static uword
1720ip4_neighbor_age_process (vlib_main_t * vm,
1721 vlib_node_runtime_t * rt, vlib_frame_t * f)
1722{
Neale Rannsdc617b82020-08-20 08:22:56 +00001723 return (ip_neighbor_age_loop (vm, rt, f, AF_IP4));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001724}
1725
1726static uword
1727ip6_neighbor_age_process (vlib_main_t * vm,
1728 vlib_node_runtime_t * rt, vlib_frame_t * f)
1729{
Neale Rannsdc617b82020-08-20 08:22:56 +00001730 return (ip_neighbor_age_loop (vm, rt, f, AF_IP6));
Neale Rannscbe25aa2019-09-30 10:53:31 +00001731}
1732
1733/* *INDENT-OFF* */
1734VLIB_REGISTER_NODE (ip4_neighbor_age_process_node,static) = {
1735 .function = ip4_neighbor_age_process,
1736 .type = VLIB_NODE_TYPE_PROCESS,
1737 .name = "ip4-neighbor-age-process",
1738};
1739VLIB_REGISTER_NODE (ip6_neighbor_age_process_node,static) = {
1740 .function = ip6_neighbor_age_process,
1741 .type = VLIB_NODE_TYPE_PROCESS,
1742 .name = "ip6-neighbor-age-process",
1743};
1744/* *INDENT-ON* */
1745
1746int
Neale Rannsdc617b82020-08-20 08:22:56 +00001747ip_neighbor_config (ip_address_family_t af, u32 limit, u32 age, bool recycle)
Neale Rannscbe25aa2019-09-30 10:53:31 +00001748{
Neale Rannsdc617b82020-08-20 08:22:56 +00001749 ip_neighbor_db[af].ipndb_limit = limit;
1750 ip_neighbor_db[af].ipndb_recycle = recycle;
1751 ip_neighbor_db[af].ipndb_age = age;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001752
1753 vlib_process_signal_event (vlib_get_main (),
Neale Rannsdc617b82020-08-20 08:22:56 +00001754 (AF_IP4 == af ?
Neale Rannscbe25aa2019-09-30 10:53:31 +00001755 ip4_neighbor_age_process_node.index :
1756 ip6_neighbor_age_process_node.index),
1757 IP_NEIGHBOR_AGE_PROCESS_WAKEUP, 0);
1758
1759 return (0);
1760}
1761
1762static clib_error_t *
1763ip_neighbor_config_show (vlib_main_t * vm,
1764 unformat_input_t * input, vlib_cli_command_t * cmd)
1765{
Neale Rannsdc617b82020-08-20 08:22:56 +00001766 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001767
1768 /* *INDENT-OFF* */
Neale Rannsdc617b82020-08-20 08:22:56 +00001769 FOR_EACH_IP_ADDRESS_FAMILY(af) {
1770 vlib_cli_output (vm, "%U:", format_ip_address_family, af);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001771 vlib_cli_output (vm, " limit:%d, age:%d, recycle:%d",
Neale Rannsdc617b82020-08-20 08:22:56 +00001772 ip_neighbor_db[af].ipndb_limit,
1773 ip_neighbor_db[af].ipndb_age,
1774 ip_neighbor_db[af].ipndb_recycle);
Neale Rannscbe25aa2019-09-30 10:53:31 +00001775 }
1776
1777 /* *INDENT-ON* */
1778 return (NULL);
1779}
1780
Ivan Shvedunovf86b9672021-02-19 23:32:18 +03001781static clib_error_t *
1782ip_neighbor_config_set (vlib_main_t *vm, unformat_input_t *input,
1783 vlib_cli_command_t *cmd)
1784{
1785 unformat_input_t _line_input, *line_input = &_line_input;
1786 clib_error_t *error = NULL;
1787 ip_address_family_t af;
1788 u32 limit, age;
1789 bool recycle;
1790
1791 if (!unformat_user (input, unformat_line_input, line_input))
1792 return 0;
1793
1794 if (!unformat (line_input, "%U", unformat_ip_address_family, &af))
1795 {
1796 error = unformat_parse_error (line_input);
1797 goto done;
1798 }
1799
1800 limit = ip_neighbor_db[af].ipndb_limit;
1801 age = ip_neighbor_db[af].ipndb_age;
1802 recycle = ip_neighbor_db[af].ipndb_recycle;
1803
1804 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1805 {
1806 if (unformat (line_input, "limit %u", &limit))
1807 ;
1808 else if (unformat (line_input, "age %u", &age))
1809 ;
1810 else if (unformat (line_input, "recycle"))
1811 recycle = true;
1812 else if (unformat (line_input, "norecycle"))
1813 recycle = false;
1814 else
1815 {
1816 error = unformat_parse_error (line_input);
1817 goto done;
1818 }
1819 }
1820
1821 ip_neighbor_config (af, limit, age, recycle);
1822
1823done:
1824 unformat_free (line_input);
1825 return error;
1826}
1827
Neale Rannsfd2417b2021-07-16 14:00:16 +00001828static void
1829ip_neighbor_stats_show_one (vlib_main_t *vm, vnet_main_t *vnm, u32 sw_if_index)
1830{
1831 vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm, sw_if_index);
1832 vlib_cli_output (vm, " arp:%U", format_ip_neighbor_counters,
1833 &ip_neighbor_counters[AF_IP4], sw_if_index);
1834 vlib_cli_output (vm, " nd: %U", format_ip_neighbor_counters,
1835 &ip_neighbor_counters[AF_IP6], sw_if_index);
1836}
1837
1838static walk_rc_t
1839ip_neighbor_stats_show_cb (vnet_main_t *vnm, vnet_sw_interface_t *si,
1840 void *ctx)
1841{
1842 ip_neighbor_stats_show_one (ctx, vnm, si->sw_if_index);
1843
1844 return (WALK_CONTINUE);
1845}
1846
1847static clib_error_t *
1848ip_neighbor_stats_show (vlib_main_t *vm, unformat_input_t *input,
1849 vlib_cli_command_t *cmd)
1850{
1851 vnet_main_t *vnm;
1852 u32 sw_if_index;
1853
1854 vnm = vnet_get_main ();
1855 sw_if_index = ~0;
1856 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1857
1858 if (~0 == sw_if_index)
1859 {
1860 vnet_sw_interface_walk (vnm, ip_neighbor_stats_show_cb, vm);
1861 }
1862 else
1863 {
1864 ip_neighbor_stats_show_one (vm, vnm, sw_if_index);
1865 }
1866 return (NULL);
1867}
1868
Neale Rannscbe25aa2019-09-30 10:53:31 +00001869/* *INDENT-OFF* */
1870VLIB_CLI_COMMAND (show_ip_neighbor_cfg_cmd_node, static) = {
1871 .path = "show ip neighbor-config",
1872 .function = ip_neighbor_config_show,
1873 .short_help = "show ip neighbor-config",
1874};
Ivan Shvedunovf86b9672021-02-19 23:32:18 +03001875VLIB_CLI_COMMAND (set_ip_neighbor_cfg_cmd_node, static) = {
1876 .path = "set ip neighbor-config",
1877 .function = ip_neighbor_config_set,
1878 .short_help = "set ip neighbor-config ip4|ip6 [limit <limit>] [age <age>] "
1879 "[recycle|norecycle]",
1880};
Neale Rannsfd2417b2021-07-16 14:00:16 +00001881VLIB_CLI_COMMAND (show_ip_neighbor_stats_cmd_node, static) = {
1882 .path = "show ip neighbor-stats",
1883 .function = ip_neighbor_stats_show,
1884 .short_help = "show ip neighbor-stats [interface]",
1885};
Neale Rannscbe25aa2019-09-30 10:53:31 +00001886/* *INDENT-ON* */
1887
1888static clib_error_t *
1889ip_neighbor_init (vlib_main_t * vm)
1890{
1891 {
1892 ip4_add_del_interface_address_callback_t cb = {
1893 .function = ip_neighbor_add_del_interface_address_v4,
1894 };
1895 vec_add1 (ip4_main.add_del_interface_address_callbacks, cb);
1896 }
1897 {
1898 ip6_add_del_interface_address_callback_t cb = {
1899 .function = ip_neighbor_add_del_interface_address_v6,
1900 };
1901 vec_add1 (ip6_main.add_del_interface_address_callbacks, cb);
1902 }
1903 {
1904 ip4_table_bind_callback_t cb = {
1905 .function = ip_neighbor_table_bind_v4,
1906 };
1907 vec_add1 (ip4_main.table_bind_callbacks, cb);
1908 }
1909 {
1910 ip6_table_bind_callback_t cb = {
1911 .function = ip_neighbor_table_bind_v6,
1912 };
1913 vec_add1 (ip6_main.table_bind_callbacks, cb);
1914 }
Neale Rannscbe25aa2019-09-30 10:53:31 +00001915 ipn_logger = vlib_log_register_class ("ip", "neighbor");
1916
Neale Rannsdc617b82020-08-20 08:22:56 +00001917 ip_address_family_t af;
Neale Rannscbe25aa2019-09-30 10:53:31 +00001918
Neale Rannsdc617b82020-08-20 08:22:56 +00001919 FOR_EACH_IP_ADDRESS_FAMILY (af)
1920 ip_neighbor_list_head[af] =
Neale Rannscbe25aa2019-09-30 10:53:31 +00001921 clib_llist_make_head (ip_neighbor_elt_pool, ipne_anchor);
1922
1923 return (NULL);
1924}
1925
1926/* *INDENT-OFF* */
1927VLIB_INIT_FUNCTION (ip_neighbor_init) =
1928{
1929 .runs_after = VLIB_INITS("ip_main_init"),
1930};
1931/* *INDENT-ON* */
1932
1933/*
1934 * fd.io coding-style-patch-verification: ON
1935 *
1936 * Local Variables:
1937 * eval: (c-set-style "gnu")
1938 * End:
1939 */