From: Damjan Marion Date: Fri, 10 Jun 2016 17:26:54 +0000 (+0200) Subject: Fix double-enqueued packet in interface-output dual-loop, fixes VPP-116 X-Git-Tag: v16.09-rc1~297 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=6c56a3c6f0382f3751272d0784e9e0d16a646f3f;p=vpp.git Fix double-enqueued packet in interface-output dual-loop, fixes VPP-116 When speculative enqueue fails and a buffer needs to be moved to a new node queue the original buffer is not correctly removed from the original queue so buffer get send for transmit and encryption at the same time. This issue will only be hit with the double loop so low throughput traffic like pings will not hit the issue. This code path is also only hit when the feature flag is enabled so will not be hit by normal traffic Patch also reorgnizes code to reduce number of branches in the interface output node loop. Change-Id: I3653400e58bdfd833e6c42823bab51586128b54b Signed-off-by: Sergio Gonzalez Monroy Signed-off-by: Damjan Marion --- diff --git a/vnet/vnet/interface.c b/vnet/vnet/interface.c index d36f7811d90..2fb93748b1e 100644 --- a/vnet/vnet/interface.c +++ b/vnet/vnet/interface.c @@ -689,8 +689,8 @@ vnet_register_interface (vnet_main_t * vnm, r.flags = 0; r.name = output_node_name; r.function = dev_class->no_flatten_output_chains ? - vnet_interface_output_node_no_flatten : - vnet_interface_output_node; + vnet_interface_output_node_no_flatten_multiarch_select() : + vnet_interface_output_node_multiarch_select() ; r.format_trace = format_vnet_interface_output_trace; { diff --git a/vnet/vnet/interface_funcs.h b/vnet/vnet/interface_funcs.h index 9d6fe48e23c..7832afcc7c4 100644 --- a/vnet/vnet/interface_funcs.h +++ b/vnet/vnet/interface_funcs.h @@ -179,14 +179,8 @@ typedef struct { } vnet_interface_output_runtime_t; /* Interface output functions. */ -uword -vnet_interface_output_node (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame); -uword -vnet_interface_output_node_no_flatten (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame); +void * vnet_interface_output_node_multiarch_select (void); +void * vnet_interface_output_node_no_flatten_multiarch_select (void); word vnet_sw_interface_compare (vnet_main_t * vnm, uword sw_if_index0, uword sw_if_index1); word vnet_hw_interface_compare (vnet_main_t * vnm, uword hw_if_index0, uword hw_if_index1); diff --git a/vnet/vnet/interface_output.c b/vnet/vnet/interface_output.c index 9f9fb707297..b19ca7c50c3 100644 --- a/vnet/vnet/interface_output.c +++ b/vnet/vnet/interface_output.c @@ -393,11 +393,14 @@ vnet_interface_output_node (vlib_main_t * vm, return n_buffers; } - -uword -vnet_interface_output_node_no_flatten (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node) +CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node) + +always_inline uword +vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, + int with_features) { vnet_main_t * vnm = vnet_get_main(); vnet_interface_output_runtime_t * rt = (void *) node->runtime_data; @@ -465,6 +468,7 @@ vnet_interface_output_node_no_flatten (vlib_main_t * vm, u32 bi0, bi1; vlib_buffer_t * b0, * b1; u32 tx_swif0, tx_swif1; + u32 next0, next1; /* Prefetch next iteration. */ vlib_prefetch_buffer_with_index (vm, from[2], LOAD); @@ -493,20 +497,16 @@ vnet_interface_output_node_no_flatten (vlib_main_t * vm, n_bytes += n_bytes_b0 + n_bytes_b1; n_packets += 2; - - if (PREDICT_FALSE(si->output_feature_bitmap && - ((b0->flags & BUFFER_OUTPUT_FEAT_DONE) == 0))) + if (with_features) { - u32 next0; b0->flags |= BUFFER_OUTPUT_FEAT_DONE; vnet_buffer(b0)->output_features.bitmap = si->output_feature_bitmap; count_trailing_zeros(next0, vnet_buffer(b0)->output_features.bitmap); vnet_buffer(b0)->output_features.bitmap &= ~(1 << next0); - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_tx, - n_left_to_tx, bi0, next0); } else { + next0 = VNET_INTERFACE_OUTPUT_NEXT_TX; vnet_buffer(b0)->output_features.bitmap = 0; if (PREDICT_FALSE(tx_swif0 != rt->sw_if_index)) @@ -521,19 +521,16 @@ vnet_interface_output_node_no_flatten (vlib_main_t * vm, } } - if (PREDICT_FALSE(si->output_feature_bitmap && - ((b1->flags & BUFFER_OUTPUT_FEAT_DONE) == 0))) + if (with_features) { - u32 next1; b1->flags |= BUFFER_OUTPUT_FEAT_DONE; vnet_buffer(b1)->output_features.bitmap = si->output_feature_bitmap; count_trailing_zeros(next1, vnet_buffer(b1)->output_features.bitmap); vnet_buffer(b1)->output_features.bitmap &= ~(1 << next1); - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_tx, - n_left_to_tx, bi1, next1); } else { + next1 = VNET_INTERFACE_OUTPUT_NEXT_TX; vnet_buffer(b1)->output_features.bitmap = 0; /* update vlan subif tx counts, if required */ @@ -548,7 +545,9 @@ vnet_interface_output_node_no_flatten (vlib_main_t * vm, n_bytes_b1); } } - + if (with_features) + vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_tx, + n_left_to_tx, bi0, bi1, next0, next1); } while (from + 1 <= from_end && n_left_to_tx >= 1) @@ -574,8 +573,7 @@ vnet_interface_output_node_no_flatten (vlib_main_t * vm, n_bytes += n_bytes_b0; n_packets += 1; - if (PREDICT_FALSE(si->output_feature_bitmap && - ((b0->flags & BUFFER_OUTPUT_FEAT_DONE) == 0))) + if (with_features) { u32 next0; b0->flags |= BUFFER_OUTPUT_FEAT_DONE; @@ -616,6 +614,32 @@ vnet_interface_output_node_no_flatten (vlib_main_t * vm, return n_buffers; } +uword +vnet_interface_output_node_no_flatten (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + vnet_main_t * vnm = vnet_get_main (); + vnet_interface_output_runtime_t * rt = (void *) node->runtime_data; + vnet_sw_interface_t * si; + si = vnet_get_sw_interface (vnm, rt->sw_if_index); + + if (PREDICT_FALSE(si->output_feature_bitmap)) + { + /* if first pakcet in the frame have BUFFER_OUTPUT_FEAT_DONE flag set + then whole frame is arriving from feature node */ + + u32 * from = vlib_frame_args (frame); + vlib_buffer_t * b = vlib_get_buffer (vm, from[0]); + + if ((b->flags & BUFFER_OUTPUT_FEAT_DONE) == 0) + return vnet_interface_output_node_no_flatten_inline (vm, node, frame, 1); + } + return vnet_interface_output_node_no_flatten_inline (vm, node, frame, 0); +} + +VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node_no_flatten) +CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node_no_flatten) /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */ static uword