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>
diff --git a/src/vnet/fib/fib_path_ext.h b/src/vnet/fib/fib_path_ext.h
index d617700..d1571a1 100644
--- a/src/vnet/fib/fib_path_ext.h
+++ b/src/vnet/fib/fib_path_ext.h
@@ -21,6 +21,45 @@
#include <vnet/dpo/load_balance.h>
/**
+ * A description of the type of path extension
+ */
+typedef enum fib_path_ext_type_t_
+{
+ /**
+ * An MPLS extension that maintains the path's outgoing labels,
+ */
+ FIB_PATH_EXT_MPLS,
+ /**
+ * A adj-source extension indicating the path's refinement criteria
+ * result
+ */
+ FIB_PATH_EXT_ADJ,
+} fib_path_ext_type_t;
+
+/**
+ * Flags present on an ADJ sourced path-extension
+ */
+typedef enum fib_path_ext_adj_attr_t_
+{
+ FIB_PATH_EXT_ADJ_ATTR_REFINES_COVER,
+} fib_path_ext_adj_attr_t;
+
+typedef enum fib_path_ext_adj_flags_t_
+{
+ FIB_PATH_EXT_ADJ_FLAG_NONE = 0,
+ FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER = (1 << FIB_PATH_EXT_ADJ_ATTR_REFINES_COVER),
+} fib_path_ext_adj_flags_t;
+
+#define FIB_PATH_EXT_ADJ_ATTR_NAMES { \
+ [FIB_PATH_EXT_ADJ_ATTR_REFINES_COVER] = "refines-cover", \
+}
+
+#define FOR_EACH_PATH_EXT_ADJ_ATTR(_item) \
+ for (_item = FIB_PATH_EXT_ADJ_ATTR_REFINES_COVER; \
+ _item <= FIB_PATH_EXT_ADJ_ATTR_REFINES_COVER; \
+ _item++)
+
+/**
* A path extension is a per-entry addition to the forwarding information
* when packets are sent for that entry over that path.
*
@@ -33,6 +72,11 @@
typedef struct fib_path_ext_t_
{
/**
+ * The type of path extension
+ */
+ fib_path_ext_type_t fpe_type;
+
+ /**
* A description of the path that is being extended.
* This description is used to match this extension with the [changing]
* instance of a fib_path_t that is extended
@@ -40,21 +84,24 @@
fib_route_path_t fpe_path;
#define fpe_label_stack fpe_path.frp_label_stack
+ union {
+ /**
+ * For an ADJ type extension
+ *
+ * Flags describing the adj state
+ */
+ fib_path_ext_adj_flags_t fpe_adj_flags;
+ };
+
/**
* The index of the path. This is the global index, not the path's
* position in the path-list.
*/
fib_node_index_t fpe_path_index;
-} fib_path_ext_t;
-
-struct fib_entry_t_;
+} __attribute__ ((packed)) fib_path_ext_t;
extern u8 * format_fib_path_ext(u8 * s, va_list * args);
-extern void fib_path_ext_init(fib_path_ext_t *path_ext,
- fib_node_index_t path_list_index,
- const fib_route_path_t *rpath);
-
extern int fib_path_ext_cmp(fib_path_ext_t *path_ext,
const fib_route_path_t *rpath);
@@ -66,5 +113,32 @@
fib_forward_chain_type_t imp_null_fct,
load_balance_path_t *nhs);
+extern 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);
+
+extern 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);
+
+extern u8* format_fib_path_ext_list (u8 * s, va_list * args);
+
+extern 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);
+
+extern 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);
+extern 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);
+extern void fib_path_ext_list_resolve(fib_path_ext_list_t *list,
+ fib_node_index_t path_list_index);
+
+extern int fib_path_ext_list_length(const fib_path_ext_list_t *list);
+extern void fib_path_ext_list_flush(fib_path_ext_list_t *list);
+
#endif