X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fadj%2Fadj_midchain.c;h=88648fea0a9f45348b45ad86188750a23ba1d092;hb=3ebebc3a2fe47f1222ba035e04ccd8caed0cf58f;hp=b32a0e4f2f72f06a009e96ac3c44acc86a8910d3;hpb=8b30e471df4d42214619e1d6c50cc8298426b45f;p=vpp.git diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c index b32a0e4f2f7..88648fea0a9 100644 --- a/src/vnet/adj/adj_midchain.c +++ b/src/vnet/adj/adj_midchain.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include /** * The two midchain tx feature node indices @@ -28,6 +30,8 @@ static u32 adj_midchain_tx_feature_node[VNET_LINK_NUM]; static u32 adj_midchain_tx_no_count_feature_node[VNET_LINK_NUM]; +static u32 *adj_midchain_feat_count_per_sw_if_index[VNET_LINK_NUM]; + /** * @brief Trace data for packets traversing the midchain tx node */ @@ -67,22 +71,13 @@ adj_midchain_tx_inline (vlib_main_t * vm, while (n_left_from >= 8 && n_left_to_next > 4) { + const ip_adjacency_t *adj0, *adj1, *adj2, *adj3; + const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3; + vlib_buffer_t * b0, *b1, *b2, *b3; u32 bi0, adj_index0, next0; - const ip_adjacency_t * adj0; - const dpo_id_t *dpo0; - vlib_buffer_t * b0; u32 bi1, adj_index1, next1; - const ip_adjacency_t * adj1; - const dpo_id_t *dpo1; - vlib_buffer_t * b1; u32 bi2, adj_index2, next2; - const ip_adjacency_t * adj2; - const dpo_id_t *dpo2; - vlib_buffer_t * b2; u32 bi3, adj_index3, next3; - const ip_adjacency_t * adj3; - const dpo_id_t *dpo3; - vlib_buffer_t * b3; /* Prefetch next iteration. */ { @@ -452,6 +447,30 @@ adj_nbr_midchain_get_feature_node (ip_adjacency_t *adj) return (adj_midchain_tx_feature_node[adj->ia_link]); } +/** + * adj_midchain_setup + * + * Setup the adj as a mid-chain + */ +void +adj_midchain_teardown (ip_adjacency_t *adj) +{ + u32 feature_index; + u8 arc_index; + + dpo_reset(&adj->sub_type.midchain.next_dpo); + + arc_index = adj_midchain_get_feature_arc_index_for_link_type (adj); + feature_index = adj_nbr_midchain_get_feature_node(adj); + + if (0 == --adj_midchain_feat_count_per_sw_if_index[adj->ia_link][adj->rewrite_header.sw_if_index]) + { + vnet_feature_enable_disable_with_index (arc_index, feature_index, + adj->rewrite_header.sw_if_index, + 0, 0, 0); + } +} + /** * adj_midchain_setup * @@ -473,15 +492,22 @@ adj_midchain_setup (adj_index_t adj_index, adj->sub_type.midchain.fixup_func = fixup; adj->sub_type.midchain.fixup_data = data; + adj->sub_type.midchain.fei = FIB_NODE_INDEX_INVALID; adj->ia_flags |= flags; arc_index = adj_midchain_get_feature_arc_index_for_link_type (adj); feature_index = adj_nbr_midchain_get_feature_node(adj); tx_node = adj_nbr_midchain_get_tx_node(adj); - vnet_feature_enable_disable_with_index (arc_index, feature_index, - adj->rewrite_header.sw_if_index, - 1 /* enable */, 0, 0); + vec_validate (adj_midchain_feat_count_per_sw_if_index[adj->ia_link], + adj->rewrite_header.sw_if_index); + + if (0 == adj_midchain_feat_count_per_sw_if_index[adj->ia_link][adj->rewrite_header.sw_if_index]++) + { + vnet_feature_enable_disable_with_index (arc_index, feature_index, + adj->rewrite_header.sw_if_index, + 1 /* enable */, 0, 0); + } /* * stack the midchain on the drop so it's ready to forward in the adj-midchain-tx. @@ -499,7 +525,7 @@ adj_midchain_setup (adj_index_t adj_index, * adj_nbr_midchain_update_rewrite * * Update the adjacency's rewrite string. A NULL string implies the - * rewrite is reset (i.e. when ARP/ND etnry is gone). + * rewrite is reset (i.e. when ARP/ND entry is gone). * NB: the adj being updated may be handling traffic in the DP. */ void @@ -516,19 +542,17 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index, adj = adj_get(adj_index); /* - * one time only update. since we don't support chainging the tunnel + * one time only update. since we don't support changing the tunnel * src,dst, this is all we need. */ - ASSERT(adj->lookup_next_index == IP_LOOKUP_NEXT_ARP); - /* - * tunnels can always provide a rewrite. - */ - ASSERT(NULL != rewrite); - - adj_midchain_setup(adj_index, fixup, fixup_data, flags); + if (adj->lookup_next_index != IP_LOOKUP_NEXT_MIDCHAIN && + adj->lookup_next_index != IP_LOOKUP_NEXT_MCAST_MIDCHAIN) + { + adj_midchain_setup(adj_index, fixup, fixup_data, flags); + } /* - * update the rewirte with the workers paused. + * update the rewrite with the workers paused. */ adj_nbr_update_rewrite_internal(adj, IP_LOOKUP_NEXT_MIDCHAIN, @@ -545,11 +569,24 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index, void adj_nbr_midchain_unstack (adj_index_t adj_index) { + fib_node_index_t *entry_indicies, tmp; ip_adjacency_t *adj; ASSERT(ADJ_INDEX_INVALID != adj_index); + adj = adj_get (adj_index); - adj = adj_get(adj_index); + /* + * check to see if this unstacking breaks a recursion loop + */ + entry_indicies = NULL; + tmp = adj->sub_type.midchain.fei; + adj->sub_type.midchain.fei = FIB_NODE_INDEX_INVALID; + + if (FIB_NODE_INDEX_INVALID != tmp) + { + fib_entry_recursive_loop_detect(tmp, &entry_indicies); + vec_free(entry_indicies); + } /* * stack on the drop @@ -561,6 +598,74 @@ adj_nbr_midchain_unstack (adj_index_t adj_index) CLIB_MEMORY_BARRIER(); } +void +adj_nbr_midchain_stack_on_fib_entry (adj_index_t ai, + fib_node_index_t fei, + fib_forward_chain_type_t fct) +{ + fib_node_index_t *entry_indicies; + dpo_id_t tmp = DPO_INVALID; + ip_adjacency_t *adj; + + adj = adj_get (ai); + + /* + * check to see if this stacking will form a recursion loop + */ + entry_indicies = NULL; + adj->sub_type.midchain.fei = fei; + + if (fib_entry_recursive_loop_detect(adj->sub_type.midchain.fei, &entry_indicies)) + { + /* + * loop formed, stack on the drop. + */ + dpo_copy(&tmp, drop_dpo_get(fib_forw_chain_type_to_dpo_proto(fct))); + } + else + { + fib_entry_contribute_forwarding (fei, fct, &tmp); + + if ((adj->ia_flags & ADJ_FLAG_MIDCHAIN_IP_STACK) && + (DPO_LOAD_BALANCE == tmp.dpoi_type)) + { + /* + * do that hash now and stack on the choice. + * If the choice is an incomplete adj then we will need a poke when + * it becomes complete. This happens since the adj update walk propagates + * as far a recursive paths. + */ + const dpo_id_t *choice; + load_balance_t *lb; + int hash; + + lb = load_balance_get (tmp.dpoi_index); + + if (FIB_FORW_CHAIN_TYPE_UNICAST_IP4 == fct) + { + hash = ip4_compute_flow_hash ((ip4_header_t *) adj_get_rewrite (ai), + lb->lb_hash_config); + } + else if (FIB_FORW_CHAIN_TYPE_UNICAST_IP6 == fct) + { + hash = ip6_compute_flow_hash ((ip6_header_t *) adj_get_rewrite (ai), + lb->lb_hash_config); + } + else + { + hash = 0; + ASSERT(0); + } + + choice = load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1); + dpo_copy (&tmp, choice); + } + } + adj_nbr_midchain_stack (ai, &tmp); + dpo_reset(&tmp); + vec_free(entry_indicies); +} + /** * adj_nbr_midchain_stack */ @@ -582,6 +687,33 @@ adj_nbr_midchain_stack (adj_index_t adj_index, next); } +int +adj_ndr_midchain_recursive_loop_detect (adj_index_t ai, + fib_node_index_t **entry_indicies) +{ + fib_node_index_t *entry_index, *entries; + ip_adjacency_t * adj; + + adj = adj_get(ai); + entries = *entry_indicies; + + vec_foreach(entry_index, entries) + { + if (*entry_index == adj->sub_type.midchain.fei) + { + /* + * The entry this midchain links to is already in the set + * of visited entries, this is a loop + */ + adj->ia_flags |= ADJ_FLAG_MIDCHAIN_LOOPED; + return (1); + } + } + + adj->ia_flags &= ~ADJ_FLAG_MIDCHAIN_LOOPED; + return (0); +} + u8* format_adj_midchain (u8* s, va_list *ap) { @@ -590,14 +722,23 @@ format_adj_midchain (u8* s, va_list *ap) ip_adjacency_t * adj = adj_get(index); s = format (s, "%U", format_vnet_link, adj->ia_link); + if (adj->rewrite_header.flags & VNET_REWRITE_HAS_FEATURES) + s = format(s, " [features]"); s = format (s, " via %U", format_ip46_address, &adj->sub_type.nbr.next_hop, adj_proto_to_46(adj->ia_nh_proto)); s = format (s, " %U", format_vnet_rewrite, &adj->rewrite_header, sizeof (adj->rewrite_data), indent); - s = format (s, "\n%Ustacked-on:\n%U%U", - format_white_space, indent, + s = format (s, "\n%Ustacked-on", + format_white_space, indent); + + if (FIB_NODE_INDEX_INVALID != adj->sub_type.midchain.fei) + { + s = format (s, " entry:%d", adj->sub_type.midchain.fei); + + } + s = format (s, ":\n%U%U", format_white_space, indent+2, format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);