From 01c1fa41f04fbc584165806d3f785cfbbd62cedc Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Tue, 14 Dec 2021 18:25:11 +0000 Subject: ip: reassembly - add a way to disable for forus Add API to disable full reassembly of "forus" packets. Mark packets passing through ip[4|6]-local nodes with a new buffer flag and check for that flag in reassembly. Enable IP6 "forus" full reassembly by default to be consistent with existing IP4 setting. Type: improvement Change-Id: I7067792fcd4304182654237968e4c4d9293c6143 Signed-off-by: Klement Sekera --- src/vnet/ip/reass/ip4_full_reass.c | 122 ++++++++++++++++++++++++++++---- src/vnet/ip/reass/ip4_full_reass.h | 3 + src/vnet/ip/reass/ip6_full_reass.c | 139 ++++++++++++++++++++++++++++++++----- src/vnet/ip/reass/ip6_full_reass.h | 2 + 4 files changed, 236 insertions(+), 30 deletions(-) (limited to 'src/vnet/ip/reass') diff --git a/src/vnet/ip/reass/ip4_full_reass.c b/src/vnet/ip/reass/ip4_full_reass.c index 79f4673a7f5..220117278c0 100644 --- a/src/vnet/ip/reass/ip4_full_reass.c +++ b/src/vnet/ip/reass/ip4_full_reass.c @@ -183,11 +183,15 @@ typedef struct /** Worker handoff */ u32 fq_index; + u32 fq_local_index; u32 fq_feature_index; u32 fq_custom_index; // reference count for enabling/disabling feature - per interface u32 *feature_use_refcount_per_intf; + + // whether local fragmented packets are reassembled or not + int is_local_reass_enabled; } ip4_full_reass_main_t; extern ip4_full_reass_main_t ip4_full_reass_main; @@ -219,6 +223,7 @@ typedef enum RANGE_OVERLAP, FINALIZE, HANDOFF, + PASSTHROUGH, } ip4_full_reass_trace_operation_e; typedef struct @@ -329,6 +334,9 @@ format_ip4_full_reass_trace (u8 * s, va_list * args) format (s, "handoff from thread #%u to thread #%u", t->thread_id, t->thread_id_to); break; + case PASSTHROUGH: + s = format (s, "passthrough - not a fragment"); + break; } return s; } @@ -1090,8 +1098,9 @@ 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, ip4_full_reass_node_type_t type) +ip4_full_reass_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, ip4_full_reass_node_type_t type, + bool is_local) { u32 *from = vlib_frame_vector_args (frame); u32 n_left_from, n_left_to_next, *to_next, next_index; @@ -1127,8 +1136,17 @@ ip4_full_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { next0 = vnet_buffer (b0)->ip.reass.next_index; } + ip4_full_reass_add_trace (vm, node, NULL, bi0, PASSTHROUGH, 0, + ~0); + goto packet_enqueue; + } + + if (is_local && !rm->is_local_reass_enabled) + { + next0 = IP4_FULL_REASS_NEXT_DROP; 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); @@ -1269,7 +1287,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, NORMAL); + return ip4_full_reass_inline (vm, node, frame, NORMAL, false /* is_local */); } VLIB_REGISTER_NODE (ip4_full_reass_node) = { @@ -1288,11 +1306,34 @@ VLIB_REGISTER_NODE (ip4_full_reass_node) = { }, }; +VLIB_NODE_FN (ip4_local_full_reass_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return ip4_full_reass_inline (vm, node, frame, NORMAL, true /* is_local */); +} + +VLIB_REGISTER_NODE (ip4_local_full_reass_node) = { + .name = "ip4-local-full-reassembly", + .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-local-full-reassembly-handoff", + + }, +}; + 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, FEATURE); + return ip4_full_reass_inline (vm, node, frame, FEATURE, + false /* is_local */); } VLIB_REGISTER_NODE (ip4_full_reass_node_feature) = { @@ -1322,7 +1363,7 @@ 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); + return ip4_full_reass_inline (vm, node, frame, CUSTOM, false /* is_local */); } VLIB_REGISTER_NODE (ip4_full_reass_node_custom) = { @@ -1495,12 +1536,16 @@ ip4_full_reass_init_function (vlib_main_t * vm) rm->ip4_drop_idx = node->index; rm->fq_index = vlib_frame_queue_main_init (ip4_full_reass_node.index, 0); + rm->fq_local_index = + vlib_frame_queue_main_init (ip4_local_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; + rm->is_local_reass_enabled = 1; + return error; } @@ -1745,10 +1790,10 @@ 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, - ip4_full_reass_node_type_t type) +ip4_full_reass_handoff_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, + ip4_full_reass_node_type_t type, + bool is_local) { ip4_full_reass_main_t *rm = &ip4_full_reass_main; @@ -1767,7 +1812,14 @@ ip4_full_reass_handoff_node_inline (vlib_main_t * vm, switch (type) { case NORMAL: - fq_index = rm->fq_index; + if (is_local) + { + fq_index = rm->fq_local_index; + } + else + { + fq_index = rm->fq_index; + } break; case FEATURE: fq_index = rm->fq_feature_index; @@ -1777,7 +1829,6 @@ ip4_full_reass_handoff_node_inline (vlib_main_t * vm, break; default: clib_warning ("Unexpected `type' (%d)!", type); - ASSERT (0); } while (n_left_from > 0) @@ -1811,7 +1862,8 @@ 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, NORMAL); + return ip4_full_reass_handoff_node_inline (vm, node, frame, NORMAL, + false /* is_local */); } @@ -1829,13 +1881,34 @@ VLIB_REGISTER_NODE (ip4_full_reass_handoff_node) = { }, }; +VLIB_NODE_FN (ip4_local_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, NORMAL, + true /* is_local */); +} + +VLIB_REGISTER_NODE (ip4_local_full_reass_handoff_node) = { + .name = "ip4-local-full-reassembly-handoff", + .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", + }, +}; VLIB_NODE_FN (ip4_full_reass_feature_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, FEATURE); + return ip4_full_reass_handoff_node_inline (vm, node, frame, FEATURE, + false /* is_local */); } @@ -1858,7 +1931,8 @@ VLIB_NODE_FN (ip4_full_reass_custom_handoff_node) (vlib_main_t * vm, node, vlib_frame_t * frame) { - return ip4_full_reass_handoff_node_inline (vm, node, frame, CUSTOM); + return ip4_full_reass_handoff_node_inline (vm, node, frame, CUSTOM, + false /* is_local */); } @@ -1903,6 +1977,26 @@ ip4_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable) } return -1; } + +void +ip4_local_full_reass_enable_disable (int enable) +{ + if (enable) + { + ip4_full_reass_main.is_local_reass_enabled = 1; + } + else + { + ip4_full_reass_main.is_local_reass_enabled = 0; + } +} + +int +ip4_local_full_reass_enabled () +{ + return ip4_full_reass_main.is_local_reass_enabled; +} + #endif /* diff --git a/src/vnet/ip/reass/ip4_full_reass.h b/src/vnet/ip/reass/ip4_full_reass.h index 000c80c5906..5df8107ca48 100644 --- a/src/vnet/ip/reass/ip4_full_reass.h +++ b/src/vnet/ip/reass/ip4_full_reass.h @@ -47,6 +47,9 @@ int ip4_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable); uword ip4_full_reass_custom_register_next_node (uword node_index); + +void ip4_local_full_reass_enable_disable (int enable); +int ip4_local_full_reass_enabled (); #endif /* __included_ip4_full_reass_h__ */ /* diff --git a/src/vnet/ip/reass/ip6_full_reass.c b/src/vnet/ip/reass/ip6_full_reass.c index 12cacfc2f33..1bcb6bd0f20 100644 --- a/src/vnet/ip/reass/ip6_full_reass.c +++ b/src/vnet/ip/reass/ip6_full_reass.c @@ -164,10 +164,14 @@ typedef struct /** Worker handoff */ u32 fq_index; + u32 fq_local_index; u32 fq_feature_index; // reference count for enabling/disabling feature - per interface u32 *feature_use_refcount_per_intf; + + // whether local fragmented packets are reassembled or not + int is_local_reass_enabled; } ip6_full_reass_main_t; extern ip6_full_reass_main_t ip6_full_reass_main; @@ -194,6 +198,7 @@ typedef enum ICMP_ERROR_FL_NOT_MULT_8, FINALIZE, HANDOFF, + PASSTHROUGH, } ip6_full_reass_trace_operation_e; typedef struct @@ -306,6 +311,9 @@ format_ip6_full_reass_trace (u8 * s, va_list * args) format (s, "handoff from thread #%u to thread #%u", t->thread_id, t->thread_id_to); break; + case PASSTHROUGH: + s = format (s, "passthrough - not a fragment"); + break; } return s; } @@ -1084,10 +1092,9 @@ ip6_full_reass_verify_packet_size_lt_64k (vlib_main_t * vm, } always_inline uword -ip6_full_reassembly_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, bool is_feature, - bool is_custom_app) +ip6_full_reassembly_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, bool is_feature, + bool is_custom_app, bool is_local) { u32 *from = vlib_frame_vector_args (frame); u32 n_left_from, n_left_to_next, *to_next, next_index; @@ -1121,6 +1128,13 @@ ip6_full_reassembly_inline (vlib_main_t * vm, hdr_chain.eh[res].protocol != IP_PROTOCOL_IPV6_FRAGMENTATION) { // this is a mangled packet - no fragmentation + next0 = IP6_FULL_REASSEMBLY_NEXT_DROP; + ip6_full_reass_add_trace (vm, node, NULL, bi0, NULL, PASSTHROUGH, + ~0); + goto skip_reass; + } + if (is_local && !rm->is_local_reass_enabled) + { next0 = IP6_FULL_REASSEMBLY_NEXT_DROP; goto skip_reass; } @@ -1303,8 +1317,9 @@ VLIB_NODE_FN (ip6_full_reass_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */ , - false /* is_custom_app */ ); + return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */, + false /* is_custom_app */, + false /* is_local */); } VLIB_REGISTER_NODE (ip6_full_reass_node) = { @@ -1323,12 +1338,37 @@ VLIB_REGISTER_NODE (ip6_full_reass_node) = { }, }; +VLIB_NODE_FN (ip6_local_full_reass_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */, + false /* is_custom_app */, + true /* is_local */); +} + +VLIB_REGISTER_NODE (ip6_local_full_reass_node) = { + .name = "ip6-local-full-reassembly", + .vector_size = sizeof (u32), + .format_trace = format_ip6_full_reass_trace, + .n_errors = ARRAY_LEN (ip6_full_reassembly_error_strings), + .error_strings = ip6_full_reassembly_error_strings, + .n_next_nodes = IP6_FULL_REASSEMBLY_N_NEXT, + .next_nodes = + { + [IP6_FULL_REASSEMBLY_NEXT_INPUT] = "ip6-input", + [IP6_FULL_REASSEMBLY_NEXT_DROP] = "ip6-drop", + [IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR] = "ip6-icmp-error", + [IP6_FULL_REASSEMBLY_NEXT_HANDOFF] = "ip6-local-full-reassembly-handoff", + }, +}; + VLIB_NODE_FN (ip6_full_reass_node_feature) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip6_full_reassembly_inline (vm, node, frame, true /* is_feature */ , - false /* is_custom_app */ ); + return ip6_full_reassembly_inline (vm, node, frame, true /* is_feature */, + false /* is_custom_app */, + false /* is_local */); } VLIB_REGISTER_NODE (ip6_full_reass_node_feature) = { @@ -1500,9 +1540,12 @@ ip6_full_reass_init_function (vlib_main_t * vm) if ((error = vlib_call_init_function (vm, ip_main_init))) return error; ip6_register_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION, - ip6_full_reass_node.index); + ip6_local_full_reass_node.index); + rm->is_local_reass_enabled = 1; rm->fq_index = vlib_frame_queue_main_init (ip6_full_reass_node.index, 0); + rm->fq_local_index = + vlib_frame_queue_main_init (ip6_local_full_reass_node.index, 0); rm->fq_feature_index = vlib_frame_queue_main_init (ip6_full_reass_node_feature.index, 0); @@ -1777,9 +1820,9 @@ format_ip6_full_reassembly_handoff_trace (u8 * s, va_list * args) } always_inline uword -ip6_full_reassembly_handoff_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, bool is_feature) +ip6_full_reassembly_handoff_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, bool is_feature, + bool is_local) { ip6_full_reass_main_t *rm = &ip6_full_reass_main; @@ -1795,7 +1838,21 @@ ip6_full_reassembly_handoff_inline (vlib_main_t * vm, b = bufs; ti = thread_indices; - fq_index = (is_feature) ? rm->fq_feature_index : rm->fq_index; + if (is_feature) + { + fq_index = rm->fq_feature_index; + } + else + { + if (is_local) + { + fq_index = rm->fq_local_index; + } + else + { + fq_index = rm->fq_index; + } + } while (n_left_from > 0) { @@ -1828,8 +1885,8 @@ VLIB_NODE_FN (ip6_full_reassembly_handoff_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip6_full_reassembly_handoff_inline (vm, node, frame, - false /* is_feature */ ); + return ip6_full_reassembly_handoff_inline ( + vm, node, frame, false /* is_feature */, false /* is_local */); } VLIB_REGISTER_NODE (ip6_full_reassembly_handoff_node) = { @@ -1846,11 +1903,32 @@ VLIB_REGISTER_NODE (ip6_full_reassembly_handoff_node) = { }, }; +VLIB_NODE_FN (ip6_local_full_reassembly_handoff_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return ip6_full_reassembly_handoff_inline ( + vm, node, frame, false /* is_feature */, true /* is_feature */); +} + +VLIB_REGISTER_NODE (ip6_local_full_reassembly_handoff_node) = { + .name = "ip6-local-full-reassembly-handoff", + .vector_size = sizeof (u32), + .n_errors = ARRAY_LEN(ip6_full_reassembly_handoff_error_strings), + .error_strings = ip6_full_reassembly_handoff_error_strings, + .format_trace = format_ip6_full_reassembly_handoff_trace, + + .n_next_nodes = 1, + + .next_nodes = { + [0] = "error-drop", + }, +}; VLIB_NODE_FN (ip6_full_reassembly_feature_handoff_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip6_full_reassembly_handoff_inline (vm, node, frame, true /* is_feature */ ); + return ip6_full_reassembly_handoff_inline ( + vm, node, frame, true /* is_feature */, false /* is_local */); } @@ -1895,6 +1973,35 @@ ip6_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable) } return -1; } + +void +ip6_local_full_reass_enable_disable (int enable) +{ + if (enable) + { + if (!ip6_full_reass_main.is_local_reass_enabled) + { + ip6_full_reass_main.is_local_reass_enabled = 1; + ip6_register_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION, + ip6_local_full_reass_node.index); + } + } + else + { + if (ip6_full_reass_main.is_local_reass_enabled) + { + ip6_full_reass_main.is_local_reass_enabled = 0; + ip6_unregister_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION); + } + } +} + +int +ip6_local_full_reass_enabled () +{ + return ip6_full_reass_main.is_local_reass_enabled; +} + #endif /* diff --git a/src/vnet/ip/reass/ip6_full_reass.h b/src/vnet/ip/reass/ip6_full_reass.h index 546075b04b4..f66cb67d796 100644 --- a/src/vnet/ip/reass/ip6_full_reass.h +++ b/src/vnet/ip/reass/ip6_full_reass.h @@ -46,6 +46,8 @@ vnet_api_error_t ip6_full_reass_enable_disable (u32 sw_if_index, int ip6_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable); +void ip6_local_full_reass_enable_disable (int enable); +int ip6_local_full_reass_enabled (); #endif /* __included_ip6_full_reass_h */ /* -- cgit 1.2.3-korg