From e821ab100aea2fb3f740a98650eb750ff5911c49 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 1 Jun 2017 07:45:05 -0700 Subject: IP mcast: allow unicast address as a next-hop Change-Id: I5e679f2601e37688f2768620479dc2efb7d19ca3 Signed-off-by: Neale Ranns --- src/vnet/mfib/mfib_entry.c | 66 ++++++++++++--------- src/vnet/mfib/mfib_itf.c | 80 ++++++++++++++++++++++++- src/vnet/mfib/mfib_itf.h | 27 ++++++++- src/vnet/mfib/mfib_test.c | 144 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 279 insertions(+), 38 deletions(-) (limited to 'src/vnet/mfib') 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 #include +#include 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, @@ -1042,6 +1066,69 @@ mfib_test_i (fib_protocol_t PROTO, "%U Gone", 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 */ @@ -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 @@ -1225,6 +1314,11 @@ mfib_test_i (fib_protocol_t PROTO, 0, 0); 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 */ @@ -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) -- cgit 1.2.3-korg