X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fpunt.c;h=d8c7d81a23a9fb475d4e66461d237a72c70b88da;hb=2af0e3a;hp=67c54c3c5c119ca0a676477bf24006a48f1b6917;hpb=2234983112fb9099135fcd1da9186004cbdf6e21;p=vpp.git diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c index 67c54c3c5c1..d8c7d81a23a 100644 --- a/src/vnet/ip/punt.c +++ b/src/vnet/ip/punt.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,7 +41,8 @@ #include #define foreach_punt_next \ - _ (PUNT, "error-punt") + _ (PUNT4, "ip4-punt") \ + _ (PUNT6, "ip6-punt") typedef enum { @@ -57,6 +60,8 @@ enum punt_socket_rx_next_e 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; @@ -103,7 +108,8 @@ udp46_punt_inline (vlib_main_t * vm, { 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) { @@ -122,7 +128,7 @@ udp46_punt_inline (vlib_main_t * vm, 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; @@ -231,18 +237,28 @@ VLIB_NODE_FUNCTION_MULTIARCH (udp6_punt_node, udp6_punt);; /* *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 @@ -254,7 +270,7 @@ 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; - 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; @@ -269,12 +285,34 @@ punt_socket_unregister (bool is_ip4, u8 protocol, u16 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; @@ -324,6 +362,15 @@ udp46_punt_socket_inline (vlib_main_t * vm, 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; @@ -346,6 +393,17 @@ udp46_punt_socket_inline (vlib_main_t * vm, 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); @@ -363,13 +421,13 @@ udp46_punt_socket_inline (vlib_main_t * vm, .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; } @@ -393,6 +451,7 @@ udp6_punt_socket (vlib_main_t * vm, 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), @@ -402,6 +461,7 @@ VLIB_REGISTER_NODE (udp4_punt_socket_node) = { 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, @@ -550,7 +610,7 @@ VLIB_REGISTER_NODE (punt_socket_rx_node, static) = format_punt_trace,}; static clib_error_t * -punt_socket_read_ready (unix_file_t * uf) +punt_socket_read_ready (clib_file_t * uf) { vlib_main_t *vm = vlib_get_main (); punt_main_t *pm = &punt_main; @@ -613,16 +673,15 @@ vnet_punt_socket_del (vlib_main_t * vm, bool is_ip4, u8 l4_protocol, u16 port) * @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 */ @@ -630,28 +689,49 @@ clib_error_t * 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); @@ -665,35 +745,51 @@ vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, } 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; } /*? @@ -717,10 +813,10 @@ udp_punt_cli (vlib_main_t * vm, * @endparblock ?*/ /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (punt_udp_command, static) = { - .path = "set punt udp", - .short_help = "set punt udp [del] ", - .function = udp_punt_cli, +VLIB_CLI_COMMAND (punt_command, static) = { + .path = "set punt", + .short_help = "set punt [udp|tcp] [del] ", + .function = punt_cli, }; /* *INDENT-ON* */ @@ -770,7 +866,7 @@ punt_config (vlib_main_t * vm, unformat_input_t * input) 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') { @@ -790,11 +886,12 @@ punt_config (vlib_main_t * vm, unformat_input_t * input) } /* Register socket */ - unix_main_t *um = &unix_main; - unix_file_t template = { 0 }; + clib_file_main_t *fm = &file_main; + clib_file_t template = { 0 }; template.read_function = punt_socket_read_ready; template.file_descriptor = pm->socket_fd; - pm->unix_file_index = unix_file_add (um, &template); + template.description = format (0, "%s", socket_path); + pm->clib_file_index = clib_file_add (fm, &template); pm->is_configured = true;