From e821ab100aea2fb3f740a98650eb750ff5911c49 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 1 Jun 2017 07:45:05 -0700 Subject: [PATCH] IP mcast: allow unicast address as a next-hop Change-Id: I5e679f2601e37688f2768620479dc2efb7d19ca3 Signed-off-by: Neale Ranns --- src/vnet/fib/fib_path.c | 4 +- src/vnet/ip/ip.api | 1 + src/vnet/ip/ip_api.c | 9 ++- src/vnet/ip/lookup.c | 16 +++++ 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 +++++++++++++++++++++++++++++++++++++++++++-- test/test_ip_mcast.py | 53 ++++++++++++++++- test/vpp_ip_route.py | 15 +++-- test/vpp_papi_provider.py | 4 +- 11 files changed, 370 insertions(+), 49 deletions(-) diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index 8cfe86a7a90..e974e31e959 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -2323,6 +2323,8 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS: case FIB_FORW_CHAIN_TYPE_ETHERNET: case FIB_FORW_CHAIN_TYPE_NSH: + case FIB_FORW_CHAIN_TYPE_MCAST_IP4: + case FIB_FORW_CHAIN_TYPE_MCAST_IP6: { adj_index_t ai; @@ -2338,8 +2340,6 @@ fib_path_contribute_forwarding (fib_node_index_t path_index, break; } - case FIB_FORW_CHAIN_TYPE_MCAST_IP4: - case FIB_FORW_CHAIN_TYPE_MCAST_IP6: case FIB_FORW_CHAIN_TYPE_BIER: break; } diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index 38024926ab7..bf16c180d4d 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -446,6 +446,7 @@ autoreply define ip_mroute_add_del u8 is_local; u8 grp_address[16]; u8 src_address[16]; + u8 nh_address[16]; }; /** \brief Dump IP multicast fib table diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 69ff719f3b9..b4d942b6bef 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -1208,13 +1208,15 @@ mroute_add_del_handler (u8 is_add, dpo_proto_t nh_proto, u32 entry_flags, fib_rpf_id_t rpf_id, - u32 next_hop_sw_if_index, u32 itf_flags, u32 bier_imp) + u32 next_hop_sw_if_index, + ip46_address_t * nh, u32 itf_flags, u32 bier_imp) { stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ ); fib_route_path_t path = { .frp_sw_if_index = next_hop_sw_if_index, .frp_proto = nh_proto, + .frp_addr = *nh, }; if (is_local) @@ -1253,6 +1255,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp) { fib_protocol_t fproto; dpo_proto_t nh_proto; + ip46_address_t nh; u32 fib_index; int rv; @@ -1277,6 +1280,8 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp) sizeof (pfx.fp_grp_addr.ip4)); clib_memcpy (&pfx.fp_src_addr.ip4, mp->src_address, sizeof (pfx.fp_src_addr.ip4)); + memset (&nh.ip6, 0, sizeof (nh.ip6)); + clib_memcpy (&nh.ip4, mp->nh_address, sizeof (nh.ip4)); } else { @@ -1284,6 +1289,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp) sizeof (pfx.fp_grp_addr.ip6)); clib_memcpy (&pfx.fp_src_addr.ip6, mp->src_address, sizeof (pfx.fp_src_addr.ip6)); + clib_memcpy (&nh.ip6, mp->nh_address, sizeof (nh.ip6)); } return (mroute_add_del_handler (mp->is_add, @@ -1293,6 +1299,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp) ntohl (mp->entry_flags), ntohl (mp->rpf_id), ntohl (mp->next_hop_sw_if_index), + &nh, ntohl (mp->itf_flags), ntohl (mp->bier_imp))); } diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c index 216af4ce371..a26dc12889e 100644 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -899,14 +899,30 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, pfx.fp_proto = FIB_PROTOCOL_IP6; pfx.fp_len = 128; } + else if (unformat (line_input, "via %U %U", + unformat_ip4_address, &rpath.frp_addr.ip4, + unformat_vnet_sw_interface, vnm, + &rpath.frp_sw_if_index)) + { + rpath.frp_weight = 1; + } + else if (unformat (line_input, "via %U %U", + unformat_ip6_address, &rpath.frp_addr.ip6, + unformat_vnet_sw_interface, vnm, + &rpath.frp_sw_if_index)) + { + rpath.frp_weight = 1; + } else if (unformat (line_input, "via %U", unformat_vnet_sw_interface, vnm, &rpath.frp_sw_if_index)) { + memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr)); rpath.frp_weight = 1; } else if (unformat (line_input, "via local")) { + memset (&rpath.frp_addr, 0, sizeof (rpath.frp_addr)); rpath.frp_sw_if_index = ~0; rpath.frp_weight = 1; rpath.frp_flags |= FIB_ROUTE_PATH_LOCAL; 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) diff --git a/test/test_ip_mcast.py b/test/test_ip_mcast.py index b4554c67f42..017f0629cd2 100644 --- a/test/test_ip_mcast.py +++ b/test/test_ip_mcast.py @@ -111,7 +111,7 @@ class TestIPMcast(VppTestCase): capture.remove(p) return capture - def verify_capture_ip4(self, rx_if, sent): + def verify_capture_ip4(self, rx_if, sent, dst_mac=None): rxd = rx_if.get_capture(len(sent)) try: @@ -129,8 +129,11 @@ class TestIPMcast(VppTestCase): tx_ip = tx[IP] rx_ip = rx[IP] + if dst_mac is None: + dst_mac = getmacbyip(rx_ip.dst) + # check the MAC address on the RX'd packet is correctly formed - self.assertEqual(eth.dst, getmacbyip(rx_ip.dst)) + self.assertEqual(eth.dst, dst_mac) self.assertEqual(rx_ip.src, tx_ip.src) self.assertEqual(rx_ip.dst, tx_ip.dst) @@ -225,6 +228,26 @@ class TestIPMcast(VppTestCase): MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)]) route_1_1_1_1_232_1_1_1.add_vpp_config() + # + # An (S,G). + # one accepting interface, pg0, 2 forwarding interfaces + # that use unicast next-hops + # + route_1_1_1_1_232_1_1_2 = VppIpMRoute( + self, + "1.1.1.1", + "232.1.1.2", 64, + MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, + [VppMRoutePath(self.pg0.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), + VppMRoutePath(self.pg1.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD, + nh=self.pg1.remote_ip4), + VppMRoutePath(self.pg2.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD, + nh=self.pg2.remote_ip4)]) + route_1_1_1_1_232_1_1_2.add_vpp_config() + # # An (*,G/m). # one accepting interface, pg0, 1 forwarding interfaces @@ -283,6 +306,26 @@ class TestIPMcast(VppTestCase): self.pg3.assert_nothing_captured( remark="IP multicast packets forwarded on PG3") + # + # a stream to the unicast next-hops + # + self.vapi.cli("clear trace") + tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.2") + self.pg0.add_stream(tx) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # We expect replications on Pg1->7 + self.verify_capture_ip4(self.pg1, tx, dst_mac=self.pg1.remote_mac) + self.verify_capture_ip4(self.pg2, tx, dst_mac=self.pg2.remote_mac) + + # no replications on Pg0 nor pg3 + self.pg0.assert_nothing_captured( + remark="IP multicast packets forwarded on PG0") + self.pg3.assert_nothing_captured( + remark="IP multicast packets forwarded on PG3") + # # a stream that matches the route for (*,232.0.0.0/8) # Send packets with the 9th bit set so we test the correct clearing @@ -316,7 +359,7 @@ class TestIPMcast(VppTestCase): self.pg_enable_capture(self.pg_interfaces) self.pg_start() - # We expect replications on Pg1, 2, 3. + # We expect replications on Pg1->7 self.verify_capture_ip4(self.pg1, tx) self.verify_capture_ip4(self.pg2, tx) self.verify_capture_ip4(self.pg3, tx) @@ -325,6 +368,10 @@ class TestIPMcast(VppTestCase): self.verify_capture_ip4(self.pg6, tx) self.verify_capture_ip4(self.pg7, tx) + # no replications on Pg0 + self.pg0.assert_nothing_captured( + remark="IP multicast packets forwarded on PG0") + def test_ip6_mcast(self): """ IPv6 Multicast Replication """ diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index 39b2b1ae1e8..17a42fec706 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -185,12 +185,14 @@ class VppRoutePath(object): class VppMRoutePath(VppRoutePath): def __init__(self, nh_sw_if_index, flags, + nh=None, proto=DpoProto.DPO_PROTO_IP4, bier_imp=0): - super(VppMRoutePath, self).__init__( - "::" if proto is DpoProto.DPO_PROTO_IP6 else "0.0.0.0", - nh_sw_if_index, - proto=proto) + if not nh: + nh = "::" if proto is DpoProto.DPO_PROTO_IP6 else "0.0.0.0" + super(VppMRoutePath, self).__init__(nh, + nh_sw_if_index, + proto=proto) self.nh_i_flags = flags self.bier_imp = bier_imp @@ -337,6 +339,7 @@ class VppIpMRoute(VppObject): self.e_flags, path.proto, path.nh_itf, + path.nh_addr, path.nh_i_flags, bier_imp=path.bier_imp, rpf_id=self.rpf_id, @@ -352,6 +355,7 @@ class VppIpMRoute(VppObject): self.e_flags, path.proto, path.nh_itf, + path.nh_addr, path.nh_i_flags, table_id=self.table_id, bier_imp=path.bier_imp, @@ -366,6 +370,7 @@ class VppIpMRoute(VppObject): self.e_flags, 0, 0xffffffff, + "", 0, table_id=self.table_id, is_ipv6=self.is_ip6) @@ -378,6 +383,7 @@ class VppIpMRoute(VppObject): self.e_flags, 0, 0xffffffff, + "", 0, rpf_id=self.rpf_id, table_id=self.table_id, @@ -394,6 +400,7 @@ class VppIpMRoute(VppObject): self.e_flags, path.proto, path.nh_itf, + path.nh_addr, path.nh_i_flags, table_id=self.table_id, is_ipv6=self.is_ip6) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 6804b4cfe4a..44cb7b6fc68 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -2300,6 +2300,7 @@ class VppPapiProvider(object): e_flags, next_hop_afi, next_hop_sw_if_index, + next_hop_address, i_flags, bier_imp=0, rpf_id=0, @@ -2324,7 +2325,8 @@ class VppPapiProvider(object): 'next_hop_afi': next_hop_afi, 'grp_address_length': grp_address_length, 'grp_address': grp_address, - 'src_address': src_address}) + 'src_address': src_address, + 'nh_address': next_hop_address}) def mfib_signal_dump(self): return self.api(self.papi.mfib_signal_dump, {}) -- 2.16.6