blob: 954b934c1388a20c5ba4bd5f7f0caaa71f2fcfbf [file] [log] [blame]
Dave Barach68b0fb02017-02-28 15:15:56 -05001/*
Florin Coras288eaab2019-02-03 15:26:14 -08002 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
Dave Barach68b0fb02017-02-28 15:15:56 -05003 * 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:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15
16#include <vnet/session/application.h>
Florin Coras6cf30ad2017-04-04 23:08:23 -070017#include <vnet/session/application_interface.h>
Florin Corascea194d2017-10-02 00:18:51 -070018#include <vnet/session/application_namespace.h>
Florin Corasba7d8f52019-02-22 13:11:38 -080019#include <vnet/session/application_local.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050020#include <vnet/session/session.h>
21
Florin Coras15531972018-08-12 23:50:53 -070022static app_main_t app_main;
Dave Barach68b0fb02017-02-28 15:15:56 -050023
Florin Corasc1a42652019-02-08 18:27:29 -080024#define app_interface_check_thread_and_barrier(_fn, _arg) \
25 if (PREDICT_FALSE (!vlib_thread_is_main_w_barrier ())) \
26 { \
27 vlib_rpc_call_main_thread (_fn, (u8 *) _arg, sizeof(*_arg)); \
28 return 0; \
29 }
30
Florin Corasab2f6db2018-08-31 14:31:41 -070031static app_listener_t *
32app_listener_alloc (application_t * app)
33{
34 app_listener_t *app_listener;
35 pool_get (app->listeners, app_listener);
Dave Barachb7b92992018-10-17 10:38:51 -040036 clib_memset (app_listener, 0, sizeof (*app_listener));
Florin Corasab2f6db2018-08-31 14:31:41 -070037 app_listener->al_index = app_listener - app->listeners;
Florin Corasc9940fc2019-02-05 20:55:11 -080038 app_listener->app_index = app->app_index;
39 app_listener->session_index = SESSION_INVALID_INDEX;
40 app_listener->local_index = SESSION_INVALID_INDEX;
Florin Corasab2f6db2018-08-31 14:31:41 -070041 return app_listener;
42}
43
Florin Corasc9940fc2019-02-05 20:55:11 -080044app_listener_t *
Florin Corasab2f6db2018-08-31 14:31:41 -070045app_listener_get (application_t * app, u32 app_listener_index)
46{
47 return pool_elt_at_index (app->listeners, app_listener_index);
48}
49
50static void
51app_listener_free (application_t * app, app_listener_t * app_listener)
52{
53 clib_bitmap_free (app_listener->workers);
54 pool_put (app->listeners, app_listener);
55 if (CLIB_DEBUG)
Dave Barachb7b92992018-10-17 10:38:51 -040056 clib_memset (app_listener, 0xfa, sizeof (*app_listener));
Florin Corasab2f6db2018-08-31 14:31:41 -070057}
58
Florin Corasc9940fc2019-02-05 20:55:11 -080059static u32
60app_listener_id (app_listener_t * al)
61{
62 ASSERT (al->app_index < 1 << 16 && al->al_index < 1 << 16);
63 return (al->app_index << 16 | al->al_index);
64}
65
66session_handle_t
67app_listener_handle (app_listener_t * al)
68{
69 return ((u64) SESSION_LISTENER_PREFIX << 32 | (u64) app_listener_id (al));
Florin Corasab2f6db2018-08-31 14:31:41 -070070}
71
72static void
Florin Corasc9940fc2019-02-05 20:55:11 -080073app_listener_id_parse (u32 listener_id, u32 * app_index,
74 u32 * app_listener_index)
Florin Corasab2f6db2018-08-31 14:31:41 -070075{
Florin Corasc9940fc2019-02-05 20:55:11 -080076 *app_index = listener_id >> 16;
77 *app_listener_index = listener_id & 0xFFFF;
78}
79
80void
81app_listener_handle_parse (session_handle_t handle, u32 * app_index,
82 u32 * app_listener_index)
83{
84 app_listener_id_parse (handle & 0xFFFFFFFF, app_index, app_listener_index);
85}
86
87static app_listener_t *
88app_listener_get_w_id (u32 listener_id)
89{
90 u32 app_index, app_listener_index;
91 application_t *app;
92
93 app_listener_id_parse (listener_id, &app_index, &app_listener_index);
94 app = application_get_if_valid (app_index);
95 if (!app)
96 return 0;
97 return app_listener_get (app, app_listener_index);
98}
99
100app_listener_t *
101app_listener_get_w_session (session_t * ls)
102{
103 application_t *app;
104
105 app = application_get_if_valid (ls->app_index);
106 if (!app)
107 return 0;
108 return app_listener_get (app, ls->al_index);
109}
110
111app_listener_t *
112app_listener_get_w_handle (session_handle_t handle)
113{
114
115 if (handle >> 32 != SESSION_LISTENER_PREFIX)
116 return 0;
117
118 return app_listener_get_w_id (handle & 0xFFFFFFFF);
119}
120
121app_listener_t *
122app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
123{
124 u32 table_index, fib_proto;
125 session_endpoint_t *sep;
126 session_handle_t handle;
127 local_session_t *ll;
128 session_t *ls;
129
130 sep = (session_endpoint_t *) sep_ext;
131 if (application_has_local_scope (app) && session_endpoint_is_local (sep))
132 {
133 table_index = application_local_session_table (app);
134 handle = session_lookup_endpoint_listener (table_index, sep, 1);
135 if (handle != SESSION_INVALID_HANDLE)
136 {
137 ll = application_get_local_listener_w_handle (handle);
138 return app_listener_get_w_session ((session_t *) ll);
139 }
140 }
141
142 fib_proto = session_endpoint_fib_proto (sep);
143 table_index = application_session_table (app, fib_proto);
144 handle = session_lookup_endpoint_listener (table_index, sep, 1);
145 if (handle != SESSION_INVALID_HANDLE)
146 {
147 ls = listen_session_get_from_handle (handle);
148 return app_listener_get_w_session ((session_t *) ls);
149 }
150
151 return 0;
152}
153
154int
155app_listener_alloc_and_init (application_t * app,
156 session_endpoint_cfg_t * sep,
157 app_listener_t ** listener)
158{
159 app_listener_t *app_listener;
160 local_session_t *ll = 0;
161 session_handle_t lh;
162 session_type_t st;
163 session_t *ls = 0;
Florin Corasa27a46e2019-02-18 13:02:28 -0800164 u32 al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800165 int rv;
166
167 app_listener = app_listener_alloc (app);
Florin Corasa27a46e2019-02-18 13:02:28 -0800168 al_index = app_listener->al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800169 st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
170
171 /*
172 * Add session endpoint to local session table. Only binds to "inaddr_any"
173 * (i.e., zero address) are added to local scope table.
174 */
175 if (application_has_local_scope (app)
176 && session_endpoint_is_local ((session_endpoint_t *) sep))
177 {
178 u32 table_index;
179
180 ll = application_local_listen_session_alloc (app);
181 ll->port = sep->port;
182 /* Store the original session type for the unbind */
183 ll->listener_session_type = st;
184 table_index = application_local_session_table (app);
185 lh = application_local_session_handle (ll);
186 session_lookup_add_session_endpoint (table_index,
187 (session_endpoint_t *) sep, lh);
188 app_listener->local_index = ll->session_index;
189 ll->al_index = app_listener->al_index;
190 }
191
192 if (application_has_global_scope (app))
193 {
194 /*
195 * Start listening on local endpoint for requested transport and scope.
196 * Creates a stream session with state LISTENING to be used in session
197 * lookups, prior to establishing connection. Requests transport to
198 * build it's own specific listening connection.
199 */
Florin Corasba7d8f52019-02-22 13:11:38 -0800200 ls = listen_session_alloc (0, st);
Florin Corasc9940fc2019-02-05 20:55:11 -0800201 ls->app_index = app->app_index;
202 ls->app_wrk_index = sep->app_wrk_index;
203
204 /* Listen pool can be reallocated if the transport is
205 * recursive (tls) */
206 lh = session_handle (ls);
207
208 if ((rv = session_listen (ls, sep)))
209 {
210 ls = session_get_from_handle (lh);
211 session_free (ls);
212 return rv;
213 }
Florin Corasa27a46e2019-02-18 13:02:28 -0800214 ls = session_get_from_handle (lh);
215 app_listener = app_listener_get (app, al_index);
Florin Corasc9940fc2019-02-05 20:55:11 -0800216 app_listener->session_index = ls->session_index;
Florin Corasa27a46e2019-02-18 13:02:28 -0800217 ls->al_index = al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800218 }
219
220 if (!ll && !ls)
221 {
222 app_listener_free (app, app_listener);
223 return -1;
224 }
225
226 *listener = app_listener;
227 return 0;
228}
229
230void
231app_listener_cleanup (app_listener_t * al)
232{
233 application_t *app = application_get (al->app_index);
234
235 if (al->session_index != SESSION_INVALID_INDEX)
236 {
237 session_t *ls = session_get (al->session_index, 0);
238 session_stop_listen (ls);
Florin Corasba7d8f52019-02-22 13:11:38 -0800239 listen_session_free (ls);
Florin Corasc9940fc2019-02-05 20:55:11 -0800240 }
241 if (al->local_index != SESSION_INVALID_INDEX)
242 {
243 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
244 local_session_t *ll;
245 u32 table_index;
246
247 table_index = application_local_session_table (app);
248 ll = application_get_local_listen_session (app, al->local_index);
249 application_local_listener_session_endpoint (ll, &sep);
250 session_lookup_del_session_endpoint (table_index, &sep);
251 application_local_listen_session_free (app, ll);
252 }
253 app_listener_free (app, al);
254}
255
256app_worker_t *
257app_listener_select_worker (app_listener_t * al)
258{
259 application_t *app;
260 u32 wrk_index;
261
262 app = application_get (al->app_index);
263 wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
264 if (wrk_index == ~0)
265 wrk_index = clib_bitmap_first_set (al->workers);
266
267 ASSERT (wrk_index != ~0);
268 al->accept_rotor = wrk_index;
269 return application_get_worker (app, wrk_index);
270}
271
272session_t *
273app_listener_get_session (app_listener_t * al)
274{
275 if (al->session_index == SESSION_INVALID_INDEX)
276 return 0;
277
278 return listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -0700279}
280
Florin Coras15531972018-08-12 23:50:53 -0700281static app_worker_map_t *
282app_worker_map_alloc (application_t * app)
283{
284 app_worker_map_t *map;
285 pool_get (app->worker_maps, map);
Dave Barachb7b92992018-10-17 10:38:51 -0400286 clib_memset (map, 0, sizeof (*map));
Florin Coras15531972018-08-12 23:50:53 -0700287 return map;
288}
Dave Barach68b0fb02017-02-28 15:15:56 -0500289
Florin Coras15531972018-08-12 23:50:53 -0700290static u32
291app_worker_map_index (application_t * app, app_worker_map_t * map)
292{
293 return (map - app->worker_maps);
294}
295
296static void
297app_worker_map_free (application_t * app, app_worker_map_t * map)
298{
299 pool_put (app->worker_maps, map);
300}
301
302static app_worker_map_t *
303app_worker_map_get (application_t * app, u32 map_index)
304{
Florin Coras01f3f892018-12-02 12:45:53 -0800305 if (pool_is_free_index (app->worker_maps, map_index))
306 return 0;
Florin Coras15531972018-08-12 23:50:53 -0700307 return pool_elt_at_index (app->worker_maps, map_index);
308}
Florin Coras0bee9ce2018-03-22 21:24:31 -0700309
Florin Coras053a0e42018-11-13 15:52:38 -0800310static const u8 *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700311app_get_name (application_t * app)
312{
Florin Coras0bee9ce2018-03-22 21:24:31 -0700313 return app->name;
314}
315
Florin Corascea194d2017-10-02 00:18:51 -0700316u32
317application_session_table (application_t * app, u8 fib_proto)
318{
319 app_namespace_t *app_ns;
320 app_ns = app_namespace_get (app->ns_index);
321 if (!application_has_global_scope (app))
322 return APP_INVALID_INDEX;
323 if (fib_proto == FIB_PROTOCOL_IP4)
324 return session_lookup_get_index_for_fib (fib_proto,
325 app_ns->ip4_fib_index);
326 else
327 return session_lookup_get_index_for_fib (fib_proto,
328 app_ns->ip6_fib_index);
329}
330
331u32
332application_local_session_table (application_t * app)
333{
334 app_namespace_t *app_ns;
335 if (!application_has_local_scope (app))
336 return APP_INVALID_INDEX;
337 app_ns = app_namespace_get (app->ns_index);
338 return app_ns->local_table_index;
339}
340
Florin Corascea194d2017-10-02 00:18:51 -0700341/**
Florin Coras053a0e42018-11-13 15:52:38 -0800342 * Returns app name for app-index
Florin Corascea194d2017-10-02 00:18:51 -0700343 */
Florin Coras053a0e42018-11-13 15:52:38 -0800344const u8 *
Florin Corascea194d2017-10-02 00:18:51 -0700345application_name_from_index (u32 app_index)
346{
347 application_t *app = application_get (app_index);
348 if (!app)
349 return 0;
Florin Coras053a0e42018-11-13 15:52:38 -0800350 return app_get_name (app);
351}
352
353static void
354application_api_table_add (u32 app_index, u32 api_client_index)
355{
Florin Corasc1f5a432018-11-20 11:31:26 -0800356 if (api_client_index != APP_INVALID_INDEX)
357 hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
Florin Coras053a0e42018-11-13 15:52:38 -0800358}
359
360static void
361application_api_table_del (u32 api_client_index)
362{
363 hash_unset (app_main.app_by_api_client_index, api_client_index);
Florin Corascea194d2017-10-02 00:18:51 -0700364}
365
Dave Barach68b0fb02017-02-28 15:15:56 -0500366static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800367application_name_table_add (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500368{
Florin Corasc1f5a432018-11-20 11:31:26 -0800369 hash_set_mem (app_main.app_by_name, app->name, app->app_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500370}
371
372static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800373application_name_table_del (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500374{
Florin Corasc1f5a432018-11-20 11:31:26 -0800375 hash_unset_mem (app_main.app_by_name, app->name);
Dave Barach68b0fb02017-02-28 15:15:56 -0500376}
377
378application_t *
379application_lookup (u32 api_client_index)
380{
381 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700382 p = hash_get (app_main.app_by_api_client_index, api_client_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500383 if (p)
Florin Coras053a0e42018-11-13 15:52:38 -0800384 return application_get_if_valid (p[0]);
Dave Barach68b0fb02017-02-28 15:15:56 -0500385
386 return 0;
387}
388
Florin Coras6cf30ad2017-04-04 23:08:23 -0700389application_t *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700390application_lookup_name (const u8 * name)
391{
392 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700393 p = hash_get_mem (app_main.app_by_name, name);
Florin Coras0bee9ce2018-03-22 21:24:31 -0700394 if (p)
395 return application_get (p[0]);
396
397 return 0;
398}
399
Florin Corasc1a42652019-02-08 18:27:29 -0800400static application_t *
Florin Coras15531972018-08-12 23:50:53 -0700401application_alloc (void)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700402{
403 application_t *app;
Florin Coras15531972018-08-12 23:50:53 -0700404 pool_get (app_main.app_pool, app);
Dave Barachb7b92992018-10-17 10:38:51 -0400405 clib_memset (app, 0, sizeof (*app));
Florin Coras15531972018-08-12 23:50:53 -0700406 app->app_index = app - app_main.app_pool;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700407 return app;
408}
409
Florin Coras15531972018-08-12 23:50:53 -0700410application_t *
411application_get (u32 app_index)
Dave Barach68b0fb02017-02-28 15:15:56 -0500412{
Florin Coras15531972018-08-12 23:50:53 -0700413 if (app_index == APP_INVALID_INDEX)
414 return 0;
415 return pool_elt_at_index (app_main.app_pool, app_index);
416}
Dave Barach68b0fb02017-02-28 15:15:56 -0500417
Florin Coras15531972018-08-12 23:50:53 -0700418application_t *
419application_get_if_valid (u32 app_index)
420{
421 if (pool_is_free_index (app_main.app_pool, app_index))
422 return 0;
Florin Corasa5464812017-04-19 13:00:05 -0700423
Florin Coras15531972018-08-12 23:50:53 -0700424 return pool_elt_at_index (app_main.app_pool, app_index);
425}
Florin Coras7999e832017-10-31 01:51:04 -0700426
Florin Corasd79b41e2017-03-04 05:37:52 -0800427static void
Florin Coras6cf30ad2017-04-04 23:08:23 -0700428application_verify_cb_fns (session_cb_vft_t * cb_fns)
Florin Corasd79b41e2017-03-04 05:37:52 -0800429{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700430 if (cb_fns->session_accept_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800431 clib_warning ("No accept callback function provided");
Florin Coras6cf30ad2017-04-04 23:08:23 -0700432 if (cb_fns->session_connected_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800433 clib_warning ("No session connected callback function provided");
434 if (cb_fns->session_disconnect_callback == 0)
435 clib_warning ("No session disconnect callback function provided");
436 if (cb_fns->session_reset_callback == 0)
437 clib_warning ("No session reset callback function provided");
438}
439
Florin Corasb384b542018-01-15 01:08:33 -0800440/**
441 * Check app config for given segment type
442 *
443 * Returns 1 on success and 0 otherwise
444 */
445static u8
446application_verify_cfg (ssvm_segment_type_t st)
447{
448 u8 is_valid;
449 if (st == SSVM_SEGMENT_MEMFD)
450 {
451 is_valid = (session_manager_get_evt_q_segment () != 0);
452 if (!is_valid)
453 clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
454 return is_valid;
455 }
456 else if (st == SSVM_SEGMENT_SHM)
457 {
458 is_valid = (session_manager_get_evt_q_segment () == 0);
459 if (!is_valid)
460 clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
461 return is_valid;
462 }
463 else
464 return 1;
465}
466
Florin Corasc1a42652019-02-08 18:27:29 -0800467static int
Florin Coras15531972018-08-12 23:50:53 -0700468application_alloc_and_init (app_init_args_t * a)
Dave Barach68b0fb02017-02-28 15:15:56 -0500469{
Florin Corasa332c462018-01-31 06:52:17 -0800470 ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
Florin Corasb384b542018-01-15 01:08:33 -0800471 segment_manager_properties_t *props;
472 vl_api_registration_t *reg;
Florin Coras15531972018-08-12 23:50:53 -0700473 application_t *app;
474 u64 *options;
Dave Barach68b0fb02017-02-28 15:15:56 -0500475
Florin Coras15531972018-08-12 23:50:53 -0700476 app = application_alloc ();
477 options = a->options;
Florin Corasb384b542018-01-15 01:08:33 -0800478 /*
479 * Make sure we support the requested configuration
480 */
Florin Corasa332c462018-01-31 06:52:17 -0800481 if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
482 {
Florin Coras15531972018-08-12 23:50:53 -0700483 reg = vl_api_client_index_to_registration (a->api_client_index);
Florin Corasa332c462018-01-31 06:52:17 -0800484 if (!reg)
485 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
486 if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
487 seg_type = SSVM_SEGMENT_SHM;
488 }
489 else
490 {
Florin Coras99368312018-08-02 10:45:44 -0700491 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
492 {
493 clib_warning ("mq eventfds can only be used if socket transport is "
494 "used for api");
495 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
496 }
Florin Corasa332c462018-01-31 06:52:17 -0800497 seg_type = SSVM_SEGMENT_PRIVATE;
498 }
Florin Corasb384b542018-01-15 01:08:33 -0800499
Florin Corasa332c462018-01-31 06:52:17 -0800500 if (!application_verify_cfg (seg_type))
Florin Corasb384b542018-01-15 01:08:33 -0800501 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
Dave Barach68b0fb02017-02-28 15:15:56 -0500502
Florin Coras15531972018-08-12 23:50:53 -0700503 /* Check that the obvious things are properly set up */
504 application_verify_cb_fns (a->session_cb_vft);
505
Florin Coras15531972018-08-12 23:50:53 -0700506 app->flags = options[APP_OPTIONS_FLAGS];
507 app->cb_fns = *a->session_cb_vft;
508 app->ns_index = options[APP_OPTIONS_NAMESPACE];
509 app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
510 app->name = vec_dup (a->name);
511
512 /* If no scope enabled, default to global */
513 if (!application_has_global_scope (app)
514 && !application_has_local_scope (app))
515 app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
516
Florin Corasa332c462018-01-31 06:52:17 -0800517 props = application_segment_manager_properties (app);
518 segment_manager_properties_init (props);
Florin Coras15531972018-08-12 23:50:53 -0700519 props->segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
520 props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
Florin Corasb384b542018-01-15 01:08:33 -0800521 if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
522 {
523 props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
524 props->add_segment = 1;
525 }
526 if (options[APP_OPTIONS_RX_FIFO_SIZE])
527 props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
528 if (options[APP_OPTIONS_TX_FIFO_SIZE])
529 props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
Florin Corasf8f516a2018-02-08 15:10:09 -0800530 if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
531 props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
Florin Coras99368312018-08-02 10:45:44 -0700532 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
533 props->use_mq_eventfd = 1;
Florin Coras58d36f02018-03-09 13:05:53 -0800534 if (options[APP_OPTIONS_TLS_ENGINE])
535 app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
Florin Corasa332c462018-01-31 06:52:17 -0800536 props->segment_type = seg_type;
Dave Barach68b0fb02017-02-28 15:15:56 -0500537
Florin Coras15531972018-08-12 23:50:53 -0700538 /* Add app to lookup by api_client_index table */
Florin Corasc1f5a432018-11-20 11:31:26 -0800539 if (!application_is_builtin (app))
540 application_api_table_add (app->app_index, a->api_client_index);
541 else
542 application_name_table_add (app);
543
544 a->app_index = app->app_index;
Florin Corasa332c462018-01-31 06:52:17 -0800545
Florin Coras15531972018-08-12 23:50:53 -0700546 APP_DBG ("New app name: %v api index: %u index %u", app->name,
547 app->api_client_index, app->app_index);
548
549 return 0;
550}
551
Florin Corasc1a42652019-02-08 18:27:29 -0800552static void
Florin Coras15531972018-08-12 23:50:53 -0700553application_free (application_t * app)
554{
555 app_worker_map_t *wrk_map;
556 app_worker_t *app_wrk;
Florin Corasab2f6db2018-08-31 14:31:41 -0700557 u32 table_index;
558 local_session_t *ll;
559 session_endpoint_t sep;
Florin Coras15531972018-08-12 23:50:53 -0700560
561 /*
562 * The app event queue allocated in first segment is cleared with
563 * the segment manager. No need to explicitly free it.
564 */
565 APP_DBG ("Delete app name %v api index: %d index: %d", app->name,
566 app->api_client_index, app->app_index);
567
568 if (application_is_proxy (app))
569 application_remove_proxy (app);
570
Florin Corasab2f6db2018-08-31 14:31:41 -0700571 /*
572 * Free workers
573 */
574
Florin Coras15531972018-08-12 23:50:53 -0700575 /* *INDENT-OFF* */
576 pool_flush (wrk_map, app->worker_maps, ({
577 app_wrk = app_worker_get (wrk_map->wrk_index);
578 app_worker_free (app_wrk);
579 }));
580 /* *INDENT-ON* */
581 pool_free (app->worker_maps);
582
Florin Corasab2f6db2018-08-31 14:31:41 -0700583 /*
584 * Free local listeners. Global table unbinds stop local listeners
585 * as well, but if we have only local binds, these won't be cleaned up.
586 * Don't bother with local accepted sessions, we clean them when
587 * cleaning up the worker.
588 */
589 table_index = application_local_session_table (app);
590 /* *INDENT-OFF* */
591 pool_foreach (ll, app->local_listen_sessions, ({
592 application_local_listener_session_endpoint (ll, &sep);
593 session_lookup_del_session_endpoint (table_index, &sep);
594 }));
595 /* *INDENT-ON* */
596 pool_free (app->local_listen_sessions);
597
598 /*
599 * Cleanup remaining state
600 */
Florin Corasc1f5a432018-11-20 11:31:26 -0800601 if (application_is_builtin (app))
602 application_name_table_del (app);
Florin Coras15531972018-08-12 23:50:53 -0700603 vec_free (app->name);
604 vec_free (app->tls_cert);
605 vec_free (app->tls_key);
606 pool_put (app_main.app_pool, app);
607}
608
Florin Corasc1a42652019-02-08 18:27:29 -0800609static void
Florin Coras053a0e42018-11-13 15:52:38 -0800610application_detach_process (application_t * app, u32 api_client_index)
611{
612 vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
613 app_worker_map_t *wrk_map;
614 u32 *wrks = 0, *wrk_index;
615 app_worker_t *app_wrk;
616
617 if (api_client_index == ~0)
618 {
619 application_free (app);
620 return;
621 }
622
623 APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
624 app->app_index, app->api_client_index);
625
626 /* *INDENT-OFF* */
627 pool_foreach (wrk_map, app->worker_maps, ({
628 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Corasc1f5a432018-11-20 11:31:26 -0800629 if (app_wrk->api_client_index == api_client_index)
Florin Coras053a0e42018-11-13 15:52:38 -0800630 vec_add1 (wrks, app_wrk->wrk_index);
631 }));
632 /* *INDENT-ON* */
633
634 if (!vec_len (wrks))
635 {
636 clib_warning ("no workers for app %u api_index %u", app->app_index,
637 api_client_index);
638 return;
639 }
640
641 args->app_index = app->app_index;
Florin Corasc1f5a432018-11-20 11:31:26 -0800642 args->api_client_index = api_client_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800643 vec_foreach (wrk_index, wrks)
644 {
645 app_wrk = app_worker_get (wrk_index[0]);
Florin Coras349f8ca2018-11-20 16:52:49 -0800646 args->wrk_map_index = app_wrk->wrk_map_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800647 args->is_add = 0;
648 vnet_app_worker_add_del (args);
649 }
650 vec_free (wrks);
651}
652
Florin Coras15531972018-08-12 23:50:53 -0700653app_worker_t *
654application_get_worker (application_t * app, u32 wrk_map_index)
655{
656 app_worker_map_t *map;
657 map = app_worker_map_get (app, wrk_map_index);
658 if (!map)
659 return 0;
660 return app_worker_get (map->wrk_index);
661}
662
663app_worker_t *
664application_get_default_worker (application_t * app)
665{
666 return application_get_worker (app, 0);
667}
668
Florin Coras053a0e42018-11-13 15:52:38 -0800669u32
670application_n_workers (application_t * app)
671{
672 return pool_elts (app->worker_maps);
673}
674
Florin Coras15531972018-08-12 23:50:53 -0700675app_worker_t *
Florin Corasc9940fc2019-02-05 20:55:11 -0800676application_listener_select_worker (session_t * ls)
Florin Corasab2f6db2018-08-31 14:31:41 -0700677{
Florin Corasc9940fc2019-02-05 20:55:11 -0800678 app_listener_t *al;
Florin Corasab2f6db2018-08-31 14:31:41 -0700679
Florin Corasc9940fc2019-02-05 20:55:11 -0800680 al = app_listener_get_w_session (ls);
681 return app_listener_select_worker (al);
Florin Corasab2f6db2018-08-31 14:31:41 -0700682}
683
Florin Coras15531972018-08-12 23:50:53 -0700684int
Florin Coras623eb562019-02-03 19:28:34 -0800685application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
Florin Coras15531972018-08-12 23:50:53 -0700686{
687 app_worker_map_t *wrk_map;
688 app_worker_t *app_wrk;
689 segment_manager_t *sm;
690 int rv;
691
692 app_wrk = app_worker_alloc (app);
693 wrk_map = app_worker_map_alloc (app);
694 wrk_map->wrk_index = app_wrk->wrk_index;
695 app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
696
697 /*
698 * Setup first segment manager
699 */
700 sm = segment_manager_new ();
701 sm->app_wrk_index = app_wrk->wrk_index;
702
703 if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
704 app->sm_properties.prealloc_fifos)))
705 {
706 app_worker_free (app_wrk);
707 return rv;
708 }
Florin Corasc87c91d2017-08-16 19:55:49 -0700709 sm->first_is_protected = 1;
Dave Barach68b0fb02017-02-28 15:15:56 -0500710
Florin Corascea194d2017-10-02 00:18:51 -0700711 /*
Florin Coras15531972018-08-12 23:50:53 -0700712 * Setup app worker
Florin Corascea194d2017-10-02 00:18:51 -0700713 */
Florin Coras15531972018-08-12 23:50:53 -0700714 app_wrk->first_segment_manager = segment_manager_index (sm);
715 app_wrk->listeners_table = hash_create (0, sizeof (u64));
716 app_wrk->event_queue = segment_manager_event_queue (sm);
717 app_wrk->app_is_builtin = application_is_builtin (app);
Dave Barach68b0fb02017-02-28 15:15:56 -0500718
Florin Corasf8f516a2018-02-08 15:10:09 -0800719 /*
720 * Segment manager for local sessions
721 */
722 sm = segment_manager_new ();
Florin Coras15531972018-08-12 23:50:53 -0700723 sm->app_wrk_index = app_wrk->wrk_index;
724 app_wrk->local_segment_manager = segment_manager_index (sm);
725 app_wrk->local_connects = hash_create (0, sizeof (u64));
726
727 *wrk = app_wrk;
Florin Corasf8f516a2018-02-08 15:10:09 -0800728
Florin Coras6cf30ad2017-04-04 23:08:23 -0700729 return 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500730}
731
Florin Coras623eb562019-02-03 19:28:34 -0800732int
Florin Corasc1a42652019-02-08 18:27:29 -0800733vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
734{
735 svm_fifo_segment_private_t *fs;
736 app_worker_map_t *wrk_map;
737 app_worker_t *app_wrk;
738 segment_manager_t *sm;
739 application_t *app;
740 int rv;
741
742 app = application_get (a->app_index);
743 if (!app)
744 return VNET_API_ERROR_INVALID_VALUE;
745
746 if (a->is_add)
747 {
748 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
749 return rv;
750
751 /* Map worker api index to the app */
752 app_wrk->api_client_index = a->api_client_index;
753 application_api_table_add (app->app_index, a->api_client_index);
754
755 sm = segment_manager_get (app_wrk->first_segment_manager);
756 fs = segment_manager_get_segment_w_lock (sm, 0);
757 a->segment = &fs->ssvm;
758 a->segment_handle = segment_manager_segment_handle (sm, fs);
759 segment_manager_segment_reader_unlock (sm);
760 a->evt_q = app_wrk->event_queue;
761 a->wrk_map_index = app_wrk->wrk_map_index;
762 }
763 else
764 {
765 wrk_map = app_worker_map_get (app, a->wrk_map_index);
766 if (!wrk_map)
767 return VNET_API_ERROR_INVALID_VALUE;
768
769 app_wrk = app_worker_get (wrk_map->wrk_index);
770 if (!app_wrk)
771 return VNET_API_ERROR_INVALID_VALUE;
772
773 application_api_table_del (app_wrk->api_client_index);
774 app_worker_free (app_wrk);
775 app_worker_map_free (app, wrk_map);
776 if (application_n_workers (app) == 0)
777 application_free (app);
778 }
779 return 0;
780}
781
782static int
783app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
784{
785 app_namespace_t *app_ns;
786 if (vec_len (namespace_id) == 0)
787 {
788 /* Use default namespace */
789 *app_ns_index = 0;
790 return 0;
791 }
792
793 *app_ns_index = app_namespace_index_from_id (namespace_id);
794 if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
795 return VNET_API_ERROR_APP_INVALID_NS;
796 app_ns = app_namespace_get (*app_ns_index);
797 if (!app_ns)
798 return VNET_API_ERROR_APP_INVALID_NS;
799 if (app_ns->ns_secret != secret)
800 return VNET_API_ERROR_APP_WRONG_NS_SECRET;
801 return 0;
802}
803
804static u8 *
805app_name_from_api_index (u32 api_client_index)
806{
807 vl_api_registration_t *regp;
808 regp = vl_api_client_index_to_registration (api_client_index);
809 if (regp)
810 return format (0, "%s%c", regp->name, 0);
811
812 clib_warning ("api client index %u does not have an api registration!",
813 api_client_index);
814 return format (0, "unknown%c", 0);
815}
816
817/**
818 * Attach application to vpp
819 *
820 * Allocates a vpp app, i.e., a structure that keeps back pointers
821 * to external app and a segment manager for shared memory fifo based
822 * communication with the external app.
823 */
824int
825vnet_application_attach (vnet_app_attach_args_t * a)
826{
827 svm_fifo_segment_private_t *fs;
828 application_t *app = 0;
829 app_worker_t *app_wrk;
830 segment_manager_t *sm;
831 u32 app_ns_index = 0;
832 u8 *app_name = 0;
833 u64 secret;
834 int rv;
835
836 if (a->api_client_index != APP_INVALID_INDEX)
837 app = application_lookup (a->api_client_index);
838 else if (a->name)
839 app = application_lookup_name (a->name);
840 else
841 return VNET_API_ERROR_INVALID_VALUE;
842
843 if (app)
844 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
845
846 if (a->api_client_index != APP_INVALID_INDEX)
847 {
848 app_name = app_name_from_api_index (a->api_client_index);
849 a->name = app_name;
850 }
851
852 secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
853 if ((rv = app_validate_namespace (a->namespace_id, secret, &app_ns_index)))
854 return rv;
855 a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
856
857 if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
858 return rv;
859
860 app = application_get (a->app_index);
861 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
862 return rv;
863
864 a->app_evt_q = app_wrk->event_queue;
865 app_wrk->api_client_index = a->api_client_index;
866 sm = segment_manager_get (app_wrk->first_segment_manager);
867 fs = segment_manager_get_segment_w_lock (sm, 0);
868
869 if (application_is_proxy (app))
870 application_setup_proxy (app);
871
872 ASSERT (vec_len (fs->ssvm.name) <= 128);
873 a->segment = &fs->ssvm;
874 a->segment_handle = segment_manager_segment_handle (sm, fs);
875
876 segment_manager_segment_reader_unlock (sm);
877 vec_free (app_name);
878 return 0;
879}
880
881/**
882 * Detach application from vpp
883 */
884int
885vnet_application_detach (vnet_app_detach_args_t * a)
886{
887 application_t *app;
888
889 app = application_get_if_valid (a->app_index);
890 if (!app)
891 {
892 clib_warning ("app not attached");
893 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
894 }
895
896 app_interface_check_thread_and_barrier (vnet_application_detach, a);
897 application_detach_process (app, a->api_client_index);
898 return 0;
899}
900
901
902static u8
903session_endpoint_in_ns (session_endpoint_t * sep)
904{
905 u8 is_lep = session_endpoint_is_local (sep);
906 if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
907 && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
908 {
909 clib_warning ("sw_if_index %u not configured with ip %U",
910 sep->sw_if_index, format_ip46_address, &sep->ip,
911 sep->is_ip4);
912 return 0;
913 }
914 return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
915}
916
917static void
918session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
919 application_t * app, u8 is_connect)
920{
921 app_namespace_t *app_ns;
922 u32 ns_index, fib_index;
923
924 ns_index = app->ns_index;
925
926 /* App is a transport proto, so fetch the calling app's ns */
927 if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
Florin Coras8a140612019-02-18 22:39:39 -0800928 ns_index = sep->ns_index;
Florin Corasc1a42652019-02-08 18:27:29 -0800929
Florin Corasc1a42652019-02-08 18:27:29 -0800930 app_ns = app_namespace_get (ns_index);
931 if (!app_ns)
932 return;
933
934 /* Ask transport and network to bind to/connect using local interface
935 * that "supports" app's namespace. This will fix our local connection
936 * endpoint.
937 */
938
939 /* If in default namespace and user requested a fib index use it */
940 if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
941 fib_index = sep->fib_index;
942 else
943 fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
944 sep->peer.fib_index = fib_index;
945 sep->fib_index = fib_index;
946
947 if (!is_connect)
948 {
949 sep->sw_if_index = app_ns->sw_if_index;
950 }
951 else
952 {
953 if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
954 && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
955 && sep->peer.sw_if_index != app_ns->sw_if_index)
956 clib_warning ("Local sw_if_index different from app ns sw_if_index");
957
958 sep->peer.sw_if_index = app_ns->sw_if_index;
959 }
960}
961
962int
963vnet_listen (vnet_listen_args_t * a)
964{
965 app_listener_t *app_listener;
966 app_worker_t *app_wrk;
967 application_t *app;
968 int rv;
969
970 app = application_get_if_valid (a->app_index);
971 if (!app)
972 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
973
974 app_wrk = application_get_worker (app, a->wrk_map_index);
975 if (!app_wrk)
976 return VNET_API_ERROR_INVALID_VALUE;
977
978 a->sep_ext.app_wrk_index = app_wrk->wrk_index;
979
980 session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
981 if (!session_endpoint_in_ns (&a->sep))
982 return VNET_API_ERROR_INVALID_VALUE_2;
983
984 /*
985 * Check if we already have an app listener
986 */
987 app_listener = app_listener_lookup (app, &a->sep_ext);
988 if (app_listener)
989 {
990 if (app_listener->app_index != app->app_index)
991 return VNET_API_ERROR_ADDRESS_IN_USE;
992 if (app_worker_start_listen (app_wrk, app_listener))
993 return -1;
994 a->handle = app_listener_handle (app_listener);
995 return 0;
996 }
997
998 /*
999 * Create new app listener
1000 */
1001 if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1002 return rv;
1003
1004 if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1005 {
1006 app_listener_cleanup (app_listener);
1007 return rv;
1008 }
1009
1010 a->handle = app_listener_handle (app_listener);
1011 return 0;
1012}
1013
1014int
1015vnet_connect (vnet_connect_args_t * a)
1016{
1017 app_worker_t *server_wrk, *client_wrk;
1018 application_t *client;
1019 local_session_t *ll;
1020 app_listener_t *al;
1021 u32 table_index;
1022 session_t *ls;
1023 u8 fib_proto;
1024 u64 lh;
1025
1026 if (session_endpoint_is_zero (&a->sep))
1027 return VNET_API_ERROR_INVALID_VALUE;
1028
1029 client = application_get (a->app_index);
1030 session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1031 client_wrk = application_get_worker (client, a->wrk_map_index);
1032
1033 /*
1034 * First check the local scope for locally attached destinations.
1035 * If we have local scope, we pass *all* connects through it since we may
1036 * have special policy rules even for non-local destinations, think proxy.
1037 */
1038 if (application_has_local_scope (client))
1039 {
1040 table_index = application_local_session_table (client);
1041 lh = session_lookup_local_endpoint (table_index, &a->sep);
1042 if (lh == SESSION_DROP_HANDLE)
1043 return VNET_API_ERROR_APP_CONNECT_FILTERED;
1044
1045 if (lh == SESSION_INVALID_HANDLE)
1046 goto global_scope;
1047
1048 ll = application_get_local_listener_w_handle (lh);
1049 al = app_listener_get_w_session ((session_t *) ll);
1050
1051 /*
1052 * Break loop if rule in local table points to connecting app. This
1053 * can happen if client is a generic proxy. Route connect through
1054 * global table instead.
1055 */
1056 if (al->app_index == a->app_index)
1057 goto global_scope;
1058
1059 server_wrk = app_listener_select_worker (al);
1060 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1061 a->api_context);
1062 }
1063
1064 /*
1065 * If nothing found, check the global scope for locally attached
1066 * destinations. Make sure first that we're allowed to.
1067 */
1068
1069global_scope:
1070 if (session_endpoint_is_local (&a->sep))
1071 return VNET_API_ERROR_SESSION_CONNECT;
1072
1073 if (!application_has_global_scope (client))
1074 return VNET_API_ERROR_APP_CONNECT_SCOPE;
1075
1076 fib_proto = session_endpoint_fib_proto (&a->sep);
1077 table_index = application_session_table (client, fib_proto);
1078 ls = session_lookup_listener (table_index, &a->sep);
1079 if (ls)
1080 {
1081 al = app_listener_get_w_session (ls);
1082 server_wrk = app_listener_select_worker (al);
1083 ll = (local_session_t *) ls;
1084 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1085 a->api_context);
1086 }
1087
1088 /*
1089 * Not connecting to a local server, propagate to transport
1090 */
1091 if (app_worker_connect_session (client_wrk, &a->sep, a->api_context))
1092 return VNET_API_ERROR_SESSION_CONNECT;
1093 return 0;
1094}
1095
1096int
1097vnet_unlisten (vnet_unlisten_args_t * a)
1098{
1099 app_worker_t *app_wrk;
1100 app_listener_t *al;
1101 application_t *app;
1102
1103 if (!(app = application_get_if_valid (a->app_index)))
1104 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1105
1106 al = app_listener_get_w_handle (a->handle);
1107 if (al->app_index != app->app_index)
1108 {
1109 clib_warning ("app doesn't own handle %llu!", a->handle);
1110 return -1;
1111 }
1112
1113 app_wrk = application_get_worker (app, a->wrk_map_index);
1114 if (!app_wrk)
1115 {
1116 clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1117 return -1;
1118 }
1119
1120 return app_worker_stop_listen (app_wrk, al);
1121}
1122
1123int
1124vnet_disconnect_session (vnet_disconnect_args_t * a)
1125{
1126 if (session_handle_is_local (a->handle))
1127 {
Florin Coras51a423d2019-02-19 20:57:06 -08001128 app_worker_t *client_wrk, *server_wrk;
Florin Corasc1a42652019-02-08 18:27:29 -08001129 local_session_t *ls;
Florin Coras51a423d2019-02-19 20:57:06 -08001130 u32 wrk_index = ~0;
Florin Corasc1a42652019-02-08 18:27:29 -08001131
1132 /* Disconnect reply came to worker 1 not main thread */
1133 app_interface_check_thread_and_barrier (vnet_disconnect_session, a);
1134
1135 if (!(ls = app_worker_get_local_session_from_handle (a->handle)))
1136 return 0;
1137
Florin Coras51a423d2019-02-19 20:57:06 -08001138 client_wrk = app_worker_get_if_valid (ls->client_wrk_index);
1139 server_wrk = app_worker_get (ls->app_wrk_index);
1140
1141 if (server_wrk->app_index == a->app_index)
1142 wrk_index = server_wrk->wrk_index;
1143 else if (client_wrk && client_wrk->app_index == a->app_index)
1144 wrk_index = client_wrk->wrk_index;
1145
1146 if (wrk_index == ~0)
1147 {
1148 clib_warning ("app %u does not own session 0x%lx", a->app_index,
1149 application_local_session_handle (ls));
1150 return VNET_API_ERROR_INVALID_VALUE;
1151 }
1152
1153 return app_worker_local_session_disconnect (wrk_index, ls);
Florin Corasc1a42652019-02-08 18:27:29 -08001154 }
1155 else
1156 {
1157 app_worker_t *app_wrk;
1158 session_t *s;
1159
1160 s = session_get_from_handle_if_valid (a->handle);
1161 if (!s)
1162 return VNET_API_ERROR_INVALID_VALUE;
1163 app_wrk = app_worker_get (s->app_wrk_index);
1164 if (app_wrk->app_index != a->app_index)
1165 return VNET_API_ERROR_INVALID_VALUE;
1166
1167 /* We're peeking into another's thread pool. Make sure */
1168 ASSERT (s->session_index == session_index_from_handle (a->handle));
1169
1170 session_close (s);
1171 }
1172 return 0;
1173}
1174
1175int
Florin Coras623eb562019-02-03 19:28:34 -08001176application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1177{
1178 app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1179 app_listener_t *app_listener;
1180 application_t *app;
1181
1182 if (!old_wrk)
1183 return -1;
1184
1185 hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1186 if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1187 && s->rx_fifo)
1188 segment_manager_dealloc_fifos (s->rx_fifo->segment_index, s->rx_fifo,
1189 s->tx_fifo);
1190
Florin Coras623eb562019-02-03 19:28:34 -08001191 app = application_get (old_wrk->app_index);
1192 if (!app)
1193 return -1;
1194
Florin Corasc9940fc2019-02-05 20:55:11 -08001195 app_listener = app_listener_get (app, s->al_index);
1196
1197 /* Only remove from lb for now */
Florin Coras623eb562019-02-03 19:28:34 -08001198 app_listener->workers = clib_bitmap_set (app_listener->workers,
1199 old_wrk->wrk_map_index, 0);
Florin Coras623eb562019-02-03 19:28:34 -08001200
Florin Corasc9940fc2019-02-05 20:55:11 -08001201 if (app_worker_start_listen (app_wrk, app_listener))
1202 return -1;
Florin Corasab2f6db2018-08-31 14:31:41 -07001203
Florin Corasc9940fc2019-02-05 20:55:11 -08001204 s->app_wrk_index = app_wrk->wrk_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001205
Dave Barach68b0fb02017-02-28 15:15:56 -05001206 return 0;
1207}
1208
Dave Barach52851e62017-08-07 09:35:25 -04001209int
1210application_is_proxy (application_t * app)
1211{
Florin Coras7999e832017-10-31 01:51:04 -07001212 return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1213}
1214
1215int
1216application_is_builtin (application_t * app)
1217{
1218 return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1219}
1220
1221int
1222application_is_builtin_proxy (application_t * app)
1223{
1224 return (application_is_proxy (app) && application_is_builtin (app));
Dave Barach52851e62017-08-07 09:35:25 -04001225}
1226
Florin Corascea194d2017-10-02 00:18:51 -07001227u8
1228application_has_local_scope (application_t * app)
1229{
1230 return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1231}
1232
1233u8
1234application_has_global_scope (application_t * app)
1235{
1236 return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1237}
1238
Florin Coras60116992018-08-27 09:52:18 -07001239u8
1240application_use_mq_for_ctrl (application_t * app)
1241{
1242 return app->flags & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
1243}
1244
Florin Coras7999e832017-10-31 01:51:04 -07001245static clib_error_t *
1246application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1247 u8 transport_proto, u8 is_start)
1248{
Florin Coras7999e832017-10-31 01:51:04 -07001249 app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1250 u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
Florin Coras5665ced2018-10-25 18:03:45 -07001251 session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
Florin Coras7999e832017-10-31 01:51:04 -07001252 transport_connection_t *tc;
Florin Coras15531972018-08-12 23:50:53 -07001253 app_worker_t *app_wrk;
Florin Corasc9940fc2019-02-05 20:55:11 -08001254 app_listener_t *al;
Florin Coras288eaab2019-02-03 15:26:14 -08001255 session_t *s;
Florin Corasc9940fc2019-02-05 20:55:11 -08001256 u32 flags;
Florin Coras7999e832017-10-31 01:51:04 -07001257
Florin Coras15531972018-08-12 23:50:53 -07001258 /* TODO decide if we want proxy to be enabled for all workers */
1259 app_wrk = application_get_default_worker (app);
Florin Coras7999e832017-10-31 01:51:04 -07001260 if (is_start)
1261 {
Florin Coras15531972018-08-12 23:50:53 -07001262 s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001263 if (!s)
1264 {
1265 sep.is_ip4 = is_ip4;
1266 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1267 sep.sw_if_index = app_ns->sw_if_index;
1268 sep.transport_proto = transport_proto;
Florin Corasab2f6db2018-08-31 14:31:41 -07001269 sep.app_wrk_index = app_wrk->wrk_index; /* only default */
Florin Corasc9940fc2019-02-05 20:55:11 -08001270
1271 /* force global scope listener */
1272 flags = app->flags;
1273 app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1274 app_listener_alloc_and_init (app, &sep, &al);
1275 app->flags = flags;
1276
1277 app_worker_start_listen (app_wrk, al);
1278 s = listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -07001279 s->enqueue_epoch = SESSION_PROXY_LISTENER_INDEX;
Florin Coras19b1f6a2017-12-11 03:37:03 -08001280 }
Florin Coras7999e832017-10-31 01:51:04 -07001281 }
1282 else
1283 {
Florin Coras623eb562019-02-03 19:28:34 -08001284 s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001285 ASSERT (s);
Florin Coras7999e832017-10-31 01:51:04 -07001286 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001287
Florin Coras7999e832017-10-31 01:51:04 -07001288 tc = listen_session_get_transport (s);
1289
1290 if (!ip_is_zero (&tc->lcl_ip, 1))
1291 {
Florin Corasdbd44562017-11-09 19:30:17 -08001292 u32 sti;
1293 sep.is_ip4 = is_ip4;
1294 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1295 sep.transport_proto = transport_proto;
1296 sep.port = 0;
1297 sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001298 if (is_start)
Florin Corasab2f6db2018-08-31 14:31:41 -07001299 session_lookup_add_session_endpoint (sti,
1300 (session_endpoint_t *) & sep,
1301 s->session_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001302 else
Florin Corasab2f6db2018-08-31 14:31:41 -07001303 session_lookup_del_session_endpoint (sti,
1304 (session_endpoint_t *) & sep);
Florin Coras7999e832017-10-31 01:51:04 -07001305 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001306
Florin Coras7999e832017-10-31 01:51:04 -07001307 return 0;
1308}
1309
Florin Coras19b1f6a2017-12-11 03:37:03 -08001310static void
1311application_start_stop_proxy_local_scope (application_t * app,
1312 u8 transport_proto, u8 is_start)
1313{
1314 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1315 app_namespace_t *app_ns;
1316 app_ns = app_namespace_get (app->ns_index);
1317 sep.is_ip4 = 1;
1318 sep.transport_proto = transport_proto;
1319 sep.port = 0;
1320
1321 if (is_start)
1322 {
1323 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001324 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001325 sep.is_ip4 = 0;
1326 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001327 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001328 }
1329 else
1330 {
1331 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1332 sep.is_ip4 = 0;
1333 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1334 }
1335}
1336
Florin Coras7999e832017-10-31 01:51:04 -07001337void
Florin Coras561af9b2017-12-09 10:19:43 -08001338application_start_stop_proxy (application_t * app,
1339 transport_proto_t transport_proto, u8 is_start)
Florin Coras7999e832017-10-31 01:51:04 -07001340{
Florin Coras7999e832017-10-31 01:51:04 -07001341 if (application_has_local_scope (app))
Florin Coras19b1f6a2017-12-11 03:37:03 -08001342 application_start_stop_proxy_local_scope (app, transport_proto, is_start);
Florin Coras7999e832017-10-31 01:51:04 -07001343
1344 if (application_has_global_scope (app))
1345 {
1346 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1347 transport_proto, is_start);
1348 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1349 transport_proto, is_start);
1350 }
1351}
1352
1353void
1354application_setup_proxy (application_t * app)
1355{
1356 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001357 transport_proto_t tp;
1358
Florin Coras7999e832017-10-31 01:51:04 -07001359 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001360
1361 /* *INDENT-OFF* */
1362 transport_proto_foreach (tp, ({
1363 if (transports & (1 << tp))
1364 application_start_stop_proxy (app, tp, 1);
1365 }));
1366 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001367}
1368
1369void
1370application_remove_proxy (application_t * app)
1371{
1372 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001373 transport_proto_t tp;
1374
Florin Coras7999e832017-10-31 01:51:04 -07001375 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001376
1377 /* *INDENT-OFF* */
1378 transport_proto_foreach (tp, ({
1379 if (transports & (1 << tp))
1380 application_start_stop_proxy (app, tp, 0);
1381 }));
1382 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001383}
1384
Florin Corasa332c462018-01-31 06:52:17 -08001385segment_manager_properties_t *
1386application_segment_manager_properties (application_t * app)
1387{
1388 return &app->sm_properties;
1389}
1390
1391segment_manager_properties_t *
1392application_get_segment_manager_properties (u32 app_index)
1393{
1394 application_t *app = application_get (app_index);
1395 return &app->sm_properties;
1396}
1397
Florin Coras371ca502018-02-21 12:07:41 -08001398clib_error_t *
1399vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1400{
1401 application_t *app;
1402 app = application_get (a->app_index);
1403 if (!app)
1404 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1405 0, "app %u doesn't exist", a->app_index);
1406 app->tls_cert = vec_dup (a->cert);
1407 return 0;
1408}
1409
1410clib_error_t *
1411vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1412{
1413 application_t *app;
1414 app = application_get (a->app_index);
1415 if (!app)
1416 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1417 0, "app %u doesn't exist", a->app_index);
1418 app->tls_key = vec_dup (a->key);
1419 return 0;
1420}
1421
Florin Coras15531972018-08-12 23:50:53 -07001422static void
1423application_format_listeners (application_t * app, int verbose)
1424{
1425 vlib_main_t *vm = vlib_get_main ();
1426 app_worker_map_t *wrk_map;
1427 app_worker_t *app_wrk;
1428 u32 sm_index;
1429 u64 handle;
1430
1431 if (!app)
1432 {
1433 vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1434 0, 0, verbose);
1435 return;
1436 }
1437
1438 /* *INDENT-OFF* */
1439 pool_foreach (wrk_map, app->worker_maps, ({
1440 app_wrk = app_worker_get (wrk_map->wrk_index);
1441 if (hash_elts (app_wrk->listeners_table) == 0)
1442 continue;
1443 hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1444 vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1445 handle, sm_index, verbose);
1446 }));
1447 }));
1448 /* *INDENT-ON* */
1449}
1450
1451static void
Florin Coras15531972018-08-12 23:50:53 -07001452application_format_connects (application_t * app, int verbose)
1453{
1454 app_worker_map_t *wrk_map;
1455 app_worker_t *app_wrk;
1456
1457 if (!app)
1458 {
1459 app_worker_format_connects (0, verbose);
1460 return;
1461 }
1462
1463 /* *INDENT-OFF* */
1464 pool_foreach (wrk_map, app->worker_maps, ({
1465 app_wrk = app_worker_get (wrk_map->wrk_index);
1466 app_worker_format_connects (app_wrk, verbose);
1467 }));
1468 /* *INDENT-ON* */
1469}
1470
1471static void
Florin Coras15531972018-08-12 23:50:53 -07001472application_format_local_sessions (application_t * app, int verbose)
1473{
Florin Corasab2f6db2018-08-31 14:31:41 -07001474 vlib_main_t *vm = vlib_get_main ();
Florin Coras15531972018-08-12 23:50:53 -07001475 app_worker_map_t *wrk_map;
1476 app_worker_t *app_wrk;
Florin Corasab2f6db2018-08-31 14:31:41 -07001477 transport_proto_t tp;
1478 local_session_t *ls;
1479 u8 *conn = 0;
Florin Coras15531972018-08-12 23:50:53 -07001480
1481 if (!app)
1482 {
1483 app_worker_format_local_sessions (0, verbose);
1484 return;
1485 }
1486
Florin Corasab2f6db2018-08-31 14:31:41 -07001487 /*
1488 * Format local listeners
1489 */
1490
1491 /* *INDENT-OFF* */
1492 pool_foreach (ls, app->local_listen_sessions, ({
1493 tp = session_type_transport_proto (ls->listener_session_type);
1494 conn = format (0, "[L][%U] *:%u", format_transport_proto_short, tp,
1495 ls->port);
1496 vlib_cli_output (vm, "%-40v%-15u%-20s", conn, ls->app_wrk_index, "*");
1497 vec_reset_length (conn);
1498 }));
1499 /* *INDENT-ON* */
1500
1501 /*
1502 * Format local accepted/connected sessions
1503 */
Florin Coras15531972018-08-12 23:50:53 -07001504 /* *INDENT-OFF* */
1505 pool_foreach (wrk_map, app->worker_maps, ({
1506 app_wrk = app_worker_get (wrk_map->wrk_index);
1507 app_worker_format_local_sessions (app_wrk, verbose);
1508 }));
1509 /* *INDENT-ON* */
1510}
1511
1512static void
Florin Coras15531972018-08-12 23:50:53 -07001513application_format_local_connects (application_t * app, int verbose)
1514{
1515 app_worker_map_t *wrk_map;
1516 app_worker_t *app_wrk;
1517
1518 if (!app)
1519 {
1520 app_worker_format_local_connects (0, verbose);
1521 return;
1522 }
1523
1524 /* *INDENT-OFF* */
1525 pool_foreach (wrk_map, app->worker_maps, ({
1526 app_wrk = app_worker_get (wrk_map->wrk_index);
1527 app_worker_format_local_connects (app_wrk, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001528 }));
1529 /* *INDENT-ON* */
1530}
1531
Florin Coras6cf30ad2017-04-04 23:08:23 -07001532u8 *
1533format_application (u8 * s, va_list * args)
1534{
1535 application_t *app = va_arg (*args, application_t *);
1536 CLIB_UNUSED (int verbose) = va_arg (*args, int);
Florin Corasad0c77f2017-11-09 18:00:15 -08001537 segment_manager_properties_t *props;
Florin Coras053a0e42018-11-13 15:52:38 -08001538 const u8 *app_ns_name, *app_name;
Florin Coras349f8ca2018-11-20 16:52:49 -08001539 app_worker_map_t *wrk_map;
1540 app_worker_t *app_wrk;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001541
1542 if (app == 0)
1543 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001544 if (!verbose)
Florin Corasc1f5a432018-11-20 11:31:26 -08001545 s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
Florin Coras6cf30ad2017-04-04 23:08:23 -07001546 return s;
1547 }
1548
Florin Coras0bee9ce2018-03-22 21:24:31 -07001549 app_name = app_get_name (app);
Florin Corascea194d2017-10-02 00:18:51 -07001550 app_ns_name = app_namespace_id_from_index (app->ns_index);
Florin Corasa332c462018-01-31 06:52:17 -08001551 props = application_segment_manager_properties (app);
Florin Coras349f8ca2018-11-20 16:52:49 -08001552 if (!verbose)
1553 {
1554 s = format (s, "%-10u%-20s%-40s", app->app_index, app_name,
1555 app_ns_name);
1556 return s;
1557 }
1558
1559 s = format (s, "app-name %s app-index %u ns-index %u seg-size %U\n",
1560 app_name, app->app_index, app->ns_index,
1561 format_memory_size, props->add_segment_size);
1562 s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1563 format_memory_size, props->rx_fifo_size,
1564 format_memory_size, props->tx_fifo_size);
1565
1566 /* *INDENT-OFF* */
1567 pool_foreach (wrk_map, app->worker_maps, ({
1568 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Coras623eb562019-02-03 19:28:34 -08001569 s = format (s, "%U", format_app_worker, app_wrk);
Florin Coras349f8ca2018-11-20 16:52:49 -08001570 }));
1571 /* *INDENT-ON* */
1572
Dave Barach68b0fb02017-02-28 15:15:56 -05001573 return s;
1574}
1575
Florin Corasf8f516a2018-02-08 15:10:09 -08001576void
1577application_format_all_listeners (vlib_main_t * vm, int do_local, int verbose)
1578{
1579 application_t *app;
Florin Corasf8f516a2018-02-08 15:10:09 -08001580
Florin Coras15531972018-08-12 23:50:53 -07001581 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001582 {
1583 vlib_cli_output (vm, "No active server bindings");
1584 return;
1585 }
1586
1587 if (do_local)
1588 {
1589 application_format_local_sessions (0, verbose);
1590 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001591 pool_foreach (app, app_main.app_pool, ({
Florin Corasf8f516a2018-02-08 15:10:09 -08001592 application_format_local_sessions (app, verbose);
1593 }));
1594 /* *INDENT-ON* */
1595 }
1596 else
1597 {
Florin Coras15531972018-08-12 23:50:53 -07001598 application_format_listeners (0, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001599
1600 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001601 pool_foreach (app, app_main.app_pool, ({
1602 application_format_listeners (app, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001603 }));
1604 /* *INDENT-ON* */
1605 }
1606}
1607
1608void
1609application_format_all_clients (vlib_main_t * vm, int do_local, int verbose)
1610{
1611 application_t *app;
1612
Florin Coras15531972018-08-12 23:50:53 -07001613 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001614 {
1615 vlib_cli_output (vm, "No active apps");
1616 return;
1617 }
1618
1619 if (do_local)
1620 {
1621 application_format_local_connects (0, verbose);
1622
1623 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001624 pool_foreach (app, app_main.app_pool, ({
1625 application_format_local_connects (app, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001626 }));
1627 /* *INDENT-ON* */
1628 }
1629 else
1630 {
1631 application_format_connects (0, verbose);
1632
1633 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001634 pool_foreach (app, app_main.app_pool, ({
Florin Corasf8f516a2018-02-08 15:10:09 -08001635 application_format_connects (app, verbose);
1636 }));
1637 /* *INDENT-ON* */
1638 }
1639}
1640
Dave Barach68b0fb02017-02-28 15:15:56 -05001641static clib_error_t *
1642show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1643 vlib_cli_command_t * cmd)
1644{
Florin Corasf8f516a2018-02-08 15:10:09 -08001645 int do_server = 0, do_client = 0, do_local = 0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001646 application_t *app;
Florin Coras349f8ca2018-11-20 16:52:49 -08001647 u32 app_index = ~0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001648 int verbose = 0;
1649
Florin Corascea194d2017-10-02 00:18:51 -07001650 session_cli_return_if_not_enabled ();
Florin Corase04c2992017-03-01 08:17:34 -08001651
Dave Barach68b0fb02017-02-28 15:15:56 -05001652 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1653 {
1654 if (unformat (input, "server"))
1655 do_server = 1;
1656 else if (unformat (input, "client"))
1657 do_client = 1;
Florin Corasf8f516a2018-02-08 15:10:09 -08001658 else if (unformat (input, "local"))
1659 do_local = 1;
Florin Coras349f8ca2018-11-20 16:52:49 -08001660 else if (unformat (input, "%u", &app_index))
1661 ;
Dave Barach68b0fb02017-02-28 15:15:56 -05001662 else if (unformat (input, "verbose"))
1663 verbose = 1;
1664 else
Florin Coras349f8ca2018-11-20 16:52:49 -08001665 return clib_error_return (0, "unknown input `%U'",
1666 format_unformat_error, input);
Dave Barach68b0fb02017-02-28 15:15:56 -05001667 }
1668
1669 if (do_server)
Florin Coras349f8ca2018-11-20 16:52:49 -08001670 {
1671 application_format_all_listeners (vm, do_local, verbose);
1672 return 0;
1673 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001674
1675 if (do_client)
Florin Coras349f8ca2018-11-20 16:52:49 -08001676 {
1677 application_format_all_clients (vm, do_local, verbose);
1678 return 0;
1679 }
1680
1681 if (app_index != ~0)
1682 {
Florin Coras47c40e22018-11-26 17:01:36 -08001683 app = application_get_if_valid (app_index);
Florin Coras349f8ca2018-11-20 16:52:49 -08001684 if (!app)
1685 return clib_error_return (0, "No app with index %u", app_index);
1686
1687 vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1688 return 0;
1689 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001690
Florin Coras6cf30ad2017-04-04 23:08:23 -07001691 /* Print app related info */
1692 if (!do_server && !do_client)
1693 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001694 vlib_cli_output (vm, "%U", format_application, 0, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001695 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001696 pool_foreach (app, app_main.app_pool, ({
Florin Coras349f8ca2018-11-20 16:52:49 -08001697 vlib_cli_output (vm, "%U", format_application, app, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001698 }));
1699 /* *INDENT-ON* */
Florin Coras6cf30ad2017-04-04 23:08:23 -07001700 }
1701
Dave Barach68b0fb02017-02-28 15:15:56 -05001702 return 0;
1703}
1704
Florin Corase04c2992017-03-01 08:17:34 -08001705/* *INDENT-OFF* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001706VLIB_CLI_COMMAND (show_app_command, static) =
1707{
Florin Corase04c2992017-03-01 08:17:34 -08001708 .path = "show app",
1709 .short_help = "show app [server|client] [verbose]",
1710 .function = show_app_command_fn,
1711};
1712/* *INDENT-ON* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001713
1714/*
1715 * fd.io coding-style-patch-verification: ON
1716 *
1717 * Local Variables:
1718 * eval: (c-set-style "gnu")
1719 * End:
1720 */