blob: f844cfaa420e793bfc36dcb6c83bfeadfe55d4c5 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vnet/fib/ip6_fib.h>
17#include <vnet/fib/fib_table.h>
Neale Ranns53da2212018-02-24 02:11:19 -080018#include <vnet/dpo/ip6_ll_dpo.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010019
Neale Rannsae809832018-11-23 09:00:27 -080020#include <vppinfra/bihash_24_8.h>
21#include <vppinfra/bihash_template.c>
22
Benoît Ganne23c48962024-04-05 09:45:29 +020023ip6_fib_fwding_table_instance_t ip6_fib_fwding_table;
Neale Ranns5a59b2b2020-10-19 14:47:20 +000024
25/* ip6 lookup table config parameters */
26u32 ip6_fib_table_nbuckets;
27uword ip6_fib_table_size;
28
Benoît Ganne23c48962024-04-05 09:45:29 +020029typedef struct ip6_fib_hash_key_t_
30{
31 ip6_address_t addr;
32 u8 len;
33} ip6_fib_hash_key_t;
34
Neale Ranns0bfe5d82016-08-25 15:29:12 +010035static void
Benoît Ganne23c48962024-04-05 09:45:29 +020036ip6_fib_hash_load_specials (u32 fib_index)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010037{
38 fib_prefix_t pfx = {
39 .fp_proto = FIB_PROTOCOL_IP6,
40 .fp_len = 0,
41 .fp_addr = {
42 .ip6 = {
43 { 0, 0, },
44 },
45 }
46 };
47
48 /*
49 * Add the default route.
50 */
51 fib_table_entry_special_add(fib_index,
52 &pfx,
53 FIB_SOURCE_DEFAULT_ROUTE,
Neale Rannsa0558302017-04-13 00:44:52 -070054 FIB_ENTRY_FLAG_DROP);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010055
56 /*
Neale Ranns53da2212018-02-24 02:11:19 -080057 * all link local via the link local lookup DPO
Neale Ranns0bfe5d82016-08-25 15:29:12 +010058 */
59 pfx.fp_addr.ip6.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
60 pfx.fp_addr.ip6.as_u64[1] = 0;
61 pfx.fp_len = 10;
Neale Ranns53da2212018-02-24 02:11:19 -080062 fib_table_entry_special_dpo_add(fib_index,
63 &pfx,
64 FIB_SOURCE_SPECIAL,
65 FIB_ENTRY_FLAG_NONE,
66 ip6_ll_dpo_get());
Neale Ranns0bfe5d82016-08-25 15:29:12 +010067}
68
69static u32
Neale Ranns15002542017-09-10 04:39:11 -070070create_fib_with_table_id (u32 table_id,
Neale Ranns53da2212018-02-24 02:11:19 -080071 fib_source_t src,
72 fib_table_flags_t flags,
73 u8 *desc)
Neale Ranns0bfe5d82016-08-25 15:29:12 +010074{
75 fib_table_t *fib_table;
Neale Rannsa3af3372017-03-28 03:49:52 -070076 ip6_fib_t *v6_fib;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010077
Dave Baracheb987d32018-05-03 08:26:39 -040078 pool_get(ip6_main.fibs, fib_table);
Neale Rannsa3af3372017-03-28 03:49:52 -070079 pool_get_aligned(ip6_main.v6_fibs, v6_fib, CLIB_CACHE_LINE_BYTES);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010080
Dave Barachb7b92992018-10-17 10:38:51 -040081 clib_memset(fib_table, 0, sizeof(*fib_table));
82 clib_memset(v6_fib, 0, sizeof(*v6_fib));
Neale Rannsa3af3372017-03-28 03:49:52 -070083
84 ASSERT((fib_table - ip6_main.fibs) ==
85 (v6_fib - ip6_main.v6_fibs));
Benoît Ganne23c48962024-04-05 09:45:29 +020086
Neale Ranns0bfe5d82016-08-25 15:29:12 +010087 fib_table->ft_proto = FIB_PROTOCOL_IP6;
88 fib_table->ft_index =
Neale Rannsa3af3372017-03-28 03:49:52 -070089 v6_fib->index =
90 (fib_table - ip6_main.fibs);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010091
92 hash_set(ip6_main.fib_index_by_table_id, table_id, fib_table->ft_index);
93
94 fib_table->ft_table_id =
Neale Rannsa3af3372017-03-28 03:49:52 -070095 v6_fib->table_id =
Neale Ranns0bfe5d82016-08-25 15:29:12 +010096 table_id;
Neale Ranns227038a2017-04-21 01:07:59 -070097 fib_table->ft_flow_hash_config = IP_FLOW_HASH_DEFAULT;
Neale Ranns53da2212018-02-24 02:11:19 -080098 fib_table->ft_flags = flags;
99 fib_table->ft_desc = desc;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100100
Neale Ranns15002542017-09-10 04:39:11 -0700101 fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_IP6, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100102
Benoît Ganne23c48962024-04-05 09:45:29 +0200103 v6_fib->fib_entry_by_dst_address = hash_create_mem(2, sizeof(ip6_fib_hash_key_t), sizeof(fib_node_index_t));
104
105 /*
106 * add the special entries into the new FIB
107 */
108 ip6_fib_hash_load_specials (fib_table->ft_index);
109
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100110 return (fib_table->ft_index);
111}
112
113u32
Neale Ranns15002542017-09-10 04:39:11 -0700114ip6_fib_table_find_or_create_and_lock (u32 table_id,
115 fib_source_t src)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100116{
117 uword * p;
118
119 p = hash_get (ip6_main.fib_index_by_table_id, table_id);
120 if (NULL == p)
Neale Ranns53da2212018-02-24 02:11:19 -0800121 return create_fib_with_table_id(table_id, src,
122 FIB_TABLE_FLAG_NONE,
123 NULL);
124
Neale Ranns15002542017-09-10 04:39:11 -0700125 fib_table_lock(p[0], FIB_PROTOCOL_IP6, src);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100126
127 return (p[0]);
128}
129
130u32
Neale Ranns53da2212018-02-24 02:11:19 -0800131ip6_fib_table_create_and_lock (fib_source_t src,
132 fib_table_flags_t flags,
133 u8 *desc)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100134{
Neale Ranns53da2212018-02-24 02:11:19 -0800135 return (create_fib_with_table_id(~0, src, flags, desc));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100136}
137
138void
139ip6_fib_table_destroy (u32 fib_index)
140{
Neale Ranns53da2212018-02-24 02:11:19 -0800141 /*
142 * all link local first ...
143 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100144 fib_prefix_t pfx = {
145 .fp_proto = FIB_PROTOCOL_IP6,
Neale Ranns53da2212018-02-24 02:11:19 -0800146 .fp_len = 10,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100147 .fp_addr = {
148 .ip6 = {
Neale Ranns53da2212018-02-24 02:11:19 -0800149 .as_u8 = {
150 [0] = 0xFE,
151 [1] = 0x80,
152 },
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100153 },
154 }
155 };
Neale Ranns53da2212018-02-24 02:11:19 -0800156 fib_table_entry_delete(fib_index,
157 &pfx,
158 FIB_SOURCE_SPECIAL);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100159
160 /*
Neale Ranns53da2212018-02-24 02:11:19 -0800161 * ... then the default route.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162 */
Neale Ranns53da2212018-02-24 02:11:19 -0800163 pfx.fp_addr.ip6.as_u64[0] = 0;
164 pfx.fp_len = 00;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100165 fib_table_entry_special_remove(fib_index,
166 &pfx,
167 FIB_SOURCE_DEFAULT_ROUTE);
168
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100169 fib_table_t *fib_table = fib_table_get(fib_index, FIB_PROTOCOL_IP6);
170 fib_source_t source;
Neale Ranns53da2212018-02-24 02:11:19 -0800171
Neale Ranns3bab8f92019-12-04 06:11:00 +0000172 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100173 * validate no more routes.
174 */
Benoît Gannecaaa6332023-09-13 17:21:04 +0200175 fib_table_assert_empty(fib_table);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000176
Neale Ranns3bab8f92019-12-04 06:11:00 +0000177 vec_foreach_index(source, fib_table->ft_src_route_counts)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100178 {
179 ASSERT(0 == fib_table->ft_src_route_counts[source]);
180 }
181
182 if (~0 != fib_table->ft_table_id)
183 {
184 hash_unset (ip6_main.fib_index_by_table_id, fib_table->ft_table_id);
185 }
Steven Luong97866a32022-02-08 07:59:11 -0800186 vec_free (fib_table->ft_locks);
Neale Ranns3bab8f92019-12-04 06:11:00 +0000187 vec_free(fib_table->ft_src_route_counts);
Benoît Ganne23c48962024-04-05 09:45:29 +0200188 hash_free(pool_elt_at_index(ip6_main.v6_fibs, fib_index)->fib_entry_by_dst_address);
Neale Rannsa3af3372017-03-28 03:49:52 -0700189 pool_put_index(ip6_main.v6_fibs, fib_table->ft_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100190 pool_put(ip6_main.fibs, fib_table);
191}
192
Benoît Ganne23c48962024-04-05 09:45:29 +0200193static void
194ip6_fib_table_mk_key (ip6_fib_hash_key_t *key, const ip6_address_t *addr, u8 len)
195{
196 const ip6_address_t *mask = &ip6_main.fib_masks[len];
197 key->addr.as_u64[0] = addr->as_u64[0] & mask->as_u64[0];
198 key->addr.as_u64[1] = addr->as_u64[1] & mask->as_u64[1];
199 key->len = len;
200}
201
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100202fib_node_index_t
203ip6_fib_table_lookup (u32 fib_index,
204 const ip6_address_t *addr,
205 u32 len)
206{
Benoît Ganne23c48962024-04-05 09:45:29 +0200207 uword *hash = pool_elt_at_index(ip6_main.v6_fibs, fib_index)->fib_entry_by_dst_address;
208 ip6_fib_hash_key_t key;
209 i32 mask_len;
210 uword *result;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100211
Benoît Ganne23c48962024-04-05 09:45:29 +0200212 for (mask_len = len; mask_len >= 0; mask_len--)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100213 {
Benoît Ganne23c48962024-04-05 09:45:29 +0200214 ip6_fib_table_mk_key (&key, addr, mask_len);
215 result = hash_get_mem(hash, &key);
216 if (result) {
217 return result[0];
218 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100219 }
220
Benoît Ganne23c48962024-04-05 09:45:29 +0200221 return FIB_NODE_INDEX_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100222}
223
224fib_node_index_t
225ip6_fib_table_lookup_exact_match (u32 fib_index,
226 const ip6_address_t *addr,
227 u32 len)
228{
Benoît Ganne23c48962024-04-05 09:45:29 +0200229 uword *hash = pool_elt_at_index(ip6_main.v6_fibs, fib_index)->fib_entry_by_dst_address;
230 ip6_fib_hash_key_t key;
231 ip6_fib_table_mk_key (&key, addr, len);
232 uword *result = hash_get(hash, &key);
233 return result ? result[0] : FIB_NODE_INDEX_INVALID;
234}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100235
Benoît Ganne23c48962024-04-05 09:45:29 +0200236void
237ip6_fib_table_entry_remove (u32 fib_index,
238 const ip6_address_t *addr,
239 u32 len)
240{
241 uword **hash = &pool_elt_at_index(ip6_main.v6_fibs, fib_index)->fib_entry_by_dst_address;
242 ip6_fib_hash_key_t key;
243 ip6_fib_table_mk_key (&key, addr, len);
244 hash_unset_mem_free(hash, &key);
245}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100246
Benoît Ganne23c48962024-04-05 09:45:29 +0200247void
248ip6_fib_table_entry_insert (u32 fib_index,
249 const ip6_address_t *addr,
250 u32 len,
251 fib_node_index_t fib_entry_index)
252{
253 uword **hash = &pool_elt_at_index(ip6_main.v6_fibs, fib_index)->fib_entry_by_dst_address;
254 ip6_fib_hash_key_t key;
255 ip6_fib_table_mk_key (&key, addr, len);
256 ASSERT (0 == hash_get(*hash, &key) && "entry already exists");
257 hash_set_mem_alloc(hash, &key, fib_entry_index);
258}
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100259
Benoît Ganne23c48962024-04-05 09:45:29 +0200260u32 ip6_fib_table_fwding_lookup_with_if_index (ip6_main_t * im,
261 u32 sw_if_index,
262 const ip6_address_t * dst)
263{
264 u32 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
265 return ip6_fib_table_fwding_lookup(fib_index, dst);
266}
267
268u32
269ip6_fib_table_get_index_for_sw_if_index (u32 sw_if_index)
270{
271 if (sw_if_index >= vec_len(ip6_main.fib_index_by_sw_if_index))
272 {
273 /*
274 * This is the case for interfaces that are not yet mapped to
275 * a IP table
276 */
277 return (~0);
278 }
279 return (ip6_main.fib_index_by_sw_if_index[sw_if_index]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280}
281
282static void
Benoît Ganne23c48962024-04-05 09:45:29 +0200283compute_prefix_lengths_in_search_order (ip6_fib_fwding_table_instance_t *table)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284{
Neale Ranns42845dd2020-05-26 13:12:17 +0000285 u8 *old, *prefix_lengths_in_search_order = NULL;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100286 int i;
Neale Ranns42845dd2020-05-26 13:12:17 +0000287
288 /*
289 * build the list in a scratch space then cutover so the workers
290 * can continue uninterrupted.
291 */
292 old = table->prefix_lengths_in_search_order;
293
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100294 /* Note: bitmap reversed so this is in fact a longest prefix match */
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100295 clib_bitmap_foreach (i, table->non_empty_dst_address_length_bitmap)
296 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 int dst_address_length = 128 - i;
Neale Ranns42845dd2020-05-26 13:12:17 +0000298 vec_add1(prefix_lengths_in_search_order, dst_address_length);
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100299 }
Neale Ranns42845dd2020-05-26 13:12:17 +0000300
301 table->prefix_lengths_in_search_order = prefix_lengths_in_search_order;
302
303 /*
304 * let the workers go once round the track before we free the old set
305 */
306 vlib_worker_wait_one_loop();
307 vec_free(old);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100308}
309
310void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100311ip6_fib_table_fwding_dpo_update (u32 fib_index,
312 const ip6_address_t *addr,
313 u32 len,
314 const dpo_id_t *dpo)
315{
Benoît Ganne23c48962024-04-05 09:45:29 +0200316 ip6_fib_fwding_table_instance_t *table;
Neale Rannsae809832018-11-23 09:00:27 -0800317 clib_bihash_kv_24_8_t kv;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100318 ip6_address_t *mask;
319 u64 fib;
320
Benoît Ganne23c48962024-04-05 09:45:29 +0200321 table = &ip6_fib_fwding_table;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100322 mask = &ip6_main.fib_masks[len];
323 fib = ((u64)((fib_index))<<32);
324
325 kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
326 kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
327 kv.key[2] = fib | len;
328 kv.value = dpo->dpoi_index;
329
Neale Rannsae809832018-11-23 09:00:27 -0800330 clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 1);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100331
Neale Ranns42845dd2020-05-26 13:12:17 +0000332 if (0 == table->dst_address_length_refcounts[len]++)
333 {
334 table->non_empty_dst_address_length_bitmap =
335 clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
336 128 - len, 1);
337 compute_prefix_lengths_in_search_order (table);
338 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100339}
340
341void
342ip6_fib_table_fwding_dpo_remove (u32 fib_index,
343 const ip6_address_t *addr,
344 u32 len,
345 const dpo_id_t *dpo)
346{
Benoît Ganne23c48962024-04-05 09:45:29 +0200347 ip6_fib_fwding_table_instance_t *table;
Neale Rannsae809832018-11-23 09:00:27 -0800348 clib_bihash_kv_24_8_t kv;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100349 ip6_address_t *mask;
350 u64 fib;
351
Benoît Ganne23c48962024-04-05 09:45:29 +0200352 table = &ip6_fib_fwding_table;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100353 mask = &ip6_main.fib_masks[len];
354 fib = ((u64)((fib_index))<<32);
355
356 kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
357 kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
358 kv.key[2] = fib | len;
359 kv.value = dpo->dpoi_index;
360
Neale Rannsae809832018-11-23 09:00:27 -0800361 clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100362
363 /* refcount accounting */
364 ASSERT (table->dst_address_length_refcounts[len] > 0);
365 if (--table->dst_address_length_refcounts[len] == 0)
366 {
367 table->non_empty_dst_address_length_bitmap =
Neale Ranns32e1c012016-11-22 17:07:28 +0000368 clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100369 128 - len, 0);
370 compute_prefix_lengths_in_search_order (table);
371 }
372}
373
Neale Ranns32e1c012016-11-22 17:07:28 +0000374void
375ip6_fib_table_walk (u32 fib_index,
376 fib_table_walk_fn_t fn,
377 void *arg)
378{
Benoît Ganne23c48962024-04-05 09:45:29 +0200379 const fib_prefix_t root = {
380 .fp_proto = FIB_PROTOCOL_IP6,
381 // address and length default to all 0
Neale Ranns32e1c012016-11-22 17:07:28 +0000382 };
Benoît Ganne23c48962024-04-05 09:45:29 +0200383 /* A full tree walk is the dengenerate case of a sub-tree from
384 * the very root */
385 return (ip6_fib_table_sub_tree_walk(fib_index, &root, fn, arg));
Neale Ranns89541992017-04-06 04:41:02 -0700386}
387
388void
389ip6_fib_table_sub_tree_walk (u32 fib_index,
390 const fib_prefix_t *root,
391 fib_table_walk_fn_t fn,
392 void *arg)
393{
Benoît Ganne23c48962024-04-05 09:45:29 +0200394 uword *hash = pool_elt_at_index(ip6_main.v6_fibs, fib_index)->fib_entry_by_dst_address;
395 const ip6_fib_hash_key_t *key, *sub_tree;
396 ip6_fib_hash_key_t *sub_trees = 0;
397 u32 fei;
Neale Ranns89541992017-04-06 04:41:02 -0700398
Benoît Ganne23c48962024-04-05 09:45:29 +0200399 /*
400 * There is no efficient way to walk this hash table.
401 * so we walk over all entries and check it is covered by the root.
402 */
403 hash_foreach_mem(key, fei, hash, ({
404 /* check if the prefix is covered by the root */
405 if (!ip6_destination_matches_route(&ip6_main, &key->addr, &root->fp_addr.ip6, root->fp_len))
406 continue; /* not covered by root, ignore */
407
408 /* exclude sub-trees the walk does not want to explore */
409 vec_foreach (sub_tree, sub_trees)
410 {
411 if (ip6_destination_matches_route(&ip6_main, &key->addr, &sub_tree->addr, sub_tree->len))
412 goto ignore_sub_tree;
413 }
414
415 switch (fn(fei, arg))
416 {
417 case FIB_TABLE_WALK_STOP:
418 goto done;
419 case FIB_TABLE_WALK_CONTINUE:
420 break;
421 case FIB_TABLE_WALK_SUB_TREE_STOP:
422 vec_add1(sub_trees, *key);
423 break;
424 }
425
426ignore_sub_tree:;
427 }));
428
429done:
430 vec_free(sub_trees);
Neale Ranns32e1c012016-11-22 17:07:28 +0000431}
432
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100433typedef struct ip6_fib_show_ctx_t_ {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100434 fib_node_index_t *entries;
435} ip6_fib_show_ctx_t;
436
Neale Ranns89541992017-04-06 04:41:02 -0700437static fib_table_walk_rc_t
Neale Ranns32e1c012016-11-22 17:07:28 +0000438ip6_fib_table_show_walk (fib_node_index_t fib_entry_index,
439 void *arg)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100440{
441 ip6_fib_show_ctx_t *ctx = arg;
442
Neale Ranns32e1c012016-11-22 17:07:28 +0000443 vec_add1(ctx->entries, fib_entry_index);
444
Neale Ranns89541992017-04-06 04:41:02 -0700445 return (FIB_TABLE_WALK_CONTINUE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446}
447
448static void
449ip6_fib_table_show_all (ip6_fib_t *fib,
450 vlib_main_t * vm)
451{
452 fib_node_index_t *fib_entry_index;
453 ip6_fib_show_ctx_t ctx = {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 .entries = NULL,
455 };
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100456
Neale Ranns32e1c012016-11-22 17:07:28 +0000457 ip6_fib_table_walk(fib->index, ip6_fib_table_show_walk, &ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458 vec_sort_with_function(ctx.entries, fib_entry_cmp_for_sort);
459
460 vec_foreach(fib_entry_index, ctx.entries)
461 {
462 vlib_cli_output(vm, "%U",
463 format_fib_entry,
464 *fib_entry_index,
465 FIB_ENTRY_FORMAT_BRIEF);
466 }
467
468 vec_free(ctx.entries);
469}
470
471static void
472ip6_fib_table_show_one (ip6_fib_t *fib,
473 vlib_main_t * vm,
474 ip6_address_t *address,
Neale Ranns88fc83e2017-04-05 08:11:14 -0700475 u32 mask_len,
476 int detail)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100477{
478 vlib_cli_output(vm, "%U",
479 format_fib_entry,
480 ip6_fib_table_lookup(fib->index, address, mask_len),
Neale Ranns88fc83e2017-04-05 08:11:14 -0700481 (detail ?
482 FIB_ENTRY_FORMAT_DETAIL2:
483 FIB_ENTRY_FORMAT_DETAIL));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484}
485
Neale Rannsc87aafa2017-11-29 00:59:31 -0800486u8 *
487format_ip6_fib_table_memory (u8 * s, va_list * args)
488{
Dave Barach97f5af02018-02-22 09:48:45 -0500489 uword bytes_inuse;
490
Benoît Ganne23c48962024-04-05 09:45:29 +0200491 bytes_inuse = alloc_arena_next(&ip6_fib_fwding_table.ip6_hash);
Dave Barach97f5af02018-02-22 09:48:45 -0500492
Neale Ranns05cac302019-05-28 11:09:40 +0000493 s = format(s, "%=30s %=6d %=12ld\n",
Neale Rannsc87aafa2017-11-29 00:59:31 -0800494 "IPv6 unicast",
495 pool_elts(ip6_main.fibs),
Dave Barach97f5af02018-02-22 09:48:45 -0500496 bytes_inuse);
Neale Rannsc87aafa2017-11-29 00:59:31 -0800497 return (s);
498}
499
Benoît Ganne23c48962024-04-05 09:45:29 +0200500void
501ip6_fib_table_show (vlib_main_t *vm, fib_table_t *fib_table, int summary)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100502{
Benoît Ganne23c48962024-04-05 09:45:29 +0200503 ip6_main_t * im6 = &ip6_main;
504 ip6_fib_t *fib = pool_elt_at_index(im6->v6_fibs, fib_table->ft_index);
505 fib_source_t source;
506 u8 *s = NULL;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100507
Benoît Ganne23c48962024-04-05 09:45:29 +0200508 s = format(s, "%U, fib_index:%d, flow hash:[%U] epoch:%d flags:%U locks:[",
509 format_fib_table_name, fib->index,
510 FIB_PROTOCOL_IP6,
511 fib->index,
512 format_ip_flow_hash_config,
513 fib_table->ft_flow_hash_config,
514 fib_table->ft_epoch,
515 format_fib_table_flags, fib_table->ft_flags);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100516
Benoît Ganne23c48962024-04-05 09:45:29 +0200517 vec_foreach_index(source, fib_table->ft_locks)
518 {
519 if (0 != fib_table->ft_locks[source])
520 {
521 s = format(s, "%U:%d, ",
522 format_fib_source, source,
523 fib_table->ft_locks[source]);
524 }
525 }
526 s = format (s, "]");
527 vlib_cli_output (vm, "%v", s);
528 vec_free(s);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100529
Benoît Ganne23c48962024-04-05 09:45:29 +0200530 /* Show summary? */
531 if (summary)
532 {
533 u32 count_by_prefix_length[129];
534 const ip6_fib_hash_key_t *key;
535 u32 fei;
536 int len;
Neale Rannsf50bac12019-12-06 05:53:17 +0000537
Benoît Ganne23c48962024-04-05 09:45:29 +0200538 vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
539
540 clib_memset (count_by_prefix_length, 0, sizeof(count_by_prefix_length));
541
542 hash_foreach_mem(key, fei, fib->fib_entry_by_dst_address, ({
543 ASSERT(key->len <= 128);
544 count_by_prefix_length[key->len]++;
545 }));
546
547 for (len = 128; len >= 0; len--)
548 {
549 if (count_by_prefix_length[len])
550 vlib_cli_output (vm, "%=20d%=16lld",
551 len, count_by_prefix_length[len]);
552 }
553 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100554}
555
556static clib_error_t *
557ip6_show_fib (vlib_main_t * vm,
558 unformat_input_t * input,
559 vlib_cli_command_t * cmd)
560{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100561 ip6_main_t * im6 = &ip6_main;
562 fib_table_t *fib_table;
563 ip6_fib_t * fib;
564 int verbose, matching;
565 ip6_address_t matching_address;
566 u32 mask_len = 128;
567 int table_id = -1, fib_index = ~0;
Neale Ranns88fc83e2017-04-05 08:11:14 -0700568 int detail = 0;
Neale Ranns05cac302019-05-28 11:09:40 +0000569 int hash = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100570
571 verbose = 1;
572 matching = 0;
573
574 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
575 {
576 if (unformat (input, "brief") ||
577 unformat (input, "summary") ||
578 unformat (input, "sum"))
579 verbose = 0;
Neale Ranns88fc83e2017-04-05 08:11:14 -0700580
581 else if (unformat (input, "detail") ||
582 unformat (input, "det"))
583 detail = 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100584
Neale Ranns05cac302019-05-28 11:09:40 +0000585 else if (unformat (input, "hash") ||
586 unformat (input, "mem") ||
587 unformat (input, "memory"))
588 hash = 1;
589
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100590 else if (unformat (input, "%U/%d",
591 unformat_ip6_address, &matching_address, &mask_len))
592 matching = 1;
593
594 else if (unformat (input, "%U", unformat_ip6_address, &matching_address))
595 matching = 1;
596
597 else if (unformat (input, "table %d", &table_id))
598 ;
599 else if (unformat (input, "index %d", &fib_index))
600 ;
601 else
602 break;
603 }
604
Neale Ranns05cac302019-05-28 11:09:40 +0000605 if (hash)
606 {
Neale Ranns05cac302019-05-28 11:09:40 +0000607 vlib_cli_output (vm, "IPv6 Forwarding Hash Table:\n%U\n",
608 BV (format_bihash),
Benoît Ganne23c48962024-04-05 09:45:29 +0200609 &ip6_fib_fwding_table.ip6_hash,
Neale Ranns05cac302019-05-28 11:09:40 +0000610 detail);
611 return (NULL);
612 }
613
Damjan Marionb2c31b62020-12-13 21:47:40 +0100614 pool_foreach (fib_table, im6->fibs)
615 {
Neale Rannsa3af3372017-03-28 03:49:52 -0700616 fib = pool_elt_at_index(im6->v6_fibs, fib_table->ft_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100617 if (table_id >= 0 && table_id != (int)fib->table_id)
618 continue;
619 if (fib_index != ~0 && fib_index != (int)fib->index)
620 continue;
Neale Ranns53da2212018-02-24 02:11:19 -0800621 if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
622 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100623
Benoît Ganne23c48962024-04-05 09:45:29 +0200624 ip6_fib_table_show(vm, fib_table, !verbose);
625 if (!verbose)
626 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100627
628 if (!matching)
629 {
630 ip6_fib_table_show_all(fib, vm);
631 }
632 else
633 {
Neale Ranns88fc83e2017-04-05 08:11:14 -0700634 ip6_fib_table_show_one(fib, vm, &matching_address, mask_len, detail);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100635 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100636 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637
638 return 0;
639}
640
641/*?
Billy McFall0683c9c2016-10-13 08:27:31 -0400642 * This command displays the IPv6 FIB Tables (VRF Tables) and the route
643 * entries for each table.
644 *
645 * @note This command will run for a long time when the FIB tables are
Nathan Skrzypczakda331052021-09-29 15:28:26 +0200646 * comprised of millions of entries. For those scenarios, consider displaying
Billy McFall0683c9c2016-10-13 08:27:31 -0400647 * in summary mode.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100648 *
649 * @cliexpar
Billy McFall0683c9c2016-10-13 08:27:31 -0400650 * @parblock
651 * Example of how to display all the IPv6 FIB tables:
652 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -0400653 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
654 * @::/0
655 * unicast-ip6-chain
656 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
657 * [0] [@0]: dpo-drop ip6
658 * fe80::/10
659 * unicast-ip6-chain
660 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
661 * [0] [@2]: dpo-receive
662 * ff02::1/128
663 * unicast-ip6-chain
664 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
665 * [0] [@2]: dpo-receive
666 * ff02::2/128
667 * unicast-ip6-chain
668 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
669 * [0] [@2]: dpo-receive
670 * ff02::16/128
671 * unicast-ip6-chain
672 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
673 * [0] [@2]: dpo-receive
674 * ff02::1:ff00:0/104
675 * unicast-ip6-chain
676 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
677 * [0] [@2]: dpo-receive
678 * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto
679 * @::/0
680 * unicast-ip6-chain
681 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
682 * [0] [@0]: dpo-drop ip6
683 * @::a:1:1:0:4/126
684 * unicast-ip6-chain
685 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
686 * [0] [@4]: ipv6-glean: af_packet0
687 * @::a:1:1:0:7/128
688 * unicast-ip6-chain
689 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
690 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
691 * fe80::/10
692 * unicast-ip6-chain
693 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
694 * [0] [@2]: dpo-receive
695 * fe80::fe:3eff:fe3e:9222/128
696 * unicast-ip6-chain
697 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
698 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
699 * ff02::1/128
700 * unicast-ip6-chain
701 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
702 * [0] [@2]: dpo-receive
703 * ff02::2/128
704 * unicast-ip6-chain
705 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
706 * [0] [@2]: dpo-receive
707 * ff02::16/128
708 * unicast-ip6-chain
709 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
710 * [0] [@2]: dpo-receive
711 * ff02::1:ff00:0/104
712 * unicast-ip6-chain
713 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
714 * [0] [@2]: dpo-receive
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100715 * @cliexend
Billy McFallebb9a6a2016-10-17 11:35:32 -0400716 *
Billy McFall0683c9c2016-10-13 08:27:31 -0400717 * Example of how to display a summary of all IPv6 FIB tables:
718 * @cliexstart{show ip6 fib summary}
Billy McFallebb9a6a2016-10-17 11:35:32 -0400719 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
Billy McFall0683c9c2016-10-13 08:27:31 -0400720 * Prefix length Count
721 * 128 3
722 * 104 1
Billy McFallebb9a6a2016-10-17 11:35:32 -0400723 * 10 1
724 * 0 1
725 * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto
Billy McFall0683c9c2016-10-13 08:27:31 -0400726 * Prefix length Count
727 * 128 5
728 * 126 1
729 * 104 1
Billy McFallebb9a6a2016-10-17 11:35:32 -0400730 * 10 1
731 * 0 1
Billy McFall0683c9c2016-10-13 08:27:31 -0400732 * @cliexend
733 * @endparblock
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100734 ?*/
735VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
736 .path = "show ip6 fib",
Neale Ranns88fc83e2017-04-05 08:11:14 -0700737 .short_help = "show ip6 fib [summary] [table <table-id>] [index <fib-id>] [<ip6-addr>[/<width>]] [detail]",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100738 .function = ip6_show_fib,
739};
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000740
741static clib_error_t *
742ip6_config (vlib_main_t * vm, unformat_input_t * input)
743{
744 uword heapsize = 0;
745 u32 nbuckets = 0;
Jon Loeligerd465fd02024-03-22 12:22:36 -0500746 char *default_name = 0;
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000747
748 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
749 {
750 if (unformat (input, "hash-buckets %d", &nbuckets))
751 ;
752 else if (unformat (input, "heap-size %U",
753 unformat_memory_size, &heapsize))
754 ;
Jon Loeligerd465fd02024-03-22 12:22:36 -0500755 else if (unformat (input, "default-table-name %s", &default_name))
756 ;
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000757 else
758 return clib_error_return (0, "unknown input '%U'",
759 format_unformat_error, input);
760 }
761
762 ip6_fib_table_nbuckets = nbuckets;
763 ip6_fib_table_size = heapsize;
Jon Loeligerd465fd02024-03-22 12:22:36 -0500764 fib_table_default_names[FIB_PROTOCOL_IP6] = default_name;
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000765
766 return 0;
767}
768
769VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
770
771static clib_error_t *
772ip6_fib_init (vlib_main_t * vm)
773{
774 if (ip6_fib_table_nbuckets == 0)
775 ip6_fib_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
776
777 ip6_fib_table_nbuckets = 1 << max_log2 (ip6_fib_table_nbuckets);
778
779 if (ip6_fib_table_size == 0)
780 ip6_fib_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
781
Benoît Ganne23c48962024-04-05 09:45:29 +0200782 clib_bihash_init_24_8 (&(ip6_fib_fwding_table.ip6_hash),
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000783 "ip6 FIB fwding table",
784 ip6_fib_table_nbuckets, ip6_fib_table_size);
Neale Ranns5a59b2b2020-10-19 14:47:20 +0000785
786 return (NULL);
787}
788
789VLIB_INIT_FUNCTION (ip6_fib_init) =
790{
791 .runs_before = VLIB_INITS("ip6_lookup_init"),
792};