From 9e829a856fdf88b3ea5770048ea20dcd50d1b4eb Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Mon, 17 Dec 2018 05:50:32 -0800 Subject: [PATCH] MFIB: recurse resolution through an MFIB entry Change-Id: I8dc261e40b8398c5c8ab6bb69ecebbd0176055d9 Signed-off-by: Neale Ranns --- src/plugins/unittest/mfib_test.c | 489 ++++++++++++++++++++++++++++++++++-- src/vnet/CMakeLists.txt | 5 + src/vnet/dpo/receive_dpo.c | 6 + src/vnet/dpo/receive_dpo.h | 2 + src/vnet/dpo/replicate_dpo.c | 88 +++++++ src/vnet/dpo/replicate_dpo.h | 17 ++ src/vnet/ip/ip_api.c | 40 +-- src/vnet/mfib/ip4_mfib.c | 32 +++ src/vnet/mfib/ip4_mfib.h | 4 + src/vnet/mfib/ip6_mfib.c | 62 ++++- src/vnet/mfib/ip6_mfib.h | 4 + src/vnet/mfib/mfib_entry.c | 423 ++++++++++++++++++++++--------- src/vnet/mfib/mfib_entry.h | 52 +++- src/vnet/mfib/mfib_entry_cover.c | 180 +++++++++++++ src/vnet/mfib/mfib_entry_cover.h | 42 ++++ src/vnet/mfib/mfib_entry_delegate.c | 143 +++++++++++ src/vnet/mfib/mfib_entry_delegate.h | 90 +++++++ src/vnet/mfib/mfib_entry_src.c | 101 ++++++++ src/vnet/mfib/mfib_entry_src.h | 142 +++++++++++ src/vnet/mfib/mfib_entry_src_rr.c | 112 +++++++++ src/vnet/mfib/mfib_table.c | 136 ++++++++-- src/vnet/mfib/mfib_table.h | 23 ++ src/vnet/mfib/mfib_types.c | 76 ++++++ src/vnet/mfib/mfib_types.h | 27 +- 24 files changed, 2097 insertions(+), 199 deletions(-) create mode 100644 src/vnet/mfib/mfib_entry_cover.c create mode 100644 src/vnet/mfib/mfib_entry_cover.h create mode 100644 src/vnet/mfib/mfib_entry_delegate.c create mode 100644 src/vnet/mfib/mfib_entry_delegate.h create mode 100644 src/vnet/mfib/mfib_entry_src.c create mode 100644 src/vnet/mfib/mfib_entry_src.h create mode 100644 src/vnet/mfib/mfib_entry_src_rr.c diff --git a/src/plugins/unittest/mfib_test.c b/src/plugins/unittest/mfib_test.c index bbe6709f4d7..0707a6f57c8 100644 --- a/src/plugins/unittest/mfib_test.c +++ b/src/plugins/unittest/mfib_test.c @@ -34,9 +34,6 @@ fformat(stderr, "FAIL:%d: " _comment "\n", \ __LINE__, ##_args); \ res = 1; \ - } else { \ - fformat(stderr, "PASS:%d: " _comment "\n", \ - __LINE__, ##_args); \ } \ res; \ }) @@ -223,16 +220,16 @@ mfib_test_entry (fib_node_index_t fei, int n_buckets, ...) { + const mfib_prefix_t *pfx; const mfib_entry_t *mfe; const replicate_t *rep; - mfib_prefix_t pfx; va_list ap; int res; res = 0; mfe = mfib_entry_get(fei); - mfib_entry_get_prefix(fei, &pfx); + pfx = mfib_entry_get_prefix(fei); MFIB_TEST_REP((eflags == mfe->mfe_flags), "%U has %U expect %U", @@ -253,7 +250,8 @@ mfib_test_entry (fib_node_index_t fei, mfib_entry_contribute_forwarding( fei, - fib_forw_chain_type_from_fib_proto(pfx.fp_proto), + mfib_forw_chain_type_from_fib_proto(pfx->fp_proto), + MFIB_ENTRY_FWD_FLAG_NONE, &tmp); rep = replicate_get(tmp.dpoi_index); @@ -278,15 +276,15 @@ mfib_test_entry_itf (fib_node_index_t fei, u32 sw_if_index, mfib_itf_flags_t flags) { + const mfib_prefix_t *pfx; const mfib_entry_t *mfe; const mfib_itf_t *mfi; - mfib_prefix_t pfx; int res; res = 0; mfe = mfib_entry_get(fei); mfi = mfib_entry_get_itf(mfe, sw_if_index); - mfib_entry_get_prefix(fei, &pfx); + pfx = mfib_entry_get_prefix(fei); MFIB_TEST_REP((NULL != mfi), "%U has interface %d", @@ -305,19 +303,19 @@ static int mfib_test_entry_no_itf (fib_node_index_t fei, u32 sw_if_index) { + const mfib_prefix_t *pfx; const mfib_entry_t *mfe; const mfib_itf_t *mfi; - mfib_prefix_t pfx; int res; res = 0; mfe = mfib_entry_get(fei); mfi = mfib_entry_get_itf(mfe, sw_if_index); - mfib_entry_get_prefix(fei, &pfx); + pfx = mfib_entry_get_prefix(fei); MFIB_TEST_REP((NULL == mfi), "%U has no interface %d", - format_mfib_prefix, &pfx, sw_if_index); + format_mfib_prefix, pfx, sw_if_index); return (res); } @@ -1143,11 +1141,12 @@ mfib_test_i (fib_protocol_t PROTO, dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_1); replicate_set_bucket(repi2, 0, &td); - mfei = mfib_table_entry_special_add(fib_index, - pfx_star_g_3, - MFIB_SOURCE_SRv6, - MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF, - repi2); + mfib_entry_update(mfei, + MFIB_SOURCE_SRv6, + (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF | + MFIB_ENTRY_FLAG_EXCLUSIVE), + MFIB_RPF_ID_NONE, + repi2); MFIB_TEST(!mfib_test_entry(mfei, (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF | MFIB_ENTRY_FLAG_EXCLUSIVE), @@ -1278,6 +1277,11 @@ mfib_test_i (fib_protocol_t PROTO, /* * Unlock the table - it's the last lock so should be gone thereafter */ + MFIB_TEST(((PROTO == FIB_PROTOCOL_IP4 ? 1 : 5) == + mfib_table_get_n_routes(fib_index, PROTO)), + "1 = %d route left in the FIB", + mfib_table_get_n_routes(fib_index, PROTO)); + mfib_table_unlock(fib_index, PROTO, MFIB_SOURCE_API); MFIB_TEST((FIB_NODE_INDEX_INVALID == @@ -1494,6 +1498,435 @@ mfib_test_v6 (void) &nbr2)); } +static int +mfib_test_rr_i (fib_protocol_t FPROTO, + dpo_proto_t DPROTO, + vnet_link_t LINKT, + const mfib_prefix_t *pfx_cover, + const mfib_prefix_t *pfx_host1, + const mfib_prefix_t *pfx_host2) +{ + fib_node_index_t mfei_cover, mfei_host1, mfei_host2, ai_1, ai_2; + u32 fib_index, n_entries, n_itfs, n_reps, n_pls; + test_main_t *tm; + int res; + + res = 0; + n_entries = pool_elts(mfib_entry_pool); + n_itfs = pool_elts(mfib_itf_pool); + n_reps = pool_elts(replicate_pool); + n_pls = fib_path_list_pool_size(); + tm = &test_main; + + fib_index = 0; + ai_1 = adj_mcast_add_or_lock(FPROTO, + LINKT, + tm->hw[1]->sw_if_index); + ai_2 = adj_mcast_add_or_lock(FPROTO, + LINKT, + tm->hw[2]->sw_if_index); + + fib_route_path_t path_via_if0 = { + .frp_proto = DPROTO, + .frp_addr = zero_addr, + .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_if1 = { + .frp_proto = DPROTO, + .frp_addr = zero_addr, + .frp_sw_if_index = tm->hw[1]->sw_if_index, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = 0, + }; + fib_route_path_t path_via_if2 = { + .frp_proto = DPROTO, + .frp_addr = zero_addr, + .frp_sw_if_index = tm->hw[2]->sw_if_index, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = 0, + }; + fib_route_path_t path_for_us = { + .frp_proto = DPROTO, + .frp_addr = zero_addr, + .frp_sw_if_index = 0xffffffff, + .frp_fib_index = ~0, + .frp_weight = 0, + .frp_flags = FIB_ROUTE_PATH_LOCAL, + }; + + /* + * with only the default in place, recusre thru the /32 + */ + mfei_host1 = mfib_table_entry_special_add(fib_index, pfx_host1, + MFIB_SOURCE_RR, + MFIB_ENTRY_FLAG_NONE, + INDEX_INVALID); + /* + * expect its forwarding to match the cover's + */ + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_DROP, + 0), + "%U no replications OK", + format_mfib_prefix, pfx_host1); + + /* + * Insert the less specific /28 + */ + mfib_table_entry_path_update(fib_index, + pfx_cover, + MFIB_SOURCE_API, + &path_via_if1, + MFIB_ITF_FLAG_FORWARD); + + mfei_cover = mfib_table_lookup_exact_match(fib_index, pfx_cover); + + MFIB_TEST(!mfib_test_entry(mfei_cover, + MFIB_ENTRY_FLAG_NONE, + 1, + DPO_ADJACENCY_MCAST, ai_1), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + + /* + * expect the /32 forwarding to match the new cover's + */ + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_NONE, + 1, + DPO_ADJACENCY_MCAST, ai_1), + "%U replicate OK", + format_mfib_prefix, pfx_host1); + + /* + * add another path to the cover + */ + mfib_table_entry_path_update(fib_index, + pfx_cover, + MFIB_SOURCE_API, + &path_via_if2, + MFIB_ITF_FLAG_FORWARD); + + /* + * expect the /32 and /28 to be via both boths + */ + MFIB_TEST(!mfib_test_entry(mfei_cover, + MFIB_ENTRY_FLAG_NONE, + 2, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_NONE, + 2, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_host1); + + /* + * and the other host whilst all is ready + */ + mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2, + MFIB_SOURCE_RR, + MFIB_ENTRY_FLAG_NONE, + INDEX_INVALID); + MFIB_TEST(!mfib_test_entry(mfei_host2, + MFIB_ENTRY_FLAG_NONE, + 2, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_host2); + + /* + * repaet multiple time to simulate multiple recursve children + */ + mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2, + MFIB_SOURCE_RR, + MFIB_ENTRY_FLAG_NONE, + INDEX_INVALID); + mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2, + MFIB_SOURCE_RR, + MFIB_ENTRY_FLAG_NONE, + INDEX_INVALID); + mfei_host2 = mfib_table_entry_special_add(fib_index, pfx_host2, + MFIB_SOURCE_RR, + MFIB_ENTRY_FLAG_NONE, + INDEX_INVALID); + + /* + * add an accepting path to the cover + */ + mfib_table_entry_path_update(fib_index, + pfx_cover, + MFIB_SOURCE_API, + &path_via_if0, + MFIB_ITF_FLAG_ACCEPT); + + /* + * expect the /32 and /28 to be via both boths + */ + MFIB_TEST(!mfib_test_entry(mfei_cover, + MFIB_ENTRY_FLAG_NONE, + 2, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_NONE, + 2, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[0]->sw_if_index, + MFIB_ITF_FLAG_ACCEPT)); + MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[0]->sw_if_index, + MFIB_ITF_FLAG_ACCEPT)); + MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[1]->sw_if_index, + MFIB_ITF_FLAG_FORWARD)); + MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[1]->sw_if_index, + MFIB_ITF_FLAG_FORWARD)); + MFIB_TEST_NS(!mfib_test_entry_itf(mfei_host1, tm->hw[2]->sw_if_index, + MFIB_ITF_FLAG_FORWARD)); + MFIB_TEST_NS(!mfib_test_entry_itf(mfei_cover, tm->hw[2]->sw_if_index, + MFIB_ITF_FLAG_FORWARD)); + + /* + * add a for-us path to the cover + */ + mfib_table_entry_path_update(fib_index, + pfx_cover, + MFIB_SOURCE_API, + &path_for_us, + MFIB_ITF_FLAG_FORWARD); + + /* + * expect the /32 and /28 to be via all three paths + */ + MFIB_TEST(!mfib_test_entry(mfei_cover, + MFIB_ENTRY_FLAG_NONE, + 3, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2, + DPO_RECEIVE, 0), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_NONE, + 3, + DPO_ADJACENCY_MCAST, ai_1, + DPO_ADJACENCY_MCAST, ai_2, + DPO_RECEIVE, 0), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + + /* + * get the forwarding chain from the RR prefix + */ + replicate_t *rep; + dpo_id_t dpo = DPO_INVALID; + + mfib_entry_contribute_forwarding( + mfei_host1, + mfib_forw_chain_type_from_dpo_proto(DPROTO), + MFIB_ENTRY_FWD_FLAG_NONE, + &dpo); + + rep = replicate_get(dpo.dpoi_index); + MFIB_TEST((3 == rep->rep_n_buckets), + "%U replicate 3 buckets", + format_mfib_prefix, pfx_host1); + + /* + * get the forwarding chain from the RR prefix without local paths + */ + mfib_entry_contribute_forwarding( + mfei_host1, + mfib_forw_chain_type_from_dpo_proto(DPROTO), + MFIB_ENTRY_FWD_FLAG_NO_LOCAL, + &dpo); + + rep = replicate_get(dpo.dpoi_index); + MFIB_TEST((2 == rep->rep_n_buckets), + "%U no-local replicate 2 buckets", + format_mfib_prefix, pfx_host1); + + dpo_reset(&dpo); + + /* + * delete the cover, expect the /32 to be via the default + */ + mfib_table_entry_delete(fib_index, pfx_cover, MFIB_SOURCE_API); + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_DROP, + 0), + "%U no replications OK", + format_mfib_prefix, pfx_host1); + + /* + * source the /32 with its own path + */ + mfib_table_entry_path_update(fib_index, + pfx_host1, + MFIB_SOURCE_API, + &path_via_if2, + MFIB_ITF_FLAG_FORWARD); + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_NONE, + 1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_host1); + + /* + * remove host2 - as many times as it was added + */ + mfib_table_entry_delete(fib_index, pfx_host2, + MFIB_SOURCE_RR); + mfib_table_entry_delete(fib_index, pfx_host2, + MFIB_SOURCE_RR); + mfib_table_entry_delete(fib_index, pfx_host2, + MFIB_SOURCE_RR); + mfib_table_entry_delete(fib_index, pfx_host2, + MFIB_SOURCE_RR); + + + /* + * remove the RR source with paths present + */ + mfib_table_entry_delete(fib_index, pfx_host1, + MFIB_SOURCE_RR); + + /* + * add the RR back then remove the path and RR + */ + mfib_table_entry_path_update(fib_index, + pfx_host1, + MFIB_SOURCE_API, + &path_via_if2, + MFIB_ITF_FLAG_FORWARD); + MFIB_TEST(!mfib_test_entry(mfei_host1, + MFIB_ENTRY_FLAG_NONE, + 1, + DPO_ADJACENCY_MCAST, ai_2), + "%U replicate OK", + format_mfib_prefix, pfx_cover); + + mfib_table_entry_delete(fib_index, pfx_host1, + MFIB_SOURCE_API); + mfib_table_entry_delete(fib_index, pfx_host1, + MFIB_SOURCE_RR); + + /* + * test we've leaked no resources + */ + adj_unlock(ai_1); + adj_unlock(ai_2); + MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size()); + MFIB_TEST(n_pls == fib_path_list_pool_size(), "%d=%d path-lists", + n_pls, fib_path_list_pool_size()); + MFIB_TEST(n_reps == pool_elts(replicate_pool), "%d=%d replicates", + n_reps, pool_elts(replicate_pool)); + MFIB_TEST(n_entries == pool_elts(mfib_entry_pool), + " No more entries %d!=%d", + n_entries, pool_elts(mfib_entry_pool)); + MFIB_TEST(n_itfs == pool_elts(mfib_itf_pool), + " No more Interfaces %d!=%d", + n_itfs, pool_elts(mfib_itf_pool)); + return (res); +} + +static int +mfib_test_rr_v4 (void) +{ + /* + * 2 length of prefix to play with + */ + const mfib_prefix_t pfx_host1 = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_grp_addr = { + .ip4.as_u32 = clib_host_to_net_u32(0xe0001011), + }, + }; + const mfib_prefix_t pfx_host2 = { + .fp_len = 64, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_grp_addr = { + .ip4.as_u32 = clib_host_to_net_u32(0xe0001011), + }, + .fp_src_addr = { + .ip4.as_u32 = clib_host_to_net_u32(0x10101010), + }, + }; + const mfib_prefix_t pfx_cover = { + .fp_len = 28, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_grp_addr = { + .ip4.as_u32 = clib_host_to_net_u32(0xe0001010), + }, + }; + + return (mfib_test_rr_i(FIB_PROTOCOL_IP4, + DPO_PROTO_IP4, + VNET_LINK_IP4, + &pfx_cover, + &pfx_host1, + &pfx_host2)); +} + +static int +mfib_test_rr_v6 (void) +{ + /* + * 2 length of prefix to play with + */ + const mfib_prefix_t pfx_host1 = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000), + .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001), + }, + }; + const mfib_prefix_t pfx_host2 = { + .fp_len = 256, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000), + .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001), + }, + .fp_src_addr = { + .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000), + .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000001), + }, + }; + const mfib_prefix_t pfx_cover = { + .fp_len = 64, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_grp_addr = { + .ip6.as_u64[0] = clib_host_to_net_u64(0xff03000000000000), + .ip6.as_u64[1] = clib_host_to_net_u64(0x0000000000000000), + }, + }; + + return (mfib_test_rr_i(FIB_PROTOCOL_IP6, + DPO_PROTO_IP6, + VNET_LINK_IP6, + &pfx_cover, + &pfx_host1, + &pfx_host2)); +} + static clib_error_t * mfib_test (vlib_main_t * vm, unformat_input_t * input, @@ -1502,23 +1935,35 @@ mfib_test (vlib_main_t * vm, int res = 0; res += mfib_test_mk_intf(4); - res += mfib_test_v4(); + res += mfib_test_rr_v4(); if (res) { - return clib_error_return(0, "MFIB Unit Test Failed"); + return clib_error_return(0, "MFIB RR V4 Unit Test Failed"); } - res += mfib_test_v6(); + res += mfib_test_rr_v6(); if (res) { - return clib_error_return(0, "MFIB Unit Test Failed"); + return clib_error_return(0, "MFIB RR V6 Unit Test Failed"); } - else + + res += mfib_test_v4(); + + if (res) { - return (NULL); + return clib_error_return(0, "MFIB V4 Unit Test Failed"); } + + res += mfib_test_v6(); + + if (res) + { + return clib_error_return(0, "MFIB V6 Unit Test Failed"); + } + + return (NULL); } VLIB_CLI_COMMAND (test_fib_command, static) = { diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 62bd57582b4..353bd3f7a6d 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -1279,6 +1279,11 @@ list(APPEND VNET_SOURCES mfib/mfib_signal.c mfib/mfib_itf.c mfib/mfib_entry.c + mfib/mfib_entry.c + mfib/mfib_entry_cover.c + mfib/mfib_entry_delegate.c + mfib/mfib_entry_src.c + mfib/mfib_entry_src_rr.c mfib/mfib_table.c ) diff --git a/src/vnet/dpo/receive_dpo.c b/src/vnet/dpo/receive_dpo.c index 30ddceeb23e..949dbfa6587 100644 --- a/src/vnet/dpo/receive_dpo.c +++ b/src/vnet/dpo/receive_dpo.c @@ -25,6 +25,12 @@ */ receive_dpo_t *receive_dpo_pool; +int +dpo_is_receive (const dpo_id_t *dpo) +{ + return (dpo->dpoi_type == DPO_RECEIVE); +} + static receive_dpo_t * receive_dpo_alloc (void) { diff --git a/src/vnet/dpo/receive_dpo.h b/src/vnet/dpo/receive_dpo.h index 9ab86a824c6..ee3c7836aff 100644 --- a/src/vnet/dpo/receive_dpo.h +++ b/src/vnet/dpo/receive_dpo.h @@ -47,6 +47,8 @@ typedef struct receive_dpo_t_ u16 rd_locks; } receive_dpo_t; +extern int dpo_is_receive(const dpo_id_t *dpo); + extern void receive_dpo_add_or_lock (dpo_proto_t proto, u32 sw_if_index, const ip46_address_t *nh_addr, diff --git a/src/vnet/dpo/replicate_dpo.c b/src/vnet/dpo/replicate_dpo.c index 39b17f103c9..69e367aa368 100644 --- a/src/vnet/dpo/replicate_dpo.c +++ b/src/vnet/dpo/replicate_dpo.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -100,6 +101,23 @@ replicate_alloc_i (void) return (rep); } +static u8* +format_replicate_flags (u8 *s, va_list *args) +{ + int flags = va_arg (*args, int); + + if (flags == REPLICATE_FLAGS_NONE) + { + s = format (s, "none"); + } + else if (flags & REPLICATE_FLAGS_HAS_LOCAL) + { + s = format (s, "has-local "); + } + + return (s); +} + static u8* replicate_format (index_t repi, replicate_format_flags_t flags, @@ -118,6 +136,7 @@ replicate_format (index_t repi, s = format(s, "%U: ", format_dpo_type, DPO_REPLICATE); s = format(s, "[index:%d buckets:%d ", repi, rep->rep_n_buckets); + s = format(s, "flags:[%U] ", format_replicate_flags, rep->rep_flags); s = format(s, "to:[%Ld:%Ld]]", to.packets, to.bytes); for (i = 0; i < rep->rep_n_buckets; i++) @@ -182,6 +201,14 @@ replicate_set_bucket_i (replicate_t *rep, dpo_id_t *buckets, const dpo_id_t *next) { + if (dpo_is_receive(&buckets[bucket])) + { + rep->rep_flags &= ~REPLICATE_FLAGS_HAS_LOCAL; + } + if (dpo_is_receive(next)) + { + rep->rep_flags |= REPLICATE_FLAGS_HAS_LOCAL; + } dpo_stack(DPO_REPLICATE, rep->rep_proto, &buckets[bucket], next); } @@ -492,6 +519,67 @@ replicate_lock (dpo_id_t *dpo) rep->rep_locks++; } +index_t +replicate_dup (replicate_flags_t flags, + index_t repi) +{ + replicate_t *rep, *copy; + + rep = replicate_get(repi); + + if (rep->rep_flags == flags || + flags & REPLICATE_FLAGS_HAS_LOCAL) + { + /* + * we can include all the buckets from the original in the copy + */ + return (repi); + } + else + { + /* + * caller doesn't want the local paths that the original has + */ + if (rep->rep_n_buckets == 1) + { + /* + * original has only one bucket that is the local, so create + * a new one with only the drop + */ + copy = replicate_create_i (1, rep->rep_proto); + + replicate_set_bucket_i(copy, 0, + replicate_get_buckets(copy), + drop_dpo_get(rep->rep_proto)); + } + else + { + dpo_id_t *old_buckets, *copy_buckets; + u16 bucket, pos; + + copy = replicate_create_i(rep->rep_n_buckets - 1, + rep->rep_proto); + + rep = replicate_get(repi); + old_buckets = replicate_get_buckets(rep); + copy_buckets = replicate_get_buckets(copy); + pos = 0; + + for (bucket = 0; bucket < rep->rep_n_buckets; bucket++) + { + if (!dpo_is_receive(&old_buckets[bucket])) + { + replicate_set_bucket_i(copy, pos, copy_buckets, + (&old_buckets[bucket])); + pos++; + } + } + } + } + + return (replicate_get_index(copy)); +} + static void replicate_destroy (replicate_t *rep) { diff --git a/src/vnet/dpo/replicate_dpo.h b/src/vnet/dpo/replicate_dpo.h index 7b075394bc3..70faef3e28f 100644 --- a/src/vnet/dpo/replicate_dpo.h +++ b/src/vnet/dpo/replicate_dpo.h @@ -46,6 +46,15 @@ extern replicate_main_t replicate_main; */ #define REP_NUM_INLINE_BUCKETS 4 +/** + * Flags on the replicate DPO + */ +typedef enum replicate_flags_t_ +{ + REPLICATE_FLAGS_NONE, + REPLICATE_FLAGS_HAS_LOCAL, +} __clib_packed replicate_flags_t; + /** * The FIB DPO provieds; * - load-balancing over the next DPOs in the chain/graph @@ -70,6 +79,11 @@ typedef struct replicate_t_ { */ dpo_proto_t rep_proto; + /** + * Flags specifying the replicate properties/behaviour + */ + replicate_flags_t rep_flags; + /** * The number of locks, which is approximately the number of users, * of this load-balance. @@ -121,6 +135,9 @@ extern int replicate_is_drop(const dpo_id_t *dpo); extern u16 replicate_n_buckets(index_t repi); +extern index_t replicate_dup(replicate_flags_t flags, + index_t repi); + /** * The encapsulation breakages are for fast DP access */ diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index b7ee17cfca8..5a2aa60b057 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -408,13 +408,13 @@ send_ip_mfib_details (vl_api_registration_t * reg, { fib_route_path_encode_t *api_rpath, *api_rpaths = NULL; vl_api_ip_mfib_details_t *mp; + const mfib_prefix_t *pfx; mfib_entry_t *mfib_entry; vl_api_fib_path_t *fp; - mfib_prefix_t pfx; int path_count; mfib_entry = mfib_entry_get (mfei); - mfib_entry_get_prefix (mfei, &pfx); + pfx = mfib_entry_get_prefix (mfei); mfib_entry_encode (mfei, &api_rpaths); path_count = vec_len (api_rpaths); @@ -428,11 +428,11 @@ send_ip_mfib_details (vl_api_registration_t * reg, mp->rpf_id = mfib_entry->mfe_rpf_id; mp->entry_flags = mfib_entry->mfe_flags; mp->table_id = htonl (table_id); - mp->address_length = pfx.fp_len; - memcpy (mp->grp_address, &pfx.fp_grp_addr.ip4, - sizeof (pfx.fp_grp_addr.ip4)); - memcpy (mp->src_address, &pfx.fp_src_addr.ip4, - sizeof (pfx.fp_src_addr.ip4)); + mp->address_length = pfx->fp_len; + memcpy (mp->grp_address, &pfx->fp_grp_addr.ip4, + sizeof (pfx->fp_grp_addr.ip4)); + memcpy (mp->src_address, &pfx->fp_src_addr.ip4, + sizeof (pfx->fp_src_addr.ip4)); mp->count = htonl (path_count); fp = mp->path; @@ -503,7 +503,7 @@ static void send_ip6_mfib_details (vpe_api_main_t * am, vl_api_registration_t * reg, u32 table_id, - mfib_prefix_t * pfx, + const mfib_prefix_t * pfx, fib_route_path_encode_t * api_rpaths, u32 context) { vl_api_ip6_mfib_details_t *mp; @@ -559,8 +559,8 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp) vl_api_registration_t *reg; ip6_main_t *im = &ip6_main; mfib_table_t *mfib_table; + const mfib_prefix_t *pfx; fib_node_index_t *mfeip; - mfib_prefix_t pfx; fib_route_path_encode_t *api_rpaths = NULL; vl_api_ip6_mfib_dump_ctc_t ctx = { .entries = NULL, @@ -582,11 +582,11 @@ vl_api_ip6_mfib_dump_t_handler (vl_api_ip6_mfib_dump_t * mp) vec_foreach(mfeip, ctx.entries) { - mfib_entry_get_prefix (*mfeip, &pfx); + pfx = mfib_entry_get_prefix (*mfeip); mfib_entry_encode (*mfeip, &api_rpaths); send_ip6_mfib_details (am, reg, mfib_table->mft_table_id, - &pfx, api_rpaths, + pfx, api_rpaths, mp->context); } vec_reset_length (api_rpaths); @@ -1833,7 +1833,7 @@ vl_mfib_signal_send_one (vl_api_registration_t * reg, u32 context, const mfib_signal_t * mfs) { vl_api_mfib_signal_details_t *mp; - mfib_prefix_t prefix; + const mfib_prefix_t *prefix; mfib_table_t *mfib; mfib_itf_t *mfi; @@ -1844,25 +1844,25 @@ vl_mfib_signal_send_one (vl_api_registration_t * reg, mp->context = context; mfi = mfib_itf_get (mfs->mfs_itf); - mfib_entry_get_prefix (mfs->mfs_entry, &prefix); + prefix = mfib_entry_get_prefix (mfs->mfs_entry); mfib = mfib_table_get (mfib_entry_get_fib_index (mfs->mfs_entry), - prefix.fp_proto); + prefix->fp_proto); mp->table_id = ntohl (mfib->mft_table_id); mp->sw_if_index = ntohl (mfi->mfi_sw_if_index); - if (FIB_PROTOCOL_IP4 == prefix.fp_proto) + if (FIB_PROTOCOL_IP4 == prefix->fp_proto) { - mp->grp_address_len = ntohs (prefix.fp_len); + mp->grp_address_len = ntohs (prefix->fp_len); - memcpy (mp->grp_address, &prefix.fp_grp_addr.ip4, 4); - if (prefix.fp_len > 32) + memcpy (mp->grp_address, &prefix->fp_grp_addr.ip4, 4); + if (prefix->fp_len > 32) { - memcpy (mp->src_address, &prefix.fp_src_addr.ip4, 4); + memcpy (mp->src_address, &prefix->fp_src_addr.ip4, 4); } } else { - mp->grp_address_len = ntohs (prefix.fp_len); + mp->grp_address_len = ntohs (prefix->fp_len); ASSERT (0); } diff --git a/src/vnet/mfib/ip4_mfib.c b/src/vnet/mfib/ip4_mfib.c index 9d70f0b664f..d20d1f6c2b9 100644 --- a/src/vnet/mfib/ip4_mfib.c +++ b/src/vnet/mfib/ip4_mfib.c @@ -224,6 +224,38 @@ ip4_mfib_table_lookup (const ip4_mfib_t *mfib, return (FIB_NODE_INDEX_INVALID); } +fib_node_index_t +ip4_mfib_table_get_less_specific (const ip4_mfib_t *mfib, + const ip4_address_t *src, + const ip4_address_t *grp, + u32 len) +{ + u32 mask_len; + + /* + * in the absence of a tree structure for the table that allows for an O(1) + * parent get, a cheeky way to find the cover is to LPM for the prefix with + * mask-1. + * there should always be a cover, though it may be the default route. the + * default route's cover is the default route. + */ + if (len == 64) + { + /* go from (S,G) to (*,G*) */ + mask_len = 32; + } + else if (len != 0) + { + mask_len = len - 1; + } + else + { + mask_len = len; + } + + return (ip4_mfib_table_lookup(mfib, src, grp, mask_len)); +} + void ip4_mfib_table_entry_insert (ip4_mfib_t *mfib, const ip4_address_t *grp, diff --git a/src/vnet/mfib/ip4_mfib.h b/src/vnet/mfib/ip4_mfib.h index 7767d795cad..5b225596469 100644 --- a/src/vnet/mfib/ip4_mfib.h +++ b/src/vnet/mfib/ip4_mfib.h @@ -38,6 +38,10 @@ extern fib_node_index_t ip4_mfib_table_lookup_exact_match(const ip4_mfib_t *fib, const ip4_address_t *grp, const ip4_address_t *src, u32 len); +extern fib_node_index_t ip4_mfib_table_get_less_specific (const ip4_mfib_t *mfib, + const ip4_address_t *src, + const ip4_address_t *grp, + u32 len); extern void ip4_mfib_table_entry_remove(ip4_mfib_t *fib, const ip4_address_t *grp, diff --git a/src/vnet/mfib/ip6_mfib.c b/src/vnet/mfib/ip6_mfib.c index 554a932844f..d47887be699 100644 --- a/src/vnet/mfib/ip6_mfib.c +++ b/src/vnet/mfib/ip6_mfib.c @@ -365,7 +365,6 @@ ip6_mfib_table_fwd_lookup (const ip6_mfib_t *mfib, ASSERT(len >= 0 && len <= 256); IP6_MFIB_MK_KEY(mfib, grp, src, len, key); - rv = clib_bihash_search_inline_2_40_8(&table->ip6_mhash, &key, &value); if (rv == 0) return value.value; @@ -374,6 +373,39 @@ ip6_mfib_table_fwd_lookup (const ip6_mfib_t *mfib, return (FIB_NODE_INDEX_INVALID); } + +fib_node_index_t +ip6_mfib_table_get_less_specific (const ip6_mfib_t *mfib, + const ip6_address_t *src, + const ip6_address_t *grp, + u32 len) +{ + u32 mask_len; + + /* + * in the absence of a tree structure for the table that allows for an O(1) + * parent get, a cheeky way to find the cover is to LPM for the prefix with + * mask-1. + * there should always be a cover, though it may be the default route. the + * default route's cover is the default route. + */ + if (len == 256) + { + /* go from (S,G) to (*,G*) */ + mask_len = 128; + } + else if (len != 0) + { + mask_len = len - 1; + } + else + { + mask_len = len; + } + + return (ip6_mfib_table_lookup(mfib, src, grp, mask_len)); +} + /* * ip6_fib_table_lookup * @@ -501,12 +533,23 @@ ip6_mfib_table_show_one (ip6_mfib_t *mfib, vlib_main_t * vm, ip6_address_t *src, ip6_address_t *grp, - u32 mask_len) + u32 mask_len, + u32 cover) { - vlib_cli_output(vm, "%U", - format_mfib_entry, - ip6_mfib_table_lookup(mfib, src, grp, mask_len), - MFIB_ENTRY_FORMAT_DETAIL); + if (cover) + { + vlib_cli_output(vm, "%U", + format_mfib_entry, + ip6_mfib_table_get_less_specific(mfib, src, grp, mask_len), + MFIB_ENTRY_FORMAT_DETAIL); + } + else + { + vlib_cli_output(vm, "%U", + format_mfib_entry, + ip6_mfib_table_lookup(mfib, src, grp, mask_len), + MFIB_ENTRY_FORMAT_DETAIL); + } } typedef struct ip6_mfib_show_ctx_t_ { @@ -600,11 +643,12 @@ ip6_show_mfib (vlib_main_t * vm, mfib_table_t *mfib_table; int verbose, matching; ip6_address_t grp, src = {{0}}; - u32 mask = 32; + u32 mask = 128, cover; int table_id = -1, fib_index = ~0; verbose = 1; matching = 0; + cover = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -634,6 +678,8 @@ ip6_show_mfib (vlib_main_t * vm, ; else if (unformat (input, "index %d", &fib_index)) ; + else if (unformat (input, "cover")) + cover = 1; else break; } @@ -671,7 +717,7 @@ ip6_show_mfib (vlib_main_t * vm, } else { - ip6_mfib_table_show_one(mfib, vm, &src, &grp, mask); + ip6_mfib_table_show_one(mfib, vm, &src, &grp, mask, cover); } })); diff --git a/src/vnet/mfib/ip6_mfib.h b/src/vnet/mfib/ip6_mfib.h index 5ed330b30af..f197b9d9fe8 100644 --- a/src/vnet/mfib/ip6_mfib.h +++ b/src/vnet/mfib/ip6_mfib.h @@ -41,6 +41,10 @@ extern fib_node_index_t ip6_mfib_table_lookup_exact_match(const ip6_mfib_t *fib, const ip6_address_t *grp, const ip6_address_t *src, u32 len); +extern fib_node_index_t ip6_mfib_table_get_less_specific (const ip6_mfib_t *mfib, + const ip6_address_t *src, + const ip6_address_t *grp, + u32 len); extern void ip6_mfib_table_entry_remove(ip6_mfib_t *fib, const ip6_address_t *grp, diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c index 90b223e3c25..51d775dd295 100644 --- a/src/vnet/mfib/mfib_entry.c +++ b/src/vnet/mfib/mfib_entry.c @@ -16,7 +16,10 @@ #include #include +#include +#include #include +#include #include #include @@ -26,66 +29,6 @@ */ vlib_log_class_t mfib_entry_logger; -/** - * Debug macro - */ -#define MFIB_ENTRY_DBG(_e, _fmt, _args...) \ -{ \ - vlib_log_debug(mfib_entry_logger, \ - "e:[%d:%U]: " _fmt, \ - mfib_entry_get_index(_e), \ - format_mfib_prefix, \ - &_e->mfe_prefix, \ - ##_args); \ -} - -/** - * MFIB extensions to each path - */ -typedef struct mfib_path_ext_t_ -{ - mfib_itf_flags_t mfpe_flags; - fib_node_index_t mfpe_path; -} mfib_path_ext_t; - -/** - * The source of an MFIB entry - */ -typedef struct mfib_entry_src_t_ -{ - /** - * Which source this is - */ - mfib_source_t mfes_src; - - /** - * Route flags - */ - mfib_entry_flags_t mfes_flags; - - /** - * The path-list of forwarding interfaces - */ - fib_node_index_t mfes_pl; - - /** - * RPF-ID - */ - fib_rpf_id_t mfes_rpf_id; - - /** - * Hash table of path extensions - */ - mfib_path_ext_t *mfes_exts; - - /** - * The hash table of all interfaces. - * This is forwarding time information derived from the paths - * and their extensions. - */ - mfib_itf_t *mfes_itfs; -} mfib_entry_src_t; - /** * Pool of path extensions */ @@ -184,8 +127,14 @@ format_mfib_entry (u8 * s, va_list * args) s = format (s, " locks:%d\n", mfib_entry->mfe_node.fn_locks); vec_foreach(msrc, mfib_entry->mfe_srcs) { - s = format (s, " src:%s", mfib_source_names[msrc->mfes_src]); - s = format (s, ": %U\n", format_mfib_entry_flags, msrc->mfes_flags); + s = format (s, " src:%s locks:%d:", + mfib_source_names[msrc->mfes_src], + msrc->mfes_ref_count); + if (msrc->mfes_cover != FIB_NODE_INDEX_INVALID) + { + s = format (s, " cover:%d", msrc->mfes_cover); + } + s = format (s, " %U\n", format_mfib_entry_flags, msrc->mfes_flags); if (FIB_NODE_INDEX_INVALID != msrc->mfes_pl) { s = fib_path_list_format(msrc->mfes_pl, s); @@ -254,6 +203,9 @@ mfib_entry_src_init (mfib_entry_t *mfib_entry, .mfes_pl = FIB_NODE_INDEX_INVALID, .mfes_flags = MFIB_ENTRY_FLAG_NONE, .mfes_src = source, + .mfes_cover = FIB_NODE_INDEX_INVALID, + .mfes_sibling = FIB_NODE_INDEX_INVALID, + .mfes_ref_count = 1, }; vec_add1(mfib_entry->mfe_srcs, esrc); @@ -294,19 +246,51 @@ static mfib_entry_src_t * mfib_entry_src_find_or_create (mfib_entry_t *mfib_entry, mfib_source_t source) { - mfib_entry_src_t *esrc; + mfib_entry_src_t *msrc; - esrc = mfib_entry_src_find(mfib_entry, source, NULL); + msrc = mfib_entry_src_find(mfib_entry, source, NULL); - if (NULL == esrc) + if (NULL == msrc) { mfib_entry_src_init(mfib_entry, source); + msrc = mfib_entry_src_find(mfib_entry, source, NULL); } - return (mfib_entry_src_find(mfib_entry, source, NULL)); + return (msrc); +} + +static mfib_entry_src_t * +mfib_entry_src_update (mfib_entry_t *mfib_entry, + mfib_source_t source, + fib_rpf_id_t rpf_id, + mfib_entry_flags_t entry_flags) +{ + mfib_entry_src_t *msrc; + + msrc = mfib_entry_src_find_or_create(mfib_entry, source); + + msrc->mfes_flags = entry_flags; + msrc->mfes_rpf_id = rpf_id; + + return (msrc); } -static mfib_entry_src_t* +static mfib_entry_src_t * +mfib_entry_src_update_and_lock (mfib_entry_t *mfib_entry, + mfib_source_t source, + fib_rpf_id_t rpf_id, + mfib_entry_flags_t entry_flags) +{ + mfib_entry_src_t *msrc; + + msrc = mfib_entry_src_update(mfib_entry, source, rpf_id, entry_flags); + + msrc->mfes_ref_count++; + + return (msrc); +} + +mfib_entry_src_t* mfib_entry_get_best_src (const mfib_entry_t *mfib_entry) { mfib_entry_src_t *bsrc; @@ -326,6 +310,16 @@ mfib_entry_get_best_src (const mfib_entry_t *mfib_entry) return (bsrc); } +static mfib_source_t +mfib_entry_get_best_source (const mfib_entry_t *mfib_entry) +{ + mfib_entry_src_t *bsrc; + + bsrc = mfib_entry_get_best_src(mfib_entry); + + return (bsrc->mfes_src); +} + int mfib_entry_is_sourced (fib_node_index_t mfib_entry_index, mfib_source_t source) @@ -337,6 +331,13 @@ mfib_entry_is_sourced (fib_node_index_t mfib_entry_index, return (NULL != mfib_entry_src_find(mfib_entry, source, NULL)); } +int +mfib_entry_is_host (fib_node_index_t mfib_entry_index) +{ + return (mfib_prefix_is_host(mfib_entry_get_prefix(mfib_entry_index))); +} + + static void mfib_entry_src_flush (mfib_entry_src_t *msrc) { @@ -364,8 +365,19 @@ mfib_entry_src_remove (mfib_entry_t *mfib_entry, if (NULL != msrc) { - mfib_entry_src_flush(msrc); - vec_del1(mfib_entry->mfe_srcs, index); + ASSERT(0 != msrc->mfes_ref_count); + msrc->mfes_ref_count--; + + if (0 == msrc->mfes_ref_count) + { + mfib_entry_src_deactivate(mfib_entry, msrc); + mfib_entry_src_flush(msrc); + + vec_del1(mfib_entry->mfe_srcs, index); + if (vec_len (mfib_entry->mfe_srcs) > 1) + vec_sort_with_function(mfib_entry->mfe_srcs, + mfib_entry_src_cmp_for_sort); + } } } @@ -552,8 +564,7 @@ mfib_entry_stack (mfib_entry_t *mfib_entry, mfib_entry->mfe_sibling); } - if (NULL != msrc && - FIB_NODE_INDEX_INVALID != msrc->mfes_pl) + if (NULL != msrc) { mfib_entry_collect_forwarding_ctx_t ctx = { .next_hops = NULL, @@ -561,10 +572,27 @@ mfib_entry_stack (mfib_entry_t *mfib_entry, .msrc = msrc, }; - fib_path_list_walk(msrc->mfes_pl, - mfib_entry_src_collect_forwarding, - &ctx); + /* + * link the entry to the path-list. + * The entry needs to be a child so that we receive the back-walk + * updates to recalculate forwarding. + */ + mfib_entry->mfe_pl = msrc->mfes_pl; + mfib_entry->mfe_flags = msrc->mfes_flags; + mfib_entry->mfe_itfs = msrc->mfes_itfs; + mfib_entry->mfe_rpf_id = msrc->mfes_rpf_id; + if (FIB_NODE_INDEX_INVALID != mfib_entry->mfe_pl) + { + mfib_entry->mfe_sibling = + fib_path_list_child_add(mfib_entry->mfe_pl, + FIB_NODE_TYPE_MFIB_ENTRY, + mfib_entry_get_index(mfib_entry)); + + fib_path_list_walk(mfib_entry->mfe_pl, + mfib_entry_src_collect_forwarding, + &ctx); + } if (!(MFIB_ENTRY_FLAG_EXCLUSIVE & mfib_entry->mfe_flags)) { if (NULL == ctx.next_hops) @@ -616,17 +644,6 @@ mfib_entry_stack (mfib_entry_t *mfib_entry, dpo_reset(&ctx.next_hops[0].path_dpo); vec_free(ctx.next_hops); } - - /* - * link the entry to the path-list. - * The entry needs to be a child so that we receive the back-walk - * updates to recalculate forwarding. - */ - mfib_entry->mfe_pl = msrc->mfes_pl; - mfib_entry->mfe_sibling = - fib_path_list_child_add(mfib_entry->mfe_pl, - FIB_NODE_TYPE_MFIB_ENTRY, - mfib_entry_get_index(mfib_entry)); } else { @@ -634,6 +651,17 @@ mfib_entry_stack (mfib_entry_t *mfib_entry, &mfib_entry->mfe_rep, drop_dpo_get(dp)); } + + /* + * time for walkies fido. + */ + fib_node_back_walk_ctx_t bw_ctx = { + .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE, + }; + + fib_walk_sync(FIB_NODE_TYPE_MFIB_ENTRY, + mfib_entry_get_index(mfib_entry), + &bw_ctx); } static fib_node_index_t @@ -689,23 +717,36 @@ mfib_entry_src_path_remove (mfib_entry_src_t *msrc, } static void -mfib_entry_recalculate_forwarding (mfib_entry_t *mfib_entry) +mfib_entry_recalculate_forwarding (mfib_entry_t *mfib_entry, + mfib_source_t old_best) { - mfib_entry_src_t *bsrc; + mfib_entry_src_t *bsrc, *osrc; /* * copy the forwarding data from the bast source */ bsrc = mfib_entry_get_best_src(mfib_entry); + osrc = mfib_entry_src_find(mfib_entry, old_best, NULL); if (NULL != bsrc) { - mfib_entry->mfe_flags = bsrc->mfes_flags; - mfib_entry->mfe_itfs = bsrc->mfes_itfs; - mfib_entry->mfe_rpf_id = bsrc->mfes_rpf_id; + if (bsrc->mfes_src != old_best) + { + /* + * we are changing from one source to another + * deactivate the old, and activate the new + */ + mfib_entry_src_deactivate(mfib_entry, osrc); + mfib_entry_src_activate(mfib_entry, bsrc); + } + } + else + { + mfib_entry_src_deactivate(mfib_entry, osrc); } mfib_entry_stack(mfib_entry, bsrc); + mfib_entry_cover_update_notify(mfib_entry); } @@ -714,7 +755,8 @@ mfib_entry_create (u32 fib_index, mfib_source_t source, const mfib_prefix_t *prefix, fib_rpf_id_t rpf_id, - mfib_entry_flags_t entry_flags) + mfib_entry_flags_t entry_flags, + index_t repi) { fib_node_index_t mfib_entry_index; mfib_entry_t *mfib_entry; @@ -722,11 +764,37 @@ mfib_entry_create (u32 fib_index, mfib_entry = mfib_entry_alloc(fib_index, prefix, &mfib_entry_index); - msrc = mfib_entry_src_find_or_create(mfib_entry, source); - msrc->mfes_flags = entry_flags; - msrc->mfes_rpf_id = rpf_id; + msrc = mfib_entry_src_update(mfib_entry, source, + rpf_id, entry_flags); - mfib_entry_recalculate_forwarding(mfib_entry); + if (INDEX_INVALID != repi) + { + /* + * The source is providing its own replicate DPO. + * Create a sepcial path-list to manage it, that way + * this entry and the source are equivalent to a normal + * entry + */ + fib_node_index_t old_pl_index; + dpo_proto_t dp; + dpo_id_t dpo = DPO_INVALID; + + dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry)); + old_pl_index = msrc->mfes_pl; + + dpo_set(&dpo, DPO_REPLICATE, dp, repi); + + msrc->mfes_pl = + fib_path_list_create_special(dp, + FIB_PATH_LIST_FLAG_EXCLUSIVE, + &dpo); + + dpo_reset(&dpo); + fib_path_list_lock(msrc->mfes_pl); + fib_path_list_unlock(old_pl_index); + } + + mfib_entry_recalculate_forwarding(mfib_entry, MFIB_SOURCE_NONE); return (mfib_entry_index); } @@ -740,25 +808,18 @@ mfib_entry_ok_for_delete (mfib_entry_t *mfib_entry) static int mfib_entry_src_ok_for_delete (const mfib_entry_src_t *msrc) { - return ((MFIB_ENTRY_FLAG_NONE == msrc->mfes_flags && + return ((INDEX_INVALID == msrc->mfes_cover && + MFIB_ENTRY_FLAG_NONE == msrc->mfes_flags && 0 == fib_path_list_get_n_paths(msrc->mfes_pl))); } -int -mfib_entry_update (fib_node_index_t mfib_entry_index, - mfib_source_t source, - mfib_entry_flags_t entry_flags, - fib_rpf_id_t rpf_id, - index_t repi) -{ - mfib_entry_t *mfib_entry; - mfib_entry_src_t *msrc; - - mfib_entry = mfib_entry_get(mfib_entry_index); - msrc = mfib_entry_src_find_or_create(mfib_entry, source); - msrc->mfes_flags = entry_flags; - msrc->mfes_rpf_id = rpf_id; +static void +mfib_entry_update_i (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc, + mfib_source_t current_best, + index_t repi) +{ if (INDEX_INVALID != repi) { /* @@ -792,10 +853,50 @@ mfib_entry_update (fib_node_index_t mfib_entry_index, * this source has no interfaces and no flags. * it has nothing left to give - remove it */ - mfib_entry_src_remove(mfib_entry, source); + mfib_entry_src_remove(mfib_entry, msrc->mfes_src); } - mfib_entry_recalculate_forwarding(mfib_entry); + mfib_entry_recalculate_forwarding(mfib_entry, current_best); +} + +int +mfib_entry_special_add (fib_node_index_t mfib_entry_index, + mfib_source_t source, + mfib_entry_flags_t entry_flags, + fib_rpf_id_t rpf_id, + index_t repi) +{ + mfib_source_t current_best; + mfib_entry_t *mfib_entry; + mfib_entry_src_t *msrc; + + mfib_entry = mfib_entry_get(mfib_entry_index); + current_best = mfib_entry_get_best_source(mfib_entry); + + msrc = mfib_entry_src_update_and_lock(mfib_entry, source, rpf_id, + entry_flags); + + mfib_entry_update_i(mfib_entry, msrc, current_best, repi); + + return (mfib_entry_ok_for_delete(mfib_entry)); +} + +int +mfib_entry_update (fib_node_index_t mfib_entry_index, + mfib_source_t source, + mfib_entry_flags_t entry_flags, + fib_rpf_id_t rpf_id, + index_t repi) +{ + mfib_source_t current_best; + mfib_entry_t *mfib_entry; + mfib_entry_src_t *msrc; + + mfib_entry = mfib_entry_get(mfib_entry_index); + current_best = mfib_entry_get_best_source(mfib_entry); + msrc = mfib_entry_src_update(mfib_entry, source, rpf_id, entry_flags); + + mfib_entry_update_i(mfib_entry, msrc, current_best, repi); return (mfib_entry_ok_for_delete(mfib_entry)); } @@ -828,6 +929,7 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index, mfib_itf_flags_t itf_flags) { fib_node_index_t path_index; + mfib_source_t current_best; mfib_path_ext_t *path_ext; mfib_entry_t *mfib_entry; mfib_entry_src_t *msrc; @@ -835,6 +937,7 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index, mfib_entry = mfib_entry_get(mfib_entry_index); ASSERT(NULL != mfib_entry); + current_best = mfib_entry_get_best_source(mfib_entry); msrc = mfib_entry_src_find_or_create(mfib_entry, source); /* @@ -897,7 +1000,7 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index, } } - mfib_entry_recalculate_forwarding(mfib_entry); + mfib_entry_recalculate_forwarding(mfib_entry, current_best); } /* @@ -912,11 +1015,13 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index, const fib_route_path_t *rpath) { fib_node_index_t path_index; + mfib_source_t current_best; mfib_entry_t *mfib_entry; mfib_entry_src_t *msrc; mfib_entry = mfib_entry_get(mfib_entry_index); ASSERT(NULL != mfib_entry); + current_best = mfib_entry_get_best_source(mfib_entry); msrc = mfib_entry_src_find(mfib_entry, source, NULL); if (NULL == msrc) @@ -968,7 +1073,7 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index, mfib_entry_src_remove(mfib_entry, source); } - mfib_entry_recalculate_forwarding(mfib_entry); + mfib_entry_recalculate_forwarding(mfib_entry, current_best); return (mfib_entry_ok_for_delete(mfib_entry)); } @@ -982,12 +1087,14 @@ int mfib_entry_delete (fib_node_index_t mfib_entry_index, mfib_source_t source) { + mfib_source_t current_best; mfib_entry_t *mfib_entry; mfib_entry = mfib_entry_get(mfib_entry_index); + current_best = mfib_entry_get_best_source(mfib_entry); mfib_entry_src_remove(mfib_entry, source); - mfib_entry_recalculate_forwarding(mfib_entry); + mfib_entry_recalculate_forwarding(mfib_entry, current_best); return (mfib_entry_ok_for_delete(mfib_entry)); } @@ -1116,7 +1223,11 @@ static fib_node_back_walk_rc_t mfib_entry_back_walk_notify (fib_node_t *node, fib_node_back_walk_ctx_t *ctx) { - mfib_entry_recalculate_forwarding(mfib_entry_from_fib_node(node)); + mfib_entry_t *mfib_entry; + + mfib_entry = mfib_entry_from_fib_node(node); + mfib_entry_recalculate_forwarding(mfib_entry, + mfib_entry_get_best_source(mfib_entry)); return (FIB_NODE_BACK_WALK_CONTINUE); } @@ -1219,15 +1330,14 @@ mfib_entry_encode (fib_node_index_t mfib_entry_index, } } - -void -mfib_entry_get_prefix (fib_node_index_t mfib_entry_index, - mfib_prefix_t *pfx) +const mfib_prefix_t * +mfib_entry_get_prefix (fib_node_index_t mfib_entry_index) { mfib_entry_t *mfib_entry; mfib_entry = mfib_entry_get(mfib_entry_index); - *pfx = mfib_entry->mfe_prefix; + + return (&mfib_entry->mfe_prefix); } u32 @@ -1253,6 +1363,7 @@ mfib_entry_contribute_ip_forwarding (fib_node_index_t mfib_entry_index) void mfib_entry_contribute_forwarding (fib_node_index_t mfib_entry_index, fib_forward_chain_type_t type, + mfib_entry_fwd_flags_t flags, dpo_id_t *dpo) { /* @@ -1267,9 +1378,26 @@ mfib_entry_contribute_forwarding (fib_node_index_t mfib_entry_index, dp = fib_proto_to_dpo(mfib_entry->mfe_prefix.fp_proto); - if (type == fib_forw_chain_type_from_dpo_proto(dp)) + if (type == mfib_forw_chain_type_from_dpo_proto(dp)) { - dpo_copy(dpo, &mfib_entry->mfe_rep); + replicate_t * rep; + + rep = replicate_get(mfib_entry->mfe_rep.dpoi_index); + + if ((rep->rep_flags & REPLICATE_FLAGS_HAS_LOCAL) && + (flags & MFIB_ENTRY_FWD_FLAG_NO_LOCAL)) + { + /* + * caller does not want the local paths that the entry has + */ + dpo_set(dpo, DPO_REPLICATE, rep->rep_proto, + replicate_dup(REPLICATE_FLAGS_NONE, + mfib_entry->mfe_rep.dpoi_index)); + } + else + { + dpo_copy(dpo, &mfib_entry->mfe_rep); + } } else { @@ -1277,6 +1405,55 @@ mfib_entry_contribute_forwarding (fib_node_index_t mfib_entry_index, } } +/* + * fib_entry_cover_changed + * + * this entry is tracking its cover and that cover has changed. + */ +void +mfib_entry_cover_changed (fib_node_index_t mfib_entry_index) +{ + mfib_entry_t *mfib_entry; + mfib_entry_src_t *msrc; + mfib_src_res_t res; + + mfib_entry = mfib_entry_get(mfib_entry_index); + msrc = mfib_entry_get_best_src(mfib_entry); + + res = mfib_entry_src_cover_change(mfib_entry, msrc); + + if (MFIB_SRC_REEVALUATE == res) + { + mfib_entry_recalculate_forwarding(mfib_entry, msrc->mfes_src); + } + MFIB_ENTRY_DBG(mfib_entry, "cover-changed"); +} + +/* + * mfib_entry_cover_updated + * + * this entry is tracking its cover and that cover has been updated + * (i.e. its forwarding information has changed). + */ +void +mfib_entry_cover_updated (fib_node_index_t mfib_entry_index) +{ + mfib_entry_t *mfib_entry; + mfib_entry_src_t *msrc; + mfib_src_res_t res; + + mfib_entry = mfib_entry_get(mfib_entry_index); + msrc = mfib_entry_get_best_src(mfib_entry); + + res = mfib_entry_src_cover_update(mfib_entry, msrc); + + if (MFIB_SRC_REEVALUATE == res) + { + mfib_entry_recalculate_forwarding(mfib_entry, msrc->mfes_src); + } + MFIB_ENTRY_DBG(mfib_entry, "cover-updated"); +} + u32 mfib_entry_pool_size (void) { diff --git a/src/vnet/mfib/mfib_entry.h b/src/vnet/mfib/mfib_entry.h index 880c1e2933c..8ab7cee5ea7 100644 --- a/src/vnet/mfib/mfib_entry.h +++ b/src/vnet/mfib/mfib_entry.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -34,10 +35,12 @@ typedef struct mfib_entry_t_ { * Base class. The entry's node representation in the graph. */ fib_node_t mfe_node; + /** * The prefix of the route */ mfib_prefix_t mfe_prefix; + /** * The index of the FIB table this entry is in */ @@ -82,8 +85,28 @@ typedef struct mfib_entry_t_ { * A hash table of interfaces */ mfib_itf_t *mfe_itfs; + + /** + * A vector of delegates. + */ + mfib_entry_delegate_t *fe_delegates; } mfib_entry_t; +/** + * Debug macro + */ +extern vlib_log_class_t mfib_entry_logger; + +#define MFIB_ENTRY_DBG(_e, _fmt, _args...) \ +{ \ + vlib_log_debug(mfib_entry_logger, \ + "e:[%d:%U]: " _fmt, \ + mfib_entry_get_index(_e), \ + format_mfib_prefix, \ + &_e->mfe_prefix, \ + ##_args); \ +} + #define MFIB_ENTRY_FORMAT_BRIEF (0x0) #define MFIB_ENTRY_FORMAT_DETAIL (0x1) #define MFIB_ENTRY_FORMAT_DETAIL2 (0x2) @@ -95,7 +118,8 @@ extern fib_node_index_t mfib_entry_create(u32 fib_index, mfib_source_t source, const mfib_prefix_t *prefix, fib_rpf_id_t rpf_id, - mfib_entry_flags_t entry_flags); + mfib_entry_flags_t entry_flags, + index_t repi); extern int mfib_entry_update(fib_node_index_t fib_entry_index, mfib_source_t source, @@ -103,6 +127,12 @@ extern int mfib_entry_update(fib_node_index_t fib_entry_index, fib_rpf_id_t rpf_id, index_t rep_dpo); +extern int mfib_entry_special_add(fib_node_index_t fib_entry_index, + mfib_source_t source, + mfib_entry_flags_t entry_flags, + fib_rpf_id_t rpf_id, + index_t rep_dpo); + extern void mfib_entry_path_update(fib_node_index_t fib_entry_index, mfib_source_t source, const fib_route_path_t *rpath, @@ -127,19 +157,35 @@ extern void mfib_entry_child_remove(fib_node_index_t mfib_entry_index, extern void mfib_entry_lock(fib_node_index_t fib_entry_index); extern void mfib_entry_unlock(fib_node_index_t fib_entry_index); -extern void mfib_entry_get_prefix(fib_node_index_t fib_entry_index, - mfib_prefix_t *pfx); +extern const mfib_prefix_t *mfib_entry_get_prefix(fib_node_index_t fib_entry_index); extern u32 mfib_entry_get_fib_index(fib_node_index_t fib_entry_index); extern int mfib_entry_is_sourced(fib_node_index_t fib_entry_index, mfib_source_t source); +extern int mfib_entry_is_host(fib_node_index_t fib_entry_index); extern u32 mfib_entry_get_stats_index(fib_node_index_t fib_entry_index); +extern void mfib_entry_cover_changed(fib_node_index_t fib_entry_index); +extern void mfib_entry_cover_updated(fib_node_index_t fib_entry_index); extern const dpo_id_t*mfib_entry_contribute_ip_forwarding( fib_node_index_t mfib_entry_index); +/** + * Flags to control what is present in the replicate DPO returned when + * the entry contributes forwarding + */ +typedef enum mfib_entry_fwd_flags_t_ +{ + MFIB_ENTRY_FWD_FLAG_NONE, + /** + * Do not reutrn any local replications in the set + */ + MFIB_ENTRY_FWD_FLAG_NO_LOCAL, +} mfib_entry_fwd_flags_t; + extern void mfib_entry_contribute_forwarding( fib_node_index_t mfib_entry_index, fib_forward_chain_type_t type, + mfib_entry_fwd_flags_t flags, dpo_id_t *dpo); extern void mfib_entry_encode(fib_node_index_t fib_entry_index, diff --git a/src/vnet/mfib/mfib_entry_cover.c b/src/vnet/mfib/mfib_entry_cover.c new file mode 100644 index 00000000000..6caeb1b6928 --- /dev/null +++ b/src/vnet/mfib/mfib_entry_cover.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +u32 +mfib_entry_cover_track (mfib_entry_t* cover, + fib_node_index_t covered) +{ + mfib_entry_delegate_t *mfed; + + MFIB_ENTRY_DBG(cover, "cover-track %d", covered); + + ASSERT(mfib_entry_get_index(cover) != covered); + + mfed = mfib_entry_delegate_get(cover, MFIB_ENTRY_DELEGATE_COVERED); + + if (NULL == mfed) + { + mfed = mfib_entry_delegate_find_or_add(cover, MFIB_ENTRY_DELEGATE_COVERED); + mfed->mfd_list = fib_node_list_create(); + } + + return (fib_node_list_push_front(mfed->mfd_list, + 0, FIB_NODE_TYPE_MFIB_ENTRY, + covered)); +} + +void +mfib_entry_cover_untrack (mfib_entry_t* cover, + u32 tracked_index) +{ + mfib_entry_delegate_t *mfed; + + MFIB_ENTRY_DBG(cover, "cover-untrack @ %d", tracked_index); + + mfed = mfib_entry_delegate_get(cover, MFIB_ENTRY_DELEGATE_COVERED); + + if (NULL == mfed) + return; + + fib_node_list_remove(mfed->mfd_list, tracked_index); + + if (0 == fib_node_list_get_size(mfed->mfd_list)) + { + fib_node_list_destroy(&mfed->mfd_list); + mfib_entry_delegate_remove(cover, MFIB_ENTRY_DELEGATE_COVERED); + } +} + +/** + * Internal struct to hold user supplied paraneters for the cover walk + */ +typedef struct mfib_enty_cover_walk_ctx_t_ { + mfib_entry_t *cover; + mfib_entry_covered_walk_t walk; + void *ctx; +} mfib_enty_cover_walk_ctx_t; + +static int +mfib_entry_cover_walk_node_ptr (fib_node_ptr_t *depend, + void *args) +{ + mfib_enty_cover_walk_ctx_t *ctx = args; + + ctx->walk(ctx->cover, depend->fnp_index, ctx->ctx); + + /* continue */ + return (1); +} + +void +mfib_entry_cover_walk (mfib_entry_t *cover, + mfib_entry_covered_walk_t walk, + void *args) +{ + mfib_entry_delegate_t *mfed; + + mfed = mfib_entry_delegate_get(cover, MFIB_ENTRY_DELEGATE_COVERED); + + if (NULL == mfed) + return; + + mfib_enty_cover_walk_ctx_t ctx = { + .cover = cover, + .walk = walk, + .ctx = args, + }; + + fib_node_list_walk(mfed->mfd_list, + mfib_entry_cover_walk_node_ptr, + &ctx); +} + +static int +mfib_entry_cover_change_one (mfib_entry_t *cover, + fib_node_index_t covered, + void *args) +{ + fib_node_index_t new_cover; + + /* + * The 3 entries involved here are: + * cover - the least specific. It will cover both the others + * new_cover - the enty just inserted below the cover + * covered - the entry that was tracking the cover. + * + * The checks below are to determine if new_cover is a cover for covered. + */ + new_cover = pointer_to_uword(args); + + if (FIB_NODE_INDEX_INVALID == new_cover) + { + /* + * nothing has been inserted, which implies the cover was removed. + * 'cover' is thus the new cover. + */ + mfib_entry_cover_changed(covered); + } + else if (new_cover != covered) + { + const mfib_prefix_t *pfx_covered, *pfx_new_cover; + + pfx_covered = mfib_entry_get_prefix(covered); + pfx_new_cover = mfib_entry_get_prefix(new_cover); + + if (mfib_prefix_is_cover(pfx_new_cover, pfx_covered)) + { + mfib_entry_cover_changed(covered); + } + } + /* continue */ + return (1); +} + +void +mfib_entry_cover_change_notify (fib_node_index_t cover_index, + fib_node_index_t covered) +{ + mfib_entry_t *cover; + + cover = mfib_entry_get(cover_index); + + mfib_entry_cover_walk(cover, + mfib_entry_cover_change_one, + uword_to_pointer(covered, void*)); +} + +static int +mfib_entry_cover_update_one (mfib_entry_t *cover, + fib_node_index_t covered, + void *args) +{ + mfib_entry_cover_updated(covered); + + /* continue */ + return (1); +} + +void +mfib_entry_cover_update_notify (mfib_entry_t *mfib_entry) +{ + mfib_entry_cover_walk(mfib_entry, + mfib_entry_cover_update_one, + NULL); +} diff --git a/src/vnet/mfib/mfib_entry_cover.h b/src/vnet/mfib/mfib_entry_cover.h new file mode 100644 index 00000000000..8f165c29dfd --- /dev/null +++ b/src/vnet/mfib/mfib_entry_cover.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MFIB_ENTRY_COVER_H__ +#define __MFIB_ENTRY_COVER_H__ + +#include + +/** + * callback function used when walking the covered entries + */ +typedef int (*mfib_entry_covered_walk_t)(mfib_entry_t *cover, + fib_node_index_t covered, + void *ctx); + +extern u32 mfib_entry_cover_track(mfib_entry_t *cover, + fib_node_index_t covered); + +extern void mfib_entry_cover_untrack(mfib_entry_t *cover, + u32 tracked_index); + +extern void mfib_entry_cover_walk(mfib_entry_t *cover, + mfib_entry_covered_walk_t walk, + void *ctx); + +extern void mfib_entry_cover_change_notify(fib_node_index_t cover_index, + fib_node_index_t covered_index); +extern void mfib_entry_cover_update_notify(mfib_entry_t *cover); + +#endif diff --git a/src/vnet/mfib/mfib_entry_delegate.c b/src/vnet/mfib/mfib_entry_delegate.c new file mode 100644 index 00000000000..95915cb3807 --- /dev/null +++ b/src/vnet/mfib/mfib_entry_delegate.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +static mfib_entry_delegate_t * +mfib_entry_delegate_find_i (const mfib_entry_t *mfib_entry, + mfib_entry_delegate_type_t type, + u32 *index) +{ + mfib_entry_delegate_t *delegate; + int ii; + + ii = 0; + vec_foreach(delegate, mfib_entry->fe_delegates) + { + if (delegate->mfd_type == type) + { + if (NULL != index) + *index = ii; + + return (delegate); + } + else + { + ii++; + } + } + + return (NULL); +} + +mfib_entry_delegate_t * +mfib_entry_delegate_get (const mfib_entry_t *mfib_entry, + mfib_entry_delegate_type_t type) +{ + return (mfib_entry_delegate_find_i(mfib_entry, type, NULL)); +} + +void +mfib_entry_delegate_remove (mfib_entry_t *mfib_entry, + mfib_entry_delegate_type_t type) +{ + mfib_entry_delegate_t *fed; + u32 index = ~0; + + fed = mfib_entry_delegate_find_i(mfib_entry, type, &index); + + ASSERT(NULL != fed); + + vec_del1(mfib_entry->fe_delegates, index); +} + +static int +mfib_entry_delegate_cmp_for_sort (void * v1, + void * v2) +{ + mfib_entry_delegate_t *delegate1 = v1, *delegate2 = v2; + + return (delegate1->mfd_type - delegate2->mfd_type); +} + +static void +mfib_entry_delegate_init (mfib_entry_t *mfib_entry, + mfib_entry_delegate_type_t type) + +{ + mfib_entry_delegate_t delegate = { + .mfd_entry_index = mfib_entry_get_index(mfib_entry), + .mfd_type = type, + }; + + vec_add1(mfib_entry->fe_delegates, delegate); + vec_sort_with_function(mfib_entry->fe_delegates, + mfib_entry_delegate_cmp_for_sort); +} + +mfib_entry_delegate_t * +mfib_entry_delegate_find_or_add (mfib_entry_t *mfib_entry, + mfib_entry_delegate_type_t fdt) +{ + mfib_entry_delegate_t *delegate; + + delegate = mfib_entry_delegate_get(mfib_entry, fdt); + + if (NULL == delegate) + { + mfib_entry_delegate_init(mfib_entry, fdt); + } + + return (mfib_entry_delegate_get(mfib_entry, fdt)); +} + +/** + * typedef for printing a delegate + */ +typedef u8 * (*mfib_entry_delegate_format_t)(const mfib_entry_delegate_t *fed, + u8 *s); + +/** + * Print a delegate that represents cover tracking + */ +static u8 * +mfib_entry_delegate_fmt_covered (const mfib_entry_delegate_t *fed, + u8 *s) +{ + s = format(s, "covered:["); + s = fib_node_children_format(fed->mfd_list, s); + s = format(s, "]"); + + return (s); +} + +/** + * A delegate type to formatter map + */ +static mfib_entry_delegate_format_t fed_formatters[] = +{ + [MFIB_ENTRY_DELEGATE_COVERED] = mfib_entry_delegate_fmt_covered, +}; + +u8 * +format_mfib_entry_deletegate (u8 * s, va_list * args) +{ + mfib_entry_delegate_t *fed; + + fed = va_arg (*args, mfib_entry_delegate_t *); + + return (fed_formatters[fed->mfd_type](fed, s)); +} diff --git a/src/vnet/mfib/mfib_entry_delegate.h b/src/vnet/mfib/mfib_entry_delegate.h new file mode 100644 index 00000000000..0454a0f157a --- /dev/null +++ b/src/vnet/mfib/mfib_entry_delegate.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MFIB_ENTRY_DELEGATE_T__ +#define __MFIB_ENTRY_DELEGATE_T__ + +#include + +/** + * Delegate types + */ +typedef enum mfib_entry_delegate_type_t_ { + /** + * Dependency list of covered entries. + * these are more specific entries that are interested in changes + * to their respective cover + */ + MFIB_ENTRY_DELEGATE_COVERED, +} mfib_entry_delegate_type_t; + +#define FOR_EACH_MFIB_DELEGATE(_entry, _fdt, _fed, _body) \ +{ \ + for (_fdt = MFIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4; \ + _fdt <= MFIB_ENTRY_DELEGATE_ATTACHED_EXPORT; \ + _fdt++) \ + { \ + _fed = mfib_entry_delegate_get(_entry, _fdt); \ + if (NULL != _fed) { \ + _body; \ + } \ + } \ +} + +/** + * A Delagate is a means to implmenet the Delagation design pattern; the extension of an + * objects functionality through the composition of, and delgation to, other objects. + * These 'other' objects are delegates. Delagates are thus attached to other MFIB objects + * to extend their functionality. + */ +typedef struct mfib_entry_delegate_t_ +{ + /** + * The MFIB entry object to which the delagate is attached + */ + fib_node_index_t mfd_entry_index; + + /** + * The delagate type + */ + mfib_entry_delegate_type_t mfd_type; + + /** + * A union of data for the different delegate types + * These delegates are stored in a sparse vector on the entry, so they + * must all be of the same size. + */ + union + { + /** + * For the cover tracking. The node list; + */ + fib_node_list_t mfd_list; + }; +} mfib_entry_delegate_t; + +struct mfib_entry_t_; + +extern void mfib_entry_delegate_remove(struct mfib_entry_t_ *mfib_entry, + mfib_entry_delegate_type_t type); + +extern mfib_entry_delegate_t *mfib_entry_delegate_find_or_add(struct mfib_entry_t_ *mfib_entry, + mfib_entry_delegate_type_t fdt); +extern mfib_entry_delegate_t *mfib_entry_delegate_get(const struct mfib_entry_t_ *mfib_entry, + mfib_entry_delegate_type_t type); + +extern u8 *format_mfib_entry_deletegate(u8 * s, va_list * args); + +#endif diff --git a/src/vnet/mfib/mfib_entry_src.c b/src/vnet/mfib/mfib_entry_src.c new file mode 100644 index 00000000000..ca5c788a546 --- /dev/null +++ b/src/vnet/mfib/mfib_entry_src.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include + +static mfib_entry_src_vft mfib_entry_src_vfts[MFIB_N_SOURCES]; + +static void +mfib_entry_src_default_deactiviate (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ +} + +static void +mfib_entry_src_default_activiate (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ +} + +static mfib_src_res_t +mfib_entry_src_default_cover_change (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + return (MFIB_SRC_OK); +} + +static mfib_src_res_t +mfib_entry_src_default_cover_update (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + return (MFIB_SRC_OK); +} + +void +mfib_entry_src_register (mfib_source_t source, + const mfib_entry_src_vft *mvft) +{ + mfib_entry_src_vfts[source] = *mvft; +} + +void +mfib_entry_src_deactivate (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + if (NULL != msrc) + mfib_entry_src_vfts[msrc->mfes_src].mev_deactivate(mfib_entry, msrc); +} + +void +mfib_entry_src_activate (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + if (NULL != msrc) + mfib_entry_src_vfts[msrc->mfes_src].mev_activate(mfib_entry, msrc); +} + +mfib_src_res_t +mfib_entry_src_cover_change (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + return (mfib_entry_src_vfts[msrc->mfes_src].mev_cover_change(mfib_entry, msrc)); +} + +mfib_src_res_t +mfib_entry_src_cover_update (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + return (mfib_entry_src_vfts[msrc->mfes_src].mev_cover_update(mfib_entry, msrc)); +} + +void +mfib_entry_src_module_init (void) +{ + mfib_entry_src_vft mvft = { + .mev_activate = mfib_entry_src_default_activiate, + .mev_deactivate = mfib_entry_src_default_deactiviate, + .mev_cover_change = mfib_entry_src_default_cover_change, + .mev_cover_update = mfib_entry_src_default_cover_update, + }; + mfib_source_t source; + + FOREACH_MFIB_SOURCE(source) + { + mfib_entry_src_register(source, &mvft); + } + + mfib_entry_src_rr_module_init(); +} diff --git a/src/vnet/mfib/mfib_entry_src.h b/src/vnet/mfib/mfib_entry_src.h new file mode 100644 index 00000000000..86752e071ec --- /dev/null +++ b/src/vnet/mfib/mfib_entry_src.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MFIB_ENTRY_SRC_H__ +#define __MFIB_ENTRY_SRC_H__ + +#include + +/** + * MFIB extensions to each path + */ +typedef struct mfib_path_ext_t_ +{ + mfib_itf_flags_t mfpe_flags; + fib_node_index_t mfpe_path; +} mfib_path_ext_t; + +/** + * The source of an MFIB entry + */ +typedef struct mfib_entry_src_t_ +{ + /** + * Which source this is + */ + mfib_source_t mfes_src; + + /** + * Route flags + */ + mfib_entry_flags_t mfes_flags; + + /** + * The reference count on the entry. this is a u32 + * since there is no path-list sharing in mfib, so the number + * os children could be high. + */ + u32 mfes_ref_count; + + /** + * The path-list of forwarding interfaces + */ + fib_node_index_t mfes_pl; + + /** + * RPF-ID + */ + fib_rpf_id_t mfes_rpf_id; + + /** + * Hash table of path extensions + */ + mfib_path_ext_t *mfes_exts; + + /** + * Covering entry (if needed) + */ + struct { + fib_node_index_t mfes_cover; + u32 mfes_sibling; + }; + + /** + * The hash table of all interfaces. + * This is forwarding time information derived from the paths + * and their extensions. + */ + mfib_itf_t *mfes_itfs; +} mfib_entry_src_t; + +/** + * signals from the sources to the caller + */ +typedef enum mfib_src_res_t_ +{ + MFIB_SRC_OK, + MFIB_SRC_REEVALUATE, +} mfib_src_res_t; + +/** + * A function provided by each source to be invoked when it is activated + */ +typedef void (*mfib_entry_src_activiate_t) (mfib_entry_t*, mfib_entry_src_t*); + +/** + * A function provided by each source to be invoked when it is deactivated + */ +typedef void (*mfib_entry_src_deactiviate_t) (mfib_entry_t*, mfib_entry_src_t*); + +/** + * A function provided by each source to be invoked when the cover changes + */ +typedef mfib_src_res_t (*mfib_entry_src_cover_change_t) (mfib_entry_t*, mfib_entry_src_t*); + +/** + * A function provided by each source to be invoked when the cover is updated + */ +typedef mfib_src_res_t (*mfib_entry_src_cover_update_t) (mfib_entry_t*, mfib_entry_src_t*); + +/** + * Virtual function table provided by each_source + */ +typedef struct mfib_entry_src_vft_t_ +{ + mfib_entry_src_activiate_t mev_activate; + mfib_entry_src_deactiviate_t mev_deactivate; + mfib_entry_src_cover_change_t mev_cover_change; + mfib_entry_src_cover_update_t mev_cover_update; +} mfib_entry_src_vft; + +extern void mfib_entry_src_register(mfib_source_t, const mfib_entry_src_vft*); + +extern void mfib_entry_src_deactivate(mfib_entry_t *mfib_entry, + mfib_entry_src_t *bsrc); + +extern void mfib_entry_src_activate(mfib_entry_t *mfib_entry, + mfib_entry_src_t *bsrc); + +extern mfib_src_res_t mfib_entry_src_cover_change(mfib_entry_t *mfib_entry, + mfib_entry_src_t *bsrc); + +extern mfib_src_res_t mfib_entry_src_cover_update(mfib_entry_t *mfib_entry, + mfib_entry_src_t *bsrc); + +extern mfib_entry_src_t* mfib_entry_get_best_src(const mfib_entry_t *mfib_entry); + +extern void mfib_entry_src_module_init(void); +extern void mfib_entry_src_rr_module_init(void); + +#endif diff --git a/src/vnet/mfib/mfib_entry_src_rr.c b/src/vnet/mfib/mfib_entry_src_rr.c new file mode 100644 index 00000000000..4512f74a9f5 --- /dev/null +++ b/src/vnet/mfib/mfib_entry_src_rr.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include + +static void +mfib_entry_src_rr_deactiviate (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + mfib_entry_t *cover; + + /* + * remove the depednecy on the covering entry + */ + if (FIB_NODE_INDEX_INVALID != msrc->mfes_cover) + { + cover = mfib_entry_get(msrc->mfes_cover); + mfib_entry_cover_untrack(cover, msrc->mfes_sibling); + msrc->mfes_cover = FIB_NODE_INDEX_INVALID; + } + + fib_path_list_unlock(msrc->mfes_pl); + msrc->mfes_pl = FIB_NODE_INDEX_INVALID; + msrc->mfes_itfs = NULL; + msrc->mfes_exts = NULL; +} + +static void +mfib_entry_src_rr_activiate (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + mfib_entry_src_t *csrc; + mfib_entry_t *cover; + + msrc->mfes_cover = mfib_table_get_less_specific(mfib_entry->mfe_fib_index, + &mfib_entry->mfe_prefix); + + ASSERT(FIB_NODE_INDEX_INVALID != msrc->mfes_cover); + + cover = mfib_entry_get(msrc->mfes_cover); + + msrc->mfes_sibling = + mfib_entry_cover_track(cover, mfib_entry_get_index(mfib_entry)); + + csrc = mfib_entry_get_best_src(cover); + + msrc->mfes_pl = csrc->mfes_pl; + fib_path_list_lock(msrc->mfes_pl); + msrc->mfes_flags = csrc->mfes_flags; + msrc->mfes_itfs = csrc->mfes_itfs; + msrc->mfes_exts = csrc->mfes_exts; + msrc->mfes_rpf_id = csrc->mfes_rpf_id; +} + +static mfib_src_res_t +mfib_entry_src_rr_cover_change (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + mfib_entry_src_rr_deactiviate(mfib_entry, msrc); + mfib_entry_src_rr_activiate(mfib_entry, msrc); + + return (MFIB_SRC_REEVALUATE); +} + +static mfib_src_res_t +mfib_entry_src_rr_cover_update (mfib_entry_t *mfib_entry, + mfib_entry_src_t *msrc) +{ + /* + * path lists are updated (i.e. not shared) in the mfib world, + * so there's no need to check for a new one. but we do need to + * copy down any new flags and input interfaces + */ + mfib_entry_t *cover; + + cover = mfib_entry_get(msrc->mfes_cover); + + msrc->mfes_flags = cover->mfe_flags; + msrc->mfes_itfs = cover->mfe_itfs; + msrc->mfes_rpf_id = cover->mfe_rpf_id; + + return (MFIB_SRC_REEVALUATE); +} + +void +mfib_entry_src_rr_module_init (void) +{ + mfib_entry_src_vft mvft = { + .mev_activate = mfib_entry_src_rr_activiate, + .mev_deactivate = mfib_entry_src_rr_deactiviate, + .mev_cover_change = mfib_entry_src_rr_cover_change, + .mev_cover_update = mfib_entry_src_rr_cover_update, + }; + + mfib_entry_src_register(MFIB_SOURCE_RR, &mvft); +} diff --git a/src/vnet/mfib/mfib_table.c b/src/vnet/mfib/mfib_table.c index 82431e370ee..8ae4a784684 100644 --- a/src/vnet/mfib/mfib_table.c +++ b/src/vnet/mfib/mfib_table.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include mfib_table_t * @@ -99,10 +101,41 @@ mfib_table_lookup_exact_match (u32 fib_index, prefix)); } +static fib_node_index_t +mfib_table_get_less_specific_i (const mfib_table_t *mfib_table, + const mfib_prefix_t *prefix) +{ + switch (prefix->fp_proto) + { + case FIB_PROTOCOL_IP4: + return (ip4_mfib_table_get_less_specific(&mfib_table->v4, + &prefix->fp_src_addr.ip4, + &prefix->fp_grp_addr.ip4, + prefix->fp_len)); + case FIB_PROTOCOL_IP6: + return (ip6_mfib_table_get_less_specific(&mfib_table->v6, + &prefix->fp_src_addr.ip6, + &prefix->fp_grp_addr.ip6, + prefix->fp_len)); + case FIB_PROTOCOL_MPLS: + break; + } + return (FIB_NODE_INDEX_INVALID); +} + +fib_node_index_t +mfib_table_get_less_specific (u32 fib_index, + const mfib_prefix_t *prefix) +{ + return (mfib_table_get_less_specific_i(mfib_table_get(fib_index, + prefix->fp_proto), + prefix)); +} + static void mfib_table_entry_remove (mfib_table_t *mfib_table, const mfib_prefix_t *prefix, - fib_node_index_t fib_entry_index) + fib_node_index_t mfib_entry_index) { vlib_smp_unsafe_warning(); @@ -127,9 +160,44 @@ mfib_table_entry_remove (mfib_table_t *mfib_table, break; } - mfib_entry_unlock(fib_entry_index); + mfib_entry_cover_change_notify(mfib_entry_index, + FIB_NODE_INDEX_INVALID); + mfib_entry_unlock(mfib_entry_index); } +static void +mfib_table_post_insert_actions (mfib_table_t *mfib_table, + const mfib_prefix_t *prefix, + fib_node_index_t mfib_entry_index) +{ + fib_node_index_t mfib_entry_cover_index; + + /* + * find the covering entry + */ + mfib_entry_cover_index = mfib_table_get_less_specific_i(mfib_table, + prefix); + /* + * the indicies are the same when the default route is first added + */ + if (mfib_entry_cover_index != mfib_entry_index) + { + /* + * inform the covering entry that a new more specific + * has been inserted beneath it. + * If the prefix that has been inserted is a host route + * then it is not possible that it will be the cover for any + * other entry, so we can elide the walk. + */ + if (!mfib_entry_is_host(mfib_entry_index)) + { + mfib_entry_cover_change_notify(mfib_entry_cover_index, + mfib_entry_index); + } + } +} + + static void mfib_table_entry_insert (mfib_table_t *mfib_table, const mfib_prefix_t *prefix, @@ -159,6 +227,8 @@ mfib_table_entry_insert (mfib_table_t *mfib_table, case FIB_PROTOCOL_MPLS: break; } + + mfib_table_post_insert_actions(mfib_table, prefix, mfib_entry_index); } fib_node_index_t @@ -183,7 +253,8 @@ mfib_table_entry_update (u32 fib_index, */ mfib_entry_index = mfib_entry_create(fib_index, source, prefix, rpf_id, - entry_flags); + entry_flags, + INDEX_INVALID); mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index); } @@ -234,16 +305,23 @@ mfib_table_entry_path_update (u32 fib_index, source, prefix, MFIB_RPF_ID_NONE, - MFIB_ENTRY_FLAG_NONE); + MFIB_ENTRY_FLAG_NONE, + INDEX_INVALID); + + mfib_entry_path_update(mfib_entry_index, + source, + rpath, + itf_flags); mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index); } - - mfib_entry_path_update(mfib_entry_index, - source, - rpath, - itf_flags); - + else + { + mfib_entry_path_update(mfib_entry_index, + source, + rpath, + itf_flags); + } return (mfib_entry_index); } @@ -295,7 +373,7 @@ mfib_table_entry_special_add (u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, mfib_entry_flags_t entry_flags, - index_t rep_dpo) + index_t repi) { fib_node_index_t mfib_entry_index; mfib_table_t *mfib_table; @@ -303,21 +381,27 @@ mfib_table_entry_special_add (u32 fib_index, mfib_table = mfib_table_get(fib_index, prefix->fp_proto); mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix); + if (INDEX_INVALID != repi) + { + entry_flags |= MFIB_ENTRY_FLAG_EXCLUSIVE; + } + if (FIB_NODE_INDEX_INVALID == mfib_entry_index) { mfib_entry_index = mfib_entry_create(fib_index, source, prefix, MFIB_RPF_ID_NONE, - MFIB_ENTRY_FLAG_NONE); + entry_flags, + repi); mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index); } - - mfib_entry_update(mfib_entry_index, source, - (MFIB_ENTRY_FLAG_EXCLUSIVE | entry_flags), - MFIB_RPF_ID_NONE, - rep_dpo); + else + { + mfib_entry_special_add(mfib_entry_index, source, entry_flags, + MFIB_RPF_ID_NONE, repi); + } return (mfib_entry_index); } @@ -380,12 +464,12 @@ void mfib_table_entry_delete_index (fib_node_index_t mfib_entry_index, mfib_source_t source) { - mfib_prefix_t prefix; + const mfib_prefix_t *prefix; - mfib_entry_get_prefix(mfib_entry_index, &prefix); + prefix = mfib_entry_get_prefix(mfib_entry_index); mfib_table_entry_delete_i(mfib_entry_get_fib_index(mfib_entry_index), - mfib_entry_index, &prefix, source); + mfib_entry_index, prefix, source); } u32 @@ -595,6 +679,17 @@ mfib_table_lock (u32 fib_index, mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]++; } +u32 +mfib_table_get_n_routes (fib_node_index_t fib_index, + fib_protocol_t proto) +{ + mfib_table_t *mfib_table; + + mfib_table = mfib_table_get(fib_index, proto); + + return (mfib_table->mft_total_route_counts); +} + void mfib_table_walk (u32 fib_index, fib_protocol_t proto, @@ -642,6 +737,7 @@ mfib_module_init (vlib_main_t * vm) { clib_error_t * error; + mfib_entry_src_module_init(); mfib_entry_module_init(); mfib_signal_module_init(); diff --git a/src/vnet/mfib/mfib_table.h b/src/vnet/mfib/mfib_table.h index b8ade8b5cd9..89f194f254e 100644 --- a/src/vnet/mfib/mfib_table.h +++ b/src/vnet/mfib/mfib_table.h @@ -403,6 +403,22 @@ extern void mfib_table_lock(u32 fib_index, extern u32 mfib_table_get_num_entries(u32 fib_index, fib_protocol_t proto); +/** + * @brief + * Get the less specific (covering) prefix + * + * @param fib_index + * The index of the FIB + * + * @param prefix + * The prefix to lookup + * + * @return + * The index of the less specific fib_entry_t. + */ +extern fib_node_index_t mfib_table_get_less_specific(u32 fib_index, + const mfib_prefix_t *prefix); + /** * @brief * Get a pointer to a FIB table @@ -430,4 +446,11 @@ extern void mfib_table_walk(u32 fib_index, */ extern u8 * format_mfib_table_memory(u8 * s, va_list * args); +/** + * To assit UT + */ +extern u32 mfib_table_get_n_routes(fib_node_index_t index, + fib_protocol_t proto); + + #endif diff --git a/src/vnet/mfib/mfib_types.c b/src/vnet/mfib/mfib_types.c index a3ed46a4b8d..19583ea18f4 100644 --- a/src/vnet/mfib/mfib_types.c +++ b/src/vnet/mfib/mfib_types.c @@ -26,6 +26,82 @@ static const char *mfib_flag_names_long[] = MFIB_ENTRY_NAMES_LONG; static const char *mfib_itf_flag_long_names[] = MFIB_ITF_NAMES_LONG; static const char *mfib_itf_flag_names[] = MFIB_ITF_NAMES_SHORT; +int +mfib_prefix_is_cover (const mfib_prefix_t *p1, + const mfib_prefix_t *p2) +{ + if (!ip46_address_is_equal(&p1->fp_src_addr, &p2->fp_src_addr)) + return (0); + + switch (p1->fp_proto) + { + case FIB_PROTOCOL_IP4: + return (ip4_destination_matches_route(&ip4_main, + &p1->fp_grp_addr.ip4, + &p2->fp_grp_addr.ip4, + p1->fp_len)); + case FIB_PROTOCOL_IP6: + return (ip6_destination_matches_route(&ip6_main, + &p1->fp_grp_addr.ip6, + &p2->fp_grp_addr.ip6, + p1->fp_len)); + case FIB_PROTOCOL_MPLS: + break; + } + return (0); +} + +int +mfib_prefix_is_host (const mfib_prefix_t *pfx) +{ + switch (pfx->fp_proto) + { + case FIB_PROTOCOL_IP4: + return (64 == pfx->fp_len); + case FIB_PROTOCOL_IP6: + return (256 == pfx->fp_len); + case FIB_PROTOCOL_MPLS: + ASSERT(0); + break; + } + return (0); +} + +fib_forward_chain_type_t +mfib_forw_chain_type_from_dpo_proto (dpo_proto_t proto) +{ + switch (proto) + { + case DPO_PROTO_IP4: + return (FIB_FORW_CHAIN_TYPE_MCAST_IP4); + case DPO_PROTO_IP6: + return (FIB_FORW_CHAIN_TYPE_MCAST_IP6); + case DPO_PROTO_MPLS: + case DPO_PROTO_ETHERNET: + case DPO_PROTO_NSH: + case DPO_PROTO_BIER: + break; + } + ASSERT(0); + return (FIB_FORW_CHAIN_TYPE_MCAST_IP4); +} + +fib_forward_chain_type_t +mfib_forw_chain_type_from_fib_proto (fib_protocol_t proto) +{ + switch (proto) + { + case FIB_PROTOCOL_IP4: + return (FIB_FORW_CHAIN_TYPE_MCAST_IP4); + case FIB_PROTOCOL_IP6: + return (FIB_FORW_CHAIN_TYPE_MCAST_IP6); + case FIB_PROTOCOL_MPLS: + break; + } + ASSERT(0); + return (FIB_FORW_CHAIN_TYPE_MCAST_IP4); +} + u8 * format_mfib_prefix (u8 * s, va_list * args) { diff --git a/src/vnet/mfib/mfib_types.h b/src/vnet/mfib/mfib_types.h index 58b7c987ab7..aea4a768a0b 100644 --- a/src/vnet/mfib/mfib_types.h +++ b/src/vnet/mfib/mfib_types.h @@ -169,10 +169,10 @@ typedef enum mfib_source_t_ MFIB_SOURCE_SRv6, MFIB_SOURCE_GTPU, MFIB_SOURCE_VXLAN_GPE, - MFIB_SOURCE_RR, MFIB_SOURCE_GENEVE, MFIB_SOURCE_IGMP, MFIB_SOURCE_VXLAN_GBP, + MFIB_SOURCE_RR, MFIB_SOURCE_DEFAULT_ROUTE, } mfib_source_t; @@ -186,14 +186,20 @@ typedef enum mfib_source_t_ [MFIB_SOURCE_SRv6] = "SRv6", \ [MFIB_SOURCE_GTPU] = "GTPU", \ [MFIB_SOURCE_VXLAN_GPE] = "VXLAN-GPE", \ - [MFIB_SOURCE_RR] = "Recursive-resolution", \ [MFIB_SOURCE_GENEVE] = "Geneve", \ [MFIB_SOURCE_IGMP] = "IGMP", \ [MFIB_SOURCE_VXLAN_GBP] = "VXLAN-GBP", \ + [MFIB_SOURCE_RR] = "Recursive-resolution", \ [MFIB_SOURCE_DEFAULT_ROUTE] = "Default Route", \ } -#define MFIB_N_SOURCES (MFIB_SOURCE_DEFAULT_ROUTE) +#define FOREACH_MFIB_SOURCE(_ms) \ + for (_ms = MFIB_SOURCE_SPECIAL; \ + _ms <= MFIB_SOURCE_DEFAULT_ROUTE; \ + _ms++) + +#define MFIB_N_SOURCES (MFIB_SOURCE_DEFAULT_ROUTE + 1) +#define MFIB_SOURCE_NONE (MFIB_SOURCE_DEFAULT_ROUTE + 1) /** * \brief Compare two prefixes for equality @@ -209,5 +215,20 @@ extern uword unformat_mfib_itf_flags(unformat_input_t * input, va_list * args); extern uword unformat_mfib_entry_flags(unformat_input_t * input, va_list * args); +/** + * \brief Compare two prefixes for covering relationship + * + * \return non-zero if the first prefix is a cover for the second + */ +extern int mfib_prefix_is_cover(const mfib_prefix_t *p1, + const mfib_prefix_t *p2); + +/** + * \brief Return true is the prefix is a host prefix + */ +extern int mfib_prefix_is_host(const mfib_prefix_t *p); + +extern fib_forward_chain_type_t mfib_forw_chain_type_from_dpo_proto(dpo_proto_t proto); +extern fib_forward_chain_type_t mfib_forw_chain_type_from_fib_proto(fib_protocol_t proto); #endif -- 2.16.6