diff options
author | Neale Ranns <nranns@cisco.com> | 2017-05-18 03:03:22 -0700 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2017-05-23 09:48:52 +0000 |
commit | 8142499cd1cb3b8d0168d0e6cf5309c5b4813cc4 (patch) | |
tree | b6191c8b7417aa3a6865ec8b90837d852b90b539 /src/vnet/fib/fib_path_ext.c | |
parent | f3b53643e87e7521c57cccc157385d2fa4bd0d80 (diff) |
ARP/ND entries for the same address on different interfaces (VPP-848)
there are, intentionally, no validation checks in the ARP/ND code to prevent an ARP/ND entry from being installed for an address that is not local to the interface's sub-net. This is ok, since the adjacency/FIB code is designed to handle this case using the 'refinement' criteria - i.e. only installing a FIB entry for the address if the address 'refines' (i.e. is more specific than) the interface's sub-net.
However, the refinement criteria currently operates on the FIB entry's prefix (which is a /32, so on the address) and not on the next-hop in the path.
So, enter multiple ARP entries for the same address on different links, and this refinement criteria uses only the last added path, and so will remove the FIB entry should the ARP entries be added in the 'wrong' order.
This fix updates the refinement criteria to work on each path of the FIB entry. The entry is installed if one of the paths refines the covers and only paths refining the cover contribute forwarding.
Per-path refinement checks are stored in path-extensions. The patch is rather large as path-extension, which were previously used only for out-going MPLS labels, have been generalized.
Change-Id: I00be359148cb948c32c52109e832a70537a7920a
Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/fib/fib_path_ext.c')
-rw-r--r-- | src/vnet/fib/fib_path_ext.c | 213 |
1 files changed, 203 insertions, 10 deletions
diff --git a/src/vnet/fib/fib_path_ext.c b/src/vnet/fib/fib_path_ext.c index 08293bcf175..45ab1f1498d 100644 --- a/src/vnet/fib/fib_path_ext.c +++ b/src/vnet/fib/fib_path_ext.c @@ -24,6 +24,8 @@ #include <vnet/fib/fib_path_list.h> #include <vnet/fib/fib_internal.h> +const char *fib_path_ext_adj_flags_names[] = FIB_PATH_EXT_ADJ_ATTR_NAMES; + u8 * format_fib_path_ext (u8 * s, va_list * args) { @@ -32,13 +34,37 @@ format_fib_path_ext (u8 * s, va_list * args) path_ext = va_arg (*args, fib_path_ext_t *); - s = format(s, "path:%d labels:", - path_ext->fpe_path_index); - for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++) + s = format(s, "path:%d ", path_ext->fpe_path_index); + + switch (path_ext->fpe_type) { - s = format(s, "%U ", - format_mpls_unicast_label, - path_ext->fpe_path.frp_label_stack[ii]); + case FIB_PATH_EXT_MPLS: + s = format(s, "labels:", + path_ext->fpe_path_index); + for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++) + { + s = format(s, "%U ", + format_mpls_unicast_label, + path_ext->fpe_path.frp_label_stack[ii]); + } + break; + case FIB_PATH_EXT_ADJ: { + fib_path_ext_adj_attr_t attr; + + s = format(s, "adj-flags:"); + if (path_ext->fpe_adj_flags) + { + FOR_EACH_PATH_EXT_ADJ_ATTR(attr) + { + s = format(s, "%s", fib_path_ext_adj_flags_names[attr]); + } + } + else + { + s = format(s, "None"); + } + break; + } } return (s); } @@ -50,7 +76,7 @@ fib_path_ext_cmp (fib_path_ext_t *path_ext, return (fib_route_path_cmp(&path_ext->fpe_path, rpath)); } -static int +static fib_path_list_walk_rc_t fib_path_ext_match (fib_node_index_t pl_index, fib_node_index_t path_index, void *ctx) @@ -61,10 +87,9 @@ fib_path_ext_match (fib_node_index_t pl_index, &path_ext->fpe_path)) { path_ext->fpe_path_index = path_index; - return (0); + return (FIB_PATH_LIST_WALK_STOP); } - // keep going - return (1); + return (FIB_PATH_LIST_WALK_CONTINUE); } void @@ -83,10 +108,13 @@ fib_path_ext_resolve (fib_path_ext_t *path_ext, void fib_path_ext_init (fib_path_ext_t *path_ext, fib_node_index_t path_list_index, + fib_path_ext_type_t ext_type, const fib_route_path_t *rpath) { path_ext->fpe_path = *rpath; path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID; + path_ext->fpe_adj_flags = FIB_PATH_EXT_ADJ_FLAG_NONE; + path_ext->fpe_type = ext_type; fib_path_ext_resolve(path_ext, path_list_index); } @@ -229,3 +257,168 @@ fib_path_ext_stack (fib_path_ext_t *path_ext, return (nhs); } + +fib_path_ext_t * +fib_path_ext_list_find (const fib_path_ext_list_t *list, + fib_path_ext_type_t ext_type, + const fib_route_path_t *rpath) +{ + fib_path_ext_t *path_ext; + + vec_foreach(path_ext, list->fpel_exts) + { + if ((path_ext->fpe_type == ext_type) && + !fib_path_ext_cmp(path_ext, rpath) ) + { + return (path_ext); + } + } + return (NULL); +} + +fib_path_ext_t * +fib_path_ext_list_find_by_path_index (const fib_path_ext_list_t *list, + fib_node_index_t path_index) +{ + fib_path_ext_t *path_ext; + + vec_foreach(path_ext, list->fpel_exts) + { + if (path_ext->fpe_path_index == path_index) + { + return (path_ext); + } + } + return (NULL); +} + + +fib_path_ext_t * +fib_path_ext_list_push_back (fib_path_ext_list_t *list, + fib_node_index_t path_list_index, + fib_path_ext_type_t ext_type, + const fib_route_path_t *rpath) +{ + fib_path_ext_t *path_ext; + + path_ext = fib_path_ext_list_find(list, ext_type, rpath); + + if (NULL == path_ext) + { + vec_add2(list->fpel_exts, path_ext, 1); + fib_path_ext_init(path_ext, path_list_index, ext_type, rpath); + } + + return (path_ext); +} + +/* + * insert, sorted, a path extension to the entry's list. + * It's not strictly necessary to sort the path extensions, since each + * extension has the path index to which it resolves. However, by being + * sorted the load-balance produced has a deterministic order, not an order + * based on the sequence of extension additions. this is a considerable benefit. + */ +fib_path_ext_t * +fib_path_ext_list_insert (fib_path_ext_list_t *list, + fib_node_index_t path_list_index, + fib_path_ext_type_t ext_type, + const fib_route_path_t *rpath) +{ + fib_path_ext_t new_path_ext, *path_ext; + int i = 0; + + if (0 == fib_path_ext_list_length(list)) + { + return (fib_path_ext_list_push_back(list, path_list_index, + ext_type, rpath)); + } + + fib_path_ext_init(&new_path_ext, path_list_index, ext_type, rpath); + + vec_foreach(path_ext, list->fpel_exts) + { + if (fib_path_ext_cmp(path_ext, rpath) < 0) + { + i++; + } + else + { + break; + } + } + vec_insert_elts(list->fpel_exts, &new_path_ext, 1, i); + + return (&(list->fpel_exts[i])); +} + +void +fib_path_ext_list_resolve (fib_path_ext_list_t *list, + fib_node_index_t path_list_index) +{ + fib_path_ext_t *path_ext; + + vec_foreach(path_ext, list->fpel_exts) + { + fib_path_ext_resolve(path_ext, path_list_index); + }; +} + +void +fib_path_ext_list_remove (fib_path_ext_list_t *list, + fib_path_ext_type_t ext_type, + const fib_route_path_t *rpath) +{ + fib_path_ext_t *path_ext; + + path_ext = fib_path_ext_list_find(list, ext_type, rpath); + + if (NULL != path_ext) + { + /* + * delete the element moving the remaining elements down 1 position. + * this preserves the sorted order. + */ + vec_free(path_ext->fpe_label_stack); + vec_delete(list->fpel_exts, 1, (path_ext - list->fpel_exts)); + } +} + +void +fib_path_ext_list_flush (fib_path_ext_list_t *list) +{ + fib_path_ext_t *path_ext; + + vec_foreach(path_ext, list->fpel_exts) + { + vec_free(path_ext->fpe_label_stack); + }; + vec_free(list->fpel_exts); + list->fpel_exts = NULL; +} + +u8* +format_fib_path_ext_list (u8 * s, va_list * args) +{ + fib_path_ext_list_t *list; + fib_path_ext_t *path_ext; + + list = va_arg (*args, fib_path_ext_list_t *); + + if (fib_path_ext_list_length(list)) + { + s = format(s, " Extensions:"); + vec_foreach(path_ext, list->fpel_exts) + { + s = format(s, "\n %U", format_fib_path_ext, path_ext); + }; + } + + return (s); +} + +int +fib_path_ext_list_length (const fib_path_ext_list_t *list) +{ + return (vec_len(list->fpel_exts)); +} |