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