mroute routers in the stats segment
[vpp.git] / src / vnet / mfib / mfib_entry.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
18 #include <vnet/mfib/mfib_entry.h>
19 #include <vnet/fib/fib_path_list.h>
20
21 #include <vnet/dpo/drop_dpo.h>
22 #include <vnet/dpo/replicate_dpo.h>
23
24 /**
25  * Debug macro
26  */
27 #ifdef MFIB_DEBUG
28 #DEFIne MFIB_ENTRY_DBG(_e, _fmt, _args...)              \
29 {                                                       \
30     u8*__tmp = NULL;                                    \
31     __tmp = format(__tmp, "e:[%d:%U",                   \
32                    mfib_entry_get_index(_e),            \
33                    format_ip46_address,                 \
34                    &_e->mfe_prefix.fp_grp_addr,         \
35                    IP46_TYPE_ANY);                      \
36     __tmp = format(__tmp, "/%d,",                       \
37                    _e->mfe_prefix.fp_len);              \
38     __tmp = format(__tmp, "%U]",                        \
39                    mfib_entry_get_index(_e),            \
40                    format_ip46_address,                 \
41                    &_e->mfe_prefix.fp_src_addr,         \
42                    IP46_TYPE_ANY);                      \
43     __tmp = format(__tmp, _fmt, ##_args);               \
44     clib_warning("%s", __tmp);                          \
45     vec_free(__tmp);                                    \
46 }
47 #else
48 #define MFIB_ENTRY_DBG(_e, _fmt, _args...)
49 #endif
50
51 /**
52  * MFIB extensions to each path
53  */
54 typedef struct mfib_path_ext_t_
55 {
56     mfib_itf_flags_t mfpe_flags;
57     fib_node_index_t mfpe_path;
58 } mfib_path_ext_t;
59
60 /**
61  * The source of an MFIB entry
62  */
63 typedef struct mfib_entry_src_t_
64 {
65     /**
66      * Which source this is
67      */
68     mfib_source_t mfes_src;
69
70     /**
71      * Route flags
72      */
73     mfib_entry_flags_t mfes_flags;
74
75     /**
76      * The path-list of forwarding interfaces
77      */
78     fib_node_index_t mfes_pl;
79
80     /**
81      * RPF-ID
82      */
83     fib_rpf_id_t mfes_rpf_id;
84
85     /**
86      * Hash table of path extensions
87      */
88     mfib_path_ext_t *mfes_exts;
89
90     /**
91      * The hash table of all interfaces.
92      *  This is forwarding time information derived from the paths
93      *  and their extensions.
94      */
95     mfib_itf_t *mfes_itfs;
96 } mfib_entry_src_t;
97
98 /**
99  * Pool of path extensions
100  */
101 static mfib_path_ext_t *mfib_path_ext_pool;
102
103 /**
104  * String names for each source
105  */
106 static const char *mfib_source_names[] = MFIB_SOURCE_NAMES;
107
108 /*
109  * Pool for all fib_entries
110  */
111 mfib_entry_t *mfib_entry_pool;
112
113 static fib_node_t *
114 mfib_entry_get_node (fib_node_index_t index)
115 {
116     return ((fib_node_t*)mfib_entry_get(index));
117 }
118
119 static fib_protocol_t
120 mfib_entry_get_proto (const mfib_entry_t * mfib_entry)
121 {
122     return (mfib_entry->mfe_prefix.fp_proto);
123 }
124
125 fib_forward_chain_type_t
126 mfib_entry_get_default_chain_type (const mfib_entry_t *mfib_entry)
127 {
128     switch (mfib_entry->mfe_prefix.fp_proto)
129     {
130     case FIB_PROTOCOL_IP4:
131         return (FIB_FORW_CHAIN_TYPE_MCAST_IP4);
132     case FIB_PROTOCOL_IP6:
133         return (FIB_FORW_CHAIN_TYPE_MCAST_IP6);
134     case FIB_PROTOCOL_MPLS:
135         ASSERT(0);
136         break;
137     }
138     return (FIB_FORW_CHAIN_TYPE_MCAST_IP4);
139 }
140
141 static u8 *
142 format_mfib_entry_dpo (u8 * s, va_list * args)
143 {
144     index_t fei = va_arg(*args, index_t);
145     CLIB_UNUSED(u32 indent) = va_arg(*args, u32);
146
147     return (format(s, "%U",
148                    format_mfib_entry, fei,
149                    MFIB_ENTRY_FORMAT_BRIEF));
150 }
151
152 static inline mfib_path_ext_t *
153 mfib_entry_path_ext_get (index_t mi)
154 {
155     return (pool_elt_at_index(mfib_path_ext_pool, mi));
156 }
157
158 static u8 *
159 format_mfib_entry_path_ext (u8 * s, va_list * args)
160 {
161     mfib_path_ext_t *path_ext;
162     index_t mpi = va_arg(*args, index_t);
163
164     path_ext = mfib_entry_path_ext_get(mpi);
165     return (format(s, "path:%d flags:%U",
166                    path_ext->mfpe_path,
167                    format_mfib_itf_flags, path_ext->mfpe_flags));
168 }
169
170 u8 *
171 format_mfib_entry (u8 * s, va_list * args)
172 {
173     fib_node_index_t fei, mfi;
174     mfib_entry_t *mfib_entry;
175     mfib_entry_src_t *msrc;
176     u32 sw_if_index;
177     int level;
178
179     fei = va_arg (*args, fib_node_index_t);
180     level = va_arg (*args, int);
181     mfib_entry = mfib_entry_get(fei);
182
183     s = format (s, "%U", format_mfib_prefix, &mfib_entry->mfe_prefix);
184     s = format (s, ": %U", format_mfib_entry_flags, mfib_entry->mfe_flags);
185
186     if (level >= MFIB_ENTRY_FORMAT_DETAIL)
187     {
188         fib_node_index_t path_index, mpi;
189
190         s = format (s, "\n");
191         s = format (s, " fib:%d", mfib_entry->mfe_fib_index);
192         s = format (s, " index:%d", mfib_entry_get_index(mfib_entry));
193         s = format (s, " locks:%d\n", mfib_entry->mfe_node.fn_locks);
194         vec_foreach(msrc, mfib_entry->mfe_srcs)
195         {
196             s = format (s, "  src:%s", mfib_source_names[msrc->mfes_src]);
197             s = format (s, ": %U\n", format_mfib_entry_flags, msrc->mfes_flags);
198             if (FIB_NODE_INDEX_INVALID != msrc->mfes_pl)
199             {
200                 s = fib_path_list_format(msrc->mfes_pl, s);
201             }
202             s = format (s, "    Extensions:\n");
203             hash_foreach(path_index, mpi, msrc->mfes_exts,
204             ({
205                 s = format(s, "     %U\n", format_mfib_entry_path_ext, mpi);
206             }));
207             s = format (s, "    Interface-Forwarding:\n");
208             hash_foreach(sw_if_index, mfi, msrc->mfes_itfs,
209             ({
210                 s = format(s, "    %U\n", format_mfib_itf, mfi);
211             }));
212         }
213     }
214
215     s = format(s, "\n  Interfaces:");
216     hash_foreach(sw_if_index, mfi, mfib_entry->mfe_itfs,
217     ({
218         s = format(s, "\n  %U", format_mfib_itf, mfi);
219     }));
220     if (MFIB_RPF_ID_NONE != mfib_entry->mfe_rpf_id)
221     {
222         s = format(s, "\n  RPF-ID:%d", mfib_entry->mfe_rpf_id);
223     }
224     s = format(s, "\n  %U-chain\n  %U",
225                format_fib_forw_chain_type,
226                mfib_entry_get_default_chain_type(mfib_entry),
227                format_dpo_id,
228                &mfib_entry->mfe_rep,
229                2);
230     s = format(s, "\n");
231
232     if (level >= MFIB_ENTRY_FORMAT_DETAIL2)
233     {
234         s = format(s, "\nchildren:");
235         s = fib_node_children_format(mfib_entry->mfe_node.fn_children, s);
236     }
237
238     return (s);
239 }
240
241 static mfib_entry_t*
242 mfib_entry_from_fib_node (fib_node_t *node)
243 {
244     ASSERT(FIB_NODE_TYPE_MFIB_ENTRY == node->fn_type);
245     return ((mfib_entry_t*)node);
246 }
247
248 static int
249 mfib_entry_src_cmp_for_sort (void * v1,
250                              void * v2)
251 {
252     mfib_entry_src_t *esrc1 = v1, *esrc2 = v2;
253
254     return (esrc1->mfes_src - esrc2->mfes_src);
255 }
256
257 static void
258 mfib_entry_src_init (mfib_entry_t *mfib_entry,
259                      mfib_source_t source)
260
261 {
262     mfib_entry_src_t esrc = {
263         .mfes_pl = FIB_NODE_INDEX_INVALID,
264         .mfes_flags = MFIB_ENTRY_FLAG_NONE,
265         .mfes_src = source,
266     };
267
268     vec_add1(mfib_entry->mfe_srcs, esrc);
269     vec_sort_with_function(mfib_entry->mfe_srcs,
270                            mfib_entry_src_cmp_for_sort);
271 }
272
273 static mfib_entry_src_t *
274 mfib_entry_src_find (const mfib_entry_t *mfib_entry,
275                     mfib_source_t source,
276                     u32 *index)
277
278 {
279     mfib_entry_src_t *esrc;
280     int ii;
281
282     ii = 0;
283     vec_foreach(esrc, mfib_entry->mfe_srcs)
284     {
285         if (esrc->mfes_src == source)
286         {
287             if (NULL != index)
288             {
289                 *index = ii;
290             }
291             return (esrc);
292         }
293         else
294         {
295             ii++;
296         }
297     }
298
299     return (NULL);
300 }
301
302 static mfib_entry_src_t *
303 mfib_entry_src_find_or_create (mfib_entry_t *mfib_entry,
304                                mfib_source_t source)
305 {
306     mfib_entry_src_t *esrc;
307
308     esrc = mfib_entry_src_find(mfib_entry, source, NULL);
309
310     if (NULL == esrc)
311     {
312         mfib_entry_src_init(mfib_entry, source);
313     }
314
315     return (mfib_entry_src_find(mfib_entry, source, NULL));
316 }
317
318 static mfib_entry_src_t*
319 mfib_entry_get_best_src (const mfib_entry_t *mfib_entry)
320 {
321     mfib_entry_src_t *bsrc;
322
323     /*
324      * the enum of sources is deliberately arranged in priority order
325      */
326     if (0 == vec_len(mfib_entry->mfe_srcs))
327     {
328         bsrc = NULL;
329     }
330     else
331     {
332         bsrc = vec_elt_at_index(mfib_entry->mfe_srcs, 0);
333     }
334
335     return (bsrc);
336 }
337
338 int
339 mfib_entry_is_sourced (fib_node_index_t mfib_entry_index,
340                        mfib_source_t source)
341 {
342     mfib_entry_t *mfib_entry;
343
344     mfib_entry = mfib_entry_get(mfib_entry_index);
345
346     return (NULL != mfib_entry_src_find(mfib_entry, source, NULL));
347 }
348
349 static void
350 mfib_entry_src_flush (mfib_entry_src_t *msrc)
351 {
352     u32 sw_if_index;
353     index_t mfii;
354
355     hash_foreach(sw_if_index, mfii, msrc->mfes_itfs,
356     ({
357         mfib_itf_delete(mfib_itf_get(mfii));
358     }));
359     hash_free(msrc->mfes_itfs);
360     msrc->mfes_itfs = NULL;
361     fib_path_list_unlock(msrc->mfes_pl);
362 }
363
364 static void
365 mfib_entry_src_remove (mfib_entry_t *mfib_entry,
366                        mfib_source_t source)
367
368 {
369     mfib_entry_src_t *msrc;
370     u32 index = ~0;
371
372     msrc = mfib_entry_src_find(mfib_entry, source, &index);
373
374     if (NULL != msrc)
375     {
376         mfib_entry_src_flush(msrc);
377         vec_del1(mfib_entry->mfe_srcs, index);
378     }
379 }
380
381 u32
382 mfib_entry_child_add (fib_node_index_t mfib_entry_index,
383                       fib_node_type_t child_type,
384                       fib_node_index_t child_index)
385 {
386     return (fib_node_child_add(FIB_NODE_TYPE_MFIB_ENTRY,
387                                mfib_entry_index,
388                                child_type,
389                                child_index));
390 };
391
392 void
393 mfib_entry_child_remove (fib_node_index_t mfib_entry_index,
394                          u32 sibling_index)
395 {
396     fib_node_child_remove(FIB_NODE_TYPE_MFIB_ENTRY,
397                           mfib_entry_index,
398                           sibling_index);
399 }
400
401 static mfib_entry_t *
402 mfib_entry_alloc (u32 fib_index,
403                   const mfib_prefix_t *prefix,
404                   fib_node_index_t *mfib_entry_index)
405 {
406     mfib_entry_t *mfib_entry;
407
408     pool_get_aligned(mfib_entry_pool, mfib_entry, CLIB_CACHE_LINE_BYTES);
409
410     fib_node_init(&mfib_entry->mfe_node,
411                   FIB_NODE_TYPE_MFIB_ENTRY);
412
413     /*
414      * Some of the members require non-default initialisation
415      * so we also init those that don't and thus save on the call to memset.
416      */
417     mfib_entry->mfe_flags = 0;
418     mfib_entry->mfe_fib_index = fib_index;
419     mfib_entry->mfe_prefix = *prefix;
420     mfib_entry->mfe_srcs = NULL;
421     mfib_entry->mfe_itfs = NULL;
422     mfib_entry->mfe_rpf_id = MFIB_RPF_ID_NONE;
423     mfib_entry->mfe_pl = FIB_NODE_INDEX_INVALID;
424
425     dpo_reset(&mfib_entry->mfe_rep);
426
427     *mfib_entry_index = mfib_entry_get_index(mfib_entry);
428
429     MFIB_ENTRY_DBG(mfib_entry, "alloc");
430
431     return (mfib_entry);
432 }
433
434 static inline mfib_path_ext_t *
435 mfib_entry_path_ext_find (mfib_path_ext_t *exts,
436                           fib_node_index_t path_index)
437 {
438     uword *p;
439
440     p = hash_get(exts, path_index);
441
442     if (NULL != p)
443     {
444         return (mfib_entry_path_ext_get(p[0]));
445     }
446
447     return (NULL);
448 }
449
450 static mfib_path_ext_t*
451 mfib_path_ext_add (mfib_entry_src_t *msrc,
452                    fib_node_index_t path_index,
453                    mfib_itf_flags_t mfi_flags)
454 {
455     mfib_path_ext_t *path_ext;
456
457     pool_get(mfib_path_ext_pool, path_ext);
458
459     path_ext->mfpe_flags = mfi_flags;
460     path_ext->mfpe_path = path_index;
461
462     hash_set(msrc->mfes_exts, path_index,
463              path_ext - mfib_path_ext_pool);
464
465     return (path_ext);
466 }
467
468 static void
469 mfib_path_ext_remove (mfib_entry_src_t *msrc,
470                       fib_node_index_t path_index)
471 {
472     mfib_path_ext_t *path_ext;
473
474     path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
475
476     hash_unset(msrc->mfes_exts, path_index);
477     pool_put(mfib_path_ext_pool, path_ext);
478 }
479
480 typedef struct mfib_entry_collect_forwarding_ctx_t_
481 {
482     load_balance_path_t * next_hops;
483     fib_forward_chain_type_t fct;
484     mfib_entry_src_t *msrc;
485 } mfib_entry_collect_forwarding_ctx_t;
486
487 static fib_path_list_walk_rc_t
488 mfib_entry_src_collect_forwarding (fib_node_index_t pl_index,
489                                    fib_node_index_t path_index,
490                                    void *arg)
491 {
492     mfib_entry_collect_forwarding_ctx_t *ctx;
493     load_balance_path_t *nh;
494
495     ctx = arg;
496
497     /*
498      * if the path is not resolved, don't include it.
499      */
500     if (!fib_path_is_resolved(path_index))
501     {
502         return (FIB_PATH_LIST_WALK_CONTINUE);
503     }
504
505     /*
506      * If the path is not forwarding to use it
507      */
508     mfib_path_ext_t *path_ext;
509     
510     path_ext = mfib_entry_path_ext_find(ctx->msrc->mfes_exts,
511                                         path_index);
512
513     if (NULL != path_ext &&
514         !(path_ext->mfpe_flags & MFIB_ITF_FLAG_FORWARD))
515     {
516         return (FIB_PATH_LIST_WALK_CONTINUE);
517     }
518     
519     switch (ctx->fct)
520     {
521     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
522     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
523         /*
524          * EOS traffic with no label to stack, we need the IP Adj
525          */
526         vec_add2(ctx->next_hops, nh, 1);
527
528         nh->path_index = path_index;
529         nh->path_weight = fib_path_get_weight(path_index);
530         fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
531         break;
532
533     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
534     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
535     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
536     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
537     case FIB_FORW_CHAIN_TYPE_ETHERNET:
538     case FIB_FORW_CHAIN_TYPE_NSH:
539     case FIB_FORW_CHAIN_TYPE_BIER:
540         ASSERT(0);
541         break;
542     }
543
544     return (FIB_PATH_LIST_WALK_CONTINUE);
545 }
546
547 static void
548 mfib_entry_stack (mfib_entry_t *mfib_entry,
549                   mfib_entry_src_t *msrc)
550 {
551     dpo_proto_t dp;
552
553     dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry));
554
555     /*
556      * unlink the enty from the previous path list.
557      */
558     if (FIB_NODE_INDEX_INVALID != mfib_entry->mfe_pl)
559     {
560         fib_path_list_child_remove(mfib_entry->mfe_pl,
561                                    mfib_entry->mfe_sibling);
562     }
563
564     if (NULL != msrc &&
565         FIB_NODE_INDEX_INVALID != msrc->mfes_pl)
566     {
567         mfib_entry_collect_forwarding_ctx_t ctx = {
568             .next_hops = NULL,
569             .fct = mfib_entry_get_default_chain_type(mfib_entry),
570             .msrc = msrc,
571         };
572
573         fib_path_list_walk(msrc->mfes_pl,
574                            mfib_entry_src_collect_forwarding,
575                            &ctx);
576
577         if (!(MFIB_ENTRY_FLAG_EXCLUSIVE & mfib_entry->mfe_flags))
578         {
579             if (NULL == ctx.next_hops)
580             {
581                 /*
582                  * no next-hops, stack directly on the drop
583                  */
584                 dpo_stack(DPO_MFIB_ENTRY, dp,
585                           &mfib_entry->mfe_rep,
586                           drop_dpo_get(dp));
587             }
588             else
589             {
590                 /*
591                  * each path contirbutes a next-hop. form a replicate
592                  * from those choices.
593                  */
594                 if (!dpo_id_is_valid(&mfib_entry->mfe_rep) ||
595                     dpo_is_drop(&mfib_entry->mfe_rep))
596                 {
597                     dpo_id_t tmp_dpo = DPO_INVALID;
598
599                     dpo_set(&tmp_dpo,
600                             DPO_REPLICATE, dp,
601                             replicate_create(0, dp));
602
603                     dpo_stack(DPO_MFIB_ENTRY, dp,
604                               &mfib_entry->mfe_rep,
605                               &tmp_dpo);
606
607                     dpo_reset(&tmp_dpo);
608                 }
609                 replicate_multipath_update(&mfib_entry->mfe_rep,
610                                            ctx.next_hops);
611             }
612         }
613         else
614         {
615             /*
616              * for exclusive routes the source provided a replicate DPO
617              * we we stashed inthe special path list with one path
618              * so we can stack directly on that.
619              */
620             ASSERT(1 == vec_len(ctx.next_hops));
621
622             dpo_stack(DPO_MFIB_ENTRY, dp,
623                       &mfib_entry->mfe_rep,
624                       &ctx.next_hops[0].path_dpo);
625             dpo_reset(&ctx.next_hops[0].path_dpo);
626             vec_free(ctx.next_hops);
627         }
628
629         /*
630          * link the entry to the path-list.
631          * The entry needs to be a child so that we receive the back-walk
632          * updates to recalculate forwarding.
633          */
634         mfib_entry->mfe_pl = msrc->mfes_pl;
635         mfib_entry->mfe_sibling =
636             fib_path_list_child_add(mfib_entry->mfe_pl,
637                                     FIB_NODE_TYPE_MFIB_ENTRY,
638                                     mfib_entry_get_index(mfib_entry));
639     }
640     else
641     {
642         dpo_stack(DPO_MFIB_ENTRY, dp,
643                   &mfib_entry->mfe_rep,
644                   drop_dpo_get(dp));
645     }
646 }
647
648 static fib_node_index_t
649 mfib_entry_src_path_add (mfib_entry_src_t *msrc,
650                          const fib_route_path_t *rpath)
651 {
652     fib_node_index_t path_index;
653     fib_route_path_t *rpaths;
654
655     ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_flags));
656
657     /*
658      * path-lists require a vector of paths
659      */
660     rpaths = NULL;
661     vec_add1(rpaths, rpath[0]);
662
663     if (FIB_NODE_INDEX_INVALID == msrc->mfes_pl)
664     {
665         /* A non-shared path-list */
666         msrc->mfes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NO_URPF,
667                                              NULL);
668         fib_path_list_lock(msrc->mfes_pl);
669     }
670
671     path_index = fib_path_list_path_add(msrc->mfes_pl, rpaths);
672
673     vec_free(rpaths);
674
675     return (path_index);
676 }
677
678 static fib_node_index_t
679 mfib_entry_src_path_remove (mfib_entry_src_t *msrc,
680                             const fib_route_path_t *rpath)
681 {
682     fib_node_index_t path_index;
683     fib_route_path_t *rpaths;
684
685     ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_flags));
686
687     /*
688      * path-lists require a vector of paths
689      */
690     rpaths = NULL;
691     vec_add1(rpaths, rpath[0]);
692
693     path_index = fib_path_list_path_remove(msrc->mfes_pl, rpaths);
694
695     vec_free(rpaths);
696
697     return (path_index);
698 }
699
700 static void
701 mfib_entry_recalculate_forwarding (mfib_entry_t *mfib_entry)
702 {
703     mfib_entry_src_t *bsrc;
704
705     /*
706      * copy the forwarding data from the bast source
707      */
708     bsrc = mfib_entry_get_best_src(mfib_entry);
709
710     if (NULL != bsrc)
711     {
712         mfib_entry->mfe_flags = bsrc->mfes_flags;
713         mfib_entry->mfe_itfs = bsrc->mfes_itfs;
714         mfib_entry->mfe_rpf_id = bsrc->mfes_rpf_id;
715     }
716
717     mfib_entry_stack(mfib_entry, bsrc);
718 }
719
720
721 fib_node_index_t
722 mfib_entry_create (u32 fib_index,
723                    mfib_source_t source,
724                    const mfib_prefix_t *prefix,
725                    fib_rpf_id_t rpf_id,
726                    mfib_entry_flags_t entry_flags)
727 {
728     fib_node_index_t mfib_entry_index;
729     mfib_entry_t *mfib_entry;
730     mfib_entry_src_t *msrc;
731
732     mfib_entry = mfib_entry_alloc(fib_index, prefix,
733                                   &mfib_entry_index);
734     msrc = mfib_entry_src_find_or_create(mfib_entry, source);
735     msrc->mfes_flags = entry_flags;
736     msrc->mfes_rpf_id = rpf_id;
737
738     mfib_entry_recalculate_forwarding(mfib_entry);
739
740     return (mfib_entry_index);
741 }
742
743 static int
744 mfib_entry_ok_for_delete (mfib_entry_t *mfib_entry)
745 {
746     return (0 == vec_len(mfib_entry->mfe_srcs));
747 }
748
749 static int
750 mfib_entry_src_ok_for_delete (const mfib_entry_src_t *msrc)
751 {
752     return ((MFIB_ENTRY_FLAG_NONE == msrc->mfes_flags &&
753              0 == fib_path_list_get_n_paths(msrc->mfes_pl)));
754 }
755
756 int
757 mfib_entry_update (fib_node_index_t mfib_entry_index,
758                    mfib_source_t source,
759                    mfib_entry_flags_t entry_flags,
760                    fib_rpf_id_t rpf_id,
761                    index_t repi)
762 {
763     mfib_entry_t *mfib_entry;
764     mfib_entry_src_t *msrc;
765
766     mfib_entry = mfib_entry_get(mfib_entry_index);
767     msrc = mfib_entry_src_find_or_create(mfib_entry, source);
768     msrc->mfes_flags = entry_flags;
769     msrc->mfes_rpf_id = rpf_id;
770
771     if (INDEX_INVALID != repi)
772     {
773         /*
774          * The source is providing its own replicate DPO.
775          * Create a sepcial path-list to manage it, that way
776          * this entry and the source are equivalent to a normal
777          * entry
778          */
779         fib_node_index_t old_pl_index;
780         dpo_proto_t dp;
781         dpo_id_t dpo = DPO_INVALID;
782
783         dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry));
784         old_pl_index = msrc->mfes_pl;
785
786         dpo_set(&dpo, DPO_REPLICATE, dp, repi);
787
788         msrc->mfes_pl =
789             fib_path_list_create_special(dp,
790                                          FIB_PATH_LIST_FLAG_EXCLUSIVE,
791                                          &dpo);
792
793         dpo_reset(&dpo);
794         fib_path_list_lock(msrc->mfes_pl);
795         fib_path_list_unlock(old_pl_index);
796     }
797
798     if (mfib_entry_src_ok_for_delete(msrc))
799     {
800         /*
801          * this source has no interfaces and no flags.
802          * it has nothing left to give - remove it
803          */
804         mfib_entry_src_remove(mfib_entry, source);
805     }
806
807     mfib_entry_recalculate_forwarding(mfib_entry);
808
809     return (mfib_entry_ok_for_delete(mfib_entry));
810 }
811
812 static void
813 mfib_entry_itf_add (mfib_entry_src_t *msrc,
814                     u32 sw_if_index,
815                     index_t mi)
816 {
817     hash_set(msrc->mfes_itfs, sw_if_index, mi);
818 }
819
820 static void
821 mfib_entry_itf_remove (mfib_entry_src_t *msrc,
822                        u32 sw_if_index)
823 {
824     mfib_itf_t *mfi;
825
826     mfi = mfib_entry_itf_find(msrc->mfes_itfs, sw_if_index);
827
828     mfib_itf_delete(mfi);
829
830     hash_unset(msrc->mfes_itfs, sw_if_index);
831 }
832
833 void
834 mfib_entry_path_update (fib_node_index_t mfib_entry_index,
835                         mfib_source_t source,
836                         const fib_route_path_t *rpath,
837                         mfib_itf_flags_t itf_flags)
838 {
839     fib_node_index_t path_index;
840     mfib_path_ext_t *path_ext;
841     mfib_entry_t *mfib_entry;
842     mfib_entry_src_t *msrc;
843     mfib_itf_flags_t old;
844
845     mfib_entry = mfib_entry_get(mfib_entry_index);
846     ASSERT(NULL != mfib_entry);
847     msrc = mfib_entry_src_find_or_create(mfib_entry, source);
848
849     /*
850      * add the path to the path-list. If it's a duplicate we'll get
851      * back the original path.
852      */
853     path_index = mfib_entry_src_path_add(msrc, rpath);
854
855     /*
856      * find the path extension for that path
857      */
858     path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
859
860     if (NULL == path_ext)
861     {
862         old = MFIB_ITF_FLAG_NONE;
863         path_ext = mfib_path_ext_add(msrc, path_index, itf_flags);
864     }
865     else
866     {
867         old = path_ext->mfpe_flags;
868         path_ext->mfpe_flags = itf_flags;
869     }
870
871     /*
872      * Has the path changed its contribution to the input interface set.
873      * Which only paths with interfaces can do...
874      */
875     if (~0 != rpath[0].frp_sw_if_index)
876     {
877         mfib_itf_t *mfib_itf;
878
879         if (old != itf_flags)
880         {
881             /*
882              * change of flag contributions
883              */
884             mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
885                                            rpath[0].frp_sw_if_index);
886
887             if (NULL == mfib_itf)
888             {
889                 mfib_entry_itf_add(msrc,
890                                    rpath[0].frp_sw_if_index,
891                                    mfib_itf_create(path_index, itf_flags));
892             }
893             else
894             {
895                 if (mfib_itf_update(mfib_itf,
896                                     path_index,
897                                     itf_flags))
898                 {
899                     /*
900                      * no more interface flags on this path, remove
901                      * from the data-plane set
902                      */
903                     mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
904                 }
905             }
906         }
907     }
908
909     mfib_entry_recalculate_forwarding(mfib_entry);
910 }
911
912 /*
913  * mfib_entry_path_remove
914  *
915  * remove a path from the entry.
916  * return the mfib_entry's index if it is still present, INVALID otherwise.
917  */
918 int
919 mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
920                         mfib_source_t source,
921                         const fib_route_path_t *rpath)
922 {
923     fib_node_index_t path_index;
924     mfib_entry_t *mfib_entry;
925     mfib_entry_src_t *msrc;
926
927     mfib_entry = mfib_entry_get(mfib_entry_index);
928     ASSERT(NULL != mfib_entry);
929     msrc = mfib_entry_src_find(mfib_entry, source, NULL);
930
931     if (NULL == msrc)
932     {
933         /*
934          * there are no paths left for this source
935          */
936         return (mfib_entry_ok_for_delete(mfib_entry));
937     }
938
939     /*
940      * remove the path from the path-list. If it's not there we'll get
941      * back invalid
942      */
943     path_index = mfib_entry_src_path_remove(msrc, rpath);
944
945     if (FIB_NODE_INDEX_INVALID != path_index)
946     {
947         /*
948          * don't need the extension, nor the interface anymore
949          */
950         mfib_path_ext_remove(msrc, path_index);
951         if (~0 != rpath[0].frp_sw_if_index)
952         {
953             mfib_itf_t *mfib_itf;
954
955             mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
956                                            rpath[0].frp_sw_if_index);
957
958             if (mfib_itf_update(mfib_itf,
959                                 path_index,
960                                 MFIB_ITF_FLAG_NONE))
961             {
962                 /*
963                  * no more interface flags on this path, remove
964                  * from the data-plane set
965                  */
966                 mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
967             }
968         }
969     }
970
971     if (mfib_entry_src_ok_for_delete(msrc))
972     {
973         /*
974          * this source has no interfaces and no flags.
975          * it has nothing left to give - remove it
976          */
977         mfib_entry_src_remove(mfib_entry, source);
978     }
979
980     mfib_entry_recalculate_forwarding(mfib_entry);
981
982     return (mfib_entry_ok_for_delete(mfib_entry));
983 }
984
985 /**
986  * mfib_entry_delete
987  *
988  * The source is withdrawing all the paths it provided
989  */
990 int
991 mfib_entry_delete (fib_node_index_t mfib_entry_index,
992                    mfib_source_t source)
993 {
994     mfib_entry_t *mfib_entry;
995
996     mfib_entry = mfib_entry_get(mfib_entry_index);
997     mfib_entry_src_remove(mfib_entry, source);
998
999     mfib_entry_recalculate_forwarding(mfib_entry);
1000
1001     return (mfib_entry_ok_for_delete(mfib_entry));
1002 }
1003
1004 static int
1005 fib_ip4_address_compare (ip4_address_t * a1,
1006                          ip4_address_t * a2)
1007 {
1008     /*
1009      * IP addresses are unsiged ints. the return value here needs to be signed
1010      * a simple subtraction won't cut it.
1011      * If the addresses are the same, the sort order is undefiend, so phoey.
1012      */
1013     return ((clib_net_to_host_u32(a1->data_u32) >
1014              clib_net_to_host_u32(a2->data_u32) ) ?
1015             1 : -1);
1016 }
1017
1018 static int
1019 fib_ip6_address_compare (ip6_address_t * a1,
1020                          ip6_address_t * a2)
1021 {
1022   int i;
1023   for (i = 0; i < ARRAY_LEN (a1->as_u16); i++)
1024   {
1025       int cmp = (clib_net_to_host_u16 (a1->as_u16[i]) -
1026                  clib_net_to_host_u16 (a2->as_u16[i]));
1027       if (cmp != 0)
1028           return cmp;
1029   }
1030   return 0;
1031 }
1032
1033 static int
1034 mfib_entry_cmp (fib_node_index_t mfib_entry_index1,
1035                 fib_node_index_t mfib_entry_index2)
1036 {
1037     mfib_entry_t *mfib_entry1, *mfib_entry2;
1038     int cmp = 0;
1039
1040     mfib_entry1 = mfib_entry_get(mfib_entry_index1);
1041     mfib_entry2 = mfib_entry_get(mfib_entry_index2);
1042
1043     switch (mfib_entry1->mfe_prefix.fp_proto)
1044     {
1045     case FIB_PROTOCOL_IP4:
1046         cmp = fib_ip4_address_compare(&mfib_entry1->mfe_prefix.fp_grp_addr.ip4,
1047                                       &mfib_entry2->mfe_prefix.fp_grp_addr.ip4);
1048
1049         if (0 == cmp)
1050         {
1051             cmp = fib_ip4_address_compare(&mfib_entry1->mfe_prefix.fp_src_addr.ip4,
1052                                           &mfib_entry2->mfe_prefix.fp_src_addr.ip4);
1053         }
1054         break;
1055     case FIB_PROTOCOL_IP6:
1056         cmp = fib_ip6_address_compare(&mfib_entry1->mfe_prefix.fp_grp_addr.ip6,
1057                                       &mfib_entry2->mfe_prefix.fp_grp_addr.ip6);
1058
1059         if (0 == cmp)
1060         {
1061             cmp = fib_ip6_address_compare(&mfib_entry1->mfe_prefix.fp_src_addr.ip6,
1062                                           &mfib_entry2->mfe_prefix.fp_src_addr.ip6);
1063         }
1064         break;
1065     case FIB_PROTOCOL_MPLS:
1066         ASSERT(0);
1067         cmp = 0;
1068         break;
1069     }
1070
1071     if (0 == cmp) {
1072         cmp = (mfib_entry1->mfe_prefix.fp_len - mfib_entry2->mfe_prefix.fp_len);
1073     }
1074     return (cmp);
1075 }
1076
1077 int
1078 mfib_entry_cmp_for_sort (void *i1, void *i2)
1079 {
1080     fib_node_index_t *mfib_entry_index1 = i1, *mfib_entry_index2 = i2;
1081
1082     return (mfib_entry_cmp(*mfib_entry_index1,
1083                            *mfib_entry_index2));
1084 }
1085
1086 static void
1087 mfib_entry_last_lock_gone (fib_node_t *node)
1088 {
1089     mfib_entry_t *mfib_entry;
1090     mfib_entry_src_t *msrc;
1091
1092     mfib_entry = mfib_entry_from_fib_node(node);
1093
1094     dpo_reset(&mfib_entry->mfe_rep);
1095
1096     MFIB_ENTRY_DBG(mfib_entry, "last-lock");
1097
1098     vec_foreach(msrc, mfib_entry->mfe_srcs)
1099     {
1100         mfib_entry_src_flush(msrc);
1101     }
1102
1103     vec_free(mfib_entry->mfe_srcs);
1104
1105     fib_node_deinit(&mfib_entry->mfe_node);
1106     pool_put(mfib_entry_pool, mfib_entry);
1107 }
1108
1109 u32
1110 mfib_entry_get_stats_index (fib_node_index_t fib_entry_index)
1111 {
1112     mfib_entry_t *mfib_entry;
1113
1114     mfib_entry = mfib_entry_get(fib_entry_index);
1115
1116     return (mfib_entry->mfe_rep.dpoi_index);
1117 }
1118
1119 /*
1120  * mfib_entry_back_walk_notify
1121  *
1122  * A back walk has reach this entry.
1123  */
1124 static fib_node_back_walk_rc_t
1125 mfib_entry_back_walk_notify (fib_node_t *node,
1126                             fib_node_back_walk_ctx_t *ctx)
1127 {
1128     mfib_entry_recalculate_forwarding(mfib_entry_from_fib_node(node));
1129
1130     return (FIB_NODE_BACK_WALK_CONTINUE);
1131 }
1132
1133 static void
1134 mfib_entry_show_memory (void)
1135 {
1136     fib_show_memory_usage("multicast-Entry",
1137                           pool_elts(mfib_entry_pool),
1138                           pool_len(mfib_entry_pool),
1139                           sizeof(mfib_entry_t));
1140 }
1141
1142 /*
1143  * The MFIB entry's graph node virtual function table
1144  */
1145 static const fib_node_vft_t mfib_entry_vft = {
1146     .fnv_get = mfib_entry_get_node,
1147     .fnv_last_lock = mfib_entry_last_lock_gone,
1148     .fnv_back_walk = mfib_entry_back_walk_notify,
1149     .fnv_mem_show = mfib_entry_show_memory,
1150 };
1151
1152 void
1153 mfib_entry_lock (fib_node_index_t mfib_entry_index)
1154 {
1155     mfib_entry_t *mfib_entry;
1156
1157     mfib_entry = mfib_entry_get(mfib_entry_index);
1158
1159     fib_node_lock(&mfib_entry->mfe_node);
1160 }
1161
1162 void
1163 mfib_entry_unlock (fib_node_index_t mfib_entry_index)
1164 {
1165     mfib_entry_t *mfib_entry;
1166
1167     mfib_entry = mfib_entry_get(mfib_entry_index);
1168
1169     fib_node_unlock(&mfib_entry->mfe_node);
1170 }
1171
1172 static void
1173 mfib_entry_dpo_lock (dpo_id_t *dpo)
1174 {
1175 }
1176 static void
1177 mfib_entry_dpo_unlock (dpo_id_t *dpo)
1178 {
1179 }
1180
1181 const static dpo_vft_t mfib_entry_dpo_vft = {
1182     .dv_lock = mfib_entry_dpo_lock,
1183     .dv_unlock = mfib_entry_dpo_unlock,
1184     .dv_format = format_mfib_entry_dpo,
1185     .dv_mem_show = mfib_entry_show_memory,
1186 };
1187
1188 const static char* const mfib_entry_ip4_nodes[] =
1189 {
1190     "ip4-mfib-forward-rpf",
1191     NULL,
1192 };
1193 const static char* const mfib_entry_ip6_nodes[] =
1194 {
1195     "ip6-mfib-forward-rpf",
1196     NULL,
1197 };
1198
1199 const static char* const * const mfib_entry_nodes[DPO_PROTO_NUM] =
1200 {
1201     [DPO_PROTO_IP4]  = mfib_entry_ip4_nodes,
1202     [DPO_PROTO_IP6]  = mfib_entry_ip6_nodes,
1203 };
1204
1205 void
1206 mfib_entry_module_init (void)
1207 {
1208     fib_node_register_type (FIB_NODE_TYPE_MFIB_ENTRY, &mfib_entry_vft);
1209     dpo_register(DPO_MFIB_ENTRY, &mfib_entry_dpo_vft, mfib_entry_nodes);
1210 }
1211
1212 void
1213 mfib_entry_encode (fib_node_index_t mfib_entry_index,
1214                   fib_route_path_encode_t **api_rpaths)
1215 {
1216     mfib_entry_t *mfib_entry;
1217     mfib_entry_src_t *bsrc;
1218
1219     mfib_entry = mfib_entry_get(mfib_entry_index);
1220     bsrc = mfib_entry_get_best_src(mfib_entry);
1221
1222     if (FIB_NODE_INDEX_INVALID != bsrc->mfes_pl)
1223     {
1224         fib_path_list_walk(bsrc->mfes_pl,
1225                            fib_path_encode,
1226                            api_rpaths);
1227     }
1228 }
1229
1230
1231 void
1232 mfib_entry_get_prefix (fib_node_index_t mfib_entry_index,
1233                       mfib_prefix_t *pfx)
1234 {
1235     mfib_entry_t *mfib_entry;
1236
1237     mfib_entry = mfib_entry_get(mfib_entry_index);
1238     *pfx = mfib_entry->mfe_prefix;
1239 }
1240
1241 u32
1242 mfib_entry_get_fib_index (fib_node_index_t mfib_entry_index)
1243 {
1244     mfib_entry_t *mfib_entry;
1245
1246     mfib_entry = mfib_entry_get(mfib_entry_index);
1247
1248     return (mfib_entry->mfe_fib_index);
1249 }
1250
1251 const dpo_id_t*
1252 mfib_entry_contribute_ip_forwarding (fib_node_index_t mfib_entry_index)
1253 {
1254     mfib_entry_t *mfib_entry;
1255
1256     mfib_entry = mfib_entry_get(mfib_entry_index);
1257
1258     return (&mfib_entry->mfe_rep);
1259 }
1260
1261 void
1262 mfib_entry_contribute_forwarding (fib_node_index_t mfib_entry_index,
1263                                   fib_forward_chain_type_t type,
1264                                   dpo_id_t *dpo)
1265 {
1266     /*
1267      * An IP mFIB entry can only provide a forwarding chain that
1268      * is the same IP proto as the prefix.
1269      * No use-cases (i know of) for other combinations.
1270      */
1271     mfib_entry_t *mfib_entry;
1272     dpo_proto_t dp;
1273
1274     mfib_entry = mfib_entry_get(mfib_entry_index);
1275
1276     dp = fib_proto_to_dpo(mfib_entry->mfe_prefix.fp_proto);
1277
1278     if (type == fib_forw_chain_type_from_dpo_proto(dp))
1279     {
1280         dpo_copy(dpo, &mfib_entry->mfe_rep);
1281     }
1282     else
1283     {
1284         dpo_copy(dpo, drop_dpo_get(dp));
1285     }
1286 }
1287
1288 u32
1289 mfib_entry_pool_size (void)
1290 {
1291     return (pool_elts(mfib_entry_pool));
1292 }
1293
1294 static clib_error_t *
1295 show_mfib_entry_command (vlib_main_t * vm,
1296                         unformat_input_t * input,
1297                         vlib_cli_command_t * cmd)
1298 {
1299     fib_node_index_t fei;
1300
1301     if (unformat (input, "%d", &fei))
1302     {
1303         /*
1304          * show one in detail
1305          */
1306         if (!pool_is_free_index(mfib_entry_pool, fei))
1307         {
1308             vlib_cli_output (vm, "%d@%U",
1309                              fei,
1310                              format_mfib_entry, fei,
1311                              MFIB_ENTRY_FORMAT_DETAIL2);
1312         }
1313         else
1314         {
1315             vlib_cli_output (vm, "entry %d invalid", fei);
1316         }
1317     }
1318     else
1319     {
1320         /*
1321          * show all
1322          */
1323         vlib_cli_output (vm, "FIB Entries:");
1324         pool_foreach_index(fei, mfib_entry_pool,
1325         ({
1326             vlib_cli_output (vm, "%d@%U",
1327                              fei,
1328                              format_mfib_entry, fei,
1329                              MFIB_ENTRY_FORMAT_BRIEF);
1330         }));
1331     }
1332
1333     return (NULL);
1334 }
1335
1336 /*?
1337  * This commnad displays an entry, or all entries, in the mfib tables indexed by their unique
1338  * numerical indentifier.
1339  ?*/
1340 VLIB_CLI_COMMAND (show_mfib_entry, static) = {
1341   .path = "show mfib entry",
1342   .function = show_mfib_entry_command,
1343   .short_help = "show mfib entry",
1344 };