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