#include <vnet/adj/adj.h>
-#include "fib_path.h"
-#include "fib_node.h"
-#include "fib_table.h"
-#include "fib_entry.h"
-#include "fib_path_list.h"
-#include "fib_internal.h"
+#include <vnet/fib/fib_path.h>
+#include <vnet/fib/fib_node.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_path_list.h>
+#include <vnet/fib/fib_internal.h>
+#include <vnet/fib/fib_urpf_list.h>
/**
* Enurmeration of path types
u32 fp_interface;
} attached;
struct {
- /**
- * The next-hop
- */
- ip46_address_t fp_nh;
+ union
+ {
+ /**
+ * The next-hop
+ */
+ ip46_address_t fp_ip;
+ /**
+ * The local label to resolve through.
+ */
+ mpls_label_t fp_local_label;
+ } fp_nh;
/**
* The FIB table index in which to find the next-hop.
* This needs to be fixed. We should lookup the adjacencies in
} recursive;
struct {
/**
- * The FIN index in which to perfom the next lookup
+ * The FIB index in which to perfom the next lookup
*/
fib_node_index_t fp_tbl_id;
} deag;
}
break;
case FIB_PATH_TYPE_RECURSIVE:
- s = format (s, "via %U",
- format_ip46_address,
- &path->recursive.fp_nh,
- IP46_TYPE_ANY);
- s = format (s, " in fib:%d", path->recursive.fp_tbl_id, path->fp_via_fib);
+ if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
+ {
+ s = format (s, "via %U",
+ format_mpls_unicast_label,
+ path->recursive.fp_nh.fp_local_label);
+ }
+ else
+ {
+ s = format (s, "via %U",
+ format_ip46_address,
+ &path->recursive.fp_nh.fp_ip,
+ IP46_TYPE_ANY);
+ }
+ s = format (s, " in fib:%d",
+ path->recursive.fp_tbl_id,
+ path->fp_via_fib);
s = format (s, " via-fib:%d", path->fp_via_fib);
s = format (s, " via-dpo:[%U:%d]",
format_dpo_type, path->fp_dpo.dpoi_type,
static const adj_index_t
fib_path_attached_next_hop_get_adj (fib_path_t *path,
- fib_link_t link)
+ vnet_link_t link)
{
if (vnet_sw_interface_is_p2p(vnet_get_main(),
path->attached_next_hop.fp_interface))
fib_forward_chain_type_t fct,
dpo_id_t *dpo)
{
- dpo_id_t via_dpo = DPO_NULL;
+ dpo_id_t via_dpo = DPO_INVALID;
/*
* get the DPO to resolve through from the via-entry
{
fib_prefix_t pfx;
- fib_prefix_from_ip46_addr(&path->recursive.fp_nh, &pfx);
+ fib_entry_get_prefix(path->fp_via_fib, &pfx);
fib_entry_child_remove(path->fp_via_fib,
path->fp_sibling);
fib_table_entry_special_remove(path->recursive.fp_tbl_id,
fib_path_proto_to_chain_type(path->fp_nh_proto),
&path->fp_dpo);
}
+ if ((FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason) ||
+ (FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason))
+ {
+ /*
+ * ADJ updates (complete<->incomplete) do not need to propagate to
+ * recursive entries.
+ * The only reason its needed as far back as here, is that the adj
+ * and the incomplete adj are a different DPO type, so the LBs need
+ * to re-stack.
+ * If this walk was quashed in the fib_entry, then any non-fib_path
+ * children (like tunnels that collapse out the LB when they stack)
+ * would not see the update.
+ */
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+ }
break;
case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
/*
*/
if (FIB_NODE_BW_REASON_FLAG_INTERFACE_UP & ctx->fnbw_reason)
{
+ if (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED)
+ {
+ /*
+ * alreday resolved. no need to walk back again
+ */
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+ }
path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
}
if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN & ctx->fnbw_reason)
{
+ if (!(path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED))
+ {
+ /*
+ * alreday unresolved. no need to walk back again
+ */
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+ }
path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
}
if (FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE & ctx->fnbw_reason)
/*
* restack the DPO to pick up the correct DPO sub-type
*/
+ uword if_is_up;
adj_index_t ai;
+ if_is_up = vnet_sw_interface_is_admin_up(
+ vnet_get_main(),
+ path->attached_next_hop.fp_interface);
+
+ if (if_is_up)
+ {
+ path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED;
+ }
+
ai = fib_path_attached_next_hop_get_adj(
path,
fib_proto_to_link(path->fp_nh_proto));
fib_proto_to_dpo(path->fp_nh_proto),
ai);
adj_unlock(ai);
+
+ if (!if_is_up)
+ {
+ /*
+ * If the interface is not up there is no reason to walk
+ * back to children. if we did they would only evalute
+ * that this path is unresolved and hence it would
+ * not contribute the adjacency - so it would be wasted
+ * CPU time.
+ */
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+ }
+ }
+ if (FIB_NODE_BW_REASON_FLAG_ADJ_DOWN & ctx->fnbw_reason)
+ {
+ if (!(path->fp_oper_flags & FIB_PATH_OPER_FLAG_RESOLVED))
+ {
+ /*
+ * alreday unresolved. no need to walk back again
+ */
+ return (FIB_NODE_BACK_WALK_CONTINUE);
+ }
+ /*
+ * the adj has gone down. the path is no longer resolved.
+ */
+ path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED;
}
break;
case FIB_PATH_TYPE_ATTACHED:
static fib_path_cfg_flags_t
fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
{
- fib_path_cfg_flags_t cfg_flags = FIB_PATH_CFG_ATTRIBUTE_FIRST;
+ fib_path_cfg_flags_t cfg_flags = FIB_PATH_CFG_FLAG_NONE;
if (rpath->frp_flags & FIB_ROUTE_PATH_RESOLVE_VIA_HOST)
cfg_flags |= FIB_PATH_CFG_FLAG_RESOLVE_HOST;
path->fp_nh_proto = nh_proto;
path->fp_via_fib = FIB_NODE_INDEX_INVALID;
path->fp_weight = rpath->frp_weight;
+ if (0 == path->fp_weight)
+ {
+ /*
+ * a weight of 0 is a meaningless value. We could either reject it, and thus force
+ * clients to always use 1, or we can accept it and fixup approrpiately.
+ */
+ path->fp_weight = 1;
+ }
path->fp_cfg_flags = flags;
path->fp_cfg_flags |= fib_path_route_flags_to_cfg_flags(rpath);
else
{
path->fp_type = FIB_PATH_TYPE_RECURSIVE;
- path->recursive.fp_nh = rpath->frp_addr;
+ if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
+ {
+ path->recursive.fp_nh.fp_local_label = rpath->frp_local_label;
+ }
+ else
+ {
+ path->recursive.fp_nh.fp_ip = rpath->frp_addr;
+ }
path->recursive.fp_tbl_id = rpath->frp_fib_index;
}
}
rpath->frp_sw_if_index);
break;
case FIB_PATH_TYPE_RECURSIVE:
- res = ip46_address_cmp(&path->recursive.fp_nh,
- &rpath->frp_addr);
-
- if (0 == res)
- {
- res = (path->recursive.fp_tbl_id - rpath->frp_fib_index);
- }
+ if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
+ {
+ res = path->recursive.fp_nh.fp_local_label - rpath->frp_local_label;
+ }
+ else
+ {
+ res = ip46_address_cmp(&path->recursive.fp_nh.fp_ip,
+ &rpath->frp_addr);
+ }
+
+ if (0 == res)
+ {
+ res = (path->recursive.fp_tbl_id - rpath->frp_fib_index);
+ }
break;
case FIB_PATH_TYPE_DEAG:
res = (path->deag.fp_tbl_id - rpath->frp_fib_index);
ASSERT(FIB_NODE_INDEX_INVALID == path->fp_via_fib);
- fib_prefix_from_ip46_addr(&path->recursive.fp_nh, &pfx);
+ if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
+ {
+ fib_prefix_from_mpls_label(path->recursive.fp_nh.fp_local_label, &pfx);
+ }
+ else
+ {
+ fib_prefix_from_ip46_addr(&path->recursive.fp_nh.fp_ip, &pfx);
+ }
fei = fib_table_entry_special_add(path->recursive.fp_tbl_id,
&pfx,
return (path->fp_weight);
}
+/**
+ * @brief Contribute the path's adjacency to the list passed.
+ * By calling this function over all paths, recursively, a child
+ * can construct its full set of forwarding adjacencies, and hence its
+ * uRPF list.
+ */
+void
+fib_path_contribute_urpf (fib_node_index_t path_index,
+ index_t urpf)
+{
+ fib_path_t *path;
+
+ if (!fib_path_is_resolved(path_index))
+ return;
+
+ path = fib_path_get(path_index);
+
+ switch (path->fp_type)
+ {
+ case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
+ fib_urpf_list_append(urpf, path->attached_next_hop.fp_interface);
+ break;
+
+ case FIB_PATH_TYPE_ATTACHED:
+ fib_urpf_list_append(urpf, path->attached.fp_interface);
+ break;
+
+ case FIB_PATH_TYPE_RECURSIVE:
+ fib_entry_contribute_urpf(path->fp_via_fib, urpf);
+ break;
+
+ case FIB_PATH_TYPE_EXCLUSIVE:
+ case FIB_PATH_TYPE_SPECIAL:
+ /*
+ * these path types may link to an adj, if that's what
+ * the clinet gave
+ */
+ if (dpo_is_adj(&path->fp_dpo))
+ {
+ ip_adjacency_t *adj;
+
+ adj = adj_get(path->fp_dpo.dpoi_index);
+
+ fib_urpf_list_append(urpf, adj->rewrite_header.sw_if_index);
+ }
+ break;
+
+ case FIB_PATH_TYPE_DEAG:
+ case FIB_PATH_TYPE_RECEIVE:
+ /*
+ * these path types don't link to an adj
+ */
+ break;
+ }
+}
+
void
fib_path_contribute_forwarding (fib_node_index_t path_index,
fib_forward_chain_type_t fct,
adj_index_t ai;
/*
- * get a MPLS link type adj.
+ * get a appropriate link type adj.
*/
ai = fib_path_attached_next_hop_get_adj(
path,
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
- /*
- * Assume that EOS and IP forwarding is the same.
- * revisit for ieBGP
- */
- dpo_copy(dpo, &path->fp_dpo);
- break;
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
fib_path_recursive_adj_update(path, fct, dpo);
break;
return (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP);
}
+int
+fib_path_encode (fib_node_index_t path_list_index,
+ fib_node_index_t path_index,
+ void *ctx)
+{
+ fib_route_path_encode_t **api_rpaths = ctx;
+ fib_route_path_encode_t *api_rpath;
+ fib_path_t *path;
+
+ path = fib_path_get(path_index);
+ if (!path)
+ return (0);
+ vec_add2(*api_rpaths, api_rpath, 1);
+ api_rpath->rpath.frp_weight = path->fp_weight;
+ api_rpath->rpath.frp_proto = path->fp_nh_proto;
+ api_rpath->rpath.frp_sw_if_index = ~0;
+ api_rpath->dpo = path->exclusive.fp_ex_dpo;
+ switch (path->fp_type)
+ {
+ case FIB_PATH_TYPE_RECEIVE:
+ api_rpath->rpath.frp_addr = path->receive.fp_addr;
+ api_rpath->rpath.frp_sw_if_index = path->receive.fp_interface;
+ break;
+ case FIB_PATH_TYPE_ATTACHED:
+ api_rpath->rpath.frp_sw_if_index = path->attached.fp_interface;
+ break;
+ case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
+ api_rpath->rpath.frp_sw_if_index = path->attached_next_hop.fp_interface;
+ api_rpath->rpath.frp_addr = path->attached_next_hop.fp_nh;
+ break;
+ case FIB_PATH_TYPE_SPECIAL:
+ break;
+ case FIB_PATH_TYPE_DEAG:
+ break;
+ case FIB_PATH_TYPE_RECURSIVE:
+ api_rpath->rpath.frp_addr = path->recursive.fp_nh.fp_ip;
+ break;
+ default:
+ break;
+ }
+ return (1);
+}
+
+fib_protocol_t
+fib_path_get_proto (fib_node_index_t path_index)
+{
+ fib_path_t *path;
+
+ path = fib_path_get(path_index);
+
+ return (path->fp_nh_proto);
+}
+
void
fib_path_module_init (void)
{
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
+ fib_node_index_t pi;
fib_path_t *path;
- vlib_cli_output (vm, "FIB Path Lists");
- pool_foreach(path, fib_path_pool,
- ({
- vlib_cli_output (vm, "%U", format_fib_path, path);
- }));
+ if (unformat (input, "%d", &pi))
+ {
+ /*
+ * show one in detail
+ */
+ if (!pool_is_free_index(fib_path_pool, pi))
+ {
+ path = fib_path_get(pi);
+ u8 *s = fib_path_format(pi, NULL);
+ s = format(s, "children:");
+ s = fib_node_children_format(path->fp_node.fn_children, s);
+ vlib_cli_output (vm, "%s", s);
+ vec_free(s);
+ }
+ else
+ {
+ vlib_cli_output (vm, "path %d invalid", pi);
+ }
+ }
+ else
+ {
+ vlib_cli_output (vm, "FIB Paths");
+ pool_foreach(path, fib_path_pool,
+ ({
+ vlib_cli_output (vm, "%U", format_fib_path, path);
+ }));
+ }
return (NULL);
}