X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=vnet%2Fvnet%2Ffib%2Ffib_path.c;h=809e3e166daab077e2682137d6d88e5c8b524c34;hb=3a2a1c47bc1f319d1f46abd2a364b3cf82404405;hp=03cc7be5d9c3185d442e1e87611df72ea0704e63;hpb=6c3ebcc2bfd36a5835a99225ad667e4403293ffb;p=vpp.git diff --git a/vnet/vnet/fib/fib_path.c b/vnet/vnet/fib/fib_path.c index 03cc7be5d9c..809e3e166da 100644 --- a/vnet/vnet/fib/fib_path.c +++ b/vnet/vnet/fib/fib_path.c @@ -24,12 +24,13 @@ #include -#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 +#include +#include +#include +#include +#include +#include /** * Enurmeration of path types @@ -206,10 +207,17 @@ typedef struct fib_path_t_ { 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 @@ -236,7 +244,7 @@ typedef struct fib_path_t_ { } 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; @@ -427,11 +435,22 @@ format_fib_path (u8 * s, va_list * args) } 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, @@ -500,7 +519,7 @@ fib_path_last_lock_gone (fib_node_t *node) 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)) @@ -562,7 +581,7 @@ fib_path_recursive_adj_update (fib_path_t *path, 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 @@ -676,7 +695,7 @@ fib_path_unresolve (fib_path_t *path) { 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, @@ -756,6 +775,21 @@ fib_path_back_walk_notify (fib_node_t *node, 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: /* @@ -771,10 +805,24 @@ FIXME comment */ 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) @@ -793,8 +841,18 @@ FIXME comment /* * 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)); @@ -803,6 +861,32 @@ FIXME comment 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: @@ -870,7 +954,7 @@ static const fib_node_vft_t fib_path_vft = { 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; @@ -905,6 +989,14 @@ fib_path_create (fib_node_index_t pl_index, 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); @@ -951,7 +1043,14 @@ fib_path_create (fib_node_index_t pl_index, 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; } } @@ -1227,13 +1326,20 @@ fib_path_cmp_w_route_path (fib_node_index_t path_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); @@ -1432,7 +1538,14 @@ fib_path_resolve (fib_node_index_t path_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, @@ -1551,6 +1664,62 @@ fib_path_get_weight (fib_node_index_t path_index) 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, @@ -1590,7 +1759,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, 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, @@ -1609,12 +1778,6 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, 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; @@ -1733,6 +1896,59 @@ fib_path_is_looped (fib_node_index_t path_index) 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) { @@ -1744,13 +1960,36 @@ show_fib_path_command (vlib_main_t * vm, 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); }