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 #define app_interface_check_thread_and_barrier(_fn, _arg) \
24 if (PREDICT_FALSE (!vlib_thread_is_main_w_barrier ())) \
26 vlib_rpc_call_main_thread (_fn, (u8 *) _arg, sizeof(*_arg)); \
31 application_local_listener_session_endpoint (local_session_t * ll,
32 session_endpoint_t * sep)
34 sep->transport_proto =
35 session_type_transport_proto (ll->listener_session_type);
37 sep->is_ip4 = ll->listener_session_type & 1;
40 static app_listener_t *
41 app_listener_alloc (application_t * app)
43 app_listener_t *app_listener;
44 pool_get (app->listeners, app_listener);
45 clib_memset (app_listener, 0, sizeof (*app_listener));
46 app_listener->al_index = app_listener - app->listeners;
47 app_listener->app_index = app->app_index;
48 app_listener->session_index = SESSION_INVALID_INDEX;
49 app_listener->local_index = SESSION_INVALID_INDEX;
54 app_listener_get (application_t * app, u32 app_listener_index)
56 return pool_elt_at_index (app->listeners, app_listener_index);
60 app_listener_free (application_t * app, app_listener_t * app_listener)
62 clib_bitmap_free (app_listener->workers);
63 pool_put (app->listeners, app_listener);
65 clib_memset (app_listener, 0xfa, sizeof (*app_listener));
69 application_local_listen_session_alloc (application_t * app)
72 pool_get_zero (app->local_listen_sessions, ll);
73 ll->session_index = ll - app->local_listen_sessions;
74 ll->session_type = session_type_from_proto_and_ip (TRANSPORT_PROTO_NONE, 0);
75 ll->app_index = app->app_index;
80 application_local_listen_session_free (application_t * app,
83 pool_put (app->local_listen_sessions, ll);
85 clib_memset (ll, 0xfb, sizeof (*ll));
89 app_listener_id (app_listener_t * al)
91 ASSERT (al->app_index < 1 << 16 && al->al_index < 1 << 16);
92 return (al->app_index << 16 | al->al_index);
96 app_listener_handle (app_listener_t * al)
98 return ((u64) SESSION_LISTENER_PREFIX << 32 | (u64) app_listener_id (al));
102 app_listener_id_parse (u32 listener_id, u32 * app_index,
103 u32 * app_listener_index)
105 *app_index = listener_id >> 16;
106 *app_listener_index = listener_id & 0xFFFF;
110 app_listener_handle_parse (session_handle_t handle, u32 * app_index,
111 u32 * app_listener_index)
113 app_listener_id_parse (handle & 0xFFFFFFFF, app_index, app_listener_index);
116 static app_listener_t *
117 app_listener_get_w_id (u32 listener_id)
119 u32 app_index, app_listener_index;
122 app_listener_id_parse (listener_id, &app_index, &app_listener_index);
123 app = application_get_if_valid (app_index);
126 return app_listener_get (app, app_listener_index);
130 app_listener_get_w_session (session_t * ls)
134 app = application_get_if_valid (ls->app_index);
137 return app_listener_get (app, ls->al_index);
141 app_listener_get_w_handle (session_handle_t handle)
144 if (handle >> 32 != SESSION_LISTENER_PREFIX)
147 return app_listener_get_w_id (handle & 0xFFFFFFFF);
151 app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
153 u32 table_index, fib_proto;
154 session_endpoint_t *sep;
155 session_handle_t handle;
159 sep = (session_endpoint_t *) sep_ext;
160 if (application_has_local_scope (app) && session_endpoint_is_local (sep))
162 table_index = application_local_session_table (app);
163 handle = session_lookup_endpoint_listener (table_index, sep, 1);
164 if (handle != SESSION_INVALID_HANDLE)
166 ll = application_get_local_listener_w_handle (handle);
167 return app_listener_get_w_session ((session_t *) ll);
171 fib_proto = session_endpoint_fib_proto (sep);
172 table_index = application_session_table (app, fib_proto);
173 handle = session_lookup_endpoint_listener (table_index, sep, 1);
174 if (handle != SESSION_INVALID_HANDLE)
176 ls = listen_session_get_from_handle (handle);
177 return app_listener_get_w_session ((session_t *) ls);
184 app_listener_alloc_and_init (application_t * app,
185 session_endpoint_cfg_t * sep,
186 app_listener_t ** listener)
188 app_listener_t *app_listener;
189 local_session_t *ll = 0;
195 app_listener = app_listener_alloc (app);
196 st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
199 * Add session endpoint to local session table. Only binds to "inaddr_any"
200 * (i.e., zero address) are added to local scope table.
202 if (application_has_local_scope (app)
203 && session_endpoint_is_local ((session_endpoint_t *) sep))
207 ll = application_local_listen_session_alloc (app);
208 ll->port = sep->port;
209 /* Store the original session type for the unbind */
210 ll->listener_session_type = st;
211 table_index = application_local_session_table (app);
212 lh = application_local_session_handle (ll);
213 session_lookup_add_session_endpoint (table_index,
214 (session_endpoint_t *) sep, lh);
215 app_listener->local_index = ll->session_index;
216 ll->al_index = app_listener->al_index;
219 if (application_has_global_scope (app))
222 * Start listening on local endpoint for requested transport and scope.
223 * Creates a stream session with state LISTENING to be used in session
224 * lookups, prior to establishing connection. Requests transport to
225 * build it's own specific listening connection.
227 ls = listen_session_new (0, st);
228 ls->app_index = app->app_index;
229 ls->app_wrk_index = sep->app_wrk_index;
231 /* Listen pool can be reallocated if the transport is
233 lh = session_handle (ls);
235 if ((rv = session_listen (ls, sep)))
237 ls = session_get_from_handle (lh);
241 app_listener->session_index = ls->session_index;
242 ls->al_index = app_listener->al_index;
247 app_listener_free (app, app_listener);
251 *listener = app_listener;
256 app_listener_cleanup (app_listener_t * al)
258 application_t *app = application_get (al->app_index);
260 if (al->session_index != SESSION_INVALID_INDEX)
262 session_t *ls = session_get (al->session_index, 0);
263 session_stop_listen (ls);
264 listen_session_del (ls);
266 if (al->local_index != SESSION_INVALID_INDEX)
268 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
272 table_index = application_local_session_table (app);
273 ll = application_get_local_listen_session (app, al->local_index);
274 application_local_listener_session_endpoint (ll, &sep);
275 session_lookup_del_session_endpoint (table_index, &sep);
276 application_local_listen_session_free (app, ll);
278 app_listener_free (app, al);
282 app_listener_select_worker (app_listener_t * al)
287 app = application_get (al->app_index);
288 wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
290 wrk_index = clib_bitmap_first_set (al->workers);
292 ASSERT (wrk_index != ~0);
293 al->accept_rotor = wrk_index;
294 return application_get_worker (app, wrk_index);
298 app_listener_get_session (app_listener_t * al)
300 if (al->session_index == SESSION_INVALID_INDEX)
303 return listen_session_get (al->session_index);
306 static app_worker_map_t *
307 app_worker_map_alloc (application_t * app)
309 app_worker_map_t *map;
310 pool_get (app->worker_maps, map);
311 clib_memset (map, 0, sizeof (*map));
316 app_worker_map_index (application_t * app, app_worker_map_t * map)
318 return (map - app->worker_maps);
322 app_worker_map_free (application_t * app, app_worker_map_t * map)
324 pool_put (app->worker_maps, map);
327 static app_worker_map_t *
328 app_worker_map_get (application_t * app, u32 map_index)
330 if (pool_is_free_index (app->worker_maps, map_index))
332 return pool_elt_at_index (app->worker_maps, map_index);
336 app_get_name (application_t * app)
342 application_session_table (application_t * app, u8 fib_proto)
344 app_namespace_t *app_ns;
345 app_ns = app_namespace_get (app->ns_index);
346 if (!application_has_global_scope (app))
347 return APP_INVALID_INDEX;
348 if (fib_proto == FIB_PROTOCOL_IP4)
349 return session_lookup_get_index_for_fib (fib_proto,
350 app_ns->ip4_fib_index);
352 return session_lookup_get_index_for_fib (fib_proto,
353 app_ns->ip6_fib_index);
357 application_local_session_table (application_t * app)
359 app_namespace_t *app_ns;
360 if (!application_has_local_scope (app))
361 return APP_INVALID_INDEX;
362 app_ns = app_namespace_get (app->ns_index);
363 return app_ns->local_table_index;
367 * Returns app name for app-index
370 application_name_from_index (u32 app_index)
372 application_t *app = application_get (app_index);
375 return app_get_name (app);
379 application_api_table_add (u32 app_index, u32 api_client_index)
381 if (api_client_index != APP_INVALID_INDEX)
382 hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
386 application_api_table_del (u32 api_client_index)
388 hash_unset (app_main.app_by_api_client_index, api_client_index);
392 application_name_table_add (application_t * app)
394 hash_set_mem (app_main.app_by_name, app->name, app->app_index);
398 application_name_table_del (application_t * app)
400 hash_unset_mem (app_main.app_by_name, app->name);
404 application_lookup (u32 api_client_index)
407 p = hash_get (app_main.app_by_api_client_index, api_client_index);
409 return application_get_if_valid (p[0]);
415 application_lookup_name (const u8 * name)
418 p = hash_get_mem (app_main.app_by_name, name);
420 return application_get (p[0]);
425 static application_t *
426 application_alloc (void)
429 pool_get (app_main.app_pool, app);
430 clib_memset (app, 0, sizeof (*app));
431 app->app_index = app - app_main.app_pool;
436 application_get (u32 app_index)
438 if (app_index == APP_INVALID_INDEX)
440 return pool_elt_at_index (app_main.app_pool, app_index);
444 application_get_if_valid (u32 app_index)
446 if (pool_is_free_index (app_main.app_pool, app_index))
449 return pool_elt_at_index (app_main.app_pool, app_index);
453 application_verify_cb_fns (session_cb_vft_t * cb_fns)
455 if (cb_fns->session_accept_callback == 0)
456 clib_warning ("No accept callback function provided");
457 if (cb_fns->session_connected_callback == 0)
458 clib_warning ("No session connected callback function provided");
459 if (cb_fns->session_disconnect_callback == 0)
460 clib_warning ("No session disconnect callback function provided");
461 if (cb_fns->session_reset_callback == 0)
462 clib_warning ("No session reset callback function provided");
466 * Check app config for given segment type
468 * Returns 1 on success and 0 otherwise
471 application_verify_cfg (ssvm_segment_type_t st)
474 if (st == SSVM_SEGMENT_MEMFD)
476 is_valid = (session_manager_get_evt_q_segment () != 0);
478 clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
481 else if (st == SSVM_SEGMENT_SHM)
483 is_valid = (session_manager_get_evt_q_segment () == 0);
485 clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
493 application_alloc_and_init (app_init_args_t * a)
495 ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
496 segment_manager_properties_t *props;
497 vl_api_registration_t *reg;
501 app = application_alloc ();
502 options = a->options;
504 * Make sure we support the requested configuration
506 if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
508 reg = vl_api_client_index_to_registration (a->api_client_index);
510 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
511 if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
512 seg_type = SSVM_SEGMENT_SHM;
516 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
518 clib_warning ("mq eventfds can only be used if socket transport is "
520 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
522 seg_type = SSVM_SEGMENT_PRIVATE;
525 if (!application_verify_cfg (seg_type))
526 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
528 /* Check that the obvious things are properly set up */
529 application_verify_cb_fns (a->session_cb_vft);
531 app->flags = options[APP_OPTIONS_FLAGS];
532 app->cb_fns = *a->session_cb_vft;
533 app->ns_index = options[APP_OPTIONS_NAMESPACE];
534 app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
535 app->name = vec_dup (a->name);
537 /* If no scope enabled, default to global */
538 if (!application_has_global_scope (app)
539 && !application_has_local_scope (app))
540 app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
542 props = application_segment_manager_properties (app);
543 segment_manager_properties_init (props);
544 props->segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
545 props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
546 if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
548 props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
549 props->add_segment = 1;
551 if (options[APP_OPTIONS_RX_FIFO_SIZE])
552 props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
553 if (options[APP_OPTIONS_TX_FIFO_SIZE])
554 props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
555 if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
556 props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
557 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
558 props->use_mq_eventfd = 1;
559 if (options[APP_OPTIONS_TLS_ENGINE])
560 app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
561 props->segment_type = seg_type;
563 /* Add app to lookup by api_client_index table */
564 if (!application_is_builtin (app))
565 application_api_table_add (app->app_index, a->api_client_index);
567 application_name_table_add (app);
569 a->app_index = app->app_index;
571 APP_DBG ("New app name: %v api index: %u index %u", app->name,
572 app->api_client_index, app->app_index);
578 application_free (application_t * app)
580 app_worker_map_t *wrk_map;
581 app_worker_t *app_wrk;
584 session_endpoint_t sep;
587 * The app event queue allocated in first segment is cleared with
588 * the segment manager. No need to explicitly free it.
590 APP_DBG ("Delete app name %v api index: %d index: %d", app->name,
591 app->api_client_index, app->app_index);
593 if (application_is_proxy (app))
594 application_remove_proxy (app);
601 pool_flush (wrk_map, app->worker_maps, ({
602 app_wrk = app_worker_get (wrk_map->wrk_index);
603 app_worker_free (app_wrk);
606 pool_free (app->worker_maps);
609 * Free local listeners. Global table unbinds stop local listeners
610 * as well, but if we have only local binds, these won't be cleaned up.
611 * Don't bother with local accepted sessions, we clean them when
612 * cleaning up the worker.
614 table_index = application_local_session_table (app);
616 pool_foreach (ll, app->local_listen_sessions, ({
617 application_local_listener_session_endpoint (ll, &sep);
618 session_lookup_del_session_endpoint (table_index, &sep);
621 pool_free (app->local_listen_sessions);
624 * Cleanup remaining state
626 if (application_is_builtin (app))
627 application_name_table_del (app);
628 vec_free (app->name);
629 vec_free (app->tls_cert);
630 vec_free (app->tls_key);
631 pool_put (app_main.app_pool, app);
635 application_detach_process (application_t * app, u32 api_client_index)
637 vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
638 app_worker_map_t *wrk_map;
639 u32 *wrks = 0, *wrk_index;
640 app_worker_t *app_wrk;
642 if (api_client_index == ~0)
644 application_free (app);
648 APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
649 app->app_index, app->api_client_index);
652 pool_foreach (wrk_map, app->worker_maps, ({
653 app_wrk = app_worker_get (wrk_map->wrk_index);
654 if (app_wrk->api_client_index == api_client_index)
655 vec_add1 (wrks, app_wrk->wrk_index);
661 clib_warning ("no workers for app %u api_index %u", app->app_index,
666 args->app_index = app->app_index;
667 args->api_client_index = api_client_index;
668 vec_foreach (wrk_index, wrks)
670 app_wrk = app_worker_get (wrk_index[0]);
671 args->wrk_map_index = app_wrk->wrk_map_index;
673 vnet_app_worker_add_del (args);
679 application_get_worker (application_t * app, u32 wrk_map_index)
681 app_worker_map_t *map;
682 map = app_worker_map_get (app, wrk_map_index);
685 return app_worker_get (map->wrk_index);
689 application_get_default_worker (application_t * app)
691 return application_get_worker (app, 0);
695 application_n_workers (application_t * app)
697 return pool_elts (app->worker_maps);
701 application_listener_select_worker (session_t * ls)
705 al = app_listener_get_w_session (ls);
706 return app_listener_select_worker (al);
710 application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
712 app_worker_map_t *wrk_map;
713 app_worker_t *app_wrk;
714 segment_manager_t *sm;
717 app_wrk = app_worker_alloc (app);
718 wrk_map = app_worker_map_alloc (app);
719 wrk_map->wrk_index = app_wrk->wrk_index;
720 app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
723 * Setup first segment manager
725 sm = segment_manager_new ();
726 sm->app_wrk_index = app_wrk->wrk_index;
728 if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
729 app->sm_properties.prealloc_fifos)))
731 app_worker_free (app_wrk);
734 sm->first_is_protected = 1;
739 app_wrk->first_segment_manager = segment_manager_index (sm);
740 app_wrk->listeners_table = hash_create (0, sizeof (u64));
741 app_wrk->event_queue = segment_manager_event_queue (sm);
742 app_wrk->app_is_builtin = application_is_builtin (app);
745 * Segment manager for local sessions
747 sm = segment_manager_new ();
748 sm->app_wrk_index = app_wrk->wrk_index;
749 app_wrk->local_segment_manager = segment_manager_index (sm);
750 app_wrk->local_connects = hash_create (0, sizeof (u64));
758 vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
760 svm_fifo_segment_private_t *fs;
761 app_worker_map_t *wrk_map;
762 app_worker_t *app_wrk;
763 segment_manager_t *sm;
767 app = application_get (a->app_index);
769 return VNET_API_ERROR_INVALID_VALUE;
773 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
776 /* Map worker api index to the app */
777 app_wrk->api_client_index = a->api_client_index;
778 application_api_table_add (app->app_index, a->api_client_index);
780 sm = segment_manager_get (app_wrk->first_segment_manager);
781 fs = segment_manager_get_segment_w_lock (sm, 0);
782 a->segment = &fs->ssvm;
783 a->segment_handle = segment_manager_segment_handle (sm, fs);
784 segment_manager_segment_reader_unlock (sm);
785 a->evt_q = app_wrk->event_queue;
786 a->wrk_map_index = app_wrk->wrk_map_index;
790 wrk_map = app_worker_map_get (app, a->wrk_map_index);
792 return VNET_API_ERROR_INVALID_VALUE;
794 app_wrk = app_worker_get (wrk_map->wrk_index);
796 return VNET_API_ERROR_INVALID_VALUE;
798 application_api_table_del (app_wrk->api_client_index);
799 app_worker_free (app_wrk);
800 app_worker_map_free (app, wrk_map);
801 if (application_n_workers (app) == 0)
802 application_free (app);
808 app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
810 app_namespace_t *app_ns;
811 if (vec_len (namespace_id) == 0)
813 /* Use default namespace */
818 *app_ns_index = app_namespace_index_from_id (namespace_id);
819 if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
820 return VNET_API_ERROR_APP_INVALID_NS;
821 app_ns = app_namespace_get (*app_ns_index);
823 return VNET_API_ERROR_APP_INVALID_NS;
824 if (app_ns->ns_secret != secret)
825 return VNET_API_ERROR_APP_WRONG_NS_SECRET;
830 app_name_from_api_index (u32 api_client_index)
832 vl_api_registration_t *regp;
833 regp = vl_api_client_index_to_registration (api_client_index);
835 return format (0, "%s%c", regp->name, 0);
837 clib_warning ("api client index %u does not have an api registration!",
839 return format (0, "unknown%c", 0);
843 * Attach application to vpp
845 * Allocates a vpp app, i.e., a structure that keeps back pointers
846 * to external app and a segment manager for shared memory fifo based
847 * communication with the external app.
850 vnet_application_attach (vnet_app_attach_args_t * a)
852 svm_fifo_segment_private_t *fs;
853 application_t *app = 0;
854 app_worker_t *app_wrk;
855 segment_manager_t *sm;
856 u32 app_ns_index = 0;
861 if (a->api_client_index != APP_INVALID_INDEX)
862 app = application_lookup (a->api_client_index);
864 app = application_lookup_name (a->name);
866 return VNET_API_ERROR_INVALID_VALUE;
869 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
871 if (a->api_client_index != APP_INVALID_INDEX)
873 app_name = app_name_from_api_index (a->api_client_index);
877 secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
878 if ((rv = app_validate_namespace (a->namespace_id, secret, &app_ns_index)))
880 a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
882 if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
885 app = application_get (a->app_index);
886 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
889 a->app_evt_q = app_wrk->event_queue;
890 app_wrk->api_client_index = a->api_client_index;
891 sm = segment_manager_get (app_wrk->first_segment_manager);
892 fs = segment_manager_get_segment_w_lock (sm, 0);
894 if (application_is_proxy (app))
895 application_setup_proxy (app);
897 ASSERT (vec_len (fs->ssvm.name) <= 128);
898 a->segment = &fs->ssvm;
899 a->segment_handle = segment_manager_segment_handle (sm, fs);
901 segment_manager_segment_reader_unlock (sm);
907 * Detach application from vpp
910 vnet_application_detach (vnet_app_detach_args_t * a)
914 app = application_get_if_valid (a->app_index);
917 clib_warning ("app not attached");
918 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
921 app_interface_check_thread_and_barrier (vnet_application_detach, a);
922 application_detach_process (app, a->api_client_index);
928 session_endpoint_in_ns (session_endpoint_t * sep)
930 u8 is_lep = session_endpoint_is_local (sep);
931 if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
932 && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
934 clib_warning ("sw_if_index %u not configured with ip %U",
935 sep->sw_if_index, format_ip46_address, &sep->ip,
939 return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
943 session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
944 application_t * app, u8 is_connect)
946 app_namespace_t *app_ns;
947 u32 ns_index, fib_index;
949 ns_index = app->ns_index;
951 /* App is a transport proto, so fetch the calling app's ns */
952 if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
954 app_worker_t *owner_wrk;
955 application_t *owner_app;
957 owner_wrk = app_worker_get (sep->app_wrk_index);
958 owner_app = application_get (owner_wrk->app_index);
959 ns_index = owner_app->ns_index;
961 app_ns = app_namespace_get (ns_index);
965 /* Ask transport and network to bind to/connect using local interface
966 * that "supports" app's namespace. This will fix our local connection
970 /* If in default namespace and user requested a fib index use it */
971 if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
972 fib_index = sep->fib_index;
974 fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
975 sep->peer.fib_index = fib_index;
976 sep->fib_index = fib_index;
980 sep->sw_if_index = app_ns->sw_if_index;
984 if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
985 && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
986 && sep->peer.sw_if_index != app_ns->sw_if_index)
987 clib_warning ("Local sw_if_index different from app ns sw_if_index");
989 sep->peer.sw_if_index = app_ns->sw_if_index;
994 vnet_listen (vnet_listen_args_t * a)
996 app_listener_t *app_listener;
997 app_worker_t *app_wrk;
1001 app = application_get_if_valid (a->app_index);
1003 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1005 app_wrk = application_get_worker (app, a->wrk_map_index);
1007 return VNET_API_ERROR_INVALID_VALUE;
1009 a->sep_ext.app_wrk_index = app_wrk->wrk_index;
1011 session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
1012 if (!session_endpoint_in_ns (&a->sep))
1013 return VNET_API_ERROR_INVALID_VALUE_2;
1016 * Check if we already have an app listener
1018 app_listener = app_listener_lookup (app, &a->sep_ext);
1021 if (app_listener->app_index != app->app_index)
1022 return VNET_API_ERROR_ADDRESS_IN_USE;
1023 if (app_worker_start_listen (app_wrk, app_listener))
1025 a->handle = app_listener_handle (app_listener);
1030 * Create new app listener
1032 if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1035 if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1037 app_listener_cleanup (app_listener);
1041 a->handle = app_listener_handle (app_listener);
1046 vnet_connect (vnet_connect_args_t * a)
1048 app_worker_t *server_wrk, *client_wrk;
1049 application_t *client;
1050 local_session_t *ll;
1057 if (session_endpoint_is_zero (&a->sep))
1058 return VNET_API_ERROR_INVALID_VALUE;
1060 client = application_get (a->app_index);
1061 session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1062 client_wrk = application_get_worker (client, a->wrk_map_index);
1065 * First check the local scope for locally attached destinations.
1066 * If we have local scope, we pass *all* connects through it since we may
1067 * have special policy rules even for non-local destinations, think proxy.
1069 if (application_has_local_scope (client))
1071 table_index = application_local_session_table (client);
1072 lh = session_lookup_local_endpoint (table_index, &a->sep);
1073 if (lh == SESSION_DROP_HANDLE)
1074 return VNET_API_ERROR_APP_CONNECT_FILTERED;
1076 if (lh == SESSION_INVALID_HANDLE)
1079 ll = application_get_local_listener_w_handle (lh);
1080 al = app_listener_get_w_session ((session_t *) ll);
1083 * Break loop if rule in local table points to connecting app. This
1084 * can happen if client is a generic proxy. Route connect through
1085 * global table instead.
1087 if (al->app_index == a->app_index)
1090 server_wrk = app_listener_select_worker (al);
1091 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1096 * If nothing found, check the global scope for locally attached
1097 * destinations. Make sure first that we're allowed to.
1101 if (session_endpoint_is_local (&a->sep))
1102 return VNET_API_ERROR_SESSION_CONNECT;
1104 if (!application_has_global_scope (client))
1105 return VNET_API_ERROR_APP_CONNECT_SCOPE;
1107 fib_proto = session_endpoint_fib_proto (&a->sep);
1108 table_index = application_session_table (client, fib_proto);
1109 ls = session_lookup_listener (table_index, &a->sep);
1112 al = app_listener_get_w_session (ls);
1113 server_wrk = app_listener_select_worker (al);
1114 ll = (local_session_t *) ls;
1115 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1120 * Not connecting to a local server, propagate to transport
1122 if (app_worker_connect_session (client_wrk, &a->sep, a->api_context))
1123 return VNET_API_ERROR_SESSION_CONNECT;
1128 vnet_unlisten (vnet_unlisten_args_t * a)
1130 app_worker_t *app_wrk;
1134 if (!(app = application_get_if_valid (a->app_index)))
1135 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1137 al = app_listener_get_w_handle (a->handle);
1138 if (al->app_index != app->app_index)
1140 clib_warning ("app doesn't own handle %llu!", a->handle);
1144 app_wrk = application_get_worker (app, a->wrk_map_index);
1147 clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1151 return app_worker_stop_listen (app_wrk, al);
1155 vnet_disconnect_session (vnet_disconnect_args_t * a)
1157 if (session_handle_is_local (a->handle))
1159 local_session_t *ls;
1161 /* Disconnect reply came to worker 1 not main thread */
1162 app_interface_check_thread_and_barrier (vnet_disconnect_session, a);
1164 if (!(ls = app_worker_get_local_session_from_handle (a->handle)))
1167 return app_worker_local_session_disconnect (a->app_index, ls);
1171 app_worker_t *app_wrk;
1174 s = session_get_from_handle_if_valid (a->handle);
1176 return VNET_API_ERROR_INVALID_VALUE;
1177 app_wrk = app_worker_get (s->app_wrk_index);
1178 if (app_wrk->app_index != a->app_index)
1179 return VNET_API_ERROR_INVALID_VALUE;
1181 /* We're peeking into another's thread pool. Make sure */
1182 ASSERT (s->session_index == session_index_from_handle (a->handle));
1190 application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1192 app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1193 app_listener_t *app_listener;
1199 hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1200 if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1202 segment_manager_dealloc_fifos (s->rx_fifo->segment_index, s->rx_fifo,
1205 app = application_get (old_wrk->app_index);
1209 app_listener = app_listener_get (app, s->al_index);
1211 /* Only remove from lb for now */
1212 app_listener->workers = clib_bitmap_set (app_listener->workers,
1213 old_wrk->wrk_map_index, 0);
1215 if (app_worker_start_listen (app_wrk, app_listener))
1218 s->app_wrk_index = app_wrk->wrk_index;
1224 application_is_proxy (application_t * app)
1226 return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1230 application_is_builtin (application_t * app)
1232 return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1236 application_is_builtin_proxy (application_t * app)
1238 return (application_is_proxy (app) && application_is_builtin (app));
1242 application_has_local_scope (application_t * app)
1244 return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1248 application_has_global_scope (application_t * app)
1250 return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1254 application_use_mq_for_ctrl (application_t * app)
1256 return app->flags & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
1259 static clib_error_t *
1260 application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1261 u8 transport_proto, u8 is_start)
1263 app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1264 u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
1265 session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
1266 transport_connection_t *tc;
1267 app_worker_t *app_wrk;
1272 /* TODO decide if we want proxy to be enabled for all workers */
1273 app_wrk = application_get_default_worker (app);
1276 s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
1279 sep.is_ip4 = is_ip4;
1280 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1281 sep.sw_if_index = app_ns->sw_if_index;
1282 sep.transport_proto = transport_proto;
1283 sep.app_wrk_index = app_wrk->wrk_index; /* only default */
1285 /* force global scope listener */
1287 app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1288 app_listener_alloc_and_init (app, &sep, &al);
1291 app_worker_start_listen (app_wrk, al);
1292 s = listen_session_get (al->session_index);
1293 s->enqueue_epoch = SESSION_PROXY_LISTENER_INDEX;
1298 s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
1302 tc = listen_session_get_transport (s);
1304 if (!ip_is_zero (&tc->lcl_ip, 1))
1307 sep.is_ip4 = is_ip4;
1308 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1309 sep.transport_proto = transport_proto;
1311 sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
1313 session_lookup_add_session_endpoint (sti,
1314 (session_endpoint_t *) & sep,
1317 session_lookup_del_session_endpoint (sti,
1318 (session_endpoint_t *) & sep);
1325 application_start_stop_proxy_local_scope (application_t * app,
1326 u8 transport_proto, u8 is_start)
1328 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1329 app_namespace_t *app_ns;
1330 app_ns = app_namespace_get (app->ns_index);
1332 sep.transport_proto = transport_proto;
1337 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1340 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1345 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1347 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1352 application_start_stop_proxy (application_t * app,
1353 transport_proto_t transport_proto, u8 is_start)
1355 if (application_has_local_scope (app))
1356 application_start_stop_proxy_local_scope (app, transport_proto, is_start);
1358 if (application_has_global_scope (app))
1360 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1361 transport_proto, is_start);
1362 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1363 transport_proto, is_start);
1368 application_setup_proxy (application_t * app)
1370 u16 transports = app->proxied_transports;
1371 transport_proto_t tp;
1373 ASSERT (application_is_proxy (app));
1376 transport_proto_foreach (tp, ({
1377 if (transports & (1 << tp))
1378 application_start_stop_proxy (app, tp, 1);
1384 application_remove_proxy (application_t * app)
1386 u16 transports = app->proxied_transports;
1387 transport_proto_t tp;
1389 ASSERT (application_is_proxy (app));
1392 transport_proto_foreach (tp, ({
1393 if (transports & (1 << tp))
1394 application_start_stop_proxy (app, tp, 0);
1399 segment_manager_properties_t *
1400 application_segment_manager_properties (application_t * app)
1402 return &app->sm_properties;
1405 segment_manager_properties_t *
1406 application_get_segment_manager_properties (u32 app_index)
1408 application_t *app = application_get (app_index);
1409 return &app->sm_properties;
1413 vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1416 app = application_get (a->app_index);
1418 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1419 0, "app %u doesn't exist", a->app_index);
1420 app->tls_cert = vec_dup (a->cert);
1425 vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1428 app = application_get (a->app_index);
1430 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1431 0, "app %u doesn't exist", a->app_index);
1432 app->tls_key = vec_dup (a->key);
1437 application_format_listeners (application_t * app, int verbose)
1439 vlib_main_t *vm = vlib_get_main ();
1440 app_worker_map_t *wrk_map;
1441 app_worker_t *app_wrk;
1447 vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1453 pool_foreach (wrk_map, app->worker_maps, ({
1454 app_wrk = app_worker_get (wrk_map->wrk_index);
1455 if (hash_elts (app_wrk->listeners_table) == 0)
1457 hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1458 vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1459 handle, sm_index, verbose);
1466 application_format_connects (application_t * app, int verbose)
1468 app_worker_map_t *wrk_map;
1469 app_worker_t *app_wrk;
1473 app_worker_format_connects (0, verbose);
1478 pool_foreach (wrk_map, app->worker_maps, ({
1479 app_wrk = app_worker_get (wrk_map->wrk_index);
1480 app_worker_format_connects (app_wrk, verbose);
1486 application_format_local_sessions (application_t * app, int verbose)
1488 vlib_main_t *vm = vlib_get_main ();
1489 app_worker_map_t *wrk_map;
1490 app_worker_t *app_wrk;
1491 transport_proto_t tp;
1492 local_session_t *ls;
1497 app_worker_format_local_sessions (0, verbose);
1502 * Format local listeners
1506 pool_foreach (ls, app->local_listen_sessions, ({
1507 tp = session_type_transport_proto (ls->listener_session_type);
1508 conn = format (0, "[L][%U] *:%u", format_transport_proto_short, tp,
1510 vlib_cli_output (vm, "%-40v%-15u%-20s", conn, ls->app_wrk_index, "*");
1511 vec_reset_length (conn);
1516 * Format local accepted/connected sessions
1519 pool_foreach (wrk_map, app->worker_maps, ({
1520 app_wrk = app_worker_get (wrk_map->wrk_index);
1521 app_worker_format_local_sessions (app_wrk, verbose);
1527 application_format_local_connects (application_t * app, int verbose)
1529 app_worker_map_t *wrk_map;
1530 app_worker_t *app_wrk;
1534 app_worker_format_local_connects (0, verbose);
1539 pool_foreach (wrk_map, app->worker_maps, ({
1540 app_wrk = app_worker_get (wrk_map->wrk_index);
1541 app_worker_format_local_connects (app_wrk, verbose);
1547 format_application (u8 * s, va_list * args)
1549 application_t *app = va_arg (*args, application_t *);
1550 CLIB_UNUSED (int verbose) = va_arg (*args, int);
1551 segment_manager_properties_t *props;
1552 const u8 *app_ns_name, *app_name;
1553 app_worker_map_t *wrk_map;
1554 app_worker_t *app_wrk;
1559 s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
1563 app_name = app_get_name (app);
1564 app_ns_name = app_namespace_id_from_index (app->ns_index);
1565 props = application_segment_manager_properties (app);
1568 s = format (s, "%-10u%-20s%-40s", app->app_index, app_name,
1573 s = format (s, "app-name %s app-index %u ns-index %u seg-size %U\n",
1574 app_name, app->app_index, app->ns_index,
1575 format_memory_size, props->add_segment_size);
1576 s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1577 format_memory_size, props->rx_fifo_size,
1578 format_memory_size, props->tx_fifo_size);
1581 pool_foreach (wrk_map, app->worker_maps, ({
1582 app_wrk = app_worker_get (wrk_map->wrk_index);
1583 s = format (s, "%U", format_app_worker, app_wrk);
1591 application_format_all_listeners (vlib_main_t * vm, int do_local, int verbose)
1595 if (!pool_elts (app_main.app_pool))
1597 vlib_cli_output (vm, "No active server bindings");
1603 application_format_local_sessions (0, verbose);
1605 pool_foreach (app, app_main.app_pool, ({
1606 application_format_local_sessions (app, verbose);
1612 application_format_listeners (0, verbose);
1615 pool_foreach (app, app_main.app_pool, ({
1616 application_format_listeners (app, verbose);
1623 application_format_all_clients (vlib_main_t * vm, int do_local, int verbose)
1627 if (!pool_elts (app_main.app_pool))
1629 vlib_cli_output (vm, "No active apps");
1635 application_format_local_connects (0, verbose);
1638 pool_foreach (app, app_main.app_pool, ({
1639 application_format_local_connects (app, verbose);
1645 application_format_connects (0, verbose);
1648 pool_foreach (app, app_main.app_pool, ({
1649 application_format_connects (app, verbose);
1655 static clib_error_t *
1656 show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1657 vlib_cli_command_t * cmd)
1659 int do_server = 0, do_client = 0, do_local = 0;
1664 session_cli_return_if_not_enabled ();
1666 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1668 if (unformat (input, "server"))
1670 else if (unformat (input, "client"))
1672 else if (unformat (input, "local"))
1674 else if (unformat (input, "%u", &app_index))
1676 else if (unformat (input, "verbose"))
1679 return clib_error_return (0, "unknown input `%U'",
1680 format_unformat_error, input);
1685 application_format_all_listeners (vm, do_local, verbose);
1691 application_format_all_clients (vm, do_local, verbose);
1695 if (app_index != ~0)
1697 app = application_get_if_valid (app_index);
1699 return clib_error_return (0, "No app with index %u", app_index);
1701 vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1705 /* Print app related info */
1706 if (!do_server && !do_client)
1708 vlib_cli_output (vm, "%U", format_application, 0, 0);
1710 pool_foreach (app, app_main.app_pool, ({
1711 vlib_cli_output (vm, "%U", format_application, app, 0);
1720 VLIB_CLI_COMMAND (show_app_command, static) =
1723 .short_help = "show app [server|client] [verbose]",
1724 .function = show_app_command_fn,
1729 * fd.io coding-style-patch-verification: ON
1732 * eval: (c-set-style "gnu")