fib: Fix some more realloc errors
[vpp.git] / src / vnet / fib / fib_entry.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vlib/vlib.h>
17 #include <vnet/ip/format.h>
18 #include <vnet/ip/lookup.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/drop_dpo.h>
22
23 #include <vnet/fib/fib_entry.h>
24 #include <vnet/fib/fib_walk.h>
25 #include <vnet/fib/fib_entry_src.h>
26 #include <vnet/fib/fib_entry_cover.h>
27 #include <vnet/fib/fib_table.h>
28 #include <vnet/fib/fib_internal.h>
29 #include <vnet/fib/fib_attached_export.h>
30 #include <vnet/fib/fib_path_ext.h>
31 #include <vnet/fib/fib_entry_delegate.h>
32 #include <vnet/fib/fib_entry_track.h>
33
34 /*
35  * Array of strings/names for the FIB sources
36  */
37 static const char *fib_attribute_names[] = FIB_ENTRY_ATTRIBUTES;
38 static const char *fib_src_attribute_names[] = FIB_ENTRY_SRC_ATTRIBUTES;
39
40 /*
41  * Pool for all fib_entries
42  */
43 static fib_entry_t *fib_entry_pool;
44
45 /**
46  * the logger
47  */
48 vlib_log_class_t fib_entry_logger;
49
50 fib_entry_t *
51 fib_entry_get (fib_node_index_t index)
52 {
53     return (pool_elt_at_index(fib_entry_pool, index));
54 }
55
56 static fib_node_t *
57 fib_entry_get_node (fib_node_index_t index)
58 {
59     return ((fib_node_t*)fib_entry_get(index));
60 }
61
62 fib_node_index_t
63 fib_entry_get_index (const fib_entry_t * fib_entry)
64 {
65     return (fib_entry - fib_entry_pool);
66 }
67
68 fib_protocol_t
69 fib_entry_get_proto (const fib_entry_t * fib_entry)
70 {
71     return (fib_entry->fe_prefix.fp_proto);
72 }
73
74 dpo_proto_t
75 fib_entry_get_dpo_proto (const fib_entry_t * fib_entry)
76 {
77     return (fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto));
78 }
79
80 fib_forward_chain_type_t
81 fib_entry_get_default_chain_type (const fib_entry_t *fib_entry)
82 {
83     switch (fib_entry->fe_prefix.fp_proto)
84     {
85     case FIB_PROTOCOL_IP4:
86         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
87     case FIB_PROTOCOL_IP6:
88         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
89     case FIB_PROTOCOL_MPLS:
90         if (MPLS_EOS == fib_entry->fe_prefix.fp_eos)
91             return (FIB_FORW_CHAIN_TYPE_MPLS_EOS);
92         else
93             return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
94     }
95
96     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
97 }
98
99 u8 *
100 format_fib_entry_flags (u8 *s, va_list *args)
101 {
102     fib_entry_attribute_t attr;
103     fib_entry_flag_t flag = va_arg(*args, int);
104
105     FOR_EACH_FIB_ATTRIBUTE(attr) {
106         if ((1<<attr) & flag) {
107             s = format (s, "%s,", fib_attribute_names[attr]);
108         }
109     }
110
111     return (s);
112 }
113
114 u8 *
115 format_fib_entry_src_flags (u8 *s, va_list *args)
116 {
117     fib_entry_src_attribute_t sattr;
118     fib_entry_src_flag_t flag = va_arg(*args, int);
119
120     FOR_EACH_FIB_SRC_ATTRIBUTE(sattr) {
121         if ((1<<sattr) & flag) {
122             s = format (s, "%s,", fib_src_attribute_names[sattr]);
123         }
124     }
125
126     return (s);
127 }
128
129 u8 *
130 format_fib_entry (u8 * s, va_list * args)
131 {
132     fib_forward_chain_type_t fct;
133     fib_entry_t *fib_entry;
134     fib_entry_src_t *src;
135     fib_node_index_t fei;
136     fib_source_t source;
137     int level;
138
139     fei = va_arg (*args, fib_node_index_t);
140     level = va_arg (*args, int);
141     fib_entry = fib_entry_get(fei);
142
143     s = format (s, "%U", format_fib_prefix, &fib_entry->fe_prefix);
144
145     if (level >= FIB_ENTRY_FORMAT_DETAIL)
146     {
147         s = format (s, " fib:%d", fib_entry->fe_fib_index);
148         s = format (s, " index:%d", fib_entry_get_index(fib_entry));
149         s = format (s, " locks:%d", fib_entry->fe_node.fn_locks);
150
151         FOR_EACH_SRC_ADDED(fib_entry, src, source,
152         ({
153             s = format (s, "\n  %U", format_fib_source, source);
154             s = format (s, " refs:%d", src->fes_ref_count);
155             if (FIB_ENTRY_FLAG_NONE != src->fes_entry_flags) {
156                 s = format(s, " entry-flags:%U",
157                            format_fib_entry_flags, src->fes_entry_flags);
158             }
159             if (FIB_ENTRY_SRC_FLAG_NONE != src->fes_flags) {
160                 s = format(s, " src-flags:%U",
161                            format_fib_entry_src_flags, src->fes_flags);
162             }
163             s = fib_entry_src_format(fib_entry, source, s);
164             s = format (s, "\n");
165             if (FIB_NODE_INDEX_INVALID != src->fes_pl)
166             {
167                 s = fib_path_list_format(src->fes_pl, s);
168             }
169             s = format(s, "%U", format_fib_path_ext_list, &src->fes_path_exts);
170         }));
171     
172         s = format (s, "\n forwarding: ");
173     }
174     else
175     {
176         s = format (s, "\n");
177     }
178
179     fct = fib_entry_get_default_chain_type(fib_entry);
180
181     if (!dpo_id_is_valid(&fib_entry->fe_lb))
182     {
183         s = format (s, "  UNRESOLVED\n");
184         return (s);
185     }
186     else
187     {
188         s = format(s, "  %U-chain\n  %U",
189                    format_fib_forw_chain_type, fct,
190                    format_dpo_id,
191                    &fib_entry->fe_lb,
192                    2);
193         s = format(s, "\n");
194
195         if (level >= FIB_ENTRY_FORMAT_DETAIL2)
196         {
197             index_t *fedi;
198
199             s = format (s, " Delegates:\n");
200             vec_foreach(fedi, fib_entry->fe_delegates)
201             {
202                 s = format(s, "  %U\n", format_fib_entry_delegate, *fedi);
203             }
204         }
205     }
206
207     if (level >= FIB_ENTRY_FORMAT_DETAIL2)
208     {
209         s = format(s, " Children:");
210         s = fib_node_children_format(fib_entry->fe_node.fn_children, s);
211     }
212
213     return (s);
214 }
215
216 static fib_entry_t*
217 fib_entry_from_fib_node (fib_node_t *node)
218 {
219     ASSERT(FIB_NODE_TYPE_ENTRY == node->fn_type);
220     return ((fib_entry_t*)node);
221 }
222
223 static void
224 fib_entry_last_lock_gone (fib_node_t *node)
225 {
226     fib_entry_delegate_type_t fdt;
227     fib_entry_delegate_t *fed;
228     fib_entry_t *fib_entry;
229
230     fib_entry = fib_entry_from_fib_node(node);
231
232     ASSERT(!dpo_id_is_valid(&fib_entry->fe_lb));
233
234     FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
235     {
236         dpo_reset(&fed->fd_dpo);
237         fib_entry_delegate_remove(fib_entry, fdt);
238     });
239
240     FIB_ENTRY_DBG(fib_entry, "last-lock");
241
242     fib_node_deinit(&fib_entry->fe_node);
243
244     ASSERT(0 == vec_len(fib_entry->fe_delegates));
245     vec_free(fib_entry->fe_delegates);
246     vec_free(fib_entry->fe_srcs);
247     pool_put(fib_entry_pool, fib_entry);
248 }
249
250 static fib_entry_src_t*
251 fib_entry_get_best_src_i (const fib_entry_t *fib_entry)
252 {
253     fib_entry_src_t *bsrc;
254
255     /*
256      * the enum of sources is deliberately arranged in priority order
257      */
258     if (0 == vec_len(fib_entry->fe_srcs))
259     {
260         bsrc = NULL;
261     }
262     else
263     {
264         bsrc = vec_elt_at_index(fib_entry->fe_srcs, 0);
265     }
266
267     return (bsrc);
268 }
269
270 static fib_source_t
271 fib_entry_src_get_source (const fib_entry_src_t *esrc)
272 {
273     if (NULL != esrc)
274     {
275         return (esrc->fes_src);
276     }
277     return (FIB_SOURCE_INVALID);
278 }
279
280 static fib_entry_flag_t
281 fib_entry_src_get_flags (const fib_entry_src_t *esrc)
282 {
283     if (NULL != esrc)
284     {
285         return (esrc->fes_entry_flags);
286     }
287     return (FIB_ENTRY_FLAG_NONE);
288 }
289
290 fib_entry_flag_t
291 fib_entry_get_flags (fib_node_index_t fib_entry_index)
292 {
293     return (fib_entry_get_flags_i(fib_entry_get(fib_entry_index)));
294 }
295
296 /*
297  * fib_entry_back_walk_notify
298  *
299  * A back walk has reach this entry.
300  */
301 static fib_node_back_walk_rc_t
302 fib_entry_back_walk_notify (fib_node_t *node,
303                             fib_node_back_walk_ctx_t *ctx)
304 {
305     fib_entry_t *fib_entry;
306
307     fib_entry = fib_entry_from_fib_node(node);
308
309     if (FIB_NODE_BW_REASON_FLAG_EVALUATE & ctx->fnbw_reason        ||
310         FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason      ||
311         FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason        ||
312         FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason    ||
313         FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason  ||
314         FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
315     {
316         fib_entry_src_action_reactivate(fib_entry,
317                                         fib_entry_get_best_source(
318                                             fib_entry_get_index(fib_entry)));
319     }
320
321     /*
322      * all other walk types can be reclassifed to a re-evaluate to
323      * all recursive dependents.
324      * By reclassifying we ensure that should any of these walk types meet
325      * they can be merged.
326      */
327     ctx->fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
328
329     /*
330      * ... and nothing is forced sync from now on.
331      */
332     ctx->fnbw_flags &= ~FIB_NODE_BW_FLAG_FORCE_SYNC;
333
334     FIB_ENTRY_DBG(fib_entry, "bw:%U",
335                   format_fib_node_bw_reason, ctx->fnbw_reason);
336
337     /*
338      * propagate the backwalk further if we haven't already reached the
339      * maximum depth.
340      */
341     fib_walk_sync(FIB_NODE_TYPE_ENTRY,
342                   fib_entry_get_index(fib_entry),
343                   ctx);
344
345     return (FIB_NODE_BACK_WALK_CONTINUE);
346 }
347
348 static void
349 fib_entry_show_memory (void)
350 {
351     u32 n_srcs = 0, n_exts = 0;
352     fib_entry_src_t *esrc;
353     fib_entry_t *entry;
354
355     fib_show_memory_usage("Entry",
356                           pool_elts(fib_entry_pool),
357                           pool_len(fib_entry_pool),
358                           sizeof(fib_entry_t));
359
360     pool_foreach(entry, fib_entry_pool,
361     ({
362         n_srcs += vec_len(entry->fe_srcs);
363         vec_foreach(esrc, entry->fe_srcs)
364         {
365             n_exts += fib_path_ext_list_length(&esrc->fes_path_exts);
366         }
367     }));
368
369     fib_show_memory_usage("Entry Source",
370                           n_srcs, n_srcs, sizeof(fib_entry_src_t));
371     fib_show_memory_usage("Entry Path-Extensions",
372                           n_exts, n_exts,
373                           sizeof(fib_path_ext_t));
374 }
375
376 /*
377  * The FIB path-list's graph node virtual function table
378  */
379 static const fib_node_vft_t fib_entry_vft = {
380     .fnv_get = fib_entry_get_node,
381     .fnv_last_lock = fib_entry_last_lock_gone,
382     .fnv_back_walk = fib_entry_back_walk_notify,
383     .fnv_mem_show = fib_entry_show_memory,
384 };
385
386 /**
387  * @brief Contribute the set of Adjacencies that this entry forwards with
388  * to build the uRPF list of its children
389  */
390 void
391 fib_entry_contribute_urpf (fib_node_index_t entry_index,
392                            index_t urpf)
393 {
394     fib_entry_t *fib_entry;
395
396     fib_entry = fib_entry_get(entry_index);
397
398     return (fib_path_list_contribute_urpf(fib_entry->fe_parent, urpf));
399 }
400
401 /*
402  * If the client is request a chain for multicast forwarding then swap
403  * the chain type to one that can provide such transport.
404  */
405 static fib_forward_chain_type_t
406 fib_entry_chain_type_mcast_to_ucast (fib_forward_chain_type_t fct)
407 {
408     switch (fct)
409     {
410     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
411     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
412         /*
413          * we can only transport IP multicast packets if there is an
414          * LSP.
415          */
416         fct = FIB_FORW_CHAIN_TYPE_MPLS_EOS;
417         break;
418     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
419     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
420     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
421     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
422     case FIB_FORW_CHAIN_TYPE_ETHERNET:
423     case FIB_FORW_CHAIN_TYPE_NSH:
424     case FIB_FORW_CHAIN_TYPE_BIER:
425         break;
426     }
427
428     return (fct);
429 }
430
431 /*
432  * fib_entry_contribute_forwarding
433  *
434  * Get an lock the forwarding information (DPO) contributed by the FIB entry.
435  */
436 void
437 fib_entry_contribute_forwarding (fib_node_index_t fib_entry_index,
438                                  fib_forward_chain_type_t fct,
439                                  dpo_id_t *dpo)
440 {
441     fib_entry_delegate_t *fed;
442     fib_entry_t *fib_entry;
443
444     fib_entry = fib_entry_get(fib_entry_index);
445
446     /*
447      * mfib children ask for mcast chains. fix these to the appropriate ucast types.
448      */
449     fct = fib_entry_chain_type_mcast_to_ucast(fct);
450
451     if (fct == fib_entry_get_default_chain_type(fib_entry))
452     {
453         dpo_copy(dpo, &fib_entry->fe_lb);
454     }
455     else
456     {
457         fed = fib_entry_delegate_find(fib_entry,
458                                       fib_entry_chain_type_to_delegate_type(fct));
459
460         if (NULL == fed)
461         {
462             /*
463              * use a temporary DPO lest the delegate realloc in the recursive
464              * calculation.
465              */
466             dpo_id_t tmp = DPO_INVALID;
467
468             /*
469              * on-demand create eos/non-eos.
470              * There is no on-demand delete because:
471              *   - memory versus complexity & reliability:
472              *      leaving unrequired [n]eos LB arounds wastes memory, cleaning
473              *      then up on the right trigger is more code. i favour the latter.
474              */
475             fib_entry_src_mk_lb(fib_entry,
476                                 fib_entry_get_best_src_i(fib_entry),
477                                 fct,
478                                 &tmp);
479
480             fed = fib_entry_delegate_find_or_add(
481                 fib_entry,
482                 fib_entry_chain_type_to_delegate_type(fct));
483
484             dpo_copy(&fed->fd_dpo, &tmp);
485             dpo_reset(&tmp);
486         }
487
488         dpo_copy(dpo, &fed->fd_dpo);
489     }
490     /*
491      * use the drop DPO is nothing else is present
492      */
493     if (!dpo_id_is_valid(dpo))
494     {
495         dpo_copy(dpo, drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
496     }
497
498     /*
499      * don't allow the special index indicating replicate.vs.load-balance
500      * to escape to the clients
501      */
502     dpo->dpoi_index &= ~MPLS_IS_REPLICATE;
503 }
504
505 const dpo_id_t *
506 fib_entry_contribute_ip_forwarding (fib_node_index_t fib_entry_index)
507 {
508     fib_forward_chain_type_t fct;
509     fib_entry_t *fib_entry;
510
511     fib_entry = fib_entry_get(fib_entry_index);
512     fct = fib_entry_get_default_chain_type(fib_entry);
513
514     ASSERT((fct == FIB_FORW_CHAIN_TYPE_UNICAST_IP4 ||
515             fct == FIB_FORW_CHAIN_TYPE_UNICAST_IP6));
516
517     if (dpo_id_is_valid(&fib_entry->fe_lb))
518     {
519         return (&fib_entry->fe_lb);
520     }
521
522     return (drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct)));
523 }
524
525 adj_index_t
526 fib_entry_get_adj (fib_node_index_t fib_entry_index)
527 {
528     const dpo_id_t *dpo;
529
530     dpo = fib_entry_contribute_ip_forwarding(fib_entry_index);
531
532     if (dpo_id_is_valid(dpo))
533     {
534         dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
535
536         if (dpo_is_adj(dpo))
537         {
538             return (dpo->dpoi_index);
539         }
540     }
541     return (ADJ_INDEX_INVALID);
542 }
543
544 fib_node_index_t
545 fib_entry_get_path_list (fib_node_index_t fib_entry_index)
546 {
547     fib_entry_t *fib_entry;
548
549     fib_entry = fib_entry_get(fib_entry_index);
550
551     return (fib_entry->fe_parent);
552 }
553
554 u32
555 fib_entry_child_add (fib_node_index_t fib_entry_index,
556                      fib_node_type_t child_type,
557                      fib_node_index_t child_index)
558 {
559     return (fib_node_child_add(FIB_NODE_TYPE_ENTRY,
560                                fib_entry_index,
561                                child_type,
562                                child_index));
563 };
564
565 void
566 fib_entry_child_remove (fib_node_index_t fib_entry_index,
567                         u32 sibling_index)
568 {
569     fib_node_child_remove(FIB_NODE_TYPE_ENTRY,
570                           fib_entry_index,
571                           sibling_index);
572
573     if (0 == fib_node_get_n_children(FIB_NODE_TYPE_ENTRY,
574                                      fib_entry_index))
575     {
576         /*
577          * if there are no children left then there is no reason to keep
578          * the non-default forwarding chains. those chains are built only
579          * because the children want them.
580          */
581         fib_entry_delegate_type_t fdt;
582         fib_entry_delegate_t *fed;
583         fib_entry_t *fib_entry;
584
585         fib_entry = fib_entry_get(fib_entry_index);
586
587         FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
588         {
589             dpo_reset(&fed->fd_dpo);
590             fib_entry_delegate_remove(fib_entry, fdt);
591         });
592     }
593 }
594
595 static fib_entry_t *
596 fib_entry_alloc (u32 fib_index,
597                  const fib_prefix_t *prefix,
598                  fib_node_index_t *fib_entry_index)
599 {
600     fib_entry_t *fib_entry;
601     fib_prefix_t *fep;
602
603     pool_get(fib_entry_pool, fib_entry);
604     clib_memset(fib_entry, 0, sizeof(*fib_entry));
605
606     fib_node_init(&fib_entry->fe_node,
607                   FIB_NODE_TYPE_ENTRY);
608
609     fib_entry->fe_fib_index = fib_index;
610
611     /*
612      * the one time we need to update the const prefix is when
613      * the entry is first created
614      */
615     fep = (fib_prefix_t*)&(fib_entry->fe_prefix);
616     *fep = *prefix;
617
618     if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
619     {
620         fep->fp_len = 21;
621         if (MPLS_NON_EOS == fep->fp_eos)
622         {
623             fep->fp_payload_proto = DPO_PROTO_MPLS;
624         }
625         ASSERT(DPO_PROTO_NONE != fib_entry->fe_prefix.fp_payload_proto);
626     }
627
628     dpo_reset(&fib_entry->fe_lb);
629
630     *fib_entry_index = fib_entry_get_index(fib_entry);
631
632     return (fib_entry);
633 }
634
635 static fib_entry_t*
636 fib_entry_post_flag_update_actions (fib_entry_t *fib_entry,
637                                     fib_entry_flag_t old_flags)
638 {
639     fib_node_index_t fei;
640
641     /*
642      * save the index so we can recover from pool reallocs
643      */
644     fei = fib_entry_get_index(fib_entry);
645
646     /*
647      * handle changes to attached export for import entries
648      */
649     int is_import  = (FIB_ENTRY_FLAG_IMPORT & fib_entry_get_flags_i(fib_entry));
650     int was_import = (FIB_ENTRY_FLAG_IMPORT & old_flags);
651
652     if (!was_import && is_import)
653     {
654         /*
655          * transition from not exported to exported
656          */
657
658         /*
659          * there is an assumption here that the entry resolves via only
660          * one interface and that it is the cross VRF interface.
661          */
662         u32 sw_if_index = fib_path_list_get_resolving_interface(fib_entry->fe_parent);
663
664         fib_attached_export_import(fib_entry,
665                                    fib_table_get_index_for_sw_if_index(
666                                        fib_entry_get_proto(fib_entry),
667                                        sw_if_index));
668     }
669     else if (was_import && !is_import)
670     {
671         /*
672          * transition from exported to not exported
673          */
674         fib_attached_export_purge(fib_entry);
675     }
676     /*
677      * else
678      *   no change. nothing to do.
679      */
680
681     /*
682      * reload the entry address post possible pool realloc
683      */
684     fib_entry = fib_entry_get(fei);
685
686     /*
687      * handle changes to attached export for export entries
688      */
689     int is_attached  = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(fib_entry));
690     int was_attached = (FIB_ENTRY_FLAG_ATTACHED & old_flags);
691
692     if (!was_attached && is_attached)
693     {
694         /*
695          * transition to attached. time to export
696          */
697         // FIXME
698     }
699     // else FIXME
700
701     return (fib_entry);
702 }
703
704 static fib_entry_t*
705 fib_entry_post_install_actions (fib_entry_t *fib_entry,
706                                 fib_source_t source,
707                                 fib_entry_flag_t old_flags)
708 {
709     fib_entry = fib_entry_post_flag_update_actions(fib_entry,
710                                                    old_flags);
711     fib_entry = fib_entry_src_action_installed(fib_entry, source);
712
713     return (fib_entry);
714 }
715
716 fib_node_index_t
717 fib_entry_create (u32 fib_index,
718                   const fib_prefix_t *prefix,
719                   fib_source_t source,
720                   fib_entry_flag_t flags,
721                   const fib_route_path_t *paths)
722 {
723     fib_node_index_t fib_entry_index;
724     fib_entry_t *fib_entry;
725
726     ASSERT(0 < vec_len(paths));
727
728     fib_entry = fib_entry_alloc(fib_index, prefix, &fib_entry_index);
729
730     /*
731      * since this is a new entry create, we don't need to check for winning
732      * sources - there is only one.
733      */
734     fib_entry = fib_entry_src_action_add(fib_entry, source, flags,
735                                          drop_dpo_get(
736                                              fib_proto_to_dpo(
737                                                  fib_entry_get_proto(fib_entry))));
738     fib_entry_src_action_path_swap(fib_entry,
739                                    source,
740                                    flags,
741                                    paths);
742     /*
743      * handle possible realloc's by refetching the pointer
744      */
745     fib_entry = fib_entry_get(fib_entry_index);
746     fib_entry_src_action_activate(fib_entry, source);
747
748     fib_entry = fib_entry_post_install_actions(fib_entry, source,
749                                                FIB_ENTRY_FLAG_NONE);
750
751     FIB_ENTRY_DBG(fib_entry, "create");
752
753     return (fib_entry_index);
754 }
755
756 fib_node_index_t
757 fib_entry_create_special (u32 fib_index,
758                           const fib_prefix_t *prefix,
759                           fib_source_t source,
760                           fib_entry_flag_t flags,
761                           const dpo_id_t *dpo)
762 {
763     fib_node_index_t fib_entry_index;
764     fib_entry_t *fib_entry;
765
766     /*
767      * create and initialize the new enty
768      */
769     fib_entry = fib_entry_alloc(fib_index, prefix, &fib_entry_index);
770
771     /*
772      * create the path-list
773      */
774     fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
775     fib_entry_src_action_activate(fib_entry, source);
776
777     fib_entry = fib_entry_post_install_actions(fib_entry, source,
778                                                FIB_ENTRY_FLAG_NONE);
779
780     FIB_ENTRY_DBG(fib_entry, "create-special");
781
782     return (fib_entry_index);
783 }
784
785 static void
786 fib_entry_post_update_actions (fib_entry_t *fib_entry,
787                                fib_source_t source,
788                                fib_entry_flag_t old_flags)
789 {
790     /*
791      * backwalk to children to inform then of the change to forwarding.
792      */
793     fib_node_back_walk_ctx_t bw_ctx = {
794         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
795     };
796
797     fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_get_index(fib_entry), &bw_ctx);
798
799     /*
800      * then inform any covered prefixes
801      */
802     fib_entry_cover_update_notify(fib_entry);
803
804     fib_entry_post_install_actions(fib_entry, source, old_flags);
805 }
806
807 void
808 fib_entry_recalculate_forwarding (fib_node_index_t fib_entry_index)
809 {
810     fib_source_t best_source;
811     fib_entry_t *fib_entry;
812     fib_entry_src_t *bsrc;
813
814     fib_entry = fib_entry_get(fib_entry_index);
815
816     bsrc = fib_entry_get_best_src_i(fib_entry);
817     best_source = fib_entry_src_get_source(bsrc);
818
819     fib_entry_src_action_reactivate(fib_entry, best_source);
820 }
821
822 static void
823 fib_entry_source_change_w_flags (fib_entry_t *fib_entry,
824                                  fib_source_t old_source,
825                                  fib_entry_flag_t old_flags,
826                                  fib_source_t new_source)
827 {
828     switch (fib_source_cmp(new_source, old_source))
829     {
830     case FIB_SOURCE_CMP_BETTER:
831         /*
832          * we have a new winning source.
833          */
834         fib_entry_src_action_deactivate(fib_entry, old_source);
835         fib_entry_src_action_activate(fib_entry, new_source);
836         break;
837
838     case FIB_SOURCE_CMP_WORSE:
839         /*
840          * the new source loses. Re-activate the winning sources
841          * in case it is an interposer and hence relied on the losing
842          * source's path-list.
843          */
844         fib_entry_src_action_reactivate(fib_entry, old_source);
845         return;
846
847     case FIB_SOURCE_CMP_EQUAL:
848         /*
849          * the new source is one this entry already has.
850          * But the path-list was updated, which will contribute new forwarding,
851          * so install it.
852          */
853         fib_entry_src_action_reactivate(fib_entry, new_source);
854         break;
855     }
856
857     fib_entry_post_update_actions(fib_entry, new_source, old_flags);
858 }
859
860 void
861 fib_entry_source_change (fib_entry_t *fib_entry,
862                          fib_source_t old_source,
863                          fib_source_t new_source)
864 {
865     fib_entry_flag_t old_flags;
866
867     old_flags = fib_entry_get_flags_for_source(
868         fib_entry_get_index(fib_entry), old_source);
869
870     return (fib_entry_source_change_w_flags(fib_entry, old_source,
871                                             old_flags, new_source));
872 }
873
874 void
875 fib_entry_special_add (fib_node_index_t fib_entry_index,
876                        fib_source_t source,
877                        fib_entry_flag_t flags,
878                        const dpo_id_t *dpo)
879 {
880     fib_source_t best_source;
881     fib_entry_t *fib_entry;
882
883     fib_entry = fib_entry_get(fib_entry_index);
884     best_source = fib_entry_get_best_source(fib_entry_index);
885
886     fib_entry = fib_entry_src_action_add(fib_entry, source, flags, dpo);
887     fib_entry_source_change(fib_entry, best_source, source);
888     FIB_ENTRY_DBG(fib_entry, "special-add:%U", format_fib_source, source);
889 }
890
891 void
892 fib_entry_special_update (fib_node_index_t fib_entry_index,
893                           fib_source_t source,
894                           fib_entry_flag_t flags,
895                           const dpo_id_t *dpo)
896 {
897     fib_source_t best_source;
898     fib_entry_t *fib_entry;
899
900     fib_entry = fib_entry_get(fib_entry_index);
901     best_source = fib_entry_get_best_source(fib_entry_index);
902
903     fib_entry = fib_entry_src_action_update(fib_entry, source, flags, dpo);
904     fib_entry_source_change(fib_entry, best_source, source);
905
906     FIB_ENTRY_DBG(fib_entry, "special-updated:%U", format_fib_source, source);
907 }
908
909
910 void
911 fib_entry_path_add (fib_node_index_t fib_entry_index,
912                     fib_source_t source,
913                     fib_entry_flag_t flags,
914                     const fib_route_path_t *rpaths)
915 {
916     fib_source_t best_source;
917     fib_entry_t *fib_entry;
918     fib_entry_src_t *bsrc;
919
920     fib_entry = fib_entry_get(fib_entry_index);
921     ASSERT(NULL != fib_entry);
922
923     bsrc = fib_entry_get_best_src_i(fib_entry);
924     best_source = fib_entry_src_get_source(bsrc);
925     
926     fib_entry = fib_entry_src_action_path_add(fib_entry, source, flags, rpaths);
927
928     fib_entry_source_change(fib_entry, best_source, source);
929
930     FIB_ENTRY_DBG(fib_entry, "path add:%U", format_fib_source, source);
931 }
932
933 static fib_entry_src_flag_t
934 fib_entry_src_burn_only_inherited (fib_entry_t *fib_entry)
935 {
936     fib_entry_src_t *src;
937     fib_source_t source;
938     int has_only_inherited_sources = 1;
939
940     FOR_EACH_SRC_ADDED(fib_entry, src, source,
941     ({
942         if (!(src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
943         {
944             has_only_inherited_sources = 0;
945             break;
946         }
947     }));
948     if (has_only_inherited_sources)
949     {
950         FOR_EACH_SRC_ADDED(fib_entry, src, source,
951         ({
952             fib_entry_src_action_remove(fib_entry, source);
953         }));
954         return (FIB_ENTRY_SRC_FLAG_NONE);
955     }
956     else
957     {
958         return (FIB_ENTRY_SRC_FLAG_ADDED);
959     }
960 }
961
962 static fib_entry_src_flag_t
963 fib_entry_source_removed (fib_entry_t *fib_entry,
964                           fib_entry_flag_t old_flags)
965 {
966     const fib_entry_src_t *bsrc;
967     fib_source_t best_source;
968
969     /*
970      * if all that is left are inherited sources, then burn them
971      */
972     fib_entry_src_burn_only_inherited(fib_entry);
973
974     bsrc = fib_entry_get_best_src_i(fib_entry);
975     best_source = fib_entry_src_get_source(bsrc);
976
977     if (FIB_SOURCE_INVALID == best_source)
978     {
979         /*
980          * no more sources left. this entry is toast.
981          */
982         fib_entry = fib_entry_post_flag_update_actions(fib_entry, old_flags);
983         fib_entry_src_action_uninstall(fib_entry);
984
985         return (FIB_ENTRY_SRC_FLAG_NONE);
986     }
987     else
988     {
989         fib_entry_src_action_activate(fib_entry, best_source);
990     }
991
992     fib_entry_post_update_actions(fib_entry, best_source, old_flags);
993
994     /*
995      * still have sources
996      */
997     return (FIB_ENTRY_SRC_FLAG_ADDED);
998 }
999
1000 /*
1001  * fib_entry_path_remove
1002  *
1003  * remove a path from the entry.
1004  * return the fib_entry's index if it is still present, INVALID otherwise.
1005  */
1006 fib_entry_src_flag_t
1007 fib_entry_path_remove (fib_node_index_t fib_entry_index,
1008                        fib_source_t source,
1009                        const fib_route_path_t *rpaths)
1010 {
1011     fib_entry_src_flag_t sflag;
1012     fib_source_t best_source;
1013     fib_entry_flag_t bflags;
1014     fib_entry_t *fib_entry;
1015     fib_entry_src_t *bsrc;
1016
1017     fib_entry = fib_entry_get(fib_entry_index);
1018     ASSERT(NULL != fib_entry);
1019
1020     bsrc = fib_entry_get_best_src_i(fib_entry);
1021     best_source = fib_entry_src_get_source(bsrc);
1022     bflags = fib_entry_src_get_flags(bsrc);
1023
1024     sflag = fib_entry_src_action_path_remove(fib_entry, source, rpaths);
1025
1026     FIB_ENTRY_DBG(fib_entry, "path remove:%U", format_fib_source, source);
1027
1028     /*
1029      * if the path list for the source passed is invalid,
1030      * then we need to create a new one. else we are updating
1031      * an existing.
1032      */
1033     switch (fib_source_cmp(source, best_source))
1034     {
1035     case FIB_SOURCE_CMP_BETTER:
1036         /*
1037          * Que! removing a path from a source that is better than the
1038          * one this entry is using.
1039          */
1040         ASSERT(0);
1041         break;
1042     case FIB_SOURCE_CMP_WORSE:
1043         /*
1044          * the source is not the best. no need to update forwarding
1045          */
1046         if (FIB_ENTRY_SRC_FLAG_ADDED & sflag)
1047         {
1048             /*
1049              * the source being removed still has paths
1050              */
1051             return (FIB_ENTRY_SRC_FLAG_ADDED);
1052         }
1053         else
1054         {
1055             /*
1056              * that was the last path from this source, check if those
1057              * that remain are non-inherited
1058              */
1059             return (fib_entry_src_burn_only_inherited(fib_entry));
1060         }
1061         break;
1062     case FIB_SOURCE_CMP_EQUAL:
1063         /*
1064          * removing a path from the path-list we were using.
1065          */
1066         if (!(FIB_ENTRY_SRC_FLAG_ADDED & sflag))
1067         {
1068             /*
1069              * the last path from the source was removed.
1070              * fallback to lower source
1071              */
1072             return (fib_entry_source_removed(fib_entry, bflags));
1073         }
1074         else
1075         {
1076             /*
1077              * re-install the new forwarding information
1078              */
1079             fib_entry_src_action_reactivate(fib_entry, source);
1080         }
1081         break;
1082     }
1083
1084     fib_entry_post_update_actions(fib_entry, source, bflags);
1085
1086     /*
1087      * still have sources
1088      */
1089     return (FIB_ENTRY_SRC_FLAG_ADDED);
1090 }
1091
1092 /*
1093  * fib_entry_special_remove
1094  *
1095  * remove a special source from the entry.
1096  * return the fib_entry's index if it is still present, INVALID otherwise.
1097  */
1098 fib_entry_src_flag_t
1099 fib_entry_special_remove (fib_node_index_t fib_entry_index,
1100                           fib_source_t source)
1101 {
1102     fib_entry_src_flag_t sflag;
1103     fib_source_t best_source;
1104     fib_entry_flag_t bflags;
1105     fib_entry_t *fib_entry;
1106     fib_entry_src_t *bsrc;
1107
1108     fib_entry = fib_entry_get(fib_entry_index);
1109     ASSERT(NULL != fib_entry);
1110
1111     bsrc = fib_entry_get_best_src_i(fib_entry);
1112     best_source = fib_entry_src_get_source(bsrc);
1113     bflags = fib_entry_src_get_flags(bsrc);
1114
1115     FIB_ENTRY_DBG(fib_entry, "special remove:%U", format_fib_source, source);
1116
1117     sflag = fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
1118
1119     /*
1120      * if the path list for the source passed is invalid,
1121      * then we need to create a new one. else we are updating
1122      * an existing.
1123      */
1124     switch (fib_source_cmp(source, best_source))
1125     {
1126     case FIB_SOURCE_CMP_BETTER:
1127         /*
1128          * Que! removing a path from a source that is better than the
1129          * one this entry is using. This can only mean it is a source
1130          * this prefix does not have.
1131          */
1132         return (FIB_ENTRY_SRC_FLAG_ADDED);
1133
1134     case FIB_SOURCE_CMP_WORSE:
1135         /*
1136          * the source is not the best. no need to update forwarding
1137          */
1138         if (FIB_ENTRY_SRC_FLAG_ADDED & sflag)
1139         {
1140             /*
1141              * the source being removed still has paths
1142              */
1143             return (FIB_ENTRY_SRC_FLAG_ADDED);
1144         }
1145         else
1146         {
1147             /*
1148              * that was the last path from this source, check if those
1149              * that remain are non-inherited
1150              */
1151             if (FIB_ENTRY_SRC_FLAG_NONE == fib_entry_src_burn_only_inherited(fib_entry))
1152             {
1153                 /*
1154                  * no more sources left. this entry is toast.
1155                  */
1156                 fib_entry = fib_entry_post_flag_update_actions(fib_entry, bflags);
1157                 fib_entry_src_action_uninstall(fib_entry);
1158                 return (FIB_ENTRY_SRC_FLAG_NONE);
1159             }
1160
1161             /*
1162              * reactivate the best source so the interposer gets restacked
1163              */
1164             fib_entry_src_action_reactivate(fib_entry, best_source);
1165
1166             return (FIB_ENTRY_SRC_FLAG_ADDED);
1167         }
1168         break;
1169
1170     case FIB_SOURCE_CMP_EQUAL:
1171         if (!(FIB_ENTRY_SRC_FLAG_ADDED & sflag))
1172         {
1173             /*
1174              * the source was removed. use the next best.
1175              */
1176             return (fib_entry_source_removed(fib_entry, bflags));
1177         }
1178         else
1179         {
1180             /*
1181              * re-install the new forwarding information
1182              */
1183             fib_entry_src_action_reactivate(fib_entry, source);
1184         }
1185         break;
1186     }
1187
1188     fib_entry_post_update_actions(fib_entry, source, bflags);
1189
1190     /*
1191      * still have sources
1192      */
1193     return (FIB_ENTRY_SRC_FLAG_ADDED);
1194 }
1195
1196 /**
1197  * fib_entry_inherit
1198  *
1199  * If the source on the cover is inheriting then push this source
1200  * down to the covered.
1201  */
1202 void
1203 fib_entry_inherit (fib_node_index_t cover,
1204                    fib_node_index_t covered)
1205 {
1206     fib_entry_src_inherit(fib_entry_get(cover),
1207                           fib_entry_get(covered));
1208 }
1209
1210 /**
1211  * fib_entry_delete
1212  *
1213  * The source is withdrawing all the paths it provided
1214  */
1215 fib_entry_src_flag_t
1216 fib_entry_delete (fib_node_index_t fib_entry_index,
1217                   fib_source_t source)
1218 {
1219     return (fib_entry_special_remove(fib_entry_index, source));
1220 }
1221
1222 /**
1223  * fib_entry_update
1224  *
1225  * The source has provided a new set of paths that will replace the old.
1226  */
1227 void
1228 fib_entry_update (fib_node_index_t fib_entry_index,
1229                   fib_source_t source,
1230                   fib_entry_flag_t flags,
1231                   const fib_route_path_t *paths)
1232 {
1233     fib_source_t best_source;
1234     fib_entry_flag_t bflags;
1235     fib_entry_t *fib_entry;
1236     fib_entry_src_t *bsrc;
1237
1238     fib_entry = fib_entry_get(fib_entry_index);
1239     ASSERT(NULL != fib_entry);
1240
1241     bsrc = fib_entry_get_best_src_i(fib_entry);
1242     best_source = fib_entry_src_get_source(bsrc);
1243     bflags = fib_entry_get_flags_i(fib_entry);
1244
1245     fib_entry = fib_entry_src_action_path_swap(fib_entry,
1246                                                source,
1247                                                flags,
1248                                                paths);
1249
1250     fib_entry_source_change_w_flags(fib_entry, best_source, bflags, source);
1251     FIB_ENTRY_DBG(fib_entry, "update");
1252 }
1253
1254
1255 /*
1256  * fib_entry_cover_changed
1257  *
1258  * this entry is tracking its cover and that cover has changed.
1259  */
1260 void
1261 fib_entry_cover_changed (fib_node_index_t fib_entry_index)
1262 {
1263     fib_entry_src_cover_res_t res = {
1264         .install = !0,
1265         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
1266     };
1267     CLIB_UNUSED(fib_source_t source);
1268     fib_source_t best_source;
1269     fib_entry_flag_t bflags;
1270     fib_entry_t *fib_entry;
1271     fib_entry_src_t *esrc;
1272     u32 index;
1273
1274     bflags = FIB_ENTRY_FLAG_NONE;
1275     best_source = FIB_SOURCE_FIRST;
1276     fib_entry = fib_entry_get(fib_entry_index);
1277
1278     fib_attached_export_cover_change(fib_entry);
1279
1280     /*
1281      * propagate the notification to each of the added sources
1282      */
1283     index = 0;
1284     FOR_EACH_SRC_ADDED(fib_entry, esrc, source,
1285     ({
1286         if (0 == index)
1287         {
1288             /*
1289              * only the best source gets to set the back walk flags
1290              */
1291             res = fib_entry_src_action_cover_change(fib_entry, esrc);
1292             bflags = fib_entry_src_get_flags(esrc);
1293             best_source = fib_entry_src_get_source(esrc);
1294         }
1295         else
1296         {
1297             fib_entry_src_action_cover_change(fib_entry, esrc);
1298         }
1299         index++;
1300     }));
1301
1302     if (res.install)
1303     {
1304         fib_entry_src_action_reactivate(fib_entry,
1305                                         fib_entry_src_get_source(
1306                                             fib_entry_get_best_src_i(fib_entry)));
1307         fib_entry = fib_entry_post_install_actions(fib_entry,
1308                                                    best_source,
1309                                                    bflags);
1310     }
1311     else
1312     {
1313         fib_entry_src_action_uninstall(fib_entry);
1314     }
1315
1316     if (FIB_NODE_BW_REASON_FLAG_NONE != res.bw_reason)
1317     {
1318         /*
1319          * time for walkies fido.
1320          */
1321         fib_node_back_walk_ctx_t bw_ctx = {
1322             .fnbw_reason = res.bw_reason,
1323         };
1324
1325         fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_index, &bw_ctx);
1326     }
1327     FIB_ENTRY_DBG(fib_entry, "cover-changed");
1328 }
1329
1330 /*
1331  * fib_entry_cover_updated
1332  *
1333  * this entry is tracking its cover and that cover has been updated
1334  * (i.e. its forwarding information has changed).
1335  */
1336 void
1337 fib_entry_cover_updated (fib_node_index_t fib_entry_index)
1338 {
1339     fib_entry_src_cover_res_t res = {
1340         .install = !0,
1341         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
1342     };
1343     CLIB_UNUSED(fib_source_t source);
1344     fib_source_t best_source;
1345     fib_entry_flag_t bflags;
1346     fib_entry_t *fib_entry;
1347     fib_entry_src_t *esrc;
1348     u32 index;
1349
1350     bflags = FIB_ENTRY_FLAG_NONE;
1351     best_source = FIB_SOURCE_FIRST;
1352     fib_entry = fib_entry_get(fib_entry_index);
1353
1354     fib_attached_export_cover_update(fib_entry);
1355
1356     /*
1357      * propagate the notification to each of the added sources
1358      */
1359     index = 0;
1360     FOR_EACH_SRC_ADDED(fib_entry, esrc, source,
1361     ({
1362         if (0 == index)
1363         {
1364             /*
1365              * only the best source gets to set the back walk flags
1366              */
1367             res = fib_entry_src_action_cover_update(fib_entry, esrc);
1368             bflags = fib_entry_src_get_flags(esrc);
1369             best_source = fib_entry_src_get_source(esrc);
1370         }
1371         else
1372         {
1373             fib_entry_src_action_cover_update(fib_entry, esrc);
1374         }
1375         index++;
1376     }));
1377
1378     if (res.install)
1379     {
1380         fib_entry_src_action_reactivate(fib_entry,
1381                                         fib_entry_src_get_source(
1382                                             fib_entry_get_best_src_i(fib_entry)));
1383         fib_entry = fib_entry_post_install_actions(fib_entry,
1384                                                    best_source,
1385                                                    bflags);
1386     }
1387     else
1388     {
1389         fib_entry_src_action_uninstall(fib_entry);
1390     }
1391
1392     if (FIB_NODE_BW_REASON_FLAG_NONE != res.bw_reason)
1393     {
1394         /*
1395          * time for walkies fido.
1396          */
1397         fib_node_back_walk_ctx_t bw_ctx = {
1398             .fnbw_reason = res.bw_reason,
1399         };
1400
1401         fib_walk_sync(FIB_NODE_TYPE_ENTRY, fib_entry_index, &bw_ctx);
1402     }
1403     FIB_ENTRY_DBG(fib_entry, "cover-updated");
1404 }
1405
1406 int
1407 fib_entry_recursive_loop_detect (fib_node_index_t entry_index,
1408                                  fib_node_index_t **entry_indicies)
1409 {
1410     fib_entry_t *fib_entry;
1411     int was_looped, is_looped;
1412
1413     fib_entry = fib_entry_get(entry_index);
1414
1415     if (FIB_NODE_INDEX_INVALID != fib_entry->fe_parent)
1416     {
1417         fib_node_index_t *entries = *entry_indicies;
1418
1419         vec_add1(entries, entry_index);
1420         was_looped = fib_path_list_is_looped(fib_entry->fe_parent);
1421         is_looped = fib_path_list_recursive_loop_detect(fib_entry->fe_parent,
1422                                                         &entries);
1423
1424         *entry_indicies = entries;
1425
1426         if (!!was_looped != !!is_looped)
1427         {
1428             /*
1429              * re-evaluate all the entry's forwarding
1430              * NOTE: this is an inplace modify
1431              */
1432             fib_entry_delegate_type_t fdt;
1433             fib_entry_delegate_t *fed;
1434
1435             FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
1436             {
1437                 fib_entry_src_mk_lb(fib_entry,
1438                                     fib_entry_get_best_src_i(fib_entry),
1439                                     fib_entry_delegate_type_to_chain_type(fdt),
1440                                     &fed->fd_dpo);
1441             });
1442         }
1443     }
1444     else
1445     {
1446         /*
1447          * the entry is currently not linked to a path-list. this happens
1448          * when it is this entry that is re-linking path-lists and has thus
1449          * broken the loop
1450          */
1451         is_looped = 0;
1452     }
1453
1454     return (is_looped);
1455 }
1456
1457 u32
1458 fib_entry_get_resolving_interface (fib_node_index_t entry_index)
1459 {
1460     fib_entry_t *fib_entry;
1461
1462     fib_entry = fib_entry_get(entry_index);
1463
1464     return (fib_path_list_get_resolving_interface(fib_entry->fe_parent));
1465 }
1466
1467 fib_source_t
1468 fib_entry_get_best_source (fib_node_index_t entry_index)
1469 {
1470     fib_entry_t *fib_entry;
1471     fib_entry_src_t *bsrc;
1472
1473     fib_entry = fib_entry_get(entry_index);
1474
1475     bsrc = fib_entry_get_best_src_i(fib_entry);
1476     return (fib_entry_src_get_source(bsrc));
1477 }
1478
1479 /**
1480  * Return !0 is the entry represents a host prefix
1481  */
1482 int
1483 fib_entry_is_host (fib_node_index_t fib_entry_index)
1484 {
1485     return (fib_prefix_is_host(fib_entry_get_prefix(fib_entry_index)));
1486 }
1487
1488 /**
1489  * Return !0 is the entry is resolved, i.e. will return a valid forwarding
1490  * chain
1491  */
1492 int
1493 fib_entry_is_resolved (fib_node_index_t fib_entry_index)
1494 {
1495     fib_entry_delegate_t *fed;
1496     fib_entry_t *fib_entry;
1497
1498     fib_entry = fib_entry_get(fib_entry_index);
1499
1500     fed = fib_entry_delegate_find(fib_entry, FIB_ENTRY_DELEGATE_BFD);
1501
1502     if (NULL == fed)
1503     {
1504         /*
1505          * no BFD tracking - consider it resolved.
1506          */
1507         return (!0);
1508     }
1509     else
1510     {
1511         /*
1512          * defer to the state of the BFD tracking
1513          */
1514         return (FIB_BFD_STATE_UP == fed->fd_bfd_state);
1515     }
1516 }
1517
1518 void
1519 fib_entry_set_flow_hash_config (fib_node_index_t fib_entry_index,
1520                                 flow_hash_config_t hash_config)
1521 {
1522     fib_entry_t *fib_entry;
1523
1524     fib_entry = fib_entry_get(fib_entry_index);
1525
1526     /*
1527      * pass the hash-config on to the load-balance object where it is cached.
1528      * we can ignore LBs in the delegate chains, since they will not be of the
1529      * correct protocol type (i.e. they are not IP)
1530      * There's no way, nor need, to change the hash config for MPLS.
1531      */
1532     if (dpo_id_is_valid(&fib_entry->fe_lb))
1533     {
1534         load_balance_t *lb;
1535
1536         ASSERT(DPO_LOAD_BALANCE == fib_entry->fe_lb.dpoi_type);
1537
1538         lb = load_balance_get(fib_entry->fe_lb.dpoi_index);
1539
1540         /*
1541          * atomic update for packets in flight
1542          */
1543         lb->lb_hash_config = hash_config;
1544     }
1545 }
1546
1547 u32
1548 fib_entry_get_stats_index (fib_node_index_t fib_entry_index)
1549 {
1550     fib_entry_t *fib_entry;
1551
1552     fib_entry = fib_entry_get(fib_entry_index);
1553
1554     return (fib_entry->fe_lb.dpoi_index);
1555 }
1556
1557 static int
1558 fib_ip4_address_compare (const ip4_address_t * a1,
1559                          const ip4_address_t * a2)
1560 {
1561     /*
1562      * IP addresses are unsigned ints. the return value here needs to be signed
1563      * a simple subtraction won't cut it.
1564      * If the addresses are the same, the sort order is undefined, so phoey.
1565      */
1566     return ((clib_net_to_host_u32(a1->data_u32) >
1567              clib_net_to_host_u32(a2->data_u32) ) ?
1568             1 : -1);
1569 }
1570
1571 static int
1572 fib_ip6_address_compare (const ip6_address_t * a1,
1573                          const ip6_address_t * a2)
1574 {
1575   int i;
1576   for (i = 0; i < ARRAY_LEN (a1->as_u16); i++)
1577   {
1578       int cmp = (clib_net_to_host_u16 (a1->as_u16[i]) -
1579                  clib_net_to_host_u16 (a2->as_u16[i]));
1580       if (cmp != 0)
1581           return cmp;
1582   }
1583   return 0;
1584 }
1585
1586 static int
1587 fib_entry_cmp (fib_node_index_t fib_entry_index1,
1588                fib_node_index_t fib_entry_index2)
1589 {
1590     fib_entry_t *fib_entry1, *fib_entry2;
1591     int cmp = 0;
1592
1593     fib_entry1 = fib_entry_get(fib_entry_index1);
1594     fib_entry2 = fib_entry_get(fib_entry_index2);
1595
1596     switch (fib_entry1->fe_prefix.fp_proto)
1597     {
1598     case FIB_PROTOCOL_IP4:
1599         cmp = fib_ip4_address_compare(&fib_entry1->fe_prefix.fp_addr.ip4,
1600                                       &fib_entry2->fe_prefix.fp_addr.ip4);
1601         break;
1602     case FIB_PROTOCOL_IP6:
1603         cmp = fib_ip6_address_compare(&fib_entry1->fe_prefix.fp_addr.ip6,
1604                                       &fib_entry2->fe_prefix.fp_addr.ip6);
1605         break;
1606     case FIB_PROTOCOL_MPLS:
1607         cmp = (fib_entry1->fe_prefix.fp_label - fib_entry2->fe_prefix.fp_label);
1608
1609         if (0 == cmp)
1610         {
1611             cmp = (fib_entry1->fe_prefix.fp_eos - fib_entry2->fe_prefix.fp_eos);
1612         }
1613         break;
1614     }
1615
1616     if (0 == cmp) {
1617         cmp = (fib_entry1->fe_prefix.fp_len - fib_entry2->fe_prefix.fp_len);
1618     }
1619     return (cmp);   
1620 }
1621
1622 int
1623 fib_entry_cmp_for_sort (void *i1, void *i2)
1624 {
1625     fib_node_index_t *fib_entry_index1 = i1, *fib_entry_index2 = i2;
1626
1627     return (fib_entry_cmp(*fib_entry_index1,
1628                           *fib_entry_index2));
1629 }
1630
1631 void
1632 fib_entry_lock (fib_node_index_t fib_entry_index)
1633 {
1634     fib_entry_t *fib_entry;
1635
1636     fib_entry = fib_entry_get(fib_entry_index);
1637
1638     fib_node_lock(&fib_entry->fe_node);
1639 }
1640
1641 void
1642 fib_entry_unlock (fib_node_index_t fib_entry_index)
1643 {
1644     fib_entry_t *fib_entry;
1645
1646     fib_entry = fib_entry_get(fib_entry_index);
1647
1648     fib_node_unlock(&fib_entry->fe_node);
1649 }
1650
1651 void
1652 fib_entry_module_init (void)
1653 {
1654     fib_node_register_type(FIB_NODE_TYPE_ENTRY, &fib_entry_vft);
1655     fib_entry_logger = vlib_log_register_class("fib", "entry");
1656
1657     fib_entry_track_module_init();
1658 }
1659
1660 fib_route_path_t *
1661 fib_entry_encode (fib_node_index_t fib_entry_index)
1662 {
1663     fib_path_ext_list_t *ext_list;
1664     fib_path_encode_ctx_t ctx = {
1665         .rpaths = NULL,
1666     };
1667     fib_entry_t *fib_entry;
1668     fib_entry_src_t *bsrc;
1669
1670     ext_list = NULL;
1671     fib_entry = fib_entry_get(fib_entry_index);
1672     bsrc = fib_entry_get_best_src_i(fib_entry);
1673
1674     if (bsrc)
1675     {
1676         ext_list = &bsrc->fes_path_exts;
1677     }
1678
1679     if (FIB_NODE_INDEX_INVALID != fib_entry->fe_parent)
1680     {
1681         fib_path_list_walk_w_ext(fib_entry->fe_parent,
1682                                  ext_list,
1683                                  fib_path_encode,
1684                                  &ctx);
1685     }
1686
1687     return (ctx.rpaths);
1688 }
1689
1690 const fib_prefix_t *
1691 fib_entry_get_prefix (fib_node_index_t fib_entry_index)
1692 {
1693     fib_entry_t *fib_entry;
1694
1695     fib_entry = fib_entry_get(fib_entry_index);
1696
1697     return (&fib_entry->fe_prefix);
1698 }
1699
1700 u32
1701 fib_entry_get_fib_index (fib_node_index_t fib_entry_index)
1702 {
1703     fib_entry_t *fib_entry;
1704
1705     fib_entry = fib_entry_get(fib_entry_index);
1706
1707     return (fib_entry->fe_fib_index);
1708 }
1709
1710 u32
1711 fib_entry_pool_size (void)
1712 {
1713     return (pool_elts(fib_entry_pool));
1714 }
1715
1716 #ifdef CLIB_DEBUG
1717 void
1718 fib_table_assert_empty (const fib_table_t *fib_table)
1719 {
1720     fib_node_index_t *fei, *feis = NULL;
1721     fib_entry_t *fib_entry;
1722
1723     pool_foreach (fib_entry, fib_entry_pool,
1724     ({
1725         if (fib_entry->fe_fib_index == fib_table->ft_index)
1726             vec_add1 (feis, fib_entry_get_index(fib_entry));
1727     }));
1728
1729     if (vec_len(feis))
1730     {
1731         vec_foreach (fei, feis)
1732             clib_error ("%U", format_fib_entry, *fei, FIB_ENTRY_FORMAT_DETAIL);
1733     }
1734
1735     ASSERT(0);
1736 }
1737 #endif
1738
1739 static clib_error_t *
1740 show_fib_entry_command (vlib_main_t * vm,
1741                         unformat_input_t * input,
1742                         vlib_cli_command_t * cmd)
1743 {
1744     fib_node_index_t fei;
1745
1746     if (unformat (input, "%d", &fei))
1747     {
1748         /*
1749          * show one in detail
1750          */
1751         if (!pool_is_free_index(fib_entry_pool, fei))
1752         {
1753             vlib_cli_output (vm, "%d@%U",
1754                              fei,
1755                              format_fib_entry, fei,
1756                              FIB_ENTRY_FORMAT_DETAIL2);
1757         }
1758         else
1759         {
1760             vlib_cli_output (vm, "entry %d invalid", fei);
1761         }
1762     }
1763     else
1764     {
1765         /*
1766          * show all
1767          */
1768         vlib_cli_output (vm, "FIB Entries:");
1769         pool_foreach_index(fei, fib_entry_pool,
1770         ({
1771             vlib_cli_output (vm, "%d@%U",
1772                              fei,
1773                              format_fib_entry, fei,
1774                              FIB_ENTRY_FORMAT_BRIEF);
1775         }));
1776     }
1777
1778     return (NULL);
1779 }
1780
1781 VLIB_CLI_COMMAND (show_fib_entry, static) = {
1782   .path = "show fib entry",
1783   .function = show_fib_entry_command,
1784   .short_help = "show fib entry",
1785 };