X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;ds=inline;f=src%2Fvnet%2Fip%2Freass%2Fip6_full_reass.c;h=7d6a31e170a787dc09e57813f3fb47d0fccca9b2;hb=a877cf9f3980f9721246887f67b22b6591cb873f;hp=92fab60d33719fe76afa86d26ec04eb0022696e6;hpb=2d0ebd7ebc555565868038a09d80a61f5de29430;p=vpp.git diff --git a/src/vnet/ip/reass/ip6_full_reass.c b/src/vnet/ip/reass/ip6_full_reass.c index 92fab60d337..7d6a31e170a 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) @@ -719,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 ... @@ -887,7 +925,7 @@ ip6_full_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node, // overlapping fragment - not allowed by RFC 8200 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); @@ -904,7 +942,8 @@ 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 && @@ -1053,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 @@ -1071,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; @@ -1160,27 +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)) { ip6_full_reass_add_trace (vm, node, rm, NULL, bi0, - HANDOFF, + 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, @@ -1308,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; @@ -1316,6 +1357,7 @@ ip6_rehash_cb (clib_bihash_kv_48_8_t * kv, void *_ctx) { ctx->failure = 1; } + return (BIHASH_WALK_CONTINUE); } static void @@ -1427,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; } @@ -1631,8 +1674,15 @@ show_ip6_full_reass (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "---------------------"); vlib_cli_output (vm, "Current IP6 reassemblies count: %lu\n", (long unsigned) sum_reass_n); - vlib_cli_output (vm, "Maximum configured concurrent IP6 reassemblies per " - "worker-thread: %lu\n", (long unsigned) rm->max_reass_n); + vlib_cli_output (vm, + "Maximum configured concurrent full IP6 reassemblies per worker-thread: %lu\n", + (long unsigned) rm->max_reass_n); + vlib_cli_output (vm, + "Maximum configured full IP6 reassembly timeout: %lums\n", + (long unsigned) rm->timeout_ms); + vlib_cli_output (vm, + "Maximum configured full IP6 reassembly expire walk interval: %lums\n", + (long unsigned) rm->expire_walk_interval_ms); vlib_cli_output (vm, "Buffers in use: %lu\n", (long unsigned) sum_buffers_n); return 0; @@ -1790,6 +1840,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 *