IP6 link-local table
[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 void
33 fib_entry_src_register (fib_source_t source,
34                         const fib_entry_src_vft_t *vft)
35 {
36     fib_entry_src_vft[source] = *vft;
37 }
38
39 static int
40 fib_entry_src_cmp_for_sort (void * v1,
41                             void * v2)
42 {
43     fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
44
45     return (esrc1->fes_src - esrc2->fes_src);
46 }
47
48 void
49 fib_entry_src_action_init (fib_entry_t *fib_entry,
50                            fib_source_t source)
51
52 {
53     fib_entry_src_t esrc = {
54         .fes_pl = FIB_NODE_INDEX_INVALID,
55         .fes_flags = FIB_ENTRY_SRC_FLAG_NONE,
56         .fes_src = source,
57     };
58
59     if (NULL != fib_entry_src_vft[source].fesv_init)
60     {
61         fib_entry_src_vft[source].fesv_init(&esrc);
62     }
63
64     vec_add1(fib_entry->fe_srcs, esrc);
65     vec_sort_with_function(fib_entry->fe_srcs,
66                            fib_entry_src_cmp_for_sort);
67 }
68
69 static fib_entry_src_t *
70 fib_entry_src_find (const fib_entry_t *fib_entry,
71                     fib_source_t source,
72                     u32 *index)
73
74 {
75     fib_entry_src_t *esrc;
76     int ii;
77
78     ii = 0;
79     vec_foreach(esrc, fib_entry->fe_srcs)
80     {
81         if (esrc->fes_src == source)
82         {
83             if (NULL != index)
84             {
85                 *index = ii;
86             }
87             return (esrc);
88         }
89         else
90         {
91             ii++;
92         }
93     }
94
95     return (NULL);
96 }
97
98 int
99 fib_entry_is_sourced (fib_node_index_t fib_entry_index,
100                       fib_source_t source)
101 {
102     fib_entry_t *fib_entry;
103
104     fib_entry = fib_entry_get(fib_entry_index);
105
106     return (NULL != fib_entry_src_find(fib_entry, source, NULL));
107 }
108
109 static fib_entry_src_t *
110 fib_entry_src_find_or_create (fib_entry_t *fib_entry,
111                               fib_source_t source)
112 {
113     fib_entry_src_t *esrc;
114
115     esrc = fib_entry_src_find(fib_entry, source, NULL);
116
117     if (NULL == esrc)
118     {
119         fib_entry_src_action_init(fib_entry, source);
120     }
121
122     return (fib_entry_src_find(fib_entry, source, NULL));
123 }
124
125 void
126 fib_entry_src_action_deinit (fib_entry_t *fib_entry,
127                              fib_source_t source)
128
129 {
130     fib_entry_src_t *esrc;
131     u32 index = ~0;
132
133     esrc = fib_entry_src_find(fib_entry, source, &index);
134
135     ASSERT(NULL != esrc);
136
137     if (NULL != fib_entry_src_vft[source].fesv_deinit)
138     {
139         fib_entry_src_vft[source].fesv_deinit(esrc);
140     }
141
142     fib_path_ext_list_flush(&esrc->fes_path_exts);
143     vec_del1(fib_entry->fe_srcs, index);
144 }
145
146 fib_entry_src_cover_res_t
147 fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
148                                    fib_source_t source)
149 {
150     if (NULL != fib_entry_src_vft[source].fesv_cover_change)
151     {
152         return (fib_entry_src_vft[source].fesv_cover_change(
153                     fib_entry_src_find(fib_entry, source, NULL),
154                     fib_entry));
155     }
156
157     fib_entry_src_cover_res_t res = {
158         .install = !0,
159         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
160     };
161     return (res);
162 }
163
164 fib_entry_src_cover_res_t
165 fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
166                                    fib_source_t source)
167 {
168     if (NULL != fib_entry_src_vft[source].fesv_cover_update)
169     {
170         return (fib_entry_src_vft[source].fesv_cover_update(
171                     fib_entry_src_find(fib_entry, source, NULL),
172                     fib_entry));
173     }
174
175     fib_entry_src_cover_res_t res = {
176         .install = !0,
177         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
178     };
179     return (res);
180 }
181
182 typedef struct fib_entry_src_collect_forwarding_ctx_t_
183 {
184     load_balance_path_t *next_hops;
185     const fib_entry_t *fib_entry;
186     const fib_entry_src_t *esrc;
187     fib_forward_chain_type_t fct;
188     int n_recursive_constrained;
189     u16 preference;
190 } fib_entry_src_collect_forwarding_ctx_t;
191
192 /**
193  * @brief Determine whether this FIB entry should use a load-balance MAP
194  * to support PIC edge fast convergence
195  */
196 load_balance_flags_t
197 fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx)
198 {
199     /**
200      * We'll use a LB map if the path-list has multiple recursive paths.
201      * recursive paths implies BGP, and hence scale.
202      */
203     if (ctx->n_recursive_constrained > 1 &&
204         fib_path_list_is_popular(ctx->esrc->fes_pl))
205     {
206         return (LOAD_BALANCE_FLAG_USES_MAP);
207     }
208     return (LOAD_BALANCE_FLAG_NONE);
209 }
210
211 static int
212 fib_entry_src_valid_out_label (mpls_label_t label)
213 {
214     return ((MPLS_LABEL_IS_REAL(label) ||
215              MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
216              MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
217              MPLS_IETF_IMPLICIT_NULL_LABEL == label));
218 }
219
220 /**
221  * @brief Turn the chain type requested by the client into the one they
222  * really wanted
223  */
224 fib_forward_chain_type_t
225 fib_entry_chain_type_fixup (const fib_entry_t *entry,
226                             fib_forward_chain_type_t fct)
227 {
228     /*
229      * The EOS chain is a tricky since one cannot know the adjacency
230      * to link to without knowing what the packets payload protocol
231      * will be once the label is popped.
232      */
233     fib_forward_chain_type_t dfct;
234
235     if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
236     {
237         return (fct);
238     }
239
240     dfct = fib_entry_get_default_chain_type(entry);
241
242     if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
243     {
244         /*
245          * If the entry being asked is a eos-MPLS label entry,
246          * then use the payload-protocol field, that we stashed there
247          * for just this purpose
248          */
249         return (fib_forw_chain_type_from_dpo_proto(
250                     entry->fe_prefix.fp_payload_proto));
251     }
252     /*
253      * else give them what this entry would be by default. i.e. if it's a v6
254      * entry, then the label its local labelled should be carrying v6 traffic.
255      * If it's a non-EOS label entry, then there are more labels and we want
256      * a non-eos chain.
257      */
258     return (dfct);
259 }
260
261 static dpo_proto_t
262 fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
263 {
264     switch (pfx->fp_proto)
265     {
266     case FIB_PROTOCOL_IP4:
267         return (DPO_PROTO_IP4);
268     case FIB_PROTOCOL_IP6:
269         return (DPO_PROTO_IP6);
270     case FIB_PROTOCOL_MPLS:
271         return (pfx->fp_payload_proto);
272     }
273
274     ASSERT(0);
275     return (DPO_PROTO_IP4);
276 }
277
278 static void
279 fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
280                                    fib_entry_src_collect_forwarding_ctx_t *ctx)
281 {
282     load_balance_path_t *nh;
283
284     /*
285      * no extension => no out-going label for this path. that's OK
286      * in the case of an IP or EOS chain, but not for non-EOS
287      */
288     switch (ctx->fct)
289     {
290     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
291     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
292     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
293     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
294     case FIB_FORW_CHAIN_TYPE_BIER:
295         /*
296          * EOS traffic with no label to stack, we need the IP Adj
297          */
298         vec_add2(ctx->next_hops, nh, 1);
299
300         nh->path_index = path_index;
301         nh->path_weight = fib_path_get_weight(path_index);
302         fib_path_contribute_forwarding(path_index, ctx->fct, &nh->path_dpo);
303
304         break;
305     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
306         if (fib_path_is_exclusive(path_index) ||
307             fib_path_is_deag(path_index))
308         {
309             vec_add2(ctx->next_hops, nh, 1);
310
311             nh->path_index = path_index;
312             nh->path_weight = fib_path_get_weight(path_index);
313             fib_path_contribute_forwarding(path_index,
314                                            FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
315                                            &nh->path_dpo);
316         }
317         break;
318     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
319         {
320             /*
321              * no label. we need a chain based on the payload. fixup.
322              */
323             vec_add2(ctx->next_hops, nh, 1);
324
325             nh->path_index = path_index;
326             nh->path_weight = fib_path_get_weight(path_index);
327             fib_path_contribute_forwarding(path_index,
328                                            fib_entry_chain_type_fixup(ctx->fib_entry,
329                                                                       ctx->fct),
330                                            &nh->path_dpo);
331             fib_path_stack_mpls_disp(path_index,
332                                      fib_prefix_get_payload_proto(&ctx->fib_entry->fe_prefix),
333                                      &nh->path_dpo);
334
335             break;
336         }
337     case FIB_FORW_CHAIN_TYPE_ETHERNET:
338     case FIB_FORW_CHAIN_TYPE_NSH:
339         ASSERT(0);
340         break;
341     }
342 }
343
344 static fib_path_list_walk_rc_t
345 fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
346                                   fib_node_index_t path_index,
347                                   void *arg)
348 {
349     fib_entry_src_collect_forwarding_ctx_t *ctx;
350     fib_path_ext_t *path_ext;
351
352     ctx = arg;
353
354     /*
355      * if the path is not resolved, don't include it.
356      */
357     if (!fib_path_is_resolved(path_index))
358     {
359         return (FIB_PATH_LIST_WALK_CONTINUE);
360     }
361
362     if (fib_path_is_recursive_constrained(path_index))
363     {
364         ctx->n_recursive_constrained += 1;
365     }
366     if (0xffff == ctx->preference)
367     {
368         /*
369          * not set a preference yet, so the first path we encounter
370          * sets the preference we are collecting.
371          */
372         ctx->preference = fib_path_get_preference(path_index);
373     }
374     else if (ctx->preference != fib_path_get_preference(path_index))
375     {
376         /*
377          * this path does not belong to the same preference as the
378          * previous paths encountered. we are done now.
379          */
380         return (FIB_PATH_LIST_WALK_STOP);
381     }
382
383     /*
384      * get the matching path-extension for the path being visited.
385      */
386     path_ext = fib_path_ext_list_find_by_path_index(&ctx->esrc->fes_path_exts,
387                                                     path_index);
388
389     if (NULL != path_ext)
390     {
391         switch (path_ext->fpe_type)
392         {
393         case FIB_PATH_EXT_MPLS:
394             if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0]))
395             {
396                 /*
397                  * found a matching extension. stack it to obtain the forwarding
398                  * info for this path.
399                  */
400                 ctx->next_hops =
401                     fib_path_ext_stack(path_ext,
402                                        ctx->fct,
403                                        fib_entry_chain_type_fixup(ctx->fib_entry,
404                                                                   ctx->fct),
405                                        ctx->next_hops);
406             }
407             else
408             {
409                 fib_entry_src_get_path_forwarding(path_index, ctx);
410             }
411             break;
412         case FIB_PATH_EXT_ADJ:
413             if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
414             {
415                 fib_entry_src_get_path_forwarding(path_index, ctx);
416             }
417             /*
418              * else
419              *  the path does not refine the cover, meaning that
420              *  the adjacency doesdoes not match the sub-net on the link.
421              *  So this path does not contribute forwarding.
422              */
423             break;
424         }
425     }
426     else
427     {
428         fib_entry_src_get_path_forwarding(path_index, ctx);
429     }
430
431     return (FIB_PATH_LIST_WALK_CONTINUE);
432 }
433
434 void
435 fib_entry_src_mk_lb (fib_entry_t *fib_entry,
436                      const fib_entry_src_t *esrc,
437                      fib_forward_chain_type_t fct,
438                      dpo_id_t *dpo_lb)
439 {
440     dpo_proto_t lb_proto;
441
442     /*
443      * If the entry has path extensions then we construct a load-balance
444      * by stacking the extensions on the forwarding chains of the paths.
445      * Otherwise we use the load-balance of the path-list
446      */
447     fib_entry_src_collect_forwarding_ctx_t ctx = {
448         .esrc = esrc,
449         .fib_entry = fib_entry,
450         .next_hops = NULL,
451         .n_recursive_constrained = 0,
452         .fct = fct,
453         .preference = 0xffff,
454     };
455
456     /*
457      * As an optimisation we allocate the vector of next-hops to be sized
458      * equal to the maximum nuber of paths we will need, which is also the
459      * most likely number we will need, since in most cases the paths are 'up'.
460      */
461     vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
462     vec_reset_length(ctx.next_hops);
463
464     lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
465
466     fib_path_list_walk(esrc->fes_pl,
467                        fib_entry_src_collect_forwarding,
468                        &ctx);
469
470     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
471     {
472         /*
473          * the client provided the DPO that the entry should link to.
474          * all entries must link to a LB, so if it is an LB already
475          * then we can use it.
476          */
477         if ((1 == vec_len(ctx.next_hops)) &&
478             (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
479         {
480             dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
481             dpo_reset(&ctx.next_hops[0].path_dpo);
482             return;
483         }
484     }
485
486     if (!dpo_id_is_valid(dpo_lb))
487     {
488         /*
489          * first time create
490          */
491         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
492         {
493             dpo_set(dpo_lb,
494                     DPO_REPLICATE,
495                     lb_proto,
496                     MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
497         }
498         else
499         {
500             fib_protocol_t flow_hash_proto;
501             flow_hash_config_t fhc;
502
503             /*
504              * if the protocol for the LB we are building does not match that
505              * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
506              * then the fib_index is not an index that relates to the table
507              * type we need. So get the default flow-hash config instead.
508              */
509             flow_hash_proto = dpo_proto_to_fib(lb_proto);
510             if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
511             {
512                 fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
513             }
514             else
515             {
516                 fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
517                                                      flow_hash_proto);
518             }
519
520             dpo_set(dpo_lb,
521                     DPO_LOAD_BALANCE,
522                     lb_proto,
523                     load_balance_create(0, lb_proto, fhc));
524         }
525     }
526
527     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
528     {
529         /*
530          * MPLS multicast
531          */
532         replicate_multipath_update(dpo_lb, ctx.next_hops);
533     }
534     else
535     {
536         load_balance_multipath_update(dpo_lb,
537                                       ctx.next_hops,
538                                       fib_entry_calc_lb_flags(&ctx));
539         vec_free(ctx.next_hops);
540
541         /*
542          * if this entry is sourced by the uRPF-exempt source then we
543          * append the always present local0 interface (index 0) to the
544          * uRPF list so it is not empty. that way packets pass the loose check.
545          */
546         index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
547
548         if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
549                                   FIB_SOURCE_URPF_EXEMPT) ||
550              (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
551             (0 == fib_urpf_check_size(ui)))
552         {
553             /*
554              * The uRPF list we get from the path-list is shared by all
555              * other users of the list, but the uRPF exemption applies
556              * only to this prefix. So we need our own list.
557              */
558             ui = fib_urpf_list_alloc_and_lock();
559             fib_urpf_list_append(ui, 0);
560             fib_urpf_list_bake(ui);
561             load_balance_set_urpf(dpo_lb->dpoi_index, ui);
562             fib_urpf_list_unlock(ui);
563         }
564         else
565         {
566             load_balance_set_urpf(dpo_lb->dpoi_index, ui);
567         }
568         load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
569                                          fib_entry_get_flags_i(fib_entry));
570     }
571 }
572
573 void
574 fib_entry_src_action_install (fib_entry_t *fib_entry,
575                               fib_source_t source)
576 {
577     /*
578      * Install the forwarding chain for the given source into the forwarding
579      * tables
580      */
581     fib_forward_chain_type_t fct;
582     fib_entry_src_t *esrc;
583     int insert;
584
585     fct = fib_entry_get_default_chain_type(fib_entry);
586     esrc = fib_entry_src_find(fib_entry, source, NULL);
587
588     /*
589      * Every entry has its own load-balance object. All changes to the entry's
590      * forwarding result in an inplace modify of the load-balance. This means
591      * the load-balance object only needs to be added to the forwarding
592      * DB once, when it is created.
593      */
594     insert = !dpo_id_is_valid(&fib_entry->fe_lb);
595
596     fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb);
597
598     ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
599     FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
600
601     /*
602      * insert the adj into the data-plane forwarding trie
603      */
604     if (insert)
605     {
606        fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
607                                    &fib_entry->fe_prefix,
608                                    &fib_entry->fe_lb);
609     }
610
611     /*
612      * if any of the other chain types are already created they will need
613      * updating too
614      */
615     fib_entry_delegate_type_t fdt;
616     fib_entry_delegate_t *fed;
617
618     FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
619     {
620         fib_entry_src_mk_lb(fib_entry, esrc,
621                             fib_entry_delegate_type_to_chain_type(fdt),
622                             &fed->fd_dpo);
623     });
624 }
625
626 void
627 fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
628 {
629     /*
630      * uninstall the forwarding chain from the forwarding tables
631      */
632     FIB_ENTRY_DBG(fib_entry, "uninstall: %d",
633                   fib_entry->fe_adj_index);
634
635     if (dpo_id_is_valid(&fib_entry->fe_lb))
636     {
637         fib_table_fwding_dpo_remove(
638             fib_entry->fe_fib_index,
639             &fib_entry->fe_prefix,
640             &fib_entry->fe_lb);
641
642         dpo_reset(&fib_entry->fe_lb);
643     }
644 }
645
646 static void
647 fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
648 {
649     fib_node_index_t *entries = NULL;
650
651     fib_path_list_recursive_loop_detect(path_list_index, &entries);
652
653     vec_free(entries);
654 }
655
656 /*
657  * fib_entry_src_action_copy
658  *
659  * copy a source data from another entry to this one
660  */
661 fib_entry_t *
662 fib_entry_src_action_copy (fib_entry_t *fib_entry,
663                            const fib_entry_src_t *orig_src)
664 {
665     fib_entry_src_t *esrc;
666
667     esrc = fib_entry_src_find_or_create(fib_entry, orig_src->fes_src);
668
669     *esrc = *orig_src;
670     esrc->fes_ref_count = 1;
671     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_INHERITED;
672     esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
673     esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
674
675     /*
676      * the source owns a lock on the entry
677      */
678     fib_path_list_lock(esrc->fes_pl);
679     fib_entry_lock(fib_entry_get_index(fib_entry));
680
681     return (fib_entry);
682 }
683
684 /*
685  * fib_entry_src_action_update
686  *
687  * copy a source data from another entry to this one
688  */
689 static fib_entry_src_t *
690 fib_entry_src_action_update_from_cover (fib_entry_t *fib_entry,
691                                         const fib_entry_src_t *orig_src)
692 {
693     fib_entry_src_t *esrc;
694
695     esrc = fib_entry_src_find_or_create(fib_entry, orig_src->fes_src);
696
697     /*
698      * the source owns a lock on the entry
699      */
700     fib_path_list_unlock(esrc->fes_pl);
701     esrc->fes_pl = orig_src->fes_pl;
702     fib_path_list_lock(esrc->fes_pl);
703
704     return (esrc);
705 }
706
707 static fib_table_walk_rc_t
708 fib_entry_src_covered_inherit_add_i (fib_entry_t *fib_entry,
709                                      const fib_entry_src_t *cover_src)
710 {
711     fib_entry_src_t *esrc;
712
713     esrc = fib_entry_src_find(fib_entry, cover_src->fes_src, NULL);
714
715     if (cover_src == esrc)
716     {
717         return (FIB_TABLE_WALK_CONTINUE);
718     }
719
720     if (NULL != esrc)
721     {
722         /*
723          * the covered entry already has this source.
724          */
725         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
726         {
727             /*
728              * the covered source is itself a COVERED_INHERIT, i.e.
729              * it also pushes this source down the sub-tree.
730              * We consider this more specfic covered to be the owner
731              * of the sub-tree from this point down.
732              */
733             return (FIB_TABLE_WALK_SUB_TREE_STOP);
734         }
735         if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
736         {
737             /*
738              * The covered's source data has been inherited, presumably
739              * from this cover, i.e. this is a modify.
740              */
741             esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
742             fib_entry_source_change(fib_entry, esrc->fes_src, esrc->fes_src);
743         }
744         else
745         {
746             /*
747              * The covered's source was not inherited and it is also
748              * not inherting. Nevertheless, it still owns the sub-tree from 
749              * this point down.
750              */
751             return (FIB_TABLE_WALK_SUB_TREE_STOP);
752         }
753     }
754     else
755     {
756         /*
757          * The covered does not have this source - add it.
758          */
759         fib_source_t best_source;
760
761         best_source = fib_entry_get_best_source(
762             fib_entry_get_index(fib_entry));
763
764         fib_entry_src_action_copy(fib_entry, cover_src);
765         fib_entry_source_change(fib_entry, best_source, cover_src->fes_src);
766
767     }
768     return (FIB_TABLE_WALK_CONTINUE);
769 }
770
771 static fib_table_walk_rc_t
772 fib_entry_src_covered_inherit_walk_add (fib_node_index_t fei,
773                                         void *ctx)
774 {
775     return (fib_entry_src_covered_inherit_add_i(fib_entry_get(fei), ctx));
776 }
777
778 static fib_table_walk_rc_t
779 fib_entry_src_covered_inherit_walk_remove (fib_node_index_t fei,
780                                            void *ctx)
781 {
782     fib_entry_src_t *cover_src, *esrc;
783     fib_entry_t *fib_entry;
784
785     fib_entry = fib_entry_get(fei);
786
787     cover_src = ctx;
788     esrc = fib_entry_src_find(fib_entry, cover_src->fes_src, NULL);
789
790     if (cover_src == esrc)
791     {
792         return (FIB_TABLE_WALK_CONTINUE);
793     }
794
795     if (NULL != esrc)
796     {
797         /*
798          * the covered entry already has this source.
799          */
800         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
801         {
802             /*
803              * the covered source is itself a COVERED_INHERIT, i.e.
804              * it also pushes this source down the sub-tree.
805              * We consider this more specfic covered to be the owner
806              * of the sub-tree from this point down.
807              */
808             return (FIB_TABLE_WALK_SUB_TREE_STOP);
809         }
810         if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
811         {
812             /*
813              * The covered's source data has been inherited, presumably
814              * from this cover
815              */
816             fib_entry_src_flag_t remaining;
817
818             remaining = fib_entry_special_remove(fei, cover_src->fes_src);
819
820             ASSERT(FIB_ENTRY_SRC_FLAG_ADDED == remaining);
821         }
822         else
823         {
824             /*
825              * The covered's source was not inherited and it is also
826              * not inherting. Nevertheless, it still owns the sub-tree from 
827              * this point down.
828              */
829             return (FIB_TABLE_WALK_SUB_TREE_STOP);
830         }
831     }
832     else
833     {
834         /*
835          * The covered does not have this source - that's an error,
836          * since it should have inherited, but there is nothing we can do
837          * about it now.
838          */
839     }
840     return (FIB_TABLE_WALK_CONTINUE);
841 }
842
843 void
844 fib_entry_src_inherit (const fib_entry_t *cover,
845                        fib_entry_t *covered)
846 {
847     CLIB_UNUSED(fib_source_t source);
848     const fib_entry_src_t *src;
849
850     FOR_EACH_SRC_ADDED(cover, src, source,
851     ({
852         if ((src->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
853             (src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
854         {
855             fib_entry_src_covered_inherit_add_i(covered, src);
856         }
857     }))
858 }
859
860 static void
861 fib_entry_src_covered_inherit_add (fib_entry_t *fib_entry,
862                                    fib_source_t source)
863
864 {
865     fib_entry_src_t *esrc;
866
867     esrc = fib_entry_src_find(fib_entry, source, NULL);
868
869     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
870
871     if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
872         (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
873     {
874         fib_table_sub_tree_walk(fib_entry->fe_fib_index,
875                                 fib_entry->fe_prefix.fp_proto,
876                                 &fib_entry->fe_prefix,
877                                 fib_entry_src_covered_inherit_walk_add,
878                                 esrc);
879     }
880 }
881
882 static void
883 fib_entry_src_covered_inherit_remove (fib_entry_t *fib_entry,
884                                       fib_entry_src_t *esrc)
885
886 {
887     ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
888
889     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
890     {
891         fib_table_sub_tree_walk(fib_entry->fe_fib_index,
892                                 fib_entry->fe_prefix.fp_proto,
893                                 &fib_entry->fe_prefix,
894                                 fib_entry_src_covered_inherit_walk_remove,
895                                 esrc);
896     }
897 }
898
899 void
900 fib_entry_src_action_activate (fib_entry_t *fib_entry,
901                                fib_source_t source)
902
903 {
904     int houston_we_are_go_for_install;
905     fib_entry_src_t *esrc;
906
907     esrc = fib_entry_src_find(fib_entry, source, NULL);
908
909     ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
910     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
911
912     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ACTIVE;
913
914     if (NULL != fib_entry_src_vft[source].fesv_activate)
915     {
916         houston_we_are_go_for_install =
917             fib_entry_src_vft[source].fesv_activate(esrc, fib_entry);
918     }
919     else
920     {
921         /*
922          * the source is not providing an activate function, we'll assume
923          * therefore it has no objection to installing the entry
924          */
925         houston_we_are_go_for_install = !0;
926     }
927
928     /*
929      * link to the path-list provided by the source, and go check
930      * if that forms any loops in the graph.
931      */
932     fib_entry->fe_parent = esrc->fes_pl;
933     fib_entry->fe_sibling =
934         fib_path_list_child_add(fib_entry->fe_parent,
935                                 FIB_NODE_TYPE_ENTRY,
936                                 fib_entry_get_index(fib_entry));
937
938     fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
939
940     FIB_ENTRY_DBG(fib_entry, "activate: %d",
941                   fib_entry->fe_parent);
942
943     /*
944      * If this source should push its state to covered prefixs, do that now.
945      */
946     fib_entry_src_covered_inherit_add(fib_entry, source);
947
948     if (0 != houston_we_are_go_for_install)
949     {
950         fib_entry_src_action_install(fib_entry, source);
951     }
952     else
953     {
954         fib_entry_src_action_uninstall(fib_entry);
955     }
956 }
957
958 void
959 fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
960                                  fib_source_t source)
961
962 {
963     fib_node_index_t path_list_index;
964     fib_entry_src_t *esrc;
965
966     esrc = fib_entry_src_find(fib_entry, source, NULL);
967
968     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
969
970     if (NULL != fib_entry_src_vft[source].fesv_deactivate)
971     {
972         fib_entry_src_vft[source].fesv_deactivate(esrc, fib_entry);
973     }
974
975     esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_ACTIVE;
976
977     FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
978
979     /*
980      * If this source should pull its state from covered prefixs, do that now.
981      * If this source also has the INHERITED flag set then it has a cover
982      * that wants to push down forwarding. We only want the covereds to see
983      * one update.
984      */
985     fib_entry_src_covered_inherit_remove(fib_entry, esrc);
986
987     /*
988      * un-link from an old path-list. Check for any loops this will clear
989      */
990     path_list_index = fib_entry->fe_parent;
991     fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
992
993     fib_entry_recursive_loop_detect_i(path_list_index);
994
995     /*
996      * this will unlock the path-list, so it may be invalid thereafter.
997      */
998     fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
999     fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
1000 }
1001
1002 static void
1003 fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
1004                                  fib_source_t source)
1005 {
1006     fib_entry_src_t *esrc;
1007
1008     vec_foreach(esrc, fib_entry->fe_srcs)
1009     {
1010         if (NULL != fib_entry_src_vft[esrc->fes_src].fesv_fwd_update)
1011         {
1012             fib_entry_src_vft[esrc->fes_src].fesv_fwd_update(esrc,
1013                                                              fib_entry,
1014                                                              source);
1015         }
1016     }
1017 }
1018
1019 void
1020 fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
1021                                  fib_source_t source)
1022 {
1023     fib_node_index_t path_list_index;
1024     fib_entry_src_t *esrc;
1025
1026     esrc = fib_entry_src_find(fib_entry, source, NULL);
1027
1028     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
1029
1030     FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
1031                   fib_entry->fe_parent,
1032                   esrc->fes_pl);
1033
1034     if (fib_entry->fe_parent != esrc->fes_pl)
1035     {
1036         int remain_installed;
1037
1038         /*
1039          * un-link from an old path-list. Check for any loops this will clear
1040          */
1041         path_list_index = fib_entry->fe_parent;
1042         fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
1043
1044         /*
1045          * temporary lock so it doesn't get deleted when this entry is no
1046          * longer a child.
1047          */
1048         fib_path_list_lock(path_list_index);
1049
1050         /*
1051          * this entry is no longer a child. after unlinking check if any loops
1052          * were broken
1053          */
1054         fib_path_list_child_remove(path_list_index,
1055                                    fib_entry->fe_sibling);
1056
1057         fib_entry_recursive_loop_detect_i(path_list_index);
1058
1059         /*
1060          * link to the path-list provided by the source, and go check
1061          * if that forms any loops in the graph.
1062          */
1063         fib_entry->fe_parent = esrc->fes_pl;
1064         fib_entry->fe_sibling =
1065             fib_path_list_child_add(fib_entry->fe_parent,
1066                                     FIB_NODE_TYPE_ENTRY,
1067                                     fib_entry_get_index(fib_entry));
1068
1069         fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
1070         fib_path_list_unlock(path_list_index);
1071
1072         /*
1073          * call the source to reactive and get the go/no-go to remain installed
1074          */
1075         if (NULL != fib_entry_src_vft[source].fesv_reactivate)
1076         {
1077             remain_installed =
1078                 fib_entry_src_vft[source].fesv_reactivate(esrc, fib_entry);
1079         }
1080         else
1081         {
1082             remain_installed = 1;
1083         }
1084
1085         /*
1086          * If this source should push its state to covered prefixs, do that now.
1087          */
1088         fib_entry_src_covered_inherit_add(fib_entry, source);
1089
1090         if (!remain_installed)
1091         {
1092             fib_entry_src_action_uninstall(fib_entry);
1093             return;
1094         }
1095     }
1096     fib_entry_src_action_install(fib_entry, source);
1097     fib_entry_src_action_fwd_update(fib_entry, source);
1098 }
1099
1100 void
1101 fib_entry_src_action_installed (const fib_entry_t *fib_entry,
1102                                 fib_source_t source)
1103 {
1104     fib_entry_src_t *esrc;
1105
1106     esrc = fib_entry_src_find(fib_entry, source, NULL);
1107
1108     if (NULL != fib_entry_src_vft[source].fesv_installed)
1109     {
1110         fib_entry_src_vft[source].fesv_installed(esrc,
1111                                                  fib_entry);
1112     }
1113
1114     fib_entry_src_action_fwd_update(fib_entry, source);
1115 }
1116
1117 /*
1118  * fib_entry_src_action_add
1119  *
1120  * Adding a source can result in a new fib_entry being created, which
1121  * can inturn mean the pool is realloc'd and thus the entry passed as
1122  * an argument it also realloc'd
1123  * @return the original entry
1124  */
1125 fib_entry_t *
1126 fib_entry_src_action_add (fib_entry_t *fib_entry,
1127                           fib_source_t source,
1128                           fib_entry_flag_t flags,
1129                           const dpo_id_t *dpo)
1130 {
1131     fib_node_index_t fib_entry_index;
1132     fib_entry_src_t *esrc;
1133
1134     esrc = fib_entry_src_find_or_create(fib_entry, source);
1135
1136     esrc->fes_ref_count++;
1137
1138     if (1 != esrc->fes_ref_count)
1139     {
1140         /*
1141          * we only want to add the source on the 0->1 transition
1142          */
1143         return (fib_entry);
1144     }
1145
1146     esrc->fes_entry_flags = flags;
1147
1148     /*
1149      * save variable so we can recover from a fib_entry realloc.
1150      */
1151     fib_entry_index = fib_entry_get_index(fib_entry);
1152
1153     if (NULL != fib_entry_src_vft[source].fesv_add)
1154     {
1155         fib_entry_src_vft[source].fesv_add(esrc,
1156                                            fib_entry,
1157                                            flags,
1158                                            fib_entry_get_dpo_proto(fib_entry),
1159                                            dpo);
1160     }
1161
1162     fib_entry = fib_entry_get(fib_entry_index);
1163
1164     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1165
1166     fib_path_list_lock(esrc->fes_pl);
1167
1168     /*
1169      * the source owns a lock on the entry
1170      */
1171     fib_entry_lock(fib_entry_get_index(fib_entry));
1172
1173     return (fib_entry);
1174 }
1175
1176 /*
1177  * fib_entry_src_action_update
1178  *
1179  * Adding a source can result in a new fib_entry being created, which
1180  * can inturn mean the pool is realloc'd and thus the entry passed as
1181  * an argument it also realloc'd
1182  * @return the original entry
1183  */
1184 fib_entry_t *
1185 fib_entry_src_action_update (fib_entry_t *fib_entry,
1186                              fib_source_t source,
1187                              fib_entry_flag_t flags,
1188                              const dpo_id_t *dpo)
1189 {
1190     fib_node_index_t fib_entry_index, old_path_list_index;
1191     fib_entry_src_t *esrc;
1192
1193     esrc = fib_entry_src_find_or_create(fib_entry, source);
1194
1195     if (NULL == esrc)
1196     {
1197         return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
1198     }
1199
1200     old_path_list_index = esrc->fes_pl;
1201     esrc->fes_entry_flags = flags;
1202
1203     /*
1204      * save variable so we can recover from a fib_entry realloc.
1205      */
1206     fib_entry_index = fib_entry_get_index(fib_entry);
1207
1208     if (NULL != fib_entry_src_vft[source].fesv_add)
1209     {
1210         fib_entry_src_vft[source].fesv_add(esrc,
1211                                            fib_entry,
1212                                            flags,
1213                                            fib_entry_get_dpo_proto(fib_entry),
1214                                            dpo);
1215     }
1216
1217     fib_entry = fib_entry_get(fib_entry_index);
1218
1219     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
1220
1221     fib_path_list_lock(esrc->fes_pl);
1222     fib_path_list_unlock(old_path_list_index);
1223
1224     return (fib_entry);
1225 }
1226
1227 fib_entry_src_flag_t
1228 fib_entry_src_action_remove_or_update_inherit (fib_entry_t *fib_entry,
1229                                                fib_source_t source)
1230 {
1231     fib_entry_src_t *esrc;
1232
1233     esrc = fib_entry_src_find(fib_entry, source, NULL);
1234
1235     if (NULL == esrc)
1236         return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1237
1238     if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) &&
1239         (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
1240     {
1241         fib_entry_src_t *cover_src;
1242         fib_node_index_t coveri;
1243         fib_entry_t *cover;
1244
1245         /*
1246          * this source was pushing inherited state, but so is its
1247          * cover. Now that this source is going away, we need to
1248          * pull the covers forwarding and use it to update the covereds.
1249          * Go grab the path-list from the cover, rather than start a walk from
1250          * the cover, so we don't recursively update this entry.
1251          */
1252         coveri = fib_table_get_less_specific(fib_entry->fe_fib_index,
1253                                              &fib_entry->fe_prefix);
1254
1255         /*
1256          * only the default route has itself as its own cover, but the
1257          * default route cannot have inherited from something else.
1258          */
1259         ASSERT(coveri != fib_entry_get_index(fib_entry));
1260
1261         cover = fib_entry_get(coveri);
1262         cover_src = fib_entry_src_find(cover, source, NULL);
1263
1264         ASSERT(NULL != cover_src);
1265
1266         esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
1267         esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
1268
1269         /*
1270          * Now push the new state from the cover down to the covereds
1271          */
1272         fib_entry_src_covered_inherit_add(fib_entry, source);
1273
1274         return (esrc->fes_flags);
1275     }
1276     else
1277     {
1278         return (fib_entry_src_action_remove(fib_entry, source));
1279     }
1280 }
1281
1282 fib_entry_src_flag_t
1283 fib_entry_src_action_remove (fib_entry_t *fib_entry,
1284                              fib_source_t source)
1285
1286 {
1287     fib_node_index_t old_path_list;
1288     fib_entry_src_flag_t sflags;
1289     fib_entry_src_t *esrc;
1290
1291     esrc = fib_entry_src_find(fib_entry, source, NULL);
1292
1293     if (NULL == esrc)
1294         return (FIB_ENTRY_SRC_FLAG_ACTIVE);
1295
1296     esrc->fes_ref_count--;
1297     sflags = esrc->fes_flags;
1298
1299     if (0 != esrc->fes_ref_count)
1300     {
1301         /*
1302          * only remove the source on the 1->0 transisition
1303          */
1304         return (sflags);
1305     }
1306
1307     if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
1308     {
1309         fib_entry_src_action_deactivate(fib_entry, source);
1310     }
1311
1312     old_path_list = esrc->fes_pl;
1313
1314     if (NULL != fib_entry_src_vft[source].fesv_remove)
1315     {
1316         fib_entry_src_vft[source].fesv_remove(esrc);
1317     }
1318
1319     fib_path_list_unlock(old_path_list);
1320     fib_entry_unlock(fib_entry_get_index(fib_entry));
1321
1322     sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
1323     fib_entry_src_action_deinit(fib_entry, source);
1324
1325     return (sflags);
1326 }
1327
1328 /*
1329  * fib_route_attached_cross_table
1330  *
1331  * Return true the the route is attached via an interface that
1332  * is not in the same table as the route
1333  */
1334 static inline int
1335 fib_route_attached_cross_table (const fib_entry_t *fib_entry,
1336                                 const fib_route_path_t *rpath)
1337 {
1338     /*
1339      * - All zeros next-hop
1340      * - a valid interface
1341      * - entry's fib index not equeal to interface's index
1342      */
1343     if (ip46_address_is_zero(&rpath->frp_addr) &&
1344         (~0 != rpath->frp_sw_if_index) &&
1345         (fib_entry->fe_fib_index != 
1346          fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
1347                                              rpath->frp_sw_if_index)))
1348     {
1349         return (!0);
1350     }
1351     return (0);
1352 }
1353
1354 /*
1355  * Return true if the path is attached
1356  */
1357 static inline int
1358 fib_path_is_attached (const fib_route_path_t *rpath)
1359 {
1360     /*
1361      * - All zeros next-hop
1362      * - a valid interface
1363      */
1364     if (ip46_address_is_zero(&rpath->frp_addr) &&
1365         (~0 != rpath->frp_sw_if_index))
1366     {
1367         return (!0);
1368     }
1369     else if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
1370     {
1371         return (!0);
1372     }
1373     return (0);
1374 }
1375
1376 fib_path_list_flags_t
1377 fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
1378 {
1379     fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
1380
1381     if (eflags & FIB_ENTRY_FLAG_DROP)
1382     {
1383         plf |= FIB_PATH_LIST_FLAG_DROP;
1384     }
1385     if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
1386     {
1387         plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
1388     }
1389     if (eflags & FIB_ENTRY_FLAG_LOCAL)
1390     {
1391         plf |= FIB_PATH_LIST_FLAG_LOCAL;
1392     }
1393
1394     return (plf);
1395 }
1396
1397 static void
1398 fib_entry_flags_update (const fib_entry_t *fib_entry,
1399                         const fib_route_path_t *rpath,
1400                         fib_path_list_flags_t *pl_flags,
1401                         fib_entry_src_t *esrc)
1402 {
1403     if ((esrc->fes_src == FIB_SOURCE_API) ||
1404         (esrc->fes_src == FIB_SOURCE_CLI))
1405     {
1406         if (fib_path_is_attached(rpath))
1407         {
1408             esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1409         }
1410         else
1411         {
1412             esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
1413         }
1414         if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
1415         {
1416             esrc->fes_entry_flags |= FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT;
1417         }
1418     }
1419     if (fib_route_attached_cross_table(fib_entry, rpath) &&
1420         !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT))
1421     {
1422         esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
1423     }
1424     else
1425     {
1426         esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
1427     }
1428 }
1429
1430 /*
1431  * fib_entry_src_action_add
1432  *
1433  * Adding a source can result in a new fib_entry being created, which
1434  * can inturn mean the pool is realloc'd and thus the entry passed as
1435  * an argument it also realloc'd
1436  * @return the entry
1437  */
1438 fib_entry_t*
1439 fib_entry_src_action_path_add (fib_entry_t *fib_entry,
1440                                fib_source_t source,
1441                                fib_entry_flag_t flags,
1442                                const fib_route_path_t *rpath)
1443 {
1444     fib_node_index_t old_path_list, fib_entry_index;
1445     fib_path_list_flags_t pl_flags;
1446     fib_entry_src_t *esrc;
1447
1448     /*
1449      * save variable so we can recover from a fib_entry realloc.
1450      */
1451     fib_entry_index = fib_entry_get_index(fib_entry);
1452
1453     esrc = fib_entry_src_find(fib_entry, source, NULL);
1454     if (NULL == esrc)
1455     {
1456         fib_entry =
1457             fib_entry_src_action_add(fib_entry,
1458                                      source,
1459                                      flags,
1460                                      drop_dpo_get(
1461                                          fib_entry_get_dpo_proto(fib_entry)));
1462         esrc = fib_entry_src_find(fib_entry, source, NULL);
1463     }
1464
1465     /*
1466      * we are no doubt modifying a path-list. If the path-list
1467      * is shared, and hence not modifiable, then the index returned
1468      * will be for a different path-list. This FIB entry to needs
1469      * to maintain its lock appropriately.
1470      */
1471     old_path_list = esrc->fes_pl;
1472
1473     ASSERT(NULL != fib_entry_src_vft[source].fesv_path_add);
1474
1475     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1476     fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1477
1478     fib_entry_src_vft[source].fesv_path_add(esrc, fib_entry, pl_flags, rpath);
1479     fib_entry = fib_entry_get(fib_entry_index);
1480
1481     fib_path_list_lock(esrc->fes_pl);
1482     fib_path_list_unlock(old_path_list);
1483
1484     return (fib_entry);
1485 }
1486
1487 /*
1488  * fib_entry_src_action_swap
1489  *
1490  * The source is providing new paths to replace the old ones.
1491  * Adding a source can result in a new fib_entry being created, which
1492  * can inturn mean the pool is realloc'd and thus the entry passed as
1493  * an argument it also realloc'd
1494  * @return the entry
1495  */
1496 fib_entry_t*
1497 fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
1498                                 fib_source_t source,
1499                                 fib_entry_flag_t flags,                         
1500                                 const fib_route_path_t *rpaths)
1501 {
1502     fib_node_index_t old_path_list, fib_entry_index;
1503     fib_path_list_flags_t pl_flags;
1504     const fib_route_path_t *rpath;
1505     fib_entry_src_t *esrc;
1506
1507     esrc = fib_entry_src_find(fib_entry, source, NULL);
1508
1509     /*
1510      * save variable so we can recover from a fib_entry realloc.
1511      */
1512     fib_entry_index = fib_entry_get_index(fib_entry);
1513
1514     if (NULL == esrc)
1515     {
1516         fib_entry = fib_entry_src_action_add(fib_entry,
1517                                              source,
1518                                              flags,
1519                                              drop_dpo_get(
1520                                                  fib_entry_get_dpo_proto(fib_entry)));
1521         esrc = fib_entry_src_find(fib_entry, source, NULL);
1522     }
1523     else
1524     {
1525         esrc->fes_entry_flags = flags;
1526     }
1527
1528     /*
1529      * swapping paths may create a new path-list (or may use an existing shared)
1530      * but we are certainly getting a different one. This FIB entry to needs
1531      * to maintain its lock appropriately.
1532      */
1533     old_path_list = esrc->fes_pl;
1534
1535     ASSERT(NULL != fib_entry_src_vft[source].fesv_path_swap);
1536
1537     pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
1538
1539     vec_foreach(rpath, rpaths)
1540     {
1541         fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1542     }
1543
1544     fib_entry_src_vft[source].fesv_path_swap(esrc,
1545                                              fib_entry,
1546                                              pl_flags,
1547                                              rpaths);
1548
1549     fib_entry = fib_entry_get(fib_entry_index);
1550
1551     fib_path_list_lock(esrc->fes_pl);
1552     fib_path_list_unlock(old_path_list);
1553
1554     return (fib_entry);
1555 }
1556
1557 fib_entry_src_flag_t
1558 fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
1559                                   fib_source_t source,
1560                                   const fib_route_path_t *rpath)
1561 {
1562     fib_path_list_flags_t pl_flags;
1563     fib_node_index_t old_path_list;
1564     fib_entry_src_t *esrc;
1565
1566     esrc = fib_entry_src_find(fib_entry, source, NULL);
1567
1568     ASSERT(NULL != esrc);
1569     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
1570
1571     /*
1572      * we no doubt modifying a path-list. If the path-list
1573      * is shared, and hence not modifiable, then the index returned
1574      * will be for a different path-list. This FIB entry to needs
1575      * to maintain its lock appropriately.
1576      */
1577     old_path_list = esrc->fes_pl;
1578
1579     ASSERT(NULL != fib_entry_src_vft[source].fesv_path_remove);
1580
1581     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
1582     fib_entry_flags_update(fib_entry, rpath, &pl_flags, esrc);
1583
1584     fib_entry_src_vft[source].fesv_path_remove(esrc, pl_flags, rpath);
1585
1586     /*
1587      * lock the new path-list, unlock the old if it had one
1588      */
1589     fib_path_list_unlock(old_path_list);
1590
1591     if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
1592         fib_path_list_lock(esrc->fes_pl);
1593         return (FIB_ENTRY_SRC_FLAG_ADDED);
1594     }
1595     else
1596     {
1597         /*
1598          * no more paths left from this source
1599          */
1600         fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
1601         return (FIB_ENTRY_SRC_FLAG_NONE);
1602     }
1603 }
1604
1605 u8*
1606 fib_entry_src_format (fib_entry_t *fib_entry,
1607                       fib_source_t source,
1608                       u8* s)
1609 {
1610     fib_entry_src_t *esrc;
1611
1612     esrc = fib_entry_src_find(fib_entry, source, NULL);
1613
1614     if (NULL != fib_entry_src_vft[source].fesv_format)
1615     {
1616         return (fib_entry_src_vft[source].fesv_format(esrc, s));
1617     }
1618     return (s);
1619 }
1620
1621 adj_index_t
1622 fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
1623                               fib_source_t source)
1624 {
1625     fib_entry_t *fib_entry;
1626     fib_entry_src_t *esrc;
1627
1628     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1629         return (ADJ_INDEX_INVALID);
1630
1631     fib_entry = fib_entry_get(fib_entry_index);
1632     esrc = fib_entry_src_find(fib_entry, source, NULL);
1633
1634     if (NULL != esrc)
1635     {
1636         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1637         {
1638             return (fib_path_list_get_adj(
1639                         esrc->fes_pl,
1640                         fib_entry_get_default_chain_type(fib_entry)));
1641         }
1642     }
1643     return (ADJ_INDEX_INVALID);
1644 }
1645
1646 const int
1647 fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
1648                               fib_source_t source,
1649                               dpo_id_t *dpo)
1650 {
1651     fib_entry_t *fib_entry;
1652     fib_entry_src_t *esrc;
1653
1654     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
1655         return (0);
1656
1657     fib_entry = fib_entry_get(fib_entry_index);
1658     esrc = fib_entry_src_find(fib_entry, source, NULL);
1659
1660     if (NULL != esrc)
1661     {
1662         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1663         {
1664             fib_path_list_contribute_forwarding(
1665                 esrc->fes_pl,
1666                 fib_entry_get_default_chain_type(fib_entry),
1667                 FIB_PATH_LIST_FWD_FLAG_NONE,
1668                 dpo);
1669
1670             return (dpo_id_is_valid(dpo));
1671         }
1672     }
1673     return (0);
1674 }
1675
1676 u32
1677 fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
1678                                               fib_source_t source)
1679 {
1680     fib_entry_t *fib_entry;
1681     fib_entry_src_t *esrc;
1682
1683     fib_entry = fib_entry_get(entry_index);
1684
1685     esrc = fib_entry_src_find(fib_entry, source, NULL);
1686
1687     if (NULL != esrc)
1688     {
1689         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
1690         {
1691             return (fib_path_list_get_resolving_interface(esrc->fes_pl));
1692         }
1693     }
1694     return (~0);
1695 }
1696
1697 fib_entry_flag_t
1698 fib_entry_get_flags_for_source (fib_node_index_t entry_index,
1699                                 fib_source_t source)
1700 {
1701     fib_entry_t *fib_entry;
1702     fib_entry_src_t *esrc;
1703
1704     fib_entry = fib_entry_get(entry_index);
1705
1706     esrc = fib_entry_src_find(fib_entry, source, NULL);
1707
1708     if (NULL != esrc)
1709     {
1710         return (esrc->fes_entry_flags);
1711     }
1712
1713     return (FIB_ENTRY_FLAG_NONE);
1714 }
1715
1716 fib_entry_flag_t
1717 fib_entry_get_flags_i (const fib_entry_t *fib_entry)
1718 {
1719     fib_entry_flag_t flags;
1720
1721     /*
1722      * the vector of sources is deliberately arranged in priority order
1723      */
1724     if (0 == vec_len(fib_entry->fe_srcs))
1725     {
1726         flags = FIB_ENTRY_FLAG_NONE;
1727     }
1728     else
1729     {
1730         fib_entry_src_t *esrc;
1731
1732         esrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
1733         flags = esrc->fes_entry_flags;
1734     }
1735
1736     return (flags);
1737 }
1738
1739 void
1740 fib_entry_set_source_data (fib_node_index_t fib_entry_index,
1741                            fib_source_t source,
1742                            const void *data)
1743 {
1744     fib_entry_t *fib_entry;
1745     fib_entry_src_t *esrc;
1746
1747     fib_entry = fib_entry_get(fib_entry_index);
1748     esrc = fib_entry_src_find(fib_entry, source, NULL);
1749
1750     if (NULL != esrc &&
1751         NULL != fib_entry_src_vft[source].fesv_set_data)
1752     {
1753         fib_entry_src_vft[source].fesv_set_data(esrc, fib_entry, data);
1754     }
1755 }
1756
1757 const void*
1758 fib_entry_get_source_data (fib_node_index_t fib_entry_index,
1759                            fib_source_t source)
1760 {
1761     fib_entry_t *fib_entry;
1762     fib_entry_src_t *esrc;
1763
1764     fib_entry = fib_entry_get(fib_entry_index);
1765     esrc = fib_entry_src_find(fib_entry, source, NULL);
1766
1767     if (NULL != esrc &&
1768         NULL != fib_entry_src_vft[source].fesv_get_data)
1769     {
1770         return (fib_entry_src_vft[source].fesv_get_data(esrc, fib_entry));
1771     }
1772     return (NULL);
1773 }
1774
1775 void
1776 fib_entry_src_module_init (void)
1777 {
1778     fib_entry_src_rr_register();
1779     fib_entry_src_interface_register();
1780     fib_entry_src_default_route_register();
1781     fib_entry_src_special_register();
1782     fib_entry_src_api_register();
1783     fib_entry_src_adj_register();
1784     fib_entry_src_mpls_register();
1785     fib_entry_src_lisp_register();
1786 }