FIB Memory Usage Diagnostics
[vpp.git] / vnet / vnet / fib / fib_path.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/vnet.h>
18 #include <vnet/ip/format.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/dpo/drop_dpo.h>
21 #include <vnet/dpo/receive_dpo.h>
22 #include <vnet/dpo/load_balance_map.h>
23 #include <vnet/dpo/lookup_dpo.h>
24
25 #include <vnet/adj/adj.h>
26
27 #include "fib_path.h"
28 #include "fib_node.h"
29 #include "fib_table.h"
30 #include "fib_entry.h"
31 #include "fib_path_list.h"
32 #include "fib_internal.h"
33
34 /**
35  * Enurmeration of path types
36  */
37 typedef enum fib_path_type_t_ {
38     /**
39      * Marker. Add new types after this one.
40      */
41     FIB_PATH_TYPE_FIRST = 0,
42     /**
43      * Attached-nexthop. An interface and a nexthop are known.
44      */
45     FIB_PATH_TYPE_ATTACHED_NEXT_HOP = FIB_PATH_TYPE_FIRST,
46     /**
47      * attached. Only the interface is known.
48      */
49     FIB_PATH_TYPE_ATTACHED,
50     /**
51      * recursive. Only the next-hop is known.
52      */
53     FIB_PATH_TYPE_RECURSIVE,
54     /**
55      * special. nothing is known. so we drop.
56      */
57     FIB_PATH_TYPE_SPECIAL,
58     /**
59      * exclusive. user provided adj.
60      */
61     FIB_PATH_TYPE_EXCLUSIVE,
62     /**
63      * deag. Link to a lookup adj in the next table
64      */
65     FIB_PATH_TYPE_DEAG,
66     /**
67      * receive. it's for-us.
68      */
69     FIB_PATH_TYPE_RECEIVE,
70     /**
71      * Marker. Add new types before this one, then update it.
72      */
73     FIB_PATH_TYPE_LAST = FIB_PATH_TYPE_RECEIVE,
74 } __attribute__ ((packed)) fib_path_type_t;
75
76 /**
77  * The maximum number of path_types
78  */
79 #define FIB_PATH_TYPE_MAX (FIB_PATH_TYPE_LAST + 1)
80
81 #define FIB_PATH_TYPES {                                        \
82     [FIB_PATH_TYPE_ATTACHED_NEXT_HOP] = "attached-nexthop",     \
83     [FIB_PATH_TYPE_ATTACHED]          = "attached",             \
84     [FIB_PATH_TYPE_RECURSIVE]         = "recursive",            \
85     [FIB_PATH_TYPE_SPECIAL]           = "special",              \
86     [FIB_PATH_TYPE_EXCLUSIVE]         = "exclusive",            \
87     [FIB_PATH_TYPE_DEAG]              = "deag",                 \
88     [FIB_PATH_TYPE_RECEIVE]           = "receive",              \
89 }
90
91 #define FOR_EACH_FIB_PATH_TYPE(_item) \
92     for (_item = FIB_PATH_TYPE_FIRST; _item <= FIB_PATH_TYPE_LAST; _item++)
93
94 /**
95  * Enurmeration of path operational (i.e. derived) attributes
96  */
97 typedef enum fib_path_oper_attribute_t_ {
98     /**
99      * Marker. Add new types after this one.
100      */
101     FIB_PATH_OPER_ATTRIBUTE_FIRST = 0,
102     /**
103      * The path forms part of a recursive loop.
104      */
105     FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP = FIB_PATH_OPER_ATTRIBUTE_FIRST,
106     /**
107      * The path is resolved
108      */
109     FIB_PATH_OPER_ATTRIBUTE_RESOLVED,
110     /**
111      * The path has become a permanent drop.
112      */
113     FIB_PATH_OPER_ATTRIBUTE_DROP,
114     /**
115      * Marker. Add new types before this one, then update it.
116      */
117     FIB_PATH_OPER_ATTRIBUTE_LAST = FIB_PATH_OPER_ATTRIBUTE_DROP,
118 } __attribute__ ((packed)) fib_path_oper_attribute_t;
119
120 /**
121  * The maximum number of path operational attributes
122  */
123 #define FIB_PATH_OPER_ATTRIBUTE_MAX (FIB_PATH_OPER_ATTRIBUTE_LAST + 1)
124
125 #define FIB_PATH_OPER_ATTRIBUTES {                                      \
126     [FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP] = "recursive-loop",        \
127     [FIB_PATH_OPER_ATTRIBUTE_RESOLVED]       = "resolved",              \
128     [FIB_PATH_OPER_ATTRIBUTE_DROP]           = "drop",                  \
129 }
130
131 #define FOR_EACH_FIB_PATH_OPER_ATTRIBUTE(_item) \
132     for (_item = FIB_PATH_OPER_ATTRIBUTE_FIRST; \
133          _item <= FIB_PATH_OPER_ATTRIBUTE_LAST; \
134          _item++)
135
136 /**
137  * Path flags from the attributes
138  */
139 typedef enum fib_path_oper_flags_t_ {
140     FIB_PATH_OPER_FLAG_NONE = 0,
141     FIB_PATH_OPER_FLAG_RECURSIVE_LOOP = (1 << FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP),
142     FIB_PATH_OPER_FLAG_DROP = (1 << FIB_PATH_OPER_ATTRIBUTE_DROP),
143     FIB_PATH_OPER_FLAG_RESOLVED = (1 << FIB_PATH_OPER_ATTRIBUTE_RESOLVED),
144 } __attribute__ ((packed)) fib_path_oper_flags_t;
145
146 /**
147  * A FIB path
148  */
149 typedef struct fib_path_t_ {
150     /**
151      * A path is a node in the FIB graph.
152      */
153     fib_node_t fp_node;
154
155     /**
156      * The index of the path-list to which this path belongs
157      */
158     u32 fp_pl_index;
159
160     /**
161      * This marks the start of the memory area used to hash
162      * the path
163      */
164     STRUCT_MARK(path_hash_start);
165
166     /**
167      * Configuration Flags
168      */
169     fib_path_cfg_flags_t fp_cfg_flags;
170
171     /**
172      * The type of the path. This is the selector for the union
173      */
174     fib_path_type_t fp_type;
175
176     /**
177      * The protocol of the next-hop, i.e. the address family of the
178      * next-hop's address. We can't derive this from the address itself
179      * since the address can be all zeros
180      */
181     fib_protocol_t fp_nh_proto;
182
183     /**
184      * UCMP [unnormalised] weigt
185      */
186     u32 fp_weight;
187
188     /**
189      * per-type union of the data required to resolve the path
190      */
191     union {
192         struct {
193             /**
194              * The next-hop
195              */
196             ip46_address_t fp_nh;
197             /**
198              * The interface
199              */
200             u32 fp_interface;
201         } attached_next_hop;
202         struct {
203             /**
204              * The interface
205              */
206             u32 fp_interface;
207         } attached;
208         struct {
209             /**
210              * The next-hop
211              */
212             ip46_address_t fp_nh;
213             /**
214              * The FIB table index in which to find the next-hop.
215              * This needs to be fixed. We should lookup the adjacencies in
216              * a separate table of adjacencies, rather than from the FIB.
217              * Two reasons I can think of:
218              *   - consider:
219              *       int ip addr Gig0 10.0.0.1/24
220              *       ip route 10.0.0.2/32 via Gig1 192.168.1.2
221              *       ip route 1.1.1.1/32 via Gig0 10.0.0.2
222              *     this is perfectly valid.
223              *     Packets addressed to 10.0.0.2 should be sent via Gig1.
224              *     Packets address to 1.1.1.1 should be sent via Gig0.
225              *    when we perform the adj resolution from the FIB for the path
226              *    "via Gig0 10.0.0.2" the lookup will result in the route via Gig1
227              *    and so we will pick up the adj via Gig1 - which was not what the
228              *    operator wanted.
229              *  - we can only return link-type IPv4 and so not the link-type MPLS.
230              *    more on this in a later commit.
231              *
232              * The table ID should only belong to a recursive path and indicate
233              * which FIB should be used to resolve the next-hop.
234              */
235             fib_node_index_t fp_tbl_id;
236         } recursive;
237         struct {
238             /**
239              * The FIN index in which to perfom the next lookup
240              */
241             fib_node_index_t fp_tbl_id;
242         } deag;
243         struct {
244         } special;
245         struct {
246             /**
247              * The user provided 'exclusive' DPO
248              */
249             dpo_id_t fp_ex_dpo;
250         } exclusive;
251         struct {
252             /**
253              * The interface on which the local address is configured
254              */
255             u32 fp_interface;
256             /**
257              * The next-hop
258              */
259             ip46_address_t fp_addr;
260         } receive;
261     };
262     STRUCT_MARK(path_hash_end);
263
264     /**
265      * Memebers in this last section represent information that is
266      * dervied during resolution. It should not be copied to new paths
267      * nor compared.
268      */
269
270     /**
271      * Operational Flags
272      */
273     fib_path_oper_flags_t fp_oper_flags;
274
275     /**
276      * the resolving via fib. not part of the union, since it it not part
277      * of the path's hash.
278      */
279     fib_node_index_t fp_via_fib;
280
281     /**
282      * The Data-path objects through which this path resolves for IP.
283      */
284     dpo_id_t fp_dpo;
285
286     /**
287      * the index of this path in the parent's child list.
288      */
289     u32 fp_sibling;
290 } fib_path_t;
291
292 /*
293  * Array of strings/names for the path types and attributes
294  */
295 static const char *fib_path_type_names[] = FIB_PATH_TYPES;
296 static const char *fib_path_oper_attribute_names[] = FIB_PATH_OPER_ATTRIBUTES;
297 static const char *fib_path_cfg_attribute_names[]  = FIB_PATH_CFG_ATTRIBUTES;
298
299 /*
300  * The memory pool from which we allocate all the paths
301  */
302 static fib_path_t *fib_path_pool;
303
304 /*
305  * Debug macro
306  */
307 #ifdef FIB_DEBUG
308 #define FIB_PATH_DBG(_p, _fmt, _args...)                        \
309 {                                                               \
310     u8 *_tmp = NULL;                                            \
311     _tmp = fib_path_format(fib_path_get_index(_p), _tmp);       \
312     clib_warning("path:[%d:%s]:" _fmt,                          \
313                  fib_path_get_index(_p), _tmp,                  \
314                  ##_args);                                      \
315     vec_free(_tmp);                                             \
316 }
317 #else
318 #define FIB_PATH_DBG(_p, _fmt, _args...)
319 #endif
320
321 static fib_path_t *
322 fib_path_get (fib_node_index_t index)
323 {
324     return (pool_elt_at_index(fib_path_pool, index));
325 }
326
327 static fib_node_index_t 
328 fib_path_get_index (fib_path_t *path)
329 {
330     return (path - fib_path_pool);
331 }
332
333 static fib_node_t *
334 fib_path_get_node (fib_node_index_t index)
335 {
336     return ((fib_node_t*)fib_path_get(index));
337 }
338
339 static fib_path_t*
340 fib_path_from_fib_node (fib_node_t *node)
341 {
342 #if CLIB_DEBUG > 0
343     ASSERT(FIB_NODE_TYPE_PATH == node->fn_type);
344 #endif
345     return ((fib_path_t*)node);
346 }
347
348 u8 *
349 format_fib_path (u8 * s, va_list * args)
350 {
351     fib_path_t *path = va_arg (*args, fib_path_t *);
352     vnet_main_t * vnm = vnet_get_main();
353     fib_path_oper_attribute_t oattr;
354     fib_path_cfg_attribute_t cattr;
355
356     s = format (s, "      index:%d ", fib_path_get_index(path));
357     s = format (s, "pl-index:%d ", path->fp_pl_index);
358     s = format (s, "%U ", format_fib_protocol, path->fp_nh_proto);
359     s = format (s, "weight=%d ", path->fp_weight);
360     s = format (s, "%s: ", fib_path_type_names[path->fp_type]);
361     if (FIB_PATH_OPER_FLAG_NONE != path->fp_oper_flags) {
362         s = format(s, " oper-flags:");
363         FOR_EACH_FIB_PATH_OPER_ATTRIBUTE(oattr) {
364             if ((1<<oattr) & path->fp_oper_flags) {
365                 s = format (s, "%s,", fib_path_oper_attribute_names[oattr]);
366             }
367         }
368     }
369     if (FIB_PATH_CFG_FLAG_NONE != path->fp_cfg_flags) {
370         s = format(s, " cfg-flags:");
371         FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(cattr) {
372             if ((1<<cattr) & path->fp_cfg_flags) {
373                 s = format (s, "%s,", fib_path_cfg_attribute_names[cattr]);
374             }
375         }
376     }
377     s = format(s, "\n       ");
378
379     switch (path->fp_type)
380     {
381     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
382         s = format (s, "%U", format_ip46_address,
383                     &path->attached_next_hop.fp_nh,
384                     IP46_TYPE_ANY);
385         if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP)
386         {
387             s = format (s, " if_index:%d", path->attached_next_hop.fp_interface);
388         }
389         else
390         {
391             s = format (s, " %U",
392                         format_vnet_sw_interface_name,
393                         vnm,
394                         vnet_get_sw_interface(
395                             vnm,
396                             path->attached_next_hop.fp_interface));
397             if (vnet_sw_interface_is_p2p(vnet_get_main(),
398                                          path->attached_next_hop.fp_interface))
399             {
400                 s = format (s, " (p2p)");
401             }
402         }
403         if (!dpo_id_is_valid(&path->fp_dpo))
404         {
405             s = format(s, "\n          unresolved");
406         }
407         else
408         {
409             s = format(s, "\n          %U",
410                        format_dpo_id,
411                        &path->fp_dpo, 13);
412         }
413         break;
414     case FIB_PATH_TYPE_ATTACHED:
415         if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP)
416         {
417             s = format (s, " if_index:%d", path->attached_next_hop.fp_interface);
418         }
419         else
420         {
421             s = format (s, " %U",
422                         format_vnet_sw_interface_name,
423                         vnm,
424                         vnet_get_sw_interface(
425                             vnm,
426                             path->attached.fp_interface));
427         }
428         break;
429     case FIB_PATH_TYPE_RECURSIVE:
430         s = format (s, "via %U",
431                     format_ip46_address,
432                     &path->recursive.fp_nh,
433                     IP46_TYPE_ANY);
434         s = format (s, " in fib:%d", path->recursive.fp_tbl_id, path->fp_via_fib); 
435         s = format (s, " via-fib:%d", path->fp_via_fib); 
436         s = format (s, " via-dpo:[%U:%d]",
437                     format_dpo_type, path->fp_dpo.dpoi_type, 
438                     path->fp_dpo.dpoi_index);
439
440         break;
441     case FIB_PATH_TYPE_RECEIVE:
442     case FIB_PATH_TYPE_SPECIAL:
443     case FIB_PATH_TYPE_DEAG:
444     case FIB_PATH_TYPE_EXCLUSIVE:
445         if (dpo_id_is_valid(&path->fp_dpo))
446         {
447             s = format(s, "%U", format_dpo_id,
448                        &path->fp_dpo, 2);
449         }
450         break;
451     }
452     return (s);
453 }
454
455 u8 *
456 fib_path_format (fib_node_index_t pi, u8 *s)
457 {
458     fib_path_t *path;
459
460     path = fib_path_get(pi);
461     ASSERT(NULL != path);
462
463     return (format (s, "%U", format_fib_path, path));
464 }
465
466 u8 *
467 fib_path_adj_format (fib_node_index_t pi,
468                      u32 indent,
469                      u8 *s)
470 {
471     fib_path_t *path;
472
473     path = fib_path_get(pi);
474     ASSERT(NULL != path);
475
476     if (!dpo_id_is_valid(&path->fp_dpo))
477     {
478         s = format(s, " unresolved");
479     }
480     else
481     {
482         s = format(s, "%U", format_dpo_id,
483                    &path->fp_dpo, 2);
484     }
485
486     return (s);
487 }
488
489 /*
490  * fib_path_last_lock_gone
491  *
492  * We don't share paths, we share path lists, so the [un]lock functions
493  * are no-ops
494  */
495 static void
496 fib_path_last_lock_gone (fib_node_t *node)
497 {
498     ASSERT(0);
499 }
500
501 static const adj_index_t
502 fib_path_attached_next_hop_get_adj (fib_path_t *path,
503                                     fib_link_t link)
504 {
505     if (vnet_sw_interface_is_p2p(vnet_get_main(),
506                                  path->attached_next_hop.fp_interface))
507     {
508         /*
509          * if the interface is p2p then the adj for the specific
510          * neighbour on that link will never exist. on p2p links
511          * the subnet address (the attached route) links to the
512          * auto-adj (see below), we want that adj here too.
513          */
514         return (adj_nbr_add_or_lock(path->fp_nh_proto,
515                                     link,
516                                     &zero_addr,
517                                     path->attached_next_hop.fp_interface));
518     }
519     else
520     {
521         return (adj_nbr_add_or_lock(path->fp_nh_proto,
522                                     link,
523                                     &path->attached_next_hop.fp_nh,
524                                     path->attached_next_hop.fp_interface));
525     }
526 }
527
528 static void
529 fib_path_attached_next_hop_set (fib_path_t *path)
530 {
531     /*
532      * resolve directly via the adjacnecy discribed by the
533      * interface and next-hop
534      */
535     if (!vnet_sw_interface_is_admin_up(vnet_get_main(),
536                                       path->attached_next_hop.fp_interface))
537     {
538         path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
539     }
540
541     dpo_set(&path->fp_dpo,
542             DPO_ADJACENCY,
543             fib_proto_to_dpo(path->fp_nh_proto),
544             fib_path_attached_next_hop_get_adj(
545                  path,
546                  fib_proto_to_link(path->fp_nh_proto)));
547
548     /*
549      * become a child of the adjacency so we receive updates
550      * when its rewrite changes
551      */
552     path->fp_sibling = adj_child_add(path->fp_dpo.dpoi_index,
553                                      FIB_NODE_TYPE_PATH,
554                                      fib_path_get_index(path));
555 }
556
557 /*
558  * create of update the paths recursive adj
559  */
560 static void
561 fib_path_recursive_adj_update (fib_path_t *path,
562                                fib_forward_chain_type_t fct,
563                                dpo_id_t *dpo)
564 {
565     dpo_id_t via_dpo = DPO_NULL;
566
567     /*
568      * get the DPO to resolve through from the via-entry
569      */
570     fib_entry_contribute_forwarding(path->fp_via_fib,
571                                     fct,
572                                     &via_dpo);
573
574
575     /*
576      * hope for the best - clear if restrictions apply.
577      */
578     path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
579
580     /*
581      * Validate any recursion constraints and over-ride the via
582      * adj if not met
583      */
584     if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP)
585     {
586         path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
587         dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
588     }
589     else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_HOST)
590     {
591         /*
592          * the via FIB must be a host route.
593          * note the via FIB just added will always be a host route
594          * since it is an RR source added host route. So what we need to
595          * check is whether the route has other sources. If it does then
596          * some other source has added it as a host route. If it doesn't
597          * then it was added only here and inherits forwarding from a cover.
598          * the cover is not a host route.
599          * The RR source is the lowest priority source, so we check if it
600          * is the best. if it is there are no other sources.
601          */
602         if (fib_entry_get_best_source(path->fp_via_fib) >= FIB_SOURCE_RR)
603         {
604             path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
605             dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
606
607             /*
608              * PIC edge trigger. let the load-balance maps know
609              */
610             load_balance_map_path_state_change(fib_path_get_index(path));
611         }
612     }
613     else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED)
614     {
615         /*
616          * RR source entries inherit the flags from the cover, so
617          * we can check the via directly
618          */
619         if (!(FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(path->fp_via_fib)))
620         {
621             path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
622             dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
623
624             /*
625              * PIC edge trigger. let the load-balance maps know
626              */
627             load_balance_map_path_state_change(fib_path_get_index(path));
628         }
629     }
630
631     /*
632      * update the path's contributed DPO
633      */
634     dpo_copy(dpo, &via_dpo);
635
636     FIB_PATH_DBG(path, "recursive update: %U",
637                  fib_get_lookup_main(path->fp_nh_proto),
638                  &path->fp_dpo, 2);
639
640     dpo_reset(&via_dpo);
641 }
642
643 /*
644  * fib_path_is_permanent_drop
645  *
646  * Return !0 if the path is configured to permanently drop,
647  * despite other attributes.
648  */
649 static int
650 fib_path_is_permanent_drop (fib_path_t *path)
651 {
652     return ((path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DROP) ||
653             (path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP));
654 }
655
656 /*
657  * fib_path_unresolve
658  *
659  * Remove our dependency on the resolution target
660  */
661 static void
662 fib_path_unresolve (fib_path_t *path)
663 {
664     /*
665      * the forced drop path does not need unresolving
666      */
667     if (fib_path_is_permanent_drop(path))
668     {
669         return;
670     }
671
672     switch (path->fp_type)
673     {
674     case FIB_PATH_TYPE_RECURSIVE:
675         if (FIB_NODE_INDEX_INVALID != path->fp_via_fib)
676         {
677             fib_prefix_t pfx;
678
679             fib_prefix_from_ip46_addr(&path->recursive.fp_nh, &pfx);
680             fib_entry_child_remove(path->fp_via_fib,
681                                    path->fp_sibling);
682             fib_table_entry_special_remove(path->recursive.fp_tbl_id,
683                                            &pfx,
684                                            FIB_SOURCE_RR);
685             path->fp_via_fib = FIB_NODE_INDEX_INVALID;
686         }
687         break;
688     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
689     case FIB_PATH_TYPE_ATTACHED:
690         adj_child_remove(path->fp_dpo.dpoi_index,
691                          path->fp_sibling);
692         adj_unlock(path->fp_dpo.dpoi_index);
693         break;
694     case FIB_PATH_TYPE_EXCLUSIVE:
695         dpo_reset(&path->exclusive.fp_ex_dpo);
696         break;
697     case FIB_PATH_TYPE_SPECIAL:
698     case FIB_PATH_TYPE_RECEIVE:
699     case FIB_PATH_TYPE_DEAG:
700         /*
701          * these hold only the path's DPO, which is reset below.
702          */
703         break;
704     }
705
706     /*
707      * release the adj we were holding and pick up the
708      * drop just in case.
709      */
710     dpo_reset(&path->fp_dpo);
711     path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
712
713     return;
714 }
715
716 static fib_forward_chain_type_t
717 fib_path_proto_to_chain_type (fib_protocol_t proto)
718 {
719     switch (proto)
720     {
721     case FIB_PROTOCOL_IP4:
722         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
723     case FIB_PROTOCOL_IP6:
724         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
725     case FIB_PROTOCOL_MPLS:
726         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
727     }
728     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
729 }
730
731 /*
732  * fib_path_back_walk_notify
733  *
734  * A back walk has reach this path.
735  */
736 static fib_node_back_walk_rc_t
737 fib_path_back_walk_notify (fib_node_t *node,
738                            fib_node_back_walk_ctx_t *ctx)
739 {
740     fib_path_t *path;
741
742     path = fib_path_from_fib_node(node);
743
744     switch (path->fp_type)
745     {
746     case FIB_PATH_TYPE_RECURSIVE:
747         if (FIB_NODE_BW_REASON_FLAG_EVALUATE & ctx->fnbw_reason)
748         {
749             /*
750              * modify the recursive adjacency to use the new forwarding
751              * of the via-fib.
752              * this update is visible to packets in flight in the DP.
753              */
754             fib_path_recursive_adj_update(
755                 path,
756                 fib_path_proto_to_chain_type(path->fp_nh_proto),
757                 &path->fp_dpo);
758         }
759         break;
760     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
761         /*
762 FIXME comment
763          * ADJ_UPDATE backwalk pass silently through here and up to
764          * the path-list when the multipath adj collapse occurs.
765          * The reason we do this is that the assumtption is that VPP
766          * runs in an environment where the Control-Plane is remote
767          * and hence reacts slowly to link up down. In order to remove
768          * this down link from the ECMP set quickly, we back-walk.
769          * VPP also has dedicated CPUs, so we are not stealing resources
770          * from the CP to do so.
771          */
772         if (FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason)
773         {
774             path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
775         }
776         if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason)
777         {
778             path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
779         }
780         if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
781         {
782             /*
783              * The interface this path resolves through has been deleted.
784              * This will leave the path in a permanent drop state. The route
785              * needs to be removed and readded (and hence the path-list deleted)
786              * before it can forward again.
787              */
788             fib_path_unresolve(path);
789             path->fp_oper_flags |= FIB_PATH_OPER_FLAG_DROP;
790         }
791         if (FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason)
792         {
793             /*
794              * restack the DPO to pick up the correct DPO sub-type
795              */
796             adj_index_t ai;
797
798             ai = fib_path_attached_next_hop_get_adj(
799                      path,
800                      fib_proto_to_link(path->fp_nh_proto));
801
802             dpo_set(&path->fp_dpo, DPO_ADJACENCY,
803                     fib_proto_to_dpo(path->fp_nh_proto),
804                     ai);
805             adj_unlock(ai);
806         }
807         break;
808     case FIB_PATH_TYPE_ATTACHED:
809         /*
810          * FIXME; this could schedule a lower priority walk, since attached
811          * routes are not usually in ECMP configurations so the backwalk to
812          * the FIB entry does not need to be high priority
813          */
814         if (FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason)
815         {
816             path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
817         }
818         if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason)
819         {
820             path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
821         }
822         if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
823         {
824             fib_path_unresolve(path);
825             path->fp_oper_flags |= FIB_PATH_OPER_FLAG_DROP;
826         }
827         break;
828     case FIB_PATH_TYPE_DEAG:
829         /*
830          * FIXME When VRF delete is allowed this will need a poke.
831          */
832     case FIB_PATH_TYPE_SPECIAL:
833     case FIB_PATH_TYPE_RECEIVE:
834     case FIB_PATH_TYPE_EXCLUSIVE:
835         /*
836          * these path types have no parents. so to be
837          * walked from one is unexpected.
838          */
839         ASSERT(0);
840         break;
841     }
842
843     /*
844      * propagate the backwalk further to the path-list
845      */
846     fib_path_list_back_walk(path->fp_pl_index, ctx);
847
848     return (FIB_NODE_BACK_WALK_CONTINUE);
849 }
850
851 static void
852 fib_path_memory_show (void)
853 {
854     fib_show_memory_usage("Path",
855                           pool_elts(fib_path_pool),
856                           pool_len(fib_path_pool),
857                           sizeof(fib_path_t));
858 }
859
860 /*
861  * The FIB path's graph node virtual function table
862  */
863 static const fib_node_vft_t fib_path_vft = {
864     .fnv_get = fib_path_get_node,
865     .fnv_last_lock = fib_path_last_lock_gone,
866     .fnv_back_walk = fib_path_back_walk_notify,
867     .fnv_mem_show = fib_path_memory_show,
868 };
869
870 static fib_path_cfg_flags_t
871 fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
872 {
873     fib_path_cfg_flags_t cfg_flags = FIB_PATH_CFG_ATTRIBUTE_FIRST;
874
875     if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
876         cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_HOST;
877     if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
878         cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED;
879
880     return (cfg_flags);
881 }
882
883 /*
884  * fib_path_create
885  *
886  * Create and initialise a new path object.
887  * return the index of the path.
888  */
889 fib_node_index_t
890 fib_path_create (fib_node_index_t pl_index,
891                  fib_protocol_t nh_proto,
892                  fib_path_cfg_flags_t flags,
893                  const fib_route_path_t *rpath)
894 {
895     fib_path_t *path;
896
897     pool_get(fib_path_pool, path);
898     memset(path, 0, sizeof(*path));
899
900     fib_node_init(&path->fp_node,
901                   FIB_NODE_TYPE_PATH);
902
903     dpo_reset(&path->fp_dpo);
904     path->fp_pl_index = pl_index;
905     path->fp_nh_proto = nh_proto;
906     path->fp_via_fib = FIB_NODE_INDEX_INVALID;
907     path->fp_weight = rpath->frp_weight;
908     path->fp_cfg_flags = flags;
909     path->fp_cfg_flags |= fib_path_route_flags_to_cfg_flags(rpath);
910
911     /*
912      * deduce the path's tpye from the parementers and save what is needed.
913      */
914     if (~0 != rpath->frp_sw_if_index)
915     {
916         if (flags & FIB_PATH_CFG_FLAG_LOCAL)
917         {
918             path->fp_type = FIB_PATH_TYPE_RECEIVE;
919             path->receive.fp_interface = rpath->frp_sw_if_index;
920             path->receive.fp_addr = rpath->frp_addr;
921         }
922         else
923         {
924             if (ip46_address_is_zero(&rpath->frp_addr))
925             {
926                 path->fp_type = FIB_PATH_TYPE_ATTACHED;
927                 path->attached.fp_interface = rpath->frp_sw_if_index;
928             }
929             else
930             {
931                 path->fp_type = FIB_PATH_TYPE_ATTACHED_NEXT_HOP;
932                 path->attached_next_hop.fp_interface = rpath->frp_sw_if_index;
933                 path->attached_next_hop.fp_nh = rpath->frp_addr;
934             }
935         }
936     }
937     else
938     {
939         if (ip46_address_is_zero(&rpath->frp_addr))
940         {
941             if (~0 == rpath->frp_fib_index)
942             {
943                 path->fp_type = FIB_PATH_TYPE_SPECIAL;
944             }
945             else
946             {
947                 path->fp_type = FIB_PATH_TYPE_DEAG;
948                 path->deag.fp_tbl_id = rpath->frp_fib_index;
949             }           
950         }
951         else
952         {
953             path->fp_type = FIB_PATH_TYPE_RECURSIVE;
954             path->recursive.fp_nh = rpath->frp_addr;
955             path->recursive.fp_tbl_id = rpath->frp_fib_index;
956         }
957     }
958
959     FIB_PATH_DBG(path, "create");
960
961     return (fib_path_get_index(path));
962 }
963
964 /*
965  * fib_path_create_special
966  *
967  * Create and initialise a new path object.
968  * return the index of the path.
969  */
970 fib_node_index_t
971 fib_path_create_special (fib_node_index_t pl_index,
972                          fib_protocol_t nh_proto,
973                          fib_path_cfg_flags_t flags,
974                          const dpo_id_t *dpo)
975 {
976     fib_path_t *path;
977
978     pool_get(fib_path_pool, path);
979     memset(path, 0, sizeof(*path));
980
981     fib_node_init(&path->fp_node,
982                   FIB_NODE_TYPE_PATH);
983     dpo_reset(&path->fp_dpo);
984
985     path->fp_pl_index = pl_index;
986     path->fp_weight = 1;
987     path->fp_nh_proto = nh_proto;
988     path->fp_via_fib = FIB_NODE_INDEX_INVALID;
989     path->fp_cfg_flags = flags;
990
991     if (FIB_PATH_CFG_FLAG_DROP & flags)
992     {
993         path->fp_type = FIB_PATH_TYPE_SPECIAL;
994     }
995     else if (FIB_PATH_CFG_FLAG_LOCAL & flags)
996     {
997         path->fp_type = FIB_PATH_TYPE_RECEIVE;
998         path->attached.fp_interface = FIB_NODE_INDEX_INVALID;
999     }
1000     else
1001     {
1002         path->fp_type = FIB_PATH_TYPE_EXCLUSIVE;
1003         ASSERT(NULL != dpo);
1004         dpo_copy(&path->exclusive.fp_ex_dpo, dpo);
1005     }
1006
1007     return (fib_path_get_index(path));
1008 }
1009
1010 /*
1011  * fib_path_copy
1012  *
1013  * Copy a path. return index of new path.
1014  */
1015 fib_node_index_t
1016 fib_path_copy (fib_node_index_t path_index,
1017                fib_node_index_t path_list_index)
1018 {
1019     fib_path_t *path, *orig_path;
1020
1021     pool_get(fib_path_pool, path);
1022
1023     orig_path = fib_path_get(path_index);
1024     ASSERT(NULL != orig_path);
1025
1026     memcpy(path, orig_path, sizeof(*path));
1027
1028     FIB_PATH_DBG(path, "create-copy:%d", path_index);
1029
1030     /*
1031      * reset the dynamic section
1032      */
1033     fib_node_init(&path->fp_node, FIB_NODE_TYPE_PATH);
1034     path->fp_oper_flags     = FIB_PATH_OPER_FLAG_NONE;
1035     path->fp_pl_index  = path_list_index;
1036     path->fp_via_fib   = FIB_NODE_INDEX_INVALID;
1037     memset(&path->fp_dpo, 0, sizeof(path->fp_dpo));
1038     dpo_reset(&path->fp_dpo);
1039
1040     return (fib_path_get_index(path));
1041 }
1042
1043 /*
1044  * fib_path_destroy
1045  *
1046  * destroy a path that is no longer required
1047  */
1048 void
1049 fib_path_destroy (fib_node_index_t path_index)
1050 {
1051     fib_path_t *path;
1052
1053     path = fib_path_get(path_index);
1054
1055     ASSERT(NULL != path);
1056     FIB_PATH_DBG(path, "destroy");
1057
1058     fib_path_unresolve(path);
1059
1060     fib_node_deinit(&path->fp_node);
1061     pool_put(fib_path_pool, path);
1062 }
1063
1064 /*
1065  * fib_path_destroy
1066  *
1067  * destroy a path that is no longer required
1068  */
1069 uword
1070 fib_path_hash (fib_node_index_t path_index)
1071 {
1072     fib_path_t *path;
1073
1074     path = fib_path_get(path_index);
1075
1076     return (hash_memory(STRUCT_MARK_PTR(path, path_hash_start),
1077                         (STRUCT_OFFSET_OF(fib_path_t, path_hash_end) -
1078                          STRUCT_OFFSET_OF(fib_path_t, path_hash_start)),
1079                         0));
1080 }
1081
1082 /*
1083  * fib_path_cmp_i
1084  *
1085  * Compare two paths for equivalence.
1086  */
1087 static int
1088 fib_path_cmp_i (const fib_path_t *path1,
1089                 const fib_path_t *path2)
1090 {
1091     int res;
1092
1093     res = 1;
1094
1095     /*
1096      * paths of different types and protocol are not equal.
1097      * different weights only are the same path.
1098      */
1099     if (path1->fp_type != path2->fp_type)
1100     {
1101         res = (path1->fp_type - path2->fp_type);
1102     }
1103     if (path1->fp_nh_proto != path2->fp_nh_proto)
1104     {
1105         res = (path1->fp_nh_proto - path2->fp_nh_proto);
1106     }
1107     else
1108     {
1109         /*
1110          * both paths are of the same type.
1111          * consider each type and its attributes in turn.
1112          */
1113         switch (path1->fp_type)
1114         {
1115         case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1116             res = ip46_address_cmp(&path1->attached_next_hop.fp_nh,
1117                                    &path2->attached_next_hop.fp_nh);
1118             if (0 == res) {
1119                 res = vnet_sw_interface_compare(
1120                           vnet_get_main(),
1121                           path1->attached_next_hop.fp_interface,
1122                           path2->attached_next_hop.fp_interface);
1123             }
1124             break;
1125         case FIB_PATH_TYPE_ATTACHED:
1126             res = vnet_sw_interface_compare(
1127                       vnet_get_main(),
1128                       path1->attached.fp_interface,
1129                       path2->attached.fp_interface);
1130             break;
1131         case FIB_PATH_TYPE_RECURSIVE:
1132             res = ip46_address_cmp(&path1->recursive.fp_nh,
1133                                    &path2->recursive.fp_nh);
1134  
1135             if (0 == res)
1136             {
1137                 res = (path1->recursive.fp_tbl_id - path2->recursive.fp_tbl_id);
1138             }
1139             break;
1140         case FIB_PATH_TYPE_DEAG:
1141             res = (path1->deag.fp_tbl_id - path2->deag.fp_tbl_id);
1142             break;
1143         case FIB_PATH_TYPE_SPECIAL:
1144         case FIB_PATH_TYPE_RECEIVE:
1145         case FIB_PATH_TYPE_EXCLUSIVE:
1146             res = 0;
1147             break;
1148         }
1149     }
1150     return (res);
1151 }
1152
1153 /*
1154  * fib_path_cmp_for_sort
1155  *
1156  * Compare two paths for equivalence. Used during path sorting.
1157  * As usual 0 means equal.
1158  */
1159 int
1160 fib_path_cmp_for_sort (void * v1,
1161                        void * v2)
1162 {
1163     fib_node_index_t *pi1 = v1, *pi2 = v2;
1164     fib_path_t *path1, *path2;
1165
1166     path1 = fib_path_get(*pi1);
1167     path2 = fib_path_get(*pi2);
1168
1169     return (fib_path_cmp_i(path1, path2));
1170 }
1171
1172 /*
1173  * fib_path_cmp
1174  *
1175  * Compare two paths for equivalence.
1176  */
1177 int
1178 fib_path_cmp (fib_node_index_t pi1,
1179               fib_node_index_t pi2)
1180 {
1181     fib_path_t *path1, *path2;
1182
1183     path1 = fib_path_get(pi1);
1184     path2 = fib_path_get(pi2);
1185
1186     return (fib_path_cmp_i(path1, path2));
1187 }
1188
1189 int
1190 fib_path_cmp_w_route_path (fib_node_index_t path_index,
1191                            const fib_route_path_t *rpath)
1192 {
1193     fib_path_t *path;
1194     int res;
1195
1196     path = fib_path_get(path_index);
1197
1198     res = 1;
1199
1200     if (path->fp_weight != rpath->frp_weight)
1201     {
1202         res = (path->fp_weight - rpath->frp_weight);
1203     }
1204     else
1205     {
1206         /*
1207          * both paths are of the same type.
1208          * consider each type and its attributes in turn.
1209          */
1210         switch (path->fp_type)
1211         {
1212         case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1213             res = ip46_address_cmp(&path->attached_next_hop.fp_nh,
1214                                    &rpath->frp_addr);
1215             if (0 == res)
1216             {
1217                 res = vnet_sw_interface_compare(
1218                           vnet_get_main(),
1219                           path->attached_next_hop.fp_interface,
1220                           rpath->frp_sw_if_index);
1221             }
1222             break;
1223         case FIB_PATH_TYPE_ATTACHED:
1224             res = vnet_sw_interface_compare(
1225                       vnet_get_main(),
1226                       path->attached.fp_interface,
1227                       rpath->frp_sw_if_index);
1228             break;
1229         case FIB_PATH_TYPE_RECURSIVE:
1230             res = ip46_address_cmp(&path->recursive.fp_nh,
1231                                    &rpath->frp_addr);
1232  
1233             if (0 == res)
1234             {
1235                 res = (path->recursive.fp_tbl_id - rpath->frp_fib_index);
1236             }
1237             break;
1238         case FIB_PATH_TYPE_DEAG:
1239             res = (path->deag.fp_tbl_id - rpath->frp_fib_index);
1240             break;
1241         case FIB_PATH_TYPE_SPECIAL:
1242         case FIB_PATH_TYPE_RECEIVE:
1243         case FIB_PATH_TYPE_EXCLUSIVE:
1244             res = 0;
1245             break;
1246         }
1247     }
1248     return (res);
1249 }
1250
1251 /*
1252  * fib_path_recursive_loop_detect
1253  *
1254  * A forward walk of the FIB object graph to detect for a cycle/loop. This
1255  * walk is initiated when an entry is linking to a new path list or from an old.
1256  * The entry vector passed contains all the FIB entrys that are children of this
1257  * path (it is all the entries encountered on the walk so far). If this vector
1258  * contains the entry this path resolve via, then a loop is about to form.
1259  * The loop must be allowed to form, since we need the dependencies in place
1260  * so that we can track when the loop breaks.
1261  * However, we MUST not produce a loop in the forwarding graph (else packets
1262  * would loop around the switch path until the loop breaks), so we mark recursive
1263  * paths as looped so that they do not contribute forwarding information.
1264  * By marking the path as looped, an etry such as;
1265  *    X/Y
1266  *     via a.a.a.a (looped)
1267  *     via b.b.b.b (not looped)
1268  * can still forward using the info provided by b.b.b.b only
1269  */
1270 int
1271 fib_path_recursive_loop_detect (fib_node_index_t path_index,
1272                                 fib_node_index_t **entry_indicies)
1273 {
1274     fib_path_t *path;
1275
1276     path = fib_path_get(path_index);
1277
1278     /*
1279      * the forced drop path is never looped, cos it is never resolved.
1280      */
1281     if (fib_path_is_permanent_drop(path))
1282     {
1283         return (0);
1284     }
1285
1286     switch (path->fp_type)
1287     {
1288     case FIB_PATH_TYPE_RECURSIVE:
1289     {
1290         fib_node_index_t *entry_index, *entries;
1291         int looped = 0;
1292         entries = *entry_indicies;
1293
1294         vec_foreach(entry_index, entries) {
1295             if (*entry_index == path->fp_via_fib)
1296             {
1297                 /*
1298                  * the entry that is about to link to this path-list (or
1299                  * one of this path-list's children) is the same entry that
1300                  * this recursive path resolves through. this is a cycle.
1301                  * abort the walk.
1302                  */
1303                 looped = 1;
1304                 break;
1305             }
1306         }
1307
1308         if (looped)
1309         {
1310             FIB_PATH_DBG(path, "recursive loop formed");
1311             path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1312
1313             dpo_copy(&path->fp_dpo,
1314                     drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
1315         }
1316         else
1317         {
1318             /*
1319              * no loop here yet. keep forward walking the graph.
1320              */     
1321             if (fib_entry_recursive_loop_detect(path->fp_via_fib, entry_indicies))
1322             {
1323                 FIB_PATH_DBG(path, "recursive loop formed");
1324                 path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1325             }
1326             else
1327             {
1328                 FIB_PATH_DBG(path, "recursive loop cleared");
1329                 path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1330             }
1331         }
1332         break;
1333     }
1334     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1335     case FIB_PATH_TYPE_ATTACHED:
1336     case FIB_PATH_TYPE_SPECIAL:
1337     case FIB_PATH_TYPE_DEAG:
1338     case FIB_PATH_TYPE_RECEIVE:
1339     case FIB_PATH_TYPE_EXCLUSIVE:
1340         /*
1341          * these path types cannot be part of a loop, since they are the leaves
1342          * of the graph.
1343          */
1344         break;
1345     }
1346
1347     return (fib_path_is_looped(path_index));
1348 }
1349
1350 int
1351 fib_path_resolve (fib_node_index_t path_index)
1352 {
1353     fib_path_t *path;
1354
1355     path = fib_path_get(path_index);
1356
1357     /*
1358      * hope for the best.
1359      */
1360     path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1361
1362     /*
1363      * the forced drop path resolves via the drop adj
1364      */
1365     if (fib_path_is_permanent_drop(path))
1366     {
1367         dpo_copy(&path->fp_dpo,
1368                  drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
1369         path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1370         return (fib_path_is_resolved(path_index));
1371     }
1372
1373     switch (path->fp_type)
1374     {
1375     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1376         fib_path_attached_next_hop_set(path);
1377         break;
1378     case FIB_PATH_TYPE_ATTACHED:
1379         /*
1380          * path->attached.fp_interface
1381          */
1382         if (!vnet_sw_interface_is_admin_up(vnet_get_main(),
1383                                            path->attached.fp_interface))
1384         {
1385             path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1386         }
1387         if (vnet_sw_interface_is_p2p(vnet_get_main(),
1388                                      path->attached.fp_interface))
1389         {
1390             /*
1391              * point-2-point interfaces do not require a glean, since
1392              * there is nothing to ARP. Install a rewrite/nbr adj instead
1393              */
1394             dpo_set(&path->fp_dpo,
1395                     DPO_ADJACENCY,
1396                     fib_proto_to_dpo(path->fp_nh_proto),
1397                     adj_nbr_add_or_lock(
1398                         path->fp_nh_proto,
1399                         fib_proto_to_link(path->fp_nh_proto),
1400                         &zero_addr,
1401                         path->attached.fp_interface));
1402         }
1403         else
1404         {
1405             dpo_set(&path->fp_dpo,
1406                     DPO_ADJACENCY_GLEAN,
1407                     fib_proto_to_dpo(path->fp_nh_proto),
1408                     adj_glean_add_or_lock(path->fp_nh_proto,
1409                                           path->attached.fp_interface,
1410                                           NULL));
1411         }
1412         /*
1413          * become a child of the adjacency so we receive updates
1414          * when the interface state changes
1415          */
1416         path->fp_sibling = adj_child_add(path->fp_dpo.dpoi_index,
1417                                          FIB_NODE_TYPE_PATH,
1418                                          fib_path_get_index(path));
1419
1420         break;
1421     case FIB_PATH_TYPE_RECURSIVE:
1422     {
1423         /*
1424          * Create a RR source entry in the table for the address
1425          * that this path recurses through.
1426          * This resolve action is recursive, hence we may create
1427          * more paths in the process. more creates mean maybe realloc
1428          * of this path.
1429          */
1430         fib_node_index_t fei;
1431         fib_prefix_t pfx;
1432
1433         ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_fib);
1434
1435         fib_prefix_from_ip46_addr(&path->recursive.fp_nh, &pfx);
1436
1437         fei = fib_table_entry_special_add(path->recursive.fp_tbl_id,
1438                                           &pfx,
1439                                           FIB_SOURCE_RR,
1440                                           FIB_ENTRY_FLAG_NONE,
1441                                           ADJ_INDEX_INVALID);
1442
1443         path = fib_path_get(path_index);
1444         path->fp_via_fib = fei;
1445
1446         /*
1447          * become a dependent child of the entry so the path is 
1448          * informed when the forwarding for the entry changes.
1449          */
1450         path->fp_sibling = fib_entry_child_add(path->fp_via_fib,
1451                                                FIB_NODE_TYPE_PATH,
1452                                                fib_path_get_index(path));
1453
1454         /*
1455          * create and configure the IP DPO
1456          */
1457         fib_path_recursive_adj_update(
1458             path,
1459             fib_path_proto_to_chain_type(path->fp_nh_proto),
1460             &path->fp_dpo);
1461
1462         break;
1463     }
1464     case FIB_PATH_TYPE_SPECIAL:
1465         /*
1466          * Resolve via the drop
1467          */
1468         dpo_copy(&path->fp_dpo,
1469                  drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
1470         break;
1471     case FIB_PATH_TYPE_DEAG:
1472         /*
1473          * Resolve via a lookup DPO.
1474          * FIXME. control plane should add routes with a table ID
1475          */
1476         lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
1477                                           fib_proto_to_dpo(path->fp_nh_proto),
1478                                           LOOKUP_INPUT_DST_ADDR,
1479                                           LOOKUP_TABLE_FROM_CONFIG,
1480                                           &path->fp_dpo);
1481         break;
1482     case FIB_PATH_TYPE_RECEIVE:
1483         /*
1484          * Resolve via a receive DPO.
1485          */
1486         receive_dpo_add_or_lock(fib_proto_to_dpo(path->fp_nh_proto),
1487                                 path->receive.fp_interface,
1488                                 &path->receive.fp_addr,
1489                                 &path->fp_dpo);
1490         break;
1491     case FIB_PATH_TYPE_EXCLUSIVE:
1492         /*
1493          * Resolve via the user provided DPO
1494          */
1495         dpo_copy(&path->fp_dpo, &path->exclusive.fp_ex_dpo);
1496         break;
1497     }
1498
1499     return (fib_path_is_resolved(path_index));
1500 }
1501
1502 u32
1503 fib_path_get_resolving_interface (fib_node_index_t path_index)
1504 {
1505     fib_path_t *path;
1506
1507     path = fib_path_get(path_index);
1508
1509     switch (path->fp_type)
1510     {
1511     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1512         return (path->attached_next_hop.fp_interface);
1513     case FIB_PATH_TYPE_ATTACHED:
1514         return (path->attached.fp_interface);
1515     case FIB_PATH_TYPE_RECEIVE:
1516         return (path->receive.fp_interface);
1517     case FIB_PATH_TYPE_RECURSIVE:
1518         return (fib_entry_get_resolving_interface(path->fp_via_fib));    
1519     case FIB_PATH_TYPE_SPECIAL:
1520     case FIB_PATH_TYPE_DEAG:
1521     case FIB_PATH_TYPE_EXCLUSIVE:
1522         break;
1523     }
1524     return (~0);
1525 }
1526
1527 adj_index_t
1528 fib_path_get_adj (fib_node_index_t path_index)
1529 {
1530     fib_path_t *path;
1531
1532     path = fib_path_get(path_index);
1533
1534     ASSERT(dpo_is_adj(&path->fp_dpo));
1535     if (dpo_is_adj(&path->fp_dpo))
1536     {
1537         return (path->fp_dpo.dpoi_index);
1538     }
1539     return (ADJ_INDEX_INVALID);
1540 }
1541
1542 int
1543 fib_path_get_weight (fib_node_index_t path_index)
1544 {
1545     fib_path_t *path;
1546
1547     path = fib_path_get(path_index);
1548
1549     ASSERT(path);
1550
1551     return (path->fp_weight);
1552 }
1553
1554 void
1555 fib_path_contribute_forwarding (fib_node_index_t path_index,
1556                                 fib_forward_chain_type_t fct,
1557                                 dpo_id_t *dpo)
1558 {
1559     fib_path_t *path;
1560
1561     path = fib_path_get(path_index);
1562
1563     ASSERT(path);
1564     ASSERT(FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct);
1565
1566     FIB_PATH_DBG(path, "contribute");
1567
1568     /*
1569      * The DPO stored in the path was created when the path was resolved.
1570      * This then represents the path's 'native' protocol; IP.
1571      * For all others will need to go find something else.
1572      */
1573     if (fib_path_proto_to_chain_type(path->fp_nh_proto) == fct)
1574     {
1575         dpo_copy(dpo, &path->fp_dpo);
1576     }
1577     else
1578     {
1579         switch (path->fp_type)
1580         {
1581         case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1582             switch (fct)
1583             {
1584             case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
1585             case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
1586             case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
1587             case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
1588             case FIB_FORW_CHAIN_TYPE_ETHERNET:
1589             {
1590                 adj_index_t ai;
1591
1592                 /*
1593                  * get a MPLS link type adj.
1594                  */
1595                 ai = fib_path_attached_next_hop_get_adj(
1596                          path,
1597                          fib_forw_chain_type_to_link_type(fct));
1598                 dpo_set(dpo, DPO_ADJACENCY,
1599                         fib_forw_chain_type_to_dpo_proto(fct), ai);
1600                 adj_unlock(ai);
1601
1602                 break;
1603             }
1604             }
1605             break;
1606         case FIB_PATH_TYPE_RECURSIVE:
1607             switch (fct)
1608             {
1609             case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
1610             case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
1611             case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
1612                 /*
1613                  * Assume that EOS and IP forwarding is the same.
1614                  * revisit for ieBGP
1615                  */
1616                 dpo_copy(dpo, &path->fp_dpo);
1617                 break;
1618             case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
1619                 fib_path_recursive_adj_update(path, fct, dpo);
1620                 break;
1621             case FIB_FORW_CHAIN_TYPE_ETHERNET:
1622                 ASSERT(0);
1623                 break;
1624             }
1625             break;
1626         case FIB_PATH_TYPE_DEAG:
1627             switch (fct)
1628             {
1629             case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
1630                 lookup_dpo_add_or_lock_w_table_id(MPLS_FIB_DEFAULT_TABLE_ID,
1631                                                   DPO_PROTO_MPLS,
1632                                                   LOOKUP_INPUT_DST_ADDR,
1633                                                   LOOKUP_TABLE_FROM_CONFIG,
1634                                                   dpo);
1635                 break;
1636             case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
1637             case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
1638             case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
1639                 dpo_copy(dpo, &path->fp_dpo);
1640                 break;          
1641             case FIB_FORW_CHAIN_TYPE_ETHERNET:
1642                 ASSERT(0);
1643                 break;
1644             }
1645             break;
1646         case FIB_PATH_TYPE_EXCLUSIVE:
1647             dpo_copy(dpo, &path->exclusive.fp_ex_dpo);
1648             break;
1649         case FIB_PATH_TYPE_ATTACHED:
1650         case FIB_PATH_TYPE_RECEIVE:
1651         case FIB_PATH_TYPE_SPECIAL:
1652             ASSERT(0);
1653             break;
1654         }
1655
1656     }
1657 }
1658
1659 load_balance_path_t *
1660 fib_path_append_nh_for_multipath_hash (fib_node_index_t path_index,
1661                                        fib_forward_chain_type_t fct,
1662                                        load_balance_path_t *hash_key)
1663 {
1664     load_balance_path_t *mnh;
1665     fib_path_t *path;
1666
1667     path = fib_path_get(path_index);
1668
1669     ASSERT(path);
1670
1671     if (fib_path_is_resolved(path_index))
1672     {
1673         vec_add2(hash_key, mnh, 1);
1674
1675         mnh->path_weight = path->fp_weight;
1676         mnh->path_index = path_index;
1677         fib_path_contribute_forwarding(path_index, fct, &mnh->path_dpo);
1678     }
1679
1680     return (hash_key);
1681 }
1682
1683 int
1684 fib_path_is_recursive (fib_node_index_t path_index)
1685 {
1686     fib_path_t *path;
1687
1688     path = fib_path_get(path_index);
1689
1690     return (FIB_PATH_TYPE_RECURSIVE == path->fp_type);
1691 }
1692
1693 int
1694 fib_path_is_exclusive (fib_node_index_t path_index)
1695 {
1696     fib_path_t *path;
1697
1698     path = fib_path_get(path_index);
1699
1700     return (FIB_PATH_TYPE_EXCLUSIVE == path->fp_type);
1701 }
1702
1703 int
1704 fib_path_is_deag (fib_node_index_t path_index)
1705 {
1706     fib_path_t *path;
1707
1708     path = fib_path_get(path_index);
1709
1710     return (FIB_PATH_TYPE_DEAG == path->fp_type);
1711 }
1712
1713 int
1714 fib_path_is_resolved (fib_node_index_t path_index)
1715 {
1716     fib_path_t *path;
1717
1718     path = fib_path_get(path_index);
1719
1720     return (dpo_id_is_valid(&path->fp_dpo) &&
1721             (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED) &&
1722             !fib_path_is_looped(path_index) &&
1723             !fib_path_is_permanent_drop(path));
1724 }
1725
1726 int
1727 fib_path_is_looped (fib_node_index_t path_index)
1728 {
1729     fib_path_t *path;
1730
1731     path = fib_path_get(path_index);
1732
1733     return (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP);
1734 }
1735
1736 void
1737 fib_path_module_init (void)
1738 {
1739     fib_node_register_type (FIB_NODE_TYPE_PATH, &fib_path_vft);
1740 }
1741
1742 static clib_error_t *
1743 show_fib_path_command (vlib_main_t * vm,
1744                         unformat_input_t * input,
1745                         vlib_cli_command_t * cmd)
1746 {
1747     fib_path_t *path;
1748
1749     vlib_cli_output (vm, "FIB Path Lists");
1750     pool_foreach(path, fib_path_pool,
1751     ({
1752         vlib_cli_output (vm, "%U", format_fib_path, path);
1753     }));
1754
1755     return (NULL);
1756 }
1757
1758 VLIB_CLI_COMMAND (show_fib_path, static) = {
1759   .path = "show fib paths",
1760   .function = show_fib_path_command,
1761   .short_help = "show fib paths",
1762 };