Line data Source code
1 : /*
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>
18 : #include <vnet/dpo/ip6_ll_dpo.h>
19 :
20 : #include <vppinfra/bihash_24_8.h>
21 : #include <vppinfra/bihash_template.c>
22 :
23 : ip6_fib_table_instance_t ip6_fib_table[IP6_FIB_NUM_TABLES];
24 :
25 : /* ip6 lookup table config parameters */
26 : u32 ip6_fib_table_nbuckets;
27 : uword ip6_fib_table_size;
28 :
29 : static void
30 2824 : vnet_ip6_fib_init (u32 fib_index)
31 : {
32 2824 : fib_prefix_t pfx = {
33 : .fp_proto = FIB_PROTOCOL_IP6,
34 : .fp_len = 0,
35 : .fp_addr = {
36 : .ip6 = {
37 : { 0, 0, },
38 : },
39 : }
40 : };
41 :
42 : /*
43 : * Add the default route.
44 : */
45 2824 : fib_table_entry_special_add(fib_index,
46 : &pfx,
47 : FIB_SOURCE_DEFAULT_ROUTE,
48 : FIB_ENTRY_FLAG_DROP);
49 :
50 : /*
51 : * all link local via the link local lookup DPO
52 : */
53 2824 : pfx.fp_addr.ip6.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
54 2824 : pfx.fp_addr.ip6.as_u64[1] = 0;
55 2824 : pfx.fp_len = 10;
56 2824 : fib_table_entry_special_dpo_add(fib_index,
57 : &pfx,
58 : FIB_SOURCE_SPECIAL,
59 : FIB_ENTRY_FLAG_NONE,
60 : ip6_ll_dpo_get());
61 2824 : }
62 :
63 : static u32
64 2824 : create_fib_with_table_id (u32 table_id,
65 : fib_source_t src,
66 : fib_table_flags_t flags,
67 : u8 *desc)
68 : {
69 : fib_table_t *fib_table;
70 : ip6_fib_t *v6_fib;
71 :
72 2824 : pool_get(ip6_main.fibs, fib_table);
73 2824 : pool_get_aligned(ip6_main.v6_fibs, v6_fib, CLIB_CACHE_LINE_BYTES);
74 :
75 2824 : clib_memset(fib_table, 0, sizeof(*fib_table));
76 2824 : clib_memset(v6_fib, 0, sizeof(*v6_fib));
77 :
78 2824 : ASSERT((fib_table - ip6_main.fibs) ==
79 : (v6_fib - ip6_main.v6_fibs));
80 :
81 2824 : fib_table->ft_proto = FIB_PROTOCOL_IP6;
82 2824 : fib_table->ft_index =
83 2824 : v6_fib->index =
84 2824 : (fib_table - ip6_main.fibs);
85 :
86 2824 : hash_set(ip6_main.fib_index_by_table_id, table_id, fib_table->ft_index);
87 :
88 2824 : fib_table->ft_table_id =
89 2824 : v6_fib->table_id =
90 : table_id;
91 2824 : fib_table->ft_flow_hash_config = IP_FLOW_HASH_DEFAULT;
92 2824 : fib_table->ft_flags = flags;
93 2824 : fib_table->ft_desc = desc;
94 :
95 2824 : vnet_ip6_fib_init(fib_table->ft_index);
96 2824 : fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_IP6, src);
97 :
98 2824 : return (fib_table->ft_index);
99 : }
100 :
101 : u32
102 787 : ip6_fib_table_find_or_create_and_lock (u32 table_id,
103 : fib_source_t src)
104 : {
105 : uword * p;
106 :
107 787 : p = hash_get (ip6_main.fib_index_by_table_id, table_id);
108 787 : if (NULL == p)
109 703 : return create_fib_with_table_id(table_id, src,
110 : FIB_TABLE_FLAG_NONE,
111 : NULL);
112 :
113 84 : fib_table_lock(p[0], FIB_PROTOCOL_IP6, src);
114 :
115 84 : return (p[0]);
116 : }
117 :
118 : u32
119 2121 : ip6_fib_table_create_and_lock (fib_source_t src,
120 : fib_table_flags_t flags,
121 : u8 *desc)
122 : {
123 2121 : return (create_fib_with_table_id(~0, src, flags, desc));
124 : }
125 :
126 : void
127 2066 : ip6_fib_table_destroy (u32 fib_index)
128 : {
129 : /*
130 : * all link local first ...
131 : */
132 2066 : fib_prefix_t pfx = {
133 : .fp_proto = FIB_PROTOCOL_IP6,
134 : .fp_len = 10,
135 : .fp_addr = {
136 : .ip6 = {
137 : .as_u8 = {
138 : [0] = 0xFE,
139 : [1] = 0x80,
140 : },
141 : },
142 : }
143 : };
144 2066 : fib_table_entry_delete(fib_index,
145 : &pfx,
146 : FIB_SOURCE_SPECIAL);
147 :
148 : /*
149 : * ... then the default route.
150 : */
151 2066 : pfx.fp_addr.ip6.as_u64[0] = 0;
152 2066 : pfx.fp_len = 00;
153 2066 : fib_table_entry_special_remove(fib_index,
154 : &pfx,
155 : FIB_SOURCE_DEFAULT_ROUTE);
156 :
157 2066 : fib_table_t *fib_table = fib_table_get(fib_index, FIB_PROTOCOL_IP6);
158 : fib_source_t source;
159 :
160 : /*
161 : * validate no more routes.
162 : */
163 : #if CLIB_DEBUG > 0
164 2066 : if (0 != fib_table->ft_total_route_counts)
165 0 : fib_table_assert_empty(fib_table);
166 : #endif
167 :
168 45486 : vec_foreach_index(source, fib_table->ft_src_route_counts)
169 : {
170 43420 : ASSERT(0 == fib_table->ft_src_route_counts[source]);
171 : }
172 :
173 2066 : if (~0 != fib_table->ft_table_id)
174 : {
175 121 : hash_unset (ip6_main.fib_index_by_table_id, fib_table->ft_table_id);
176 : }
177 2066 : vec_free (fib_table->ft_locks);
178 2066 : vec_free(fib_table->ft_src_route_counts);
179 2066 : pool_put_index(ip6_main.v6_fibs, fib_table->ft_index);
180 2066 : pool_put(ip6_main.fibs, fib_table);
181 2066 : }
182 :
183 : fib_node_index_t
184 29773 : ip6_fib_table_lookup (u32 fib_index,
185 : const ip6_address_t *addr,
186 : u32 len)
187 : {
188 : ip6_fib_table_instance_t *table;
189 : clib_bihash_kv_24_8_t kv, value;
190 : int i, n_p, rv;
191 : u64 fib;
192 :
193 29773 : table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
194 29773 : n_p = vec_len (table->prefix_lengths_in_search_order);
195 :
196 29773 : kv.key[0] = addr->as_u64[0];
197 29773 : kv.key[1] = addr->as_u64[1];
198 29773 : fib = ((u64)((fib_index))<<32);
199 :
200 : /*
201 : * start search from a mask length same length or shorter.
202 : * we don't want matches longer than the mask passed
203 : */
204 29773 : i = 0;
205 67282 : while (i < n_p && table->prefix_lengths_in_search_order[i] > len)
206 : {
207 37509 : i++;
208 : }
209 :
210 44853 : for (; i < n_p; i++)
211 : {
212 44853 : int dst_address_length = table->prefix_lengths_in_search_order[i];
213 44853 : ip6_address_t * mask = &ip6_main.fib_masks[dst_address_length];
214 :
215 44853 : ASSERT(dst_address_length >= 0 && dst_address_length <= 128);
216 : //As lengths are decreasing, masks are increasingly specific.
217 44853 : kv.key[0] &= mask->as_u64[0];
218 44853 : kv.key[1] &= mask->as_u64[1];
219 44853 : kv.key[2] = fib | dst_address_length;
220 :
221 44853 : rv = clib_bihash_search_inline_2_24_8(&table->ip6_hash, &kv, &value);
222 44853 : if (rv == 0)
223 29773 : return value.value;
224 : }
225 :
226 0 : return (FIB_NODE_INDEX_INVALID);
227 : }
228 :
229 : fib_node_index_t
230 59433 : ip6_fib_table_lookup_exact_match (u32 fib_index,
231 : const ip6_address_t *addr,
232 : u32 len)
233 : {
234 : ip6_fib_table_instance_t *table;
235 : clib_bihash_kv_24_8_t kv, value;
236 : ip6_address_t *mask;
237 : u64 fib;
238 : int rv;
239 :
240 59433 : table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
241 59433 : mask = &ip6_main.fib_masks[len];
242 59433 : fib = ((u64)((fib_index))<<32);
243 :
244 59433 : kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
245 59433 : kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
246 59433 : kv.key[2] = fib | len;
247 :
248 59433 : rv = clib_bihash_search_inline_2_24_8(&table->ip6_hash, &kv, &value);
249 59433 : if (rv == 0)
250 41393 : return value.value;
251 :
252 18040 : return (FIB_NODE_INDEX_INVALID);
253 : }
254 :
255 : static void
256 7679 : compute_prefix_lengths_in_search_order (ip6_fib_table_instance_t *table)
257 : {
258 7679 : u8 *old, *prefix_lengths_in_search_order = NULL;
259 : int i;
260 :
261 : /*
262 : * build the list in a scratch space then cutover so the workers
263 : * can continue uninterrupted.
264 : */
265 7679 : old = table->prefix_lengths_in_search_order;
266 :
267 : /* Note: bitmap reversed so this is in fact a longest prefix match */
268 27836 : clib_bitmap_foreach (i, table->non_empty_dst_address_length_bitmap)
269 : {
270 20157 : int dst_address_length = 128 - i;
271 20157 : vec_add1(prefix_lengths_in_search_order, dst_address_length);
272 : }
273 :
274 7679 : table->prefix_lengths_in_search_order = prefix_lengths_in_search_order;
275 :
276 : /*
277 : * let the workers go once round the track before we free the old set
278 : */
279 7679 : vlib_worker_wait_one_loop();
280 7679 : vec_free(old);
281 7679 : }
282 :
283 : void
284 13990 : ip6_fib_table_entry_remove (u32 fib_index,
285 : const ip6_address_t *addr,
286 : u32 len)
287 : {
288 : ip6_fib_table_instance_t *table;
289 : clib_bihash_kv_24_8_t kv;
290 : ip6_address_t *mask;
291 : u64 fib;
292 :
293 13990 : table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
294 13990 : mask = &ip6_main.fib_masks[len];
295 13990 : fib = ((u64)((fib_index))<<32);
296 :
297 13990 : kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
298 13990 : kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
299 13990 : kv.key[2] = fib | len;
300 :
301 13990 : clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 0);
302 :
303 : /* refcount accounting */
304 13990 : ASSERT (table->dst_address_length_refcounts[len] > 0);
305 13990 : if (--table->dst_address_length_refcounts[len] == 0)
306 : {
307 1277 : table->non_empty_dst_address_length_bitmap =
308 1277 : clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
309 1277 : 128 - len, 0);
310 1277 : compute_prefix_lengths_in_search_order (table);
311 : }
312 13990 : }
313 :
314 : void
315 17827 : ip6_fib_table_entry_insert (u32 fib_index,
316 : const ip6_address_t *addr,
317 : u32 len,
318 : fib_node_index_t fib_entry_index)
319 : {
320 : ip6_fib_table_instance_t *table;
321 : clib_bihash_kv_24_8_t kv;
322 : ip6_address_t *mask;
323 : u64 fib;
324 :
325 17827 : table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
326 17827 : mask = &ip6_main.fib_masks[len];
327 17827 : fib = ((u64)((fib_index))<<32);
328 :
329 17827 : kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
330 17827 : kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
331 17827 : kv.key[2] = fib | len;
332 17827 : kv.value = fib_entry_index;
333 :
334 17827 : clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 1);
335 :
336 17827 : if (0 == table->dst_address_length_refcounts[len]++)
337 : {
338 2579 : table->non_empty_dst_address_length_bitmap =
339 2579 : clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
340 2579 : 128 - len, 1);
341 2579 : compute_prefix_lengths_in_search_order (table);
342 : }
343 17827 : }
344 :
345 1758 : u32 ip6_fib_table_fwding_lookup_with_if_index (ip6_main_t * im,
346 : u32 sw_if_index,
347 : const ip6_address_t * dst)
348 : {
349 1758 : u32 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
350 1758 : return ip6_fib_table_fwding_lookup(fib_index, dst);
351 : }
352 :
353 : u32
354 16239 : ip6_fib_table_get_index_for_sw_if_index (u32 sw_if_index)
355 : {
356 16239 : if (sw_if_index >= vec_len(ip6_main.fib_index_by_sw_if_index))
357 : {
358 : /*
359 : * This is the case for interfaces that are not yet mapped to
360 : * a IP table
361 : */
362 0 : return (~0);
363 : }
364 16239 : return (ip6_main.fib_index_by_sw_if_index[sw_if_index]);
365 : }
366 :
367 : void
368 17850 : ip6_fib_table_fwding_dpo_update (u32 fib_index,
369 : const ip6_address_t *addr,
370 : u32 len,
371 : const dpo_id_t *dpo)
372 : {
373 : ip6_fib_table_instance_t *table;
374 : clib_bihash_kv_24_8_t kv;
375 : ip6_address_t *mask;
376 : u64 fib;
377 :
378 17850 : table = &ip6_fib_table[IP6_FIB_TABLE_FWDING];
379 17850 : mask = &ip6_main.fib_masks[len];
380 17850 : fib = ((u64)((fib_index))<<32);
381 :
382 17850 : kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
383 17850 : kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
384 17850 : kv.key[2] = fib | len;
385 17850 : kv.value = dpo->dpoi_index;
386 :
387 17850 : clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 1);
388 :
389 17850 : if (0 == table->dst_address_length_refcounts[len]++)
390 : {
391 2564 : table->non_empty_dst_address_length_bitmap =
392 2564 : clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
393 2564 : 128 - len, 1);
394 2564 : compute_prefix_lengths_in_search_order (table);
395 : }
396 17850 : }
397 :
398 : void
399 14009 : ip6_fib_table_fwding_dpo_remove (u32 fib_index,
400 : const ip6_address_t *addr,
401 : u32 len,
402 : const dpo_id_t *dpo)
403 : {
404 : ip6_fib_table_instance_t *table;
405 : clib_bihash_kv_24_8_t kv;
406 : ip6_address_t *mask;
407 : u64 fib;
408 :
409 14009 : table = &ip6_fib_table[IP6_FIB_TABLE_FWDING];
410 14009 : mask = &ip6_main.fib_masks[len];
411 14009 : fib = ((u64)((fib_index))<<32);
412 :
413 14009 : kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
414 14009 : kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
415 14009 : kv.key[2] = fib | len;
416 14009 : kv.value = dpo->dpoi_index;
417 :
418 14009 : clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 0);
419 :
420 : /* refcount accounting */
421 14009 : ASSERT (table->dst_address_length_refcounts[len] > 0);
422 14009 : if (--table->dst_address_length_refcounts[len] == 0)
423 : {
424 1259 : table->non_empty_dst_address_length_bitmap =
425 1259 : clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
426 1259 : 128 - len, 0);
427 1259 : compute_prefix_lengths_in_search_order (table);
428 : }
429 14009 : }
430 :
431 : /**
432 : * @brief Context when walking the IPv6 table. Since all VRFs are in the
433 : * same hash table, we need to filter only those we need as we walk
434 : */
435 : typedef struct ip6_fib_walk_ctx_t_
436 : {
437 : u32 i6w_fib_index;
438 : fib_table_walk_fn_t i6w_fn;
439 : void *i6w_ctx;
440 : fib_prefix_t i6w_root;
441 : fib_prefix_t *i6w_sub_trees;
442 : } ip6_fib_walk_ctx_t;
443 :
444 : static int
445 47248 : ip6_fib_walk_cb (clib_bihash_kv_24_8_t * kvp,
446 : void *arg)
447 : {
448 47248 : ip6_fib_walk_ctx_t *ctx = arg;
449 : ip6_address_t key;
450 :
451 47248 : if ((kvp->key[2] >> 32) == ctx->i6w_fib_index)
452 : {
453 17899 : key.as_u64[0] = kvp->key[0];
454 17899 : key.as_u64[1] = kvp->key[1];
455 :
456 17899 : if (ip6_destination_matches_route(&ip6_main,
457 : &key,
458 17899 : &ctx->i6w_root.fp_addr.ip6,
459 17899 : ctx->i6w_root.fp_len))
460 : {
461 : const fib_prefix_t *sub_tree;
462 17883 : int skip = 0;
463 :
464 : /*
465 : * exclude sub-trees the walk does not want to explore
466 : */
467 17885 : vec_foreach(sub_tree, ctx->i6w_sub_trees)
468 : {
469 3 : if (ip6_destination_matches_route(&ip6_main,
470 : &key,
471 : &sub_tree->fp_addr.ip6,
472 3 : sub_tree->fp_len))
473 : {
474 1 : skip = 1;
475 1 : break;
476 : }
477 : }
478 :
479 17883 : if (!skip)
480 : {
481 17882 : switch (ctx->i6w_fn(kvp->value, ctx->i6w_ctx))
482 : {
483 17880 : case FIB_TABLE_WALK_CONTINUE:
484 17880 : break;
485 2 : case FIB_TABLE_WALK_SUB_TREE_STOP: {
486 2 : fib_prefix_t pfx = {
487 : .fp_proto = FIB_PROTOCOL_IP6,
488 2 : .fp_len = kvp->key[2] & 0xffffffff,
489 : .fp_addr.ip6 = key,
490 : };
491 2 : vec_add1(ctx->i6w_sub_trees, pfx);
492 2 : break;
493 : }
494 0 : case FIB_TABLE_WALK_STOP:
495 0 : goto done;
496 : }
497 : }
498 : }
499 : }
500 29366 : done:
501 :
502 47248 : return (1);
503 : }
504 :
505 : void
506 1402 : ip6_fib_table_walk (u32 fib_index,
507 : fib_table_walk_fn_t fn,
508 : void *arg)
509 : {
510 1402 : ip6_fib_walk_ctx_t ctx = {
511 : .i6w_fib_index = fib_index,
512 : .i6w_fn = fn,
513 : .i6w_ctx = arg,
514 : .i6w_root = {
515 : .fp_proto = FIB_PROTOCOL_IP6,
516 : },
517 : .i6w_sub_trees = NULL,
518 : };
519 :
520 1402 : clib_bihash_foreach_key_value_pair_24_8(
521 : &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
522 : ip6_fib_walk_cb,
523 : &ctx);
524 :
525 1402 : vec_free(ctx.i6w_sub_trees);
526 1402 : }
527 :
528 : void
529 6 : ip6_fib_table_sub_tree_walk (u32 fib_index,
530 : const fib_prefix_t *root,
531 : fib_table_walk_fn_t fn,
532 : void *arg)
533 : {
534 6 : ip6_fib_walk_ctx_t ctx = {
535 : .i6w_fib_index = fib_index,
536 : .i6w_fn = fn,
537 : .i6w_ctx = arg,
538 : .i6w_root = *root,
539 : };
540 :
541 6 : clib_bihash_foreach_key_value_pair_24_8(
542 : &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
543 : ip6_fib_walk_cb,
544 : &ctx);
545 6 : }
546 :
547 : typedef struct ip6_fib_show_ctx_t_ {
548 : fib_node_index_t *entries;
549 : } ip6_fib_show_ctx_t;
550 :
551 : static fib_table_walk_rc_t
552 1742 : ip6_fib_table_show_walk (fib_node_index_t fib_entry_index,
553 : void *arg)
554 : {
555 1742 : ip6_fib_show_ctx_t *ctx = arg;
556 :
557 1742 : vec_add1(ctx->entries, fib_entry_index);
558 :
559 1742 : return (FIB_TABLE_WALK_CONTINUE);
560 : }
561 :
562 : static void
563 199 : ip6_fib_table_show_all (ip6_fib_t *fib,
564 : vlib_main_t * vm)
565 : {
566 : fib_node_index_t *fib_entry_index;
567 199 : ip6_fib_show_ctx_t ctx = {
568 : .entries = NULL,
569 : };
570 :
571 199 : ip6_fib_table_walk(fib->index, ip6_fib_table_show_walk, &ctx);
572 199 : vec_sort_with_function(ctx.entries, fib_entry_cmp_for_sort);
573 :
574 1941 : vec_foreach(fib_entry_index, ctx.entries)
575 : {
576 1742 : vlib_cli_output(vm, "%U",
577 : format_fib_entry,
578 : *fib_entry_index,
579 : FIB_ENTRY_FORMAT_BRIEF);
580 : }
581 :
582 199 : vec_free(ctx.entries);
583 199 : }
584 :
585 : static void
586 135 : ip6_fib_table_show_one (ip6_fib_t *fib,
587 : vlib_main_t * vm,
588 : ip6_address_t *address,
589 : u32 mask_len,
590 : int detail)
591 : {
592 135 : vlib_cli_output(vm, "%U",
593 : format_fib_entry,
594 : ip6_fib_table_lookup(fib->index, address, mask_len),
595 : (detail ?
596 : FIB_ENTRY_FORMAT_DETAIL2:
597 : FIB_ENTRY_FORMAT_DETAIL));
598 135 : }
599 :
600 : u8 *
601 1 : format_ip6_fib_table_memory (u8 * s, va_list * args)
602 : {
603 : uword bytes_inuse;
604 :
605 1 : bytes_inuse = (alloc_arena_next(&(ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash)) +
606 1 : alloc_arena_next(&(ip6_fib_table[IP6_FIB_TABLE_FWDING].ip6_hash)));
607 :
608 1 : s = format(s, "%=30s %=6d %=12ld\n",
609 : "IPv6 unicast",
610 1 : pool_elts(ip6_main.fibs),
611 : bytes_inuse);
612 1 : return (s);
613 : }
614 :
615 : typedef struct {
616 : u32 fib_index;
617 : u64 count_by_prefix_length[129];
618 : } count_routes_in_fib_at_prefix_length_arg_t;
619 :
620 : static int
621 0 : count_routes_in_fib_at_prefix_length (clib_bihash_kv_24_8_t * kvp,
622 : void *arg)
623 : {
624 0 : count_routes_in_fib_at_prefix_length_arg_t * ap = arg;
625 : int mask_width;
626 :
627 0 : if ((kvp->key[2]>>32) != ap->fib_index)
628 0 : return (BIHASH_WALK_CONTINUE);
629 :
630 0 : mask_width = kvp->key[2] & 0xFF;
631 :
632 0 : ap->count_by_prefix_length[mask_width]++;
633 :
634 0 : return (BIHASH_WALK_CONTINUE);
635 : }
636 :
637 : static clib_error_t *
638 106 : ip6_show_fib (vlib_main_t * vm,
639 : unformat_input_t * input,
640 : vlib_cli_command_t * cmd)
641 : {
642 106 : count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
643 106 : ip6_main_t * im6 = &ip6_main;
644 : fib_table_t *fib_table;
645 : ip6_fib_t * fib;
646 : int verbose, matching;
647 : ip6_address_t matching_address;
648 106 : u32 mask_len = 128;
649 106 : int table_id = -1, fib_index = ~0;
650 106 : int detail = 0;
651 106 : int hash = 0;
652 :
653 106 : verbose = 1;
654 106 : matching = 0;
655 :
656 174 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
657 : {
658 136 : if (unformat (input, "brief") ||
659 136 : unformat (input, "summary") ||
660 68 : unformat (input, "sum"))
661 0 : verbose = 0;
662 :
663 136 : else if (unformat (input, "detail") ||
664 68 : unformat (input, "det"))
665 0 : detail = 1;
666 :
667 136 : else if (unformat (input, "hash") ||
668 136 : unformat (input, "mem") ||
669 68 : unformat (input, "memory"))
670 0 : hash = 1;
671 :
672 68 : else if (unformat (input, "%U/%d",
673 : unformat_ip6_address, &matching_address, &mask_len))
674 0 : matching = 1;
675 :
676 68 : else if (unformat (input, "%U", unformat_ip6_address, &matching_address))
677 68 : matching = 1;
678 :
679 0 : else if (unformat (input, "table %d", &table_id))
680 : ;
681 0 : else if (unformat (input, "index %d", &fib_index))
682 : ;
683 : else
684 0 : break;
685 : }
686 :
687 106 : if (hash)
688 : {
689 0 : vlib_cli_output (vm, "IPv6 Non-Forwarding Hash Table:\n%U\n",
690 : BV (format_bihash),
691 : &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
692 : detail);
693 0 : vlib_cli_output (vm, "IPv6 Forwarding Hash Table:\n%U\n",
694 : BV (format_bihash),
695 : &ip6_fib_table[IP6_FIB_TABLE_FWDING].ip6_hash,
696 : detail);
697 0 : return (NULL);
698 : }
699 :
700 787 : pool_foreach (fib_table, im6->fibs)
701 : {
702 : fib_source_t source;
703 681 : u8 *s = NULL;
704 :
705 681 : fib = pool_elt_at_index(im6->v6_fibs, fib_table->ft_index);
706 681 : if (table_id >= 0 && table_id != (int)fib->table_id)
707 347 : continue;
708 681 : if (fib_index != ~0 && fib_index != (int)fib->index)
709 0 : continue;
710 681 : if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
711 347 : continue;
712 :
713 668 : s = format(s, "%U, fib_index:%d, flow hash:[%U] epoch:%d flags:%U locks:[",
714 : format_fib_table_name, fib->index,
715 : FIB_PROTOCOL_IP6,
716 : fib->index,
717 : format_ip_flow_hash_config,
718 : fib_table->ft_flow_hash_config,
719 : fib_table->ft_epoch,
720 334 : format_fib_table_flags, fib_table->ft_flags);
721 :
722 6415 : vec_foreach_index(source, fib_table->ft_locks)
723 : {
724 6081 : if (0 != fib_table->ft_locks[source])
725 : {
726 682 : s = format(s, "%U:%d, ",
727 : format_fib_source, source,
728 682 : fib_table->ft_locks[source]);
729 : }
730 : }
731 334 : s = format (s, "]");
732 334 : vlib_cli_output (vm, "%v", s);
733 334 : vec_free(s);
734 :
735 : /* Show summary? */
736 334 : if (! verbose)
737 : {
738 0 : clib_bihash_24_8_t * h = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
739 : int len;
740 :
741 0 : vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
742 :
743 0 : clib_memset (ca, 0, sizeof(*ca));
744 0 : ca->fib_index = fib->index;
745 :
746 0 : clib_bihash_foreach_key_value_pair_24_8
747 : (h, count_routes_in_fib_at_prefix_length, ca);
748 :
749 0 : for (len = 128; len >= 0; len--)
750 : {
751 0 : if (ca->count_by_prefix_length[len])
752 0 : vlib_cli_output (vm, "%=20d%=16lld",
753 : len, ca->count_by_prefix_length[len]);
754 : }
755 0 : continue;
756 : }
757 :
758 334 : if (!matching)
759 : {
760 199 : ip6_fib_table_show_all(fib, vm);
761 : }
762 : else
763 : {
764 135 : ip6_fib_table_show_one(fib, vm, &matching_address, mask_len, detail);
765 : }
766 : }
767 :
768 106 : return 0;
769 : }
770 :
771 : /*?
772 : * This command displays the IPv6 FIB Tables (VRF Tables) and the route
773 : * entries for each table.
774 : *
775 : * @note This command will run for a long time when the FIB tables are
776 : * comprised of millions of entries. For those scenarios, consider displaying
777 : * in summary mode.
778 : *
779 : * @cliexpar
780 : * @parblock
781 : * Example of how to display all the IPv6 FIB tables:
782 : * @cliexstart{show ip6 fib}
783 : * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
784 : * @::/0
785 : * unicast-ip6-chain
786 : * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
787 : * [0] [@0]: dpo-drop ip6
788 : * fe80::/10
789 : * unicast-ip6-chain
790 : * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
791 : * [0] [@2]: dpo-receive
792 : * ff02::1/128
793 : * unicast-ip6-chain
794 : * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
795 : * [0] [@2]: dpo-receive
796 : * ff02::2/128
797 : * unicast-ip6-chain
798 : * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
799 : * [0] [@2]: dpo-receive
800 : * ff02::16/128
801 : * unicast-ip6-chain
802 : * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
803 : * [0] [@2]: dpo-receive
804 : * ff02::1:ff00:0/104
805 : * unicast-ip6-chain
806 : * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
807 : * [0] [@2]: dpo-receive
808 : * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto
809 : * @::/0
810 : * unicast-ip6-chain
811 : * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
812 : * [0] [@0]: dpo-drop ip6
813 : * @::a:1:1:0:4/126
814 : * unicast-ip6-chain
815 : * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
816 : * [0] [@4]: ipv6-glean: af_packet0
817 : * @::a:1:1:0:7/128
818 : * unicast-ip6-chain
819 : * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
820 : * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
821 : * fe80::/10
822 : * unicast-ip6-chain
823 : * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
824 : * [0] [@2]: dpo-receive
825 : * fe80::fe:3eff:fe3e:9222/128
826 : * unicast-ip6-chain
827 : * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
828 : * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
829 : * ff02::1/128
830 : * unicast-ip6-chain
831 : * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
832 : * [0] [@2]: dpo-receive
833 : * ff02::2/128
834 : * unicast-ip6-chain
835 : * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
836 : * [0] [@2]: dpo-receive
837 : * ff02::16/128
838 : * unicast-ip6-chain
839 : * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
840 : * [0] [@2]: dpo-receive
841 : * ff02::1:ff00:0/104
842 : * unicast-ip6-chain
843 : * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
844 : * [0] [@2]: dpo-receive
845 : * @cliexend
846 : *
847 : * Example of how to display a summary of all IPv6 FIB tables:
848 : * @cliexstart{show ip6 fib summary}
849 : * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
850 : * Prefix length Count
851 : * 128 3
852 : * 104 1
853 : * 10 1
854 : * 0 1
855 : * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto
856 : * Prefix length Count
857 : * 128 5
858 : * 126 1
859 : * 104 1
860 : * 10 1
861 : * 0 1
862 : * @cliexend
863 : * @endparblock
864 : ?*/
865 : /* *INDENT-OFF* */
866 285289 : VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
867 : .path = "show ip6 fib",
868 : .short_help = "show ip6 fib [summary] [table <table-id>] [index <fib-id>] [<ip6-addr>[/<width>]] [detail]",
869 : .function = ip6_show_fib,
870 : };
871 : /* *INDENT-ON* */
872 :
873 : static clib_error_t *
874 575 : ip6_config (vlib_main_t * vm, unformat_input_t * input)
875 : {
876 575 : uword heapsize = 0;
877 575 : u32 nbuckets = 0;
878 :
879 575 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
880 : {
881 0 : if (unformat (input, "hash-buckets %d", &nbuckets))
882 : ;
883 0 : else if (unformat (input, "heap-size %U",
884 : unformat_memory_size, &heapsize))
885 : ;
886 : else
887 0 : return clib_error_return (0, "unknown input '%U'",
888 : format_unformat_error, input);
889 : }
890 :
891 575 : ip6_fib_table_nbuckets = nbuckets;
892 575 : ip6_fib_table_size = heapsize;
893 :
894 575 : return 0;
895 : }
896 :
897 7514 : VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
898 :
899 : static clib_error_t *
900 575 : ip6_fib_init (vlib_main_t * vm)
901 : {
902 575 : if (ip6_fib_table_nbuckets == 0)
903 575 : ip6_fib_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
904 :
905 575 : ip6_fib_table_nbuckets = 1 << max_log2 (ip6_fib_table_nbuckets);
906 :
907 575 : if (ip6_fib_table_size == 0)
908 575 : ip6_fib_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
909 :
910 575 : clib_bihash_init_24_8 (&(ip6_fib_table[IP6_FIB_TABLE_FWDING].ip6_hash),
911 : "ip6 FIB fwding table",
912 : ip6_fib_table_nbuckets, ip6_fib_table_size);
913 575 : clib_bihash_init_24_8 (&ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
914 : "ip6 FIB non-fwding table",
915 : ip6_fib_table_nbuckets, ip6_fib_table_size);
916 :
917 575 : return (NULL);
918 : }
919 :
920 14399 : VLIB_INIT_FUNCTION (ip6_fib_init) =
921 : {
922 : .runs_before = VLIB_INITS("ip6_lookup_init"),
923 : };
|