diff options
Diffstat (limited to 'src/vnet/adj')
-rw-r--r-- | src/vnet/adj/adj.c | 9 | ||||
-rw-r--r-- | src/vnet/adj/adj.h | 84 | ||||
-rw-r--r-- | src/vnet/adj/adj_delegate.c | 14 | ||||
-rw-r--r-- | src/vnet/adj/adj_delegate.h | 7 | ||||
-rw-r--r-- | src/vnet/adj/adj_dp.h | 66 | ||||
-rw-r--r-- | src/vnet/adj/adj_internal.h | 3 | ||||
-rw-r--r-- | src/vnet/adj/adj_l2.c | 44 | ||||
-rw-r--r-- | src/vnet/adj/adj_midchain.c | 546 | ||||
-rw-r--r-- | src/vnet/adj/adj_midchain.h | 23 | ||||
-rw-r--r-- | src/vnet/adj/adj_nbr.c | 11 | ||||
-rw-r--r-- | src/vnet/adj/rewrite.c | 2 | ||||
-rw-r--r-- | src/vnet/adj/rewrite.h | 19 |
12 files changed, 483 insertions, 345 deletions
diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c index c601e6bd19d..2fb77fe78d3 100644 --- a/src/vnet/adj/adj.c +++ b/src/vnet/adj/adj.c @@ -79,6 +79,7 @@ adj_alloc (fib_protocol_t proto) adj->ia_nh_proto = proto; adj->ia_flags = 0; + adj->ia_cfg_index = 0; adj->rewrite_header.sw_if_index = ~0; adj->rewrite_header.flags = 0; adj->lookup_next_index = 0; @@ -399,10 +400,18 @@ adj_feature_update_walk_cb (adj_index_t ai, ((ctx->arc == mpls_main.output_feature_arc_index) && (VNET_LINK_MPLS == adj->ia_link))) { + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm; + + cm = &fm->feature_config_mains[ctx->arc]; + if (ctx->enable) adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES; else adj->rewrite_header.flags &= ~VNET_REWRITE_HAS_FEATURES; + + adj->ia_cfg_index = vec_elt (cm->config_index_by_sw_if_index, + adj->rewrite_header.sw_if_index); } return (ADJ_WALK_RC_CONTINUE); } diff --git a/src/vnet/adj/adj.h b/src/vnet/adj/adj.h index e22e7ecd58a..a53122711a8 100644 --- a/src/vnet/adj/adj.h +++ b/src/vnet/adj/adj.h @@ -181,6 +181,10 @@ typedef enum adj_attr_t_ * If the midchain were to stack on its FIB entry a loop would form. */ ADJ_ATTR_MIDCHAIN_LOOPED, + /** + * the fixup function is standard IP4o4 header + */ + ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR, } adj_attr_t; #define ADJ_ATTR_NAMES { \ @@ -188,11 +192,12 @@ typedef enum adj_attr_t_ [ADJ_ATTR_MIDCHAIN_NO_COUNT] = "midchain-no-count", \ [ADJ_ATTR_MIDCHAIN_IP_STACK] = "midchain-ip-stack", \ [ADJ_ATTR_MIDCHAIN_LOOPED] = "midchain-looped", \ + [ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR] = "midchain-ip4o4-hdr-fixup", \ } -#define FOR_EACH_ADJ_ATTR(_attr) \ - for (_attr = ADJ_ATTR_SYNC_WALK_ACTIVE; \ - _attr <= ADJ_ATTR_MIDCHAIN_LOOPED; \ +#define FOR_EACH_ADJ_ATTR(_attr) \ + for (_attr = ADJ_ATTR_SYNC_WALK_ACTIVE; \ + _attr <= ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR; \ _attr++) /** @@ -205,6 +210,7 @@ typedef enum adj_flags_t_ ADJ_FLAG_MIDCHAIN_NO_COUNT = (1 << ADJ_ATTR_MIDCHAIN_NO_COUNT), ADJ_FLAG_MIDCHAIN_IP_STACK = (1 << ADJ_ATTR_MIDCHAIN_IP_STACK), ADJ_FLAG_MIDCHAIN_LOOPED = (1 << ADJ_ATTR_MIDCHAIN_LOOPED), + ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR = (1 << ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR), } __attribute__ ((packed)) adj_flags_t; /** @@ -227,32 +233,10 @@ typedef struct ip_adjacency_t_ * has 8 byte alignment requirements. */ fib_node_t ia_node; - - /** - * Next hop after ip4-lookup. - * This is not accessed in the rewrite nodes. - * 1-bytes - */ - ip_lookup_next_t lookup_next_index; - - /** - * link/ether-type - * 1 bytes - */ - vnet_link_t ia_link; - /** - * The protocol of the neighbor/peer. i.e. the protocol with - * which to interpret the 'next-hop' attributes of the sub-types. - * 1-bytes + * feature [arc] config index */ - fib_protocol_t ia_nh_proto; - - /** - * Flags on the adjacency - * 1-bytes - */ - adj_flags_t ia_flags; + u32 ia_cfg_index; union { @@ -298,6 +282,10 @@ typedef struct ip_adjacency_t_ * loop detection. */ fib_node_index_t fei; + + /** spare space */ + u8 __ia_midchain_pad[4]; + } midchain; /** * IP_LOOKUP_NEXT_GLEAN @@ -315,12 +303,14 @@ typedef struct ip_adjacency_t_ CLIB_CACHE_LINE_ALIGN_MARK (cacheline1); - /* Rewrite in second/third cache lines */ + /** Rewrite in second and third cache lines */ VNET_DECLARE_REWRITE; /** * more control plane members that do not fit on the first cacheline */ + CLIB_CACHE_LINE_ALIGN_MARK (cacheline3); + /** * A sorted vector of delegates */ @@ -330,6 +320,37 @@ typedef struct ip_adjacency_t_ * The VLIB node in which this adj is used to forward packets */ u32 ia_node_index; + + /** + * Next hop after ip4-lookup. + * This is not accessed in the rewrite nodes. + * 1-bytes + */ + ip_lookup_next_t lookup_next_index; + + /** + * link/ether-type + * 1 bytes + */ + vnet_link_t ia_link; + + /** + * The protocol of the neighbor/peer. i.e. the protocol with + * which to interpret the 'next-hop' attributes of the sub-types. + * 1-bytes + */ + fib_protocol_t ia_nh_proto; + + /** + * Flags on the adjacency + * 1-bytes + */ + adj_flags_t ia_flags; + + /** + * Free space on the fourth cacheline (not used in the DP) + */ + u8 __ia_pad[48]; } ip_adjacency_t; STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline0) == 0), @@ -337,6 +358,13 @@ STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline0) == 0), STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline1) == CLIB_CACHE_LINE_BYTES), "IP adjacency cacheline 1 is more than one cacheline size offset"); +#if defined __x86_64__ +STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline3) == + 3 * CLIB_CACHE_LINE_BYTES), + "IP adjacency cacheline 3 is more than one cacheline size offset"); +/* An adj fits into 4 cachelines on your average machine */ +STATIC_ASSERT_SIZEOF (ip_adjacency_t, 4 * 64); +#endif /** * @brief diff --git a/src/vnet/adj/adj_delegate.c b/src/vnet/adj/adj_delegate.c index 87a83fb4239..8f590461b20 100644 --- a/src/vnet/adj/adj_delegate.c +++ b/src/vnet/adj/adj_delegate.c @@ -125,6 +125,20 @@ adj_delegate_add (ip_adjacency_t *adj, } void +adj_delegate_adj_modified (ip_adjacency_t *adj) +{ + adj_delegate_t *aed; + + vec_foreach(aed, adj->ia_delegates) + { + if (ad_vfts[aed->ad_type].adv_adj_modified) + { + ad_vfts[aed->ad_type].adv_adj_modified(aed); + } + } +} + +void adj_delegate_adj_deleted (ip_adjacency_t *adj) { adj_delegate_t *aed; diff --git a/src/vnet/adj/adj_delegate.h b/src/vnet/adj/adj_delegate.h index d49c6661c19..c83a00cd271 100644 --- a/src/vnet/adj/adj_delegate.h +++ b/src/vnet/adj/adj_delegate.h @@ -83,11 +83,18 @@ typedef u8 * (*adj_delegate_format_t)(const adj_delegate_t *aed, u8 *s); typedef void (*adj_delegate_adj_created_t)(adj_index_t ai); /** + * Indication that the adjacency has been modified. + * the delegate. + */ +typedef void (*adj_delegate_adj_modified_t)(adj_delegate_t *aed); + +/** * An ADJ delegate virtual function table */ typedef struct adj_delegate_vft_t_ { adj_delegate_format_t adv_format; adj_delegate_adj_deleted_t adv_adj_deleted; + adj_delegate_adj_modified_t adv_adj_modified; adj_delegate_adj_created_t adv_adj_created; } adj_delegate_vft_t; diff --git a/src/vnet/adj/adj_dp.h b/src/vnet/adj/adj_dp.h new file mode 100644 index 00000000000..27c0581fcfb --- /dev/null +++ b/src/vnet/adj/adj_dp.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef __ADJ_DP_H__ +#define __ADJ_DP_H__ + +#include <vnet/adj/adj.h> +#include <vnet/tunnel/tunnel_dp.h> + +static_always_inline void +adj_midchain_ipip44_fixup (vlib_main_t * vm, + const ip_adjacency_t * adj, + vlib_buffer_t * b) +{ + tunnel_encap_decap_flags_t flags; + ip4_header_t *ip4; + + flags = pointer_to_uword (adj->sub_type.midchain.fixup_data); + + ip4 = vlib_buffer_get_current (b); + ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b)); + + if (PREDICT_TRUE(TUNNEL_ENCAP_DECAP_FLAG_NONE == flags)) + { + ip_csum_t sum; + u16 old,new; + + old = 0; + new = ip4->length; + + sum = ip4->checksum; + sum = ip_csum_update (sum, old, new, ip4_header_t, length); + ip4->checksum = ip_csum_fold (sum); + } + else + { + tunnel_encap_fixup_4o4 (flags, ip4 + 1, ip4); + ip4->checksum = ip4_header_checksum (ip4); + } +} + +static_always_inline void +adj_midchain_fixup (vlib_main_t *vm, + const ip_adjacency_t *adj, + vlib_buffer_t * b) +{ + if (PREDICT_TRUE(adj->rewrite_header.flags & VNET_REWRITE_FIXUP_IP4_O_4)) + adj_midchain_ipip44_fixup (vm, adj, b); + else if (adj->sub_type.midchain.fixup_func) + adj->sub_type.midchain.fixup_func + (vm, adj, b, adj->sub_type.midchain.fixup_data); +} + +#endif diff --git a/src/vnet/adj/adj_internal.h b/src/vnet/adj/adj_internal.h index c4dda51324c..11214932a3a 100644 --- a/src/vnet/adj/adj_internal.h +++ b/src/vnet/adj/adj_internal.h @@ -53,7 +53,7 @@ adj_get_rewrite_node (vnet_link_t linkt) case VNET_LINK_MPLS: return (mpls_output_node.index); case VNET_LINK_ETHERNET: - return (adj_l2_rewrite_node.index); + return (adj_l2_rewrite_node.index); case VNET_LINK_NSH: return (adj_nsh_rewrite_node.index); case VNET_LINK_ARP: @@ -138,6 +138,7 @@ extern int adj_bfd_is_up (adj_index_t ai); */ extern void adj_delegate_adj_deleted(ip_adjacency_t *adj); extern void adj_delegate_adj_created(ip_adjacency_t *adj); +extern void adj_delegate_adj_modified(ip_adjacency_t *adj); extern u8* adj_delegate_format(u8* s, ip_adjacency_t *adj); #endif diff --git a/src/vnet/adj/adj_l2.c b/src/vnet/adj/adj_l2.c index a289158c7f3..5413eca6212 100644 --- a/src/vnet/adj/adj_l2.c +++ b/src/vnet/adj/adj_l2.c @@ -48,7 +48,8 @@ always_inline uword adj_l2_rewrite_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, - int is_midchain) + int is_midchain, + int do_counters) { u32 * from = vlib_frame_vector_args (frame); u32 n_left_from, n_left_to_next, * to_next, next_index; @@ -67,7 +68,7 @@ adj_l2_rewrite_inline (vlib_main_t * vm, ip_adjacency_t * adj0; vlib_buffer_t * p0; char *h0; - u32 pi0, rw_len0, adj_index0, next0 = 0; + u32 pi0, rw_len0, len0, adj_index0, next0 = 0; u32 tx_sw_if_index0; pi0 = to_next[0] = from[0]; @@ -83,29 +84,30 @@ adj_l2_rewrite_inline (vlib_main_t * vm, adj0 = adj_get (adj_index0); - /* Guess we are only writing on simple Ethernet header. */ + /* Guess we are writing on ip4 header. */ vnet_rewrite_one_header (adj0[0], h0, - sizeof (ethernet_header_t)); + //sizeof (gre_header_t) + + sizeof (ip4_header_t)); /* Update packet buffer attributes/set output interface. */ rw_len0 = adj0[0].rewrite_header.data_bytes; vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; vnet_buffer(p0)->sw_if_index[VLIB_TX] = adj0->rewrite_header.sw_if_index; + len0 = vlib_buffer_length_in_chain (vm, p0); /* since we are coming out of the L2 world, where the vlib_buffer * union is used for other things, make sure it is clean for * MPLS from now on. */ vnet_buffer(p0)->mpls.first = 0; - vlib_increment_combined_counter(&adjacency_counters, - thread_index, - adj_index0, - /* packet increment */ 0, - /* byte increment */ rw_len0); + if (do_counters) + vlib_increment_combined_counter(&adjacency_counters, + thread_index, + adj_index0, + 0, len0); /* Check MTU of outgoing interface. */ - if (PREDICT_TRUE((vlib_buffer_length_in_chain (vm, p0) <= - adj0[0].rewrite_header.max_l3_packet_bytes))) + if (PREDICT_TRUE(len0 <= adj0[0].rewrite_header.max_l3_packet_bytes)) { /* Don't adjust the buffer for ttl issue; icmp-error node wants * to see the IP header */ @@ -126,7 +128,15 @@ adj_l2_rewrite_inline (vlib_main_t * vm, * Follow the feature ARC. this will result eventually in * the midchain-tx node */ - vnet_feature_arc_start(em->output_feature_arc_index, tx_sw_if_index0, &next0, p0); + if (PREDICT_FALSE (adj0->rewrite_header.flags & + VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start_w_cfg_index ( + em->output_feature_arc_index, + tx_sw_if_index0, + &next0, p0, + adj0->ia_cfg_index); + else + next0 = adj0[0].rewrite_header.next_index; } else { @@ -156,14 +166,20 @@ VLIB_NODE_FN (adj_l2_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return adj_l2_rewrite_inline (vm, node, frame, 0); + if (adj_are_counters_enabled ()) + return adj_l2_rewrite_inline (vm, node, frame, 0, 1); + else + return adj_l2_rewrite_inline (vm, node, frame, 0, 0); } VLIB_NODE_FN (adj_l2_midchain_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return adj_l2_rewrite_inline (vm, node, frame, 1); + if (adj_are_counters_enabled ()) + return adj_l2_rewrite_inline (vm, node, frame, 1, 1); + else + return adj_l2_rewrite_inline (vm, node, frame, 1, 0); } VLIB_REGISTER_NODE (adj_l2_rewrite_node) = { diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c index 88648fea0a9..4741ec9a953 100644 --- a/src/vnet/adj/adj_midchain.c +++ b/src/vnet/adj/adj_midchain.c @@ -25,14 +25,6 @@ #include <vnet/fib/fib_entry.h> /** - * The two midchain tx feature node indices - */ -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 */ typedef struct adj_midchain_tx_trace_t_ @@ -49,203 +41,158 @@ adj_midchain_tx_inline (vlib_main_t * vm, vlib_frame_t * frame, int interface_count) { - u32 * from, * to_next, n_left_from, n_left_to_next; - u32 next_index; + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + u16 nexts[VLIB_FRAME_SIZE], *next; + u32 * from, n_left, thread_index; vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *im = &vnm->interface_main; - u32 thread_index = vm->thread_index; - /* Vector of buffer / pkt indices we're supposed to process */ + thread_index = vm->thread_index; + n_left = frame->n_vectors; from = vlib_frame_vector_args (frame); - /* Number of buffers / pkts */ - n_left_from = frame->n_vectors; + vlib_get_buffers (vm, from, bufs, n_left); - /* Speculatively send the first buffer to the last disposition we used */ - next_index = node->cached_next_index; + next = nexts; + b = bufs; - while (n_left_from > 0) + while (n_left > 8) { - /* set up to enqueue to our disposition with index = next_index */ - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + u32 adj_index0, adj_index1, adj_index2, adj_index3; + const ip_adjacency_t *adj0, *adj1, *adj2, *adj3; + const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3; - 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; - u32 bi1, adj_index1, next1; - u32 bi2, adj_index2, next2; - u32 bi3, adj_index3, next3; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p4, * p5; - vlib_buffer_t * p6, * p7; - - p4 = vlib_get_buffer (vm, from[4]); - p5 = vlib_get_buffer (vm, from[5]); - p6 = vlib_get_buffer (vm, from[6]); - p7 = vlib_get_buffer (vm, from[7]); - - vlib_prefetch_buffer_header (p4, LOAD); - vlib_prefetch_buffer_header (p5, LOAD); - vlib_prefetch_buffer_header (p6, LOAD); - vlib_prefetch_buffer_header (p7, LOAD); - } - - bi0 = from[0]; - to_next[0] = bi0; - bi1 = from[1]; - to_next[1] = bi1; - bi2 = from[2]; - to_next[2] = bi2; - bi3 = from[3]; - to_next[3] = bi3; - - from += 4; - to_next += 4; - n_left_from -= 4; - n_left_to_next -= 4; - - b0 = vlib_get_buffer(vm, bi0); - b1 = vlib_get_buffer(vm, bi1); - b2 = vlib_get_buffer(vm, bi2); - b3 = vlib_get_buffer(vm, bi3); - - /* Follow the DPO on which the midchain is stacked */ - adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; - adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX]; - adj_index2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX]; - adj_index3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX]; - - adj0 = adj_get(adj_index0); - adj1 = adj_get(adj_index1); - adj2 = adj_get(adj_index2); - adj3 = adj_get(adj_index3); - - dpo0 = &adj0->sub_type.midchain.next_dpo; - dpo1 = &adj1->sub_type.midchain.next_dpo; - dpo2 = &adj2->sub_type.midchain.next_dpo; - dpo3 = &adj3->sub_type.midchain.next_dpo; - - next0 = dpo0->dpoi_next_node; - next1 = dpo1->dpoi_next_node; - next2 = dpo2->dpoi_next_node; - next3 = dpo3->dpoi_next_node; - - vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; - vnet_buffer(b2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index; - vnet_buffer(b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index; - - if (interface_count) - { - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_TX, - thread_index, - adj0->rewrite_header.sw_if_index, - 1, - vlib_buffer_length_in_chain (vm, b0)); - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_TX, - thread_index, - adj1->rewrite_header.sw_if_index, - 1, - vlib_buffer_length_in_chain (vm, b1)); - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_TX, - thread_index, - adj2->rewrite_header.sw_if_index, - 1, - vlib_buffer_length_in_chain (vm, b2)); - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_TX, - thread_index, - adj3->rewrite_header.sw_if_index, - 1, - vlib_buffer_length_in_chain (vm, b3)); - } - - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->ai = adj_index0; - } - if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED)) - { - adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, - b1, sizeof (*tr)); - tr->ai = adj_index1; - } - if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED)) - { - adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, - b2, sizeof (*tr)); - tr->ai = adj_index2; - } - if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED)) - { - adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, - b3, sizeof (*tr)); - tr->ai = adj_index3; - } - - vlib_validate_buffer_enqueue_x4 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, bi2, bi3, - next0, next1, next2, next3); - } - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0, adj_index0, next0; - const ip_adjacency_t * adj0; - const dpo_id_t *dpo0; - vlib_buffer_t * b0; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer(vm, bi0); - - /* Follow the DPO on which the midchain is stacked */ - adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; - adj0 = adj_get(adj_index0); - dpo0 = &adj0->sub_type.midchain.next_dpo; - next0 = dpo0->dpoi_next_node; - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; - - if (interface_count) - { - vlib_increment_combined_counter (im->combined_sw_if_counters - + VNET_INTERFACE_COUNTER_TX, - thread_index, - adj0->rewrite_header.sw_if_index, - 1, - vlib_buffer_length_in_chain (vm, b0)); - } - - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, - b0, sizeof (*tr)); - tr->ai = adj_index0; - } - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } + /* Prefetch next iteration. */ + { + vlib_prefetch_buffer_header (b[4], LOAD); + vlib_prefetch_buffer_header (b[5], LOAD); + vlib_prefetch_buffer_header (b[6], LOAD); + vlib_prefetch_buffer_header (b[7], LOAD); + } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); + /* Follow the DPO on which the midchain is stacked */ + adj_index0 = vnet_buffer(b[0])->ip.adj_index[VLIB_TX]; + adj_index1 = vnet_buffer(b[1])->ip.adj_index[VLIB_TX]; + adj_index2 = vnet_buffer(b[2])->ip.adj_index[VLIB_TX]; + adj_index3 = vnet_buffer(b[3])->ip.adj_index[VLIB_TX]; + + adj0 = adj_get(adj_index0); + adj1 = adj_get(adj_index1); + adj2 = adj_get(adj_index2); + adj3 = adj_get(adj_index3); + + dpo0 = &adj0->sub_type.midchain.next_dpo; + dpo1 = &adj1->sub_type.midchain.next_dpo; + dpo2 = &adj2->sub_type.midchain.next_dpo; + dpo3 = &adj3->sub_type.midchain.next_dpo; + + next[0] = dpo0->dpoi_next_node; + next[1] = dpo1->dpoi_next_node; + next[2] = dpo2->dpoi_next_node; + next[3] = dpo3->dpoi_next_node; + + vnet_buffer(b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; + vnet_buffer(b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; + vnet_buffer(b[2])->ip.adj_index[VLIB_TX] = dpo2->dpoi_index; + vnet_buffer(b[3])->ip.adj_index[VLIB_TX] = dpo3->dpoi_index; + + if (interface_count) + { + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_TX, + thread_index, + adj0->rewrite_header.sw_if_index, + 1, + vlib_buffer_length_in_chain (vm, b[0])); + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_TX, + thread_index, + adj1->rewrite_header.sw_if_index, + 1, + vlib_buffer_length_in_chain (vm, b[1])); + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_TX, + thread_index, + adj2->rewrite_header.sw_if_index, + 1, + vlib_buffer_length_in_chain (vm, b[2])); + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_TX, + thread_index, + adj3->rewrite_header.sw_if_index, + 1, + vlib_buffer_length_in_chain (vm, b[3])); + } + + if (PREDICT_FALSE(node->flags & VLIB_NODE_FLAG_TRACE)) + { + if (PREDICT_FALSE(b[0]->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, + b[0], sizeof (*tr)); + tr->ai = adj_index0; + } + if (PREDICT_FALSE(b[1]->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, + b[1], sizeof (*tr)); + tr->ai = adj_index1; + } + if (PREDICT_FALSE(b[2]->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, + b[2], sizeof (*tr)); + tr->ai = adj_index2; + } + if (PREDICT_FALSE(b[3]->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, + b[3], sizeof (*tr)); + tr->ai = adj_index3; + } + } + n_left -= 4; + b += 4; + next += 4; } + while (n_left) + { + const ip_adjacency_t * adj0; + const dpo_id_t *dpo0; + u32 adj_index0; + + /* Follow the DPO on which the midchain is stacked */ + adj_index0 = vnet_buffer(b[0])->ip.adj_index[VLIB_TX]; + adj0 = adj_get(adj_index0); + dpo0 = &adj0->sub_type.midchain.next_dpo; + next[0] = dpo0->dpoi_next_node; + vnet_buffer(b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; + + if (interface_count) + { + vlib_increment_combined_counter (im->combined_sw_if_counters + + VNET_INTERFACE_COUNTER_TX, + thread_index, + adj0->rewrite_header.sw_if_index, + 1, + vlib_buffer_length_in_chain (vm, b[0])); + } + + if (PREDICT_FALSE(b[0]->flags & VLIB_BUFFER_IS_TRACED)) + { + adj_midchain_tx_trace_t *tr = vlib_add_trace (vm, node, + b[0], sizeof (*tr)); + tr->ai = adj_index0; + } + + n_left -= 1; + b += 1; + next += 1; + } + + vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); + return frame->n_vectors; } @@ -271,7 +218,7 @@ adj_midchain_tx (vlib_main_t * vm, return (adj_midchain_tx_inline(vm, node, frame, 1)); } -VLIB_REGISTER_NODE (adj_midchain_tx_node, static) = { +VLIB_REGISTER_NODE (adj_midchain_tx_node) = { .function = adj_midchain_tx, .name = "adj-midchain-tx", .vector_size = sizeof (u32), @@ -292,79 +239,44 @@ adj_midchain_tx_no_count (vlib_main_t * vm, return (adj_midchain_tx_inline(vm, node, frame, 0)); } -VLIB_REGISTER_NODE (adj_midchain_tx_no_count_node, static) = { +VLIB_REGISTER_NODE (adj_midchain_tx_no_count_node) = { .function = adj_midchain_tx_no_count, .name = "adj-midchain-tx-no-count", .vector_size = sizeof (u32), .format_trace = format_adj_midchain_tx_trace, - - .n_next_nodes = 1, - .next_nodes = { - [0] = "error-drop", - }, + .sibling_of = "adj-midchain-tx", }; -VNET_FEATURE_INIT (adj_midchain_tx_ip4, static) = { - .arc_name = "ip4-output", - .node_name = "adj-midchain-tx", - .runs_before = VNET_FEATURES ("interface-output"), - .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_IP4], -}; -VNET_FEATURE_INIT (adj_midchain_tx_no_count_ip4, static) = { - .arc_name = "ip4-output", - .node_name = "adj-midchain-tx-no-count", - .runs_before = VNET_FEATURES ("interface-output"), - .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_IP4], -}; -VNET_FEATURE_INIT (adj_midchain_tx_ip6, static) = { - .arc_name = "ip6-output", - .node_name = "adj-midchain-tx", - .runs_before = VNET_FEATURES ("interface-output"), - .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_IP6], -}; -VNET_FEATURE_INIT (adj_midchain_tx_no_count_ip6, static) = { - .arc_name = "ip6-output", - .node_name = "adj-midchain-tx-no-count", - .runs_before = VNET_FEATURES ("interface-output"), - .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_IP6], -}; -VNET_FEATURE_INIT (adj_midchain_tx_mpls, static) = { - .arc_name = "mpls-output", - .node_name = "adj-midchain-tx", - .runs_before = VNET_FEATURES ("interface-output"), - .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_MPLS], -}; -VNET_FEATURE_INIT (adj_midchain_tx_no_count_mpls, static) = { - .arc_name = "mpls-output", - .node_name = "adj-midchain-tx-no-count", - .runs_before = VNET_FEATURES ("interface-output"), - .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_MPLS], -}; -VNET_FEATURE_INIT (adj_midchain_tx_ethernet, static) = { - .arc_name = "ethernet-output", - .node_name = "adj-midchain-tx", - .runs_before = VNET_FEATURES ("error-drop"), - .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_ETHERNET], -}; -VNET_FEATURE_INIT (adj_midchain_tx_no_count_ethernet, static) = { - .arc_name = "ethernet-output", - .node_name = "adj-midchain-tx-no-count", - .runs_before = VNET_FEATURES ("error-drop"), - .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_ETHERNET], -}; -VNET_FEATURE_INIT (adj_midchain_tx_nsh, static) = { - .arc_name = "nsh-output", - .node_name = "adj-midchain-tx", - .runs_before = VNET_FEATURES ("error-drop"), - .feature_index_ptr = &adj_midchain_tx_feature_node[VNET_LINK_NSH], -}; -VNET_FEATURE_INIT (adj_midchain_tx_no_count_nsh, static) = { - .arc_name = "nsh-output", - .node_name = "adj-midchain-tx-no-count", - .runs_before = VNET_FEATURES ("error-drop"), - .feature_index_ptr = &adj_midchain_tx_no_count_feature_node[VNET_LINK_NSH], -}; +#ifndef CLIB_MARCH_VARIANT + +u8 +adj_is_midchain (adj_index_t ai) +{ + ip_adjacency_t *adj; + + adj = adj_get(ai); + + switch (adj->lookup_next_index) + { + case IP_LOOKUP_NEXT_MIDCHAIN: + case IP_LOOKUP_NEXT_MCAST_MIDCHAIN: + return (1); + case IP_LOOKUP_NEXT_ARP: + case IP_LOOKUP_NEXT_GLEAN: + case IP_LOOKUP_NEXT_BCAST: + case IP_LOOKUP_NEXT_MCAST: + case IP_LOOKUP_NEXT_DROP: + case IP_LOOKUP_NEXT_PUNT: + case IP_LOOKUP_NEXT_LOCAL: + case IP_LOOKUP_NEXT_REWRITE: + case IP_LOOKUP_NEXT_ICMP_ERROR: + case IP_LOOKUP_N_NEXT: + return (0); + } + + return (0); +} static inline u32 adj_get_midchain_node (vnet_link_t link) @@ -436,17 +348,6 @@ adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj) adj_midchain_tx_node.index); } -static u32 -adj_nbr_midchain_get_feature_node (ip_adjacency_t *adj) -{ - if (adj->ia_flags & ADJ_FLAG_MIDCHAIN_NO_COUNT) - { - return (adj_midchain_tx_no_count_feature_node[adj->ia_link]); - } - - return (adj_midchain_tx_feature_node[adj->ia_link]); -} - /** * adj_midchain_setup * @@ -455,20 +356,17 @@ adj_nbr_midchain_get_feature_node (ip_adjacency_t *adj) void adj_midchain_teardown (ip_adjacency_t *adj) { - u32 feature_index; - u8 arc_index; + vlib_main_t *vm = vlib_get_main(); 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); - } + vlib_worker_thread_barrier_sync(vm); + vnet_feature_modify_end_node( + adj_midchain_get_feature_arc_index_for_link_type (adj), + adj->rewrite_header.sw_if_index, + vlib_get_node_by_name (vlib_get_main(), + (u8*) "interface-output")->index); + vlib_worker_thread_barrier_release(vm); } /** @@ -482,9 +380,9 @@ adj_midchain_setup (adj_index_t adj_index, const void *data, adj_flags_t flags) { - u32 feature_index, tx_node; + vlib_main_t *vm = vlib_get_main(); ip_adjacency_t *adj; - u8 arc_index; + u32 tx_node; ASSERT(ADJ_INDEX_INVALID != adj_index); @@ -495,19 +393,23 @@ adj_midchain_setup (adj_index_t adj_index, 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); - - 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]++) + if (flags & ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR) { - vnet_feature_enable_disable_with_index (arc_index, feature_index, - adj->rewrite_header.sw_if_index, - 1 /* enable */, 0, 0); + adj->rewrite_header.flags |= VNET_REWRITE_FIXUP_IP4_O_4; } + else + { + adj->rewrite_header.flags &= ~VNET_REWRITE_FIXUP_IP4_O_4; + } + + tx_node = adj_nbr_midchain_get_tx_node(adj); + + vlib_worker_thread_barrier_sync(vm); + vnet_feature_modify_end_node( + adj_midchain_get_feature_arc_index_for_link_type (adj), + adj->rewrite_header.sw_if_index, + tx_node); + vlib_worker_thread_barrier_release(vm); /* * stack the midchain on the drop so it's ready to forward in the adj-midchain-tx. @@ -561,6 +463,58 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index, rewrite); } +void +adj_nbr_midchain_update_next_node (adj_index_t adj_index, + u32 next_node) +{ + ip_adjacency_t *adj; + vlib_main_t * vm; + + ASSERT(ADJ_INDEX_INVALID != adj_index); + + adj = adj_get(adj_index); + vm = vlib_get_main(); + + vlib_worker_thread_barrier_sync(vm); + + adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(), + adj->ia_node_index, + next_node); + + vnet_feature_modify_end_node( + adj_midchain_get_feature_arc_index_for_link_type (adj), + adj->rewrite_header.sw_if_index, + next_node); + + vlib_worker_thread_barrier_release(vm); +} + +void +adj_nbr_midchain_reset_next_node(adj_index_t adj_index) +{ + ip_adjacency_t *adj; + vlib_main_t * vm; + + ASSERT(ADJ_INDEX_INVALID != adj_index); + + adj = adj_get(adj_index); + vm = vlib_get_main(); + + vlib_worker_thread_barrier_sync(vm); + + adj->rewrite_header.next_index = + vlib_node_add_next(vlib_get_main(), + adj->ia_node_index, + adj_nbr_midchain_get_tx_node(adj)); + + vnet_feature_modify_end_node( + adj_midchain_get_feature_arc_index_for_link_type (adj), + adj->rewrite_header.sw_if_index, + adj_nbr_midchain_get_tx_node(adj)); + + vlib_worker_thread_barrier_release(vm); +} + /** * adj_nbr_midchain_unstack * @@ -810,3 +764,5 @@ adj_midchain_module_init (void) { dpo_register(DPO_ADJACENCY_MIDCHAIN, &adj_midchain_dpo_vft, midchain_nodes); } + +#endif diff --git a/src/vnet/adj/adj_midchain.h b/src/vnet/adj/adj_midchain.h index 1f5deaecd95..5fb0ee8efb3 100644 --- a/src/vnet/adj/adj_midchain.h +++ b/src/vnet/adj/adj_midchain.h @@ -52,6 +52,27 @@ extern void adj_nbr_midchain_update_rewrite(adj_index_t adj_index, /** * @brief + * Return the adjacency's next node to its default value + * + * @param adj_index + * The index of the neighbour adjacency. + */ +extern void adj_nbr_midchain_reset_next_node(adj_index_t adj_index); + +/** + * @brief + * Update the VLIB node to which packets are sent post processing + * + * @param adj_index + * The index of the neighbour adjacency. + * + * @param node node-index to send to + */ +extern void adj_nbr_midchain_update_next_node(adj_index_t adj_index, + u32 node_index); + +/** + * @brief * [re]stack a midchain. 'Stacking' is the act of forming parent-child * relationships in the data-plane graph. Do NOT use this function to * stack on a DPO type that might form a loop. @@ -139,4 +160,6 @@ extern void adj_midchain_delegate_restack(adj_index_t ai); */ extern void adj_midchain_delegate_unstack(adj_index_t ai); +extern u8 adj_is_midchain (adj_index_t ai); + #endif diff --git a/src/vnet/adj/adj_nbr.c b/src/vnet/adj/adj_nbr.c index 7acdccc72b0..8604bf73dd6 100644 --- a/src/vnet/adj/adj_nbr.c +++ b/src/vnet/adj/adj_nbr.c @@ -168,9 +168,16 @@ adj_nbr_evaluate_feature (adj_index_t ai) { feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index]; if (feature_count > 0) + { + vnet_feature_config_main_t *cm; + adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES; - } + cm = &fm->feature_config_mains[arc_index]; + adj->ia_cfg_index = vec_elt (cm->config_index_by_sw_if_index, + sw_if_index); + } + } return; } @@ -521,6 +528,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj, walk_adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE; } + adj_delegate_adj_modified(adj); adj_unlock(ai); adj_unlock(walk_ai); } @@ -578,7 +586,6 @@ adj_nbr_walk_cb (BVT(clib_bihash_kv) * kvp, { adj_walk_ctx_t *ctx = arg; - // FIXME: can't stop early... if (ADJ_WALK_RC_STOP == ctx->awc_cb(kvp->value, ctx->awc_ctx)) return (BIHASH_WALK_STOP); return (BIHASH_WALK_CONTINUE); diff --git a/src/vnet/adj/rewrite.c b/src/vnet/adj/rewrite.c index c8508c4b37a..fc2df9af109 100644 --- a/src/vnet/adj/rewrite.c +++ b/src/vnet/adj/rewrite.c @@ -60,7 +60,7 @@ format_vnet_rewrite (u8 * s, va_list * args) s = format (s, "DELETED:%d", rw->sw_if_index); } - s = format (s, " mtu:%d", rw->max_l3_packet_bytes); + s = format (s, " mtu:%d next:%d", rw->max_l3_packet_bytes, rw->next_index); /* Format rewrite string. */ if (rw->data_bytes > 0) diff --git a/src/vnet/adj/rewrite.h b/src/vnet/adj/rewrite.h index 5c1d24ea890..c23edbe1f60 100644 --- a/src/vnet/adj/rewrite.h +++ b/src/vnet/adj/rewrite.h @@ -55,10 +55,15 @@ typedef enum vnet_rewrite_flags_t_ * This adjacency/interface has output features configured */ VNET_REWRITE_HAS_FEATURES = (1 << 0), + + /** + * this adj performs IP4 over IP4 fixup + */ + VNET_REWRITE_FIXUP_IP4_O_4 = (1 << 1), } __attribute__ ((packed)) vnet_rewrite_flags_t; -/* *INDENT-OFF* */ -typedef CLIB_PACKED (struct { +typedef struct vnet_rewrite_header_t_ +{ /* Interface to mark re-written packets with. */ u32 sw_if_index; @@ -83,8 +88,7 @@ typedef CLIB_PACKED (struct { /* Rewrite string starting at end and going backwards. */ u8 data[0]; -}) vnet_rewrite_header_t; -/* *INDENT-ON* */ +} __clib_packed vnet_rewrite_header_t; /** * At 16 bytes of rewrite herader we have enought space left for a IPv6 @@ -114,6 +118,13 @@ STATIC_ASSERT (sizeof (vnet_rewrite_header_t) <= 16, sizeof (vnet_rewrite_header_t)]; \ } +typedef struct __rewrite_unused_t__ +{ + VNET_DECLARE_REWRITE; +} __rewrite_unused_t; + +STATIC_ASSERT_SIZEOF (__rewrite_unused_t, 128); + always_inline void vnet_rewrite_clear_data_internal (vnet_rewrite_header_t * rw, int max_size) { |