A Protocol Independent Hierarchical FIB (VPP-352)
[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 /*
852  * The FIB path's graph node virtual function table
853  */
854 static const fib_node_vft_t fib_path_vft = {
855     .fnv_get = fib_path_get_node,
856     .fnv_last_lock = fib_path_last_lock_gone,
857     .fnv_back_walk = fib_path_back_walk_notify,
858 };
859
860 static fib_path_cfg_flags_t
861 fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
862 {
863     fib_path_cfg_flags_t cfg_flags = FIB_PATH_CFG_ATTRIBUTE_FIRST;
864
865     if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
866         cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_HOST;
867     if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED)
868         cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED;
869
870     return (cfg_flags);
871 }
872
873 /*
874  * fib_path_create
875  *
876  * Create and initialise a new path object.
877  * return the index of the path.
878  */
879 fib_node_index_t
880 fib_path_create (fib_node_index_t pl_index,
881                  fib_protocol_t nh_proto,
882                  fib_path_cfg_flags_t flags,
883                  const fib_route_path_t *rpath)
884 {
885     fib_path_t *path;
886
887     pool_get(fib_path_pool, path);
888     memset(path, 0, sizeof(*path));
889
890     fib_node_init(&path->fp_node,
891                   FIB_NODE_TYPE_PATH);
892
893     dpo_reset(&path->fp_dpo);
894     path->fp_pl_index = pl_index;
895     path->fp_nh_proto = nh_proto;
896     path->fp_via_fib = FIB_NODE_INDEX_INVALID;
897     path->fp_weight = rpath->frp_weight;
898     path->fp_cfg_flags = flags;
899     path->fp_cfg_flags |= fib_path_route_flags_to_cfg_flags(rpath);
900
901     /*
902      * deduce the path's tpye from the parementers and save what is needed.
903      */
904     if (~0 != rpath->frp_sw_if_index)
905     {
906         if (flags & FIB_PATH_CFG_FLAG_LOCAL)
907         {
908             path->fp_type = FIB_PATH_TYPE_RECEIVE;
909             path->receive.fp_interface = rpath->frp_sw_if_index;
910             path->receive.fp_addr = rpath->frp_addr;
911         }
912         else
913         {
914             if (ip46_address_is_zero(&rpath->frp_addr))
915             {
916                 path->fp_type = FIB_PATH_TYPE_ATTACHED;
917                 path->attached.fp_interface = rpath->frp_sw_if_index;
918             }
919             else
920             {
921                 path->fp_type = FIB_PATH_TYPE_ATTACHED_NEXT_HOP;
922                 path->attached_next_hop.fp_interface = rpath->frp_sw_if_index;
923                 path->attached_next_hop.fp_nh = rpath->frp_addr;
924             }
925         }
926     }
927     else
928     {
929         if (ip46_address_is_zero(&rpath->frp_addr))
930         {
931             if (~0 == rpath->frp_fib_index)
932             {
933                 path->fp_type = FIB_PATH_TYPE_SPECIAL;
934             }
935             else
936             {
937                 path->fp_type = FIB_PATH_TYPE_DEAG;
938                 path->deag.fp_tbl_id = rpath->frp_fib_index;
939             }           
940         }
941         else
942         {
943             path->fp_type = FIB_PATH_TYPE_RECURSIVE;
944             path->recursive.fp_nh = rpath->frp_addr;
945             path->recursive.fp_tbl_id = rpath->frp_fib_index;
946         }
947     }
948
949     FIB_PATH_DBG(path, "create");
950
951     return (fib_path_get_index(path));
952 }
953
954 /*
955  * fib_path_create_special
956  *
957  * Create and initialise a new path object.
958  * return the index of the path.
959  */
960 fib_node_index_t
961 fib_path_create_special (fib_node_index_t pl_index,
962                          fib_protocol_t nh_proto,
963                          fib_path_cfg_flags_t flags,
964                          const dpo_id_t *dpo)
965 {
966     fib_path_t *path;
967
968     pool_get(fib_path_pool, path);
969     memset(path, 0, sizeof(*path));
970
971     fib_node_init(&path->fp_node,
972                   FIB_NODE_TYPE_PATH);
973     dpo_reset(&path->fp_dpo);
974
975     path->fp_pl_index = pl_index;
976     path->fp_weight = 1;
977     path->fp_nh_proto = nh_proto;
978     path->fp_via_fib = FIB_NODE_INDEX_INVALID;
979     path->fp_cfg_flags = flags;
980
981     if (FIB_PATH_CFG_FLAG_DROP & flags)
982     {
983         path->fp_type = FIB_PATH_TYPE_SPECIAL;
984     }
985     else if (FIB_PATH_CFG_FLAG_LOCAL & flags)
986     {
987         path->fp_type = FIB_PATH_TYPE_RECEIVE;
988         path->attached.fp_interface = FIB_NODE_INDEX_INVALID;
989     }
990     else
991     {
992         path->fp_type = FIB_PATH_TYPE_EXCLUSIVE;
993         ASSERT(NULL != dpo);
994         dpo_copy(&path->exclusive.fp_ex_dpo, dpo);
995     }
996
997     return (fib_path_get_index(path));
998 }
999
1000 /*
1001  * fib_path_copy
1002  *
1003  * Copy a path. return index of new path.
1004  */
1005 fib_node_index_t
1006 fib_path_copy (fib_node_index_t path_index,
1007                fib_node_index_t path_list_index)
1008 {
1009     fib_path_t *path, *orig_path;
1010
1011     pool_get(fib_path_pool, path);
1012
1013     orig_path = fib_path_get(path_index);
1014     ASSERT(NULL != orig_path);
1015
1016     memcpy(path, orig_path, sizeof(*path));
1017
1018     FIB_PATH_DBG(path, "create-copy:%d", path_index);
1019
1020     /*
1021      * reset the dynamic section
1022      */
1023     fib_node_init(&path->fp_node, FIB_NODE_TYPE_PATH);
1024     path->fp_oper_flags     = FIB_PATH_OPER_FLAG_NONE;
1025     path->fp_pl_index  = path_list_index;
1026     path->fp_via_fib   = FIB_NODE_INDEX_INVALID;
1027     memset(&path->fp_dpo, 0, sizeof(path->fp_dpo));
1028     dpo_reset(&path->fp_dpo);
1029
1030     return (fib_path_get_index(path));
1031 }
1032
1033 /*
1034  * fib_path_destroy
1035  *
1036  * destroy a path that is no longer required
1037  */
1038 void
1039 fib_path_destroy (fib_node_index_t path_index)
1040 {
1041     fib_path_t *path;
1042
1043     path = fib_path_get(path_index);
1044
1045     ASSERT(NULL != path);
1046     FIB_PATH_DBG(path, "destroy");
1047
1048     fib_path_unresolve(path);
1049
1050     fib_node_deinit(&path->fp_node);
1051     pool_put(fib_path_pool, path);
1052 }
1053
1054 /*
1055  * fib_path_destroy
1056  *
1057  * destroy a path that is no longer required
1058  */
1059 uword
1060 fib_path_hash (fib_node_index_t path_index)
1061 {
1062     fib_path_t *path;
1063
1064     path = fib_path_get(path_index);
1065
1066     return (hash_memory(STRUCT_MARK_PTR(path, path_hash_start),
1067                         (STRUCT_OFFSET_OF(fib_path_t, path_hash_end) -
1068                          STRUCT_OFFSET_OF(fib_path_t, path_hash_start)),
1069                         0));
1070 }
1071
1072 /*
1073  * fib_path_cmp_i
1074  *
1075  * Compare two paths for equivalence.
1076  */
1077 static int
1078 fib_path_cmp_i (const fib_path_t *path1,
1079                 const fib_path_t *path2)
1080 {
1081     int res;
1082
1083     res = 1;
1084
1085     /*
1086      * paths of different types and protocol are not equal.
1087      * different weights only are the same path.
1088      */
1089     if (path1->fp_type != path2->fp_type)
1090     {
1091         res = (path1->fp_type - path2->fp_type);
1092     }
1093     if (path1->fp_nh_proto != path2->fp_nh_proto)
1094     {
1095         res = (path1->fp_nh_proto - path2->fp_nh_proto);
1096     }
1097     else
1098     {
1099         /*
1100          * both paths are of the same type.
1101          * consider each type and its attributes in turn.
1102          */
1103         switch (path1->fp_type)
1104         {
1105         case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1106             res = ip46_address_cmp(&path1->attached_next_hop.fp_nh,
1107                                    &path2->attached_next_hop.fp_nh);
1108             if (0 == res) {
1109                 res = vnet_sw_interface_compare(
1110                           vnet_get_main(),
1111                           path1->attached_next_hop.fp_interface,
1112                           path2->attached_next_hop.fp_interface);
1113             }
1114             break;
1115         case FIB_PATH_TYPE_ATTACHED:
1116             res = vnet_sw_interface_compare(
1117                       vnet_get_main(),
1118                       path1->attached.fp_interface,
1119                       path2->attached.fp_interface);
1120             break;
1121         case FIB_PATH_TYPE_RECURSIVE:
1122             res = ip46_address_cmp(&path1->recursive.fp_nh,
1123                                    &path2->recursive.fp_nh);
1124  
1125             if (0 == res)
1126             {
1127                 res = (path1->recursive.fp_tbl_id - path2->recursive.fp_tbl_id);
1128             }
1129             break;
1130         case FIB_PATH_TYPE_DEAG:
1131             res = (path1->deag.fp_tbl_id - path2->deag.fp_tbl_id);
1132             break;
1133         case FIB_PATH_TYPE_SPECIAL:
1134         case FIB_PATH_TYPE_RECEIVE:
1135         case FIB_PATH_TYPE_EXCLUSIVE:
1136             res = 0;
1137             break;
1138         }
1139     }
1140     return (res);
1141 }
1142
1143 /*
1144  * fib_path_cmp_for_sort
1145  *
1146  * Compare two paths for equivalence. Used during path sorting.
1147  * As usual 0 means equal.
1148  */
1149 int
1150 fib_path_cmp_for_sort (void * v1,
1151                        void * v2)
1152 {
1153     fib_node_index_t *pi1 = v1, *pi2 = v2;
1154     fib_path_t *path1, *path2;
1155
1156     path1 = fib_path_get(*pi1);
1157     path2 = fib_path_get(*pi2);
1158
1159     return (fib_path_cmp_i(path1, path2));
1160 }
1161
1162 /*
1163  * fib_path_cmp
1164  *
1165  * Compare two paths for equivalence.
1166  */
1167 int
1168 fib_path_cmp (fib_node_index_t pi1,
1169               fib_node_index_t pi2)
1170 {
1171     fib_path_t *path1, *path2;
1172
1173     path1 = fib_path_get(pi1);
1174     path2 = fib_path_get(pi2);
1175
1176     return (fib_path_cmp_i(path1, path2));
1177 }
1178
1179 int
1180 fib_path_cmp_w_route_path (fib_node_index_t path_index,
1181                            const fib_route_path_t *rpath)
1182 {
1183     fib_path_t *path;
1184     int res;
1185
1186     path = fib_path_get(path_index);
1187
1188     res = 1;
1189
1190     if (path->fp_weight != rpath->frp_weight)
1191     {
1192         res = (path->fp_weight - rpath->frp_weight);
1193     }
1194     else
1195     {
1196         /*
1197          * both paths are of the same type.
1198          * consider each type and its attributes in turn.
1199          */
1200         switch (path->fp_type)
1201         {
1202         case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1203             res = ip46_address_cmp(&path->attached_next_hop.fp_nh,
1204                                    &rpath->frp_addr);
1205             if (0 == res)
1206             {
1207                 res = vnet_sw_interface_compare(
1208                           vnet_get_main(),
1209                           path->attached_next_hop.fp_interface,
1210                           rpath->frp_sw_if_index);
1211             }
1212             break;
1213         case FIB_PATH_TYPE_ATTACHED:
1214             res = vnet_sw_interface_compare(
1215                       vnet_get_main(),
1216                       path->attached.fp_interface,
1217                       rpath->frp_sw_if_index);
1218             break;
1219         case FIB_PATH_TYPE_RECURSIVE:
1220             res = ip46_address_cmp(&path->recursive.fp_nh,
1221                                    &rpath->frp_addr);
1222  
1223             if (0 == res)
1224             {
1225                 res = (path->recursive.fp_tbl_id - rpath->frp_fib_index);
1226             }
1227             break;
1228         case FIB_PATH_TYPE_DEAG:
1229             res = (path->deag.fp_tbl_id - rpath->frp_fib_index);
1230             break;
1231         case FIB_PATH_TYPE_SPECIAL:
1232         case FIB_PATH_TYPE_RECEIVE:
1233         case FIB_PATH_TYPE_EXCLUSIVE:
1234             res = 0;
1235             break;
1236         }
1237     }
1238     return (res);
1239 }
1240
1241 /*
1242  * fib_path_recursive_loop_detect
1243  *
1244  * A forward walk of the FIB object graph to detect for a cycle/loop. This
1245  * walk is initiated when an entry is linking to a new path list or from an old.
1246  * The entry vector passed contains all the FIB entrys that are children of this
1247  * path (it is all the entries encountered on the walk so far). If this vector
1248  * contains the entry this path resolve via, then a loop is about to form.
1249  * The loop must be allowed to form, since we need the dependencies in place
1250  * so that we can track when the loop breaks.
1251  * However, we MUST not produce a loop in the forwarding graph (else packets
1252  * would loop around the switch path until the loop breaks), so we mark recursive
1253  * paths as looped so that they do not contribute forwarding information.
1254  * By marking the path as looped, an etry such as;
1255  *    X/Y
1256  *     via a.a.a.a (looped)
1257  *     via b.b.b.b (not looped)
1258  * can still forward using the info provided by b.b.b.b only
1259  */
1260 int
1261 fib_path_recursive_loop_detect (fib_node_index_t path_index,
1262                                 fib_node_index_t **entry_indicies)
1263 {
1264     fib_path_t *path;
1265
1266     path = fib_path_get(path_index);
1267
1268     /*
1269      * the forced drop path is never looped, cos it is never resolved.
1270      */
1271     if (fib_path_is_permanent_drop(path))
1272     {
1273         return (0);
1274     }
1275
1276     switch (path->fp_type)
1277     {
1278     case FIB_PATH_TYPE_RECURSIVE:
1279     {
1280         fib_node_index_t *entry_index, *entries;
1281         int looped = 0;
1282         entries = *entry_indicies;
1283
1284         vec_foreach(entry_index, entries) {
1285             if (*entry_index == path->fp_via_fib)
1286             {
1287                 /*
1288                  * the entry that is about to link to this path-list (or
1289                  * one of this path-list's children) is the same entry that
1290                  * this recursive path resolves through. this is a cycle.
1291                  * abort the walk.
1292                  */
1293                 looped = 1;
1294                 break;
1295             }
1296         }
1297
1298         if (looped)
1299         {
1300             FIB_PATH_DBG(path, "recursive loop formed");
1301             path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1302
1303             dpo_copy(&path->fp_dpo,
1304                     drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
1305         }
1306         else
1307         {
1308             /*
1309              * no loop here yet. keep forward walking the graph.
1310              */     
1311             if (fib_entry_recursive_loop_detect(path->fp_via_fib, entry_indicies))
1312             {
1313                 FIB_PATH_DBG(path, "recursive loop formed");
1314                 path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1315             }
1316             else
1317             {
1318                 FIB_PATH_DBG(path, "recursive loop cleared");
1319                 path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;
1320             }
1321         }
1322         break;
1323     }
1324     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1325     case FIB_PATH_TYPE_ATTACHED:
1326     case FIB_PATH_TYPE_SPECIAL:
1327     case FIB_PATH_TYPE_DEAG:
1328     case FIB_PATH_TYPE_RECEIVE:
1329     case FIB_PATH_TYPE_EXCLUSIVE:
1330         /*
1331          * these path types cannot be part of a loop, since they are the leaves
1332          * of the graph.
1333          */
1334         break;
1335     }
1336
1337     return (fib_path_is_looped(path_index));
1338 }
1339
1340 int
1341 fib_path_resolve (fib_node_index_t path_index)
1342 {
1343     fib_path_t *path;
1344
1345     path = fib_path_get(path_index);
1346
1347     /*
1348      * hope for the best.
1349      */
1350     path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
1351
1352     /*
1353      * the forced drop path resolves via the drop adj
1354      */
1355     if (fib_path_is_permanent_drop(path))
1356     {
1357         dpo_copy(&path->fp_dpo,
1358                  drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
1359         path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1360         return (fib_path_is_resolved(path_index));
1361     }
1362
1363     switch (path->fp_type)
1364     {
1365     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1366         fib_path_attached_next_hop_set(path);
1367         break;
1368     case FIB_PATH_TYPE_ATTACHED:
1369         /*
1370          * path->attached.fp_interface
1371          */
1372         if (!vnet_sw_interface_is_admin_up(vnet_get_main(),
1373                                            path->attached.fp_interface))
1374         {
1375             path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
1376         }
1377         if (vnet_sw_interface_is_p2p(vnet_get_main(),
1378                                      path->attached.fp_interface))
1379         {
1380             /*
1381              * point-2-point interfaces do not require a glean, since
1382              * there is nothing to ARP. Install a rewrite/nbr adj instead
1383              */
1384             dpo_set(&path->fp_dpo,
1385                     DPO_ADJACENCY,
1386                     fib_proto_to_dpo(path->fp_nh_proto),
1387                     adj_nbr_add_or_lock(
1388                         path->fp_nh_proto,
1389                         fib_proto_to_link(path->fp_nh_proto),
1390                         &zero_addr,
1391                         path->attached.fp_interface));
1392         }
1393         else
1394         {
1395             dpo_set(&path->fp_dpo,
1396                     DPO_ADJACENCY_GLEAN,
1397                     fib_proto_to_dpo(path->fp_nh_proto),
1398                     adj_glean_add_or_lock(path->fp_nh_proto,
1399                                           path->attached.fp_interface,
1400                                           NULL));
1401         }
1402         /*
1403          * become a child of the adjacency so we receive updates
1404          * when the interface state changes
1405          */
1406         path->fp_sibling = adj_child_add(path->fp_dpo.dpoi_index,
1407                                          FIB_NODE_TYPE_PATH,
1408                                          fib_path_get_index(path));
1409
1410         break;
1411     case FIB_PATH_TYPE_RECURSIVE:
1412     {
1413         /*
1414          * Create a RR source entry in the table for the address
1415          * that this path recurses through.
1416          * This resolve action is recursive, hence we may create
1417          * more paths in the process. more creates mean maybe realloc
1418          * of this path.
1419          */
1420         fib_node_index_t fei;
1421         fib_prefix_t pfx;
1422
1423         ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_fib);
1424
1425         fib_prefix_from_ip46_addr(&path->recursive.fp_nh, &pfx);
1426
1427         fei = fib_table_entry_special_add(path->recursive.fp_tbl_id,
1428                                           &pfx,
1429                                           FIB_SOURCE_RR,
1430                                           FIB_ENTRY_FLAG_NONE,
1431                                           ADJ_INDEX_INVALID);
1432
1433         path = fib_path_get(path_index);
1434         path->fp_via_fib = fei;
1435
1436         /*
1437          * become a dependent child of the entry so the path is 
1438          * informed when the forwarding for the entry changes.
1439          */
1440         path->fp_sibling = fib_entry_child_add(path->fp_via_fib,
1441                                                FIB_NODE_TYPE_PATH,
1442                                                fib_path_get_index(path));
1443
1444         /*
1445          * create and configure the IP DPO
1446          */
1447         fib_path_recursive_adj_update(
1448             path,
1449             fib_path_proto_to_chain_type(path->fp_nh_proto),
1450             &path->fp_dpo);
1451
1452         break;
1453     }
1454     case FIB_PATH_TYPE_SPECIAL:
1455         /*
1456          * Resolve via the drop
1457          */
1458         dpo_copy(&path->fp_dpo,
1459                  drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
1460         break;
1461     case FIB_PATH_TYPE_DEAG:
1462         /*
1463          * Resolve via a lookup DPO.
1464          * FIXME. control plane should add routes with a table ID
1465          */
1466         lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
1467                                           fib_proto_to_dpo(path->fp_nh_proto),
1468                                           LOOKUP_INPUT_DST_ADDR,
1469                                           LOOKUP_TABLE_FROM_CONFIG,
1470                                           &path->fp_dpo);
1471         break;
1472     case FIB_PATH_TYPE_RECEIVE:
1473         /*
1474          * Resolve via a receive DPO.
1475          */
1476         receive_dpo_add_or_lock(fib_proto_to_dpo(path->fp_nh_proto),
1477                                 path->receive.fp_interface,
1478                                 &path->receive.fp_addr,
1479                                 &path->fp_dpo);
1480         break;
1481     case FIB_PATH_TYPE_EXCLUSIVE:
1482         /*
1483          * Resolve via the user provided DPO
1484          */
1485         dpo_copy(&path->fp_dpo, &path->exclusive.fp_ex_dpo);
1486         break;
1487     }
1488
1489     return (fib_path_is_resolved(path_index));
1490 }
1491
1492 u32
1493 fib_path_get_resolving_interface (fib_node_index_t path_index)
1494 {
1495     fib_path_t *path;
1496
1497     path = fib_path_get(path_index);
1498
1499     switch (path->fp_type)
1500     {
1501     case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1502         return (path->attached_next_hop.fp_interface);
1503     case FIB_PATH_TYPE_ATTACHED:
1504         return (path->attached.fp_interface);
1505     case FIB_PATH_TYPE_RECEIVE:
1506         return (path->receive.fp_interface);
1507     case FIB_PATH_TYPE_RECURSIVE:
1508         return (fib_entry_get_resolving_interface(path->fp_via_fib));    
1509     case FIB_PATH_TYPE_SPECIAL:
1510     case FIB_PATH_TYPE_DEAG:
1511     case FIB_PATH_TYPE_EXCLUSIVE:
1512         break;
1513     }
1514     return (~0);
1515 }
1516
1517 adj_index_t
1518 fib_path_get_adj (fib_node_index_t path_index)
1519 {
1520     fib_path_t *path;
1521
1522     path = fib_path_get(path_index);
1523
1524     ASSERT(dpo_is_adj(&path->fp_dpo));
1525     if (dpo_is_adj(&path->fp_dpo))
1526     {
1527         return (path->fp_dpo.dpoi_index);
1528     }
1529     return (ADJ_INDEX_INVALID);
1530 }
1531
1532 int
1533 fib_path_get_weight (fib_node_index_t path_index)
1534 {
1535     fib_path_t *path;
1536
1537     path = fib_path_get(path_index);
1538
1539     ASSERT(path);
1540
1541     return (path->fp_weight);
1542 }
1543
1544 void
1545 fib_path_contribute_forwarding (fib_node_index_t path_index,
1546                                 fib_forward_chain_type_t fct,
1547                                 dpo_id_t *dpo)
1548 {
1549     fib_path_t *path;
1550
1551     path = fib_path_get(path_index);
1552
1553     ASSERT(path);
1554     ASSERT(FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct);
1555
1556     FIB_PATH_DBG(path, "contribute");
1557
1558     /*
1559      * The DPO stored in the path was created when the path was resolved.
1560      * This then represents the path's 'native' protocol; IP.
1561      * For all others will need to go find something else.
1562      */
1563     if (fib_path_proto_to_chain_type(path->fp_nh_proto) == fct)
1564     {
1565         dpo_copy(dpo, &path->fp_dpo);
1566     }
1567     else {
1568         switch (path->fp_type)
1569         {
1570         case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
1571             switch (fct)
1572             {
1573             case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
1574             case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
1575             case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
1576             case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
1577             {
1578                 adj_index_t ai;
1579
1580                 /*
1581                  * get a MPLS link type adj.
1582                  */
1583                 ai = fib_path_attached_next_hop_get_adj(
1584                          path,
1585                          fib_forw_chain_type_to_link_type(fct));
1586                 dpo_set(dpo, DPO_ADJACENCY,
1587                         fib_forw_chain_type_to_dpo_proto(fct), ai);
1588                 adj_unlock(ai);
1589
1590                 break;
1591             }
1592             }
1593             break;
1594         case FIB_PATH_TYPE_RECURSIVE:
1595             switch (fct)
1596             {
1597             case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
1598             case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
1599             case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
1600                 /*
1601                  * Assume that EOS and IP forwarding is the same.
1602                  * revisit for ieBGP
1603                  */
1604                 dpo_copy(dpo, &path->fp_dpo);
1605                 break;
1606             case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
1607                 fib_path_recursive_adj_update(path, fct, dpo);
1608                 break;
1609             }
1610             break;
1611         case FIB_PATH_TYPE_DEAG:
1612             switch (fct)
1613             {
1614             case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
1615                 lookup_dpo_add_or_lock_w_table_id(MPLS_FIB_DEFAULT_TABLE_ID,
1616                                                   DPO_PROTO_MPLS,
1617                                                   LOOKUP_INPUT_DST_ADDR,
1618                                                   LOOKUP_TABLE_FROM_CONFIG,
1619                                                   dpo);
1620                 break;
1621             case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
1622             case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
1623             case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
1624                 dpo_copy(dpo, &path->fp_dpo);
1625                 break;          
1626             }
1627             break;
1628         case FIB_PATH_TYPE_EXCLUSIVE:
1629             dpo_copy(dpo, &path->exclusive.fp_ex_dpo);
1630             break;
1631         case FIB_PATH_TYPE_ATTACHED:
1632         case FIB_PATH_TYPE_RECEIVE:
1633         case FIB_PATH_TYPE_SPECIAL:
1634             ASSERT(0);
1635             break;
1636         }
1637
1638     }
1639 }
1640
1641 load_balance_path_t *
1642 fib_path_append_nh_for_multipath_hash (fib_node_index_t path_index,
1643                                        fib_forward_chain_type_t fct,
1644                                        load_balance_path_t *hash_key)
1645 {
1646     load_balance_path_t *mnh;
1647     fib_path_t *path;
1648
1649     path = fib_path_get(path_index);
1650
1651     ASSERT(path);
1652
1653     if (fib_path_is_resolved(path_index))
1654     {
1655         vec_add2(hash_key, mnh, 1);
1656
1657         mnh->path_weight = path->fp_weight;
1658         mnh->path_index = path_index;
1659         dpo_copy(&mnh->path_dpo, &path->fp_dpo);
1660     }
1661
1662     return (hash_key);
1663 }
1664
1665 int
1666 fib_path_is_recursive (fib_node_index_t path_index)
1667 {
1668     fib_path_t *path;
1669
1670     path = fib_path_get(path_index);
1671
1672     return (FIB_PATH_TYPE_RECURSIVE == path->fp_type);
1673 }
1674
1675 int
1676 fib_path_is_exclusive (fib_node_index_t path_index)
1677 {
1678     fib_path_t *path;
1679
1680     path = fib_path_get(path_index);
1681
1682     return (FIB_PATH_TYPE_EXCLUSIVE == path->fp_type);
1683 }
1684
1685 int
1686 fib_path_is_deag (fib_node_index_t path_index)
1687 {
1688     fib_path_t *path;
1689
1690     path = fib_path_get(path_index);
1691
1692     return (FIB_PATH_TYPE_DEAG == path->fp_type);
1693 }
1694
1695 int
1696 fib_path_is_resolved (fib_node_index_t path_index)
1697 {
1698     fib_path_t *path;
1699
1700     path = fib_path_get(path_index);
1701
1702     return (dpo_id_is_valid(&path->fp_dpo) &&
1703             (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED) &&
1704             !fib_path_is_looped(path_index) &&
1705             !fib_path_is_permanent_drop(path));
1706 }
1707
1708 int
1709 fib_path_is_looped (fib_node_index_t path_index)
1710 {
1711     fib_path_t *path;
1712
1713     path = fib_path_get(path_index);
1714
1715     return (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP);
1716 }
1717
1718 void
1719 fib_path_module_init (void)
1720 {
1721     fib_node_register_type (FIB_NODE_TYPE_PATH, &fib_path_vft);
1722 }
1723
1724 static clib_error_t *
1725 show_fib_path_command (vlib_main_t * vm,
1726                         unformat_input_t * input,
1727                         vlib_cli_command_t * cmd)
1728 {
1729     fib_path_t *path;
1730
1731     vlib_cli_output (vm, "FIB Path Lists");
1732     pool_foreach(path, fib_path_pool,
1733     ({
1734         vlib_cli_output (vm, "%U", format_fib_path, path);
1735     }));
1736
1737     return (NULL);
1738 }
1739
1740 VLIB_CLI_COMMAND (show_fib_path, static) = {
1741   .path = "show fib paths",
1742   .function = show_fib_path_command,
1743   .short_help = "show fib paths",
1744 };