Improve Load-Balance MAPs
[vpp.git] / src / vnet / fib / fib_entry_src.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 <vnet/adj/adj.h>
17 #include <vnet/dpo/load_balance.h>
18 #include <vnet/dpo/mpls_label_dpo.h>
19 #include <vnet/dpo/drop_dpo.h>
20 #include <vnet/dpo/replicate_dpo.h>
21
22 #include <vnet/fib/fib_entry_src.h>
23 #include <vnet/fib/fib_table.h>
24 #include <vnet/fib/fib_path_ext.h>
25 #include <vnet/fib/fib_urpf_list.h>
26
27 /*
28  * per-source type vft
29  */
30 static fib_entry_src_vft_t fib_entry_src_vft[FIB_SOURCE_MAX];
31
32 static fib_protocol_t
33 fib_entry_get_proto (const fib_entry_t * fib_entry)
34 {
35     return (fib_entry->fe_prefix.fp_proto);
36 }
37
38 void
39 fib_entry_src_register (fib_source_t source,
40                         const fib_entry_src_vft_t *vft)
41 {
42     fib_entry_src_vft[source] = *vft;
43 }
44
45 static int
46 fib_entry_src_cmp_for_sort (void * v1,
47                             void * v2)
48 {
49     fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
50
51     return (esrc1->fes_src - esrc2->fes_src);
52 }
53
54 void
55 fib_entry_src_action_init (fib_entry_t *fib_entry,
56                            fib_source_t source)
57
58 {
59     fib_entry_src_t esrc = {
60         .fes_pl = FIB_NODE_INDEX_INVALID,
61         .fes_flags = FIB_ENTRY_SRC_FLAG_NONE,
62         .fes_src = source,
63     };
64
65     if (NULL != fib_entry_src_vft[source].fesv_init)
66     {
67         fib_entry_src_vft[source].fesv_init(&esrc);
68     }
69
70     vec_add1(fib_entry->fe_srcs, esrc);
71     vec_sort_with_function(fib_entry->fe_srcs,
72                            fib_entry_src_cmp_for_sort);
73 }
74
75 static fib_entry_src_t *
76 fib_entry_src_find (const fib_entry_t *fib_entry,
77                     fib_source_t source,
78                     u32 *index)
79
80 {
81     fib_entry_src_t *esrc;
82     int ii;
83
84     ii = 0;
85     vec_foreach(esrc, fib_entry->fe_srcs)
86     {
87         if (esrc->fes_src == source)
88         {
89             if (NULL != index)
90             {
91                 *index = ii;
92             }
93             return (esrc);
94         }
95         else
96         {
97             ii++;
98         }
99     }
100
101     return (NULL);
102 }
103
104 int
105 fib_entry_is_sourced (fib_node_index_t fib_entry_index,
106                       fib_source_t source)
107 {
108     fib_entry_t *fib_entry;
109
110     fib_entry = fib_entry_get(fib_entry_index);
111
112     return (NULL != fib_entry_src_find(fib_entry, source, NULL));
113 }
114
115 static fib_entry_src_t *
116 fib_entry_src_find_or_create (fib_entry_t *fib_entry,
117                               fib_source_t source,
118                               u32 *index)
119 {
120     fib_entry_src_t *esrc;
121
122     esrc = fib_entry_src_find(fib_entry, source, NULL);
123
124     if (NULL == esrc)
125     {
126         fib_entry_src_action_init(fib_entry, source);
127     }
128
129     return (fib_entry_src_find(fib_entry, source, NULL));
130 }
131
132 void
133 fib_entry_src_action_deinit (fib_entry_t *fib_entry,
134                              fib_source_t source)
135
136 {
137     fib_entry_src_t *esrc;
138     u32 index = ~0;
139
140     esrc = fib_entry_src_find(fib_entry, source, &index);
141
142     ASSERT(NULL != esrc);
143
144     if (NULL != fib_entry_src_vft[source].fesv_deinit)
145     {
146         fib_entry_src_vft[source].fesv_deinit(esrc);
147     }
148
149     vec_free(esrc->fes_path_exts);
150     vec_del1(fib_entry->fe_srcs, index);
151 }
152
153 fib_entry_src_cover_res_t
154 fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
155                                    fib_source_t source)
156 {
157     if (NULL != fib_entry_src_vft[source].fesv_cover_change)
158     {
159         return (fib_entry_src_vft[source].fesv_cover_change(
160                     fib_entry_src_find(fib_entry, source, NULL),
161                     fib_entry));
162     }
163
164     fib_entry_src_cover_res_t res = {
165         .install = !0,
166         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
167     };
168     return (res);
169 }
170
171 fib_entry_src_cover_res_t
172 fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
173                                    fib_source_t source)
174 {
175     if (NULL != fib_entry_src_vft[source].fesv_cover_update)
176     {
177         return (fib_entry_src_vft[source].fesv_cover_update(
178                     fib_entry_src_find(fib_entry, source, NULL),
179                     fib_entry));
180     }
181
182     fib_entry_src_cover_res_t res = {
183         .install = !0,
184         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
185     };
186     return (res);
187 }
188
189 typedef struct fib_entry_src_collect_forwarding_ctx_t_
190 {
191     load_balance_path_t * next_hops;
192     const fib_entry_t *fib_entry;
193     const fib_entry_src_t *esrc;
194     fib_forward_chain_type_t fct;
195     int n_recursive_constrained;
196 } fib_entry_src_collect_forwarding_ctx_t;
197
198 /**
199  * @brief Determine whether this FIB entry should use a load-balance MAP
200  * to support PIC edge fast convergence
201  */
202 load_balance_flags_t
203 fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx)
204 {
205     /**
206      * We'll use a LB map if the path-list has multiple recursive paths.
207      * recursive paths implies BGP, and hence scale.
208      */
209     if (ctx->n_recursive_constrained > 1 &&
210         fib_path_list_is_popular(ctx->esrc->fes_pl))
211     {
212         return (LOAD_BALANCE_FLAG_USES_MAP);
213     }
214     return (LOAD_BALANCE_FLAG_NONE);
215 }
216
217 static int
218 fib_entry_src_valid_out_label (mpls_label_t label)
219 {
220     return ((MPLS_LABEL_IS_REAL(label) ||
221              MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
222              MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
223              MPLS_IETF_IMPLICIT_NULL_LABEL == label));
224 }
225
226 /**
227  * @brief Turn the chain type requested by the client into the one they
228  * really wanted
229  */
230 fib_forward_chain_type_t
231 fib_entry_chain_type_fixup (const fib_entry_t *entry,
232                             fib_forward_chain_type_t fct)
233 {
234     /*
235      * The EOS chain is a tricky since one cannot know the adjacency
236      * to link to without knowing what the packets payload protocol
237      * will be once the label is popped.
238      */
239     fib_forward_chain_type_t dfct;
240
241     if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
242     {
243         return (fct);
244     }
245
246     dfct = fib_entry_get_default_chain_type(entry);
247
248     if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
249     {
250         /*
251          * If the entry being asked is a eos-MPLS label entry,
252          * then use the payload-protocol field, that we stashed there
253          * for just this purpose
254          */
255         return (fib_forw_chain_type_from_dpo_proto(
256                     entry->fe_prefix.fp_payload_proto));
257     }
258     /*
259      * else give them what this entry would be by default. i.e. if it's a v6
260      * entry, then the label its local labelled should be carrying v6 traffic.
261      * If it's a non-EOS label entry, then there are more labels and we want
262      * a non-eos chain.
263      */
264     return (dfct);
265 }
266
267 static int
268 fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
269                                   fib_node_index_t path_index,
270                                   void *arg)
271 {
272     fib_entry_src_collect_forwarding_ctx_t *ctx;
273     fib_path_ext_t *path_ext;
274     int have_path_ext;
275
276     ctx = arg;
277
278     /*
279      * if the path is not resolved, don't include it.
280      */
281     if (!fib_path_is_resolved(path_index))
282     {
283         return (!0);
284     }
285
286     if (fib_path_is_recursive_constrained(path_index))
287     {
288         ctx->n_recursive_constrained += 1;
289     }
290
291     /*
292      * get the matching path-extension for the path being visited.
293      */
294     have_path_ext = 0;
295     vec_foreach(path_ext, ctx->esrc->fes_path_exts)
296     {
297         if (path_ext->fpe_path_index == path_index)
298         {
299             have_path_ext = 1;
300             break;
301         }
302     }
303     
304     if (have_path_ext &&
305         fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0]))
306     {
307         /*
308          * found a matching extension. stack it to obtain the forwarding
309          * info for this path.
310          */
311         ctx->next_hops =
312             fib_path_ext_stack(path_ext,
313                                ctx->fct,
314                                fib_entry_chain_type_fixup(ctx->fib_entry,
315                                                           ctx->fct),
316                                ctx->next_hops);
317     }
318     else
319     {
320         load_balance_path_t *nh;
321
322         /*
323          * no extension => no out-going label for this path. that's OK
324          * in the case of an IP or EOS chain, but not for non-EOS
325          */
326         switch (ctx->fct)
327         {
328         case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
329         case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
330         case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
331         case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
332             /*
333              * EOS traffic with no label to stack, we need the IP Adj
334              */
335             vec_add2(ctx->next_hops, nh, 1);
336
337             nh->path_index = path_index;
338             nh->path_weight = fib_path_get_weight(path_index);
339             fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
340
341             break;
342         case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
343             if (fib_path_is_exclusive(path_index) ||
344                 fib_path_is_deag(path_index))
345             {
346                 vec_add2(ctx->next_hops, nh, 1);
347
348                 nh->path_index = path_index;
349                 nh->path_weight = fib_path_get_weight(path_index);
350                 fib_path_contribute_forwarding(path_index,
351                                                FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
352                                                &nh->path_dpo);
353             }
354             break;
355         case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
356         {
357             /*
358              * no label. we need a chain based on the payload. fixup.
359              */
360             vec_add2(ctx->next_hops, nh, 1);
361
362             nh->path_index = path_index;
363             nh->path_weight = fib_path_get_weight(path_index);
364             fib_path_contribute_forwarding(path_index,
365                                            fib_entry_chain_type_fixup(ctx->fib_entry,
366                                                                       ctx->fct),
367                                            &nh->path_dpo);
368             fib_path_stack_mpls_disp(path_index,
369                                      ctx->fib_entry->fe_prefix.fp_payload_proto,
370                                      &nh->path_dpo);
371
372             break;
373         }
374         case FIB_FORW_CHAIN_TYPE_ETHERNET:
375         case FIB_FORW_CHAIN_TYPE_NSH:
376             ASSERT(0);
377             break;
378         }
379     }
380
381     return (!0);
382 }
383
384 void
385 fib_entry_src_mk_lb (fib_entry_t *fib_entry,
386                      const fib_entry_src_t *esrc,
387                      fib_forward_chain_type_t fct,
388                      dpo_id_t *dpo_lb)
389 {
390     dpo_proto_t lb_proto;
391
392     /*
393      * If the entry has path extensions then we construct a load-balance
394      * by stacking the extensions on the forwarding chains of the paths.
395      * Otherwise we use the load-balance of the path-list
396      */
397     fib_entry_src_collect_forwarding_ctx_t ctx = {
398         .esrc = esrc,
399         .fib_entry = fib_entry,
400         .next_hops = NULL,
401         .n_recursive_constrained = 0,
402         .fct = fct,
403     };
404
405     /*
406      * As an optimisation we allocate the vector of next-hops to be sized
407      * equal to the maximum nuber of paths we will need, which is also the
408      * most likely number we will need, since in most cases the paths are 'up'.
409      */
410     vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
411     vec_reset_length(ctx.next_hops);
412
413     lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
414
415     fib_path_list_walk(esrc->fes_pl,
416                        fib_entry_src_collect_forwarding,
417                        &ctx);
418
419     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
420     {
421         /*
422          * the client provided the DPO that the entry should link to.
423          * all entries must link to a LB, so if it is an LB already
424          * then we can use it.
425          */
426         if ((1 == vec_len(ctx.next_hops)) &&
427             (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
428         {
429             dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
430             dpo_reset(&ctx.next_hops[0].path_dpo);
431             return;
432         }
433     }
434
435     if (!dpo_id_is_valid(dpo_lb))
436     {
437         /*
438          * first time create
439          */
440         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
441         {
442             dpo_set(dpo_lb,
443                     DPO_REPLICATE,
444                     lb_proto,
445                     MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
446         }
447         else
448         {
449             flow_hash_config_t fhc;
450
451             fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
452                                                  dpo_proto_to_fib(lb_proto));
453             dpo_set(dpo_lb,
454                     DPO_LOAD_BALANCE,
455                     lb_proto,
456                     load_balance_create(0, lb_proto, fhc));
457         }
458     }
459
460     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
461     {
462         /*
463          * MPLS multicast
464          */
465         replicate_multipath_update(dpo_lb, ctx.next_hops);
466     }
467     else
468     {
469         load_balance_multipath_update(dpo_lb,
470                                       ctx.next_hops,
471                                       fib_entry_calc_lb_flags(&ctx));
472         vec_free(ctx.next_hops);
473
474         /*
475          * if this entry is sourced by the uRPF-exempt source then we
476          * append the always present local0 interface (index 0) to the
477          * uRPF list so it is not empty. that way packets pass the loose check.
478          */
479         index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
480
481         if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
482                                   FIB_SOURCE_URPF_EXEMPT) ||
483              (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
484             (0 == fib_urpf_check_size(ui)))
485         {
486             /*
487              * The uRPF list we get from the path-list is shared by all
488              * other users of the list, but the uRPF exemption applies
489              * only to this prefix. So we need our own list.
490              */
491             ui = fib_urpf_list_alloc_and_lock();
492             fib_urpf_list_append(ui, 0);
493             fib_urpf_list_bake(ui);
494             load_balance_set_urpf(dpo_lb->dpoi_index, ui);
495             fib_urpf_list_unlock(ui);
496         }
497         else
498         {
499             load_balance_set_urpf(dpo_lb->dpoi_index, ui);
500         }
501         load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
502                                          fib_entry_get_flags_i(fib_entry));
503     }
504 }
505
506 void
507 fib_entry_src_action_install (fib_entry_t *fib_entry,
508                               fib_source_t source)
509 {
510     /*
511      * Install the forwarding chain for the given source into the forwarding
512      * tables
513      */
514     fib_forward_chain_type_t fct;
515     fib_entry_src_t *esrc;
516     int insert;
517
518     fct = fib_entry_get_default_chain_type(fib_entry);
519     esrc = fib_entry_src_find(fib_entry, source, NULL);
520
521     /*
522      * Every entry has its own load-balance object. All changes to the entry's
523      * forwarding result in an inplace modify of the load-balance. This means
524      * the load-balance object only needs to be added to the forwarding
525      * DB once, when it is created.
526      */
527     insert = !dpo_id_is_valid(&fib_entry->fe_lb);
528
529     fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
530
531     ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
532     FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
533
534     /*
535      * insert the adj into the data-plane forwarding trie
536      */
537     if (insert)
538     {
539        fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
540                                    &fib_entry->fe_prefix,
541                                    &fib_entry->fe_lb);
542     }
543
544     /*
545      * if any of the other chain types are already created they will need
546      * updating too
547      */
548     fib_entry_delegate_type_t fdt;
549     fib_entry_delegate_t *fed;
550
551     FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
552     {
553         fib_entry_src_mk_lb(fib_entry, esrc,
554                             fib_entry_delegate_type_to_chain_type(fdt),
555                             &fed->fd_dpo);
556     });
557 }
558
559 void
560 fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
561 {
562     /*
563      * uninstall the forwarding chain from the forwarding tables
564      */
565     FIB_ENTRY_DBG(fib_entry, "uninstall: %d",
566                   fib_entry->fe_adj_index);
567
568     if (dpo_id_is_valid(&fib_entry->fe_lb))
569     {
570         fib_table_fwding_dpo_remove(
571             fib_entry->fe_fib_index,
572             &fib_entry->fe_prefix,
573             &fib_entry->fe_lb);
574
575         dpo_reset(&fib_entry->fe_lb);
576     }
577 }
578
579 static void
580 fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
581 {
582     fib_node_index_t *entries = NULL;
583
584     fib_path_list_recursive_loop_detect(path_list_index, &entries);
585
586     vec_free(entries);
587 }
588
589 void
590 fib_entry_src_action_activate (fib_entry_t *fib_entry,
591                                fib_source_t source)
592
593 {
594     int houston_we_are_go_for_install;
595     fib_entry_src_t *esrc;
596
597     esrc = fib_entry_src_find(fib_entry, source, NULL);
598
599     ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
600     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
601
602     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ACTIVE;
603
604     if (NULL != fib_entry_src_vft[source].fesv_activate)
605     {
606         houston_we_are_go_for_install =
607             fib_entry_src_vft[source].fesv_activate(esrc, fib_entry);
608     }
609     else
610     {
611         /*
612          * the source is not providing an activate function, we'll assume
613          * therefore it has no objection to installing the entry
614          */
615         houston_we_are_go_for_install = !0;
616     }
617
618     /*
619      * link to the path-list provided by the source, and go check
620      * if that forms any loops in the graph.
621      */
622     fib_entry->fe_parent = esrc->fes_pl;
623     fib_entry->fe_sibling =
624         fib_path_list_child_add(fib_entry->fe_parent,
625                                 FIB_NODE_TYPE_ENTRY,
626                                 fib_entry_get_index(fib_entry));
627
628     fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
629
630     FIB_ENTRY_DBG(fib_entry, "activate: %d",
631                   fib_entry->fe_parent);
632
633     if (0 != houston_we_are_go_for_install)
634     {
635         fib_entry_src_action_install(fib_entry, source);
636     }
637     else
638     {
639         fib_entry_src_action_uninstall(fib_entry);
640     }
641 }
642
643 void
644 fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
645                                  fib_source_t source)
646
647 {
648     fib_node_index_t path_list_index;
649     fib_entry_src_t *esrc;
650
651     esrc = fib_entry_src_find(fib_entry, source, NULL);
652
653     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
654
655     if (NULL != fib_entry_src_vft[source].fesv_deactivate)
656     {
657         fib_entry_src_vft[source].fesv_deactivate(esrc, fib_entry);
658     }
659
660     esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
661
662     FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
663
664     /*
665      * un-link from an old path-list. Check for any loops this will clear
666      */
667     path_list_index = fib_entry->fe_parent;
668     fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
669
670     fib_entry_recursive_loop_detect_i(path_list_index);
671
672     /*
673      * this will unlock the path-list, so it may be invalid thereafter.
674      */
675     fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
676     fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
677 }
678
679 static void
680 fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
681                                  fib_source_t source)
682 {
683     fib_entry_src_t *esrc;
684
685     vec_foreach(esrc, fib_entry->fe_srcs)
686     {
687         if (NULL != fib_entry_src_vft[esrc->fes_src].fesv_fwd_update)
688         {
689             fib_entry_src_vft[esrc->fes_src].fesv_fwd_update(esrc,
690                                                              fib_entry,
691                                                              source);
692         }
693     }
694 }
695
696 void
697 fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
698                                  fib_source_t source)
699 {
700     fib_node_index_t path_list_index;
701     fib_entry_src_t *esrc;
702
703     esrc = fib_entry_src_find(fib_entry, source, NULL);
704
705     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
706
707     FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
708                   fib_entry->fe_parent,
709                   esrc->fes_pl);
710
711     if (fib_entry->fe_parent != esrc->fes_pl)
712     {
713         /*
714          * un-link from an old path-list. Check for any loops this will clear
715          */
716         path_list_index = fib_entry->fe_parent;
717         fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
718
719         /*
720          * temporary lock so it doesn't get deleted when this entry is no
721          * longer a child.
722          */
723         fib_path_list_lock(path_list_index);
724
725         /*
726          * this entry is no longer a child. after unlinking check if any loops
727          * were broken
728          */
729         fib_path_list_child_remove(path_list_index,
730                                    fib_entry->fe_sibling);
731
732         fib_entry_recursive_loop_detect_i(path_list_index);
733
734         /*
735          * link to the path-list provided by the source, and go check
736          * if that forms any loops in the graph.
737          */
738         fib_entry->fe_parent = esrc->fes_pl;
739         fib_entry->fe_sibling =
740             fib_path_list_child_add(fib_entry->fe_parent,
741                                     FIB_NODE_TYPE_ENTRY,
742                                     fib_entry_get_index(fib_entry));
743
744         fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
745         fib_path_list_unlock(path_list_index);
746     }
747     fib_entry_src_action_install(fib_entry, source);
748     fib_entry_src_action_fwd_update(fib_entry, source);
749 }
750
751 void
752 fib_entry_src_action_installed (const fib_entry_t *fib_entry,
753                                 fib_source_t source)
754 {
755     fib_entry_src_t *esrc;
756
757     esrc = fib_entry_src_find(fib_entry, source, NULL);
758
759     if (NULL != fib_entry_src_vft[source].fesv_installed)
760     {
761         fib_entry_src_vft[source].fesv_installed(esrc,
762                                                  fib_entry);
763     }
764
765     fib_entry_src_action_fwd_update(fib_entry, source);
766 }
767
768 /*
769  * fib_entry_src_action_add
770  *
771  * Adding a source can result in a new fib_entry being created, which
772  * can inturn mean the pool is realloc'd and thus the entry passed as
773  * an argument it also realloc'd
774  * @return the original entry
775  */
776 fib_entry_t *
777 fib_entry_src_action_add (fib_entry_t *fib_entry,
778                           fib_source_t source,
779                           fib_entry_flag_t flags,
780                           const dpo_id_t *dpo)
781 {
782     fib_node_index_t fib_entry_index;
783     fib_entry_src_t *esrc;
784
785     esrc = fib_entry_src_find_or_create(fib_entry, source, NULL);
786
787     esrc->fes_ref_count++;
788
789     if (1 != esrc->fes_ref_count)
790     {
791         /*
792          * we only want to add the source on the 0->1 transition
793          */
794         return (fib_entry);
795     }
796
797     esrc->fes_entry_flags = flags;
798
799     /*
800      * save variable so we can recover from a fib_entry realloc.
801      */
802     fib_entry_index = fib_entry_get_index(fib_entry);
803
804     if (NULL != fib_entry_src_vft[source].fesv_add)
805     {
806         fib_entry_src_vft[source].fesv_add(esrc,
807                                            fib_entry,
808                                            flags,
809                                            fib_entry_get_proto(fib_entry),
810                                            dpo);
811     }
812
813     fib_entry = fib_entry_get(fib_entry_index);
814
815     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
816
817     fib_path_list_lock(esrc->fes_pl);
818
819     /*
820      * the source owns a lock on the entry
821      */
822     fib_entry_lock(fib_entry_get_index(fib_entry));
823
824     return (fib_entry);
825 }
826
827 /*
828  * fib_entry_src_action_update
829  *
830  * Adding a source can result in a new fib_entry being created, which
831  * can inturn mean the pool is realloc'd and thus the entry passed as
832  * an argument it also realloc'd
833  * @return the original entry
834  */
835 fib_entry_t *
836 fib_entry_src_action_update (fib_entry_t *fib_entry,
837                              fib_source_t source,
838                              fib_entry_flag_t flags,
839                              const dpo_id_t *dpo)
840 {
841     fib_node_index_t fib_entry_index, old_path_list_index;
842     fib_entry_src_t *esrc;
843
844     esrc = fib_entry_src_find_or_create(fib_entry, source, NULL);
845
846     if (NULL == esrc)
847         return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
848
849     old_path_list_index = esrc->fes_pl;
850     esrc->fes_entry_flags = flags;
851
852     /*
853      * save variable so we can recover from a fib_entry realloc.
854      */
855     fib_entry_index = fib_entry_get_index(fib_entry);
856
857     if (NULL != fib_entry_src_vft[source].fesv_add)
858     {
859         fib_entry_src_vft[source].fesv_add(esrc,
860                                            fib_entry,
861                                            flags,
862                                            fib_entry_get_proto(fib_entry),
863                                            dpo);
864     }
865
866     fib_entry = fib_entry_get(fib_entry_index);
867
868     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
869
870     fib_path_list_lock(esrc->fes_pl);
871     fib_path_list_unlock(old_path_list_index);
872
873     return (fib_entry);
874 }
875
876
877 fib_entry_src_flag_t
878 fib_entry_src_action_remove (fib_entry_t *fib_entry,
879                              fib_source_t source)
880
881 {
882     fib_node_index_t old_path_list;
883     fib_entry_src_flag_t sflags;
884     fib_entry_src_t *esrc;
885
886     esrc = fib_entry_src_find(fib_entry, source, NULL);
887
888     if (NULL == esrc)
889         return (FIB_ENTRY_SRC_FLAG_ACTIVE);
890
891     esrc->fes_ref_count--;
892     sflags = esrc->fes_flags;
893
894     if (0 != esrc->fes_ref_count)
895     {
896         /*
897          * only remove the source on the 1->0 transisition
898          */
899         return (sflags);
900     }
901
902     if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
903     {
904         fib_entry_src_action_deactivate(fib_entry, source);
905     }
906
907     old_path_list = esrc->fes_pl;
908
909     if (NULL != fib_entry_src_vft[source].fesv_remove)
910     {
911         fib_entry_src_vft[source].fesv_remove(esrc);
912     }
913
914     fib_path_list_unlock(old_path_list);
915     fib_entry_unlock(fib_entry_get_index(fib_entry));
916
917     sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
918     fib_entry_src_action_deinit(fib_entry, source);
919
920     return (sflags);
921 }
922
923 /*
924  * fib_route_attached_cross_table
925  *
926  * Return true the the route is attached via an interface that
927  * is not in the same table as the route
928  */
929 static inline int
930 fib_route_attached_cross_table (const fib_entry_t *fib_entry,
931                                 const fib_route_path_t *rpath)
932 {
933     /*
934      * - All zeros next-hop
935      * - a valid interface
936      * - entry's fib index not equeal to interface's index
937      */
938     if (ip46_address_is_zero(&rpath->frp_addr) &&
939         (~0 != rpath->frp_sw_if_index) &&
940         (fib_entry->fe_fib_index != 
941          fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
942                                              rpath->frp_sw_if_index)))
943     {
944         return (!0);
945     }
946     return (0);
947 }
948
949 /*
950  * fib_route_attached_cross_table
951  *
952  * Return true the the route is attached via an interface that
953  * is not in the same table as the route
954  */
955 static inline int
956 fib_path_is_attached (const fib_route_path_t *rpath)
957 {
958     /*
959      * - All zeros next-hop
960      * - a valid interface
961      */
962     if (ip46_address_is_zero(&rpath->frp_addr) &&
963         (~0 != rpath->frp_sw_if_index))
964     {
965         return (!0);
966     }
967     else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
968     {
969         return (!0);
970     }
971     return (0);
972 }
973
974 fib_path_list_flags_t
975 fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
976 {
977     fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
978
979     if (eflags & FIB_ENTRY_FLAG_DROP)
980     {
981         plf |= FIB_PATH_LIST_FLAG_DROP;
982     }
983     if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
984     {
985         plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
986     }
987     if (eflags & FIB_ENTRY_FLAG_LOCAL)
988     {
989         plf |= FIB_PATH_LIST_FLAG_LOCAL;
990     }
991
992     return (plf);
993 }
994
995 static void
996 fib_entry_flags_update (const fib_entry_t *fib_entry,
997                         const fib_route_path_t *rpath,
998                         fib_path_list_flags_t *pl_flags,
999                         fib_entry_src_t *esrc)
1000 {
1001     if ((esrc->fes_src == FIB_SOURCE_API) ||
1002         (esrc->fes_src == FIB_SOURCE_CLI))
1003     {
1004         if (fib_path_is_attached(rpath))
1005         {
1006             esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1007         }
1008         else
1009         {
1010             esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1011         }
1012     }
1013     if (fib_route_attached_cross_table(fib_entry, rpath))
1014     {
1015         esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1016     }
1017     else
1018     {
1019         esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1020     }
1021 }
1022
1023 /*
1024  * fib_entry_src_path_ext_add
1025  *
1026  * append a path extension to the entry's list
1027  */
1028 static void
1029 fib_entry_src_path_ext_append (fib_entry_src_t *esrc,
1030                                const fib_route_path_t *rpath)
1031 {
1032     if (NULL != rpath->frp_label_stack)
1033     {
1034         fib_path_ext_t *path_ext;
1035
1036         vec_add2(esrc->fes_path_exts, path_ext, 1);
1037
1038         fib_path_ext_init(path_ext, esrc->fes_pl, rpath);
1039     }
1040 }
1041
1042 /*
1043  * fib_entry_src_path_ext_insert
1044  *
1045  * insert, sorted, a path extension to the entry's list.
1046  * It's not strictly necessary in sort the path extensions, since each
1047  * extension has the path index to which it resolves. However, by being
1048  * sorted the load-balance produced has a deterministic order, not an order
1049  * based on the sequence of extension additions. this is a considerable benefit.
1050  */
1051 static void
1052 fib_entry_src_path_ext_insert (fib_entry_src_t *esrc,
1053                                const fib_route_path_t *rpath)
1054 {
1055     if (0 == vec_len(esrc->fes_path_exts))
1056         return (fib_entry_src_path_ext_append(esrc, rpath));
1057
1058     if (NULL != rpath->frp_label_stack)
1059     {
1060         fib_path_ext_t path_ext;
1061         int i = 0;
1062
1063         fib_path_ext_init(&path_ext, esrc->fes_pl, rpath);
1064
1065         while (i < vec_len(esrc->fes_path_exts) &&
1066                (fib_path_ext_cmp(&esrc->fes_path_exts[i], rpath) < 0))
1067         {
1068             i++;
1069         }
1070
1071         vec_insert_elts(esrc->fes_path_exts, &path_ext, 1, i);
1072     }
1073 }
1074
1075 /*
1076  * fib_entry_src_action_add
1077  *
1078  * Adding a source can result in a new fib_entry being created, which
1079  * can inturn mean the pool is realloc'd and thus the entry passed as
1080  * an argument it also realloc'd
1081  * @return the entry
1082  */
1083 fib_entry_t*
1084 fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1085                                fib_source_t source,
1086                                fib_entry_flag_t flags,
1087                                const fib_route_path_t *rpath)
1088 {
1089     fib_node_index_t old_path_list, fib_entry_index;
1090     fib_path_list_flags_t pl_flags;
1091     fib_path_ext_t *path_ext;
1092     fib_entry_src_t *esrc;
1093
1094     /*
1095      * save variable so we can recover from a fib_entry realloc.
1096      */
1097     fib_entry_index = fib_entry_get_index(fib_entry);
1098
1099     esrc = fib_entry_src_find(fib_entry, source, NULL);
1100     if (NULL == esrc)
1101     {
1102         fib_entry =
1103             fib_entry_src_action_add(fib_entry,
1104                                      source,
1105                                      flags,
1106                                      drop_dpo_get(
1107                                          fib_proto_to_dpo(
1108                                              fib_entry_get_proto(fib_entry))));
1109         esrc = fib_entry_src_find(fib_entry, source, NULL);
1110     }
1111
1112     /*
1113      * we are no doubt modifying a path-list. If the path-list
1114      * is shared, and hence not modifiable, then the index returned
1115      * will be for a different path-list. This FIB entry to needs
1116      * to maintain its lock appropriately.
1117      */
1118     old_path_list = esrc->fes_pl;
1119
1120     ASSERT(NULL != fib_entry_src_vft[source].fesv_path_add);
1121
1122     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1123     fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1124
1125     fib_entry_src_vft[source].fesv_path_add(esrc, fib_entry, pl_flags, rpath);
1126     fib_entry = fib_entry_get(fib_entry_index);
1127
1128     /*
1129      * re-resolve all the path-extensions with the new path-list
1130      */
1131     vec_foreach(path_ext, esrc->fes_path_exts)
1132     {
1133         fib_path_ext_resolve(path_ext, esrc->fes_pl);
1134     }
1135     /*
1136      * if the path has a label we need to add a path extension
1137      */
1138     fib_entry_src_path_ext_insert(esrc, rpath);
1139
1140     fib_path_list_lock(esrc->fes_pl);
1141     fib_path_list_unlock(old_path_list);
1142
1143     return (fib_entry);
1144 }
1145
1146 /*
1147  * fib_entry_src_action_swap
1148  *
1149  * The source is providing new paths to replace the old ones.
1150  * Adding a source can result in a new fib_entry being created, which
1151  * can inturn mean the pool is realloc'd and thus the entry passed as
1152  * an argument it also realloc'd
1153  * @return the entry
1154  */
1155 fib_entry_t*
1156 fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1157                                 fib_source_t source,
1158                                 fib_entry_flag_t flags,                         
1159                                 const fib_route_path_t *rpaths)
1160 {
1161     fib_node_index_t old_path_list, fib_entry_index;
1162     fib_path_list_flags_t pl_flags;
1163     const fib_route_path_t *rpath;
1164     fib_path_ext_t *path_ext;
1165     fib_entry_src_t *esrc;
1166
1167     esrc = fib_entry_src_find(fib_entry, source, NULL);
1168
1169     /*
1170      * save variable so we can recover from a fib_entry realloc.
1171      */
1172     fib_entry_index = fib_entry_get_index(fib_entry);
1173
1174     if (NULL == esrc)
1175     {
1176         fib_entry = fib_entry_src_action_add(fib_entry,
1177                                              source,
1178                                              flags,
1179                                              drop_dpo_get(
1180                                                  fib_proto_to_dpo(
1181                                                      fib_entry_get_proto(fib_entry))));
1182         esrc = fib_entry_src_find(fib_entry, source, NULL);
1183     }
1184
1185     /*
1186      * swapping paths may create a new path-list (or may use an existing shared)
1187      * but we are certainly getting a different one. This FIB entry to needs
1188      * to maintain its lock appropriately.
1189      */
1190     old_path_list = esrc->fes_pl;
1191
1192     ASSERT(NULL != fib_entry_src_vft[source].fesv_path_swap);
1193
1194     pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1195
1196     vec_foreach(rpath, rpaths)
1197     {
1198         fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1199     }
1200
1201     fib_entry_src_vft[source].fesv_path_swap(esrc,
1202                                              fib_entry,
1203                                              pl_flags,
1204                                              rpaths);
1205
1206     vec_foreach(path_ext, esrc->fes_path_exts)
1207     {
1208         vec_free(path_ext->fpe_label_stack);
1209     }
1210     vec_free(esrc->fes_path_exts);
1211
1212     vec_foreach(rpath, rpaths)
1213     {
1214         fib_entry_src_path_ext_append(esrc, rpath);
1215     }
1216
1217     fib_entry = fib_entry_get(fib_entry_index);
1218
1219     fib_path_list_lock(esrc->fes_pl);
1220     fib_path_list_unlock(old_path_list);
1221
1222     return (fib_entry);
1223 }
1224
1225 fib_entry_src_flag_t
1226 fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1227                                   fib_source_t source,
1228                                   const fib_route_path_t *rpath)
1229 {
1230     fib_path_list_flags_t pl_flags;
1231     fib_node_index_t old_path_list;
1232     fib_path_ext_t *path_ext;
1233     fib_entry_src_t *esrc;
1234
1235     esrc = fib_entry_src_find(fib_entry, source, NULL);
1236
1237     ASSERT(NULL != esrc);
1238     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1239
1240     /*
1241      * we no doubt modifying a path-list. If the path-list
1242      * is shared, and hence not modifiable, then the index returned
1243      * will be for a different path-list. This FIB entry to needs
1244      * to maintain its lock appropriately.
1245      */
1246     old_path_list = esrc->fes_pl;
1247
1248     ASSERT(NULL != fib_entry_src_vft[source].fesv_path_remove);
1249
1250     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1251     fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1252
1253     fib_entry_src_vft[source].fesv_path_remove(esrc, pl_flags, rpath);
1254     /*
1255      * find the matching path extension and remove it
1256      */
1257     vec_foreach(path_ext, esrc->fes_path_exts)
1258     {
1259         if (!fib_path_ext_cmp(path_ext, rpath))
1260         {
1261             /*
1262              * delete the element moving the remaining elements down 1 position.
1263              * this preserves the sorted order.
1264              */
1265             vec_free(path_ext->fpe_label_stack);
1266             vec_delete(esrc->fes_path_exts, 1, (path_ext - esrc->fes_path_exts));
1267             break;
1268         }
1269     }
1270     /*
1271      * re-resolve all the path-extensions with the new path-list
1272      */
1273     vec_foreach(path_ext, esrc->fes_path_exts)
1274     {
1275         fib_path_ext_resolve(path_ext, esrc->fes_pl);
1276     }
1277
1278     /*
1279      * lock the new path-list, unlock the old if it had one
1280      */
1281     fib_path_list_unlock(old_path_list);
1282
1283     if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1284         fib_path_list_lock(esrc->fes_pl);
1285         return (FIB_ENTRY_SRC_FLAG_ADDED);
1286     }
1287     else
1288     {
1289         /*
1290          * no more paths left from this source
1291          */
1292         fib_entry_src_action_remove(fib_entry, source);
1293         return (FIB_ENTRY_SRC_FLAG_NONE);
1294     }
1295 }
1296
1297 u8*
1298 fib_entry_src_format (fib_entry_t *fib_entry,
1299                       fib_source_t source,
1300                       u8* s)
1301 {
1302     fib_entry_src_t *esrc;
1303
1304     esrc = fib_entry_src_find(fib_entry, source, NULL);
1305
1306     if (NULL != fib_entry_src_vft[source].fesv_format)
1307     {
1308         return (fib_entry_src_vft[source].fesv_format(esrc, s));
1309     }
1310     return (s);
1311 }
1312
1313 adj_index_t
1314 fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1315                               fib_source_t source)
1316 {
1317     fib_entry_t *fib_entry;
1318     fib_entry_src_t *esrc;
1319
1320     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1321         return (ADJ_INDEX_INVALID);
1322
1323     fib_entry = fib_entry_get(fib_entry_index);
1324     esrc = fib_entry_src_find(fib_entry, source, NULL);
1325
1326     if (NULL != esrc)
1327     {
1328         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1329         {
1330             return (fib_path_list_get_adj(
1331                         esrc->fes_pl,
1332                         fib_entry_get_default_chain_type(fib_entry)));
1333         }
1334     }
1335     return (ADJ_INDEX_INVALID);
1336 }
1337
1338 const int
1339 fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1340                               fib_source_t source,
1341                               dpo_id_t *dpo)
1342 {
1343     fib_entry_t *fib_entry;
1344     fib_entry_src_t *esrc;
1345
1346     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1347         return (0);
1348
1349     fib_entry = fib_entry_get(fib_entry_index);
1350     esrc = fib_entry_src_find(fib_entry, source, NULL);
1351
1352     if (NULL != esrc)
1353     {
1354         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1355         {
1356             fib_path_list_contribute_forwarding(
1357                 esrc->fes_pl,
1358                 fib_entry_get_default_chain_type(fib_entry),
1359                 dpo);
1360
1361             return (dpo_id_is_valid(dpo));
1362         }
1363     }
1364     return (0);
1365 }
1366
1367 u32
1368 fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1369                                               fib_source_t source)
1370 {
1371     fib_entry_t *fib_entry;
1372     fib_entry_src_t *esrc;
1373
1374     fib_entry = fib_entry_get(entry_index);
1375
1376     esrc = fib_entry_src_find(fib_entry, source, NULL);
1377
1378     if (NULL != esrc)
1379     {
1380         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1381         {
1382             return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1383         }
1384     }
1385     return (~0);
1386 }
1387
1388 fib_entry_flag_t
1389 fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1390                                 fib_source_t source)
1391 {
1392     fib_entry_t *fib_entry;
1393     fib_entry_src_t *esrc;
1394
1395     fib_entry = fib_entry_get(entry_index);
1396
1397     esrc = fib_entry_src_find(fib_entry, source, NULL);
1398
1399     if (NULL != esrc)
1400     {
1401         return (esrc->fes_entry_flags);
1402     }
1403
1404     return (FIB_ENTRY_FLAG_NONE);
1405 }
1406
1407 fib_entry_flag_t
1408 fib_entry_get_flags_i (const fib_entry_t *fib_entry)
1409 {
1410     fib_entry_flag_t flags;
1411
1412     /*
1413      * the vector of sources is deliberately arranged in priority order
1414      */
1415     if (0 == vec_len(fib_entry->fe_srcs))
1416     {
1417         flags = FIB_ENTRY_FLAG_NONE;
1418     }
1419     else
1420     {
1421         fib_entry_src_t *esrc;
1422
1423         esrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
1424         flags = esrc->fes_entry_flags;
1425     }
1426
1427     return (flags);
1428 }
1429
1430 void
1431 fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1432                            fib_source_t source,
1433                            const void *data)
1434 {
1435     fib_entry_t *fib_entry;
1436     fib_entry_src_t *esrc;
1437
1438     fib_entry = fib_entry_get(fib_entry_index);
1439     esrc = fib_entry_src_find(fib_entry, source, NULL);
1440
1441     if (NULL != esrc &&
1442         NULL != fib_entry_src_vft[source].fesv_set_data)
1443     {
1444         fib_entry_src_vft[source].fesv_set_data(esrc, fib_entry, data);
1445     }
1446 }
1447
1448 const void*
1449 fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1450                            fib_source_t source)
1451 {
1452     fib_entry_t *fib_entry;
1453     fib_entry_src_t *esrc;
1454
1455     fib_entry = fib_entry_get(fib_entry_index);
1456     esrc = fib_entry_src_find(fib_entry, source, NULL);
1457
1458     if (NULL != esrc &&
1459         NULL != fib_entry_src_vft[source].fesv_get_data)
1460     {
1461         return (fib_entry_src_vft[source].fesv_get_data(esrc, fib_entry));
1462     }
1463     return (NULL);
1464 }
1465
1466 void
1467 fib_entry_src_module_init (void)
1468 {
1469     fib_entry_src_rr_register();
1470     fib_entry_src_interface_register();
1471     fib_entry_src_default_route_register();
1472     fib_entry_src_special_register();
1473     fib_entry_src_api_register();
1474     fib_entry_src_adj_register();
1475     fib_entry_src_mpls_register();
1476     fib_entry_src_lisp_register();
1477 }