+ /*
+ * Entries with paths via unicast next-hops
+ */
+ fib_route_path_t path_via_nbr1 = {
+ .frp_proto = fib_proto_to_dpo(PROTO),
+ .frp_addr = *addr_nbr1,
+ .frp_sw_if_index = tm->hw[0]->sw_if_index,
+ .frp_fib_index = ~0,
+ .frp_weight = 0,
+ .frp_flags = 0,
+ };
+ fib_route_path_t path_via_nbr2 = {
+ .frp_proto = fib_proto_to_dpo(PROTO),
+ .frp_addr = *addr_nbr2,
+ .frp_sw_if_index = tm->hw[0]->sw_if_index,
+ .frp_fib_index = ~0,
+ .frp_weight = 0,
+ .frp_flags = 0,
+ };
+
+ mfei_g_1 = mfib_table_entry_path_update(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr1,
+ (MFIB_ITF_FLAG_FORWARD));
+ mfei_g_1 = mfib_table_entry_path_update(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr2,
+ (MFIB_ITF_FLAG_FORWARD));
+ MFIB_TEST(!mfib_test_entry(mfei_g_1,
+ MFIB_ENTRY_FLAG_NONE,
+ 2,
+ DPO_ADJACENCY_INCOMPLETE, ai_nbr1,
+ DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
+ "%U replicate OK",
+ format_mfib_prefix, pfx_star_g_1);
+ MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
+ MFIB_ITF_FLAG_FORWARD));
+
+ mfib_table_entry_path_remove(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr1);
+
+ MFIB_TEST(!mfib_test_entry(mfei_g_1,
+ MFIB_ENTRY_FLAG_NONE,
+ 1,
+ DPO_ADJACENCY_INCOMPLETE, ai_nbr2),
+ "%U replicate OK",
+ format_mfib_prefix, pfx_star_g_1);
+ MFIB_TEST_NS(!mfib_test_entry_itf(mfei_g_1, tm->hw[0]->sw_if_index,
+ MFIB_ITF_FLAG_FORWARD));
+
+ mfib_table_entry_path_remove(fib_index,
+ pfx_star_g_1,
+ MFIB_SOURCE_API,
+ &path_via_nbr2);
+ mfei = mfib_table_lookup_exact_match(fib_index, pfx_star_g_1);
+ MFIB_TEST(FIB_NODE_INDEX_INVALID == mfei,
+ "%U Gone",
+ format_mfib_prefix, pfx_star_g_1);
+
+ /*
+ * Add a prefix as a special/exclusive route
+ */
+ dpo_id_t td = DPO_INVALID;
+ index_t repi = replicate_create(1, fib_proto_to_dpo(PROTO));
+
+ dpo_set(&td, DPO_ADJACENCY_MCAST, fib_proto_to_dpo(PROTO), ai_2);
+ replicate_set_bucket(repi, 0, &td);
+
+ mfei = mfib_table_entry_special_add(fib_index,
+ pfx_star_g_3,
+ MFIB_SOURCE_SRv6,
+ MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF,
+ repi);
+ MFIB_TEST(!mfib_test_entry(mfei,
+ (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
+ MFIB_ENTRY_FLAG_EXCLUSIVE),
+ 1,
+ DPO_ADJACENCY_MCAST, ai_2),
+ "%U exclusive replicate OK",
+ format_mfib_prefix, pfx_star_g_3);
+
+ /*
+ * update a special/exclusive route
+ */
+ index_t repi2 = replicate_create(1, fib_proto_to_dpo(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_TEST(!mfib_test_entry(mfei,
+ (MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF |
+ MFIB_ENTRY_FLAG_EXCLUSIVE),
+ 1,
+ DPO_ADJACENCY_MCAST, ai_1),
+ "%U exclusive update replicate OK",
+ format_mfib_prefix, pfx_star_g_3);
+
+ mfib_table_entry_delete(fib_index,
+ pfx_star_g_3,
+ MFIB_SOURCE_SRv6);
+ dpo_reset(&td);
+
+ /*
+ * A Multicast LSP. This a mLDP head-end
+ */
+ fib_node_index_t ai_mpls_10_10_10_1, lfei;
+ ip46_address_t nh_10_10_10_1 = {
+ .ip4 = {
+ .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
+ },
+ };
+ ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+ VNET_LINK_MPLS,
+ &nh_10_10_10_1,
+ tm->hw[0]->sw_if_index);
+
+ fib_prefix_t pfx_3500 = {
+ .fp_len = 21,
+ .fp_proto = FIB_PROTOCOL_MPLS,
+ .fp_label = 3500,
+ .fp_eos = MPLS_EOS,
+ .fp_payload_proto = DPO_PROTO_IP4,
+ };
+ fib_test_rep_bucket_t mc_0 = {
+ .type = FT_REP_LABEL_O_ADJ,
+ .label_o_adj = {
+ .adj = ai_mpls_10_10_10_1,
+ .label = 3300,
+ .eos = MPLS_EOS,
+ },
+ };
+ fib_mpls_label_t *l3300 = NULL, fml3300 = {
+ .fml_value = 3300,
+ };
+ vec_add1(l3300, fml3300);
+
+ /*
+ * MPLS enable an interface so we get the MPLS table created
+ */
+ mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
+ mpls_sw_interface_enable_disable(&mpls_main,
+ tm->hw[0]->sw_if_index,
+ 1, 0);
+
+ lfei = fib_table_entry_update_one_path(0, // default MPLS Table
+ &pfx_3500,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_MULTICAST,
+ DPO_PROTO_IP4,
+ &nh_10_10_10_1,
+ tm->hw[0]->sw_if_index,
+ ~0, // invalid fib index
+ 1,
+ l3300,
+ FIB_ROUTE_PATH_FLAG_NONE);
+ MFIB_TEST(!fib_test_validate_entry(lfei,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ 1,
+ &mc_0),
+ "3500 via replicate over 10.10.10.1");
+
+ /*
+ * An (S,G) that resolves via the mLDP head-end
+ */
+ fib_route_path_t path_via_mldp = {
+ .frp_proto = DPO_PROTO_MPLS,
+ .frp_local_label = pfx_3500.fp_label,
+ .frp_eos = MPLS_EOS,
+ .frp_sw_if_index = 0xffffffff,
+ .frp_fib_index = 0,
+ .frp_weight = 1,
+ .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+ };
+ dpo_id_t mldp_dpo = DPO_INVALID;
+
+ fib_entry_contribute_forwarding(lfei,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ &mldp_dpo);
+
+ mfei = mfib_table_entry_path_update(fib_index,
+ pfx_s_g,
+ MFIB_SOURCE_API,
+ &path_via_mldp,
+ MFIB_ITF_FLAG_FORWARD);
+
+ MFIB_TEST(!mfib_test_entry(mfei,
+ MFIB_ENTRY_FLAG_NONE,
+ 1,
+ DPO_REPLICATE, mldp_dpo.dpoi_index),
+ "%U over-mLDP replicate OK",
+ format_mfib_prefix, pfx_s_g);
+
+ /*
+ * add a for-us path. this tests two types of non-attached paths on one entry
+ */
+ mfei = mfib_table_entry_path_update(fib_index,
+ pfx_s_g,
+ MFIB_SOURCE_API,
+ &path_for_us,
+ MFIB_ITF_FLAG_FORWARD);
+ MFIB_TEST(!mfib_test_entry(mfei,
+ MFIB_ENTRY_FLAG_NONE,
+ 2,
+ DPO_REPLICATE, mldp_dpo.dpoi_index,
+ DPO_RECEIVE, 0),
+ "%U mLDP+for-us replicate OK",
+ format_mfib_prefix, pfx_s_g);
+
+ mfib_table_entry_delete(fib_index,
+ pfx_s_g,
+ MFIB_SOURCE_API);
+ fib_table_entry_delete(0,
+ &pfx_3500,
+ FIB_SOURCE_API);
+ dpo_reset(&mldp_dpo);
+