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