From 7fe51f3e3e80ed6ffe989df1c6963527166afc25 Mon Sep 17 00:00:00 2001 From: Pierre Pfister Date: Wed, 20 Sep 2017 08:48:36 +0200 Subject: tcp: add option to punt traffic Until now, if the stack didn't find a connection for a packet, it sent back a reset. With the punt option enabled, packets are now enqueued to error-punt where they can be handed off to the host os. Change-Id: I12dea8694b8bd24c92b0d601412928aa7b8046cb Signed-off-by: Florin Coras Signed-off-by: Pierre Pfister --- src/vnet/ip/punt.c | 66 +++++++++++++++++++++++++++++----------------- src/vnet/tcp/tcp.c | 33 +++++++++++++++++++++++ src/vnet/tcp/tcp.h | 5 ++++ src/vnet/tcp/tcp_error.def | 3 ++- src/vnet/tcp/tcp_input.c | 22 ++++++++++++---- 5 files changed, 99 insertions(+), 30 deletions(-) (limited to 'src/vnet') diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c index 1ea32fa0c78..0869954c283 100644 --- a/src/vnet/ip/punt.c +++ b/src/vnet/ip/punt.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -613,16 +614,15 @@ vnet_punt_socket_del (vlib_main_t * vm, bool is_ip4, u8 l4_protocol, u16 port) * @brief Request IP traffic punt to the local TCP/IP stack. * * @em Note - * - UDP is the only protocol supported in the current implementation - * - When requesting UDP punt port number(s) must be specified - * - All TCP traffic is currently punted to the host by default + * - UDP and TCP are the only protocols supported in the current implementation * * @param vm vlib_main_t corresponding to the current thread * @param ipv IP protcol version. * 4 - IPv4, 6 - IPv6, ~0 for both IPv6 and IPv4 * @param protocol 8-bits L4 protocol value - * Only value of 17 (UDP) is currently supported - * @param port 16-bits L4 (TCP/IP) port number when applicable + * UDP is 17 + * TCP is 1 + * @param port 16-bits L4 (TCP/IP) port number when applicable (UDP only) * * @returns 0 on success, non-zero value otherwise */ @@ -630,28 +630,42 @@ clib_error_t * vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, bool is_add) { + /* For now we only support UDP punt */ - if (protocol != IP_PROTOCOL_UDP) + if (protocol != IP_PROTOCOL_UDP && protocol != IP_PROTOCOL_TCP) return clib_error_return (0, - "only UDP protocol (%d) is supported, got %d", - IP_PROTOCOL_UDP, protocol); + "only UDP (%d) and TCP (%d) protocols are supported, got %d", + IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, protocol); if (ipv != (u8) ~ 0 && ipv != 4 && ipv != 6) return clib_error_return (0, "IP version must be 4 or 6, got %d", ipv); if (port == (u16) ~ 0) { - if (ipv == 4 || ipv == (u8) ~ 0) - udp_punt_unknown (vm, 1, is_add); + if ((ipv == 4) || (ipv == (u8) ~ 0)) + { + if (protocol == IP_PROTOCOL_UDP) + udp_punt_unknown (vm, 1, is_add); + else if (protocol == IP_PROTOCOL_TCP) + tcp_punt_unknown (vm, 1, is_add); + } - if (ipv == 6 || ipv == (u8) ~ 0) - udp_punt_unknown (vm, 0, is_add); + if ((ipv == 6) || (ipv == (u8) ~ 0)) + { + if (protocol == IP_PROTOCOL_UDP) + udp_punt_unknown (vm, 0, is_add); + else if (protocol == IP_PROTOCOL_TCP) + tcp_punt_unknown (vm, 0, is_add); + } return 0; } else if (is_add) { + if (protocol == IP_PROTOCOL_TCP) + return clib_error_return (0, "punt TCP ports is not supported yet"); + if (ipv == 4 || ipv == (u8) ~ 0) udp_register_dst_port (vm, port, udp4_punt_node.index, 1); @@ -665,32 +679,36 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, } static clib_error_t * -udp_punt_cli (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +punt_cli (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) { - u32 udp_port; + u32 port; bool is_add = true; + u32 protocol = ~0; clib_error_t *error; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "del")) is_add = false; - if (unformat (input, "all")) + else if (unformat (input, "all")) { /* punt both IPv6 and IPv4 when used in CLI */ - error = vnet_punt_add_del (vm, ~0, IP_PROTOCOL_UDP, ~0, is_add); + error = vnet_punt_add_del (vm, ~0, protocol, ~0, is_add); if (error) clib_error_report (error); } - else if (unformat (input, "%d", &udp_port)) + else if (unformat (input, "%d", &port)) { /* punt both IPv6 and IPv4 when used in CLI */ - error = - vnet_punt_add_del (vm, ~0, IP_PROTOCOL_UDP, udp_port, is_add); + error = vnet_punt_add_del (vm, ~0, protocol, port, is_add); if (error) clib_error_report (error); } + else if (unformat (input, "udp")) + protocol = IP_PROTOCOL_UDP; + else if (unformat (input, "tcp")) + protocol = IP_PROTOCOL_TCP; } return 0; @@ -717,10 +735,10 @@ udp_punt_cli (vlib_main_t * vm, * @endparblock ?*/ /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (punt_udp_command, static) = { - .path = "set punt udp", - .short_help = "set punt udp [del] ", - .function = udp_punt_cli, +VLIB_CLI_COMMAND (punt_command, static) = { + .path = "set punt", + .short_help = "set punt [udp|tcp] [del] ", + .function = punt_cli, }; /* *INDENT-ON* */ diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index f779428fbaf..f457ef7e536 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -1398,6 +1398,16 @@ vnet_tcp_enable_disable (vlib_main_t * vm, u8 is_en) return 0; } +void +tcp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add) +{ + tcp_main_t *tm = &tcp_main; + if (is_ip4) + tm->punt_unknown4 = is_add; + else + tm->punt_unknown6 = is_add; +} + clib_error_t * tcp_init (vlib_main_t * vm) { @@ -1893,6 +1903,29 @@ VLIB_CLI_COMMAND (tcp_replay_scoreboard_command, static) = }; /* *INDENT-ON* */ +static clib_error_t * +show_tcp_punt_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd_arg) +{ + tcp_main_t *tm = vnet_get_tcp_main (); + if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + return clib_error_return (0, "unknown input `%U'", format_unformat_error, + input); + vlib_cli_output (vm, "IPv4 TCP punt: %s", + tm->punt_unknown4 ? "enabled" : "disabled"); + vlib_cli_output (vm, "IPv6 TCP punt: %s", + tm->punt_unknown6 ? "enabled" : "disabled"); + return 0; +} +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_tcp_punt_command, static) = +{ + .path = "show tcp punt", + .short_help = "show tcp punt", + .function = show_tcp_punt_fn, +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h index bb8091af84f..259dbca1519 100644 --- a/src/vnet/tcp/tcp.h +++ b/src/vnet/tcp/tcp.h @@ -417,6 +417,9 @@ typedef struct _tcp_main /** vlib buffer size */ u32 bytes_per_buffer; + + u8 punt_unknown4; + u8 punt_unknown6; } tcp_main_t; extern tcp_main_t tcp_main; @@ -441,6 +444,8 @@ tcp_buffer_hdr (vlib_buffer_t * b) clib_error_t *vnet_tcp_enable_disable (vlib_main_t * vm, u8 is_en); +void tcp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add); + always_inline tcp_connection_t * tcp_connection_get (u32 conn_index, u32 thread_index) { diff --git a/src/vnet/tcp/tcp_error.def b/src/vnet/tcp/tcp_error.def index 08922315c99..a179717ff13 100644 --- a/src/vnet/tcp/tcp_error.def +++ b/src/vnet/tcp/tcp_error.def @@ -39,4 +39,5 @@ tcp_error (RST_SENT, "Resets sent") tcp_error (INVALID_CONNECTION, "Invalid connection") tcp_error (NO_WND, "No window") tcp_error (CONNECTION_CLOSED, "Connection closed") -tcp_error (CREATE_EXISTS, "Connection already exists") \ No newline at end of file +tcp_error (CREATE_EXISTS, "Connection already exists") +tcp_error (PUNT, "Packets punted") \ No newline at end of file diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index 64a07070ec2..bd57eca3223 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -2869,6 +2869,7 @@ typedef enum _tcp_input_next TCP_INPUT_NEXT_SYN_SENT, TCP_INPUT_NEXT_ESTABLISHED, TCP_INPUT_NEXT_RESET, + TCP_INPUT_NEXT_PUNT, TCP_INPUT_N_NEXT } tcp_input_next_t; @@ -2878,7 +2879,8 @@ typedef enum _tcp_input_next _ (RCV_PROCESS, "tcp4-rcv-process") \ _ (SYN_SENT, "tcp4-syn-sent") \ _ (ESTABLISHED, "tcp4-established") \ - _ (RESET, "tcp4-reset") + _ (RESET, "tcp4-reset") \ + _ (PUNT, "error-punt") #define foreach_tcp6_input_next \ _ (DROP, "error-drop") \ @@ -2886,7 +2888,8 @@ typedef enum _tcp_input_next _ (RCV_PROCESS, "tcp6-rcv-process") \ _ (SYN_SENT, "tcp6-syn-sent") \ _ (ESTABLISHED, "tcp6-established") \ - _ (RESET, "tcp6-reset") + _ (RESET, "tcp6-reset") \ + _ (PUNT, "error-punt") #define filter_flags (TCP_FLAG_SYN|TCP_FLAG_ACK|TCP_FLAG_RST|TCP_FLAG_FIN) @@ -3010,9 +3013,18 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } else { - /* Send reset */ - next0 = TCP_INPUT_NEXT_RESET; - error0 = TCP_ERROR_NO_LISTENER; + if ((is_ip4 && tm->punt_unknown4) || + (!is_ip4 && tm->punt_unknown6)) + { + next0 = TCP_INPUT_NEXT_PUNT; + error0 = TCP_ERROR_PUNT; + } + else + { + /* Send reset */ + next0 = TCP_INPUT_NEXT_RESET; + error0 = TCP_ERROR_NO_LISTENER; + } } done: -- cgit 1.2.3-korg