aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Kotucek <pavel.kotucek@pantheon.tech>2018-11-28 07:42:11 +0100
committerOle Trøan <otroan@employees.org>2018-12-07 12:24:52 +0000
commite88865d7bc9cd45b044f8aeadf1916c38e0eb165 (patch)
treea6dfb198549ff9f2335724e3ea7b0f942ad08540
parente6b58cf86affdf434a15f8833e959cded6c15784 (diff)
VPP-1506: dump local punts and registered punt sockets
Change-Id: If7835e9b80ec9402404bfc8d271eb11a10ef992b Signed-off-by: Pavel Kotucek <pavel.kotucek@pantheon.tech>
-rw-r--r--src/vat/api_format.c18
-rw-r--r--src/vnet/ip/punt.api69
-rw-r--r--src/vnet/ip/punt.c299
-rw-r--r--src/vnet/ip/punt.h12
-rw-r--r--src/vnet/ip/punt_api.c75
-rw-r--r--src/vnet/sctp/sctp.c23
-rw-r--r--src/vnet/udp/udp.c60
-rw-r--r--src/vnet/udp/udp.h1
-rw-r--r--src/vnet/udp/udp_local.c16
-rw-r--r--src/vpp/api/custom_dump.c14
-rw-r--r--test/framework.py4
-rw-r--r--test/test_punt.py309
-rw-r--r--test/vpp_papi_provider.py28
13 files changed, 838 insertions, 90 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index f54aa02d228..7f4dabeffa1 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -5572,7 +5572,7 @@ _(ip_source_and_port_range_check_add_del_reply) \
_(ip_source_and_port_range_check_interface_add_del_reply)\
_(delete_subif_reply) \
_(l2_interface_pbb_tag_rewrite_reply) \
-_(punt_reply) \
+_(set_punt_reply) \
_(feature_enable_disable_reply) \
_(sw_interface_tag_add_del_reply) \
_(hw_interface_set_mtu_reply) \
@@ -5902,7 +5902,7 @@ _(IPSEC_GRE_ADD_DEL_TUNNEL_REPLY, ipsec_gre_add_del_tunnel_reply) \
_(IPSEC_GRE_TUNNEL_DETAILS, ipsec_gre_tunnel_details) \
_(DELETE_SUBIF_REPLY, delete_subif_reply) \
_(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \
-_(PUNT_REPLY, punt_reply) \
+_(SET_PUNT_REPLY, set_punt_reply) \
_(IP_FIB_DETAILS, ip_fib_details) \
_(IP6_FIB_DETAILS, ip6_fib_details) \
_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) \
@@ -21725,10 +21725,10 @@ api_ipsec_gre_add_del_tunnel (vat_main_t * vam)
}
static int
-api_punt (vat_main_t * vam)
+api_set_punt (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
- vl_api_punt_t *mp;
+ vl_api_set_punt_t *mp;
u32 ipv = ~0;
u32 protocol = ~0;
u32 port = ~0;
@@ -21752,12 +21752,12 @@ api_punt (vat_main_t * vam)
}
}
- M (PUNT, mp);
+ M (SET_PUNT, mp);
mp->is_add = (u8) is_add;
- mp->ipv = (u8) ipv;
- mp->l4_protocol = (u8) protocol;
- mp->l4_port = htons ((u16) port);
+ mp->punt.ipv = (u8) ipv;
+ mp->punt.l4_protocol = (u8) protocol;
+ mp->punt.l4_port = htons ((u16) port);
S (mp);
W (ret);
@@ -24033,7 +24033,7 @@ _(l2_interface_pbb_tag_rewrite, \
"<intfc> | sw_if_index <nn> \n" \
"[disable | push | pop | translate_pbb_stag <outer_tag>] \n" \
"dmac <mac> smac <mac> sid <nn> [vlanid <nn>]") \
-_(punt, "protocol <l4-protocol> [ip <ver>] [port <l4-port>] [del]") \
+_(set_punt, "protocol <l4-protocol> [ip <ver>] [port <l4-port>] [del]") \
_(flow_classify_set_interface, \
"<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>] [del]") \
_(flow_classify_dump, "type [ip4|ip6]") \
diff --git a/src/vnet/ip/punt.api b/src/vnet/ip/punt.api
index 4477e5c14e5..c8b222a211b 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 d8c7d81a23a..c0902f346ff 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 @@ punt_socket_get (bool is_ip4, u16 port)
return NULL;
}
-static void
+static int
punt_socket_register (bool is_ip4, u8 protocol, u16 port,
char *client_pathname)
{
@@ -270,12 +268,18 @@ punt_socket_register (bool is_ip4, u8 protocol, u16 port,
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 @@ udp46_punt_socket_inline (vlib_main_t * vm,
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 @@ punt_socket_rx (vlib_main_t * vm,
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 @@ vnet_punt_socket_add (vlib_main_t * vm, u32 header_version,
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 @@ static clib_error_t *
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 @@ punt_cli (vlib_main_t * vm,
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 @@ punt_cli (vlib_main_t * vm,
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 @@ VLIB_CLI_COMMAND (punt_command, static) = {
};
/* *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 @@ punt_config (vlib_main_t * vm, unformat_input_t * input)
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 4cef5278558..0518b2b91ef 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 __attribute__ ((packed))
*/
typedef struct
{
+ u8 protocol;
u16 port;
struct sockaddr_un caddr;
} punt_client_t;
@@ -82,6 +83,15 @@ typedef struct
} 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 55ab838b167..3ca9621a410 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 @@ vl_api_punt_socket_register_t_handler (vl_api_punt_socket_register_t * mp)
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_punt_socket_register_t_handler (vl_api_punt_socket_register_t * mp)
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 @@ vl_api_punt_socket_deregister_t_handler (vl_api_punt_socket_deregister_t * mp)
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 41548bc0d7a..85ca9b8048f 100644
--- a/src/vnet/sctp/sctp.c
+++ b/src/vnet/sctp/sctp.c
@@ -987,6 +987,29 @@ sctp_init (vlib_main_t * vm)
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 ccac921b8b3..8c2daaf66e6 100644
--- a/src/vnet/udp/udp.c
+++ b/src/vnet/udp/udp.c
@@ -441,6 +441,66 @@ udp_init (vlib_main_t * vm)
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 8b94a0088f6..19db4f81777 100644
--- a/src/vnet/udp/udp.h
+++ b/src/vnet/udp/udp.h
@@ -252,6 +252,7 @@ void udp_register_dst_port (vlib_main_t * vm,
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 bb7305d8d03..a16ba22cf27 100644
--- a/src/vnet/udp/udp_local.c
+++ b/src/vnet/udp/udp_local.c
@@ -549,6 +549,22 @@ udp_unregister_dst_port (vlib_main_t * vm, udp_dst_port_t dst_port, u8 is_ip4)
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)
{
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
index 833972108a8..41a24ef5a34 100644
--- a/src/vpp/api/custom_dump.c
+++ b/src/vpp/api/custom_dump.c
@@ -3363,19 +3363,19 @@ static void *vl_api_flow_classify_set_interface_t_print
}
static void *
-vl_api_punt_t_print (vl_api_punt_t * mp, void *handle)
+vl_api_set_punt_t_print (vl_api_set_punt_t * mp, void *handle)
{
u8 *s;
s = format (0, "SCRIPT: punt ");
- if (mp->ipv != (u8) ~ 0)
- s = format (s, "ip %d ", mp->ipv);
+ if (mp->punt.ipv != (u8) ~ 0)
+ s = format (s, "ip %d ", mp->punt.ipv);
- s = format (s, "protocol %d ", mp->l4_protocol);
+ s = format (s, "protocol %d ", mp->punt.l4_protocol);
- if (mp->l4_port != (u16) ~ 0)
- s = format (s, "port %d ", ntohs (mp->l4_port));
+ if (mp->punt.l4_port != (u16) ~ 0)
+ s = format (s, "port %d ", ntohs (mp->punt.l4_port));
if (!mp->is_add)
s = format (s, "del ");
@@ -3891,7 +3891,7 @@ _(IPSEC_GRE_ADD_DEL_TUNNEL, ipsec_gre_add_del_tunnel) \
_(IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump) \
_(DELETE_SUBIF, delete_subif) \
_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
-_(PUNT, punt) \
+_(SET_PUNT, set_punt) \
_(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \
_(FLOW_CLASSIFY_DUMP, flow_classify_dump) \
_(GET_FIRST_MSG_ID, get_first_msg_id) \
diff --git a/test/framework.py b/test/framework.py
index 6c1ba5e3f33..8a1bfcb660b 100644
--- a/test/framework.py
+++ b/test/framework.py
@@ -193,6 +193,8 @@ class VppTestCase(unittest.TestCase):
classes. It provides methods to create and run test case.
"""
+ extra_vpp_punt_config = []
+
@property
def packet_infos(self):
"""List of packet infos"""
@@ -308,6 +310,8 @@ class VppTestCase(unittest.TestCase):
"{", "plugin", "dpdk_plugin.so", "{", "disable",
"}", "plugin", "unittest_plugin.so", "{", "enable",
"}", "}", ]
+ if cls.extra_vpp_punt_config is not None:
+ cls.vpp_cmdline.extend(cls.extra_vpp_punt_config)
if plugin_path is not None:
cls.vpp_cmdline.extend(["plugin_path", plugin_path])
cls.logger.info("vpp_cmdline args: %s" % cls.vpp_cmdline)
diff --git a/test/test_punt.py b/test/test_punt.py
new file mode 100644
index 00000000000..c31bdcfb2c5
--- /dev/null
+++ b/test/test_punt.py
@@ -0,0 +1,309 @@
+#!/usr/bin/env python
+import binascii
+import random
+import socket
+import unittest
+import os
+import scapy.layers.inet6 as inet6
+
+from util import ppp, ppc
+from re import compile
+from scapy.packet import Raw
+from scapy.layers.l2 import Ether
+from scapy.layers.inet import IP, UDP, ICMP
+from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
+from framework import VppTestCase, VppTestRunner
+
+
+class TestPuntSocket(VppTestCase):
+ """ Punt Socket """
+
+ tempdir = ""
+ sock = None
+ err_ptr = compile(r"^([\d]+)\s+([-\w]+)\s+([ -\.\w)(]+)$")
+
+ @classmethod
+ def setUpConstants(cls):
+ tempdir = cls.tempdir
+ cls.extra_vpp_punt_config = [
+ "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
+ super(TestPuntSocket, cls).setUpConstants()
+
+ def process_cli(self, exp, ptr):
+ for line in self.vapi.cli(exp).split('\n')[1:]:
+ m = ptr.match(line.strip())
+ if m:
+ yield m.groups()
+
+ def show_errors(self):
+ for pack in self.process_cli("show errors", self.err_ptr):
+ try:
+ count, node, reason = pack
+ except ValueError:
+ pass
+ else:
+ yield count, node, reason
+
+ def get_punt_count(self, counter):
+ errors = list(self.show_errors())
+ for count, node, reason in errors:
+ if (node == counter and
+ reason == u'Socket TX'):
+ return int(count)
+ return 0
+
+ def socket_client_create(self, sock_name):
+ self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+ try:
+ os.unlink(sock_name)
+ except:
+ self.logger.debug("Unlink socket faild")
+ self.sock.bind(sock_name)
+
+ def socket_client_close(self):
+ self.sock.close()
+
+
+class TestIP4PuntSocket(TestPuntSocket):
+ """ Punt Socket for IPv4 """
+
+ def setUp(self):
+ super(TestIP4PuntSocket, self).setUp()
+
+ self.create_pg_interfaces(range(2))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip4()
+ i.resolve_arp()
+
+ def tearDown(self):
+ super(TestIP4PuntSocket, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip4()
+ i.admin_down()
+
+ def test_punt_socket_dump(self):
+ """ Punt socket registration"""
+
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 0)
+
+ #
+ # configure a punt socket
+ #
+ self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
+ self.vapi.punt_socket_register(2222, self.tempdir+"/socket_punt_2222")
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 2)
+ self.assertEqual(punts[0].punt.l4_port, 1111)
+ # self.assertEqual(punts[0].pathname, "/tmp/punt_socket_udp_1234")
+ self.assertEqual(punts[1].punt.l4_port, 2222)
+ # self.assertEqual(punts[1].pathname, "/tmp/punt_socket_udp_5678")
+
+ #
+ # deregister a punt socket
+ #
+ self.vapi.punt_socket_deregister(1111)
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 1)
+
+ #
+ # configure a punt socket again
+ #
+ self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
+ self.vapi.punt_socket_register(3333, self.tempdir+"/socket_punt_3333")
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 3)
+
+ #
+ # deregister all punt socket
+ #
+ self.vapi.punt_socket_deregister(1111)
+ self.vapi.punt_socket_deregister(2222)
+ self.vapi.punt_socket_deregister(3333)
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 0)
+
+ def test_punt_socket_traffic(self):
+ """ Punt socket traffic"""
+
+ nr_packets = 8
+ p = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
+ UDP(sport=9876, dport=1234) /
+ Raw('\xa5' * 100))
+
+ pkts = p * nr_packets
+
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 0)
+
+ #
+ # expect ICMP - port unreachable for all packets
+ #
+ self.vapi.cli("clear trace")
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ rx = self.pg0.get_capture(nr_packets)
+ for p in rx:
+ self.assertEqual(int(p[IP].proto), 1) # ICMP
+ self.assertEqual(int(p[ICMP].code), 3) # unreachable
+
+ #
+ # configure a punt socket
+ #
+ self.socket_client_create(self.tempdir+"/socket_punt_1234")
+ self.vapi.punt_socket_register(1234, self.tempdir+"/socket_punt_1234")
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 1)
+
+ #
+ # expect punt socket and no packets on pg0
+ #
+ self.vapi.cli("clear errors")
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ self.pg0.get_capture(0)
+ self.socket_client_close()
+
+ #
+ # remove punt socket. expect ICMP - port unreachable for all packets
+ #
+ self.vapi.punt_socket_deregister(1234)
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 0)
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ # FIXME - when punt socket deregister is implemented
+ # self.pg0.get_capture(nr_packets)
+
+
+class TestIP6PuntSocket(TestPuntSocket):
+ """ Punt Socket for IPv6"""
+
+ def setUp(self):
+ super(TestIP6PuntSocket, self).setUp()
+
+ self.create_pg_interfaces(range(2))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestIP6PuntSocket, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+
+ def test_punt_socket_dump(self):
+ """ Punt socket registration """
+
+ punts = self.vapi.punt_socket_dump(0)
+ self.assertEqual(len(punts), 0)
+
+ #
+ # configure a punt socket
+ #
+ self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111",
+ is_ip4=0)
+ self.vapi.punt_socket_register(2222, self.tempdir+"/socket_punt_2222",
+ is_ip4=0)
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 2)
+ self.assertEqual(punts[0].punt.l4_port, 1111)
+ # self.assertEqual(punts[0].pathname, "/tmp/punt_socket_udp_1234")
+ self.assertEqual(punts[1].punt.l4_port, 2222)
+ # self.assertEqual(punts[1].pathname, "/tmp/punt_socket_udp_5678")
+
+ #
+ # deregister a punt socket
+ #
+ self.vapi.punt_socket_deregister(1111, is_ip4=0)
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 1)
+
+ #
+ # configure a punt socket again
+ #
+ self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111",
+ is_ip4=0)
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 2)
+
+ #
+ # deregister all punt socket
+ #
+ self.vapi.punt_socket_deregister(1111, is_ip4=0)
+ self.vapi.punt_socket_deregister(2222, is_ip4=0)
+ self.vapi.punt_socket_deregister(3333, is_ip4=0)
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 0)
+
+ def test_punt_socket_traffic(self):
+ """ Punt socket traffic"""
+
+ nr_packets = 2
+ p = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
+ inet6.UDP(sport=9876, dport=1234) /
+ Raw('\xa5' * 100))
+
+ pkts = p * nr_packets
+
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 0)
+
+ #
+ # expect ICMPv6 - destination unreachable for all packets
+ #
+ self.vapi.cli("clear trace")
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ rx = self.pg0.get_capture(nr_packets)
+ for p in rx:
+ self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
+ self.assertEqual(int(p[ICMPv6DestUnreach].code), 4) # unreachable
+
+ #
+ # configure a punt socket
+ #
+ self.socket_client_create(self.tempdir+"/socket_punt_1234")
+ self.vapi.punt_socket_register(1234, self.tempdir+"/socket_punt_1234",
+ is_ip4=0)
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 1)
+
+ #
+ # expect punt socket and no packets on pg0
+ #
+ self.vapi.cli("clear errors")
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ self.pg0.get_capture(0)
+ self.socket_client_close()
+
+ #
+ # remove punt socket. expect ICMP - dest. unreachable for all packets
+ #
+ self.vapi.punt_socket_deregister(1234, is_ip4=0)
+ punts = self.vapi.punt_socket_dump(1)
+ self.assertEqual(len(punts), 0)
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ # FIXME - when punt socket deregister is implemented
+# self.pg0.get_capture(nr_packets)
+
+
+if __name__ == '__main__':
+ unittest.main(testRunner=VppTestRunner)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 8153e031607..612a678ae9d 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -3486,15 +3486,27 @@ class VppPapiProvider(object):
'namespace_id': namespace_id,
'namespace_id_len': len(namespace_id)})
- def punt_socket_register(self, l4_port, pathname, header_version=1,
- is_ip4=1, l4_protocol=0x11):
- """ Punt to socket """
+ def punt_socket_register(self, port, pathname, protocol=0x11,
+ header_version=1, is_ip4=1):
+ """ Register punt socket """
return self.api(self.papi.punt_socket_register,
- {'is_ip4': is_ip4,
- 'l4_protocol': l4_protocol,
- 'l4_port': l4_port,
- 'pathname': pathname,
- 'header_version': header_version})
+ {'header_version': header_version,
+ 'punt': {'ipv': is_ip4,
+ 'l4_protocol': protocol,
+ 'l4_port': port},
+ 'pathname': pathname})
+
+ def punt_socket_deregister(self, port, protocol=0x11, is_ip4=1):
+ """ Unregister punt socket """
+ return self.api(self.papi.punt_socket_deregister,
+ {'punt': {'ipv': is_ip4,
+ 'l4_protocol': protocol,
+ 'l4_port': port}})
+
+ def punt_socket_dump(self, is_ip6=1):
+ """ Dump punt socket"""
+ return self.api(self.papi.punt_socket_dump,
+ {'is_ipv6': is_ip6})
def ip_reassembly_set(self, timeout_ms, max_reassemblies,
expire_walk_interval_ms, is_ip6=0):