X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Freass%2Fip4_full_reass.c;h=ecd2fb0e5c61361c652e236499a9a9aa27605215;hb=b2c31b685fd2cf28436ca32bc93e23eb24c74878;hp=18ac4d1b1b01694ee05cd49bf03846a7b558c205;hpb=de34c35fc73226943538149fae9dbc5cfbdc6e75;p=vpp.git diff --git a/src/vnet/ip/reass/ip4_full_reass.c b/src/vnet/ip/reass/ip4_full_reass.c index 18ac4d1b1b0..ecd2fb0e5c6 100644 --- a/src/vnet/ip/reass/ip4_full_reass.c +++ b/src/vnet/ip/reass/ip4_full_reass.c @@ -184,7 +184,10 @@ typedef struct /** Worker handoff */ u32 fq_index; u32 fq_feature_index; + u32 fq_custom_index; + // reference count for enabling/disabling feature - per interface + u32 *feature_use_refcount_per_intf; } ip4_full_reass_main_t; extern ip4_full_reass_main_t ip4_full_reass_main; @@ -201,6 +204,13 @@ typedef enum IP4_FULL_REASS_N_NEXT, } ip4_full_reass_next_t; +typedef enum +{ + NORMAL, + FEATURE, + CUSTOM +} ip4_full_reass_node_type_t; + typedef enum { RANGE_NEW, @@ -233,10 +243,13 @@ typedef struct u32 fragment_first; u32 fragment_last; u32 total_data_len; + bool is_after_handoff; + ip4_header_t ip4_header; } ip4_full_reass_trace_t; extern vlib_node_registration_t ip4_full_reass_node; extern vlib_node_registration_t ip4_full_reass_node_feature; +extern vlib_node_registration_t ip4_full_reass_node_custom; static void ip4_full_reass_trace_details (vlib_main_t * vm, u32 bi, @@ -272,7 +285,16 @@ format_ip4_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_ip4_header, &t->ip4_header, + sizeof (t->ip4_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, @@ -320,7 +342,18 @@ ip4_full_reass_add_trace (vlib_main_t * vm, vlib_node_runtime_t * node, { 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; + } ip4_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->ip4_header, vlib_buffer_get_current (b), + clib_min (sizeof (t->ip4_header), b->current_length)); + } if (reass) { t->reass_id = reass->id; @@ -431,6 +464,7 @@ ip4_full_reass_drop_all (vlib_main_t * vm, vlib_node_runtime_t * node, { vlib_buffer_free (vm, to_free, vec_len (to_free)); } + vec_free (to_free); } always_inline void @@ -456,18 +490,17 @@ again: reass = NULL; now = vlib_time_now (vm); - if (!clib_bihash_search_16_8 - (&rm->hash, (clib_bihash_kv_16_8_t *) kv, (clib_bihash_kv_16_8_t *) kv)) + if (!clib_bihash_search_16_8 (&rm->hash, &kv->kv, &kv->kv)) { + if (vm->thread_index != kv->v.memory_owner_thread_index) + { + *do_handoff = 1; + return NULL; + } reass = pool_elt_at_index (rm->per_thread_data [kv->v.memory_owner_thread_index].pool, kv->v.reass_index); - if (vm->thread_index != reass->memory_owner_thread_index) - { - *do_handoff = 1; - return reass; - } if (now > reass->last_heard + rm->timeout) { @@ -499,14 +532,13 @@ again: ++rt->reass_n; } - reass->key.as_u64[0] = ((clib_bihash_kv_16_8_t *) kv)->key[0]; - reass->key.as_u64[1] = ((clib_bihash_kv_16_8_t *) kv)->key[1]; + reass->key.as_u64[0] = kv->kv.key[0]; + reass->key.as_u64[1] = kv->kv.key[1]; kv->v.reass_index = (reass - rt->pool); kv->v.memory_owner_thread_index = vm->thread_index; reass->last_heard = now; - int rv = - clib_bihash_add_del_16_8 (&rm->hash, (clib_bihash_kv_16_8_t *) kv, 2); + int rv = clib_bihash_add_del_16_8 (&rm->hash, &kv->kv, 2); if (rv) { ip4_full_reass_free_ctx (rt, reass); @@ -524,7 +556,7 @@ ip4_full_reass_finalize (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_t * reass, u32 * bi0, - u32 * next0, u32 * error0, bool is_custom_app) + u32 * next0, u32 * error0, bool is_custom) { vlib_buffer_t *first_b = vlib_get_buffer (vm, reass->first_bi); vlib_buffer_t *last_b = NULL; @@ -708,7 +740,7 @@ ip4_full_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node, #endif } *bi0 = reass->first_bi; - if (!is_custom_app) + if (!is_custom) { *next0 = IP4_FULL_REASS_NEXT_INPUT; } @@ -818,12 +850,11 @@ ip4_full_reass_update (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_t * reass, u32 * bi0, u32 * next0, - u32 * error0, bool is_custom_app, - u32 * handoff_thread_idx) + u32 * error0, bool is_custom, u32 * handoff_thread_idx) { vlib_buffer_t *fb = vlib_get_buffer (vm, *bi0); vnet_buffer_opaque_t *fvnb = vnet_buffer (fb); - if (is_custom_app) + if (is_custom) { // store (error_)next_index before it's overwritten reass->next_index = fvnb->ip.reass.next_index; @@ -1040,11 +1071,12 @@ ip4_full_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node, 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; rc = ip4_full_reass_finalize (vm, node, rm, rt, reass, bi0, next0, error0, - is_custom_app); - if (IP4_REASS_RC_OK == rc - && reass->memory_owner_thread_index != reass->sendout_thread_index) + is_custom); + if (IP4_REASS_RC_OK == rc && handoff) { rc = IP4_REASS_RC_HANDOFF; } @@ -1070,8 +1102,7 @@ ip4_full_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node, always_inline uword ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, bool is_feature, - bool is_custom_app) + vlib_frame_t * frame, ip4_full_reass_node_type_t type) { u32 *from = vlib_frame_vector_args (frame); u32 n_left_from, n_left_to_next, *to_next, next_index; @@ -1099,7 +1130,7 @@ ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (!ip4_get_fragment_more (ip0) && !ip4_get_fragment_offset (ip0)) { // this is a whole packet - no fragmentation - if (!is_custom_app) + if (CUSTOM != type) { next0 = IP4_FULL_REASS_NEXT_INPUT; } @@ -1154,7 +1185,7 @@ ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, u32 handoff_thread_idx; switch (ip4_full_reass_update (vm, node, rm, rt, reass, &bi0, &next0, - &error0, is_custom_app, &handoff_thread_idx)) + &error0, CUSTOM == type, &handoff_thread_idx)) { case IP4_REASS_RC_OK: /* nothing to do here */ @@ -1199,13 +1230,20 @@ ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, packet_enqueue: - b0->error = node->errors[error0]; if (bi0 != ~0) { 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)) @@ -1216,9 +1254,8 @@ ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, reass.owner_thread_index); } } - else if (is_feature && IP4_ERROR_NONE == error0) + else if (FEATURE == type && IP4_ERROR_NONE == error0) { - b0 = vlib_get_buffer (vm, bi0); vnet_feature_next (&next0, b0); } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, @@ -1249,8 +1286,7 @@ VLIB_NODE_FN (ip4_full_reass_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_full_reass_inline (vm, node, frame, false /* is_feature */ , - false /* is_custom_app */ ); + return ip4_full_reass_inline (vm, node, frame, NORMAL); } /* *INDENT-OFF* */ @@ -1275,8 +1311,7 @@ VLIB_NODE_FN (ip4_full_reass_node_feature) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_full_reass_inline (vm, node, frame, true /* is_feature */ , - false /* is_custom_app */ ); + return ip4_full_reass_inline (vm, node, frame, FEATURE); } /* *INDENT-OFF* */ @@ -1306,7 +1341,49 @@ VNET_FEATURE_INIT (ip4_full_reass_feature, static) = { }; /* *INDENT-ON* */ +VLIB_NODE_FN (ip4_full_reass_node_custom) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return ip4_full_reass_inline (vm, node, frame, CUSTOM); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (ip4_full_reass_node_custom) = { + .name = "ip4-full-reassembly-custom", + .vector_size = sizeof (u32), + .format_trace = format_ip4_full_reass_trace, + .n_errors = ARRAY_LEN (ip4_full_reass_error_strings), + .error_strings = ip4_full_reass_error_strings, + .n_next_nodes = IP4_FULL_REASS_N_NEXT, + .next_nodes = + { + [IP4_FULL_REASS_NEXT_INPUT] = "ip4-input", + [IP4_FULL_REASS_NEXT_DROP] = "ip4-drop", + [IP4_FULL_REASS_NEXT_HANDOFF] = "ip4-full-reass-custom-hoff", + }, +}; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +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, +}; + +/* *INDENT-ON* */ + #ifndef CLIB_MARCH_VARIANT +uword +ip4_full_reass_custom_register_next_node (uword node_index) +{ + return vlib_node_add_next (vlib_get_main (), + ip4_full_reass_node_custom.index, node_index); +} + always_inline u32 ip4_full_reass_get_nbuckets () { @@ -1337,7 +1414,7 @@ typedef struct } ip4_rehash_cb_ctx; #ifndef CLIB_MARCH_VARIANT -static void +static int ip4_rehash_cb (clib_bihash_kv_16_8_t * kv, void *_ctx) { ip4_rehash_cb_ctx *ctx = _ctx; @@ -1345,6 +1422,7 @@ ip4_rehash_cb (clib_bihash_kv_16_8_t * kv, void *_ctx) { ctx->failure = 1; } + return (BIHASH_WALK_CONTINUE); } static void @@ -1446,7 +1524,10 @@ ip4_full_reass_init_function (vlib_main_t * vm) rm->fq_index = vlib_frame_queue_main_init (ip4_full_reass_node.index, 0); rm->fq_feature_index = vlib_frame_queue_main_init (ip4_full_reass_node_feature.index, 0); + rm->fq_custom_index = + vlib_frame_queue_main_init (ip4_full_reass_node_custom.index, 0); + rm->feature_use_refcount_per_intf = NULL; return error; } @@ -1495,13 +1576,13 @@ ip4_full_reass_walk_expired (vlib_main_t * vm, vec_reset_length (pool_indexes_to_free); /* *INDENT-OFF* */ - pool_foreach_index (index, rt->pool, ({ + pool_foreach_index (index, rt->pool) { reass = pool_elt_at_index (rt->pool, index); if (now > reass->last_heard + rm->timeout) { vec_add1 (pool_indexes_to_free, index); } - })); + } /* *INDENT-ON* */ int *i; /* *INDENT-OFF* */ @@ -1615,20 +1696,26 @@ show_ip4_reass (vlib_main_t * vm, if (details) { /* *INDENT-OFF* */ - pool_foreach (reass, rt->pool, { + pool_foreach (reass, rt->pool) { vlib_cli_output (vm, "%U", format_ip4_reass, vm, reass); - }); + } /* *INDENT-ON* */ } sum_reass_n += rt->reass_n; clib_spinlock_unlock (&rt->lock); } vlib_cli_output (vm, "---------------------"); - vlib_cli_output (vm, "Current IP4 reassemblies count: %lu\n", + vlib_cli_output (vm, "Current full IP4 reassemblies count: %lu\n", (long unsigned) sum_reass_n); vlib_cli_output (vm, - "Maximum configured concurrent IP4 reassemblies per worker-thread: %lu\n", + "Maximum configured concurrent full IP4 reassemblies per worker-thread: %lu\n", (long unsigned) rm->max_reass_n); + vlib_cli_output (vm, + "Maximum configured full IP4 reassembly timeout: %lums\n", + (long unsigned) rm->timeout_ms); + vlib_cli_output (vm, + "Maximum configured full IP4 reassembly expire walk interval: %lums\n", + (long unsigned) rm->expire_walk_interval_ms); return 0; } @@ -1692,7 +1779,8 @@ format_ip4_full_reass_handoff_trace (u8 * s, va_list * args) always_inline uword ip4_full_reass_handoff_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, bool is_feature) + vlib_frame_t * frame, + ip4_full_reass_node_type_t type) { ip4_full_reass_main_t *rm = &ip4_full_reass_main; @@ -1708,7 +1796,21 @@ ip4_full_reass_handoff_node_inline (vlib_main_t * vm, b = bufs; ti = thread_indices; - fq_index = (is_feature) ? rm->fq_feature_index : rm->fq_index; + switch (type) + { + case NORMAL: + fq_index = rm->fq_index; + break; + case FEATURE: + fq_index = rm->fq_feature_index; + break; + case CUSTOM: + fq_index = rm->fq_custom_index; + break; + default: + clib_warning ("Unexpected `type' (%d)!", type); + ASSERT (0); + } while (n_left_from > 0) { @@ -1742,8 +1844,7 @@ VLIB_NODE_FN (ip4_full_reass_handoff_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip4_full_reass_handoff_node_inline (vm, node, frame, - false /* is_feature */ ); + return ip4_full_reass_handoff_node_inline (vm, node, frame, NORMAL); } @@ -1770,8 +1871,7 @@ VLIB_NODE_FN (ip4_full_reass_feature_handoff_node) (vlib_main_t * vm, node, vlib_frame_t * frame) { - return ip4_full_reass_handoff_node_inline (vm, node, frame, - true /* is_feature */ ); + return ip4_full_reass_handoff_node_inline (vm, node, frame, FEATURE); } /* *INDENT-ON* */ @@ -1792,6 +1892,62 @@ VLIB_REGISTER_NODE (ip4_full_reass_feature_handoff_node) = { }; /* *INDENT-ON* */ +/* *INDENT-OFF* */ +VLIB_NODE_FN (ip4_full_reass_custom_handoff_node) (vlib_main_t * vm, + vlib_node_runtime_t * + node, + vlib_frame_t * frame) +{ + return ip4_full_reass_handoff_node_inline (vm, node, frame, CUSTOM); +} +/* *INDENT-ON* */ + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (ip4_full_reass_custom_handoff_node) = { + .name = "ip4-full-reass-custom-hoff", + .vector_size = sizeof (u32), + .n_errors = ARRAY_LEN(ip4_full_reass_handoff_error_strings), + .error_strings = ip4_full_reass_handoff_error_strings, + .format_trace = format_ip4_full_reass_handoff_trace, + + .n_next_nodes = 1, + + .next_nodes = { + [0] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +#ifndef CLIB_MARCH_VARIANT +int +ip4_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable) +{ + ip4_full_reass_main_t *rm = &ip4_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 ("ip4-unicast", + "ip4-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 ("ip4-unicast", + "ip4-full-reassembly-feature", + sw_if_index, 0, 0, 0); + } + return -1; +} +#endif + /* * fd.io coding-style-patch-verification: ON *