fib: fib api updates
[vpp.git] / src / vnet / mfib / mfib_table.c
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 <vlib/vlib.h>
17 #include <vnet/dpo/drop_dpo.h>
18
19 #include <vnet/mfib/mfib_table.h>
20 #include <vnet/mfib/ip4_mfib.h>
21 #include <vnet/mfib/ip6_mfib.h>
22 #include <vnet/mfib/mfib_entry.h>
23 #include <vnet/mfib/mfib_entry_src.h>
24 #include <vnet/mfib/mfib_entry_cover.h>
25 #include <vnet/mfib/mfib_signal.h>
26
27 mfib_table_t *
28 mfib_table_get (fib_node_index_t index,
29                 fib_protocol_t proto)
30 {
31     switch (proto)
32     {
33     case FIB_PROTOCOL_IP4:
34         return (pool_elt_at_index(ip4_main.mfibs, index));
35     case FIB_PROTOCOL_IP6:
36         return (pool_elt_at_index(ip6_main.mfibs, index));
37     case FIB_PROTOCOL_MPLS:
38         break;
39     }
40     ASSERT(0);
41     return (NULL);
42 }
43
44 static inline fib_node_index_t
45 mfib_table_lookup_i (const mfib_table_t *mfib_table,
46                      const mfib_prefix_t *prefix)
47 {
48     switch (prefix->fp_proto)
49     {
50     case FIB_PROTOCOL_IP4:
51         return (ip4_mfib_table_lookup(&mfib_table->v4,
52                                       &prefix->fp_src_addr.ip4,
53                                       &prefix->fp_grp_addr.ip4,
54                                       prefix->fp_len));
55     case FIB_PROTOCOL_IP6:
56         return (ip6_mfib_table_lookup(&mfib_table->v6,
57                                       &prefix->fp_src_addr.ip6,
58                                       &prefix->fp_grp_addr.ip6,
59                                       prefix->fp_len));
60     case FIB_PROTOCOL_MPLS:
61         break;
62     }
63     return (FIB_NODE_INDEX_INVALID);
64 }
65
66 fib_node_index_t
67 mfib_table_lookup (u32 fib_index,
68                    const mfib_prefix_t *prefix)
69 {
70     return (mfib_table_lookup_i(mfib_table_get(fib_index, prefix->fp_proto), prefix));
71 }
72
73 static inline fib_node_index_t
74 mfib_table_lookup_exact_match_i (const mfib_table_t *mfib_table,
75                                  const mfib_prefix_t *prefix)
76 {
77     switch (prefix->fp_proto)
78     {
79     case FIB_PROTOCOL_IP4:
80         return (ip4_mfib_table_lookup_exact_match(&mfib_table->v4,
81                                                   &prefix->fp_grp_addr.ip4,
82                                                   &prefix->fp_src_addr.ip4,
83                                                   prefix->fp_len));
84     case FIB_PROTOCOL_IP6:
85         return (ip6_mfib_table_lookup_exact_match(&mfib_table->v6,
86                                                   &prefix->fp_grp_addr.ip6,
87                                                   &prefix->fp_src_addr.ip6,
88                                                   prefix->fp_len));
89     case FIB_PROTOCOL_MPLS:
90         break;
91     }
92     return (FIB_NODE_INDEX_INVALID);
93 }
94
95 fib_node_index_t
96 mfib_table_lookup_exact_match (u32 fib_index,
97                               const mfib_prefix_t *prefix)
98 {
99     return (mfib_table_lookup_exact_match_i(mfib_table_get(fib_index,
100                                                           prefix->fp_proto),
101                                             prefix));
102 }
103
104 static fib_node_index_t
105 mfib_table_get_less_specific_i (const mfib_table_t *mfib_table,
106                                 const mfib_prefix_t *prefix)
107 {
108     switch (prefix->fp_proto)
109     {
110     case FIB_PROTOCOL_IP4:
111         return (ip4_mfib_table_get_less_specific(&mfib_table->v4,
112                                                  &prefix->fp_src_addr.ip4,
113                                                  &prefix->fp_grp_addr.ip4,
114                                                  prefix->fp_len));
115     case FIB_PROTOCOL_IP6:
116         return (ip6_mfib_table_get_less_specific(&mfib_table->v6,
117                                                  &prefix->fp_src_addr.ip6,
118                                                  &prefix->fp_grp_addr.ip6,
119                                                  prefix->fp_len));
120     case FIB_PROTOCOL_MPLS:
121         break;
122     }
123     return (FIB_NODE_INDEX_INVALID);
124 }
125
126 fib_node_index_t
127 mfib_table_get_less_specific (u32 fib_index,
128                               const mfib_prefix_t *prefix)
129 {
130     return (mfib_table_get_less_specific_i(mfib_table_get(fib_index,
131                                                           prefix->fp_proto),
132                                            prefix));
133 }
134
135 static void
136 mfib_table_entry_remove (mfib_table_t *mfib_table,
137                          const mfib_prefix_t *prefix,
138                          fib_node_index_t mfib_entry_index)
139 {
140     vlib_smp_unsafe_warning();
141
142     mfib_table->mft_total_route_counts--;
143
144     switch (prefix->fp_proto)
145     {
146     case FIB_PROTOCOL_IP4:
147         ip4_mfib_table_entry_remove(&mfib_table->v4,
148                                     &prefix->fp_grp_addr.ip4,
149                                     &prefix->fp_src_addr.ip4,
150                                     prefix->fp_len);
151         break;
152     case FIB_PROTOCOL_IP6:
153         ip6_mfib_table_entry_remove(&mfib_table->v6,
154                                     &prefix->fp_grp_addr.ip6,
155                                     &prefix->fp_src_addr.ip6,
156                                     prefix->fp_len);
157         break;
158     case FIB_PROTOCOL_MPLS:
159         ASSERT(0);
160         break;
161     }
162
163     mfib_entry_cover_change_notify(mfib_entry_index,
164                                    FIB_NODE_INDEX_INVALID);
165     mfib_entry_unlock(mfib_entry_index);
166 }
167
168 static void
169 mfib_table_post_insert_actions (mfib_table_t *mfib_table,
170                                 const mfib_prefix_t *prefix,
171                                 fib_node_index_t mfib_entry_index)
172 {
173     fib_node_index_t mfib_entry_cover_index;
174
175     /*
176      * find  the covering entry
177      */
178     mfib_entry_cover_index = mfib_table_get_less_specific_i(mfib_table,
179                                                             prefix);
180     /*
181      * the indicies are the same when the default route is first added
182      */
183     if (mfib_entry_cover_index != mfib_entry_index)
184     {
185         /*
186          * inform the covering entry that a new more specific
187          * has been inserted beneath it.
188          * If the prefix that has been inserted is a host route
189          * then it is not possible that it will be the cover for any
190          * other entry, so we can elide the walk.
191          */
192         if (!mfib_entry_is_host(mfib_entry_index))
193         {
194             mfib_entry_cover_change_notify(mfib_entry_cover_index,
195                                            mfib_entry_index);
196         }
197     }
198 }
199
200
201 static void
202 mfib_table_entry_insert (mfib_table_t *mfib_table,
203                          const mfib_prefix_t *prefix,
204                          fib_node_index_t mfib_entry_index)
205 {
206     vlib_smp_unsafe_warning();
207
208     mfib_entry_lock(mfib_entry_index);
209     mfib_table->mft_total_route_counts++;
210
211     switch (prefix->fp_proto)
212     {
213     case FIB_PROTOCOL_IP4:
214         ip4_mfib_table_entry_insert(&mfib_table->v4,
215                                     &prefix->fp_grp_addr.ip4,
216                                     &prefix->fp_src_addr.ip4,
217                                     prefix->fp_len,
218                                     mfib_entry_index);
219         break;
220     case FIB_PROTOCOL_IP6:
221         ip6_mfib_table_entry_insert(&mfib_table->v6,
222                                     &prefix->fp_grp_addr.ip6,
223                                     &prefix->fp_src_addr.ip6,
224                                     prefix->fp_len,
225                                     mfib_entry_index);
226         break;
227     case FIB_PROTOCOL_MPLS:
228         break;
229     }
230
231     mfib_table_post_insert_actions(mfib_table, prefix, mfib_entry_index);
232 }
233
234 fib_node_index_t
235 mfib_table_entry_update (u32 fib_index,
236                          const mfib_prefix_t *prefix,
237                          mfib_source_t source,
238                          fib_rpf_id_t rpf_id,
239                          mfib_entry_flags_t entry_flags)
240 {
241     fib_node_index_t mfib_entry_index;
242     mfib_table_t *mfib_table;
243
244     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
245     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
246
247     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
248     {
249         if (MFIB_ENTRY_FLAG_NONE != entry_flags)
250         {
251             /*
252              * update to a non-existing entry with non-zero flags
253              */
254             mfib_entry_index = mfib_entry_create(fib_index, source,
255                                                  prefix, rpf_id,
256                                                  entry_flags,
257                                                  INDEX_INVALID);
258
259             mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
260         }
261         /*
262          * else
263          *   the entry doesn't exist and the request is to set no flags
264          *   the result would be an entry that doesn't exist - so do nothing
265          */
266     }
267     else
268     {
269         mfib_entry_lock(mfib_entry_index);
270
271         if (mfib_entry_update(mfib_entry_index,
272                               source,
273                               entry_flags,
274                               rpf_id,
275                               INDEX_INVALID))
276         {
277             /*
278              * this update means we can now remove the entry.
279              */
280             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
281         }
282
283         mfib_entry_unlock(mfib_entry_index);
284     }
285
286     return (mfib_entry_index);
287 }
288
289 static fib_node_index_t
290 mfib_table_entry_paths_update_i (u32 fib_index,
291                                  const mfib_prefix_t *prefix,
292                                  mfib_source_t source,
293                                  const fib_route_path_t *rpaths)
294 {
295     fib_node_index_t mfib_entry_index;
296     mfib_table_t *mfib_table;
297
298     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
299     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
300
301     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
302     {
303         mfib_entry_index = mfib_entry_create(fib_index,
304                                              source,
305                                              prefix,
306                                              MFIB_RPF_ID_NONE,
307                                              MFIB_ENTRY_FLAG_NONE,
308                                              INDEX_INVALID);
309
310         mfib_entry_path_update(mfib_entry_index, source, rpaths);
311
312         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
313     }
314     else
315     {
316         mfib_entry_path_update(mfib_entry_index, source, rpaths);
317     }
318     return (mfib_entry_index);
319 }
320
321
322 fib_node_index_t
323 mfib_table_entry_path_update (u32 fib_index,
324                               const mfib_prefix_t *prefix,
325                               mfib_source_t source,
326                               const fib_route_path_t *rpath)
327 {
328     fib_node_index_t mfib_entry_index;
329     fib_route_path_t *rpaths = NULL;
330
331     vec_add1(rpaths, *rpath);
332
333     mfib_entry_index = mfib_table_entry_paths_update_i(fib_index, prefix,
334                                                        source, rpaths);
335
336     vec_free(rpaths);
337     return (mfib_entry_index);
338 }
339
340 fib_node_index_t
341 mfib_table_entry_paths_update (u32 fib_index,
342                               const mfib_prefix_t *prefix,
343                               mfib_source_t source,
344                               const fib_route_path_t *rpaths)
345 {
346     return (mfib_table_entry_paths_update_i(fib_index, prefix,
347                                             source, rpaths));
348 }
349
350 static void
351 mfib_table_entry_paths_remove_i (u32 fib_index,
352                                  const mfib_prefix_t *prefix,
353                                  mfib_source_t source,
354                                  const fib_route_path_t *rpaths)
355 {
356     fib_node_index_t mfib_entry_index;
357     mfib_table_t *mfib_table;
358
359     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
360     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
361
362     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
363     {
364         /*
365          * removing an entry that does not exist. i'll allow it.
366          */
367     }
368     else
369     {
370         int no_more_sources;
371
372         /*
373          * don't nobody go nowhere
374          */
375         mfib_entry_lock(mfib_entry_index);
376
377         no_more_sources = mfib_entry_path_remove(mfib_entry_index,
378                                                  source,
379                                                  rpaths);
380
381         if (no_more_sources)
382         {
383             /*
384              * last source gone. remove from the table
385              */
386             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
387         }
388
389         mfib_entry_unlock(mfib_entry_index);
390     }
391 }
392 void
393 mfib_table_entry_paths_remove (u32 fib_index,
394                               const mfib_prefix_t *prefix,
395                               mfib_source_t source,
396                               const fib_route_path_t *rpaths)
397 {
398     mfib_table_entry_paths_remove_i(fib_index,
399                                     prefix,
400                                     source,
401                                     rpaths);
402 }
403
404 void
405 mfib_table_entry_path_remove (u32 fib_index,
406                               const mfib_prefix_t *prefix,
407                               mfib_source_t source,
408                               const fib_route_path_t *rpath)
409 {
410     fib_route_path_t *rpaths = NULL;
411
412     vec_add1(rpaths, *rpath);
413
414     mfib_table_entry_paths_remove_i(fib_index,
415                                     prefix,
416                                     source,
417                                     rpaths);
418
419     vec_free(rpaths);
420 }
421
422 fib_node_index_t
423 mfib_table_entry_special_add (u32 fib_index,
424                               const mfib_prefix_t *prefix,
425                               mfib_source_t source,
426                               mfib_entry_flags_t entry_flags,
427                               index_t repi)
428 {
429     fib_node_index_t mfib_entry_index;
430     mfib_table_t *mfib_table;
431
432     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
433     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
434
435     if (INDEX_INVALID != repi)
436     {
437         entry_flags |= MFIB_ENTRY_FLAG_EXCLUSIVE;
438     }
439
440     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
441     {
442         mfib_entry_index = mfib_entry_create(fib_index,
443                                              source,
444                                              prefix,
445                                              MFIB_RPF_ID_NONE,
446                                              entry_flags,
447                                              repi);
448
449         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
450     }
451     else
452     {
453         mfib_entry_special_add(mfib_entry_index, source, entry_flags,
454                                MFIB_RPF_ID_NONE, repi);
455     }
456
457     return (mfib_entry_index);
458 }
459
460 static void
461 mfib_table_entry_delete_i (u32 fib_index,
462                            fib_node_index_t mfib_entry_index,
463                            const mfib_prefix_t *prefix,
464                            mfib_source_t source)
465 {
466     mfib_table_t *mfib_table;
467
468     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
469
470     /*
471      * don't nobody go nowhere
472      */
473     mfib_entry_lock(mfib_entry_index);
474
475     if (mfib_entry_delete(mfib_entry_index, source))
476     {
477         /*
478          * last source gone. remove from the table
479          */
480         mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
481     }
482     /*
483      * else
484      *   still has sources, leave it be.
485      */
486
487     mfib_entry_unlock(mfib_entry_index);
488 }
489
490 void
491 mfib_table_entry_delete (u32 fib_index,
492                          const mfib_prefix_t *prefix,
493                          mfib_source_t source)
494 {
495     fib_node_index_t mfib_entry_index;
496
497     mfib_entry_index = mfib_table_lookup_exact_match(fib_index, prefix);
498
499     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
500     {
501         /*
502          * removing an etry that does not exist.
503          * i'll allow it, but i won't like it.
504          */
505         clib_warning("%U not in FIB", format_mfib_prefix, prefix);
506     }
507     else
508     {
509         mfib_table_entry_delete_i(fib_index, mfib_entry_index,
510                                   prefix, source);
511     }
512 }
513
514 void
515 mfib_table_entry_delete_index (fib_node_index_t mfib_entry_index,
516                                mfib_source_t source)
517 {
518     mfib_table_entry_delete_i(mfib_entry_get_fib_index(mfib_entry_index),
519                               mfib_entry_index,
520                               mfib_entry_get_prefix(mfib_entry_index),
521                               source);
522 }
523
524 u32
525 mfib_table_get_index_for_sw_if_index (fib_protocol_t proto,
526                                       u32 sw_if_index)
527 {
528     switch (proto)
529     {
530     case FIB_PROTOCOL_IP4:
531         return (ip4_mfib_table_get_index_for_sw_if_index(sw_if_index));
532     case FIB_PROTOCOL_IP6:
533         return (ip6_mfib_table_get_index_for_sw_if_index(sw_if_index));
534     case FIB_PROTOCOL_MPLS:
535         ASSERT(0);
536         break;
537     }
538     return (~0);
539 }
540
541 u32
542 mfib_table_get_table_id (u32 fib_index,
543                         fib_protocol_t proto)
544 {
545     mfib_table_t *mfib_table;
546
547     mfib_table = mfib_table_get(fib_index, proto);
548
549     return ((NULL != mfib_table ? mfib_table->mft_table_id : ~0));
550 }
551
552 u32
553 mfib_table_find (fib_protocol_t proto,
554                  u32 table_id)
555 {
556     switch (proto)
557     {
558     case FIB_PROTOCOL_IP4:
559         return (ip4_mfib_index_from_table_id(table_id));
560     case FIB_PROTOCOL_IP6:
561         return (ip6_mfib_index_from_table_id(table_id));
562     case FIB_PROTOCOL_MPLS:
563         ASSERT(0);
564         break;
565     }
566     return (~0);
567 }
568
569 static u32
570 mfib_table_find_or_create_and_lock_i (fib_protocol_t proto,
571                                       u32 table_id,
572                                       mfib_source_t src,
573                                       const u8 *name)
574 {
575     mfib_table_t *mfib_table;
576     fib_node_index_t fi;
577
578     switch (proto)
579     {
580     case FIB_PROTOCOL_IP4:
581         fi = ip4_mfib_table_find_or_create_and_lock(table_id, src);
582         break;
583     case FIB_PROTOCOL_IP6:
584         fi = ip6_mfib_table_find_or_create_and_lock(table_id, src);
585         break;
586     case FIB_PROTOCOL_MPLS:
587     default:
588         return (~0);
589     }
590
591     mfib_table = mfib_table_get(fi, proto);
592
593     if (NULL == mfib_table->mft_desc)
594     {
595         if (name && name[0])
596         {
597             mfib_table->mft_desc = format(NULL, "%s", name);
598         }
599         else
600         {
601             mfib_table->mft_desc = format(NULL, "%U-VRF:%d",
602                                           format_fib_protocol, proto,
603                                           table_id);
604         }
605     }
606
607     return (fi);
608 }
609
610 u32
611 mfib_table_find_or_create_and_lock (fib_protocol_t proto,
612                                     u32 table_id,
613                                     mfib_source_t src)
614 {
615     return (mfib_table_find_or_create_and_lock_i(proto, table_id,
616                                                  src, NULL));
617 }
618
619 u32
620 mfib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
621                                            u32 table_id,
622                                            mfib_source_t src,
623                                            const u8 *name)
624 {
625     return (mfib_table_find_or_create_and_lock_i(proto, table_id,
626                                                  src, name));
627 }
628
629 /**
630  * @brief Table flush context. Store the indicies of matching FIB entries
631  * that need to be removed.
632  */
633 typedef struct mfib_table_flush_ctx_t_
634 {
635     /**
636      * The list of entries to flush
637      */
638     fib_node_index_t *mftf_entries;
639
640     /**
641      * The source we are flushing
642      */
643     mfib_source_t mftf_source;
644 } mfib_table_flush_ctx_t;
645
646 static int
647 mfib_table_flush_cb (fib_node_index_t mfib_entry_index,
648                      void *arg)
649 {
650     mfib_table_flush_ctx_t *ctx = arg;
651
652     if (mfib_entry_is_sourced(mfib_entry_index, ctx->mftf_source))
653     {
654         vec_add1(ctx->mftf_entries, mfib_entry_index);
655     }
656     return (1);
657 }
658
659 void
660 mfib_table_flush (u32 mfib_index,
661                   fib_protocol_t proto,
662                   mfib_source_t source)
663 {
664     fib_node_index_t *mfib_entry_index;
665     mfib_table_flush_ctx_t ctx = {
666         .mftf_entries = NULL,
667         .mftf_source = source,
668     };
669
670     mfib_table_walk(mfib_index, proto,
671                     mfib_table_flush_cb,
672                     &ctx);
673
674     vec_foreach(mfib_entry_index, ctx.mftf_entries)
675     {
676         mfib_table_entry_delete_index(*mfib_entry_index, source);
677     }
678
679     vec_free(ctx.mftf_entries);
680 }
681
682 static void
683 mfib_table_destroy (mfib_table_t *mfib_table)
684 {
685     vec_free(mfib_table->mft_desc);
686
687     switch (mfib_table->mft_proto)
688     {
689     case FIB_PROTOCOL_IP4:
690         ip4_mfib_table_destroy(&mfib_table->v4);
691         break;
692     case FIB_PROTOCOL_IP6:
693         ip6_mfib_table_destroy(&mfib_table->v6);
694         break;
695     case FIB_PROTOCOL_MPLS:
696         ASSERT(0);
697         break;
698     }
699 }
700
701 void
702 mfib_table_unlock (u32 fib_index,
703                    fib_protocol_t proto,
704                    mfib_source_t source)
705 {
706     mfib_table_t *mfib_table;
707
708     mfib_table = mfib_table_get(fib_index, proto);
709     mfib_table->mft_locks[source]--;
710     mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]--;
711
712     if (0 == mfib_table->mft_locks[source])
713     {
714         /*
715          * The source no longer needs the table. flush any routes
716          * from it just in case
717          */
718         mfib_table_flush(fib_index, proto, source);
719     }
720
721     if (0 == mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS])
722     {
723         /*
724          * no more locak from any source - kill it
725          */
726         mfib_table_destroy(mfib_table);
727     }
728 }
729
730 void
731 mfib_table_lock (u32 fib_index,
732                  fib_protocol_t proto,
733                  mfib_source_t source)
734 {
735     mfib_table_t *mfib_table;
736
737     mfib_table = mfib_table_get(fib_index, proto);
738     mfib_table->mft_locks[source]++;
739     mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]++;
740 }
741
742 u32
743 mfib_table_get_n_routes (fib_node_index_t fib_index,
744                          fib_protocol_t proto)
745 {
746     mfib_table_t *mfib_table;
747
748     mfib_table = mfib_table_get(fib_index, proto);
749
750     return (mfib_table->mft_total_route_counts);
751 }
752
753 void
754 mfib_table_walk (u32 fib_index,
755                  fib_protocol_t proto,
756                  mfib_table_walk_fn_t fn,
757                  void *ctx)
758 {
759     switch (proto)
760     {
761     case FIB_PROTOCOL_IP4:
762         ip4_mfib_table_walk(ip4_mfib_get(fib_index), fn, ctx);
763         break;
764     case FIB_PROTOCOL_IP6:
765         ip6_mfib_table_walk(ip6_mfib_get(fib_index), fn, ctx);
766         break;
767     case FIB_PROTOCOL_MPLS:
768         break;
769     }
770 }
771
772 u8*
773 format_mfib_table_name (u8* s, va_list *ap)
774 {
775     fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
776     fib_protocol_t proto = va_arg(*ap, int); // int promotion
777     mfib_table_t *mfib_table;
778
779     mfib_table = mfib_table_get(fib_index, proto);
780
781     s = format(s, "%v", mfib_table->mft_desc);
782
783     return (s);
784 }
785
786 u8 *
787 format_mfib_table_memory (u8 *s, va_list *args)
788 {
789     s = format(s, "%U", format_ip4_mfib_table_memory);
790     s = format(s, "%U", format_ip6_mfib_table_memory);
791
792     return (s);
793 }
794
795 static clib_error_t *
796 mfib_module_init (vlib_main_t * vm)
797 {
798     clib_error_t * error;
799
800     mfib_entry_src_module_init();
801     mfib_entry_module_init();
802     mfib_signal_module_init();
803
804     if ((error = vlib_call_init_function (vm, fib_module_init)))
805         return (error);
806     if ((error = vlib_call_init_function (vm, rn_module_init)))
807         return (error);
808
809     return (error);
810 }
811
812 VLIB_INIT_FUNCTION(mfib_module_init);