X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fsession%2Fapplication.c;h=8090e75a6dc33dc09e6ebbe5e262cbf31e0e08bd;hb=e86a8edd3c14fb41ace2a12efd17bc7772bf623f;hp=8a953719f8159d1f2e3c130b4d1eb1ce32de35fb;hpb=2c25a62cc1cc4937165de740a3b32d78429c72d6;p=vpp.git diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 8a953719f81..8090e75a6dc 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -15,6 +15,7 @@ #include #include +#include #include /** @@ -32,10 +33,50 @@ static uword *app_by_api_client_index; */ 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) @@ -50,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) { @@ -80,8 +136,8 @@ application_new () pool_get (app_pool, app); memset (app, 0, sizeof (*app)); app->index = application_get_index (app); - app->connects_seg_manager = ~0; - app->first_segment_manager = ~0; + 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; @@ -90,11 +146,12 @@ application_new () void application_del (application_t * app) { + segment_manager_properties_t *props; + vnet_unbind_args_t _a, *a = &_a; segment_manager_t *sm; - u64 handle; - u32 index, *handles = 0; + u64 handle, *handles = 0; + u32 index; int i; - vnet_unbind_args_t _a, *a = &_a; /* * The app event queue allocated in first segment is cleared with @@ -103,23 +160,22 @@ application_del (application_t * app) if (CLIB_DEBUG > 1) clib_warning ("[%d] Delete app (%d)", getpid (), app->index); + if (application_is_proxy (app)) + application_remove_proxy (app); + /* - * Cleanup segment managers + * Listener cleanup */ - if (app->connects_seg_manager != (u32) ~ 0) - { - sm = segment_manager_get (app->connects_seg_manager); - segment_manager_del (sm); - } /* *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* */ - /* Actual listener cleanup */ for (i = 0; i < vec_len (handles); i++) { a->app_index = app->index; @@ -128,12 +184,32 @@ application_del (application_t * app) vnet_unbind (a); } - if (app->first_segment_manager != ~0) + /* + * Connects segment manager cleanup + */ + + if (app->connects_seg_manager != APP_INVALID_SEGMENT_MANAGER_INDEX) { - sm = segment_manager_get (app->first_segment_manager); - segment_manager_first_segment_maybe_del (sm); + 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); } @@ -158,33 +234,52 @@ application_init (application_t * app, u32 api_client_index, u64 * options, segment_manager_t *sm; segment_manager_properties_t *props; u32 app_evt_queue_size, first_seg_size; + u32 default_rx_fifo_size = 16 << 10, default_tx_fifo_size = 16 << 10; int rv; - app_evt_queue_size = options[APP_EVT_QUEUE_SIZE] > 0 ? - options[APP_EVT_QUEUE_SIZE] : default_app_evt_queue_size; + app_evt_queue_size = options[APP_OPTIONS_EVT_QUEUE_SIZE] > 0 ? + options[APP_OPTIONS_EVT_QUEUE_SIZE] : default_app_evt_queue_size; - /* Setup segment manager */ + /* + * Setup segment manager + */ sm = segment_manager_new (); sm->app_index = app->index; - props = &app->sm_properties; - props->add_segment_size = options[SESSION_OPTIONS_ADD_SEGMENT_SIZE]; - props->rx_fifo_size = options[SESSION_OPTIONS_RX_FIFO_SIZE]; - props->tx_fifo_size = options[SESSION_OPTIONS_TX_FIFO_SIZE]; + props = segment_manager_properties_alloc (); + app->sm_properties = segment_manager_properties_index (props); + props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE]; + props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE]; + props->rx_fifo_size = + props->rx_fifo_size ? props->rx_fifo_size : default_rx_fifo_size; + props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE]; + props->tx_fifo_size = + props->tx_fifo_size ? props->tx_fifo_size : default_tx_fifo_size; props->add_segment = props->add_segment_size != 0; props->preallocated_fifo_pairs = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS]; props->use_private_segment = options[APP_OPTIONS_FLAGS] - & APP_OPTIONS_FLAGS_BUILTIN_APP; + & APP_OPTIONS_FLAGS_IS_BUILTIN; props->private_segment_count = options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT]; - props->private_segment_size = options[APP_OPTIONS_PRIVATE_SEGMENT_SIZE]; - first_seg_size = options[SESSION_OPTIONS_SEGMENT_SIZE]; - if ((rv = segment_manager_init (sm, props, first_seg_size))) + first_seg_size = options[APP_OPTIONS_SEGMENT_SIZE]; + if ((rv = segment_manager_init (sm, app->sm_properties, first_seg_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 = 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); @@ -201,6 +296,8 @@ application_init (application_t * app, u32 api_client_index, u64 * options, application_t * application_get (u32 index) { + if (index == APP_INVALID_INDEX) + return 0; return pool_elt_at_index (app_pool, index); } @@ -224,15 +321,18 @@ application_alloc_segment_manager (application_t * app) { segment_manager_t *sm = 0; - if (app->first_segment_manager != (u32) ~ 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 (); - if (segment_manager_init (sm, &app->sm_properties, 0)) - return 0; + sm->properties_index = app->sm_properties; + return sm; } @@ -244,17 +344,19 @@ application_alloc_segment_manager (application_t * app) * it's own specific listening connection. */ int -application_start_listen (application_t * srv, session_type_t session_type, - transport_endpoint_t * tep, u64 * res) +application_start_listen (application_t * srv, session_endpoint_t * sep, + u64 * res) { segment_manager_t *sm; stream_session_t *s; u64 handle; + session_type_t sst; - s = listen_session_new (session_type); + 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, tep)) + if (stream_session_listen (s, sep)) goto err; /* Allocate segment manager. All sessions derived out of a listen session @@ -299,8 +401,16 @@ application_stop_listen (application_t * srv, u64 handle) ASSERT (indexp); sm = segment_manager_get (*indexp); - segment_manager_del (sm); - srv->first_segment_manager = ~0; + 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); @@ -308,15 +418,14 @@ application_stop_listen (application_t * srv, u64 handle) } int -application_open_session (application_t * app, session_type_t sst, - transport_endpoint_t * tep, u32 api_context) +application_open_session (application_t * app, session_endpoint_t * sep, + u32 api_context) { segment_manager_t *sm; - transport_connection_t *tc = 0; int rv; /* Make sure we have a segment manager for connects */ - if (app->connects_seg_manager == (u32) ~ 0) + if (app->connects_seg_manager == APP_INVALID_SEGMENT_MANAGER_INDEX) { sm = application_alloc_segment_manager (app); if (sm == 0) @@ -324,13 +433,9 @@ application_open_session (application_t * app, session_type_t sst, app->connects_seg_manager = segment_manager_index (sm); } - if ((rv = stream_session_open (app->index, sst, tep, &tc))) + if ((rv = session_open (app->index, sep, api_context))) return rv; - /* Store api_context for when the reply comes. Not the nicest thing - * but better allocating a separate half-open pool. */ - tc->s_index = api_context; - return 0; } @@ -351,19 +456,230 @@ application_get_listen_segment_manager (application_t * app, return segment_manager_get (*smp); } -static u8 * -app_get_name_from_reg_index (application_t * app) +int +application_is_proxy (application_t * app) { - u8 *app_name; + return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY); +} - 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); +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); + u32 seg_size = 0; + u8 *seg_name; + + /* Send an API message to the external app, to map new segment */ + ASSERT (app->cb_fns.add_segment_callback); + + segment_manager_get_segment_info (fifo_segment_index, &seg_name, &seg_size); + return app->cb_fns.add_segment_callback (app->api_client_index, seg_name, + seg_size); +} + +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 - app_name = format (0, "%s%c", regp->name, 0); + { + s = application_proxy_listener (app, fib_proto, transport_proto); + ASSERT (s); + } - return app_name; + tc = listen_session_get_transport (s); + + if (!ip_is_zero (&tc->lcl_ip, 1)) + { + 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); + } + + 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 * @@ -436,7 +752,7 @@ application_format_connects (application_t * app, int verbose) svm_fifo_t *fifo; u8 *str; - fifo_segment = svm_fifo_get_segment (sm->segment_indices[j]); + fifo_segment = svm_fifo_segment_get_segment (sm->segment_indices[j]); fifo = svm_fifo_segment_get_fifo_list (fifo_segment); while (fifo) { @@ -446,7 +762,7 @@ application_format_connects (application_t * app, int verbose) session_index = fifo->master_session_index; thread_index = fifo->master_thread_index; - session = stream_session_get (session_index, thread_index); + session = session_get (session_index, thread_index); str = format (0, "%U", format_stream_session, session, verbose); if (verbose) @@ -472,28 +788,35 @@ 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) { if (verbose) - s = format (s, "%-10s%-20s%-15s%-15s%-15s%-15s", "Index", "Name", - "API Client", "Add seg size", "Rx fifo size", + 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%-20s", "Index", "Name", "API Client"); + 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", app->index, app_name, - app->api_client_index, app->sm_properties.add_segment_size, - app->sm_properties.rx_fifo_size, - app->sm_properties.tx_fifo_size); + 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, "%-10d%-20s%-20d", app->index, app_name, - app->api_client_index); + s = format (s, "%-10d%-20s%-15d%-40s", app->index, app_name, + app->api_client_index, app_ns_name); return s; } @@ -506,10 +829,7 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, int do_client = 0; int verbose = 0; - if (!session_manager_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) { @@ -532,7 +852,7 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "%U", format_application_listener, 0 /* header */ , 0, 0, verbose); - /* *INDENT-OFF* */ + /* *INDENT-OFF* */ pool_foreach (app, app_pool, ({ /* App's listener sessions */ @@ -573,13 +893,11 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, if (!do_server && !do_client) { vlib_cli_output (vm, "%U", format_application, 0, verbose); - pool_foreach (app, app_pool, ( - { - vlib_cli_output (vm, "%U", - format_application, app, - verbose); - } - )); + /* *INDENT-OFF* */ + pool_foreach (app, app_pool, ({ + vlib_cli_output (vm, "%U", format_application, app, verbose); + })); + /* *INDENT-ON* */ } return 0;