X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fpunt.c;h=d4d502887d7a457b1463128d816b8feb2374c4c1;hb=50f0ac0f0;hp=4855840129208878c5ec4369fc7f7088b90de0dd;hpb=68b0fb0c620c7451ef1a6380c43c39de6614db51;p=vpp.git diff --git a/src/vnet/ip/punt.c b/src/vnet/ip/punt.c index 48558401292..d4d502887d7 100644 --- a/src/vnet/ip/punt.c +++ b/src/vnet/ip/punt.c @@ -17,273 +17,389 @@ * @file * @brief Local TCP/IP stack punt infrastructure. * - * Provides a set of VPP nodes togather with the relevant APIs and CLI + * Provides a set of VPP nodes together with the relevant APIs and CLI * commands in order to adjust and dispatch packets from the VPP data plane * to the local TCP/IP stack */ + +#include #include #include #include +#include +#include #include +#include + +#include +#include +#include +#include +#include -#define foreach_punt_next \ - _ (PUNT, "error-punt") +punt_main_t punt_main; -typedef enum +char * +vnet_punt_get_server_pathname (void) { -#define _(s,n) PUNT_NEXT_##s, - foreach_punt_next -#undef _ - PUNT_N_NEXT, -} punt_next_t; - -vlib_node_registration_t udp4_punt_node; -vlib_node_registration_t udp6_punt_node; - -/** @brief IPv4/IPv6 UDP punt node main loop. - - This is the main loop inline function for IPv4/IPv6 UDP punt - transition node. - - @param vm vlib_main_t corresponding to the current thread - @param node vlib_node_runtime_t - @param frame vlib_frame_t whose contents should be dispatched - @param is_ipv4 indicates if called for IPv4 or IPv6 node -*/ -always_inline uword -udp46_punt_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame, int is_ip4) + punt_main_t *pm = &punt_main; + return pm->sun_path; +} + +static void +punt_client_l4_db_add (ip_address_family_t af, u16 port, u32 index) { - u32 n_left_from, *from, *to_next; - word advance; + punt_main_t *pm = &punt_main; - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; + pm->db.clients_by_l4_port = hash_set (pm->db.clients_by_l4_port, + punt_client_l4_mk_key (af, port), + index); +} - /* udp[46]_lookup hands us the data payload, not the IP header */ - if (is_ip4) - advance = -(sizeof (ip4_header_t) + sizeof (udp_header_t)); - else - advance = -(sizeof (ip6_header_t) + sizeof (udp_header_t)); +static u32 +punt_client_l4_db_remove (ip_address_family_t af, u16 port) +{ + punt_main_t *pm = &punt_main; + u32 key, index = ~0; + uword *p; - while (n_left_from > 0) - { - u32 n_left_to_next; + key = punt_client_l4_mk_key (af, port); + p = hash_get (pm->db.clients_by_l4_port, key); - vlib_get_next_frame (vm, node, PUNT_NEXT_PUNT, to_next, n_left_to_next); + if (p) + index = p[0]; - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - vlib_buffer_advance (b0, advance); - b0->error = node->errors[PUNT_ERROR_UDP_PORT]; - } + hash_unset (pm->db.clients_by_l4_port, key); + + return (index); +} + +static void +punt_client_exception_db_add (vlib_punt_reason_t reason, u32 pci) +{ + punt_main_t *pm = &punt_main; + + vec_validate_init_empty (pm->db.clients_by_exception, reason, ~0); - vlib_put_next_frame (vm, node, PUNT_NEXT_PUNT, n_left_to_next); + pm->db.clients_by_exception[reason] = pci; +} + +static u32 +punt_client_exception_db_remove (vlib_punt_reason_t reason) +{ + punt_main_t *pm = &punt_main; + u32 pci = ~0; + + if (punt_client_exception_get (reason)) + { + pci = pm->db.clients_by_exception[reason]; + pm->db.clients_by_exception[reason] = ~0; } - return from_frame->n_vectors; + return pci; } -static char *punt_error_strings[] = { -#define punt_error(n,s) s, -#include "punt_error.def" -#undef punt_error -}; +static clib_error_t * +punt_socket_read_ready (clib_file_t * uf) +{ + vlib_main_t *vm = vlib_get_main (); + punt_main_t *pm = &punt_main; -/** @brief IPv4 UDP punt node. - @node ip4-udp-punt + /** Schedule the rx node */ + vlib_node_set_interrupt_pending (vm, punt_socket_rx_node.index); + vec_add1 (pm->ready_fds, uf->file_descriptor); - This is the IPv4 UDP punt transition node. It is registered as a next - node for the "ip4-udp-lookup" handling UDP port(s) requested for punt. - The buffer's current data pointer is adjusted to the original packet - IPv4 header. All buffers are dispatched to "error-punt". + return 0; +} - @param vm vlib_main_t corresponding to the current thread - @param node vlib_node_runtime_t - @param frame vlib_frame_t whose contents should be dispatched +static clib_error_t * +punt_socket_register_l4 (vlib_main_t * vm, + ip_address_family_t af, + u8 protocol, u16 port, char *client_pathname) +{ + punt_main_t *pm = &punt_main; + punt_client_t *c; - @par Graph mechanics: next index usage + /* 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 (port == (u16) ~ 0) + return clib_error_return (0, "UDP port number required"); - @em Sets: - - vnet_buffer(b)->current_data - - vnet_buffer(b)->current_len + if (strncmp (client_pathname, vnet_punt_get_server_pathname (), + UNIX_PATH_MAX) == 0) + return clib_error_return (0, + "Punt socket: Invalid client path: %s", + client_pathname); + + c = punt_client_l4_get (af, port); - Next Index: - - Dispatches the packet to the "error-punt" node -*/ -static uword -udp4_punt (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * from_frame) + if (NULL == c) + { + pool_get_zero (pm->punt_client_pool, c); + punt_client_l4_db_add (af, port, c - pm->punt_client_pool); + } + + memcpy (c->caddr.sun_path, client_pathname, sizeof (c->caddr.sun_path)); + c->caddr.sun_family = AF_UNIX; + c->reg.type = PUNT_TYPE_L4; + c->reg.punt.l4.port = port; + c->reg.punt.l4.protocol = protocol; + c->reg.punt.l4.af = af; + + u32 node_index = (af == AF_IP4 ? + udp4_punt_socket_node.index : + udp6_punt_socket_node.index); + + udp_register_dst_port (vm, port, node_index, af == AF_IP4); + + return (NULL); +} + +static clib_error_t * +punt_socket_register_exception (vlib_main_t * vm, + vlib_punt_reason_t reason, + char *client_pathname) { - return udp46_punt_inline (vm, node, from_frame, 1 /* is_ip4 */ ); + punt_main_t *pm = &punt_main; + punt_client_t *pc; + + pc = punt_client_exception_get (reason); + + if (NULL == pc) + { + pool_get_zero (pm->punt_client_pool, pc); + punt_client_exception_db_add (reason, pc - pm->punt_client_pool); + } + + memcpy (pc->caddr.sun_path, client_pathname, sizeof (pc->caddr.sun_path)); + pc->caddr.sun_family = AF_UNIX; + pc->reg.type = PUNT_TYPE_EXCEPTION; + pc->reg.punt.exception.reason = reason; + + vlib_punt_register (pm->hdl, + pc->reg.punt.exception.reason, "exception-punt-socket"); + + return (NULL); } -/** @brief IPv6 UDP punt node. - @node ip6-udp-punt +static clib_error_t * +punt_socket_unregister_l4 (ip_address_family_t af, + ip_protocol_t protocol, u16 port) +{ + u32 pci; - This is the IPv6 UDP punt transition node. It is registered as a next - node for the "ip6-udp-lookup" handling UDP port(s) requested for punt. - The buffer's current data pointer is adjusted to the original packet - IPv6 header. All buffers are dispatched to "error-punt". + udp_unregister_dst_port (vlib_get_main (), port, af == AF_IP4); - @param vm vlib_main_t corresponding to the current thread - @param node vlib_node_runtime_t - @param frame vlib_frame_t whose contents should be dispatched + pci = punt_client_l4_db_remove (af, port); - @par Graph mechanics: next index usage + if (~0 != pci) + pool_put_index (punt_main.punt_client_pool, pci); - @em Sets: - - vnet_buffer(b)->current_data - - vnet_buffer(b)->current_len + return (NULL); +} - Next Index: - - Dispatches the packet to the "error-punt" node -*/ -static uword -udp6_punt (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * from_frame) +static clib_error_t * +punt_socket_unregister_exception (vlib_punt_reason_t reason) { - return udp46_punt_inline (vm, node, from_frame, 0 /* is_ip4 */ ); + u32 pci; + + pci = punt_client_exception_db_remove (reason); + + if (~0 != pci) + pool_put_index (punt_main.punt_client_pool, pci); + + return (NULL); } -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (udp4_punt_node) = { - .function = udp4_punt, - .name = "ip4-udp-punt", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), - - .n_errors = PUNT_N_ERROR, - .error_strings = punt_error_strings, - - .n_next_nodes = PUNT_N_NEXT, - .next_nodes = { -#define _(s,n) [PUNT_NEXT_##s] = n, - foreach_punt_next -#undef _ - }, -}; +clib_error_t * +vnet_punt_socket_add (vlib_main_t * vm, u32 header_version, + const punt_reg_t * pr, char *client_pathname) +{ + punt_main_t *pm = &punt_main; -VLIB_NODE_FUNCTION_MULTIARCH (udp4_punt_node, udp4_punt); + if (!pm->is_configured) + return clib_error_return (0, "socket is not configured"); -VLIB_REGISTER_NODE (udp6_punt_node) = { - .function = udp6_punt, - .name = "ip6-udp-punt", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), + if (header_version != PUNT_PACKETDESC_VERSION) + return clib_error_return (0, "Invalid packet descriptor version"); - .n_errors = PUNT_N_ERROR, - .error_strings = punt_error_strings, + /* Register client */ + switch (pr->type) + { + case PUNT_TYPE_L4: + return (punt_socket_register_l4 (vm, + pr->punt.l4.af, + pr->punt.l4.protocol, + pr->punt.l4.port, client_pathname)); + case PUNT_TYPE_EXCEPTION: + return (punt_socket_register_exception (vm, + pr->punt.exception.reason, + client_pathname)); + } - .n_next_nodes = PUNT_N_NEXT, - .next_nodes = { -#define _(s,n) [PUNT_NEXT_##s] = n, - foreach_punt_next -#undef _ - }, -}; -/* *INDENT-ON* */ + return 0; +} -VLIB_NODE_FUNCTION_MULTIARCH (udp6_punt_node, udp6_punt);; +clib_error_t * +vnet_punt_socket_del (vlib_main_t * vm, const punt_reg_t * pr) +{ + punt_main_t *pm = &punt_main; + + if (!pm->is_configured) + return clib_error_return (0, "socket is not configured"); + + switch (pr->type) + { + case PUNT_TYPE_L4: + return (punt_socket_unregister_l4 (pr->punt.l4.af, + pr->punt.l4.protocol, + pr->punt.l4.port)); + case PUNT_TYPE_EXCEPTION: + return (punt_socket_unregister_exception (pr->punt.exception.reason)); + } + + return 0; +} /** * @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, TCP and SCTP 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 af IP address family. * @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 */ -clib_error_t * -vnet_punt_add_del (vlib_main_t * vm, u8 ipv, u8 protocol, u16 port, - int is_add) +static clib_error_t * +punt_l4_add_del (vlib_main_t * vm, + ip_address_family_t af, + ip_protocol_t 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); - - if (ipv != (u8) ~ 0 && ipv != 4 && ipv != 6) - return clib_error_return (0, "IP version must be 4 or 6, got %d", ipv); + "only UDP (%d), TCP (%d) and SCTP (%d) protocols are supported, got %d", + IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, + IP_PROTOCOL_SCTP, protocol); 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 (protocol == IP_PROTOCOL_UDP) + udp_punt_unknown (vm, af == AF_IP4, is_add); + else if (protocol == IP_PROTOCOL_TCP) + tcp_punt_unknown (vm, af == AF_IP4, is_add); + else if (protocol == IP_PROTOCOL_SCTP) + sctp_punt_unknown (vm, af == AF_IP4, is_add); return 0; } else if (is_add) { - if (ipv == 4 || ipv == (u8) ~ 0) - udp_register_dst_port (vm, port, udp4_punt_node.index, 1); + if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP) + return clib_error_return (0, + "punt TCP/SCTP ports is not supported yet"); - if (ipv == 6 || ipv == (u8) ~ 0) - udp_register_dst_port (vm, port, udp6_punt_node.index, 0); + if (!udp_is_valid_dst_port (port, af == AF_IP4)) + return clib_error_return (0, "invalid port: %d", port); + + udp_register_dst_port (vm, port, udp4_punt_node.index, af == AF_IP4); return 0; } - else - return clib_error_return (0, "punt delete is not supported yet"); + { + if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP) + return clib_error_return (0, + "punt TCP/SCTP ports is not supported yet"); + + udp_unregister_dst_port (vm, port, af == AF_IP4); + + return 0; + } } static clib_error_t * -udp_punt_cli (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +punt_exception_add_del (vlib_main_t * vm, + vlib_punt_reason_t reason, bool is_add) { - u32 udp_port; - int is_add = 1; - clib_error_t *error; + return (NULL); +} + +clib_error_t * +vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add) +{ + switch (pr->type) + { + case PUNT_TYPE_L4: + return (punt_l4_add_del (vm, pr->punt.l4.af, pr->punt.l4.protocol, + pr->punt.l4.port, is_add)); + case PUNT_TYPE_EXCEPTION: + return (punt_exception_add_del (vm, pr->punt.exception.reason, is_add)); + } + + return (clib_error_return (0, "Unsupported punt type: %d", pr->type)); +} + +static clib_error_t * +punt_cli (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = NULL; + bool is_add = true; + punt_reg_t pr = { + .punt = { + .l4 = { + .af = AF_IP4, + .port = ~0, + .protocol = ~0, + }, + }, + .type = PUNT_TYPE_L4, + }; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "del")) - is_add = 0; - if (unformat (input, "all")) + is_add = false; + else if (unformat (input, "ipv6")) + pr.punt.l4.af = AF_IP6; + else if (unformat (input, "ip6")) + pr.punt.l4.af = AF_IP6; + else if (unformat (input, "%d", &pr.punt.l4.port)) + ; + else if (unformat (input, "udp")) + pr.punt.l4.protocol = IP_PROTOCOL_UDP; + else if (unformat (input, "tcp")) + pr.punt.l4.protocol = IP_PROTOCOL_TCP; + else { - /* 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 */ - error = vnet_punt_add_del (vm, ~0, IP_PROTOCOL_UDP, - udp_port, is_add); - if (error) - clib_error_report (error); + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, input); + goto done; } } - return 0; + /* punt both IPv6 and IPv4 when used in CLI */ + error = vnet_punt_add_del (vm, &pr, is_add); + if (error) + { + clib_error_report (error); + } + +done: + return error; } /*? @@ -307,13 +423,335 @@ 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* */ +static clib_error_t * +punt_socket_register_cmd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u8 *socket_name = 0; + clib_error_t *error = NULL; + /* *INDENT-OFF* */ + punt_reg_t pr = { + .punt = { + .l4 = { + .af = AF_IP4, + .port = ~0, + .protocol = ~0, + }, + }, + .type = PUNT_TYPE_L4, + }; + /* *INDENT-ON* */ + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ipv4")) + ; + else if (unformat (input, "ipv6")) + pr.punt.l4.af = AF_IP6; + else if (unformat (input, "udp")) + pr.punt.l4.protocol = IP_PROTOCOL_UDP; + else if (unformat (input, "tcp")) + pr.punt.l4.protocol = IP_PROTOCOL_TCP; + else if (unformat (input, "%d", &pr.punt.l4.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, &pr, (char *) socket_name); + +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]> ", + .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) +{ + clib_error_t *error = NULL; + /* *INDENT-OFF* */ + punt_reg_t pr = { + .punt = { + .l4 = { + .af = AF_IP4, + .port = ~0, + .protocol = ~0, + }, + }, + .type = PUNT_TYPE_L4, + }; + /* *INDENT-ON* */ + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ipv4")) + ; + else if (unformat (input, "ipv6")) + pr.punt.l4.af = AF_IP6; + else if (unformat (input, "udp")) + pr.punt.l4.protocol = IP_PROTOCOL_UDP; + else if (unformat (input, "tcp")) + pr.punt.l4.protocol = IP_PROTOCOL_TCP; + else if (unformat (input, "%d", &pr.punt.l4.port)) + ; + else + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, input); + goto done; + } + } + + error = vnet_punt_socket_del (vm, &pr); +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]> ", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +void +punt_client_walk (punt_type_t pt, punt_client_walk_cb_t cb, void *ctx) +{ + punt_main_t *pm = &punt_main; + + switch (pt) + { + case PUNT_TYPE_L4: + { + u32 pci; + u16 port; + + /* *INDENT-OFF* */ + hash_foreach(port, pci, pm->db.clients_by_l4_port, + ({ + cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx); + })); + /* *INDENT-ON* */ + break; + } + case PUNT_TYPE_EXCEPTION: + { + u32 *pci; + + vec_foreach (pci, pm->db.clients_by_exception) + { + if (~0 != *pci) + cb (pool_elt_at_index (pm->punt_client_pool, *pci), ctx); + } + + break; + } + } +} + +static u8 * +format_punt_client (u8 * s, va_list * args) +{ + punt_client_t *pc = va_arg (*args, punt_client_t *); + + s = format (s, " punt "); + + switch (pc->reg.type) + { + case PUNT_TYPE_L4: + s = format (s, "%U %U port %d", + format_ip_address_family, pc->reg.punt.l4.af, + format_ip_protocol, pc->reg.punt.l4.protocol, + pc->reg.punt.l4.port); + break; + case PUNT_TYPE_EXCEPTION: + s = format (s, " %U", format_vlib_punt_reason, + pc->reg.punt.exception.reason); + break; + } + + s = format (s, " to socket %s \n", pc->caddr.sun_path); + + return (s); +} + +static walk_rc_t +punt_client_show_one (const punt_client_t * pc, void *ctx) +{ + vlib_cli_output (ctx, "%U", format_punt_client, pc); + + return (WALK_CONTINUE); +} + +static clib_error_t * +punt_socket_show_cmd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = NULL; + punt_type_t pt; + + pt = PUNT_TYPE_L4; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "exception")) + pt = PUNT_TYPE_EXCEPTION; + else if (unformat (input, "l4")) + pt = PUNT_TYPE_L4; + else + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, input); + goto done; + } + } + + punt_client_walk (pt, punt_client_show_one, vm); + +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 [l4|exception]", + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + +clib_error_t * +ip_punt_init (vlib_main_t * vm) +{ + clib_error_t *error = NULL; + punt_main_t *pm = &punt_main; + + pm->is_configured = false; + pm->interface_output_node = + vlib_get_node_by_name (vm, (u8 *) "interface-output"); + + if ((error = vlib_call_init_function (vm, punt_init))) + return error; + + pm->hdl = vlib_punt_client_register ("ip-punt"); + + return (error); +} + +VLIB_INIT_FUNCTION (ip_punt_init); + +static clib_error_t * +punt_config (vlib_main_t * vm, unformat_input_t * input) +{ + punt_main_t *pm = &punt_main; + char *socket_path = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "socket %s", &socket_path)) + strncpy (pm->sun_path, socket_path, UNIX_PATH_MAX - 1); + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + if (socket_path == 0) + return 0; + + /* UNIX domain socket */ + struct sockaddr_un addr; + if ((pm->socket_fd = socket (AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1) + { + return clib_error_return (0, "socket error"); + } + + clib_memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_UNIX; + if (*socket_path == '\0') + { + *addr.sun_path = '\0'; + strncpy (addr.sun_path + 1, socket_path + 1, + sizeof (addr.sun_path) - 2); + } + else + { + strncpy (addr.sun_path, socket_path, sizeof (addr.sun_path) - 1); + unlink (socket_path); + } + + if (bind (pm->socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) + { + return clib_error_return (0, "bind error"); + } + + int n_bytes = 0x10000; + + if (setsockopt + (pm->socket_fd, SOL_SOCKET, SO_SNDBUF, &n_bytes, + sizeof (n_bytes)) == -1) + { + return clib_error_return (0, "setsockopt error"); + } + + /* Register socket */ + 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; + template.description = format (0, "%s", socket_path); + pm->clib_file_index = clib_file_add (fm, &template); + + pm->is_configured = true; + + return 0; +} + +VLIB_CONFIG_FUNCTION (punt_config, "punt"); + /* * fd.io coding-style-patch-verification: ON *