From 1a9e2f96d48e346311bbc584510a14e3f721b41c Mon Sep 17 00:00:00 2001 From: Nathan Skrzypczak Date: Wed, 28 Jul 2021 19:35:08 +0200 Subject: session: Add sock_name option to add_ns This adds a new API call to add session namespaces It now takes a netns and a sock_name. (1) If no netns is passed, sock_name will be used as socket path. Defaulting to /run/vpp/app_ns_sockets/${ns_id} (2) If a netns is passed, the sock_name has to be abstract (i.e. start with '@'). It will default to `@vpp/session/${ns_id}` and will be created in the provided netns. Type: feature Change-Id: I90e9a8e5ecca2cabe7c05335663e33c8506dc9e7 Signed-off-by: Nathan Skrzypczak --- src/vnet/session/application_namespace.c | 80 ++++++++++++++++++++++--------- src/vnet/session/application_namespace.h | 7 +-- src/vnet/session/session.api | 35 ++++++++++++++ src/vnet/session/session_api.c | 81 +++++++++++++++++++++++++++----- src/vnet/session/session_lookup.c | 24 ++++++---- 5 files changed, 183 insertions(+), 44 deletions(-) diff --git a/src/vnet/session/application_namespace.c b/src/vnet/session/application_namespace.c index 6d91fc362b2..c1061c08e27 100644 --- a/src/vnet/session/application_namespace.c +++ b/src/vnet/session/application_namespace.c @@ -40,7 +40,7 @@ app_namespace_get (u32 index) } app_namespace_t * -app_namespace_get_from_id (const u8 * ns_id) +app_namespace_get_from_id (const u8 *ns_id) { u32 index = app_namespace_index_from_id (ns_id); if (index == APP_NAMESPACE_INVALID_INDEX) @@ -55,14 +55,19 @@ app_namespace_index (app_namespace_t * app_ns) } app_namespace_t * -app_namespace_alloc (u8 * ns_id) +app_namespace_alloc (const u8 *ns_id) { app_namespace_t *app_ns; + pool_get (app_namespace_pool, app_ns); clib_memset (app_ns, 0, sizeof (*app_ns)); - app_ns->ns_id = vec_dup (ns_id); + + app_ns->ns_id = vec_dup ((u8 *) ns_id); + vec_terminate_c_string (app_ns->ns_id); + hash_set_mem (app_namespace_lookup_table, app_ns->ns_id, app_ns - app_namespace_pool); + return app_ns; } @@ -71,6 +76,7 @@ vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t * a) { app_namespace_t *app_ns; session_table_t *st; + int rv; if (a->is_add) { @@ -105,6 +111,7 @@ vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t * a) } app_ns->ns_secret = a->secret; app_ns->netns = a->netns ? vec_dup (a->netns) : 0; + app_ns->sock_name = a->sock_name ? vec_dup (a->sock_name) : 0; app_ns->sw_if_index = a->sw_if_index; app_ns->ip4_fib_index = fib_table_find (FIB_PROTOCOL_IP4, a->ip4_fib_id); @@ -114,7 +121,11 @@ vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t * a) /* Add socket for namespace */ if (app_sapi_enabled) - appns_sapi_add_ns_socket (app_ns); + { + rv = appns_sapi_add_ns_socket (app_ns); + if (rv) + return rv; + } } else { @@ -133,7 +144,13 @@ u32 app_namespace_index_from_id (const u8 * ns_id) { uword *indexp; - indexp = hash_get_mem (app_namespace_lookup_table, ns_id); + u8 *key; + + key = vec_dup ((u8 *) ns_id); + vec_terminate_c_string (key); + + indexp = hash_get_mem (app_namespace_lookup_table, key); + vec_free (key); if (!indexp) return APP_NAMESPACE_INVALID_INDEX; return *indexp; @@ -190,6 +207,7 @@ app_namespaces_init (void) vnet_app_namespace_add_del_args_t a = { .ns_id = ns_id, .netns = 0, + .sock_name = 0, .secret = 0, .sw_if_index = APP_NAMESPACE_INVALID_INDEX, .is_add = 1 @@ -204,9 +222,11 @@ static clib_error_t * app_ns_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - u8 is_add = 0, *ns_id = 0, secret_set = 0, sw_if_index_set = 0, *netns = 0; + u8 is_add = 0, *ns_id = 0, secret_set = 0, sw_if_index_set = 0; + u8 *netns = 0, *sock_name = 0; unformat_input_t _line_input, *line_input = &_line_input; u32 sw_if_index, fib_id = APP_NAMESPACE_INVALID_INDEX; + vnet_main_t *vnm = vnet_get_main (); u64 secret; clib_error_t *error = 0; int rv; @@ -226,10 +246,15 @@ app_ns_fn (vlib_main_t * vm, unformat_input_t * input, secret_set = 1; else if (unformat (line_input, "sw_if_index %u", &sw_if_index)) sw_if_index_set = 1; + else if (unformat (line_input, "if %U", unformat_vnet_sw_interface, vnm, + &sw_if_index)) + sw_if_index_set = 1; else if (unformat (line_input, "fib_id", &fib_id)) ; else if (unformat (line_input, "netns %_%v%_", &netns)) ; + else if (unformat (line_input, "sock-name %_%v%_", &sock_name)) + ; else { error = clib_error_return (0, "unknown input `%U'", @@ -240,8 +265,8 @@ app_ns_fn (vlib_main_t * vm, unformat_input_t * input, if (!ns_id || !secret_set || !sw_if_index_set) { - vlib_cli_output (vm, "namespace-id, secret and sw_if_index must be " - "provided"); + vlib_cli_output (vm, "namespace-id, secret and interface must be " + "provided"); goto done; } @@ -251,6 +276,7 @@ app_ns_fn (vlib_main_t * vm, unformat_input_t * input, vnet_app_namespace_add_del_args_t args = { .ns_id = ns_id, .netns = netns, + .sock_name = sock_name, .secret = secret, .sw_if_index = sw_if_index, .ip4_fib_id = fib_id, @@ -266,6 +292,7 @@ done: vec_free (ns_id); vec_free (netns); + vec_free (sock_name); unformat_free (line_input); return error; @@ -275,7 +302,7 @@ done: VLIB_CLI_COMMAND (app_ns_command, static) = { .path = "app ns", .short_help = "app ns [add] id secret " - "sw_if_index [netns ]", + "if [netns ]", .function = app_ns_fn, }; /* *INDENT-ON* */ @@ -284,11 +311,18 @@ u8 * format_app_namespace (u8 * s, va_list * args) { app_namespace_t *app_ns = va_arg (*args, app_namespace_t *); + vnet_main_t *vnm = vnet_get_main (); + + s = format (s, "Application namespace [%u]\nid: %s\nsecret: %lu", + app_namespace_index (app_ns), app_ns->ns_id, app_ns->ns_secret); + if (app_ns->sw_if_index != (u32) ~0) + s = format (s, "\nInterface: %U", format_vnet_sw_if_index_name, vnm, + app_ns->sw_if_index); + if (app_ns->netns) + s = format (s, "\nNetns: %s", app_ns->netns); + if (app_ns->sock_name) + s = format (s, "\nSocket: %s", app_ns->sock_name); - s = - format (s, "%-10u%-10lu%-15d%-15v%-15v%-40v", app_namespace_index (app_ns), - app_ns->ns_secret, app_ns->sw_if_index, app_ns->ns_id, - app_ns->netns, app_ns->sock_name); return s; } @@ -335,8 +369,9 @@ show_app_ns_fn (vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - u8 *ns_id, do_table = 0, had_input = 1, do_api = 0; + u8 *ns_id = 0, do_table = 0, had_input = 1, do_api = 0; app_namespace_t *app_ns; + vnet_main_t *vnm = vnet_get_main (); session_table_t *st; session_cli_return_if_not_enabled (); @@ -349,7 +384,7 @@ show_app_ns_fn (vlib_main_t * vm, unformat_input_t * main_input, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat (line_input, "table %_%v%_", &ns_id)) + if (unformat (line_input, "id %_%v%_", &ns_id)) do_table = 1; else if (unformat (line_input, "api-clients")) do_api = 1; @@ -386,18 +421,22 @@ show_app_ns_fn (vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_output (vm, "table for ns %v could not be found", ns_id); goto done; } + vlib_cli_output (vm, "%U", format_app_namespace, app_ns); session_lookup_show_table_entries (vm, st, 0, 1); vec_free (ns_id); goto done; } do_ns_list: - vlib_cli_output (vm, "%-10s%-10s%-15s%-15s%-15s%-40s", "Index", "Secret", - "sw_if_index", "Id", "netns", "Socket"); + vlib_cli_output (vm, "%-10s%-10s%-12s%-15s%-20s%-40s", "Index", "Secret", + "Interface", "Id", "Netns", "Socket"); /* *INDENT-OFF* */ pool_foreach (app_ns, app_namespace_pool) { - vlib_cli_output (vm, "%U", format_app_namespace, app_ns); + vlib_cli_output (vm, "%-10u%-10lu%-12U%-15s%-20s%-40v", + app_namespace_index (app_ns), app_ns->ns_secret, + format_vnet_sw_if_index_name, vnm, app_ns->sw_if_index, + app_ns->ns_id, app_ns->netns, app_ns->sock_name); } /* *INDENT-ON* */ @@ -408,10 +447,9 @@ done: } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_app_ns_command, static) = -{ +VLIB_CLI_COMMAND (show_app_ns_command, static) = { .path = "show app ns", - .short_help = "show app ns [table [api-clients]]", + .short_help = "show app ns [id [api-clients]]", .function = show_app_ns_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/session/application_namespace.h b/src/vnet/session/application_namespace.h index 313b2d0e63d..5449d4755c3 100644 --- a/src/vnet/session/application_namespace.h +++ b/src/vnet/session/application_namespace.h @@ -70,6 +70,7 @@ typedef struct _vnet_app_namespace_add_del_args { u8 *ns_id; u8 *netns; + u8 *sock_name; u64 secret; u32 sw_if_index; u32 ip4_fib_id; @@ -79,13 +80,13 @@ typedef struct _vnet_app_namespace_add_del_args #define APP_NAMESPACE_INVALID_INDEX ((u32)~0) -app_namespace_t *app_namespace_alloc (u8 * ns_id); +app_namespace_t *app_namespace_alloc (const u8 *ns_id); app_namespace_t *app_namespace_get (u32 index); -app_namespace_t *app_namespace_get_from_id (const u8 * ns_id); +app_namespace_t *app_namespace_get_from_id (const u8 *ns_id); u32 app_namespace_index (app_namespace_t * app_ns); const u8 *app_namespace_id (app_namespace_t * app_ns); const u8 *app_namespace_id_from_index (u32 index); -u32 app_namespace_index_from_id (const u8 * ns_id); +u32 app_namespace_index_from_id (const u8 *ns_id); void app_namespaces_init (void); int vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t * a); u32 app_namespace_get_fib_index (app_namespace_t * app_ns, u8 fib_proto); diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api index 43bde1afbbd..0eb773c0c28 100644 --- a/src/vnet/session/session.api +++ b/src/vnet/session/session.api @@ -252,6 +252,34 @@ define app_namespace_add_del_v2 { string netns[64]; }; +/** \brief add/del application namespace + @param client_index - opaque cookie to identify the sender + client to vpp direction only + @param context - sender context, to match reply w/ request + @param secret - secret shared between app and vpp + @param sw_if_index - local interface that "supports" namespace. Set to + ~0 if no preference + @param ip4_fib_id - id of ip4 fib that "supports" the namespace. Ignored + if sw_if_index set. + @param ip6_fib_id - id of ip6 fib that "supports" the namespace. Ignored + if sw_if_index set. + @param namespace_id - namespace id + @param netns - linux net namespace + @param sock_name - socket name (path, abstract socket name) +*/ +define app_namespace_add_del_v3 { + u32 client_index; + u32 context; + u64 secret; + bool is_add [default=true]; + vl_api_interface_index_t sw_if_index [default=0xffffffff]; + u32 ip4_fib_id; + u32 ip6_fib_id; + string namespace_id[64]; + string netns[64]; + string sock_name[]; +}; + /** \brief Reply for app namespace add/del @param context - returned sender context, to match reply w/ request @param retval - return code @@ -277,6 +305,13 @@ define app_namespace_add_del_v2_reply u32 appns_index; }; +define app_namespace_add_del_v3_reply +{ + u32 context; + i32 retval; + u32 appns_index; +}; + enum session_rule_scope { SESSION_RULE_SCOPE_API_GLOBAL = 0, SESSION_RULE_SCOPE_API_LOCAL = 1, diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c index 371fcfc9271..c0ed1250dab 100644 --- a/src/vnet/session/session_api.c +++ b/src/vnet/session/session_api.c @@ -834,6 +834,8 @@ vl_api_app_namespace_add_del_t_handler (vl_api_app_namespace_add_del_t * mp) vnet_app_namespace_add_del_args_t args = { .ns_id = ns_id, + .netns = 0, + .sock_name = 0, .secret = clib_net_to_host_u64 (mp->secret), .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index), .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id), @@ -884,6 +886,7 @@ vl_api_app_namespace_add_del_v2_t_handler ( vnet_app_namespace_add_del_args_t args = { .ns_id = ns_id, .netns = netns, + .sock_name = 0, .secret = clib_net_to_host_u64 (mp->secret), .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index), .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id), @@ -896,7 +899,7 @@ vl_api_app_namespace_add_del_v2_t_handler ( appns_index = app_namespace_index_from_id (ns_id); if (appns_index == APP_NAMESPACE_INVALID_INDEX) { - clib_warning ("app ns lookup failed"); + clib_warning ("app ns lookup failed id:%s", ns_id); rv = VNET_API_ERROR_UNSPECIFIED; } } @@ -910,6 +913,54 @@ done: })); } +static void +vl_api_app_namespace_add_del_v3_t_handler ( + vl_api_app_namespace_add_del_v3_t *mp) +{ + vl_api_app_namespace_add_del_v3_reply_t *rmp; + u8 *ns_id = 0, *netns = 0, *sock_name = 0; + u32 appns_index = 0; + int rv = 0; + if (session_main_is_enabled () == 0) + { + rv = VNET_API_ERROR_FEATURE_DISABLED; + goto done; + } + mp->namespace_id[sizeof (mp->namespace_id) - 1] = 0; + mp->netns[sizeof (mp->netns) - 1] = 0; + ns_id = format (0, "%s", &mp->namespace_id); + netns = format (0, "%s", &mp->netns); + sock_name = format (0, "%s", &mp->sock_name); + vnet_app_namespace_add_del_args_t args = { + .ns_id = ns_id, + .netns = netns, + .sock_name = sock_name, + .secret = clib_net_to_host_u64 (mp->secret), + .sw_if_index = clib_net_to_host_u32 (mp->sw_if_index), + .ip4_fib_id = clib_net_to_host_u32 (mp->ip4_fib_id), + .ip6_fib_id = clib_net_to_host_u32 (mp->ip6_fib_id), + .is_add = mp->is_add, + }; + rv = vnet_app_namespace_add_del (&args); + if (!rv && mp->is_add) + { + appns_index = app_namespace_index_from_id (ns_id); + if (appns_index == APP_NAMESPACE_INVALID_INDEX) + { + clib_warning ("app ns lookup failed id:%s", ns_id); + rv = VNET_API_ERROR_UNSPECIFIED; + } + } + vec_free (ns_id); + vec_free (netns); + vec_free (sock_name); +done: + REPLY_MACRO2 (VL_API_APP_NAMESPACE_ADD_DEL_V3_REPLY, ({ + if (!rv) + rmp->appns_index = clib_host_to_net_u32 (appns_index); + })); +} + static void vl_api_session_rule_add_del_t_handler (vl_api_session_rule_add_del_t * mp) { @@ -1722,19 +1773,27 @@ appns_sapi_add_ns_socket (app_namespace_t * app_ns) clib_socket_t *cs; char dir[4096]; - snprintf (dir, sizeof (dir), "%s%s", vlib_unix_get_runtime_dir (), subdir); - err = vlib_unix_recursive_mkdir ((char *) dir); - if (err) + if (app_ns->netns) { - clib_error_report (err); - return -1; + if (!app_ns->sock_name) + app_ns->sock_name = format (0, "@vpp/session/%v%c", app_ns->ns_id, 0); + if (app_ns->sock_name[0] != '@') + return VNET_API_ERROR_INVALID_VALUE; } - - /* Use abstract sockets if a netns was provided */ - if (app_ns->netns) - app_ns->sock_name = format (0, "@vpp/session/%v%c", app_ns->ns_id, 0); else - app_ns->sock_name = format (0, "%s%v%c", dir, app_ns->ns_id, 0); + { + snprintf (dir, sizeof (dir), "%s%s", vlib_unix_get_runtime_dir (), + subdir); + err = vlib_unix_recursive_mkdir ((char *) dir); + if (err) + { + clib_error_report (err); + return VNET_API_ERROR_SYSCALL_ERROR_1; + } + + if (!app_ns->sock_name) + app_ns->sock_name = format (0, "%s%v%c", dir, app_ns->ns_id, 0); + } /* * Create and initialize socket to listen on diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c index 6e060cb119d..5cd1712f195 100644 --- a/src/vnet/session/session_lookup.c +++ b/src/vnet/session/session_lookup.c @@ -1452,6 +1452,7 @@ session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen = 0, rmt_plen = 0; + clib_error_t *error = 0; u32 appns_index, scope = 0; ip46_address_t lcl_ip, rmt_ip; u8 is_ip4 = 1, conn_set = 0; @@ -1501,29 +1502,32 @@ session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input, else if (unformat (input, "tag %_%v%_", &tag)) ; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + goto done; + } } if (proto == ~0) { vlib_cli_output (vm, "proto must be set"); - return 0; + goto done; } if (is_add && !conn_set && action == ~0) { vlib_cli_output (vm, "connection and action must be set for add"); - return 0; + goto done; } if (!is_add && !tag && !conn_set) { vlib_cli_output (vm, "connection or tag must be set for delete"); - return 0; + goto done; } if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN) { vlib_cli_output (vm, "tag too long (max u64)"); - return 0; + goto done; } if (ns_id) @@ -1532,7 +1536,7 @@ session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input, if (!app_ns) { vlib_cli_output (vm, "namespace %v does not exist", ns_id); - return 0; + goto done; } } else @@ -1559,10 +1563,12 @@ session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input, .scope = scope, }; if ((rv = vnet_session_rule_add_del (&args))) - return clib_error_return (0, "rule add del returned %u", rv); + error = clib_error_return (0, "rule add del returned %u", rv); +done: + vec_free (ns_id); vec_free (tag); - return 0; + return error; } /* *INDENT-OFF* */ -- cgit 1.2.3-korg