summaryrefslogtreecommitdiffstats
path: root/src/vnet/fib
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/fib')
-rw-r--r--src/vnet/fib/fib_entry_src_rr.c78
-rw-r--r--src/vnet/fib/fib_path.c11
-rw-r--r--src/vnet/fib/fib_test.c30
3 files changed, 81 insertions, 38 deletions
diff --git a/src/vnet/fib/fib_entry_src_rr.c b/src/vnet/fib/fib_entry_src_rr.c
index c145aaa2915..d66ef7b1108 100644
--- a/src/vnet/fib/fib_entry_src_rr.c
+++ b/src/vnet/fib/fib_entry_src_rr.c
@@ -69,6 +69,47 @@ fib_entry_src_rr_init (fib_entry_src_t *src)
src->rr.fesr_sibling = FIB_NODE_INDEX_INVALID;
}
+
+/*
+ * use the path-list of the cover, unless it would form a loop.
+ * that is unless the cover is via this entry.
+ * If a loop were to form it would be a 1 level loop (i.e. X via X),
+ * and there would be 2 locks on the path-list; one since its used
+ * by the cover, and 1 from here. The first lock will go when the
+ * cover is removed, the second, and last, when the covered walk
+ * occurs during the cover's removel - this is not a place where
+ * we can handle last lock gone.
+ * In short, don't let the loop form. The usual rules of 'we must
+ * let it form so we know when it breaks' don't apply here, since
+ * the loop will break when the cover changes, and this function
+ * will be called again when that happens.
+ */
+static void
+fib_entry_src_rr_use_covers_pl (fib_entry_src_t *src,
+ const fib_entry_t *fib_entry,
+ const fib_entry_t *cover)
+{
+ fib_node_index_t *entries = NULL;
+ fib_protocol_t proto;
+
+ proto = fib_entry->fe_prefix.fp_proto;
+ vec_add1(entries, fib_entry_get_index(fib_entry));
+
+ if (fib_path_list_recursive_loop_detect(cover->fe_parent,
+ &entries))
+ {
+ src->fes_pl = fib_path_list_create_special(
+ proto,
+ FIB_PATH_LIST_FLAG_DROP,
+ drop_dpo_get(fib_proto_to_dpo(proto)));
+ }
+ else
+ {
+ src->fes_pl = cover->fe_parent;
+ }
+ vec_free(entries);
+}
+
/*
* Source activation. Called when the source is the new best source on the entry
*/
@@ -112,40 +153,7 @@ fib_entry_src_rr_activate (fib_entry_src_t *src,
}
else
{
- /*
- * use the path-list of the cover, unless it would form a loop.
- * that is unless the cover is via this entry.
- * If a loop were to form it would be a 1 level loop (i.e. X via X),
- * and there would be 2 locks on the path-list; one since its used
- * by the cover, and 1 from here. The first lock will go when the
- * cover is removed, the second, and last, when the covered walk
- * occurs during the cover's removel - this is not a place where
- * we can handle last lock gone.
- * In short, don't let the loop form. The usual rules of 'we must
- * let it form so we know when it breaks' don't apply here, since
- * the loop will break when the cover changes, and this function
- * will be called again when that happens.
- */
- fib_node_index_t *entries = NULL;
- fib_protocol_t proto;
-
- proto = fib_entry->fe_prefix.fp_proto;
- vec_add1(entries, fib_entry_get_index(fib_entry));
-
- if (fib_path_list_recursive_loop_detect(cover->fe_parent,
- &entries))
- {
- src->fes_pl = fib_path_list_create_special(
- proto,
- FIB_PATH_LIST_FLAG_DROP,
- drop_dpo_get(fib_proto_to_dpo(proto)));
- }
- else
- {
- src->fes_pl = cover->fe_parent;
- }
- vec_free(entries);
-
+ fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
}
fib_path_list_lock(src->fes_pl);
@@ -256,7 +264,7 @@ fib_entry_src_rr_cover_update (fib_entry_src_t *src,
}
else
{
- src->fes_pl = cover->fe_parent;
+ fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
}
fib_path_list_lock(src->fes_pl);
fib_path_list_unlock(old_path_list);
diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c
index 889317fd83c..b47d51f8d51 100644
--- a/src/vnet/fib/fib_path.c
+++ b/src/vnet/fib/fib_path.c
@@ -1716,7 +1716,11 @@ fib_path_get_resolving_interface (fib_node_index_t path_index)
case FIB_PATH_TYPE_RECEIVE:
return (path->receive.fp_interface);
case FIB_PATH_TYPE_RECURSIVE:
- return (fib_entry_get_resolving_interface(path->fp_via_fib));
+ if (fib_path_is_resolved(path_index))
+ {
+ return (fib_entry_get_resolving_interface(path->fp_via_fib));
+ }
+ break;
case FIB_PATH_TYPE_INTF_RX:
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_DEAG:
@@ -1781,11 +1785,12 @@ fib_path_contribute_urpf (fib_node_index_t path_index,
break;
case FIB_PATH_TYPE_RECURSIVE:
- if (FIB_NODE_INDEX_INVALID != path->fp_via_fib)
+ if (FIB_NODE_INDEX_INVALID != path->fp_via_fib &&
+ !fib_path_is_looped(path_index))
{
/*
* there's unresolved due to constraints, and there's unresolved
- * due to ain't go no via. can't do nowt w'out via.
+ * due to ain't got no via. can't do nowt w'out via.
*/
fib_entry_contribute_urpf(path->fp_via_fib, urpf);
}
diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c
index ddea6b86e7e..486e5616798 100644
--- a/src/vnet/fib/fib_test.c
+++ b/src/vnet/fib/fib_test.c
@@ -2977,6 +2977,36 @@ fib_test_v4 (void)
fib_entry_pool_size());
/*
+ * Make the default route recursive via a unknown next-hop. Thus the
+ * next hop's cover would be the default route
+ */
+ fei = fib_table_entry_path_add(fib_index,
+ &pfx_0_0_0_0_s_0,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_NONE,
+ FIB_PROTOCOL_IP4,
+ &pfx_23_23_23_23_s_32.fp_addr,
+ ~0, // recursive
+ fib_index,
+ 1,
+ NULL,
+ FIB_ROUTE_PATH_FLAG_NONE);
+ dpo = fib_entry_contribute_ip_forwarding(fei);
+ FIB_TEST(load_balance_is_drop(dpo),
+ "0.0.0.0.0/0 via is DROP");
+ FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
+ "no resolving interface for looped 0.0.0.0/0");
+
+ fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
+ dpo = fib_entry_contribute_ip_forwarding(fei);
+ FIB_TEST(load_balance_is_drop(dpo),
+ "23.23.23.23/32 via is DROP");
+ FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
+ "no resolving interface for looped 23.23.23.23/32");
+
+ fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
+
+ /*
* A recursive route with recursion constraints.
* 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
*/
mpls.h> #include <vnet/fib/fib_path_ext.h> typedef enum mpls_tunnel_attribute_t_ { MPLS_TUNNEL_ATTRIBUTE_FIRST = 0, /** * @brief The tunnel is L2 only */ MPLS_TUNNEL_ATTRIBUTE_L2 = MPLS_TUNNEL_ATTRIBUTE_FIRST, /** * @brief The tunnel has an underlying multicast LSP */ MPLS_TUNNEL_ATTRIBUTE_MCAST, MPLS_TUNNEL_ATTRIBUTE_LAST = MPLS_TUNNEL_ATTRIBUTE_MCAST, } mpls_tunnel_attribute_t; #define MPLS_TUNNEL_ATTRIBUTES { \ [MPLS_TUNNEL_ATTRIBUTE_MCAST] = "multicast", \ [MPLS_TUNNEL_ATTRIBUTE_L2] = "L2", \ } #define FOR_EACH_MPLS_TUNNEL_ATTRIBUTE(_item) \ for (_item = MPLS_TUNNEL_ATTRIBUTE_FIRST; \ _item <= MPLS_TUNNEL_ATTRIBUTE_LAST; \ _item++) typedef enum mpls_tunnel_flag_t_ { MPLS_TUNNEL_FLAG_NONE = 0, MPLS_TUNNEL_FLAG_L2 = (1 << MPLS_TUNNEL_ATTRIBUTE_L2), MPLS_TUNNEL_FLAG_MCAST = (1 << MPLS_TUNNEL_ATTRIBUTE_MCAST), } __attribute__ ((packed)) mpls_tunnel_flags_t; /** * @brief A uni-directional MPLS tunnel */ typedef struct mpls_tunnel_t_ { /** * @brief The tunnel hooks into the FIB control plane graph. */ fib_node_t mt_node; /** * @brief Tunnel flags */ mpls_tunnel_flags_t mt_flags; /** * @brief If the tunnel is an L2 tunnel, this is the link type ETHERNET * load-balance */ dpo_id_t mt_l2_lb; /** * @brief The HW interface index of the tunnel interfaces */ u32 mt_hw_if_index; /** * @brief The SW interface index of the tunnel interfaces */ u32 mt_sw_if_index; /** * @brief The path-list over which the tunnel's destination is reachable */ fib_node_index_t mt_path_list; /** * @brief sibling index on the path-list so notifications are received. */ u32 mt_sibling_index; /** * A vector of path extensions o hold the label stack for each path */ fib_path_ext_list_t mt_path_exts; } mpls_tunnel_t; /** * @brief Create a new MPLS tunnel * @return the SW Interface index of the newly created tuneel */ extern u32 vnet_mpls_tunnel_create (u8 l2_only, u8 is_multicast); /** * @brief Add a path to an MPLS tunnel */ extern void vnet_mpls_tunnel_path_add (u32 sw_if_index, fib_route_path_t *rpath); /** * @brief remove a path from a tunnel. * @return the number of remaining paths. 0 implies the tunnel can be deleted */ extern int vnet_mpls_tunnel_path_remove (u32 sw_if_index, fib_route_path_t *rpath); /** * @vrief return the tunnel index from the sw_if_index */ extern int vnet_mpls_tunnel_get_index (u32 sw_if_index); /** * @brief Delete an MPLS tunnel */ extern void vnet_mpls_tunnel_del (u32 sw_if_index); extern const mpls_tunnel_t *mpls_tunnel_get(u32 index); /** * @brief Callback function invoked while walking MPLS tunnels */ typedef void (*mpls_tunnel_walk_cb_t)(u32 index, void *ctx); /** * @brief Walk all the MPLS tunnels */ extern void mpls_tunnel_walk(mpls_tunnel_walk_cb_t cb, void *ctx); #endif