aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/mfib
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-06-01 07:45:05 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2018-04-17 22:29:46 +0000
commite821ab100aea2fb3f740a98650eb750ff5911c49 (patch)
treee679732692ca211858ca64a3125a1e2a82104a7c /src/vnet/mfib
parent167d458cba92e2f64f48fa7bc4430c770f290561 (diff)
IP mcast: allow unicast address as a next-hop
Change-Id: I5e679f2601e37688f2768620479dc2efb7d19ca3 Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/mfib')
-rw-r--r--src/vnet/mfib/mfib_entry.c66
-rw-r--r--src/vnet/mfib/mfib_itf.c80
-rw-r--r--src/vnet/mfib/mfib_itf.h27
-rw-r--r--src/vnet/mfib/mfib_test.c144
4 files changed, 279 insertions, 38 deletions
diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c
index bc7f7dec406..a88f375ec19 100644
--- a/src/vnet/mfib/mfib_entry.c
+++ b/src/vnet/mfib/mfib_entry.c
@@ -217,7 +217,10 @@ format_mfib_entry (u8 * s, va_list * args)
({
s = format(s, "\n %U", format_mfib_itf, mfi);
}));
- s = format(s, "\n RPF-ID:%d", mfib_entry->mfe_rpf_id);
+ if (MFIB_RPF_ID_NONE != mfib_entry->mfe_rpf_id)
+ {
+ s = format(s, "\n RPF-ID:%d", mfib_entry->mfe_rpf_id);
+ }
s = format(s, "\n %U-chain\n %U",
format_fib_forw_chain_type,
mfib_entry_get_default_chain_type(mfib_entry),
@@ -835,9 +838,9 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index,
{
fib_node_index_t path_index;
mfib_path_ext_t *path_ext;
- mfib_itf_flags_t old, new;
mfib_entry_t *mfib_entry;
mfib_entry_src_t *msrc;
+ mfib_itf_flags_t old;
mfib_entry = mfib_entry_get(mfib_entry_index);
ASSERT(NULL != mfib_entry);
@@ -873,37 +876,32 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index,
{
mfib_itf_t *mfib_itf;
- new = itf_flags;
-
- if (old != new)
+ if (old != itf_flags)
{
- if (MFIB_ITF_FLAG_NONE == new)
- {
- /*
- * no more interface flags on this path, remove
- * from the data-plane set
- */
- mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
- }
- else if (MFIB_ITF_FLAG_NONE == old)
+ /*
+ * change of flag contributions
+ */
+ mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
+ rpath[0].frp_sw_if_index);
+
+ if (NULL == mfib_itf)
{
- /*
- * This interface is now contributing
- */
mfib_entry_itf_add(msrc,
rpath[0].frp_sw_if_index,
- mfib_itf_create(rpath[0].frp_sw_if_index,
- itf_flags));
+ mfib_itf_create(path_index, itf_flags));
}
else
{
- /*
- * change of flag contributions
- */
- mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
- rpath[0].frp_sw_if_index);
- /* Seen by packets inflight */
- mfib_itf->mfi_flags = new;
+ if (mfib_itf_update(mfib_itf,
+ path_index,
+ itf_flags))
+ {
+ /*
+ * no more interface flags on this path, remove
+ * from the data-plane set
+ */
+ mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+ }
}
}
}
@@ -952,7 +950,21 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
mfib_path_ext_remove(msrc, path_index);
if (~0 != rpath[0].frp_sw_if_index)
{
- mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+ mfib_itf_t *mfib_itf;
+
+ mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
+ rpath[0].frp_sw_if_index);
+
+ if (mfib_itf_update(mfib_itf,
+ path_index,
+ MFIB_ITF_FLAG_NONE))
+ {
+ /*
+ * no more interface flags on this path, remove
+ * from the data-plane set
+ */
+ mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+ }
}
}
diff --git a/src/vnet/mfib/mfib_itf.c b/src/vnet/mfib/mfib_itf.c
index f77b40e743a..33ef98764e2 100644
--- a/src/vnet/mfib/mfib_itf.c
+++ b/src/vnet/mfib/mfib_itf.c
@@ -17,11 +17,12 @@
#include <vnet/mfib/mfib_itf.h>
#include <vnet/mfib/mfib_signal.h>
+#include <vnet/fib/fib_path.h>
mfib_itf_t *mfib_itf_pool;
index_t
-mfib_itf_create (u32 sw_if_index,
+mfib_itf_create (fib_node_index_t path_index,
mfib_itf_flags_t mfi_flags)
{
mfib_itf_t *mfib_itf;
@@ -29,16 +30,89 @@ mfib_itf_create (u32 sw_if_index,
pool_get_aligned(mfib_itf_pool, mfib_itf,
CLIB_CACHE_LINE_BYTES);
- mfib_itf->mfi_sw_if_index = sw_if_index;
- mfib_itf->mfi_flags = mfi_flags;
+ mfib_itf->mfi_sw_if_index = fib_path_get_resolving_interface(path_index);
mfib_itf->mfi_si = INDEX_INVALID;
+ /*
+ * add the path index to the per-path hash
+ */
+ mfib_itf->mfi_hash = hash_set(mfib_itf->mfi_hash, path_index, mfi_flags);
+
+ /*
+ * the combined flags from all the paths is from just the one contributor
+ */
+ mfib_itf->mfi_flags = mfi_flags;
+
return (mfib_itf - mfib_itf_pool);
}
+static mfib_itf_flags_t
+mfib_itf_mk_flags (const mfib_itf_t *mfib_itf)
+{
+ mfib_itf_flags_t combined_flags, flags;
+ fib_node_index_t *path_index;
+
+ combined_flags = MFIB_ITF_FLAG_NONE;
+
+ hash_foreach(path_index, flags, mfib_itf->mfi_hash,
+ {
+ combined_flags |= flags;
+ });
+
+ return (combined_flags);
+}
+
+int
+mfib_itf_update (mfib_itf_t *mfib_itf,
+ fib_node_index_t path_index,
+ mfib_itf_flags_t mfi_flags)
+{
+ /*
+ * add or remove the path index to the per-path hash
+ */
+ if (MFIB_ITF_FLAG_NONE == mfi_flags)
+ {
+ hash_unset(mfib_itf->mfi_hash, path_index);
+ }
+ else
+ {
+ mfib_itf->mfi_hash = hash_set(mfib_itf->mfi_hash,
+ path_index,
+ mfi_flags);
+ }
+
+ /*
+ * re-generate the combined flags from all the paths.
+ */
+ mfib_itf->mfi_flags = mfib_itf_mk_flags(mfib_itf);
+
+ /*
+ * The interface can be removed if there are no more flags
+ */
+ return (MFIB_ITF_FLAG_NONE == mfib_itf->mfi_flags);
+}
+
+static void
+mfib_itf_hash_flush (mfib_itf_t *mfi)
+{
+ fib_node_index_t path_index, *path_indexp, *all = NULL;
+ mfib_itf_flags_t flags;
+
+ hash_foreach(path_index, flags, mfi->mfi_hash,
+ {
+ vec_add1(all, path_index);
+ });
+
+ vec_foreach(path_indexp, all)
+ {
+ hash_unset(mfi->mfi_hash, *path_indexp);
+ };
+}
+
void
mfib_itf_delete (mfib_itf_t *mfi)
{
+ mfib_itf_hash_flush(mfi);
mfib_signal_remove_itf(mfi);
pool_put(mfib_itf_pool, mfi);
}
diff --git a/src/vnet/mfib/mfib_itf.h b/src/vnet/mfib/mfib_itf.h
index 5f26a476525..fe39c895d8b 100644
--- a/src/vnet/mfib/mfib_itf.h
+++ b/src/vnet/mfib/mfib_itf.h
@@ -25,7 +25,7 @@
typedef struct mfib_itf_t_
{
/**
- * @brief Falags on the entry
+ * @brief Forwarding Flags on the entry - checked in the data-path
*/
mfib_itf_flags_t mfi_flags;
@@ -38,22 +38,43 @@ typedef struct mfib_itf_t_
* The index of the signal in the pending list
*/
u32 mfi_si;
+
+ /**
+ * A hash table of path-inidices that are contributing flags to this interface.
+ * Since paths with next-hops can be on the same interface and each of those
+ * paths can contribute different flags, we need to maintain the flag
+ * contribution from each path, and use a combination for forwarding.
+ */
+ uword *mfi_hash;
} mfib_itf_t;
+/**
+ * update an interface from a path.
+ * returns 1 if the entry is removed, i.e. has no flags left, as a result
+ * of the update.
+ */
+extern int mfib_itf_update(mfib_itf_t *itf,
+ fib_node_index_t path_index,
+ mfib_itf_flags_t mfi_flags);
-extern index_t mfib_itf_create(u32 sw_if_index,
+extern index_t mfib_itf_create(fib_node_index_t path_index,
mfib_itf_flags_t mfi_flags);
-extern void mfib_itf_delete(mfib_itf_t *mfi);
+
+extern void mfib_itf_delete(mfib_itf_t *itf);
extern u8 *format_mfib_itf(u8 * s, va_list * args);
extern mfib_itf_t *mfib_itf_pool;
+/**
+ * Get the MFIB interface representation
+ */
static inline mfib_itf_t *
mfib_itf_get (index_t mi)
{
return (pool_elt_at_index(mfib_itf_pool, mi));
}
+
static inline index_t
mfib_itf_get_index (const mfib_itf_t *mfi)
{
diff --git a/src/vnet/mfib/mfib_test.c b/src/vnet/mfib/mfib_test.c
index 8c75e349b86..a94b308473e 100644
--- a/src/vnet/mfib/mfib_test.c
+++ b/src/vnet/mfib/mfib_test.c
@@ -347,11 +347,14 @@ mfib_test_i (fib_protocol_t PROTO,
const mfib_prefix_t *pfx_star_g_1,
const mfib_prefix_t *pfx_star_g_2,
const mfib_prefix_t *pfx_star_g_3,
- const mfib_prefix_t *pfx_star_g_slash_m)
+ const mfib_prefix_t *pfx_star_g_slash_m,
+ const fib_prefix_t *pfx_itf,
+ const ip46_address_t *addr_nbr1,
+ const ip46_address_t *addr_nbr2)
{
fib_node_index_t mfei, mfei_dflt, mfei_no_f, mfei_s_g, mfei_g_1, mfei_g_2, mfei_g_3, mfei_g_m;
u32 fib_index, n_entries, n_itfs, n_reps, n_pls;
- fib_node_index_t ai_1, ai_2, ai_3;
+ fib_node_index_t ai_1, ai_2, ai_3, ai_nbr1, ai_nbr2;
test_main_t *tm;
int res;
@@ -374,12 +377,33 @@ mfib_test_i (fib_protocol_t PROTO,
ai_3 = adj_mcast_add_or_lock(PROTO,
LINKT,
tm->hw[3]->sw_if_index);
+ ai_nbr1 = adj_nbr_add_or_lock(PROTO,
+ LINKT,
+ addr_nbr1,
+ tm->hw[0]->sw_if_index);
+ ai_nbr2 = adj_nbr_add_or_lock(PROTO,
+ LINKT,
+ addr_nbr2,
+ tm->hw[0]->sw_if_index);
MFIB_TEST(3 == adj_mcast_db_size(), "3 MCAST adjs");
/* Find or create FIB table 11 */
fib_index = mfib_table_find_or_create_and_lock(PROTO, 11, MFIB_SOURCE_API);
+ fib_table_entry_update_one_path(0,
+ pfx_itf,
+ FIB_SOURCE_INTERFACE,
+ (FIB_ENTRY_FLAG_CONNECTED |
+ FIB_ENTRY_FLAG_ATTACHED),
+ DPO_PROTO_IP4,
+ NULL,
+ tm->hw[0]->sw_if_index,
+ ~0, // invalid fib index
+ 1, // weight
+ NULL,
+ FIB_ROUTE_PATH_FLAG_NONE);
+
mfib_prefix_t pfx_dft = {
.fp_len = 0,
.fp_proto = PROTO,
@@ -1043,6 +1067,69 @@ mfib_test_i (fib_protocol_t PROTO,
format_mfib_prefix, pfx_star_g_slash_m);
/*
+ * Entries with paths via unicast next-hops
+ */
+ fib_route_path_t path_via_nbr1 = {
+ .frp_proto = fib_proto_to_dpo(PROTO),
+ .frp_addr = *addr_nbr1,
+ .frp_sw_if_index = tm->hw[0]->sw_if_index,
+ .frp_fib_index = ~0,
+ .frp_weight = 0,
+ .frp_flags = 0,
+ };
+ fib_route_path_t path_via_nbr2 = {
+ .frp_proto = fib_proto_to_dpo(PROTO),
+ .frp_addr = *addr_nbr2,
+ .frp_sw_if_index = tm->hw[0]->sw_if_index,
+ .frp_fib_index = ~0,
+ .frp_weight = 0,
+ .frp_flags = 0,
+ };
+
+ mfei_g_1 = mfib_table_entry_path_update(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr1,
+ (MFIB_ITF_FLAG_FORWARD));
+ mfei_g_1 = mfib_table_entry_path_update(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr2,
+ (MFIB_ITF_FLAG_FORWARD));
+ MFIB_TEST(!mfib_test_entry(mfei_g_1,
+ MFIB_ENTRY_FLAG_NONE,
+ 2,
+ DPO_ADJACENCY_INCOMPLETE, ai_nbr1,
+ DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
+ "%U replicate OK",
+ format_mfib_prefix, pfx_star_g_1);
+ MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
+ MFIB_ITF_FLAG_FORWARD));
+
+ mfib_table_entry_path_remove(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr1);
+
+ MFIB_TEST(!mfib_test_entry(mfei_g_1,
+ MFIB_ENTRY_FLAG_NONE,
+ 1,
+ DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
+ "%U replicate OK",
+ format_mfib_prefix, pfx_star_g_1);
+ MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
+ MFIB_ITF_FLAG_FORWARD));
+
+ mfib_table_entry_path_remove(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr2);
+ mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
+ MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
+ "%U Gone",
+ format_mfib_prefix, pfx_star_g_1);
+
+ /*
* Add a prefix as a special/exclusive route
*/
dpo_id_t td = DPO_INVALID;
@@ -1216,6 +1303,8 @@ mfib_test_i (fib_protocol_t PROTO,
adj_unlock(ai_1);
adj_unlock(ai_2);
adj_unlock(ai_3);
+ adj_unlock(ai_nbr1);
+ adj_unlock(ai_nbr2);
/*
* MPLS disable the interface
@@ -1226,6 +1315,11 @@ mfib_test_i (fib_protocol_t PROTO,
mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
/*
+ * remove the connected
+ */
+ fib_table_entry_delete(0, pfx_itf, FIB_SOURCE_INTERFACE);
+
+ /*
* test we've leaked no resources
*/
MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
@@ -1303,7 +1397,19 @@ mfib_test_v4 (void)
.ip4.as_u32 = 0,
},
};
-
+ const fib_prefix_t pfx_itf = {
+ .fp_len = 24,
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_addr = {
+ .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
+ },
+ };
+ const ip46_address_t nbr1 = {
+ .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0b),
+ };
+ const ip46_address_t nbr2 = {
+ .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0c),
+ };
return (mfib_test_i(FIB_PROTOCOL_IP4,
VNET_LINK_IP4,
&pfx_224_s_8,
@@ -1311,7 +1417,10 @@ mfib_test_v4 (void)
&pfx_239_1_1_1,
&pfx_239_1_1_2,
&pfx_239_1_1_3,
- &pfx_239));
+ &pfx_239,
+ &pfx_itf,
+ &nbr1,
+ &nbr2));
}
static int
@@ -1371,6 +1480,22 @@ mfib_test_v6 (void)
.ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000),
},
};
+ const fib_prefix_t pfx_itf = {
+ .fp_len = 64,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr = {
+ .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
+ .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001),
+ },
+ };
+ const ip46_address_t nbr1 = {
+ .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
+ .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000002),
+ };
+ const ip46_address_t nbr2 = {
+ .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
+ .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000003),
+ };
return (mfib_test_i(FIB_PROTOCOL_IP6,
VNET_LINK_IP6,
@@ -1379,7 +1504,10 @@ mfib_test_v6 (void)
&pfx_ff_1,
&pfx_ff_2,
&pfx_ff_3,
- &pfx_ff));
+ &pfx_ff,
+ &pfx_itf,
+ &nbr1,
+ &nbr2));
}
static clib_error_t *
@@ -1391,6 +1519,12 @@ mfib_test (vlib_main_t * vm,
res += mfib_test_mk_intf(4);
res += mfib_test_v4();
+
+ if (res)
+ {
+ return clib_error_return(0, "MFIB Unit Test Failed");
+ }
+
res += mfib_test_v6();
if (res)