hs-test: clean up Makefile for compatibility with ci-management
[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                                  mfib_entry_flags_t entry_flags,
296                                  const fib_route_path_t *rpaths)
297 {
298     fib_node_index_t mfib_entry_index;
299     mfib_table_t *mfib_table;
300
301     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
302     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
303
304     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
305     {
306         mfib_entry_index = mfib_entry_create(fib_index,
307                                              source,
308                                              prefix,
309                                              MFIB_RPF_ID_NONE,
310                                              entry_flags,
311                                              INDEX_INVALID);
312
313         mfib_entry_path_update(mfib_entry_index, source, rpaths);
314
315         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
316     }
317     else
318     {
319         mfib_entry_path_update(mfib_entry_index, source, rpaths);
320     }
321     return (mfib_entry_index);
322 }
323
324
325 fib_node_index_t
326 mfib_table_entry_path_update (u32 fib_index,
327                               const mfib_prefix_t *prefix,
328                               mfib_source_t source,
329                               mfib_entry_flags_t entry_flags,
330                               const fib_route_path_t *rpath)
331 {
332     fib_node_index_t mfib_entry_index;
333     fib_route_path_t *rpaths = NULL;
334
335     vec_add1(rpaths, *rpath);
336
337     mfib_entry_index = mfib_table_entry_paths_update_i(fib_index, prefix,
338                                                        source, entry_flags,
339                                                        rpaths);
340
341     vec_free(rpaths);
342     return (mfib_entry_index);
343 }
344
345 fib_node_index_t
346 mfib_table_entry_paths_update (u32 fib_index,
347                               const mfib_prefix_t *prefix,
348                               mfib_source_t source,
349                               mfib_entry_flags_t entry_flags,
350                               const fib_route_path_t *rpaths)
351 {
352     return (mfib_table_entry_paths_update_i(fib_index, prefix,
353                                             source, entry_flags, rpaths));
354 }
355
356 static void
357 mfib_table_entry_paths_remove_i (u32 fib_index,
358                                  const mfib_prefix_t *prefix,
359                                  mfib_source_t source,
360                                  const fib_route_path_t *rpaths)
361 {
362     fib_node_index_t mfib_entry_index;
363     mfib_table_t *mfib_table;
364
365     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
366     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
367
368     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
369     {
370         /*
371          * removing an entry that does not exist. i'll allow it.
372          */
373     }
374     else
375     {
376         int no_more_sources;
377
378         /*
379          * don't nobody go nowhere
380          */
381         mfib_entry_lock(mfib_entry_index);
382
383         no_more_sources = mfib_entry_path_remove(mfib_entry_index,
384                                                  source,
385                                                  rpaths);
386
387         if (no_more_sources)
388         {
389             /*
390              * last source gone. remove from the table
391              */
392             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
393         }
394
395         mfib_entry_unlock(mfib_entry_index);
396     }
397 }
398 void
399 mfib_table_entry_paths_remove (u32 fib_index,
400                               const mfib_prefix_t *prefix,
401                               mfib_source_t source,
402                               const fib_route_path_t *rpaths)
403 {
404     mfib_table_entry_paths_remove_i(fib_index,
405                                     prefix,
406                                     source,
407                                     rpaths);
408 }
409
410 void
411 mfib_table_entry_path_remove (u32 fib_index,
412                               const mfib_prefix_t *prefix,
413                               mfib_source_t source,
414                               const fib_route_path_t *rpath)
415 {
416     fib_route_path_t *rpaths = NULL;
417
418     vec_add1(rpaths, *rpath);
419
420     mfib_table_entry_paths_remove_i(fib_index,
421                                     prefix,
422                                     source,
423                                     rpaths);
424
425     vec_free(rpaths);
426 }
427
428 fib_node_index_t
429 mfib_table_entry_special_add (u32 fib_index,
430                               const mfib_prefix_t *prefix,
431                               mfib_source_t source,
432                               mfib_entry_flags_t entry_flags,
433                               index_t repi)
434 {
435     fib_node_index_t mfib_entry_index;
436     mfib_table_t *mfib_table;
437
438     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
439     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
440
441     if (INDEX_INVALID != repi)
442     {
443         entry_flags |= MFIB_ENTRY_FLAG_EXCLUSIVE;
444     }
445
446     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
447     {
448         mfib_entry_index = mfib_entry_create(fib_index,
449                                              source,
450                                              prefix,
451                                              MFIB_RPF_ID_NONE,
452                                              entry_flags,
453                                              repi);
454
455         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
456     }
457     else
458     {
459         mfib_entry_special_add(mfib_entry_index, source, entry_flags,
460                                MFIB_RPF_ID_NONE, repi);
461     }
462
463     return (mfib_entry_index);
464 }
465
466 static void
467 mfib_table_entry_delete_i (u32 fib_index,
468                            fib_node_index_t mfib_entry_index,
469                            const mfib_prefix_t *prefix,
470                            mfib_source_t source)
471 {
472     mfib_table_t *mfib_table;
473
474     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
475
476     /*
477      * don't nobody go nowhere
478      */
479     mfib_entry_lock(mfib_entry_index);
480
481     if (mfib_entry_delete(mfib_entry_index, source))
482     {
483         /*
484          * last source gone. remove from the table
485          */
486         mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
487     }
488     /*
489      * else
490      *   still has sources, leave it be.
491      */
492
493     mfib_entry_unlock(mfib_entry_index);
494 }
495
496 void
497 mfib_table_entry_delete (u32 fib_index,
498                          const mfib_prefix_t *prefix,
499                          mfib_source_t source)
500 {
501     fib_node_index_t mfib_entry_index;
502
503     mfib_entry_index = mfib_table_lookup_exact_match(fib_index, prefix);
504
505     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
506     {
507         /*
508          * removing an etry that does not exist.
509          * i'll allow it, but i won't like it.
510          */
511         clib_warning("%U not in FIB", format_mfib_prefix, prefix);
512     }
513     else
514     {
515         mfib_table_entry_delete_i(fib_index, mfib_entry_index,
516                                   prefix, source);
517     }
518 }
519
520 void
521 mfib_table_entry_delete_index (fib_node_index_t mfib_entry_index,
522                                mfib_source_t source)
523 {
524     mfib_table_entry_delete_i(mfib_entry_get_fib_index(mfib_entry_index),
525                               mfib_entry_index,
526                               mfib_entry_get_prefix(mfib_entry_index),
527                               source);
528 }
529
530 u32
531 mfib_table_get_index_for_sw_if_index (fib_protocol_t proto,
532                                       u32 sw_if_index)
533 {
534     switch (proto)
535     {
536     case FIB_PROTOCOL_IP4:
537         return (ip4_mfib_table_get_index_for_sw_if_index(sw_if_index));
538     case FIB_PROTOCOL_IP6:
539         return (ip6_mfib_table_get_index_for_sw_if_index(sw_if_index));
540     case FIB_PROTOCOL_MPLS:
541         ASSERT(0);
542         break;
543     }
544     return (~0);
545 }
546
547 u32
548 mfib_table_get_table_id (u32 fib_index,
549                         fib_protocol_t proto)
550 {
551     mfib_table_t *mfib_table;
552
553     mfib_table = mfib_table_get(fib_index, proto);
554
555     return ((NULL != mfib_table ? mfib_table->mft_table_id : ~0));
556 }
557
558 u32
559 mfib_table_find (fib_protocol_t proto,
560                  u32 table_id)
561 {
562     switch (proto)
563     {
564     case FIB_PROTOCOL_IP4:
565         return (ip4_mfib_index_from_table_id(table_id));
566     case FIB_PROTOCOL_IP6:
567         return (ip6_mfib_index_from_table_id(table_id));
568     case FIB_PROTOCOL_MPLS:
569         ASSERT(0);
570         break;
571     }
572     return (~0);
573 }
574
575 static u32
576 mfib_table_find_or_create_and_lock_i (fib_protocol_t proto,
577                                       u32 table_id,
578                                       mfib_source_t src,
579                                       const u8 *name)
580 {
581     mfib_table_t *mfib_table;
582     fib_node_index_t fi;
583
584     switch (proto)
585     {
586     case FIB_PROTOCOL_IP4:
587         fi = ip4_mfib_table_find_or_create_and_lock(table_id, src);
588         break;
589     case FIB_PROTOCOL_IP6:
590         fi = ip6_mfib_table_find_or_create_and_lock(table_id, src);
591         break;
592     case FIB_PROTOCOL_MPLS:
593     default:
594         return (~0);
595     }
596
597     mfib_table = mfib_table_get(fi, proto);
598
599     if (NULL == mfib_table->mft_desc)
600     {
601         if (name && name[0])
602         {
603             mfib_table->mft_desc = format(NULL, "%s", name);
604         }
605         else
606         {
607             mfib_table->mft_desc = format(NULL, "%U-VRF:%d",
608                                           format_fib_protocol, proto,
609                                           table_id);
610         }
611     }
612
613     return (fi);
614 }
615
616 u32
617 mfib_table_find_or_create_and_lock (fib_protocol_t proto,
618                                     u32 table_id,
619                                     mfib_source_t src)
620 {
621     return (mfib_table_find_or_create_and_lock_i(proto, table_id,
622                                                  src, NULL));
623 }
624
625 u32
626 mfib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
627                                            u32 table_id,
628                                            mfib_source_t src,
629                                            const u8 *name)
630 {
631     return (mfib_table_find_or_create_and_lock_i(proto, table_id,
632                                                  src, name));
633 }
634
635 /**
636  * @brief Table flush context. Store the indicies of matching FIB entries
637  * that need to be removed.
638  */
639 typedef struct mfib_table_flush_ctx_t_
640 {
641     /**
642      * The list of entries to flush
643      */
644     fib_node_index_t *mftf_entries;
645
646     /**
647      * The source we are flushing
648      */
649     mfib_source_t mftf_source;
650 } mfib_table_flush_ctx_t;
651
652 static walk_rc_t
653 mfib_table_flush_cb (fib_node_index_t mfib_entry_index,
654                      void *arg)
655 {
656     mfib_table_flush_ctx_t *ctx = arg;
657
658     if (mfib_entry_is_sourced(mfib_entry_index, ctx->mftf_source))
659     {
660         vec_add1(ctx->mftf_entries, mfib_entry_index);
661     }
662     return (WALK_CONTINUE);
663 }
664
665 void
666 mfib_table_flush (u32 mfib_index,
667                   fib_protocol_t proto,
668                   mfib_source_t source)
669 {
670     fib_node_index_t *mfib_entry_index;
671     mfib_table_flush_ctx_t ctx = {
672         .mftf_entries = NULL,
673         .mftf_source = source,
674     };
675
676     mfib_table_walk(mfib_index, proto,
677                     mfib_table_flush_cb,
678                     &ctx);
679
680     vec_foreach(mfib_entry_index, ctx.mftf_entries)
681     {
682         mfib_table_entry_delete_index(*mfib_entry_index, source);
683     }
684
685     vec_free(ctx.mftf_entries);
686 }
687
688 static walk_rc_t
689 mfib_table_mark_cb (fib_node_index_t fib_entry_index,
690                    void *arg)
691 {
692     mfib_table_flush_ctx_t *ctx = arg;
693
694     if (mfib_entry_is_sourced(fib_entry_index, ctx->mftf_source))
695     {
696         mfib_entry_mark(fib_entry_index, ctx->mftf_source);
697     }
698     return (WALK_CONTINUE);
699 }
700
701 void
702 mfib_table_mark (u32 fib_index,
703                  fib_protocol_t proto,
704                  mfib_source_t source)
705 {
706     mfib_table_flush_ctx_t ctx = {
707         .mftf_source = source,
708     };
709     mfib_table_t *mfib_table;
710
711     mfib_table = mfib_table_get(fib_index, proto);
712
713     mfib_table->mft_epoch++;
714     mfib_table->mft_flags |= MFIB_TABLE_FLAG_RESYNC;
715
716     mfib_table_walk(fib_index, proto,
717                    mfib_table_mark_cb,
718                    &ctx);
719 }
720
721 static walk_rc_t
722 mfib_table_sweep_cb (fib_node_index_t fib_entry_index,
723                     void *arg)
724 {
725     mfib_table_flush_ctx_t *ctx = arg;
726
727     if (mfib_entry_is_marked(fib_entry_index, ctx->mftf_source))
728     {
729         vec_add1(ctx->mftf_entries, fib_entry_index);
730     }
731     return (WALK_CONTINUE);
732 }
733
734 void
735 mfib_table_sweep (u32 fib_index,
736                   fib_protocol_t proto,
737                   mfib_source_t source)
738 {
739     mfib_table_flush_ctx_t ctx = {
740         .mftf_source = source,
741     };
742     fib_node_index_t *fib_entry_index;
743     mfib_table_t *mfib_table;
744
745     mfib_table = mfib_table_get(fib_index, proto);
746
747     mfib_table->mft_flags &= ~MFIB_TABLE_FLAG_RESYNC;
748
749     mfib_table_walk(fib_index, proto,
750                     mfib_table_sweep_cb,
751                     &ctx);
752
753     vec_foreach(fib_entry_index, ctx.mftf_entries)
754     {
755         mfib_table_entry_delete_index(*fib_entry_index, source);
756     }
757
758     vec_free(ctx.mftf_entries);
759 }
760
761 static void
762 mfib_table_destroy (mfib_table_t *mfib_table)
763 {
764     vec_free(mfib_table->mft_desc);
765
766     switch (mfib_table->mft_proto)
767     {
768     case FIB_PROTOCOL_IP4:
769         ip4_mfib_table_destroy(&mfib_table->v4);
770         break;
771     case FIB_PROTOCOL_IP6:
772         ip6_mfib_table_destroy(&mfib_table->v6);
773         break;
774     case FIB_PROTOCOL_MPLS:
775         ASSERT(0);
776         break;
777     }
778 }
779
780 void
781 mfib_table_unlock (u32 fib_index,
782                    fib_protocol_t proto,
783                    mfib_source_t source)
784 {
785     mfib_table_t *mfib_table;
786
787     mfib_table = mfib_table_get(fib_index, proto);
788     mfib_table->mft_locks[source]--;
789     mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]--;
790
791     if (0 == mfib_table->mft_locks[source])
792     {
793         /*
794          * The source no longer needs the table. flush any routes
795          * from it just in case
796          */
797         mfib_table_flush(fib_index, proto, source);
798     }
799
800     if (0 == mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS])
801     {
802         /*
803          * no more locak from any source - kill it
804          */
805         mfib_table_destroy(mfib_table);
806     }
807 }
808
809 void
810 mfib_table_lock (u32 fib_index,
811                  fib_protocol_t proto,
812                  mfib_source_t source)
813 {
814     mfib_table_t *mfib_table;
815
816     mfib_table = mfib_table_get(fib_index, proto);
817     mfib_table->mft_locks[source]++;
818     mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]++;
819 }
820
821 u32
822 mfib_table_get_n_routes (fib_node_index_t fib_index,
823                          fib_protocol_t proto)
824 {
825     mfib_table_t *mfib_table;
826
827     mfib_table = mfib_table_get(fib_index, proto);
828
829     return (mfib_table->mft_total_route_counts);
830 }
831
832 void
833 mfib_table_walk (u32 fib_index,
834                  fib_protocol_t proto,
835                  mfib_table_walk_fn_t fn,
836                  void *ctx)
837 {
838     switch (proto)
839     {
840     case FIB_PROTOCOL_IP4:
841         ip4_mfib_table_walk(ip4_mfib_get(fib_index), fn, ctx);
842         break;
843     case FIB_PROTOCOL_IP6:
844         ip6_mfib_table_walk(ip6_mfib_get(fib_index), fn, ctx);
845         break;
846     case FIB_PROTOCOL_MPLS:
847         break;
848     }
849 }
850
851 u8*
852 format_mfib_table_flags (u8 *s, va_list *args)
853 {
854     mfib_table_flags_t flags = va_arg(*args, int);
855     mfib_table_attribute_t attr;
856
857     if (!flags)
858     {
859         return format(s, "none");
860     }
861
862     FOR_EACH_MFIB_TABLE_ATTRIBUTE(attr) {
863         if (1 << attr & flags) {
864             s = format(s, "%s", mfib_table_flags_strings[attr]);
865         }
866     }
867
868     return (s);
869 }
870
871 u8*
872 format_mfib_table_name (u8* s, va_list *ap)
873 {
874     fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
875     fib_protocol_t proto = va_arg(*ap, int); // int promotion
876     mfib_table_t *mfib_table;
877
878     mfib_table = mfib_table_get(fib_index, proto);
879
880     s = format(s, "%v", mfib_table->mft_desc);
881
882     return (s);
883 }
884
885 u8 *
886 format_mfib_table_memory (u8 *s, va_list *args)
887 {
888     s = format(s, "%U", format_ip4_mfib_table_memory);
889     s = format(s, "%U", format_ip6_mfib_table_memory);
890
891     return (s);
892 }
893
894 static clib_error_t *
895 mfib_module_init (vlib_main_t * vm)
896 {
897     clib_error_t * error;
898
899     mfib_entry_src_module_init();
900     mfib_entry_module_init();
901     mfib_signal_module_init();
902
903     if ((error = vlib_call_init_function (vm, fib_module_init)))
904         return (error);
905     if ((error = vlib_call_init_function (vm, rn_module_init)))
906         return (error);
907
908     return (error);
909 }
910
911 VLIB_INIT_FUNCTION(mfib_module_init);