From 740bcdbd2b13bef4f5c9b487ed0dcbbee6a760c9 Mon Sep 17 00:00:00 2001 From: "Alexander Popovsky (apopovsk)" Date: Tue, 15 Nov 2016 15:36:23 -0800 Subject: Add an ability to punt all unknown UDP traffic to the host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default, VPP replies with ICMP error: port unreachable when receives an ‘unknown’ UDP (destination port with no registered listener) packet. An existing punt() API is extended to accept ALL (~0) as a L4 port number and if used redirects all ‘unknown’ UDP packets to the host. New ‘all’ option is added to the “set punt udp” CLI as well. Change-Id: I444fc5e32ffa3f0f085bb17708bf32b883ba09df Signed-off-by: Alexander Popovsky (apopovsk) --- vnet/vnet/ip/punt.c | 64 +++++++++++++++++++++++++++------------------- vnet/vnet/ip/udp.h | 2 ++ vnet/vnet/ip/udp_error.def | 1 + vnet/vnet/ip/udp_local.c | 53 +++++++++++++++++++++++++++++++++----- 4 files changed, 88 insertions(+), 32 deletions(-) diff --git a/vnet/vnet/ip/punt.c b/vnet/vnet/ip/punt.c index 188d03a82cc..30d3deb6fa5 100644 --- a/vnet/vnet/ip/punt.c +++ b/vnet/vnet/ip/punt.c @@ -219,38 +219,39 @@ clib_error_t * vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, int is_add) { - /* For now we only support adding specific UDP port punt */ - { - if (!is_add) - return clib_error_return (0, "punt delete is not supported yet"); + /* For now we only support UDP punt */ + if (protocol != IP_PROTOCOL_UDP) + return clib_error_return (0, + "only UDP protocol (%d) is supported, got %d", + IP_PROTOCOL_UDP, protocol); - if (protocol != IP_PROTOCOL_UDP) - return clib_error_return (0, - "only UDP protocol (%d) is supported, got %d", - IP_PROTOCOL_UDP, 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) - return clib_error_return (0, "TCP/UDP port must be specified"); - } + if (port == (u16) ~ 0) + { + if (ipv == 4 || ipv == (u8) ~ 0) + udp_punt_unknown (vm, 1, is_add); + + if (ipv == 6 || ipv == (u8) ~ 0) + udp_punt_unknown (vm, 0, is_add); - if (ipv != (u8) ~ 0) + return 0; + } + + else if (is_add) { - if (ipv == 4) + if (ipv == 4 || ipv == (u8) ~ 0) udp_register_dst_port (vm, port, udp4_punt_node.index, 1); - else if (ipv == 6) + + if (ipv == 6 || ipv == (u8) ~ 0) udp_register_dst_port (vm, port, udp6_punt_node.index, 0); - else - return clib_error_return (0, "IP version must be 4 or 6, got %d", - ipv); - } - else - { - udp_register_dst_port (vm, port, udp4_punt_node.index, 1); - udp_register_dst_port (vm, port, udp6_punt_node.index, 0); - } - return 0; + return 0; + } + else + return clib_error_return (0, "punt delete is not supported yet"); } static clib_error_t * @@ -265,6 +266,13 @@ udp_punt_cli (vlib_main_t * vm, { if (unformat (input, "del")) is_add = 0; + 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); + if (error) + clib_error_report (error); + } else if (unformat (input, "%d", &udp_port)) { /* punt both IPv6 and IPv4 when used in CLI */ @@ -284,7 +292,6 @@ udp_punt_cli (vlib_main_t * vm, * * @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 * * @cliexpar @@ -292,12 +299,17 @@ udp_punt_cli (vlib_main_t * vm, * Example of how to request NTP traffic to be punted * @cliexcmd{set punt udp 125} * + * Example of how to request all 'unknown' UDP traffic to be punted + * @cliexcmd{set punt udp all} + * + * Example of how to stop all 'unknown' UDP traffic to be punted + * @cliexcmd{set punt udp del all} * @endparblock ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (punt_udp_command, static) = { .path = "set punt udp", - .short_help = "set punt udp [del] port-num1 [port-num2 ...]", + .short_help = "set punt udp [del] ", .function = udp_punt_cli, }; /* *INDENT-ON* */ diff --git a/vnet/vnet/ip/udp.h b/vnet/vnet/ip/udp.h index 1845fa74a46..4de30f1d16f 100644 --- a/vnet/vnet/ip/udp.h +++ b/vnet/vnet/ip/udp.h @@ -114,6 +114,8 @@ void udp_register_dst_port (vlib_main_t * vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4); +void udp_punt_unknown(vlib_main_t * vm, u8 is_ip4, u8 is_add); + always_inline void ip_udp_fixup_one (vlib_main_t * vm, vlib_buffer_t * b0, diff --git a/vnet/vnet/ip/udp_error.def b/vnet/vnet/ip/udp_error.def index 311d20684c5..bfdae0acc77 100644 --- a/vnet/vnet/ip/udp_error.def +++ b/vnet/vnet/ip/udp_error.def @@ -18,3 +18,4 @@ udp_error (NONE, "no error") udp_error (NO_LISTENER, "no listener for dst port") udp_error (LENGTH_ERROR, "UDP packets with length errors") +udp_error (PUNT, "no listener punt") diff --git a/vnet/vnet/ip/udp_local.c b/vnet/vnet/ip/udp_local.c index 76766308df9..e4f64a5efe6 100644 --- a/vnet/vnet/ip/udp_local.c +++ b/vnet/vnet/ip/udp_local.c @@ -59,6 +59,7 @@ typedef struct { /* Sparse vector mapping udp dst_port in network byte order to next index. */ u16 * next_by_dst_port; + u8 punt_unknown; } udp_input_runtime_t; vlib_node_registration_t udp4_input_node; @@ -75,6 +76,7 @@ udp46_input_inline (vlib_main_t * vm, : (void *) vlib_node_get_runtime_data (vm, udp6_input_node.index); __attribute__((unused)) u32 n_left_from, next_index, * from, * to_next; word n_no_listener = 0; + u8 punt_unknown = rt->punt_unknown; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -185,19 +187,25 @@ udp46_input_inline (vlib_main_t * vm, // ip packet header vlib_buffer_advance (b0, - (word)advance0); - if (is_ip4) + if (PREDICT_FALSE(punt_unknown)) + { + b0->error = node->errors[UDP_ERROR_PUNT]; + next0 = UDP_INPUT_NEXT_PUNT; + } + else if (is_ip4) { icmp4_error_set_vnet_buffer(b0, ICMP4_destination_unreachable, ICMP4_destination_unreachable_port_unreachable, 0); next0 = UDP_INPUT_NEXT_ICMP4_ERROR; + n_no_listener ++; } else { icmp6_error_set_vnet_buffer(b0, ICMP6_destination_unreachable, ICMP6_destination_unreachable_port_unreachable, 0); next0 = UDP_INPUT_NEXT_ICMP6_ERROR; + n_no_listener ++; } - n_no_listener ++; } else { @@ -212,19 +220,25 @@ udp46_input_inline (vlib_main_t * vm, // ip packet header vlib_buffer_advance (b1, - (word)advance1); - if (is_ip4) + if (PREDICT_FALSE(punt_unknown)) + { + b1->error = node->errors[UDP_ERROR_PUNT]; + next1 = UDP_INPUT_NEXT_PUNT; + } + else if (is_ip4) { icmp4_error_set_vnet_buffer(b1, ICMP4_destination_unreachable, ICMP4_destination_unreachable_port_unreachable, 0); next1 = UDP_INPUT_NEXT_ICMP4_ERROR; + n_no_listener ++; } else { icmp6_error_set_vnet_buffer(b1, ICMP6_destination_unreachable, ICMP6_destination_unreachable_port_unreachable, 0); next1 = UDP_INPUT_NEXT_ICMP6_ERROR; + n_no_listener ++; } - n_no_listener ++; } else { @@ -309,19 +323,25 @@ udp46_input_inline (vlib_main_t * vm, // ip packet header vlib_buffer_advance (b0, - (word)advance0); - if (is_ip4) + if (PREDICT_FALSE(punt_unknown)) + { + b0->error = node->errors[UDP_ERROR_PUNT]; + next0 = UDP_INPUT_NEXT_PUNT; + } + else if (is_ip4) { icmp4_error_set_vnet_buffer(b0, ICMP4_destination_unreachable, ICMP4_destination_unreachable_port_unreachable, 0); next0 = UDP_INPUT_NEXT_ICMP4_ERROR; + n_no_listener ++; } else { icmp6_error_set_vnet_buffer(b0, ICMP6_destination_unreachable, ICMP6_destination_unreachable_port_unreachable, 0); next0 = UDP_INPUT_NEXT_ICMP6_ERROR; + n_no_listener ++; } - n_no_listener ++; } else { @@ -492,6 +512,23 @@ udp_register_dst_port (vlib_main_t * vm, n[0] = pi->next_index; } +void +udp_punt_unknown(vlib_main_t * vm, u8 is_ip4, u8 is_add) +{ + udp_input_runtime_t * rt; + + { + clib_error_t * error = vlib_call_init_function (vm, udp_local_init); + if (error) + clib_error_report (error); + } + + rt = vlib_node_get_runtime_data + (vm, is_ip4 ? udp4_input_node.index: udp6_input_node.index); + + rt->punt_unknown = is_add; +} + /* Parse a UDP header. */ uword unformat_udp_header (unformat_input_t * input, va_list * args) { @@ -560,6 +597,8 @@ clib_error_t * udp_local_init (vlib_main_t * vm) (/* elt bytes */ sizeof (rt->next_by_dst_port[0]), /* bits in index */ BITS (((udp_header_t *) 0)->dst_port)); + rt->punt_unknown = 0; + #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 1 /* is_ip4 */); foreach_udp4_dst_port #undef _ @@ -570,6 +609,8 @@ clib_error_t * udp_local_init (vlib_main_t * vm) (/* elt bytes */ sizeof (rt->next_by_dst_port[0]), /* bits in index */ BITS (((udp_header_t *) 0)->dst_port)); + rt->punt_unknown = 0; + #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 0 /* is_ip4 */); foreach_udp6_dst_port #undef _ -- cgit 1.2.3-korg