#include <vnet/ip/ip.h>
#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 <vlib/unix/unix.h>
return (index);
}
+static void
+punt_client_ip_proto_db_add (ip_address_family_t af,
+ ip_protocol_t proto, u32 index)
+{
+ punt_main_t *pm = &punt_main;
+
+ pm->db.clients_by_ip_proto = hash_set (pm->db.clients_by_ip_proto,
+ punt_client_ip_proto_mk_key (af,
+ proto),
+ index);
+}
+
+static u32
+punt_client_ip_proto_db_remove (ip_address_family_t af, ip_protocol_t proto)
+{
+ punt_main_t *pm = &punt_main;
+ u32 key, index = ~0;
+ uword *p;
+
+ key = punt_client_ip_proto_mk_key (af, proto);
+ p = hash_get (pm->db.clients_by_ip_proto, key);
+
+ if (p)
+ index = p[0];
+
+ hash_unset (pm->db.clients_by_ip_proto, key);
+
+ return (index);
+}
+
static void
punt_client_exception_db_add (vlib_punt_reason_t reason, u32 pci)
{
if (port == (u16) ~ 0)
return clib_error_return (0, "UDP port number required");
- 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);
if (NULL == c)
return (NULL);
}
+static clib_error_t *
+punt_socket_register_ip_proto (vlib_main_t * vm,
+ ip_address_family_t af,
+ ip_protocol_t proto, char *client_pathname)
+{
+ punt_main_t *pm = &punt_main;
+ punt_client_t *c;
+
+ c = punt_client_ip_proto_get (af, proto);
+
+ if (NULL == c)
+ {
+ pool_get_zero (pm->punt_client_pool, c);
+ punt_client_ip_proto_db_add (af, proto, 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_IP_PROTO;
+ c->reg.punt.ip_proto.protocol = proto;
+ c->reg.punt.ip_proto.af = af;
+
+ if (af == AF_IP4)
+ ip4_register_protocol (proto, ip4_proto_punt_socket_node.index);
+ else
+ ip6_register_protocol (proto, ip6_proto_punt_socket_node.index);
+
+ return (NULL);
+}
+
static clib_error_t *
punt_socket_register_exception (vlib_main_t * vm,
vlib_punt_reason_t reason,
return (NULL);
}
+static clib_error_t *
+punt_socket_unregister_ip_proto (ip_address_family_t af, ip_protocol_t proto)
+{
+ u32 pci;
+
+ if (af == AF_IP4)
+ ip4_unregister_protocol (proto);
+ else
+ ip6_unregister_protocol (proto);
+
+ pci = punt_client_ip_proto_db_remove (af, proto);
+
+ if (~0 != pci)
+ pool_put_index (punt_main.punt_client_pool, pci);
+
+ return (NULL);
+}
+
static clib_error_t *
punt_socket_unregister_exception (vlib_punt_reason_t reason)
{
if (header_version != PUNT_PACKETDESC_VERSION)
return clib_error_return (0, "Invalid packet descriptor version");
+ 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);
+
/* Register client */
switch (pr->type)
{
pr->punt.l4.af,
pr->punt.l4.protocol,
pr->punt.l4.port, client_pathname));
+ case PUNT_TYPE_IP_PROTO:
+ return (punt_socket_register_ip_proto (vm,
+ pr->punt.ip_proto.af,
+ pr->punt.ip_proto.protocol,
+ client_pathname));
case PUNT_TYPE_EXCEPTION:
return (punt_socket_register_exception (vm,
pr->punt.exception.reason,
return (punt_socket_unregister_l4 (pr->punt.l4.af,
pr->punt.l4.protocol,
pr->punt.l4.port));
+ case PUNT_TYPE_IP_PROTO:
+ return (punt_socket_unregister_ip_proto (pr->punt.ip_proto.af,
+ pr->punt.ip_proto.protocol));
case PUNT_TYPE_EXCEPTION:
return (punt_socket_unregister_exception (pr->punt.exception.reason));
}
}
/**
- * @brief Request IP traffic punt to the local TCP/IP stack.
+ * @brief Request IP L4 traffic punt to the local TCP/IP stack.
*
* @em Note
- * - UDP, TCP and SCTP are the only protocols supported in the current implementation
+ * - UDP is the only protocol supported in the current implementation
*
* @param vm vlib_main_t corresponding to the current thread
* @param af IP address family.
ip_address_family_t af,
ip_protocol_t protocol, u16 port, bool is_add)
{
- /* For now we only support TCP, UDP and SCTP punt */
- if (protocol != IP_PROTOCOL_UDP &&
- protocol != IP_PROTOCOL_TCP && protocol != IP_PROTOCOL_SCTP)
+ /* For now we only support TCP and UDP punt */
+ if (protocol != IP_PROTOCOL_UDP && protocol != IP_PROTOCOL_TCP)
return clib_error_return (0,
- "only UDP (%d), TCP (%d) and SCTP (%d) protocols are supported, got %d",
- IP_PROTOCOL_UDP, IP_PROTOCOL_TCP,
- IP_PROTOCOL_SCTP, protocol);
+ "only UDP (%d) and TCP (%d) protocols are supported, got %d",
+ IP_PROTOCOL_UDP, IP_PROTOCOL_TCP, protocol);
if (port == (u16) ~ 0)
{
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 (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP)
- return clib_error_return (0,
- "punt TCP/SCTP ports is not supported yet");
-
- if (!udp_is_valid_dst_port (port, af == AF_IP4))
- return clib_error_return (0, "invalid port: %d", port);
+ if (protocol == IP_PROTOCOL_TCP)
+ return clib_error_return (0, "punt TCP ports is not supported yet");
udp_register_dst_port (vm, port, udp4_punt_node.index, af == AF_IP4);
}
else
{
- if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_SCTP)
- return clib_error_return (0,
- "punt TCP/SCTP ports is not supported yet");
+ if (protocol == IP_PROTOCOL_TCP)
+ return clib_error_return (0, "punt TCP ports is not supported yet");
udp_unregister_dst_port (vm, port, af == AF_IP4);
}
}
-static clib_error_t *
-punt_exception_add_del (vlib_main_t * vm,
- vlib_punt_reason_t reason, bool is_add)
-{
- return (NULL);
-}
-
clib_error_t *
vnet_punt_add_del (vlib_main_t * vm, const punt_reg_t * pr, bool is_add)
{
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));
+ case PUNT_TYPE_IP_PROTO:
+ break;
}
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)
+ unformat_input_t * input__, vlib_cli_command_t * cmd)
{
+ unformat_input_t line_input, *input = &line_input;
clib_error_t *error = NULL;
bool is_add = true;
+ /* *INDENT-OFF* */
punt_reg_t pr = {
.punt = {
- .l4 = {
- .af = AF_IP4,
- .port = ~0,
- .protocol = ~0,
- },
- },
+ .l4 = {
+ .af = AF_IP4,
+ .port = ~0,
+ .protocol = IP_PROTOCOL_UDP,
+ },
+ },
.type = PUNT_TYPE_L4,
};
+ u32 port;
+ /* *INDENT-ON* */
+
+ if (!unformat_user (input__, unformat_line_input, input))
+ return 0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "del"))
is_add = false;
+ else if (unformat (input, "ipv4"))
+ pr.punt.l4.af = AF_IP4;
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, "%d", &port))
+ pr.punt.l4.port = port;
+ else if (unformat (input, "all"))
+ pr.punt.l4.port = ~0;
else if (unformat (input, "udp"))
pr.punt.l4.protocol = IP_PROTOCOL_UDP;
else if (unformat (input, "tcp"))
}
done:
+ unformat_free (input);
return error;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (punt_command, static) = {
.path = "set punt",
- .short_help = "set punt [udp|tcp] [del] <all | port-num1 [port-num2 ...]>",
+ .short_help = "set punt [IPV4|ip6|ipv6] [UDP|tcp] [del] [ALL|<port-num>]",
.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)
+ unformat_input_t * input__,
+ vlib_cli_command_t * cmd)
{
+ unformat_input_t line_input, *input = &line_input;
u8 *socket_name = 0;
clib_error_t *error = NULL;
/* *INDENT-OFF* */
.l4 = {
.af = AF_IP4,
.port = ~0,
- .protocol = ~0,
+ .protocol = IP_PROTOCOL_UDP,
},
},
.type = PUNT_TYPE_L4,
};
/* *INDENT-ON* */
+ if (!unformat_user (input__, unformat_line_input, input))
+ return 0;
+
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "ipv4"))
- ;
+ pr.punt.l4.af = AF_IP4;
else if (unformat (input, "ipv6"))
pr.punt.l4.af = AF_IP6;
else if (unformat (input, "udp"))
pr.punt.l4.protocol = IP_PROTOCOL_TCP;
else if (unformat (input, "%d", &pr.punt.l4.port))
;
+ else if (unformat (input, "all"))
+ pr.punt.l4.port = ~0;
else if (unformat (input, "socket %s", &socket_name))
;
else
}
}
- error = vnet_punt_socket_add (vm, 1, &pr, (char *) socket_name);
+ if (!socket_name)
+ error = clib_error_return (0, "socket name not specified");
+ else
+ error = vnet_punt_socket_add (vm, 1, &pr, (char *) socket_name);
done:
+ unformat_free (input);
return error;
}
/*?
*
* @cliexpar
- * @cliexcmd{punt socket register}
+ * @cliexcmd{punt socket register socket punt_l4_foo.sock}
+
?*/
/* *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>",
+ .short_help = "punt socket register [IPV4|ipv6] [UDP|tcp] [ALL|<port-num>] socket <socket>",
.is_mp_safe = 1,
};
/* *INDENT-ON* */
static clib_error_t *
punt_socket_deregister_cmd (vlib_main_t * vm,
- unformat_input_t * input,
+ unformat_input_t * input__,
vlib_cli_command_t * cmd)
{
+ unformat_input_t line_input, *input = &line_input;
clib_error_t *error = NULL;
/* *INDENT-OFF* */
punt_reg_t pr = {
.l4 = {
.af = AF_IP4,
.port = ~0,
- .protocol = ~0,
+ .protocol = IP_PROTOCOL_UDP,
},
},
.type = PUNT_TYPE_L4,
};
/* *INDENT-ON* */
+ if (!unformat_user (input__, unformat_line_input, input))
+ return 0;
+
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "ipv4"))
- ;
+ pr.punt.l4.af = AF_IP4;
else if (unformat (input, "ipv6"))
pr.punt.l4.af = AF_IP6;
else if (unformat (input, "udp"))
pr.punt.l4.protocol = IP_PROTOCOL_TCP;
else if (unformat (input, "%d", &pr.punt.l4.port))
;
+ else if (unformat (input, "all"))
+ pr.punt.l4.port = ~0;
else
{
error = clib_error_return (0, "parse error: '%U'",
error = vnet_punt_socket_del (vm, &pr);
done:
+ unformat_free (input);
return error;
}
{
.path = "punt socket deregister",
.function = punt_socket_deregister_cmd,
- .short_help = "punt socket deregister [ipv4|ipv6] [udp|tcp]> <all | port-num1 [port-num2 ...]>",
+ .short_help = "punt socket deregister [IPV4|ipv6] [UDP|tcp] [ALL|<port-num>]",
.is_mp_safe = 1,
};
/* *INDENT-ON* */
{
case PUNT_TYPE_L4:
{
- u32 pci;
- u16 port;
+ u32 pci, key;
/* *INDENT-OFF* */
- hash_foreach(port, pci, pm->db.clients_by_l4_port,
+ hash_foreach(key, pci, pm->db.clients_by_l4_port,
+ ({
+ cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
+ }));
+ /* *INDENT-ON* */
+ break;
+ }
+ case PUNT_TYPE_IP_PROTO:
+ {
+ u32 pci, key;
+
+ /* *INDENT-OFF* */
+ hash_foreach(key, pci, pm->db.clients_by_ip_proto,
({
cb (pool_elt_at_index(pm->punt_client_pool, pci), ctx);
}));
format_ip_protocol, pc->reg.punt.l4.protocol,
pc->reg.punt.l4.port);
break;
+ case PUNT_TYPE_IP_PROTO:
+ s = format (s, "%U %U",
+ format_ip_address_family, pc->reg.punt.ip_proto.af,
+ format_ip_protocol, pc->reg.punt.ip_proto.protocol);
+ break;
case PUNT_TYPE_EXCEPTION:
s = format (s, " %U", format_vlib_punt_reason,
pc->reg.punt.exception.reason);
static clib_error_t *
punt_socket_show_cmd (vlib_main_t * vm,
- unformat_input_t * input, vlib_cli_command_t * cmd)
+ unformat_input_t * input__, vlib_cli_command_t * cmd)
{
+ unformat_input_t line_input, *input = &line_input;
clib_error_t *error = NULL;
punt_type_t pt;
pt = PUNT_TYPE_L4;
+ if (!unformat_user (input__, unformat_line_input, input))
+ return 0;
+
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 if (unformat (input, "ip"))
+ pt = PUNT_TYPE_IP_PROTO;
else
{
error = clib_error_return (0, "parse error: '%U'",
punt_client_walk (pt, punt_client_show_one, vm);
done:
+ unformat_free (input);
return (error);
}
{
clib_error_t *error = NULL;
punt_main_t *pm = &punt_main;
+ vlib_thread_main_t *tm = vlib_get_thread_main ();
pm->is_configured = false;
pm->interface_output_node =
pm->hdl = vlib_punt_client_register ("ip-punt");
+ vec_validate_aligned (pm->thread_data, tm->n_vlib_mains,
+ CLIB_CACHE_LINE_BYTES);
+
return (error);
}
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);
+ template.description = format (0, "punt socket %s", socket_path);
pm->clib_file_index = clib_file_add (fm, &template);
pm->is_configured = true;