From 01c1fa41f04fbc584165806d3f785cfbbd62cedc Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Tue, 14 Dec 2021 18:25:11 +0000 Subject: [PATCH] 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/ip.api | 24 +++++++ src/vnet/ip/ip4_forward.c | 3 +- src/vnet/ip/ip4_input.c | 1 - src/vnet/ip/ip4_input.h | 1 - src/vnet/ip/ip6_forward.c | 2 +- src/vnet/ip/ip_api.c | 24 +++++++ src/vnet/ip/ip_test.c | 18 +++++ 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 + test/Makefile | 4 +- test/test_reassembly.py | 109 ++++++++++++++++++++--------- 13 files changed, 384 insertions(+), 68 deletions(-) diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index ca1e2008e4f..cd180981773 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -836,6 +836,30 @@ autoreply define ip_reassembly_enable_disable vl_api_ip_reass_type_t type; }; +/** enable/disable full reassembly of packets aimed at our addresses */ +autoreply define ip_local_reass_enable_disable +{ + u32 client_index; + u32 context; + bool enable_ip4; + bool enable_ip6; +}; + +/** get status of local reassembly */ +define ip_local_reass_get +{ + u32 client_index; + u32 context; +}; + +define ip_local_reass_get_reply +{ + u32 context; + i32 retval; + bool ip4_is_enabled; + bool ip6_is_enabled; +}; + /** @brief Set a Path MTU value. i.e. a MTU value for a given neighbour. The neighbour can be described as attached (w/ interface and next-hop) diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index de8e8e8538f..4d0638209e5 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -61,6 +61,7 @@ #include #include #include +#include /** @brief IPv4 lookup node. @node ip4-lookup @@ -1880,7 +1881,7 @@ VLIB_REGISTER_NODE (ip4_local_node) = [IP_LOCAL_NEXT_PUNT] = "ip4-punt", [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup", [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input", - [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly", + [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-local-full-reassembly", }, }; diff --git a/src/vnet/ip/ip4_input.c b/src/vnet/ip/ip4_input.c index 3b3edf9fca7..0e8d22e188b 100644 --- a/src/vnet/ip/ip4_input.c +++ b/src/vnet/ip/ip4_input.c @@ -399,7 +399,6 @@ VLIB_REGISTER_NODE (ip4_input_node) = { [IP4_INPUT_NEXT_LOOKUP] = "ip4-lookup", [IP4_INPUT_NEXT_LOOKUP_MULTICAST] = "ip4-mfib-forward-lookup", [IP4_INPUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - [IP4_INPUT_NEXT_REASSEMBLY] = "ip4-full-reassembly", }, .format_buffer = format_ip4_header, diff --git a/src/vnet/ip/ip4_input.h b/src/vnet/ip/ip4_input.h index 53948d60266..57aef0bf77a 100644 --- a/src/vnet/ip/ip4_input.h +++ b/src/vnet/ip/ip4_input.h @@ -52,7 +52,6 @@ typedef enum IP4_INPUT_NEXT_LOOKUP, IP4_INPUT_NEXT_LOOKUP_MULTICAST, IP4_INPUT_NEXT_ICMP_ERROR, - IP4_INPUT_NEXT_REASSEMBLY, IP4_INPUT_N_NEXT, } ip4_input_next_t; diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index ce165e0e2e4..b876b6f2a78 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -1677,7 +1677,7 @@ VLIB_REGISTER_NODE (ip6_local_node) = [IP_LOCAL_NEXT_PUNT] = "ip6-punt", [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup", [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input", - [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly", + [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-local-full-reassembly", }, }; diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index b1b7ff3a7ae..3ff3a6ce5e0 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -1875,6 +1875,30 @@ void REPLY_MACRO (VL_API_IP_REASSEMBLY_ENABLE_DISABLE_REPLY); } +void +vl_api_ip_local_reass_enable_disable_t_handler ( + vl_api_ip_local_reass_enable_disable_t *mp) +{ + vl_api_ip_local_reass_enable_disable_reply_t *rmp; + int rv = 0; + + ip4_local_full_reass_enable_disable (mp->enable_ip4); + ip6_local_full_reass_enable_disable (mp->enable_ip6); + + REPLY_MACRO (VL_API_IP_LOCAL_REASS_ENABLE_DISABLE_REPLY); +} + +void +vl_api_ip_local_reass_get_t_handler (vl_api_ip_local_reass_get_t *mp) +{ + vl_api_ip_local_reass_get_reply_t *rmp; + int rv = 0; + REPLY_MACRO2 (VL_API_IP_LOCAL_REASS_GET, { + rmp->ip4_is_enabled = ip4_local_full_reass_enabled (); + rmp->ip6_is_enabled = ip6_local_full_reass_enabled (); + }); +} + static walk_rc_t send_ip_punt_redirect_details (u32 rx_sw_if_index, const ip_punt_redirect_rx_t * ipr, void *arg) diff --git a/src/vnet/ip/ip_test.c b/src/vnet/ip/ip_test.c index f87b47f8912..7c994868d87 100644 --- a/src/vnet/ip/ip_test.c +++ b/src/vnet/ip/ip_test.c @@ -1014,6 +1014,24 @@ api_ip_reassembly_enable_disable (vat_main_t *vat) return -1; } +static int +api_ip_local_reass_enable_disable (vat_main_t *vat) +{ + return -1; +} + +static int +api_ip_local_reass_get (vat_main_t *vat) +{ + return -1; +} + +static void +vl_api_ip_local_reass_get_reply_t_handler ( + vl_api_ip_local_reass_get_reply_t *mp) +{ +} + static void vl_api_ip_reassembly_get_reply_t_handler (vl_api_ip_reassembly_get_reply_t *mp) { 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 */ /* diff --git a/test/Makefile b/test/Makefile index 5616e9c3e55..3dbf00723ce 100644 --- a/test/Makefile +++ b/test/Makefile @@ -271,8 +271,8 @@ checkstyle-diff: $(PIP_INSTALL_DONE) @bash -c "source $(VENV_PATH)/bin/activate &&\ $(PYTHON_INTERP) -m pip install pycodestyle" @bash -c "source $(VENV_PATH)/bin/activate &&\ - cd $(WS_ROOT) && git diff --name-only --no-color --relative HEAD~1 ':!*.patch' | grep '.py$$' | xargs -n 1 -I XXX \ - pycodestyle --show-source --ignore=W504,E126,E241,E226,E305,E704,E741,E722 -v XXX ||\ + cd $(WS_ROOT) && git diff --name-only --no-color --relative HEAD~1 ':!*.patch' | grep '.py$$' | xargs -n 1 \ + pycodestyle --show-source --ignore=W504,E126,E241,E226,E305,E704,E741,E722 -v ||\ (echo \"*********************************************************************\" &&\ echo \"* Test framework PEP8 compliance check FAILED (checked changed files)\" &&\ echo \"*********************************************************************\" &&\ diff --git a/test/test_reassembly.py b/test/test_reassembly.py index faec5f42c30..2291c933833 100644 --- a/test/test_reassembly.py +++ b/test/test_reassembly.py @@ -8,10 +8,11 @@ from framework import VppTestCase, VppTestRunner import scapy.compat from scapy.packet import Raw from scapy.layers.l2 import Ether, GRE -from scapy.layers.inet import IP, UDP, ICMP +from scapy.layers.inet import IP, UDP, ICMP, icmptypes from scapy.layers.inet6 import HBHOptUnknown, ICMPv6ParamProblem,\ ICMPv6TimeExceeded, IPv6, IPv6ExtHdrFragment,\ - IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, PadN, ICMPv6EchoRequest + IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, PadN, ICMPv6EchoRequest,\ + ICMPv6EchoReply from framework import VppTestCase, VppTestRunner from util import ppp, ppc, fragment_rfc791, fragment_rfc8200 from vpp_gre_interface import VppGreInterface @@ -28,7 +29,7 @@ class TestIPv4Reassembly(VppTestCase): @classmethod def setUpClass(cls): - super(TestIPv4Reassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 @@ -48,11 +49,11 @@ class TestIPv4Reassembly(VppTestCase): @classmethod def tearDownClass(cls): - super(TestIPv4Reassembly, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv4Reassembly, self).setUp() + super().setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip4=True) self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, @@ -64,7 +65,9 @@ class TestIPv4Reassembly(VppTestCase): expire_walk_interval_ms=10000) def tearDown(self): - super(TestIPv4Reassembly, self).tearDown() + self.vapi.ip_reassembly_enable_disable( + sw_if_index=self.src_if.sw_if_index, enable_ip4=False) + super().tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details")) @@ -511,13 +514,31 @@ Ethernet-Payload.IPv4-Packet.IPv4-Header.Fragment-Offset; Test-case: 5737''' self.verify_capture(packets, dropped_packet_indexes) self.src_if.assert_nothing_captured() + def test_local_enable_disable(self): + """ local reassembly enabled/disable """ + self.vapi.ip_reassembly_enable_disable( + sw_if_index=self.src_if.sw_if_index, enable_ip4=False) + self.vapi.ip_local_reass_enable_disable(enable_ip4=True) + p = (Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / + IP(src=self.src_if.remote_ip4, dst=self.src_if.local_ip4) / + ICMP(id=1234, type='echo-request') / + Raw('x' * 1000)) + frags = fragment_rfc791(p, 400) + r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0] + self.assertEqual(1234, r[ICMP].id) + self.assertEqual(icmptypes[r[ICMP].type], 'echo-reply') + self.vapi.ip_local_reass_enable_disable() + + self.send_and_assert_no_replies(self.src_if, frags) + self.vapi.ip_local_reass_enable_disable(enable_ip4=True) + class TestIPv4SVReassembly(VppTestCase): """ IPv4 Shallow Virtual Reassembly """ @classmethod def setUpClass(cls): - super(TestIPv4SVReassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 @@ -531,7 +552,7 @@ class TestIPv4SVReassembly(VppTestCase): def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv4SVReassembly, self).setUp() + super().setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip4=True, type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL) @@ -548,7 +569,7 @@ class TestIPv4SVReassembly(VppTestCase): expire_walk_interval_ms=10000) def tearDown(self): - super(TestIPv4SVReassembly, self).tearDown() + super().tearDown() self.logger.debug(self.vapi.ppcli("show ip4-sv-reassembly details")) self.logger.debug(self.vapi.ppcli("show buffers")) @@ -791,7 +812,7 @@ class TestIPv4MWReassembly(VppTestCase): @classmethod def setUpClass(cls): - super(TestIPv4MWReassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces(range(cls.vpp_worker_count+1)) cls.src_if = cls.pg0 @@ -815,11 +836,11 @@ class TestIPv4MWReassembly(VppTestCase): @classmethod def tearDownClass(cls): - super(TestIPv4MWReassembly, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv4MWReassembly, self).setUp() + super().setUp() for intf in self.send_ifs: self.vapi.ip_reassembly_enable_disable( sw_if_index=intf.sw_if_index, enable_ip4=True) @@ -832,7 +853,10 @@ class TestIPv4MWReassembly(VppTestCase): expire_walk_interval_ms=10000) def tearDown(self): - super(TestIPv4MWReassembly, self).tearDown() + for intf in self.send_ifs: + self.vapi.ip_reassembly_enable_disable( + sw_if_index=intf.sw_if_index, enable_ip4=False) + super().tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details")) @@ -968,7 +992,7 @@ class TestIPv6Reassembly(VppTestCase): @classmethod def setUpClass(cls): - super(TestIPv6Reassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 @@ -988,11 +1012,11 @@ class TestIPv6Reassembly(VppTestCase): @classmethod def tearDownClass(cls): - super(TestIPv6Reassembly, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv6Reassembly, self).setUp() + super().setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip6=True) self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, @@ -1006,7 +1030,9 @@ class TestIPv6Reassembly(VppTestCase): self.logger.debug(self.vapi.ppcli("show buffers")) def tearDown(self): - super(TestIPv6Reassembly, self).tearDown() + self.vapi.ip_reassembly_enable_disable( + sw_if_index=self.src_if.sw_if_index, enable_ip6=False) + super().tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details")) @@ -1505,6 +1531,22 @@ class TestIPv6Reassembly(VppTestCase): rx = self.send_and_expect(self.pg0, [pkt], self.pg0) self.assertNotIn(IPv6ExtHdrFragment, rx) + def test_local_enable_disable(self): + """ local reassembly enabled/disable """ + self.vapi.ip_reassembly_enable_disable( + sw_if_index=self.src_if.sw_if_index, enable_ip6=False) + self.vapi.ip_local_reass_enable_disable(enable_ip6=True) + pkt = (Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) / + IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) / + ICMPv6EchoRequest(id=1234)/Raw('X' * 1600)) + frags = fragment_rfc8200(pkt, 1, 400) + r = self.send_and_expect(self.src_if, frags, self.src_if, n_rx=1)[0] + self.assertEqual(1234, r[ICMPv6EchoReply].id) + self.vapi.ip_local_reass_enable_disable() + + self.send_and_assert_no_replies(self.src_if, frags) + self.vapi.ip_local_reass_enable_disable(enable_ip6=True) + class TestIPv6MWReassembly(VppTestCase): """ IPv6 Reassembly (multiple workers) """ @@ -1512,7 +1554,7 @@ class TestIPv6MWReassembly(VppTestCase): @classmethod def setUpClass(cls): - super(TestIPv6MWReassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces(range(cls.vpp_worker_count+1)) cls.src_if = cls.pg0 @@ -1536,11 +1578,11 @@ class TestIPv6MWReassembly(VppTestCase): @classmethod def tearDownClass(cls): - super(TestIPv6MWReassembly, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv6MWReassembly, self).setUp() + super().setUp() for intf in self.send_ifs: self.vapi.ip_reassembly_enable_disable( sw_if_index=intf.sw_if_index, enable_ip6=True) @@ -1553,7 +1595,10 @@ class TestIPv6MWReassembly(VppTestCase): expire_walk_interval_ms=1000, is_ip6=1) def tearDown(self): - super(TestIPv6MWReassembly, self).tearDown() + for intf in self.send_ifs: + self.vapi.ip_reassembly_enable_disable( + sw_if_index=intf.sw_if_index, enable_ip6=False) + super().tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip6-full-reassembly details")) @@ -1689,7 +1734,7 @@ class TestIPv6SVReassembly(VppTestCase): @classmethod def setUpClass(cls): - super(TestIPv6SVReassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 @@ -1703,7 +1748,7 @@ class TestIPv6SVReassembly(VppTestCase): def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv6SVReassembly, self).setUp() + super().setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip6=True, type=VppEnum.vl_api_ip_reass_type_t.IP_REASS_TYPE_SHALLOW_VIRTUAL) @@ -1720,7 +1765,7 @@ class TestIPv6SVReassembly(VppTestCase): expire_walk_interval_ms=10000, is_ip6=1) def tearDown(self): - super(TestIPv6SVReassembly, self).tearDown() + super().tearDown() self.logger.debug(self.vapi.ppcli("show ip6-sv-reassembly details")) self.logger.debug(self.vapi.ppcli("show buffers")) @@ -1941,7 +1986,7 @@ class TestIPv4ReassemblyLocalNode(VppTestCase): @classmethod def setUpClass(cls): - super(TestIPv4ReassemblyLocalNode, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces([0]) cls.src_dst_if = cls.pg0 @@ -1958,11 +2003,11 @@ class TestIPv4ReassemblyLocalNode(VppTestCase): @classmethod def tearDownClass(cls): - super(TestIPv4ReassemblyLocalNode, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestIPv4ReassemblyLocalNode, self).setUp() + super().setUp() self.vapi.ip_reassembly_set(timeout_ms=0, max_reassemblies=1000, max_reassembly_length=1000, expire_walk_interval_ms=10) @@ -1972,7 +2017,7 @@ class TestIPv4ReassemblyLocalNode(VppTestCase): expire_walk_interval_ms=10000) def tearDown(self): - super(TestIPv4ReassemblyLocalNode, self).tearDown() + super().tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details")) @@ -2068,7 +2113,7 @@ class TestFIFReassembly(VppTestCase): @classmethod def setUpClass(cls): - super(TestFIFReassembly, cls).setUpClass() + super().setUpClass() cls.create_pg_interfaces([0, 1]) cls.src_if = cls.pg0 @@ -2085,11 +2130,11 @@ class TestFIFReassembly(VppTestCase): @classmethod def tearDownClass(cls): - super(TestFIFReassembly, cls).tearDownClass() + super().tearDownClass() def setUp(self): """ Test setup - force timeout on existing reassemblies """ - super(TestFIFReassembly, self).setUp() + super().setUp() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.src_if.sw_if_index, enable_ip4=True, enable_ip6=True) @@ -2111,7 +2156,7 @@ class TestFIFReassembly(VppTestCase): expire_walk_interval_ms=10000, is_ip6=1) def tearDown(self): - super(TestFIFReassembly, self).tearDown() + super().tearDown() def show_commands_at_teardown(self): self.logger.debug(self.vapi.ppcli("show ip4-full-reassembly details")) -- 2.16.6