VPP-1506: dump local punts and registered punt sockets
Change-Id: If7835e9b80ec9402404bfc8d271eb11a10ef992b
Signed-off-by: Pavel Kotucek <pavel.kotucek@pantheon.tech>
diff --git a/src/vnet/ip/punt.api b/src/vnet/ip/punt.api
index 4477e5c..c8b222a 100644
--- a/src/vnet/ip/punt.api
+++ b/src/vnet/ip/punt.api
@@ -13,56 +13,85 @@
* limitations under the License.
*/
-option version = "1.0.0";
+option version = "2.0.0";
+
+/** \brief Punt definition
+ @param ipv - L3 protocol 4 - IPv4, 6 - IPv6, ~0 - All
+ @param l4_protocol - L4 protocol to be punted
+ @param l4_port - TCP/UDP port to be punted
+*/
+typeonly define punt
+{
+ u8 ipv;
+ u8 l4_protocol;
+ u16 l4_port;
+};
/** \brief Punt traffic to the host
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_add - add punt if non-zero, else delete
- @param ipv - L3 protocol 4 - IPv4, 6 - IPv6, ~0 - All
- @param l4_protocol - L4 protocol to be punted, only UDP (0x11) is supported
- @param l4_port - TCP/UDP port to be punted
+ @param punt - punt definition, only UDP (0x11) is supported
*/
-autoreply define punt {
+autoreply define set_punt {
u32 client_index;
u32 context;
u8 is_add;
- u8 ipv;
- u8 l4_protocol;
- u16 l4_port;
+ vl_api_punt_t punt;
+};
+
+define punt_dump
+{
+ u32 client_index;
+ u32 context;
+ u8 is_ipv6;
+};
+
+define punt_details
+{
+ u32 context;
+ vl_api_punt_t punt;
};
/** \brief Punt traffic to the host via socket
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param header_version - expected meta data header version (currently 1)
- @param is_ip4 - L3 protocol 1 - IPv4, 0 - IPv6
- @param l4_protocol - L4 protocol to be punted, only UDP (0x11) is supported
- @param l4_port - TCP/UDP port to be punted
+ @param punt - punt definition
*/
define punt_socket_register {
u32 client_index;
u32 context;
u32 header_version;
- u8 is_ip4;
- u8 l4_protocol;
- u16 l4_port;
+ vl_api_punt_t punt;
u8 pathname[108]; /* Linux sun_path defined to be 108 bytes, see unix(7) */
};
define punt_socket_register_reply
{
- u32 context;
- i32 retval;
- u8 pathname[64];
+ u32 context;
+ i32 retval;
+ u8 pathname[64];
+};
+
+define punt_socket_dump
+{
+ u32 client_index;
+ u32 context;
+ u8 is_ipv6;
+};
+
+define punt_socket_details
+{
+ u32 context;
+ vl_api_punt_t punt;
+ u8 pathname[108];
};
autoreply define punt_socket_deregister {
u32 client_index;
u32 context;
- u8 is_ip4;
- u8 l4_protocol;
- u16 l4_port;
+ vl_api_punt_t punt;
};
/*
diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c
index d8c7d81..c0902f3 100644
--- a/src/vnet/ip/punt.c
+++ b/src/vnet/ip/punt.c
@@ -35,10 +35,8 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
-#include <sys/un.h>
#include <sys/uio.h>
#include <stdlib.h>
-#include <stdbool.h>
#define foreach_punt_next \
_ (PUNT4, "ip4-punt") \
@@ -261,7 +259,7 @@
return NULL;
}
-static void
+static int
punt_socket_register (bool is_ip4, u8 protocol, u16 port,
char *client_pathname)
{
@@ -270,12 +268,18 @@
punt_client_t *v = is_ip4 ? pm->clients_by_dst_port4 :
pm->clients_by_dst_port6;
+ if (strncmp (client_pathname, vnet_punt_get_server_pathname (),
+ UNIX_PATH_MAX) == 0)
+ return -1;
+
clib_memset (&c, 0, sizeof (c));
memcpy (c.caddr.sun_path, client_pathname, sizeof (c.caddr.sun_path));
c.caddr.sun_family = AF_UNIX;
c.port = port;
+ c.protocol = protocol;
n = sparse_vec_validate (v, port);
n[0] = c;
+ return 0;
}
/* $$$$ Just leaves the mapping in place for now */
@@ -424,6 +428,9 @@
if (sendmsg (pm->socket_fd, &msg, 0) < (ssize_t) l)
vlib_node_increment_counter (vm, node_index,
PUNT_ERROR_SOCKET_TX_ERROR, 1);
+ else
+ vlib_node_increment_counter (vm, node_index, PUNT_ERROR_SOCKET_TX, 1);
+
}
error:
@@ -597,17 +604,25 @@
return total_count;
}
+/* *INDENT-OFF* */
VLIB_REGISTER_NODE (punt_socket_rx_node, static) =
{
- .function = punt_socket_rx,.name = "punt-socket-rx",.type =
- VLIB_NODE_TYPE_INPUT,.state = VLIB_NODE_STATE_INTERRUPT,.vector_size =
- 1,.n_errors = PUNT_N_ERROR,.error_strings =
- punt_error_strings,.n_next_nodes = PUNT_SOCKET_RX_N_NEXT,.next_nodes =
- {
-[PUNT_SOCKET_RX_NEXT_INTERFACE_OUTPUT] = "interface-output",
- [PUNT_SOCKET_RX_NEXT_IP4_LOOKUP] = "ip4-lookup",
- [PUNT_SOCKET_RX_NEXT_IP6_LOOKUP] = "ip6-lookup",},.format_trace =
- format_punt_trace,};
+ .function = punt_socket_rx,
+ .name = "punt-socket-rx",
+ .type = VLIB_NODE_TYPE_INPUT,
+ .state = VLIB_NODE_STATE_INTERRUPT,
+ .vector_size = 1,
+ .n_errors = PUNT_N_ERROR,
+ .error_strings = punt_error_strings,
+ .n_next_nodes = PUNT_SOCKET_RX_N_NEXT,
+ .next_nodes = {
+ [PUNT_SOCKET_RX_NEXT_INTERFACE_OUTPUT] = "interface-output",
+ [PUNT_SOCKET_RX_NEXT_IP4_LOOKUP] = "ip4-lookup",
+ [PUNT_SOCKET_RX_NEXT_IP6_LOOKUP] = "ip6-lookup",
+ },
+ .format_trace = format_punt_trace,
+};
+/* *INDENT-ON* */
static clib_error_t *
punt_socket_read_ready (clib_file_t * uf)
@@ -645,7 +660,10 @@
return clib_error_return (0, "UDP port number required");
/* Register client */
- punt_socket_register (is_ip4, protocol, port, client_pathname);
+ if (punt_socket_register (is_ip4, protocol, port, client_pathname) < 0)
+ return clib_error_return (0,
+ "Punt socket: Invalid client path: %s",
+ client_pathname);
u32 node_index = is_ip4 ? udp4_punt_socket_node.index :
udp6_punt_socket_node.index;
@@ -748,7 +766,7 @@
punt_cli (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
- u32 port;
+ u32 port = ~0;
bool is_add = true;
u32 protocol = ~0;
clib_error_t *error = NULL;
@@ -758,25 +776,9 @@
if (unformat (input, "del"))
is_add = false;
else if (unformat (input, "all"))
- {
- /* punt both IPv6 and IPv4 when used in CLI */
- error = vnet_punt_add_del (vm, ~0, protocol, ~0, is_add);
- if (error)
- {
- clib_error_report (error);
- goto done;
- }
- }
+ ;
else if (unformat (input, "%d", &port))
- {
- /* punt both IPv6 and IPv4 when used in CLI */
- error = vnet_punt_add_del (vm, ~0, protocol, port, is_add);
- if (error)
- {
- clib_error_report (error);
- goto done;
- }
- }
+ ;
else if (unformat (input, "udp"))
protocol = IP_PROTOCOL_UDP;
else if (unformat (input, "tcp"))
@@ -788,6 +790,15 @@
goto done;
}
}
+
+ /* punt both IPv6 and IPv4 when used in CLI */
+ error = vnet_punt_add_del (vm, ~0, protocol, port, is_add);
+ if (error)
+ {
+ clib_error_report (error);
+ goto done;
+ }
+
done:
return error;
}
@@ -820,6 +831,228 @@
};
/* *INDENT-ON* */
+static clib_error_t *
+punt_socket_register_cmd (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ bool is_ipv4 = true;
+ u32 protocol = ~0;
+ u32 port = ~0;
+ u8 *socket_name = 0;
+ clib_error_t *error = NULL;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "ipv4"))
+ ;
+ else if (unformat (input, "ipv6"))
+ is_ipv4 = false;
+ else if (unformat (input, "udp"))
+ protocol = IP_PROTOCOL_UDP;
+ else if (unformat (input, "tcp"))
+ protocol = IP_PROTOCOL_TCP;
+ else if (unformat (input, "%d", &port))
+ ;
+ else if (unformat (input, "socket %s", &socket_name))
+ ;
+ else
+ {
+ error = clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, input);
+ goto done;
+ }
+ }
+
+ error =
+ vnet_punt_socket_add (vm, 1, is_ipv4, protocol, port,
+ (char *) socket_name);
+ if (error)
+ {
+ goto done;
+ }
+done:
+ return error;
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{punt socket register}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (punt_socket_register_command, static) =
+{
+ .path = "punt socket register",
+ .function = punt_socket_register_cmd,
+ .short_help = "punt socket register [ipv4|ipv6] [udp|tcp]> <all | port-num1 [port-num2 ...]> <socket>",
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+punt_socket_deregister_cmd (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ bool is_ipv4 = true;
+ u32 protocol = ~0;
+ u32 port = ~0;
+ clib_error_t *error = NULL;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "ipv4"))
+ ;
+ else if (unformat (input, "ipv6"))
+ is_ipv4 = false;
+ else if (unformat (input, "udp"))
+ protocol = IP_PROTOCOL_UDP;
+ else if (unformat (input, "tcp"))
+ protocol = IP_PROTOCOL_TCP;
+ else if (unformat (input, "%d", &port))
+ ;
+ else
+ {
+ error = clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, input);
+ goto done;
+ }
+ }
+
+ error = vnet_punt_socket_del (vm, is_ipv4, protocol, port);
+ if (error)
+ {
+ goto done;
+ }
+done:
+ return error;
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{punt socket register}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (punt_socket_deregister_command, static) =
+{
+ .path = "punt socket deregister",
+ .function = punt_socket_deregister_cmd,
+ .short_help = "punt socket deregister [ipv4|ipv6] [udp|tcp]> <all | port-num1 [port-num2 ...]>",
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+punt_socket_detail_t *
+punt_socket_entries (u8 ipv)
+{
+ punt_main_t *pm = &punt_main;
+ punt_client_t *pc;
+ punt_socket_detail_t *ps = 0;
+ bool is_valid;
+
+ punt_client_t *v = !ipv ? pm->clients_by_dst_port4 :
+ pm->clients_by_dst_port6;
+
+ vec_foreach (pc, v)
+ {
+ if (pc && pc->port != 0)
+ {
+ is_valid = false;
+ if (pc->protocol == IP_PROTOCOL_UDP)
+ {
+ is_valid = udp_is_valid_dst_port (pc->port, !ipv);
+ }
+ if (is_valid)
+ {
+ punt_socket_detail_t detail = {
+ .ipv = ipv,
+ .l4_protocol = pc->protocol,
+ .l4_port = pc->port
+ };
+ memcpy (detail.pathname, pc->caddr.sun_path,
+ sizeof (pc->caddr.sun_path));
+ vec_add1 (ps, detail);
+ }
+ }
+ }
+ return ps;
+}
+
+u8 *
+format_punt_socket (u8 * s, va_list * args)
+{
+ punt_client_t *clients = va_arg (*args, punt_client_t *);
+ u8 *is_ipv6 = va_arg (*args, u8 *);
+ punt_client_t *pc;
+ bool is_valid;
+
+ vec_foreach (pc, clients)
+ {
+ if (pc && pc->port != 0)
+ {
+ is_valid = false;
+ if (pc->protocol == IP_PROTOCOL_UDP)
+ {
+ is_valid = udp_is_valid_dst_port (pc->port, !(*is_ipv6));
+ }
+ if (is_valid)
+ {
+ s = format (s, " punt %s port %d to socket %s \n",
+ (pc->protocol == IP_PROTOCOL_UDP) ? "UDP" : "TCP",
+ pc->port, pc->caddr.sun_path);
+ }
+ }
+ }
+
+ return (s);
+}
+
+static clib_error_t *
+punt_socket_show_cmd (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ u8 is_ipv6;
+ punt_main_t *pm = &punt_main;
+ clib_error_t *error = NULL;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "ipv4"))
+ is_ipv6 = 0;
+ else if (unformat (input, "ipv6"))
+ is_ipv6 = 1;
+ else
+ {
+ error = clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, input);
+ goto done;
+ }
+ }
+
+ punt_client_t *v =
+ is_ipv6 ? pm->clients_by_dst_port6 : pm->clients_by_dst_port4;
+ vlib_cli_output (vm, "%U", format_punt_socket, v, &is_ipv6);
+
+done:
+ return (error);
+}
+
+/*?
+ *
+ * @cliexpar
+ * @cliexcmd{show punt socket ipv4}
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_punt_socket_registration_command, static) =
+{
+ .path = "show punt socket registrations",
+ .function = punt_socket_show_cmd,
+ .short_help = "show punt socket registrations [ipv4|ipv6]",
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
clib_error_t *
punt_init (vlib_main_t * vm)
{
@@ -850,7 +1083,7 @@
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "socket %s", &socket_path))
- strncpy (pm->sun_path, socket_path, 108 - 1);
+ strncpy (pm->sun_path, socket_path, UNIX_PATH_MAX - 1);
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
diff --git a/src/vnet/ip/punt.h b/src/vnet/ip/punt.h
index 4cef527..0518b2b 100644
--- a/src/vnet/ip/punt.h
+++ b/src/vnet/ip/punt.h
@@ -20,7 +20,7 @@
#ifndef included_punt_h
#define included_punt_h
-#include <sys/un.h>
+#include <linux/un.h>
#include <stdbool.h>
typedef enum
@@ -64,6 +64,7 @@
*/
typedef struct
{
+ u8 protocol;
u16 port;
struct sockaddr_un caddr;
} punt_client_t;
@@ -82,6 +83,15 @@
} punt_main_t;
extern punt_main_t punt_main;
+typedef struct punt_socket_detail_t_
+{
+ u8 ipv;
+ u8 l4_protocol;
+ u16 l4_port;
+ u8 pathname[108];
+} punt_socket_detail_t;
+
+punt_socket_detail_t *punt_socket_entries (u8 ipv);
#endif
/*
diff --git a/src/vnet/ip/punt_api.c b/src/vnet/ip/punt_api.c
index 55ab838..3ca9621 100644
--- a/src/vnet/ip/punt_api.c
+++ b/src/vnet/ip/punt_api.c
@@ -40,27 +40,35 @@
#include <vlibapi/api_helper_macros.h>
#define foreach_punt_api_msg \
-_(PUNT, punt) \
+_(SET_PUNT, set_punt) \
_(PUNT_SOCKET_REGISTER, punt_socket_register) \
-_(PUNT_SOCKET_DEREGISTER, punt_socket_deregister)
+_(PUNT_SOCKET_DEREGISTER, punt_socket_deregister) \
+_(PUNT_DUMP, punt_dump) \
+_(PUNT_SOCKET_DUMP, punt_socket_dump)
static void
-vl_api_punt_t_handler (vl_api_punt_t * mp)
+vl_api_set_punt_t_handler (vl_api_set_punt_t * mp)
{
- vl_api_punt_reply_t *rmp;
+ vl_api_set_punt_reply_t *rmp;
vlib_main_t *vm = vlib_get_main ();
int rv = 0;
clib_error_t *error;
- error = vnet_punt_add_del (vm, mp->ipv, mp->l4_protocol,
- ntohs (mp->l4_port), mp->is_add);
+ error = vnet_punt_add_del (vm, mp->punt.ipv, mp->punt.l4_protocol,
+ ntohs (mp->punt.l4_port), mp->is_add);
if (error)
{
rv = -1;
clib_error_report (error);
}
- REPLY_MACRO (VL_API_PUNT_REPLY);
+ REPLY_MACRO (VL_API_SET_PUNT_REPLY);
+}
+
+static void
+vl_api_punt_dump_t_handler (vl_api_punt_dump_t * mp)
+{
+
}
static void
@@ -72,9 +80,10 @@
clib_error_t *error;
vl_api_registration_t *reg;
- error = vnet_punt_socket_add (vm, ntohl (mp->header_version),
- mp->is_ip4, mp->l4_protocol,
- ntohs (mp->l4_port), (char *) mp->pathname);
+ error = 0;
+ vnet_punt_socket_add (vm, ntohl (mp->header_version),
+ mp->punt.ipv, mp->punt.l4_protocol,
+ ntohs (mp->punt.l4_port), (char *) mp->pathname);
if (error)
{
rv = -1;
@@ -95,6 +104,48 @@
vl_api_send_msg (reg, (u8 *) rmp);
}
+void
+send_punt_socket_details (vl_api_registration_t * reg,
+ u32 context, punt_socket_detail_t * p)
+{
+ vl_api_punt_socket_details_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ if (!mp)
+ return;
+
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_PUNT_SOCKET_DETAILS);
+ mp->context = context;
+ mp->punt.ipv = p->ipv;
+ mp->punt.l4_protocol = p->l4_protocol;
+ mp->punt.l4_port = htons (p->l4_port);
+ memcpy (mp->pathname, p->pathname, sizeof (p->pathname));
+
+ vl_api_send_msg (reg, (u8 *) mp);
+}
+
+static void
+vl_api_punt_socket_dump_t_handler (vl_api_punt_socket_dump_t * mp)
+{
+ vl_api_registration_t *reg;
+ punt_socket_detail_t *p, *ps;
+ int rv __attribute__ ((unused)) = 0;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ ps = punt_socket_entries (mp->is_ipv6);
+ /* *INDENT-OFF* */
+ vec_foreach (p, ps)
+ {
+ send_punt_socket_details (reg, mp->context, p);
+ }
+ /* *INDENT-ON* */
+ vec_free (ps);
+}
+
static void
vl_api_punt_socket_deregister_t_handler (vl_api_punt_socket_deregister_t * mp)
{
@@ -104,8 +155,8 @@
clib_error_t *error;
vl_api_registration_t *reg;
- error = vnet_punt_socket_del (vm, mp->is_ip4, mp->l4_protocol,
- ntohs (mp->l4_port));
+ error = vnet_punt_socket_del (vm, mp->punt.ipv, mp->punt.l4_protocol,
+ ntohs (mp->punt.l4_port));
if (error)
{
rv = -1;
diff --git a/src/vnet/sctp/sctp.c b/src/vnet/sctp/sctp.c
index 41548bc..85ca9b8 100644
--- a/src/vnet/sctp/sctp.c
+++ b/src/vnet/sctp/sctp.c
@@ -987,6 +987,29 @@
VLIB_INIT_FUNCTION (sctp_init);
+static clib_error_t *
+show_sctp_punt_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd_arg)
+{
+ sctp_main_t *tm = &sctp_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 UDP punt: %s",
+ tm->punt_unknown4 ? "enabled" : "disabled");
+ vlib_cli_output (vm, "IPv6 UDP punt: %s",
+ tm->punt_unknown6 ? "enabled" : "disabled");
+ return 0;
+}
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
+{
+ .path = "show sctp punt",
+ .short_help = "show sctp punt",
+ .function = show_sctp_punt_fn,
+};
+/* *INDENT-ON* */
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/udp/udp.c b/src/vnet/udp/udp.c
index ccac921..8c2daaf 100644
--- a/src/vnet/udp/udp.c
+++ b/src/vnet/udp/udp.c
@@ -441,6 +441,66 @@
VLIB_INIT_FUNCTION (udp_init);
+static clib_error_t *
+show_udp_punt_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd_arg)
+{
+ udp_main_t *um = vnet_get_udp_main ();
+
+ clib_error_t *error = NULL;
+
+ if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ return clib_error_return (0, "unknown input `%U'", format_unformat_error,
+ input);
+
+ udp_dst_port_info_t *port_info;
+ if (um->punt_unknown4)
+ {
+ vlib_cli_output (vm, "IPv4 UDP punt: enabled");
+ }
+ else
+ {
+ u8 *s = NULL;
+ vec_foreach (port_info, um->dst_port_infos[UDP_IP4])
+ {
+ if (udp_is_valid_dst_port (port_info->dst_port, 1))
+ {
+ s = format (s, (!s) ? "%d" : ", %d", port_info->dst_port);
+ }
+ }
+ s = format (s, "%c", 0);
+ vlib_cli_output (vm, "IPV4 UDP ports punt : %s", s);
+ }
+
+ if (um->punt_unknown6)
+ {
+ vlib_cli_output (vm, "IPv6 UDP punt: enabled");
+ }
+ else
+ {
+ u8 *s = NULL;
+ vec_foreach (port_info, um->dst_port_infos[UDP_IP6])
+ {
+ if (udp_is_valid_dst_port (port_info->dst_port, 01))
+ {
+ s = format (s, (!s) ? "%d" : ", %d", port_info->dst_port);
+ }
+ }
+ s = format (s, "%c", 0);
+ vlib_cli_output (vm, "IPV6 UDP ports punt : %s", s);
+ }
+
+ return (error);
+}
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
+{
+ .path = "show udp punt",
+ .short_help = "show udp punt [ipv4|ipv6]",
+ .function = show_udp_punt_fn,
+};
+/* *INDENT-ON* */
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/udp/udp.h b/src/vnet/udp/udp.h
index 8b94a00..19db4f8 100644
--- a/src/vnet/udp/udp.h
+++ b/src/vnet/udp/udp.h
@@ -252,6 +252,7 @@
u32 node_index, u8 is_ip4);
void udp_unregister_dst_port (vlib_main_t * vm,
udp_dst_port_t dst_port, u8 is_ip4);
+bool udp_is_valid_dst_port (udp_dst_port_t dst_port, u8 is_ip4);
void udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add);
diff --git a/src/vnet/udp/udp_local.c b/src/vnet/udp/udp_local.c
index bb7305d..a16ba22 100644
--- a/src/vnet/udp/udp_local.c
+++ b/src/vnet/udp/udp_local.c
@@ -549,6 +549,22 @@
n[0] = SPARSE_VEC_INVALID_INDEX;
}
+bool
+udp_is_valid_dst_port (udp_dst_port_t dst_port, u8 is_ip4)
+{
+ udp_main_t *um = &udp_main;
+ u16 *n;
+
+ if (is_ip4)
+ n = sparse_vec_validate (um->next_by_dst_port4,
+ clib_host_to_net_u16 (dst_port));
+ else
+ n = sparse_vec_validate (um->next_by_dst_port6,
+ clib_host_to_net_u16 (dst_port));
+
+ return (n[0] != SPARSE_VEC_INVALID_INDEX);
+}
+
void
udp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
{