X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Freass%2Fip6_full_reass.c;h=7bcfdfc9f00dbb5d3d3f7efb0163ef430980ad0d;hb=f50bac1bb25b02d7f086627c4c0a0709ee0f61d5;hp=7b11e78b40f827dcd0d334e5f9e28b8ac5546dc8;hpb=896c896a3c4ed563a270281ff8b50fd253f4833f;p=vpp.git diff --git a/src/vnet/ip/reass/ip6_full_reass.c b/src/vnet/ip/reass/ip6_full_reass.c index 7b11e78b40f..7bcfdfc9f00 100644 --- a/src/vnet/ip/reass/ip6_full_reass.c +++ b/src/vnet/ip/reass/ip6_full_reass.c @@ -164,6 +164,8 @@ typedef struct u32 fq_index; u32 fq_feature_index; + // reference count for enabling/disabling feature - per interface + u32 *feature_use_refcount_per_intf; } ip6_full_reass_main_t; extern ip6_full_reass_main_t ip6_full_reass_main; @@ -213,6 +215,9 @@ typedef struct u32 total_data_len; u32 thread_id; u32 thread_id_to; + bool is_after_handoff; + ip6_header_t ip6_header; + ip6_frag_hdr_t ip6_frag_header; } ip6_full_reass_trace_t; static void @@ -249,7 +254,19 @@ format_ip6_full_reass_trace (u8 * s, va_list * args) u32 indent = 0; if (~0 != t->reass_id) { - s = format (s, "reass id: %u, op id: %u ", t->reass_id, t->op_id); + if (t->is_after_handoff) + { + s = + format (s, "%U\n", format_ip6_header, &t->ip6_header, + sizeof (t->ip6_header)); + s = + format (s, " %U\n", format_ip6_frag_hdr, &t->ip6_frag_header, + sizeof (t->ip6_frag_header)); + indent = 2; + } + s = + format (s, "%Ureass id: %u, op id: %u, ", format_white_space, indent, + t->reass_id, t->op_id); indent = format_get_indent (s); s = format (s, "first bi: %u, data len: %u, ip/fragment[%u, %u]", t->trace_range.first_bi, t->total_data_len, @@ -295,12 +312,33 @@ static void ip6_full_reass_add_trace (vlib_main_t * vm, vlib_node_runtime_t * node, ip6_full_reass_main_t * rm, ip6_full_reass_t * reass, u32 bi, + ip6_frag_hdr_t * ip6_frag_header, ip6_full_reass_trace_operation_e action, u32 thread_id_to) { vlib_buffer_t *b = vlib_get_buffer (vm, bi); vnet_buffer_opaque_t *vnb = vnet_buffer (b); + bool is_after_handoff = false; + if (vlib_buffer_get_trace_thread (b) != vm->thread_index) + { + is_after_handoff = true; + } ip6_full_reass_trace_t *t = vlib_add_trace (vm, node, b, sizeof (t[0])); + t->is_after_handoff = is_after_handoff; + if (t->is_after_handoff) + { + clib_memcpy (&t->ip6_header, vlib_buffer_get_current (b), + clib_min (sizeof (t->ip6_header), b->current_length)); + if (ip6_frag_header) + { + clib_memcpy (&t->ip6_frag_header, ip6_frag_header, + sizeof (t->ip6_frag_header)); + } + else + { + clib_memset (&t->ip6_frag_header, 0, sizeof (t->ip6_frag_header)); + } + } if (reass) { t->reass_id = reass->id; @@ -432,7 +470,7 @@ ip6_full_reass_on_timeout (vlib_main_t * vm, vlib_node_runtime_t * node, if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) { ip6_full_reass_add_trace (vm, node, rm, reass, reass->first_bi, - ICMP_ERROR_RT_EXCEEDED, ~0); + NULL, ICMP_ERROR_RT_EXCEEDED, ~0); } // fragment with offset zero received - send icmp message back if (b->flags & VLIB_BUFFER_NEXT_PRESENT) @@ -688,8 +726,9 @@ ip6_full_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node, ip6_header_t *ip = vlib_buffer_get_current (first_b); u16 ip6_frag_hdr_offset = first_b_vnb->ip.reass.ip6_frag_hdr_offset; ip6_ext_header_t *prev_hdr; - ip6_ext_header_find_t (ip, prev_hdr, frag_hdr, - IP_PROTOCOL_IPV6_FRAGMENTATION); + frag_hdr = + ip6_ext_header_find (vm, first_b, ip, IP_PROTOCOL_IPV6_FRAGMENTATION, + &prev_hdr); if (prev_hdr) { prev_hdr->next_hdr = frag_hdr->next_hdr; @@ -718,7 +757,7 @@ ip6_full_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node, first_b->flags &= ~VLIB_BUFFER_EXT_HDR_VALID; if (PREDICT_FALSE (first_b->flags & VLIB_BUFFER_IS_TRACED)) { - ip6_full_reass_add_trace (vm, node, rm, reass, reass->first_bi, + ip6_full_reass_add_trace (vm, node, rm, reass, reass->first_bi, NULL, FINALIZE, ~0); #if 0 // following code does a hexdump of packet fragments to stdout ... @@ -884,13 +923,13 @@ ip6_full_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node, else { // overlapping fragment - not allowed by RFC 8200 - ip6_full_reass_drop_all (vm, node, rm, reass); - ip6_full_reass_free (rm, rt, reass); if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED)) { - ip6_full_reass_add_trace (vm, node, rm, reass, *bi0, + ip6_full_reass_add_trace (vm, node, rm, reass, *bi0, frag_hdr, RANGE_OVERLAP, ~0); } + ip6_full_reass_drop_all (vm, node, rm, reass); + ip6_full_reass_free (rm, rt, reass); *next0 = IP6_FULL_REASSEMBLY_NEXT_DROP; *error0 = IP6_ERROR_REASS_OVERLAPPING_FRAGMENT; return IP6_FULL_REASS_RC_OK; @@ -903,18 +942,20 @@ check_if_done_maybe: { if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED)) { - ip6_full_reass_add_trace (vm, node, rm, reass, *bi0, RANGE_NEW, ~0); + ip6_full_reass_add_trace (vm, node, rm, reass, *bi0, frag_hdr, + RANGE_NEW, ~0); } } if (~0 != reass->last_packet_octet && reass->data_len == reass->last_packet_octet + 1) { *handoff_thread_idx = reass->sendout_thread_index; + int handoff = + reass->memory_owner_thread_index != reass->sendout_thread_index; ip6_full_reass_rc_t rc = ip6_full_reass_finalize (vm, node, rm, rt, reass, bi0, next0, error0, is_custom_app); - if (IP6_FULL_REASS_RC_OK == rc - && reass->memory_owner_thread_index != reass->sendout_thread_index) + if (IP6_FULL_REASS_RC_OK == rc && handoff) { return IP6_FULL_REASS_RC_HANDOFF; } @@ -1040,8 +1081,10 @@ ip6_full_reassembly_inline (vlib_main_t * vm, ip6_ext_header_t *prev_hdr; if (ip6_ext_hdr (ip0->protocol)) { - ip6_ext_header_find_t (ip0, prev_hdr, frag_hdr, - IP_PROTOCOL_IPV6_FRAGMENTATION); + frag_hdr = + ip6_ext_header_find (vm, b0, ip0, + IP_PROTOCOL_IPV6_FRAGMENTATION, + &prev_hdr); } if (!frag_hdr) { @@ -1049,6 +1092,9 @@ ip6_full_reassembly_inline (vlib_main_t * vm, next0 = IP6_FULL_REASSEMBLY_NEXT_INPUT; goto skip_reass; } + vnet_buffer (b0)->ip.reass.ip6_frag_hdr_offset = + (u8 *) frag_hdr - (u8 *) ip0; + if (0 == ip6_frag_hdr_offset (frag_hdr)) { // first fragment - verify upper-layer is present @@ -1067,9 +1113,6 @@ ip6_full_reassembly_inline (vlib_main_t * vm, next0 = IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR; goto skip_reass; } - vnet_buffer (b0)->ip.reass.ip6_frag_hdr_offset = - (u8 *) frag_hdr - (u8 *) ip0; - ip6_full_reass_kv_t kv; u8 do_handoff = 0; @@ -1098,12 +1141,8 @@ ip6_full_reassembly_inline (vlib_main_t * vm, if (PREDICT_FALSE (do_handoff)) { next0 = IP6_FULL_REASSEMBLY_NEXT_HANDOFF; - if (is_feature) - vnet_buffer (b0)->ip.reass.owner_feature_thread_index = - kv.v.memory_owner_thread_index; - else - vnet_buffer (b0)->ip.reass.owner_thread_index = - kv.v.memory_owner_thread_index; + vnet_buffer (b0)->ip.reass.owner_thread_index = + kv.v.memory_owner_thread_index; } else if (reass) { @@ -1118,12 +1157,8 @@ ip6_full_reassembly_inline (vlib_main_t * vm, case IP6_FULL_REASS_RC_HANDOFF: next0 = IP6_FULL_REASSEMBLY_NEXT_HANDOFF; b0 = vlib_get_buffer (vm, bi0); - if (is_feature) - vnet_buffer (b0)->ip.reass.owner_feature_thread_index = - handoff_thread_idx; - else - vnet_buffer (b0)->ip.reass.owner_thread_index = - handoff_thread_idx; + vnet_buffer (b0)->ip.reass.owner_thread_index = + handoff_thread_idx; break; case IP6_FULL_REASS_RC_TOO_MANY_FRAGMENTS: vlib_node_increment_counter (vm, node->node_index, @@ -1164,33 +1199,29 @@ ip6_full_reassembly_inline (vlib_main_t * vm, error0 = IP6_ERROR_REASS_LIMIT_REACHED; } - b0->error = node->errors[error0]; - if (~0 != bi0) { skip_reass: 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); + b0->error = node->errors[error0]; + if (next0 == IP6_FULL_REASSEMBLY_NEXT_HANDOFF) { if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - if (is_feature) - ip6_full_reass_add_trace (vm, node, rm, NULL, bi0, - HANDOFF, - vnet_buffer (b0)->ip. - reass.owner_feature_thread_index); - else - ip6_full_reass_add_trace (vm, node, rm, NULL, bi0, - HANDOFF, - vnet_buffer (b0)->ip. - reass.owner_thread_index); + ip6_full_reass_add_trace (vm, node, rm, NULL, bi0, + frag_hdr, HANDOFF, + vnet_buffer (b0)->ip. + reass.owner_thread_index); } } else if (is_feature && IP6_ERROR_NONE == error0) { - b0 = vlib_get_buffer (vm, bi0); vnet_feature_next (&next0, b0); } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, @@ -1318,7 +1349,7 @@ typedef struct clib_bihash_48_8_t *new_hash; } ip6_rehash_cb_ctx; -static void +static int ip6_rehash_cb (clib_bihash_kv_48_8_t * kv, void *_ctx) { ip6_rehash_cb_ctx *ctx = _ctx; @@ -1326,6 +1357,7 @@ ip6_rehash_cb (clib_bihash_kv_48_8_t * kv, void *_ctx) { ctx->failure = 1; } + return (BIHASH_WALK_CONTINUE); } static void @@ -1437,6 +1469,7 @@ ip6_full_reass_init_function (vlib_main_t * vm) rm->fq_feature_index = vlib_frame_queue_main_init (ip6_full_reass_node_feature.index, 0); + rm->feature_use_refcount_per_intf = NULL; return error; } @@ -1727,10 +1760,7 @@ ip6_full_reassembly_handoff_inline (vlib_main_t * vm, while (n_left_from > 0) { - ti[0] = - (is_feature) ? vnet_buffer (b[0])->ip. - reass.owner_feature_thread_index : vnet_buffer (b[0])->ip. - reass.owner_thread_index; + ti[0] = vnet_buffer (b[0])->ip.reass.owner_thread_index; if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1803,6 +1833,35 @@ VLIB_REGISTER_NODE (ip6_full_reassembly_feature_handoff_node) = { }; /* *INDENT-ON* */ +#ifndef CLIB_MARCH_VARIANT +int +ip6_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable) +{ + ip6_full_reass_main_t *rm = &ip6_full_reass_main; + vec_validate (rm->feature_use_refcount_per_intf, sw_if_index); + if (is_enable) + { + if (!rm->feature_use_refcount_per_intf[sw_if_index]) + { + ++rm->feature_use_refcount_per_intf[sw_if_index]; + return vnet_feature_enable_disable ("ip6-unicast", + "ip6-full-reassembly-feature", + sw_if_index, 1, 0, 0); + } + ++rm->feature_use_refcount_per_intf[sw_if_index]; + } + else + { + --rm->feature_use_refcount_per_intf[sw_if_index]; + if (!rm->feature_use_refcount_per_intf[sw_if_index]) + return vnet_feature_enable_disable ("ip6-unicast", + "ip6-full-reassembly-feature", + sw_if_index, 0, 0, 0); + } + return -1; +} +#endif + /* * fd.io coding-style-patch-verification: ON *