X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fsession%2Fapplication.c;h=13ccdd7cbc8424d86eaee88c46bc526a05c50903;hb=b384b543313b6b47a277c903e9d4fcd4343054fa;hp=a542eebe43fc89ed5c14b135d0f5585218ecb4b0;hpb=e04c29942af6a130591059679531c9ffa3d7237a;p=vpp.git diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index a542eebe43f..13ccdd7cbc8 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -14,22 +14,69 @@ */ #include +#include +#include #include -/* +/** * Pool from which we allocate all applications */ static application_t *app_pool; -/* +/** * Hash table of apps by api client index */ static uword *app_by_api_client_index; +/** + * Default application event queue size + */ +static u32 default_app_evt_queue_size = 128; + +static u8 * +app_get_name_from_reg_index (application_t * app) +{ + u8 *app_name; + + vl_api_registration_t *regp; + regp = vl_api_client_index_to_registration (app->api_client_index); + if (!regp) + app_name = format (0, "builtin-%d%c", app->index, 0); + else + app_name = format (0, "%s%c", regp->name, 0); + + return app_name; +} + +u32 +application_session_table (application_t * app, u8 fib_proto) +{ + app_namespace_t *app_ns; + app_ns = app_namespace_get (app->ns_index); + if (!application_has_global_scope (app)) + return APP_INVALID_INDEX; + if (fib_proto == FIB_PROTOCOL_IP4) + return session_lookup_get_index_for_fib (fib_proto, + app_ns->ip4_fib_index); + else + return session_lookup_get_index_for_fib (fib_proto, + app_ns->ip6_fib_index); +} + +u32 +application_local_session_table (application_t * app) +{ + app_namespace_t *app_ns; + if (!application_has_local_scope (app)) + return APP_INVALID_INDEX; + app_ns = app_namespace_get (app->ns_index); + return app_ns->local_table_index; +} + int application_api_queue_is_full (application_t * app) { - unix_shared_memory_queue_t *q; + svm_queue_t *q; /* builtin servers are always OK */ if (app->api_client_index == ~0) @@ -44,6 +91,21 @@ application_api_queue_is_full (application_t * app) return 0; } +/** + * Returns app name + * + * Since the name is not stored per app, we generate it on the fly. It is + * the caller's responsibility to free the vector + */ +u8 * +application_name_from_index (u32 app_index) +{ + application_t *app = application_get (app_index); + if (!app) + return 0; + return app_get_name_from_reg_index (app); +} + static void application_table_add (application_t * app) { @@ -67,90 +129,219 @@ application_lookup (u32 api_client_index) return 0; } +application_t * +application_new () +{ + application_t *app; + pool_get (app_pool, app); + memset (app, 0, sizeof (*app)); + app->index = application_get_index (app); + app->connects_seg_manager = APP_INVALID_SEGMENT_MANAGER_INDEX; + app->first_segment_manager = APP_INVALID_SEGMENT_MANAGER_INDEX; + if (CLIB_DEBUG > 1) + clib_warning ("[%d] New app (%d)", getpid (), app->index); + return app; +} + void application_del (application_t * app) { - session_manager_main_t *smm = vnet_get_session_manager_main (); - api_main_t *am = &api_main; - void *oldheap; - session_manager_t *sm; - - if (app->mode == APP_SERVER) + segment_manager_properties_t *props; + vnet_unbind_args_t _a, *a = &_a; + segment_manager_t *sm; + u64 handle, *handles = 0; + u32 index; + int i; + + /* + * The app event queue allocated in first segment is cleared with + * the segment manager. No need to explicitly free it. + */ + if (CLIB_DEBUG > 1) + clib_warning ("[%d] Delete app (%d)", getpid (), app->index); + + if (application_is_proxy (app)) + application_remove_proxy (app); + + /* + * Listener cleanup + */ + + /* *INDENT-OFF* */ + hash_foreach (handle, index, app->listeners_table, + ({ + vec_add1 (handles, handle); + sm = segment_manager_get (index); + sm->app_index = SEGMENT_MANAGER_INVALID_APP_INDEX; + })); + /* *INDENT-ON* */ + + for (i = 0; i < vec_len (handles); i++) { - sm = session_manager_get (app->session_manager_index); - session_manager_del (smm, sm); + a->app_index = app->index; + a->handle = handles[i]; + /* seg manager is removed when unbind completes */ + vnet_unbind (a); } - /* Free the event fifo in the /vpe-api shared-memory segment */ - oldheap = svm_push_data_heap (am->vlib_rp); - if (app->event_queue) - unix_shared_memory_queue_free (app->event_queue); - svm_pop_heap (oldheap); + /* + * Connects segment manager cleanup + */ - application_table_del (app); + if (app->connects_seg_manager != APP_INVALID_SEGMENT_MANAGER_INDEX) + { + sm = segment_manager_get (app->connects_seg_manager); + sm->app_index = SEGMENT_MANAGER_INVALID_APP_INDEX; + segment_manager_init_del (sm); + } + /* If first segment manager is used by a listener */ + if (app->first_segment_manager != APP_INVALID_SEGMENT_MANAGER_INDEX + && app->first_segment_manager != app->connects_seg_manager) + { + sm = segment_manager_get (app->first_segment_manager); + /* .. and has no fifos, e.g. it might be used for redirected sessions, + * remove it */ + if (!segment_manager_has_fifos (sm)) + { + sm->app_index = SEGMENT_MANAGER_INVALID_APP_INDEX; + segment_manager_del (sm); + } + } + props = segment_manager_properties_get (app->sm_properties); + segment_manager_properties_free (props); + application_table_del (app); pool_put (app_pool, app); } -application_t * -application_new (application_type_t type, session_type_t sst, - u32 api_client_index, u32 flags, session_cb_vft_t * cb_fns) +static void +application_verify_cb_fns (session_cb_vft_t * cb_fns) { - session_manager_main_t *smm = vnet_get_session_manager_main (); - api_main_t *am = &api_main; - application_t *app; - void *oldheap; - session_manager_t *sm; - - pool_get (app_pool, app); - memset (app, 0, sizeof (*app)); - - /* Allocate event fifo in the /vpe-api shared-memory segment */ - oldheap = svm_push_data_heap (am->vlib_rp); - - /* Allocate server event queue */ - app->event_queue = - unix_shared_memory_queue_init (128 /* nels $$$$ config */ , - sizeof (session_fifo_event_t), - 0 /* consumer pid */ , - 0 - /* (do not) signal when queue non-empty */ - ); - - svm_pop_heap (oldheap); + if (cb_fns->session_accept_callback == 0) + clib_warning ("No accept callback function provided"); + if (cb_fns->session_connected_callback == 0) + clib_warning ("No session connected callback function provided"); + if (cb_fns->session_disconnect_callback == 0) + clib_warning ("No session disconnect callback function provided"); + if (cb_fns->session_reset_callback == 0) + clib_warning ("No session reset callback function provided"); +} - /* If a server, allocate session manager */ - if (type == APP_SERVER) +/** + * Check app config for given segment type + * + * Returns 1 on success and 0 otherwise + */ +static u8 +application_verify_cfg (ssvm_segment_type_t st) +{ + u8 is_valid; + if (st == SSVM_SEGMENT_MEMFD) { - pool_get (smm->session_managers, sm); - memset (sm, 0, sizeof (*sm)); - - app->session_manager_index = sm - smm->session_managers; + is_valid = (session_manager_get_evt_q_segment () != 0); + if (!is_valid) + clib_warning ("memfd seg: vpp's event qs IN binary api svm region"); + return is_valid; } - else if (type == APP_CLIENT) + else if (st == SSVM_SEGMENT_SHM) { - /* Allocate connect session manager if needed */ - if (smm->connect_manager_index[sst] == INVALID_INDEX) - connects_session_manager_init (smm, sst); - app->session_manager_index = smm->connect_manager_index[sst]; + is_valid = (session_manager_get_evt_q_segment () == 0); + if (!is_valid) + clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region"); + return is_valid; } + else + return 1; +} - app->mode = type; - app->index = application_get_index (app); - app->session_type = sst; +int +application_init (application_t * app, u32 api_client_index, u64 * options, + session_cb_vft_t * cb_fns) +{ + ssvm_segment_type_t st = SSVM_SEGMENT_MEMFD; + u32 app_evt_queue_size, first_seg_size; + segment_manager_properties_t *props; + vl_api_registration_t *reg; + segment_manager_t *sm; + int rv; + + /* + * Make sure we support the requested configuration + */ + reg = vl_api_client_index_to_registration (api_client_index); + if (!reg) + return VNET_API_ERROR_APP_UNSUPPORTED_CFG; + + if (vl_api_registration_file_index (reg) == ~0) + st = SSVM_SEGMENT_SHM; + + if (!application_verify_cfg (st)) + return VNET_API_ERROR_APP_UNSUPPORTED_CFG; + + /* + * Setup segment manager + */ + sm = segment_manager_new (); + sm->app_index = app->index; + props = segment_manager_properties_alloc (); + app->sm_properties = segment_manager_properties_index (props); + if (options[APP_OPTIONS_ADD_SEGMENT_SIZE]) + { + props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE]; + props->add_segment = 1; + } + if (options[APP_OPTIONS_RX_FIFO_SIZE]) + props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE]; + if (options[APP_OPTIONS_TX_FIFO_SIZE]) + props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE]; + props->preallocated_fifo_pairs = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS]; + props->private_segment_count = options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT]; + if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN) + props->segment_type = SSVM_N_SEGMENT_TYPES; + else + props->segment_type = st; + + app_evt_queue_size = options[APP_OPTIONS_EVT_QUEUE_SIZE] > 0 ? + options[APP_OPTIONS_EVT_QUEUE_SIZE] : default_app_evt_queue_size; + first_seg_size = options[APP_OPTIONS_SEGMENT_SIZE]; + if ((rv = segment_manager_init (sm, app->sm_properties, first_seg_size, + app_evt_queue_size))) + return rv; + sm->first_is_protected = 1; + + /* + * Setup application + */ + app->first_segment_manager = segment_manager_index (sm); app->api_client_index = api_client_index; - app->flags = flags; + app->flags = options[APP_OPTIONS_FLAGS]; app->cb_fns = *cb_fns; + app->ns_index = options[APP_OPTIONS_NAMESPACE]; + app->listeners_table = hash_create (0, sizeof (u64)); + app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT]; + + /* If no scope enabled, default to global */ + if (!application_has_global_scope (app) + && !application_has_local_scope (app)) + app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE; + + /* Allocate app event queue in the first shared-memory segment */ + app->event_queue = segment_manager_alloc_queue (sm, app_evt_queue_size); + + /* Check that the obvious things are properly set up */ + application_verify_cb_fns (cb_fns); /* Add app to lookup by api_client_index table */ application_table_add (app); - return app; + return 0; } application_t * application_get (u32 index) { + if (index == APP_INVALID_INDEX) + return 0; return pool_elt_at_index (app_pool, index); } @@ -169,108 +360,505 @@ application_get_index (application_t * app) return app - app_pool; } +static segment_manager_t * +application_alloc_segment_manager (application_t * app) +{ + segment_manager_t *sm = 0; + + /* If the first segment manager is not in use, don't allocate a new one */ + if (app->first_segment_manager != APP_INVALID_SEGMENT_MANAGER_INDEX + && app->first_segment_manager_in_use == 0) + { + sm = segment_manager_get (app->first_segment_manager); + app->first_segment_manager_in_use = 1; + return sm; + } + + sm = segment_manager_new (); + sm->properties_index = app->sm_properties; + + return sm; +} + +/** + * Start listening local transport endpoint for requested transport. + * + * Creates a 'dummy' stream session with state LISTENING to be used in session + * lookups, prior to establishing connection. Requests transport to build + * it's own specific listening connection. + */ int -application_server_init (application_t * server, u32 segment_size, - u32 add_segment_size, u32 rx_fifo_size, - u32 tx_fifo_size, u8 ** segment_name) +application_start_listen (application_t * srv, session_endpoint_t * sep, + u64 * res) { - session_manager_main_t *smm = vnet_get_session_manager_main (); - session_manager_t *sm; + segment_manager_t *sm; + stream_session_t *s; + u64 handle; + session_type_t sst; + + sst = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4); + s = listen_session_new (sst); + s->app_index = srv->index; + + if (stream_session_listen (s, sep)) + goto err; + + /* Allocate segment manager. All sessions derived out of a listen session + * have fifos allocated by the same segment manager. */ + sm = application_alloc_segment_manager (srv); + if (sm == 0) + goto err; + + /* Add to app's listener table. Useful to find all child listeners + * when app goes down, although, just for unbinding this is not needed */ + handle = listen_session_get_handle (s); + hash_set (srv->listeners_table, handle, segment_manager_index (sm)); + + *res = handle; + return 0; + +err: + listen_session_del (s); + return -1; +} + +/** + * Stop listening on session associated to handle + */ +int +application_stop_listen (application_t * srv, u64 handle) +{ + stream_session_t *listener; + uword *indexp; + segment_manager_t *sm; + + if (srv && hash_get (srv->listeners_table, handle) == 0) + { + clib_warning ("app doesn't own handle %llu!", handle); + return -1; + } + + listener = listen_session_get_from_handle (handle); + stream_session_stop_listen (listener); + + indexp = hash_get (srv->listeners_table, handle); + ASSERT (indexp); + + sm = segment_manager_get (*indexp); + if (srv->first_segment_manager == *indexp) + { + /* Delete sessions but don't remove segment manager */ + srv->first_segment_manager_in_use = 0; + segment_manager_del_sessions (sm); + } + else + { + segment_manager_init_del (sm); + } + hash_unset (srv->listeners_table, handle); + listen_session_del (listener); + + return 0; +} + +int +application_open_session (application_t * app, session_endpoint_t * sep, + u32 api_context) +{ + segment_manager_t *sm; int rv; - sm = session_manager_get (server->session_manager_index); + /* Make sure we have a segment manager for connects */ + if (app->connects_seg_manager == APP_INVALID_SEGMENT_MANAGER_INDEX) + { + sm = application_alloc_segment_manager (app); + if (sm == 0) + return -1; + app->connects_seg_manager = segment_manager_index (sm); + } + + if ((rv = session_open (app->index, sep, api_context))) + return rv; - /* Add first segment */ - if ((rv = session_manager_add_first_segment (smm, sm, segment_size, - segment_name))) + return 0; +} + +segment_manager_t * +application_get_connect_segment_manager (application_t * app) +{ + ASSERT (app->connects_seg_manager != (u32) ~ 0); + return segment_manager_get (app->connects_seg_manager); +} + +segment_manager_t * +application_get_listen_segment_manager (application_t * app, + stream_session_t * s) +{ + uword *smp; + smp = hash_get (app->listeners_table, listen_session_get_handle (s)); + ASSERT (smp != 0); + return segment_manager_get (*smp); +} + +int +application_is_proxy (application_t * app) +{ + return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY); +} + +int +application_is_builtin (application_t * app) +{ + return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN); +} + +int +application_is_builtin_proxy (application_t * app) +{ + return (application_is_proxy (app) && application_is_builtin (app)); +} + +int +application_add_segment_notify (u32 app_index, u32 fifo_segment_index) +{ + application_t *app = application_get (app_index); + svm_fifo_segment_private_t *fs; + + /* Send an API message to the external app, to map new segment */ + ASSERT (app->cb_fns.add_segment_callback); + + fs = segment_manager_get_segment (fifo_segment_index); + return app->cb_fns.add_segment_callback (app->api_client_index, &fs->ssvm); +} + +u8 +application_has_local_scope (application_t * app) +{ + return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE; +} + +u8 +application_has_global_scope (application_t * app) +{ + return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE; +} + +u32 +application_n_listeners (application_t * app) +{ + return hash_elts (app->listeners_table); +} + +stream_session_t * +application_first_listener (application_t * app, u8 fib_proto, + u8 transport_proto) +{ + stream_session_t *listener; + u64 handle; + u32 sm_index; + u8 sst; + + sst = session_type_from_proto_and_ip (transport_proto, + fib_proto == FIB_PROTOCOL_IP4); + + /* *INDENT-OFF* */ + hash_foreach (handle, sm_index, app->listeners_table, ({ + listener = listen_session_get_from_handle (handle); + if (listener->session_type == sst + && listener->listener_index != SESSION_PROXY_LISTENER_INDEX) + return listener; + })); + /* *INDENT-ON* */ + + return 0; +} + +stream_session_t * +application_proxy_listener (application_t * app, u8 fib_proto, + u8 transport_proto) +{ + stream_session_t *listener; + u64 handle; + u32 sm_index; + u8 sst; + + sst = session_type_from_proto_and_ip (transport_proto, + fib_proto == FIB_PROTOCOL_IP4); + + /* *INDENT-OFF* */ + hash_foreach (handle, sm_index, app->listeners_table, ({ + listener = listen_session_get_from_handle (handle); + if (listener->session_type == sst + && listener->listener_index == SESSION_PROXY_LISTENER_INDEX) + return listener; + })); + /* *INDENT-ON* */ + + return 0; +} + +static clib_error_t * +application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto, + u8 transport_proto, u8 is_start) +{ + app_namespace_t *app_ns = app_namespace_get (app->ns_index); + u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4); + session_endpoint_t sep = SESSION_ENDPOINT_NULL; + transport_connection_t *tc; + stream_session_t *s; + u64 handle; + + if (is_start) + { + s = application_first_listener (app, fib_proto, transport_proto); + if (!s) + { + sep.is_ip4 = is_ip4; + sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto); + sep.sw_if_index = app_ns->sw_if_index; + sep.transport_proto = transport_proto; + application_start_listen (app, &sep, &handle); + s = listen_session_get_from_handle (handle); + s->listener_index = SESSION_PROXY_LISTENER_INDEX; + } + } + else + { + s = application_proxy_listener (app, fib_proto, transport_proto); + ASSERT (s); + } + + tc = listen_session_get_transport (s); + + if (!ip_is_zero (&tc->lcl_ip, 1)) { - return rv; + u32 sti; + sep.is_ip4 = is_ip4; + sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto); + sep.transport_proto = transport_proto; + sep.port = 0; + sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index); + if (is_start) + session_lookup_add_session_endpoint (sti, &sep, s->session_index); + else + session_lookup_del_session_endpoint (sti, &sep); } - /* Setup session manager */ - sm->add_segment_size = add_segment_size; - sm->rx_fifo_size = rx_fifo_size; - sm->tx_fifo_size = tx_fifo_size; - sm->add_segment = sm->add_segment_size != 0; return 0; } +static void +application_start_stop_proxy_local_scope (application_t * app, + u8 transport_proto, u8 is_start) +{ + session_endpoint_t sep = SESSION_ENDPOINT_NULL; + app_namespace_t *app_ns; + app_ns = app_namespace_get (app->ns_index); + sep.is_ip4 = 1; + sep.transport_proto = transport_proto; + sep.port = 0; + + if (is_start) + { + session_lookup_add_session_endpoint (app_ns->local_table_index, &sep, + app->index); + sep.is_ip4 = 0; + session_lookup_add_session_endpoint (app_ns->local_table_index, &sep, + app->index); + } + else + { + session_lookup_del_session_endpoint (app_ns->local_table_index, &sep); + sep.is_ip4 = 0; + session_lookup_del_session_endpoint (app_ns->local_table_index, &sep); + } +} + +void +application_start_stop_proxy (application_t * app, + transport_proto_t transport_proto, u8 is_start) +{ + if (application_has_local_scope (app)) + application_start_stop_proxy_local_scope (app, transport_proto, is_start); + + if (application_has_global_scope (app)) + { + application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4, + transport_proto, is_start); + application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6, + transport_proto, is_start); + } +} + +void +application_setup_proxy (application_t * app) +{ + u16 transports = app->proxied_transports; + transport_proto_t tp; + + ASSERT (application_is_proxy (app)); + if (application_is_builtin (app)) + return; + + /* *INDENT-OFF* */ + transport_proto_foreach (tp, ({ + if (transports & (1 << tp)) + application_start_stop_proxy (app, tp, 1); + })); + /* *INDENT-ON* */ +} + +void +application_remove_proxy (application_t * app) +{ + u16 transports = app->proxied_transports; + transport_proto_t tp; + + ASSERT (application_is_proxy (app)); + + /* *INDENT-OFF* */ + transport_proto_foreach (tp, ({ + if (transports & (1 << tp)) + application_start_stop_proxy (app, tp, 0); + })); + /* *INDENT-ON* */ +} + u8 * -format_application_server (u8 * s, va_list * args) +format_application_listener (u8 * s, va_list * args) { - application_t *srv = va_arg (*args, application_t *); + application_t *app = va_arg (*args, application_t *); + u64 handle = va_arg (*args, u64); + u32 index = va_arg (*args, u32); int verbose = va_arg (*args, int); - vl_api_registration_t *regp; stream_session_t *listener; - u8 *server_name, *str, *seg_name; - u32 segment_size; + u8 *app_name, *str; - if (srv == 0) + if (app == 0) { if (verbose) - s = format (s, "%-40s%-20s%-15s%-15s%-10s", "Connection", "Server", - "Segment", "API Client", "Cookie"); + s = format (s, "%-40s%-20s%-15s%-15s%-10s", "Connection", "App", + "API Client", "ListenerID", "SegManager"); else - s = format (s, "%-40s%-20s", "Connection", "Server"); + s = format (s, "%-40s%-20s", "Connection", "App"); return s; } - regp = vl_api_client_index_to_registration (srv->api_client_index); - if (!regp) - server_name = format (0, "builtin-%d%c", srv->index, 0); - else - server_name = regp->name; - - listener = stream_session_listener_get (srv->session_type, - srv->session_index); + app_name = app_get_name_from_reg_index (app); + listener = listen_session_get_from_handle (handle); str = format (0, "%U", format_stream_session, listener, verbose); - session_manager_get_segment_info (listener->server_segment_index, &seg_name, - &segment_size); if (verbose) { - s = format (s, "%-40s%-20s%-20s%-10d%-10d", str, server_name, - seg_name, srv->api_client_index, srv->accept_cookie); + s = format (s, "%-40s%-20s%-15u%-15u%-10u", str, app_name, + app->api_client_index, handle, index); } else - s = format (s, "%-40s%-20s", str, server_name); + s = format (s, "%-40s%-20s", str, app_name); + + vec_free (app_name); return s; } -u8 * -format_application_client (u8 * s, va_list * args) +void +application_format_connects (application_t * app, int verbose) { - application_t *client = va_arg (*args, application_t *); - int verbose = va_arg (*args, int); - stream_session_t *session; - u8 *str, *seg_name; - u32 segment_size; + vlib_main_t *vm = vlib_get_main (); + segment_manager_t *sm; + u8 *app_name, *s = 0; + int j; - if (client == 0) + /* Header */ + if (app == 0) { if (verbose) - s = - format (s, "%-40s%-20s%-10s", "Connection", "Segment", - "API Client"); + vlib_cli_output (vm, "%-40s%-20s%-15s%-10s", "Connection", "App", + "API Client", "SegManager"); else - s = format (s, "%-40s", "Connection"); + vlib_cli_output (vm, "%-40s%-20s", "Connection", "App"); + return; + } - return s; + /* make sure */ + if (app->connects_seg_manager == (u32) ~ 0) + return; + + app_name = app_get_name_from_reg_index (app); + + /* Across all fifo segments */ + sm = segment_manager_get (app->connects_seg_manager); + for (j = 0; j < vec_len (sm->segment_indices); j++) + { + svm_fifo_segment_private_t *fifo_segment; + svm_fifo_t *fifo; + u8 *str; + + fifo_segment = svm_fifo_segment_get_segment (sm->segment_indices[j]); + fifo = svm_fifo_segment_get_fifo_list (fifo_segment); + while (fifo) + { + u32 session_index, thread_index; + stream_session_t *session; + + session_index = fifo->master_session_index; + thread_index = fifo->master_thread_index; + + session = session_get (session_index, thread_index); + str = format (0, "%U", format_stream_session, session, verbose); + + if (verbose) + s = format (s, "%-40s%-20s%-15u%-10u", str, app_name, + app->api_client_index, app->connects_seg_manager); + else + s = format (s, "%-40s%-20s", str, app_name); + + vlib_cli_output (vm, "%v", s); + vec_reset_length (s); + vec_free (str); + + fifo = fifo->next; + } + vec_free (s); } - session = stream_session_get (client->session_index, client->thread_index); - str = format (0, "%U", format_stream_session, session, verbose); + vec_free (app_name); +} - session_manager_get_segment_info (session->server_segment_index, &seg_name, - &segment_size); - if (verbose) +u8 * +format_application (u8 * s, va_list * args) +{ + application_t *app = va_arg (*args, application_t *); + CLIB_UNUSED (int verbose) = va_arg (*args, int); + segment_manager_properties_t *props; + const u8 *app_ns_name; + u8 *app_name; + + if (app == 0) { - s = format (s, "%-40s%-20s%-10d%", str, seg_name, - client->api_client_index); + if (verbose) + s = format (s, "%-10s%-20s%-15s%-15s%-15s%-15s%-15s", "Index", "Name", + "API Client", "Namespace", "Add seg size", "Rx fifo size", + "Tx fifo size"); + else + s = + format (s, "%-10s%-20s%-15s%-40s", "Index", "Name", "API Client", + "Namespace"); + return s; } + + app_name = app_get_name_from_reg_index (app); + app_ns_name = app_namespace_id_from_index (app->ns_index); + props = segment_manager_properties_get (app->sm_properties); + if (verbose) + s = + format (s, "%-10d%-20s%-15d%-15d%-15d%-15d%-15d", app->index, app_name, + app->api_client_index, app->ns_index, + props->add_segment_size, + props->rx_fifo_size, props->tx_fifo_size); else - s = format (s, "%-40s", str); + s = format (s, "%-10d%-20s%-15d%-40s", app->index, app_name, + app->api_client_index, app_ns_name); return s; } @@ -278,16 +866,12 @@ static clib_error_t * show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - session_manager_main_t *smm = &session_manager_main; application_t *app; int do_server = 0; int do_client = 0; int verbose = 0; - if (!smm->is_enabled) - { - clib_error_return (0, "session layer is not enabled"); - } + session_cli_return_if_not_enabled (); while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -303,17 +887,24 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, if (do_server) { + u64 handle; + u32 index; if (pool_elts (app_pool)) { - vlib_cli_output (vm, "%U", format_application_server, - 0 /* header */ , + vlib_cli_output (vm, "%U", format_application_listener, + 0 /* header */ , 0, 0, verbose); - /* *INDENT-OFF* */ + /* *INDENT-OFF* */ pool_foreach (app, app_pool, ({ - if (app->mode == APP_SERVER) - vlib_cli_output (vm, "%U", format_application_server, app, - verbose); + /* App's listener sessions */ + if (hash_elts (app->listeners_table) == 0) + continue; + hash_foreach (handle, index, app->listeners_table, + ({ + vlib_cli_output (vm, "%U", format_application_listener, app, + handle, index, verbose); + })); })); /* *INDENT-ON* */ } @@ -325,15 +916,14 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (pool_elts (app_pool)) { - vlib_cli_output (vm, "%U", format_application_client, - 0 /* header */ , - verbose); + application_format_connects (0, verbose); + /* *INDENT-OFF* */ pool_foreach (app, app_pool, ({ - if (app->mode == APP_CLIENT) - vlib_cli_output (vm, "%U", format_application_client, app, - verbose); + if (app->connects_seg_manager == (u32)~0) + continue; + application_format_connects (app, verbose); })); /* *INDENT-ON* */ } @@ -341,6 +931,17 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "No active client bindings"); } + /* Print app related info */ + if (!do_server && !do_client) + { + vlib_cli_output (vm, "%U", format_application, 0, verbose); + /* *INDENT-OFF* */ + pool_foreach (app, app_pool, ({ + vlib_cli_output (vm, "%U", format_application, app, verbose); + })); + /* *INDENT-ON* */ + } + return 0; }