X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Freass%2Fip4_full_reass.c;h=bab7d479dcf52b96e46a423c2323548e67c030b1;hb=99c317a6066f825af002ca0c18caaef337ef0bcb;hp=5b69234e438ce8b0c9355302f7b34a2f80ffbdcd;hpb=121a16af699b168daa712f58521275127f8eb29b;p=vpp.git diff --git a/src/vnet/ip/reass/ip4_full_reass.c b/src/vnet/ip/reass/ip4_full_reass.c index 5b69234e438..bab7d479dcf 100644 --- a/src/vnet/ip/reass/ip4_full_reass.c +++ b/src/vnet/ip/reass/ip4_full_reass.c @@ -427,8 +427,7 @@ ip4_full_reass_free (ip4_full_reass_main_t * rm, * with local variables would cause either buffer leak or corruption */ always_inline void ip4_full_reass_drop_all (vlib_main_t *vm, vlib_node_runtime_t *node, - ip4_full_reass_t *reass, u32 *n_left_to_next, - u32 **to_next) + ip4_full_reass_t *reass) { u32 range_bi = reass->first_bi; vlib_buffer_t *range_b; @@ -452,40 +451,23 @@ ip4_full_reass_drop_all (vlib_main_t *vm, vlib_node_runtime_t *node, if (~0 != reass->error_next_index && reass->error_next_index < node->n_next_nodes) { - u32 next_index; - - next_index = reass->error_next_index; - u32 bi = ~0; + u32 n_free = vec_len (to_free); /* record number of packets sent to custom app */ vlib_node_increment_counter (vm, node->node_index, - IP4_ERROR_REASS_TO_CUSTOM_APP, - vec_len (to_free)); - - while (vec_len (to_free) > 0) - { - vlib_get_next_frame (vm, node, next_index, *to_next, - (*n_left_to_next)); + IP4_ERROR_REASS_TO_CUSTOM_APP, n_free); - while (vec_len (to_free) > 0 && (*n_left_to_next) > 0) - { - bi = vec_pop (to_free); + if (node->flags & VLIB_NODE_FLAG_TRACE) + for (u32 i = 0; i < n_free; i++) + { + vlib_buffer_t *b = vlib_get_buffer (vm, to_free[i]); + if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) + ip4_full_reass_add_trace (vm, node, reass, to_free[i], + RANGE_DISCARD, 0, ~0); + } - if (~0 != bi) - { - vlib_buffer_t *b = vlib_get_buffer (vm, bi); - if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) - { - ip4_full_reass_add_trace (vm, node, reass, bi, - RANGE_DISCARD, 0, ~0); - } - *to_next[0] = bi; - (*to_next) += 1; - (*n_left_to_next) -= 1; - } - } - vlib_put_next_frame (vm, node, next_index, (*n_left_to_next)); - } + vlib_buffer_enqueue_to_single_next (vm, node, to_free, + reass->error_next_index, n_free); } else { @@ -564,8 +546,7 @@ always_inline ip4_full_reass_t * ip4_full_reass_find_or_create (vlib_main_t *vm, vlib_node_runtime_t *node, ip4_full_reass_main_t *rm, ip4_full_reass_per_thread_t *rt, - ip4_full_reass_kv_t *kv, u8 *do_handoff, - u32 *n_left_to_next, u32 **to_next) + ip4_full_reass_kv_t *kv, u8 *do_handoff) { ip4_full_reass_t *reass; f64 now; @@ -590,7 +571,7 @@ again: { vlib_node_increment_counter (vm, node->node_index, IP4_ERROR_REASS_TIMEOUT, 1); - ip4_full_reass_drop_all (vm, node, reass, n_left_to_next, to_next); + ip4_full_reass_drop_all (vm, node, reass); ip4_full_reass_free (rm, rt, reass); reass = NULL; } @@ -647,7 +628,6 @@ ip4_full_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t *last_b = NULL; u32 sub_chain_bi = reass->first_bi; u32 total_length = 0; - u32 buf_cnt = 0; do { u32 tmp_bi = sub_chain_bi; @@ -684,7 +664,6 @@ ip4_full_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_length_in_chain (vm, tmp) - trim_front - trim_end; while (1) { - ++buf_cnt; if (trim_front) { if (trim_front > tmp->current_length) @@ -1184,205 +1163,195 @@ ip4_full_reass_inline (vlib_main_t *vm, vlib_node_runtime_t *node, bool is_local) { u32 *from = vlib_frame_vector_args (frame); - u32 n_left_from, n_left_to_next, *to_next, next_index; + u32 n_left, n_next = 0, to_next[VLIB_FRAME_SIZE]; ip4_full_reass_main_t *rm = &ip4_full_reass_main; ip4_full_reass_per_thread_t *rt = &rm->per_thread_data[vm->thread_index]; + u16 nexts[VLIB_FRAME_SIZE]; + clib_spinlock_lock (&rt->lock); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - while (n_left_from > 0) + n_left = frame->n_vectors; + while (n_left > 0) { - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 error0 = IP4_ERROR_NONE; - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0; - u32 error0 = IP4_ERROR_NONE; - - bi0 = from[0]; - b0 = vlib_get_buffer (vm, bi0); + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); - ip4_header_t *ip0 = vlib_buffer_get_current (b0); - if (!ip4_get_fragment_more (ip0) && !ip4_get_fragment_offset (ip0)) + ip4_header_t *ip0 = vlib_buffer_get_current (b0); + if (!ip4_get_fragment_more (ip0) && !ip4_get_fragment_offset (ip0)) + { + // this is a whole packet - no fragmentation + if (CUSTOM != type) { - // this is a whole packet - no fragmentation - if (CUSTOM != type) - { - next0 = IP4_FULL_REASS_NEXT_INPUT; - } - else - { - next0 = vnet_buffer (b0)->ip.reass.next_index; - } - ip4_full_reass_add_trace (vm, node, NULL, bi0, PASSTHROUGH, 0, - ~0); - goto packet_enqueue; + next0 = IP4_FULL_REASS_NEXT_INPUT; } - - if (is_local && !rm->is_local_reass_enabled) + else { - next0 = IP4_FULL_REASS_NEXT_DROP; - goto packet_enqueue; + next0 = vnet_buffer (b0)->ip.reass.next_index; } + ip4_full_reass_add_trace (vm, node, NULL, bi0, PASSTHROUGH, 0, ~0); + goto packet_enqueue; + } - const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0); - const u32 fragment_length = - clib_net_to_host_u16 (ip0->length) - ip4_header_bytes (ip0); - const u32 fragment_last = fragment_first + fragment_length - 1; + if (is_local && !rm->is_local_reass_enabled) + { + next0 = IP4_FULL_REASS_NEXT_DROP; + goto packet_enqueue; + } - /* Keep track of received fragments */ - vlib_node_increment_counter (vm, node->node_index, - IP4_ERROR_REASS_FRAGMENTS_RCVD, 1); + const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0); + const u32 fragment_length = + clib_net_to_host_u16 (ip0->length) - ip4_header_bytes (ip0); + const u32 fragment_last = fragment_first + fragment_length - 1; - if (fragment_first > fragment_last || - fragment_first + fragment_length > UINT16_MAX - 20 || - (fragment_length < 8 && // 8 is minimum frag length per RFC 791 - ip4_get_fragment_more (ip0))) - { - next0 = IP4_FULL_REASS_NEXT_DROP; - error0 = IP4_ERROR_REASS_MALFORMED_PACKET; - goto packet_enqueue; - } + /* Keep track of received fragments */ + vlib_node_increment_counter (vm, node->node_index, + IP4_ERROR_REASS_FRAGMENTS_RCVD, 1); - u32 fib_index = vec_elt (ip4_main.fib_index_by_sw_if_index, - vnet_buffer (b0)->sw_if_index[VLIB_RX]); + if (fragment_first > fragment_last || + fragment_first + fragment_length > UINT16_MAX - 20 || + (fragment_length < 8 && // 8 is minimum frag length per RFC 791 + ip4_get_fragment_more (ip0))) + { + next0 = IP4_FULL_REASS_NEXT_DROP; + error0 = IP4_ERROR_REASS_MALFORMED_PACKET; + goto packet_enqueue; + } + + u32 fib_index = (vnet_buffer (b0)->sw_if_index[VLIB_TX] == (u32) ~0) ? + vec_elt (ip4_main.fib_index_by_sw_if_index, + vnet_buffer (b0)->sw_if_index[VLIB_RX]) : + vnet_buffer (b0)->sw_if_index[VLIB_TX]; - ip4_full_reass_kv_t kv = { .k.fib_index = fib_index, - .k.src.as_u32 = ip0->src_address.as_u32, - .k.dst.as_u32 = ip0->dst_address.as_u32, - .k.frag_id = ip0->fragment_id, - .k.proto = ip0->protocol + ip4_full_reass_kv_t kv = { .k.fib_index = fib_index, + .k.src.as_u32 = ip0->src_address.as_u32, + .k.dst.as_u32 = ip0->dst_address.as_u32, + .k.frag_id = ip0->fragment_id, + .k.proto = ip0->protocol - }; - u8 do_handoff = 0; + }; + u8 do_handoff = 0; - ip4_full_reass_t *reass = ip4_full_reass_find_or_create ( - vm, node, rm, rt, &kv, &do_handoff, &n_left_to_next, &to_next); + ip4_full_reass_t *reass = + ip4_full_reass_find_or_create (vm, node, rm, rt, &kv, &do_handoff); - if (reass) + if (reass) + { + const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0); + if (0 == fragment_first) { - const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0); - if (0 == fragment_first) - { - reass->sendout_thread_index = vm->thread_index; - } + reass->sendout_thread_index = vm->thread_index; } + } - if (PREDICT_FALSE (do_handoff)) + if (PREDICT_FALSE (do_handoff)) + { + next0 = IP4_FULL_REASS_NEXT_HANDOFF; + vnet_buffer (b0)->ip.reass.owner_thread_index = + kv.v.memory_owner_thread_index; + } + else if (reass) + { + u32 handoff_thread_idx; + u32 counter = ~0; + switch (ip4_full_reass_update (vm, node, rm, rt, reass, &bi0, &next0, + &error0, CUSTOM == type, + &handoff_thread_idx)) { + case IP4_REASS_RC_OK: + /* nothing to do here */ + break; + case IP4_REASS_RC_HANDOFF: next0 = IP4_FULL_REASS_NEXT_HANDOFF; + b0 = vlib_get_buffer (vm, bi0); vnet_buffer (b0)->ip.reass.owner_thread_index = - kv.v.memory_owner_thread_index; + handoff_thread_idx; + break; + case IP4_REASS_RC_TOO_MANY_FRAGMENTS: + counter = IP4_ERROR_REASS_FRAGMENT_CHAIN_TOO_LONG; + break; + case IP4_REASS_RC_NO_BUF: + counter = IP4_ERROR_REASS_NO_BUF; + break; + case IP4_REASS_RC_INTERNAL_ERROR: + counter = IP4_ERROR_REASS_INTERNAL_ERROR; + /* Sanitization is needed in internal error cases only, as + * the incoming packet is already dropped in other cases, + * also adding bi0 back to the reassembly list, fixes the + * leaking of buffers during internal errors. + * + * Also it doesnt make sense to send these buffers custom + * app, these fragments are with internal errors */ + sanitize_reass_buffers_add_missing (vm, reass, &bi0); + reass->error_next_index = ~0; + break; } - else if (reass) - { - u32 handoff_thread_idx; - u32 counter = ~0; - switch (ip4_full_reass_update - (vm, node, rm, rt, reass, &bi0, &next0, - &error0, CUSTOM == type, &handoff_thread_idx)) - { - case IP4_REASS_RC_OK: - /* nothing to do here */ - break; - case IP4_REASS_RC_HANDOFF: - next0 = IP4_FULL_REASS_NEXT_HANDOFF; - b0 = vlib_get_buffer (vm, bi0); - vnet_buffer (b0)->ip.reass.owner_thread_index = - handoff_thread_idx; - break; - case IP4_REASS_RC_TOO_MANY_FRAGMENTS: - counter = IP4_ERROR_REASS_FRAGMENT_CHAIN_TOO_LONG; - break; - case IP4_REASS_RC_NO_BUF: - counter = IP4_ERROR_REASS_NO_BUF; - break; - case IP4_REASS_RC_INTERNAL_ERROR: - counter = IP4_ERROR_REASS_INTERNAL_ERROR; - /* Sanitization is needed in internal error cases only, as - * the incoming packet is already dropped in other cases, - * also adding bi0 back to the reassembly list, fixes the - * leaking of buffers during internal errors. - * - * Also it doesnt make sense to send these buffers custom - * app, these fragments are with internal errors */ - sanitize_reass_buffers_add_missing (vm, reass, &bi0); - reass->error_next_index = ~0; - break; - } - if (~0 != counter) - { - vlib_node_increment_counter (vm, node->node_index, counter, - 1); - ip4_full_reass_drop_all (vm, node, reass, &n_left_to_next, - &to_next); - ip4_full_reass_free (rm, rt, reass); - goto next_packet; - } - } - else + if (~0 != counter) { - next0 = IP4_FULL_REASS_NEXT_DROP; - error0 = IP4_ERROR_REASS_LIMIT_REACHED; + vlib_node_increment_counter (vm, node->node_index, counter, 1); + ip4_full_reass_drop_all (vm, node, reass); + ip4_full_reass_free (rm, rt, reass); + goto next_packet; } + } + else + { + next0 = IP4_FULL_REASS_NEXT_DROP; + error0 = IP4_ERROR_REASS_LIMIT_REACHED; + } + packet_enqueue: - packet_enqueue: - - if (bi0 != ~0) + if (bi0 != ~0) + { + /* bi0 might have been updated by reass_finalize, reload */ + b0 = vlib_get_buffer (vm, bi0); + if (IP4_ERROR_NONE != error0) { - to_next[0] = bi0; - to_next += 1; - n_left_to_next -= 1; - - /* bi0 might have been updated by reass_finalize, reload */ - b0 = vlib_get_buffer (vm, bi0); - if (IP4_ERROR_NONE != error0) - { - b0->error = node->errors[error0]; - } - - if (next0 == IP4_FULL_REASS_NEXT_HANDOFF) - { - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - ip4_full_reass_add_trace ( - vm, node, NULL, bi0, HANDOFF, 0, - vnet_buffer (b0)->ip.reass.owner_thread_index); - } - } - else if (FEATURE == type && IP4_ERROR_NONE == error0) - { - vnet_feature_next (&next0, b0); - } + b0->error = node->errors[error0]; + } - /* Increment the counter to-custom-app also as this fragment is - * also going to application */ - if (CUSTOM == type) + if (next0 == IP4_FULL_REASS_NEXT_HANDOFF) + { + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - vlib_node_increment_counter ( - vm, node->node_index, IP4_ERROR_REASS_TO_CUSTOM_APP, 1); + ip4_full_reass_add_trace ( + vm, node, NULL, bi0, HANDOFF, 0, + vnet_buffer (b0)->ip.reass.owner_thread_index); } + } + else if (FEATURE == type && IP4_ERROR_NONE == error0) + { + vnet_feature_next (&next0, b0); + } - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - IP4_REASS_DEBUG_BUFFER (bi0, enqueue_next); + /* Increment the counter to-custom-app also as this fragment is + * also going to application */ + if (CUSTOM == type) + { + vlib_node_increment_counter (vm, node->node_index, + IP4_ERROR_REASS_TO_CUSTOM_APP, 1); } - next_packet: - from += 1; - n_left_from -= 1; + to_next[n_next] = bi0; + nexts[n_next] = next0; + n_next++; + IP4_REASS_DEBUG_BUFFER (bi0, enqueue_next); } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); + next_packet: + from += 1; + n_left -= 1; } clib_spinlock_unlock (&rt->lock); + + vlib_buffer_enqueue_to_next (vm, node, to_next, nexts, n_next); return frame->n_vectors; } @@ -1455,11 +1424,11 @@ VLIB_REGISTER_NODE (ip4_full_reass_node_feature) = { }; VNET_FEATURE_INIT (ip4_full_reass_feature, static) = { - .arc_name = "ip4-unicast", - .node_name = "ip4-full-reassembly-feature", - .runs_before = VNET_FEATURES ("ip4-lookup", - "ipsec4-input-feature"), - .runs_after = 0, + .arc_name = "ip4-unicast", + .node_name = "ip4-full-reassembly-feature", + .runs_before = VNET_FEATURES ("ip4-lookup", "ipsec4-input-feature", + "ip4-sv-reassembly-feature"), + .runs_after = 0, }; VLIB_NODE_FN (ip4_full_reass_node_custom) (vlib_main_t * vm, @@ -1484,15 +1453,6 @@ VLIB_REGISTER_NODE (ip4_full_reass_node_custom) = { }, }; -VNET_FEATURE_INIT (ip4_full_reass_custom, static) = { - .arc_name = "ip4-unicast", - .node_name = "ip4-full-reassembly-feature", - .runs_before = VNET_FEATURES ("ip4-lookup", - "ipsec4-input-feature"), - .runs_after = 0, -}; - - #ifndef CLIB_MARCH_VARIANT uword ip4_full_reass_custom_register_next_node (uword node_index) @@ -1688,7 +1648,6 @@ ip4_full_reass_walk_expired (vlib_main_t *vm, vlib_node_runtime_t *node, uword thread_index = 0; int index; const uword nthreads = vlib_num_workers () + 1; - u32 n_left_to_next, *to_next; for (thread_index = 0; thread_index < nthreads; ++thread_index) { @@ -1734,8 +1693,7 @@ ip4_full_reass_walk_expired (vlib_main_t *vm, vlib_node_runtime_t *node, vec_foreach (i, pool_indexes_to_free) { ip4_full_reass_t *reass = pool_elt_at_index (rt->pool, i[0]); - ip4_full_reass_drop_all (vm, node, reass, &n_left_to_next, - &to_next); + ip4_full_reass_drop_all (vm, node, reass); ip4_full_reass_free (rm, rt, reass); } @@ -2101,7 +2059,7 @@ ip4_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable) "ip4-full-reassembly-feature", sw_if_index, 0, 0, 0); } - return -1; + return 0; } void