blob: 191ac01e373311a31a2043f34b04b979afbb52fb [file] [log] [blame]
Neale Rannsd792d9c2017-10-21 10:53:20 -07001/*
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 <vppinfra/vec.h>
17
18#include <vnet/bier/bier_table.h>
19#include <vnet/bier/bier_entry.h>
20#include <vnet/bier/bier_update.h>
21#include <vnet/bier/bier_fmask_db.h>
22#include <vnet/bier/bier_fmask.h>
23
24#include <vnet/fib/mpls_fib.h>
25#include <vnet/mpls/mpls.h>
26#include <vnet/fib/fib_path_list.h>
27
28/**
29 * Memory pool of all the allocated tables
30 */
31bier_table_t *bier_table_pool;
32
33/**
34 * DB store of all BIER tables index by SD/set/hdr-len
35 */
36static uword *bier_tables_by_key;
37
38/**
39 * The magic number of BIER ECMP tables to create.
40 * The load-balance distribution algorithm will use a power of 2
41 * for the number of buckets, which constrains the choice.
42 */
43#define BIER_N_ECMP_TABLES 16
44
45static inline index_t
46bier_table_get_index (const bier_table_t *bt)
47{
48 return (bt - bier_table_pool);
49}
50
51int
52bier_table_is_main (const bier_table_t *bt)
53{
54 return (BIER_ECMP_TABLE_ID_MAIN == bt->bt_id.bti_ecmp);
55}
56
57/*
58 * Construct the key to use to find a BIER table
59 * in the global hash map
60 */
61static u32
62bier_table_mk_key (const bier_table_id_t *id)
63{
64 /*
65 * the set and sub-domain Ids are 8 bit values.
66 * we have space for ECMP table ID and talbe type (SPF/TE)
67 * for later
68 */
69 u32 key = ((id->bti_sub_domain << 24) |
70 (id->bti_set << 16) |
71 (id->bti_ecmp << 8) |
72 (id->bti_hdr_len << 4) |
73 (id->bti_type));
74
75 return (key);
76}
77
78static void
79bier_table_init (bier_table_t *bt,
80 const bier_table_id_t *id,
81 mpls_label_t ll)
82{
83 u32 num_entries;
84
85 bt->bt_lfei = FIB_NODE_INDEX_INVALID;
86 bt->bt_id = *id;
87 bt->bt_ll = ll;
88 num_entries = bier_hdr_len_id_to_num_bits(bt->bt_id.bti_hdr_len);
89
90 /*
91 * create the lookup table of entries.
92 */
93 if (bier_table_is_main(bt))
94 {
95 vec_validate_init_empty_aligned(bt->bt_entries,
96 num_entries,
97 INDEX_INVALID,
98 CLIB_CACHE_LINE_BYTES);
99 fib_table_find_or_create_and_lock(FIB_PROTOCOL_MPLS,
100 MPLS_FIB_DEFAULT_TABLE_ID,
101 FIB_SOURCE_BIER);
102 }
103 else
104 {
105 vec_validate_init_empty_aligned(bt->bt_fmasks,
106 num_entries,
107 INDEX_INVALID,
108 CLIB_CACHE_LINE_BYTES);
109 }
110}
111
112static void
113bier_table_rm_lfib (bier_table_t *bt)
114{
115 if (FIB_NODE_INDEX_INVALID != bt->bt_lfei)
116 {
117 fib_table_entry_delete_index(bt->bt_lfei,
118 FIB_SOURCE_BIER);
119 }
120 bt->bt_lfei = FIB_NODE_INDEX_INVALID;
121}
122
123static void
124bier_table_destroy (bier_table_t *bt)
125{
126 if (bier_table_is_main(bt))
127 {
128 index_t *bei;
129
130 fib_path_list_unlock(bt->bt_pl);
131 bt->bt_pl = FIB_NODE_INDEX_INVALID;
132 /*
133 * unresolve/remove all entries from the table
134 */
135 vec_foreach (bei, bt->bt_entries)
136 {
137 if (INDEX_INVALID != *bei)
138 {
139 bier_entry_delete(*bei);
140 }
141 }
142 vec_free (bt->bt_entries);
143 fib_table_unlock(fib_table_find(FIB_PROTOCOL_MPLS,
144 MPLS_FIB_DEFAULT_TABLE_ID),
145 FIB_PROTOCOL_MPLS,
146 FIB_SOURCE_BIER);
147 }
148 else
149 {
150 index_t *bfmi;
151
152 /*
153 * unlock any fmasks
154 */
155 vec_foreach (bfmi, bt->bt_fmasks)
156 {
157 bier_fmask_unlock(*bfmi);
158 }
159 vec_free(bt->bt_fmasks);
160 }
161
162 hash_unset(bier_tables_by_key,
163 bier_table_mk_key(&bt->bt_id));
164 pool_put(bier_table_pool, bt);
165}
166
167static void
168bier_table_lock_i (bier_table_t *bt)
169{
170 bt->bt_locks++;
171}
172
173static void
174bier_table_unlock_i (bier_table_t *bt)
175{
176 bt->bt_locks--;
177
178 if (0 == bt->bt_locks)
179 {
180 bier_table_rm_lfib(bt);
181 bier_table_destroy(bt);
182 }
183}
184
185void
186bier_table_unlock (const bier_table_id_t *bti)
187{
188 uword *p;
189 u32 key;
190
191 key = bier_table_mk_key(bti);
192
193 p = hash_get (bier_tables_by_key, key);
194
195 if (NULL != p) {
196 bier_table_unlock_i(bier_table_get(p[0]));
197 }
198}
199
200static void
201bier_table_mk_lfib (bier_table_t *bt)
202{
203 /*
204 * Add a new MPLS lfib entry
205 */
206 if (MPLS_LABEL_INVALID != bt->bt_ll) {
207 fib_prefix_t pfx = {
208 .fp_proto = FIB_PROTOCOL_MPLS,
209 .fp_len = 21,
210 .fp_label = bt->bt_ll,
211 .fp_eos = MPLS_EOS,
212 .fp_payload_proto = DPO_PROTO_BIER,
213 };
214 u32 mpls_fib_index;
215 dpo_id_t dpo = DPO_INVALID;
216
217 /*
218 * stack the entry on the forwarding chain prodcued by the
219 * path-list via the ECMP tables.
220 */
221 fib_path_list_contribute_forwarding(bt->bt_pl,
222 FIB_FORW_CHAIN_TYPE_BIER,
223 &dpo);
224
225 mpls_fib_index = fib_table_find(FIB_PROTOCOL_MPLS,
226 MPLS_FIB_DEFAULT_TABLE_ID);
227 bt->bt_lfei = fib_table_entry_special_dpo_add(mpls_fib_index,
228 &pfx,
229 FIB_SOURCE_BIER,
230 FIB_ENTRY_FLAG_EXCLUSIVE,
231 &dpo);
232 dpo_reset(&dpo);
233 }
234}
235
236static bier_table_t *
237bier_table_find (const bier_table_id_t *bti)
238{
239 uword *p;
240 u32 key;
241
242 key = bier_table_mk_key(bti);
243
244 p = hash_get(bier_tables_by_key, key);
245
246 if (NULL != p)
247 {
248 return (bier_table_get(p[0]));
249 }
250
251 return (NULL);
252}
253
254static bier_table_t *
255bier_table_mk_ecmp (index_t bti)
256{
257 fib_route_path_t *rpaths;
258 fib_node_index_t pli;
259 bier_table_t *bt;
260 int ii;
261
262 rpaths = NULL;
263 bt = bier_table_get(bti);
264
265 vec_validate(rpaths, BIER_N_ECMP_TABLES-1);
266
267 vec_foreach_index(ii, rpaths)
268 {
269 rpaths[ii].frp_bier_tbl = bt->bt_id;
270 rpaths[ii].frp_bier_tbl.bti_ecmp = ii;
271 rpaths[ii].frp_flags = FIB_ROUTE_PATH_BIER_TABLE;
272 }
273
274 /*
275 * no oppotunity to share, this the resolving ECMP tables are unique
276 * to this table.
277 * no need to be a child of the path list, we can do nothing with any
278 * notifications it would generate [not that it will].
279 */
280 pli = fib_path_list_create(FIB_PATH_LIST_FLAG_NO_URPF, rpaths);
281 fib_path_list_lock(pli);
282
283 /*
284 * constructing the path-list will have created many more BIER tables,
285 * so this main table will no doubt have re-alloc.
286 */
287 bt = bier_table_get(bti);
288 bt->bt_pl = pli;
289
290 vec_free(rpaths);
291
292 return (bt);
293}
294
295index_t
296bier_table_add_or_lock (const bier_table_id_t *btid,
297 mpls_label_t local_label)
298{
299 bier_table_t *bt;
300 index_t bti;
301
302 bt = bier_table_find(btid);
303
304 if (NULL != bt) {
305 /*
306 * modify an existing table.
307 * change the lfib entry to the new local label
308 */
309 if (bier_table_is_main(bt) &&
310 (local_label != MPLS_LABEL_INVALID))
311 {
312 bier_table_rm_lfib(bt);
313
314 bt->bt_ll = local_label;
315 bier_table_mk_lfib(bt);
316 }
317 bti = bier_table_get_index(bt);
318 }
319 else
320 {
321 /*
322 * add a new table
323 */
324 u32 key;
325
326 key = bier_table_mk_key(btid);
327
328 pool_get_aligned(bier_table_pool, bt, CLIB_CACHE_LINE_BYTES);
329 bier_table_init(bt, btid, local_label);
330
331 hash_set(bier_tables_by_key, key, bier_table_get_index(bt));
332 bti = bier_table_get_index(bt);
333
334 if (bier_table_is_main(bt))
335 {
336 bt = bier_table_mk_ecmp(bti);
337 bier_table_mk_lfib(bt);
338 }
339 }
340
341 bier_table_lock_i(bt);
342
343 return (bti);
344}
345
346index_t
347bier_table_ecmp_create_and_lock (const bier_table_id_t *btid)
348{
349 return (bier_table_add_or_lock(btid, MPLS_LABEL_INVALID));
350}
351
352void
353bier_table_ecmp_unlock (index_t bti)
354{
355 bier_table_unlock_i(bier_table_get(bti));
356}
357
358static void
359bier_table_dpo_lock (dpo_id_t *dpo)
360{
361}
362
363static void
364bier_table_dpo_unlock (dpo_id_t *dpo)
365{
366}
367
368static void
369bier_table_dpo_mem_show (void)
370{
371 fib_show_memory_usage("BIER-table",
372 pool_elts(bier_table_pool),
373 pool_len(bier_table_pool),
374 sizeof(bier_table_t));
375}
376static u8 *
377format_bier_table_dpo (u8 *s, va_list *ap)
378{
379 index_t bti = va_arg(*ap, index_t);
380 bier_table_t *bt;
381
382 bt = bier_table_get(bti);
383
384 return (format(s, "[%U]", format_bier_table_id, &bt->bt_id));
385}
386
387const static dpo_vft_t bier_table_dpo_vft = {
388 .dv_lock = bier_table_dpo_lock,
389 .dv_unlock = bier_table_dpo_unlock,
390 .dv_format = format_bier_table_dpo,
391 .dv_mem_show = bier_table_dpo_mem_show,
392};
393
394const static char *const bier_table_mpls_nodes[] =
395{
Gabriel Ganne0f8a96c2017-11-14 14:43:34 +0100396 "bier-input",
397 NULL
Neale Rannsd792d9c2017-10-21 10:53:20 -0700398};
399const static char * const * const bier_table_nodes[DPO_PROTO_NUM] =
400{
401 [DPO_PROTO_BIER] = bier_table_mpls_nodes,
402};
403
404static clib_error_t *
405bier_table_module_init (vlib_main_t *vm)
406{
407 dpo_register(DPO_BIER_TABLE, &bier_table_dpo_vft, bier_table_nodes);
408
409 return (NULL);
410}
411
412VLIB_INIT_FUNCTION (bier_table_module_init);
413
414const bier_table_id_t *
415bier_table_get_id (index_t bti)
416{
417 bier_table_t *bt;
418
419 bt = bier_table_get(bti);
420
421 return (&bt->bt_id);
422}
423
424static void
425bier_table_insert (bier_table_t *bt,
426 bier_bp_t bp,
427 index_t bei)
428{
429 bt->bt_entries[BIER_BP_TO_INDEX(bp)] = bei;
430}
431
432static void
433bier_table_remove (bier_table_t *bt,
434 bier_bp_t bp)
435{
436 bt->bt_entries[BIER_BP_TO_INDEX(bp)] = INDEX_INVALID;
437}
438
439void
440bier_table_route_add (const bier_table_id_t *btid,
441 bier_bp_t bp,
442 fib_route_path_t *brps)
443{
444 index_t bfmi, bti, bei, *bfmip, *bfmis = NULL;
445 fib_route_path_t *brp;
446 bier_table_t *bt;
447
448 bt = bier_table_find(btid);
449
450 if (NULL == bt) {
451 return;
452 }
453
454 bti = bier_table_get_index(bt);
455 bei = bier_table_lookup(bt, bp);
456
457 /*
458 * set the FIB index in the path to the BIER table index
459 */
460 vec_foreach(brp, brps)
461 {
462 bier_fmask_id_t fmid = {
463 .bfmi_nh = brp->frp_addr,
464 .bfmi_hdr_type = BIER_HDR_O_MPLS,
465 };
466 bfmi = bier_fmask_db_find_or_create_and_lock(bier_table_get_index(bt),
467 &fmid,
468 brp);
469
470 brp->frp_bier_fib_index = bti;
471 vec_add1(bfmis, bfmi);
472 }
473
474 if (INDEX_INVALID == bei)
475 {
476 bei = bier_entry_create(bti, bp);
477 bier_table_insert(bt, bp, bei);
478 }
479 bier_entry_path_add(bei, brps);
480
481 vec_foreach(bfmip, bfmis)
482 {
483 bier_fmask_unlock(*bfmip);
484 }
485 vec_free(bfmis);
486}
487
488void
489bier_table_route_remove (const bier_table_id_t *bti,
490 bier_bp_t bp,
491 fib_route_path_t *brps)
492{
493 fib_route_path_t *brp = NULL;
494 bier_table_t *bt;
495 index_t bei;
496
497 bt = bier_table_find(bti);
498
499 if (NULL == bt) {
500 return;
501 }
502
503 bei = bier_table_lookup(bt, bp);
504
505 if (INDEX_INVALID == bei)
506 {
507 /* no such entry */
508 return;
509 }
510
511 vec_foreach(brp, brps)
512 {
513 brp->frp_bier_fib_index = bier_table_get_index(bt);
514 }
515
516 if (0 == bier_entry_path_remove(bei, brps))
517 {
518 /* 0 remaining paths */
519 bier_table_remove(bt, bp);
520 bier_entry_delete(bei);
521 }
522}
523
524void
525bier_table_contribute_forwarding (index_t bti,
526 dpo_id_t *dpo)
527{
528 bier_table_t *bt;
529
530 bt = bier_table_get(bti);
531
532 if (BIER_ECMP_TABLE_ID_MAIN == bt->bt_id.bti_ecmp)
533 {
534 /*
535 * return the load-balance for the ECMP tables
536 */
537 fib_path_list_contribute_forwarding(bt->bt_pl,
538 FIB_FORW_CHAIN_TYPE_BIER,
539 dpo);
540 }
541 else
542 {
543 dpo_set(dpo, DPO_BIER_TABLE, DPO_PROTO_BIER, bti);
544 }
545}
546
547typedef struct bier_table_ecmp_walk_ctx_t_
548{
549 bier_table_ecmp_walk_fn_t fn;
550 void *ctx;
551} bier_table_ecmp_walk_ctx_t;
552
553static fib_path_list_walk_rc_t
554bier_table_ecmp_walk_path_list (fib_node_index_t pl_index,
555 fib_node_index_t path_index,
556 void *arg)
557{
558 bier_table_ecmp_walk_ctx_t *ctx = arg;
559
560 ctx->fn(fib_path_get_resolving_index(path_index), ctx->ctx);
561 /* continue */
562 return (FIB_PATH_LIST_WALK_CONTINUE);
563}
564
565void
566bier_table_ecmp_walk (index_t bti,
567 bier_table_ecmp_walk_fn_t fn,
568 void *ctx)
569{
570 bier_table_ecmp_walk_ctx_t ewc = {
571 .fn = fn,
572 .ctx = ctx,
573 };
574 bier_table_t *bt;
575
576 bt = bier_table_get(bti);
577
578 fib_path_list_walk(bt->bt_pl,
579 bier_table_ecmp_walk_path_list,
580 &ewc);
581}
582
583void
584bier_table_ecmp_set_fmask (index_t bti,
585 bier_bp_t bp,
586 index_t bfmi)
587{
588 bier_table_t *bt;
589
590 bt = bier_table_get(bti);
591
592 /*
593 * we hold a lock for fmasks in the table
594 */
595 bier_fmask_lock(bfmi);
596 bier_fmask_unlock(bt->bt_fmasks[BIER_BP_TO_INDEX(bp)]);
597
598 bt->bt_fmasks[BIER_BP_TO_INDEX(bp)] = bfmi;
599}
600
601u8 *
602format_bier_table_entry (u8 *s, va_list *ap)
603{
604 index_t bti = va_arg(*ap, index_t);
605 bier_bp_t bp = va_arg(*ap, bier_bp_t);
606 bier_table_t *bt;
607 bt = bier_table_get(bti);
608
609 if (bier_table_is_main(bt))
610 {
611 index_t bei;
612
613 bei = bier_table_lookup(bier_table_get(bti), bp);
614
615 if (INDEX_INVALID != bei)
616 {
617 s = format(s, "%U", format_bier_entry, bei,
618 BIER_SHOW_DETAIL);
619 }
620 }
621 else
622 {
623 index_t bfmi;
624
625 bfmi = bier_table_fwd_lookup(bier_table_get(bti), bp);
626
627 if (INDEX_INVALID != bfmi)
628 {
629 s = format(s, "%U", format_bier_fmask, bfmi,
630 BIER_SHOW_DETAIL);
631 }
632 }
633 return (s);
634}
635
636u8 *
637format_bier_table (u8 *s, va_list *ap)
638{
639 index_t bti = va_arg(*ap, index_t);
640 bier_show_flags_t flags = va_arg(*ap, bier_show_flags_t);
641 bier_table_t *bt;
642
643 if (pool_is_free_index(bier_table_pool, bti))
644 {
645 return (format(s, "No BIER f-mask %d", bti));
646 }
647
648 bt = bier_table_get(bti);
649
650 s = format(s, "[@%d] bier-table:[%U local-label:%U]",
651 bti,
652 format_bier_table_id, &bt->bt_id,
653 format_mpls_unicast_label, bt->bt_ll);
654
655 if (flags & BIER_SHOW_DETAIL)
656 {
657 s = format(s, " locks:%d", bt->bt_locks);
658 }
659 s = format(s, "]");
660
661 if (flags & BIER_SHOW_DETAIL)
662 {
663 if (bier_table_is_main(bt))
664 {
665 index_t *bei;
666
667 vec_foreach (bei, bt->bt_entries)
668 {
669 if (INDEX_INVALID != *bei)
670 {
671 s = format(s, "\n%U", format_bier_entry, *bei, 2);
672 }
673 }
674 }
675 else
676 {
677 u32 ii;
678
679 vec_foreach_index (ii, bt->bt_fmasks)
680 {
681 if (INDEX_INVALID != bt->bt_fmasks[ii])
682 {
683 s = format(s, "\n bp:%d\n %U", ii,
684 format_bier_fmask, bt->bt_fmasks[ii], 2);
685 }
686 }
687 }
688 }
689
690 return (s);
691}
692
693void
694bier_table_show_all (vlib_main_t * vm,
695 bier_show_flags_t flags)
696{
697 if (!pool_elts(bier_table_pool))
698 {
699 vlib_cli_output (vm, "No BIER tables");
700 }
701 else
702 {
703 int ii;
704
705 pool_foreach_index(ii, bier_table_pool,
706 ({
707 vlib_cli_output (vm, "%U", format_bier_table, ii, flags);
708 }));
709 }
710}
711
712void
713bier_tables_walk (bier_tables_walk_fn_t fn,
714 void *ctx)
715{
716 ASSERT(0);
717}
718
719
720void
721bier_table_walk (const bier_table_id_t *bti,
722 bier_table_walk_fn_t fn,
723 void *ctx)
724{
725 bier_table_t *bt;
726 bier_entry_t *be;
727 index_t *bei;
728
729 bt = bier_table_find(bti);
730
731 if (NULL == bt)
732 {
733 return;
734 }
735
736 vec_foreach (bei, bt->bt_entries)
737 {
738 if (INDEX_INVALID != *bei)
739 {
740 be = bier_entry_get(*bei);
741
742 fn(bt, be, ctx);
743 }
744 }
745}