#include <vlib/vlib.h>
#include <vnet/pg/pg.h>
#include <vnet/udp/udp.h>
+#include <vnet/tcp/tcp.h>
+#include <vnet/sctp/sctp.h>
#include <vnet/ip/punt.h>
#include <vppinfra/sparse_vec.h>
#include <vlib/unix/unix.h>
#include <stdbool.h>
#define foreach_punt_next \
- _ (PUNT, "error-punt")
+ _ (PUNT4, "ip4-punt") \
+ _ (PUNT6, "ip6-punt")
typedef enum
{
PUNT_SOCKET_RX_N_NEXT
};
+#define punt_next_punt(is_ip4) (is_ip4 ? PUNT_NEXT_PUNT4 : PUNT_NEXT_PUNT6)
+
vlib_node_registration_t udp4_punt_node;
vlib_node_registration_t udp6_punt_node;
vlib_node_registration_t udp4_punt_socket_node;
{
u32 n_left_to_next;
- vlib_get_next_frame (vm, node, PUNT_NEXT_PUNT, to_next, n_left_to_next);
+ vlib_get_next_frame (vm, node, punt_next_punt (is_ip4), to_next,
+ n_left_to_next);
while (n_left_from > 0 && n_left_to_next > 0)
{
b0->error = node->errors[PUNT_ERROR_UDP_PORT];
}
- vlib_put_next_frame (vm, node, PUNT_NEXT_PUNT, n_left_to_next);
+ vlib_put_next_frame (vm, node, punt_next_punt (is_ip4), n_left_to_next);
}
return from_frame->n_vectors;
/* *INDENT-ON* */
-static struct sockaddr_un *
-punt_socket_get (bool is_ip4, u16 port)
+static punt_client_t *
+punt_client_get (bool is_ip4, u16 port)
{
punt_main_t *pm = &punt_main;
- punt_client_t *v = is_ip4 ? pm->clients_by_dst_port4 :
- pm->clients_by_dst_port6;
+ punt_client_t *v =
+ is_ip4 ? pm->clients_by_dst_port4 : pm->clients_by_dst_port6;
u16 i = sparse_vec_index (v, port);
if (i == SPARSE_VEC_INVALID_INDEX)
return 0;
- return &vec_elt (v, i).caddr;
+ return &vec_elt (v, i);
+}
+
+static struct sockaddr_un *
+punt_socket_get (bool is_ip4, u16 port)
+{
+ punt_client_t *v = punt_client_get (is_ip4, port);
+ if (v)
+ return &v->caddr;
+
+ return NULL;
}
static void
punt_client_t *v = is_ip4 ? pm->clients_by_dst_port4 :
pm->clients_by_dst_port6;
- memset (&c, 0, sizeof (c));
+ 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;
return;
}
+typedef struct
+{
+ punt_client_t client;
+ u8 is_midchain;
+} udp_punt_trace_t;
+
+u8 *
+format_udp_punt_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ udp_punt_trace_t *t = va_arg (*args, udp_punt_trace_t *);
+ u32 indent = format_get_indent (s);
+ s = format (s, "to: %s", t->client.caddr.sun_path);
+ if (t->is_midchain)
+ {
+ s = format (s, "\n%U(buffer is part of chain)", format_white_space,
+ indent);
+ }
+ return s;
+}
+
always_inline uword
udp46_punt_socket_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame, bool is_ip4)
{
- u32 *buffers = vlib_frame_args (frame);
+ u32 *buffers = vlib_frame_vector_args (frame);
uword n_packets = frame->n_vectors;
struct iovec *iovecs = 0;
punt_main_t *pm = &punt_main;
goto error;
}
+ punt_client_t *c = NULL;
+ if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ c = punt_client_get (is_ip4, port);
+ udp_punt_trace_t *t;
+ t = vlib_add_trace (vm, node, b, sizeof (t[0]));
+ clib_memcpy_fast (&t->client, c, sizeof (t->client));
+ }
+
/* Re-set iovecs if present. */
if (iovecs)
_vec_len (iovecs) = 0;
do
{
b = vlib_get_buffer (vm, b->next_buffer);
+ if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ if (PREDICT_FALSE (!c))
+ {
+ c = punt_client_get (is_ip4, port);
+ }
+ udp_punt_trace_t *t;
+ t = vlib_add_trace (vm, node, b, sizeof (t[0]));
+ clib_memcpy_fast (&t->client, c, sizeof (t->client));
+ t->is_midchain = 1;
+ }
vec_add2 (iovecs, iov, 1);
.msg_iovlen = vec_len (iovecs),
};
- if (sendmsg (pm->socket_fd, &msg, 0) < l)
+ if (sendmsg (pm->socket_fd, &msg, 0) < (ssize_t) l)
vlib_node_increment_counter (vm, node_index,
PUNT_ERROR_SOCKET_TX_ERROR, 1);
}
error:
- vlib_buffer_free_no_next (vm, buffers, n_packets);
+ vlib_buffer_free (vm, buffers, n_packets);
return n_packets;
}
VLIB_REGISTER_NODE (udp4_punt_socket_node) = {
.function = udp4_punt_socket,
.name = "ip4-udp-punt-socket",
+ .format_trace = format_udp_punt_trace,
.flags = VLIB_NODE_FLAG_IS_DROP,
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
VLIB_REGISTER_NODE (udp6_punt_socket_node) = {
.function = udp6_punt_socket,
.name = "ip6-udp-punt-socket",
+ .format_trace = format_udp_punt_trace,
.flags = VLIB_NODE_FLAG_IS_DROP,
.vector_size = sizeof (u32),
.n_errors = PUNT_N_ERROR,
* @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
*/
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)
+
+ /* For now we only support TCP, UDP and SCTP punt */
+ if (protocol != IP_PROTOCOL_UDP &&
+ protocol != IP_PROTOCOL_TCP && protocol != IP_PROTOCOL_SCTP)
return clib_error_return (0,
- "only UDP protocol (%d) is supported, got %d",
- IP_PROTOCOL_UDP, protocol);
+ "only UDP (%d), TCP (%d) and SCTP (%d) protocols are supported, got %d",
+ IP_PROTOCOL_UDP, IP_PROTOCOL_TCP,
+ IP_PROTOCOL_SCTP, 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);
+ else if (protocol == IP_PROTOCOL_SCTP)
+ sctp_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);
+ else if (protocol == IP_PROTOCOL_SCTP)
+ sctp_punt_unknown (vm, 0, is_add);
+ }
return 0;
}
else if (is_add)
{
+ if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP)
+ return clib_error_return (0,
+ "punt TCP/SCTP ports is not supported yet");
+
if (ipv == 4 || ipv == (u8) ~ 0)
udp_register_dst_port (vm, port, udp4_punt_node.index, 1);
}
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;
- clib_error_t *error;
+ u32 protocol = ~0;
+ clib_error_t *error = NULL;
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);
+ {
+ clib_error_report (error);
+ goto done;
+ }
}
- 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);
+ {
+ clib_error_report (error);
+ goto done;
+ }
+ }
+ else if (unformat (input, "udp"))
+ protocol = IP_PROTOCOL_UDP;
+ else if (unformat (input, "tcp"))
+ protocol = IP_PROTOCOL_TCP;
+ else
+ {
+ error = clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, input);
+ goto done;
}
}
-
- return 0;
+done:
+ return error;
}
/*?
* @endparblock
?*/
/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (punt_udp_command, static) = {
- .path = "set punt udp",
- .short_help = "set punt udp [del] <all | port-num1 [port-num2 ...]>",
- .function = udp_punt_cli,
+VLIB_CLI_COMMAND (punt_command, static) = {
+ .path = "set punt",
+ .short_help = "set punt [udp|tcp] [del] <all | port-num1 [port-num2 ...]>",
+ .function = punt_cli,
};
/* *INDENT-ON* */
return clib_error_return (0, "socket error");
}
- memset (&addr, 0, sizeof (addr));
+ clib_memset (&addr, 0, sizeof (addr));
addr.sun_family = AF_UNIX;
if (*socket_path == '\0')
{
clib_file_t template = { 0 };
template.read_function = punt_socket_read_ready;
template.file_descriptor = pm->socket_fd;
+ template.description = format (0, "%s", socket_path);
pm->clib_file_index = clib_file_add (fm, &template);
pm->is_configured = true;