summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Popovsky (apopovsk) <apopovsk@cisco.com>2016-11-15 15:36:23 -0800
committerJohn Lo <loj@cisco.com>2016-11-16 07:24:26 +0000
commit740bcdbd2b13bef4f5c9b487ed0dcbbee6a760c9 (patch)
tree88ccaafef0c9e57d046830cb591c9450f9a1185e
parent25e26dc5136137c771715145dd5b2884060ff9eb (diff)
Add an ability to punt all unknown UDP traffic to the host
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) <apopovsk@cisco.com>
-rw-r--r--vnet/vnet/ip/punt.c64
-rw-r--r--vnet/vnet/ip/udp.h2
-rw-r--r--vnet/vnet/ip/udp_error.def1
-rw-r--r--vnet/vnet/ip/udp_local.c53
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] <all | port-num1 [port-num2 ...]>",
.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 _