2 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/session/application.h>
17 #include <vnet/session/application_interface.h>
18 #include <vnet/session/application_namespace.h>
19 #include <vnet/session/session.h>
21 static app_main_t app_main;
23 static app_listener_t *
24 app_listener_alloc (application_t * app)
26 app_listener_t *app_listener;
27 pool_get (app->listeners, app_listener);
28 clib_memset (app_listener, 0, sizeof (*app_listener));
29 app_listener->al_index = app_listener - app->listeners;
33 static app_listener_t *
34 app_listener_get (application_t * app, u32 app_listener_index)
36 return pool_elt_at_index (app->listeners, app_listener_index);
40 app_listener_free (application_t * app, app_listener_t * app_listener)
42 clib_bitmap_free (app_listener->workers);
43 pool_put (app->listeners, app_listener);
45 clib_memset (app_listener, 0xfa, sizeof (*app_listener));
48 static app_listener_t *
49 app_local_listener_alloc (application_t * app)
51 app_listener_t *app_listener;
52 pool_get (app->local_listeners, app_listener);
53 clib_memset (app_listener, 0, sizeof (*app_listener));
54 app_listener->al_index = app_listener - app->local_listeners;
58 static app_listener_t *
59 app_local_listener_get (application_t * app, u32 app_listener_index)
61 return pool_elt_at_index (app->local_listeners, app_listener_index);
65 app_local_listener_free (application_t * app, app_listener_t * app_listener)
67 clib_bitmap_free (app_listener->workers);
68 pool_put (app->local_listeners, app_listener);
70 clib_memset (app_listener, 0xfa, sizeof (*app_listener));
73 static app_worker_map_t *
74 app_worker_map_alloc (application_t * app)
76 app_worker_map_t *map;
77 pool_get (app->worker_maps, map);
78 clib_memset (map, 0, sizeof (*map));
83 app_worker_map_index (application_t * app, app_worker_map_t * map)
85 return (map - app->worker_maps);
89 app_worker_map_free (application_t * app, app_worker_map_t * map)
91 pool_put (app->worker_maps, map);
94 static app_worker_map_t *
95 app_worker_map_get (application_t * app, u32 map_index)
97 if (pool_is_free_index (app->worker_maps, map_index))
99 return pool_elt_at_index (app->worker_maps, map_index);
103 app_get_name (application_t * app)
109 application_session_table (application_t * app, u8 fib_proto)
111 app_namespace_t *app_ns;
112 app_ns = app_namespace_get (app->ns_index);
113 if (!application_has_global_scope (app))
114 return APP_INVALID_INDEX;
115 if (fib_proto == FIB_PROTOCOL_IP4)
116 return session_lookup_get_index_for_fib (fib_proto,
117 app_ns->ip4_fib_index);
119 return session_lookup_get_index_for_fib (fib_proto,
120 app_ns->ip6_fib_index);
124 application_local_session_table (application_t * app)
126 app_namespace_t *app_ns;
127 if (!application_has_local_scope (app))
128 return APP_INVALID_INDEX;
129 app_ns = app_namespace_get (app->ns_index);
130 return app_ns->local_table_index;
134 application_local_listener_session_endpoint (local_session_t * ll,
135 session_endpoint_t * sep)
137 sep->transport_proto =
138 session_type_transport_proto (ll->listener_session_type);
139 sep->port = ll->port;
140 sep->is_ip4 = ll->listener_session_type & 1;
144 * Returns app name for app-index
147 application_name_from_index (u32 app_index)
149 application_t *app = application_get (app_index);
152 return app_get_name (app);
156 application_api_table_add (u32 app_index, u32 api_client_index)
158 if (api_client_index != APP_INVALID_INDEX)
159 hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
163 application_api_table_del (u32 api_client_index)
165 hash_unset (app_main.app_by_api_client_index, api_client_index);
169 application_name_table_add (application_t * app)
171 hash_set_mem (app_main.app_by_name, app->name, app->app_index);
175 application_name_table_del (application_t * app)
177 hash_unset_mem (app_main.app_by_name, app->name);
181 application_lookup (u32 api_client_index)
184 p = hash_get (app_main.app_by_api_client_index, api_client_index);
186 return application_get_if_valid (p[0]);
192 application_lookup_name (const u8 * name)
195 p = hash_get_mem (app_main.app_by_name, name);
197 return application_get (p[0]);
203 application_alloc (void)
206 pool_get (app_main.app_pool, app);
207 clib_memset (app, 0, sizeof (*app));
208 app->app_index = app - app_main.app_pool;
213 application_get (u32 app_index)
215 if (app_index == APP_INVALID_INDEX)
217 return pool_elt_at_index (app_main.app_pool, app_index);
221 application_get_if_valid (u32 app_index)
223 if (pool_is_free_index (app_main.app_pool, app_index))
226 return pool_elt_at_index (app_main.app_pool, app_index);
230 application_verify_cb_fns (session_cb_vft_t * cb_fns)
232 if (cb_fns->session_accept_callback == 0)
233 clib_warning ("No accept callback function provided");
234 if (cb_fns->session_connected_callback == 0)
235 clib_warning ("No session connected callback function provided");
236 if (cb_fns->session_disconnect_callback == 0)
237 clib_warning ("No session disconnect callback function provided");
238 if (cb_fns->session_reset_callback == 0)
239 clib_warning ("No session reset callback function provided");
243 * Check app config for given segment type
245 * Returns 1 on success and 0 otherwise
248 application_verify_cfg (ssvm_segment_type_t st)
251 if (st == SSVM_SEGMENT_MEMFD)
253 is_valid = (session_manager_get_evt_q_segment () != 0);
255 clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
258 else if (st == SSVM_SEGMENT_SHM)
260 is_valid = (session_manager_get_evt_q_segment () == 0);
262 clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
270 application_alloc_and_init (app_init_args_t * a)
272 ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
273 segment_manager_properties_t *props;
274 vl_api_registration_t *reg;
278 app = application_alloc ();
279 options = a->options;
281 * Make sure we support the requested configuration
283 if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
285 reg = vl_api_client_index_to_registration (a->api_client_index);
287 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
288 if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
289 seg_type = SSVM_SEGMENT_SHM;
293 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
295 clib_warning ("mq eventfds can only be used if socket transport is "
297 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
299 seg_type = SSVM_SEGMENT_PRIVATE;
302 if (!application_verify_cfg (seg_type))
303 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
305 /* Check that the obvious things are properly set up */
306 application_verify_cb_fns (a->session_cb_vft);
308 app->flags = options[APP_OPTIONS_FLAGS];
309 app->cb_fns = *a->session_cb_vft;
310 app->ns_index = options[APP_OPTIONS_NAMESPACE];
311 app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
312 app->name = vec_dup (a->name);
314 /* If no scope enabled, default to global */
315 if (!application_has_global_scope (app)
316 && !application_has_local_scope (app))
317 app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
319 props = application_segment_manager_properties (app);
320 segment_manager_properties_init (props);
321 props->segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
322 props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
323 if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
325 props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
326 props->add_segment = 1;
328 if (options[APP_OPTIONS_RX_FIFO_SIZE])
329 props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
330 if (options[APP_OPTIONS_TX_FIFO_SIZE])
331 props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
332 if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
333 props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
334 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
335 props->use_mq_eventfd = 1;
336 if (options[APP_OPTIONS_TLS_ENGINE])
337 app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
338 props->segment_type = seg_type;
340 /* Add app to lookup by api_client_index table */
341 if (!application_is_builtin (app))
342 application_api_table_add (app->app_index, a->api_client_index);
344 application_name_table_add (app);
346 a->app_index = app->app_index;
348 APP_DBG ("New app name: %v api index: %u index %u", app->name,
349 app->api_client_index, app->app_index);
355 application_free (application_t * app)
357 app_worker_map_t *wrk_map;
358 app_worker_t *app_wrk;
361 session_endpoint_t sep;
364 * The app event queue allocated in first segment is cleared with
365 * the segment manager. No need to explicitly free it.
367 APP_DBG ("Delete app name %v api index: %d index: %d", app->name,
368 app->api_client_index, app->app_index);
370 if (application_is_proxy (app))
371 application_remove_proxy (app);
378 pool_flush (wrk_map, app->worker_maps, ({
379 app_wrk = app_worker_get (wrk_map->wrk_index);
380 app_worker_free (app_wrk);
383 pool_free (app->worker_maps);
386 * Free local listeners. Global table unbinds stop local listeners
387 * as well, but if we have only local binds, these won't be cleaned up.
388 * Don't bother with local accepted sessions, we clean them when
389 * cleaning up the worker.
391 table_index = application_local_session_table (app);
393 pool_foreach (ll, app->local_listen_sessions, ({
394 application_local_listener_session_endpoint (ll, &sep);
395 session_lookup_del_session_endpoint (table_index, &sep);
398 pool_free (app->local_listen_sessions);
401 * Cleanup remaining state
403 if (application_is_builtin (app))
404 application_name_table_del (app);
405 vec_free (app->name);
406 vec_free (app->tls_cert);
407 vec_free (app->tls_key);
408 pool_put (app_main.app_pool, app);
412 application_detach_process (application_t * app, u32 api_client_index)
414 vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
415 app_worker_map_t *wrk_map;
416 u32 *wrks = 0, *wrk_index;
417 app_worker_t *app_wrk;
419 if (api_client_index == ~0)
421 application_free (app);
425 APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
426 app->app_index, app->api_client_index);
429 pool_foreach (wrk_map, app->worker_maps, ({
430 app_wrk = app_worker_get (wrk_map->wrk_index);
431 if (app_wrk->api_client_index == api_client_index)
432 vec_add1 (wrks, app_wrk->wrk_index);
438 clib_warning ("no workers for app %u api_index %u", app->app_index,
443 args->app_index = app->app_index;
444 args->api_client_index = api_client_index;
445 vec_foreach (wrk_index, wrks)
447 app_wrk = app_worker_get (wrk_index[0]);
448 args->wrk_map_index = app_wrk->wrk_map_index;
450 vnet_app_worker_add_del (args);
456 application_get_worker (application_t * app, u32 wrk_map_index)
458 app_worker_map_t *map;
459 map = app_worker_map_get (app, wrk_map_index);
462 return app_worker_get (map->wrk_index);
466 application_get_default_worker (application_t * app)
468 return application_get_worker (app, 0);
472 application_n_workers (application_t * app)
474 return pool_elts (app->worker_maps);
478 application_listener_select_worker (session_t * ls, u8 is_local)
480 app_listener_t *app_listener;
484 app = application_get (ls->app_index);
486 app_listener = app_listener_get (app, ls->listener_db_index);
488 app_listener = app_local_listener_get (app, ls->listener_db_index);
490 wrk_index = clib_bitmap_next_set (app_listener->workers,
491 app_listener->accept_rotor + 1);
493 wrk_index = clib_bitmap_first_set (app_listener->workers);
495 ASSERT (wrk_index != ~0);
496 app_listener->accept_rotor = wrk_index;
497 return application_get_worker (app, wrk_index);
501 application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
503 app_worker_map_t *wrk_map;
504 app_worker_t *app_wrk;
505 segment_manager_t *sm;
508 app_wrk = app_worker_alloc (app);
509 wrk_map = app_worker_map_alloc (app);
510 wrk_map->wrk_index = app_wrk->wrk_index;
511 app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
514 * Setup first segment manager
516 sm = segment_manager_new ();
517 sm->app_wrk_index = app_wrk->wrk_index;
519 if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
520 app->sm_properties.prealloc_fifos)))
522 app_worker_free (app_wrk);
525 sm->first_is_protected = 1;
530 app_wrk->first_segment_manager = segment_manager_index (sm);
531 app_wrk->listeners_table = hash_create (0, sizeof (u64));
532 app_wrk->event_queue = segment_manager_event_queue (sm);
533 app_wrk->app_is_builtin = application_is_builtin (app);
536 * Segment manager for local sessions
538 sm = segment_manager_new ();
539 sm->app_wrk_index = app_wrk->wrk_index;
540 app_wrk->local_segment_manager = segment_manager_index (sm);
541 app_wrk->local_connects = hash_create (0, sizeof (u64));
549 * Start listening local transport endpoint for requested transport.
551 * Creates a 'dummy' stream session with state LISTENING to be used in session
552 * lookups, prior to establishing connection. Requests transport to build
553 * it's own specific listening connection.
556 application_start_listen (application_t * app,
557 session_endpoint_cfg_t * sep_ext,
558 session_handle_t * res)
560 app_listener_t *app_listener;
561 u32 table_index, fib_proto;
562 session_endpoint_t *sep;
563 app_worker_t *app_wrk;
569 * Check if sep is already listened on
571 sep = (session_endpoint_t *) sep_ext;
572 fib_proto = session_endpoint_fib_proto (sep);
573 table_index = application_session_table (app, fib_proto);
574 lh = session_lookup_endpoint_listener (table_index, sep, 1);
575 if (lh != SESSION_INVALID_HANDLE)
577 ls = listen_session_get_from_handle (lh);
578 if (ls->app_index != app->app_index)
579 return VNET_API_ERROR_ADDRESS_IN_USE;
581 app_wrk = app_worker_get (sep_ext->app_wrk_index);
582 if (ls->app_wrk_index == app_wrk->wrk_index)
583 return VNET_API_ERROR_ADDRESS_IN_USE;
585 if (app_worker_start_listen (app_wrk, ls))
588 app_listener = app_listener_get (app, ls->listener_db_index);
589 app_listener->workers = clib_bitmap_set (app_listener->workers,
590 app_wrk->wrk_map_index, 1);
592 *res = listen_session_get_handle (ls);
597 * Allocate new listener for application
599 sst = session_type_from_proto_and_ip (sep_ext->transport_proto,
601 ls = listen_session_new (0, sst);
602 ls->app_index = app->app_index;
603 lh = listen_session_get_handle (ls);
604 if (session_listen (ls, sep_ext))
608 ls = listen_session_get_from_handle (lh);
609 app_listener = app_listener_alloc (app);
610 ls->listener_db_index = app_listener->al_index;
613 * Setup app worker as a listener
615 app_wrk = app_worker_get (sep_ext->app_wrk_index);
616 ls->app_wrk_index = app_wrk->wrk_index;
617 if (app_worker_start_listen (app_wrk, ls))
619 app_listener->workers = clib_bitmap_set (app_listener->workers,
620 app_wrk->wrk_map_index, 1);
626 listen_session_del (ls);
631 application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
633 app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
634 app_listener_t *app_listener;
640 hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
641 if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
643 segment_manager_dealloc_fifos (s->rx_fifo->segment_index, s->rx_fifo,
646 if (app_worker_start_listen (app_wrk, s))
649 s->app_wrk_index = app_wrk->wrk_index;
651 app = application_get (old_wrk->app_index);
655 app_listener = app_listener_get (app, s->listener_db_index);
656 app_listener->workers = clib_bitmap_set (app_listener->workers,
657 app_wrk->wrk_map_index, 1);
658 app_listener->workers = clib_bitmap_set (app_listener->workers,
659 old_wrk->wrk_map_index, 0);
664 * Stop listening on session associated to handle
666 * @param handle listener handle
667 * @param app_index index of the app owning the handle.
668 * @param app_wrk_index index of the worker requesting the stop
671 application_stop_listen (u32 app_index, u32 app_wrk_index,
672 session_handle_t handle)
674 app_listener_t *app_listener;
676 app_worker_t *app_wrk;
679 listener = listen_session_get_from_handle (handle);
680 app = application_get (app_index);
681 if (PREDICT_FALSE (!app || app->app_index != listener->app_index))
683 clib_warning ("app doesn't own handle %llu!", handle);
687 app_listener = app_listener_get (app, listener->listener_db_index);
688 if (!clib_bitmap_get (app_listener->workers, app_wrk_index))
690 clib_warning ("worker %u not listening on handle %lu", app_wrk_index,
695 app_wrk = application_get_worker (app, app_wrk_index);
696 app_worker_stop_listen (app_wrk, handle);
697 clib_bitmap_set_no_check (app_listener->workers, app_wrk_index, 0);
699 if (clib_bitmap_is_zero (app_listener->workers))
701 session_stop_listen (listener);
702 app_listener_free (app, app_listener);
703 listen_session_del (listener);
710 vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
712 svm_fifo_segment_private_t *fs;
713 app_worker_map_t *wrk_map;
714 app_worker_t *app_wrk;
715 segment_manager_t *sm;
719 app = application_get (a->app_index);
721 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
722 "App %u does not exist", a->app_index);
726 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
727 return clib_error_return_code (0, rv, 0, "app wrk init: %d", rv);
729 /* Map worker api index to the app */
730 app_wrk->api_client_index = a->api_client_index;
731 application_api_table_add (app->app_index, a->api_client_index);
733 sm = segment_manager_get (app_wrk->first_segment_manager);
734 fs = segment_manager_get_segment_w_lock (sm, 0);
735 a->segment = &fs->ssvm;
736 a->segment_handle = segment_manager_segment_handle (sm, fs);
737 segment_manager_segment_reader_unlock (sm);
738 a->evt_q = app_wrk->event_queue;
739 a->wrk_map_index = app_wrk->wrk_map_index;
743 wrk_map = app_worker_map_get (app, a->wrk_map_index);
745 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
746 "App %u does not have worker %u",
747 app->app_index, a->wrk_map_index);
748 app_wrk = app_worker_get (wrk_map->wrk_index);
750 return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
751 "No worker %u", a->wrk_map_index);
752 application_api_table_del (app_wrk->api_client_index);
753 app_worker_free (app_wrk);
754 app_worker_map_free (app, wrk_map);
755 if (application_n_workers (app) == 0)
756 application_free (app);
762 application_is_proxy (application_t * app)
764 return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
768 application_is_builtin (application_t * app)
770 return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
774 application_is_builtin_proxy (application_t * app)
776 return (application_is_proxy (app) && application_is_builtin (app));
780 application_has_local_scope (application_t * app)
782 return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
786 application_has_global_scope (application_t * app)
788 return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
792 application_use_mq_for_ctrl (application_t * app)
794 return app->flags & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
797 static clib_error_t *
798 application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
799 u8 transport_proto, u8 is_start)
801 app_namespace_t *app_ns = app_namespace_get (app->ns_index);
802 u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
803 session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
804 transport_connection_t *tc;
805 app_worker_t *app_wrk;
809 /* TODO decide if we want proxy to be enabled for all workers */
810 app_wrk = application_get_default_worker (app);
813 s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
817 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
818 sep.sw_if_index = app_ns->sw_if_index;
819 sep.transport_proto = transport_proto;
820 sep.app_wrk_index = app_wrk->wrk_index; /* only default */
821 application_start_listen (app, &sep, &handle);
822 s = listen_session_get_from_handle (handle);
823 s->enqueue_epoch = SESSION_PROXY_LISTENER_INDEX;
828 s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
832 tc = listen_session_get_transport (s);
834 if (!ip_is_zero (&tc->lcl_ip, 1))
838 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
839 sep.transport_proto = transport_proto;
841 sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
843 session_lookup_add_session_endpoint (sti,
844 (session_endpoint_t *) & sep,
847 session_lookup_del_session_endpoint (sti,
848 (session_endpoint_t *) & sep);
855 application_start_stop_proxy_local_scope (application_t * app,
856 u8 transport_proto, u8 is_start)
858 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
859 app_namespace_t *app_ns;
860 app_ns = app_namespace_get (app->ns_index);
862 sep.transport_proto = transport_proto;
867 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
870 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
875 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
877 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
882 application_start_stop_proxy (application_t * app,
883 transport_proto_t transport_proto, u8 is_start)
885 if (application_has_local_scope (app))
886 application_start_stop_proxy_local_scope (app, transport_proto, is_start);
888 if (application_has_global_scope (app))
890 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
891 transport_proto, is_start);
892 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
893 transport_proto, is_start);
898 application_setup_proxy (application_t * app)
900 u16 transports = app->proxied_transports;
901 transport_proto_t tp;
903 ASSERT (application_is_proxy (app));
906 transport_proto_foreach (tp, ({
907 if (transports & (1 << tp))
908 application_start_stop_proxy (app, tp, 1);
914 application_remove_proxy (application_t * app)
916 u16 transports = app->proxied_transports;
917 transport_proto_t tp;
919 ASSERT (application_is_proxy (app));
922 transport_proto_foreach (tp, ({
923 if (transports & (1 << tp))
924 application_start_stop_proxy (app, tp, 0);
929 segment_manager_properties_t *
930 application_segment_manager_properties (application_t * app)
932 return &app->sm_properties;
935 segment_manager_properties_t *
936 application_get_segment_manager_properties (u32 app_index)
938 application_t *app = application_get (app_index);
939 return &app->sm_properties;
943 application_local_listen_session_alloc (application_t * app)
946 pool_get (app->local_listen_sessions, ll);
947 clib_memset (ll, 0, sizeof (*ll));
952 application_local_listener_index (application_t * app, local_session_t * ll)
954 return (ll - app->local_listen_sessions);
958 application_local_listen_session_free (application_t * app,
959 local_session_t * ll)
961 pool_put (app->local_listen_sessions, ll);
963 clib_memset (ll, 0xfb, sizeof (*ll));
967 application_start_local_listen (application_t * app,
968 session_endpoint_cfg_t * sep_ext,
969 session_handle_t * handle)
971 app_listener_t *app_listener;
972 session_endpoint_t *sep;
973 app_worker_t *app_wrk;
978 sep = (session_endpoint_t *) sep_ext;
979 table_index = application_local_session_table (app);
980 app_wrk = app_worker_get (sep_ext->app_wrk_index);
982 /* An exact sep match, as opposed to session_lookup_local_listener */
983 lh = session_lookup_endpoint_listener (table_index, sep, 1);
984 if (lh != SESSION_INVALID_HANDLE)
986 ll = application_get_local_listener_w_handle (lh);
987 if (ll->app_index != app->app_index)
988 return VNET_API_ERROR_ADDRESS_IN_USE;
990 if (ll->app_wrk_index == app_wrk->wrk_index)
991 return VNET_API_ERROR_ADDRESS_IN_USE;
993 app_listener = app_local_listener_get (app, ll->listener_db_index);
994 app_listener->workers = clib_bitmap_set (app_listener->workers,
995 app_wrk->wrk_map_index, 1);
996 *handle = application_local_session_handle (ll);
1000 ll = application_local_listen_session_alloc (app);
1001 ll->session_type = session_type_from_proto_and_ip (TRANSPORT_PROTO_NONE, 0);
1002 ll->app_wrk_index = app_wrk->app_index;
1003 ll->session_index = application_local_listener_index (app, ll);
1004 ll->port = sep_ext->port;
1005 /* Store the original session type for the unbind */
1006 ll->listener_session_type =
1007 session_type_from_proto_and_ip (sep_ext->transport_proto,
1009 ll->transport_listener_index = ~0;
1010 ll->app_index = app->app_index;
1012 app_listener = app_local_listener_alloc (app);
1013 ll->listener_db_index = app_listener->al_index;
1014 app_listener->workers = clib_bitmap_set (app_listener->workers,
1015 app_wrk->wrk_map_index, 1);
1017 *handle = application_local_session_handle (ll);
1018 session_lookup_add_session_endpoint (table_index, sep, *handle);
1024 * Clean up local session table. If we have a listener session use it to
1025 * find the port and proto. If not, the handle must be a local table handle
1029 application_stop_local_listen (u32 app_index, u32 wrk_map_index,
1030 session_handle_t lh)
1032 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1033 u32 table_index, ll_index, server_index;
1034 app_listener_t *app_listener;
1035 app_worker_t *server_wrk;
1037 local_session_t *ll, *ls;
1038 application_t *server;
1040 server = application_get (app_index);
1041 table_index = application_local_session_table (server);
1043 /* We have both local and global table binds. Figure from global what
1044 * sep we should be cleaning up.
1046 if (!session_handle_is_local (lh))
1048 sl = listen_session_get_from_handle (lh);
1049 if (!sl || listen_session_get_local_session_endpoint (sl, &sep))
1051 clib_warning ("broken listener");
1054 lh = session_lookup_endpoint_listener (table_index, &sep, 0);
1055 if (lh == SESSION_INVALID_HANDLE)
1059 local_session_parse_handle (lh, &server_index, &ll_index);
1060 if (PREDICT_FALSE (server_index != app_index))
1062 clib_warning ("app %u does not own local handle 0x%lx", app_index, lh);
1066 ll = application_get_local_listen_session (server, ll_index);
1067 if (PREDICT_FALSE (!ll))
1069 clib_warning ("no local listener");
1073 app_listener = app_local_listener_get (server, ll->listener_db_index);
1074 if (!clib_bitmap_get (app_listener->workers, wrk_map_index))
1076 clib_warning ("app wrk %u not listening on handle %lu", wrk_map_index,
1081 server_wrk = application_get_worker (server, wrk_map_index);
1083 pool_foreach (ls, server_wrk->local_sessions, ({
1084 if (ls->listener_index == ll->session_index)
1085 app_worker_local_session_disconnect (server_wrk->app_index, ls);
1089 clib_bitmap_set_no_check (app_listener->workers, wrk_map_index, 0);
1090 if (clib_bitmap_is_zero (app_listener->workers))
1092 app_local_listener_free (server, app_listener);
1093 application_local_listener_session_endpoint (ll, &sep);
1094 session_lookup_del_session_endpoint (table_index, &sep);
1095 application_local_listen_session_free (server, ll);
1102 vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1105 app = application_get (a->app_index);
1107 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1108 0, "app %u doesn't exist", a->app_index);
1109 app->tls_cert = vec_dup (a->cert);
1114 vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1117 app = application_get (a->app_index);
1119 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1120 0, "app %u doesn't exist", a->app_index);
1121 app->tls_key = vec_dup (a->key);
1126 application_format_listeners (application_t * app, int verbose)
1128 vlib_main_t *vm = vlib_get_main ();
1129 app_worker_map_t *wrk_map;
1130 app_worker_t *app_wrk;
1136 vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1142 pool_foreach (wrk_map, app->worker_maps, ({
1143 app_wrk = app_worker_get (wrk_map->wrk_index);
1144 if (hash_elts (app_wrk->listeners_table) == 0)
1146 hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1147 vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1148 handle, sm_index, verbose);
1155 application_format_connects (application_t * app, int verbose)
1157 app_worker_map_t *wrk_map;
1158 app_worker_t *app_wrk;
1162 app_worker_format_connects (0, verbose);
1167 pool_foreach (wrk_map, app->worker_maps, ({
1168 app_wrk = app_worker_get (wrk_map->wrk_index);
1169 app_worker_format_connects (app_wrk, verbose);
1175 application_format_local_sessions (application_t * app, int verbose)
1177 vlib_main_t *vm = vlib_get_main ();
1178 app_worker_map_t *wrk_map;
1179 app_worker_t *app_wrk;
1180 transport_proto_t tp;
1181 local_session_t *ls;
1186 app_worker_format_local_sessions (0, verbose);
1191 * Format local listeners
1195 pool_foreach (ls, app->local_listen_sessions, ({
1196 tp = session_type_transport_proto (ls->listener_session_type);
1197 conn = format (0, "[L][%U] *:%u", format_transport_proto_short, tp,
1199 vlib_cli_output (vm, "%-40v%-15u%-20s", conn, ls->app_wrk_index, "*");
1200 vec_reset_length (conn);
1205 * Format local accepted/connected sessions
1208 pool_foreach (wrk_map, app->worker_maps, ({
1209 app_wrk = app_worker_get (wrk_map->wrk_index);
1210 app_worker_format_local_sessions (app_wrk, verbose);
1216 application_format_local_connects (application_t * app, int verbose)
1218 app_worker_map_t *wrk_map;
1219 app_worker_t *app_wrk;
1223 app_worker_format_local_connects (0, verbose);
1228 pool_foreach (wrk_map, app->worker_maps, ({
1229 app_wrk = app_worker_get (wrk_map->wrk_index);
1230 app_worker_format_local_connects (app_wrk, verbose);
1236 format_application (u8 * s, va_list * args)
1238 application_t *app = va_arg (*args, application_t *);
1239 CLIB_UNUSED (int verbose) = va_arg (*args, int);
1240 segment_manager_properties_t *props;
1241 const u8 *app_ns_name, *app_name;
1242 app_worker_map_t *wrk_map;
1243 app_worker_t *app_wrk;
1248 s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
1252 app_name = app_get_name (app);
1253 app_ns_name = app_namespace_id_from_index (app->ns_index);
1254 props = application_segment_manager_properties (app);
1257 s = format (s, "%-10u%-20s%-40s", app->app_index, app_name,
1262 s = format (s, "app-name %s app-index %u ns-index %u seg-size %U\n",
1263 app_name, app->app_index, app->ns_index,
1264 format_memory_size, props->add_segment_size);
1265 s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1266 format_memory_size, props->rx_fifo_size,
1267 format_memory_size, props->tx_fifo_size);
1270 pool_foreach (wrk_map, app->worker_maps, ({
1271 app_wrk = app_worker_get (wrk_map->wrk_index);
1272 s = format (s, "%U", format_app_worker, app_wrk);
1280 application_format_all_listeners (vlib_main_t * vm, int do_local, int verbose)
1284 if (!pool_elts (app_main.app_pool))
1286 vlib_cli_output (vm, "No active server bindings");
1292 application_format_local_sessions (0, verbose);
1294 pool_foreach (app, app_main.app_pool, ({
1295 application_format_local_sessions (app, verbose);
1301 application_format_listeners (0, verbose);
1304 pool_foreach (app, app_main.app_pool, ({
1305 application_format_listeners (app, verbose);
1312 application_format_all_clients (vlib_main_t * vm, int do_local, int verbose)
1316 if (!pool_elts (app_main.app_pool))
1318 vlib_cli_output (vm, "No active apps");
1324 application_format_local_connects (0, verbose);
1327 pool_foreach (app, app_main.app_pool, ({
1328 application_format_local_connects (app, verbose);
1334 application_format_connects (0, verbose);
1337 pool_foreach (app, app_main.app_pool, ({
1338 application_format_connects (app, verbose);
1344 static clib_error_t *
1345 show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1346 vlib_cli_command_t * cmd)
1348 int do_server = 0, do_client = 0, do_local = 0;
1353 session_cli_return_if_not_enabled ();
1355 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1357 if (unformat (input, "server"))
1359 else if (unformat (input, "client"))
1361 else if (unformat (input, "local"))
1363 else if (unformat (input, "%u", &app_index))
1365 else if (unformat (input, "verbose"))
1368 return clib_error_return (0, "unknown input `%U'",
1369 format_unformat_error, input);
1374 application_format_all_listeners (vm, do_local, verbose);
1380 application_format_all_clients (vm, do_local, verbose);
1384 if (app_index != ~0)
1386 app = application_get_if_valid (app_index);
1388 return clib_error_return (0, "No app with index %u", app_index);
1390 vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1394 /* Print app related info */
1395 if (!do_server && !do_client)
1397 vlib_cli_output (vm, "%U", format_application, 0, 0);
1399 pool_foreach (app, app_main.app_pool, ({
1400 vlib_cli_output (vm, "%U", format_application, app, 0);
1409 VLIB_CLI_COMMAND (show_app_command, static) =
1412 .short_help = "show app [server|client] [verbose]",
1413 .function = show_app_command_fn,
1418 * fd.io coding-style-patch-verification: ON
1421 * eval: (c-set-style "gnu")