blob: e6292157dfad468d523190c13d8e72d2dbfb9892 [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>
Dave Barach68b0fb02017-02-28 15:15:56 -050019#include <vnet/session/session.h>
20
Florin Coras15531972018-08-12 23:50:53 -070021static app_main_t app_main;
Dave Barach68b0fb02017-02-28 15:15:56 -050022
Florin Corasc1a42652019-02-08 18:27:29 -080023#define app_interface_check_thread_and_barrier(_fn, _arg) \
24 if (PREDICT_FALSE (!vlib_thread_is_main_w_barrier ())) \
25 { \
26 vlib_rpc_call_main_thread (_fn, (u8 *) _arg, sizeof(*_arg)); \
27 return 0; \
28 }
29
Florin Corasc9940fc2019-02-05 20:55:11 -080030static void
31application_local_listener_session_endpoint (local_session_t * ll,
32 session_endpoint_t * sep)
33{
34 sep->transport_proto =
35 session_type_transport_proto (ll->listener_session_type);
36 sep->port = ll->port;
37 sep->is_ip4 = ll->listener_session_type & 1;
38}
39
Florin Corasab2f6db2018-08-31 14:31:41 -070040static app_listener_t *
41app_listener_alloc (application_t * app)
42{
43 app_listener_t *app_listener;
44 pool_get (app->listeners, app_listener);
Dave Barachb7b92992018-10-17 10:38:51 -040045 clib_memset (app_listener, 0, sizeof (*app_listener));
Florin Corasab2f6db2018-08-31 14:31:41 -070046 app_listener->al_index = app_listener - app->listeners;
Florin Corasc9940fc2019-02-05 20:55:11 -080047 app_listener->app_index = app->app_index;
48 app_listener->session_index = SESSION_INVALID_INDEX;
49 app_listener->local_index = SESSION_INVALID_INDEX;
Florin Corasab2f6db2018-08-31 14:31:41 -070050 return app_listener;
51}
52
Florin Corasc9940fc2019-02-05 20:55:11 -080053app_listener_t *
Florin Corasab2f6db2018-08-31 14:31:41 -070054app_listener_get (application_t * app, u32 app_listener_index)
55{
56 return pool_elt_at_index (app->listeners, app_listener_index);
57}
58
59static void
60app_listener_free (application_t * app, app_listener_t * app_listener)
61{
62 clib_bitmap_free (app_listener->workers);
63 pool_put (app->listeners, app_listener);
64 if (CLIB_DEBUG)
Dave Barachb7b92992018-10-17 10:38:51 -040065 clib_memset (app_listener, 0xfa, sizeof (*app_listener));
Florin Corasab2f6db2018-08-31 14:31:41 -070066}
67
Florin Corasc9940fc2019-02-05 20:55:11 -080068local_session_t *
69application_local_listen_session_alloc (application_t * app)
Florin Corasab2f6db2018-08-31 14:31:41 -070070{
Florin Corasc9940fc2019-02-05 20:55:11 -080071 local_session_t *ll;
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;
76 return ll;
Florin Corasab2f6db2018-08-31 14:31:41 -070077}
78
Florin Corasc9940fc2019-02-05 20:55:11 -080079void
80application_local_listen_session_free (application_t * app,
81 local_session_t * ll)
Florin Corasab2f6db2018-08-31 14:31:41 -070082{
Florin Corasc9940fc2019-02-05 20:55:11 -080083 pool_put (app->local_listen_sessions, ll);
84 if (CLIB_DEBUG)
85 clib_memset (ll, 0xfb, sizeof (*ll));
86}
87
88static u32
89app_listener_id (app_listener_t * al)
90{
91 ASSERT (al->app_index < 1 << 16 && al->al_index < 1 << 16);
92 return (al->app_index << 16 | al->al_index);
93}
94
95session_handle_t
96app_listener_handle (app_listener_t * al)
97{
98 return ((u64) SESSION_LISTENER_PREFIX << 32 | (u64) app_listener_id (al));
Florin Corasab2f6db2018-08-31 14:31:41 -070099}
100
101static void
Florin Corasc9940fc2019-02-05 20:55:11 -0800102app_listener_id_parse (u32 listener_id, u32 * app_index,
103 u32 * app_listener_index)
Florin Corasab2f6db2018-08-31 14:31:41 -0700104{
Florin Corasc9940fc2019-02-05 20:55:11 -0800105 *app_index = listener_id >> 16;
106 *app_listener_index = listener_id & 0xFFFF;
107}
108
109void
110app_listener_handle_parse (session_handle_t handle, u32 * app_index,
111 u32 * app_listener_index)
112{
113 app_listener_id_parse (handle & 0xFFFFFFFF, app_index, app_listener_index);
114}
115
116static app_listener_t *
117app_listener_get_w_id (u32 listener_id)
118{
119 u32 app_index, app_listener_index;
120 application_t *app;
121
122 app_listener_id_parse (listener_id, &app_index, &app_listener_index);
123 app = application_get_if_valid (app_index);
124 if (!app)
125 return 0;
126 return app_listener_get (app, app_listener_index);
127}
128
129app_listener_t *
130app_listener_get_w_session (session_t * ls)
131{
132 application_t *app;
133
134 app = application_get_if_valid (ls->app_index);
135 if (!app)
136 return 0;
137 return app_listener_get (app, ls->al_index);
138}
139
140app_listener_t *
141app_listener_get_w_handle (session_handle_t handle)
142{
143
144 if (handle >> 32 != SESSION_LISTENER_PREFIX)
145 return 0;
146
147 return app_listener_get_w_id (handle & 0xFFFFFFFF);
148}
149
150app_listener_t *
151app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
152{
153 u32 table_index, fib_proto;
154 session_endpoint_t *sep;
155 session_handle_t handle;
156 local_session_t *ll;
157 session_t *ls;
158
159 sep = (session_endpoint_t *) sep_ext;
160 if (application_has_local_scope (app) && session_endpoint_is_local (sep))
161 {
162 table_index = application_local_session_table (app);
163 handle = session_lookup_endpoint_listener (table_index, sep, 1);
164 if (handle != SESSION_INVALID_HANDLE)
165 {
166 ll = application_get_local_listener_w_handle (handle);
167 return app_listener_get_w_session ((session_t *) ll);
168 }
169 }
170
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)
175 {
176 ls = listen_session_get_from_handle (handle);
177 return app_listener_get_w_session ((session_t *) ls);
178 }
179
180 return 0;
181}
182
183int
184app_listener_alloc_and_init (application_t * app,
185 session_endpoint_cfg_t * sep,
186 app_listener_t ** listener)
187{
188 app_listener_t *app_listener;
189 local_session_t *ll = 0;
190 session_handle_t lh;
191 session_type_t st;
192 session_t *ls = 0;
193 int rv;
194
195 app_listener = app_listener_alloc (app);
196 st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
197
198 /*
199 * Add session endpoint to local session table. Only binds to "inaddr_any"
200 * (i.e., zero address) are added to local scope table.
201 */
202 if (application_has_local_scope (app)
203 && session_endpoint_is_local ((session_endpoint_t *) sep))
204 {
205 u32 table_index;
206
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;
217 }
218
219 if (application_has_global_scope (app))
220 {
221 /*
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.
226 */
227 ls = listen_session_new (0, st);
228 ls->app_index = app->app_index;
229 ls->app_wrk_index = sep->app_wrk_index;
230
231 /* Listen pool can be reallocated if the transport is
232 * recursive (tls) */
233 lh = session_handle (ls);
234
235 if ((rv = session_listen (ls, sep)))
236 {
237 ls = session_get_from_handle (lh);
238 session_free (ls);
239 return rv;
240 }
241 app_listener->session_index = ls->session_index;
242 ls->al_index = app_listener->al_index;
243 }
244
245 if (!ll && !ls)
246 {
247 app_listener_free (app, app_listener);
248 return -1;
249 }
250
251 *listener = app_listener;
252 return 0;
253}
254
255void
256app_listener_cleanup (app_listener_t * al)
257{
258 application_t *app = application_get (al->app_index);
259
260 if (al->session_index != SESSION_INVALID_INDEX)
261 {
262 session_t *ls = session_get (al->session_index, 0);
263 session_stop_listen (ls);
264 listen_session_del (ls);
265 }
266 if (al->local_index != SESSION_INVALID_INDEX)
267 {
268 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
269 local_session_t *ll;
270 u32 table_index;
271
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);
277 }
278 app_listener_free (app, al);
279}
280
281app_worker_t *
282app_listener_select_worker (app_listener_t * al)
283{
284 application_t *app;
285 u32 wrk_index;
286
287 app = application_get (al->app_index);
288 wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
289 if (wrk_index == ~0)
290 wrk_index = clib_bitmap_first_set (al->workers);
291
292 ASSERT (wrk_index != ~0);
293 al->accept_rotor = wrk_index;
294 return application_get_worker (app, wrk_index);
295}
296
297session_t *
298app_listener_get_session (app_listener_t * al)
299{
300 if (al->session_index == SESSION_INVALID_INDEX)
301 return 0;
302
303 return listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -0700304}
305
Florin Coras15531972018-08-12 23:50:53 -0700306static app_worker_map_t *
307app_worker_map_alloc (application_t * app)
308{
309 app_worker_map_t *map;
310 pool_get (app->worker_maps, map);
Dave Barachb7b92992018-10-17 10:38:51 -0400311 clib_memset (map, 0, sizeof (*map));
Florin Coras15531972018-08-12 23:50:53 -0700312 return map;
313}
Dave Barach68b0fb02017-02-28 15:15:56 -0500314
Florin Coras15531972018-08-12 23:50:53 -0700315static u32
316app_worker_map_index (application_t * app, app_worker_map_t * map)
317{
318 return (map - app->worker_maps);
319}
320
321static void
322app_worker_map_free (application_t * app, app_worker_map_t * map)
323{
324 pool_put (app->worker_maps, map);
325}
326
327static app_worker_map_t *
328app_worker_map_get (application_t * app, u32 map_index)
329{
Florin Coras01f3f892018-12-02 12:45:53 -0800330 if (pool_is_free_index (app->worker_maps, map_index))
331 return 0;
Florin Coras15531972018-08-12 23:50:53 -0700332 return pool_elt_at_index (app->worker_maps, map_index);
333}
Florin Coras0bee9ce2018-03-22 21:24:31 -0700334
Florin Coras053a0e42018-11-13 15:52:38 -0800335static const u8 *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700336app_get_name (application_t * app)
337{
Florin Coras0bee9ce2018-03-22 21:24:31 -0700338 return app->name;
339}
340
Florin Corascea194d2017-10-02 00:18:51 -0700341u32
342application_session_table (application_t * app, u8 fib_proto)
343{
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);
351 else
352 return session_lookup_get_index_for_fib (fib_proto,
353 app_ns->ip6_fib_index);
354}
355
356u32
357application_local_session_table (application_t * app)
358{
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;
364}
365
Florin Corascea194d2017-10-02 00:18:51 -0700366/**
Florin Coras053a0e42018-11-13 15:52:38 -0800367 * Returns app name for app-index
Florin Corascea194d2017-10-02 00:18:51 -0700368 */
Florin Coras053a0e42018-11-13 15:52:38 -0800369const u8 *
Florin Corascea194d2017-10-02 00:18:51 -0700370application_name_from_index (u32 app_index)
371{
372 application_t *app = application_get (app_index);
373 if (!app)
374 return 0;
Florin Coras053a0e42018-11-13 15:52:38 -0800375 return app_get_name (app);
376}
377
378static void
379application_api_table_add (u32 app_index, u32 api_client_index)
380{
Florin Corasc1f5a432018-11-20 11:31:26 -0800381 if (api_client_index != APP_INVALID_INDEX)
382 hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
Florin Coras053a0e42018-11-13 15:52:38 -0800383}
384
385static void
386application_api_table_del (u32 api_client_index)
387{
388 hash_unset (app_main.app_by_api_client_index, api_client_index);
Florin Corascea194d2017-10-02 00:18:51 -0700389}
390
Dave Barach68b0fb02017-02-28 15:15:56 -0500391static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800392application_name_table_add (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500393{
Florin Corasc1f5a432018-11-20 11:31:26 -0800394 hash_set_mem (app_main.app_by_name, app->name, app->app_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500395}
396
397static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800398application_name_table_del (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500399{
Florin Corasc1f5a432018-11-20 11:31:26 -0800400 hash_unset_mem (app_main.app_by_name, app->name);
Dave Barach68b0fb02017-02-28 15:15:56 -0500401}
402
403application_t *
404application_lookup (u32 api_client_index)
405{
406 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700407 p = hash_get (app_main.app_by_api_client_index, api_client_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500408 if (p)
Florin Coras053a0e42018-11-13 15:52:38 -0800409 return application_get_if_valid (p[0]);
Dave Barach68b0fb02017-02-28 15:15:56 -0500410
411 return 0;
412}
413
Florin Coras6cf30ad2017-04-04 23:08:23 -0700414application_t *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700415application_lookup_name (const u8 * name)
416{
417 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700418 p = hash_get_mem (app_main.app_by_name, name);
Florin Coras0bee9ce2018-03-22 21:24:31 -0700419 if (p)
420 return application_get (p[0]);
421
422 return 0;
423}
424
Florin Corasc1a42652019-02-08 18:27:29 -0800425static application_t *
Florin Coras15531972018-08-12 23:50:53 -0700426application_alloc (void)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700427{
428 application_t *app;
Florin Coras15531972018-08-12 23:50:53 -0700429 pool_get (app_main.app_pool, app);
Dave Barachb7b92992018-10-17 10:38:51 -0400430 clib_memset (app, 0, sizeof (*app));
Florin Coras15531972018-08-12 23:50:53 -0700431 app->app_index = app - app_main.app_pool;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700432 return app;
433}
434
Florin Coras15531972018-08-12 23:50:53 -0700435application_t *
436application_get (u32 app_index)
Dave Barach68b0fb02017-02-28 15:15:56 -0500437{
Florin Coras15531972018-08-12 23:50:53 -0700438 if (app_index == APP_INVALID_INDEX)
439 return 0;
440 return pool_elt_at_index (app_main.app_pool, app_index);
441}
Dave Barach68b0fb02017-02-28 15:15:56 -0500442
Florin Coras15531972018-08-12 23:50:53 -0700443application_t *
444application_get_if_valid (u32 app_index)
445{
446 if (pool_is_free_index (app_main.app_pool, app_index))
447 return 0;
Florin Corasa5464812017-04-19 13:00:05 -0700448
Florin Coras15531972018-08-12 23:50:53 -0700449 return pool_elt_at_index (app_main.app_pool, app_index);
450}
Florin Coras7999e832017-10-31 01:51:04 -0700451
Florin Corasd79b41e2017-03-04 05:37:52 -0800452static void
Florin Coras6cf30ad2017-04-04 23:08:23 -0700453application_verify_cb_fns (session_cb_vft_t * cb_fns)
Florin Corasd79b41e2017-03-04 05:37:52 -0800454{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700455 if (cb_fns->session_accept_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800456 clib_warning ("No accept callback function provided");
Florin Coras6cf30ad2017-04-04 23:08:23 -0700457 if (cb_fns->session_connected_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800458 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");
463}
464
Florin Corasb384b542018-01-15 01:08:33 -0800465/**
466 * Check app config for given segment type
467 *
468 * Returns 1 on success and 0 otherwise
469 */
470static u8
471application_verify_cfg (ssvm_segment_type_t st)
472{
473 u8 is_valid;
474 if (st == SSVM_SEGMENT_MEMFD)
475 {
476 is_valid = (session_manager_get_evt_q_segment () != 0);
477 if (!is_valid)
478 clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
479 return is_valid;
480 }
481 else if (st == SSVM_SEGMENT_SHM)
482 {
483 is_valid = (session_manager_get_evt_q_segment () == 0);
484 if (!is_valid)
485 clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
486 return is_valid;
487 }
488 else
489 return 1;
490}
491
Florin Corasc1a42652019-02-08 18:27:29 -0800492static int
Florin Coras15531972018-08-12 23:50:53 -0700493application_alloc_and_init (app_init_args_t * a)
Dave Barach68b0fb02017-02-28 15:15:56 -0500494{
Florin Corasa332c462018-01-31 06:52:17 -0800495 ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
Florin Corasb384b542018-01-15 01:08:33 -0800496 segment_manager_properties_t *props;
497 vl_api_registration_t *reg;
Florin Coras15531972018-08-12 23:50:53 -0700498 application_t *app;
499 u64 *options;
Dave Barach68b0fb02017-02-28 15:15:56 -0500500
Florin Coras15531972018-08-12 23:50:53 -0700501 app = application_alloc ();
502 options = a->options;
Florin Corasb384b542018-01-15 01:08:33 -0800503 /*
504 * Make sure we support the requested configuration
505 */
Florin Corasa332c462018-01-31 06:52:17 -0800506 if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
507 {
Florin Coras15531972018-08-12 23:50:53 -0700508 reg = vl_api_client_index_to_registration (a->api_client_index);
Florin Corasa332c462018-01-31 06:52:17 -0800509 if (!reg)
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;
513 }
514 else
515 {
Florin Coras99368312018-08-02 10:45:44 -0700516 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
517 {
518 clib_warning ("mq eventfds can only be used if socket transport is "
519 "used for api");
520 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
521 }
Florin Corasa332c462018-01-31 06:52:17 -0800522 seg_type = SSVM_SEGMENT_PRIVATE;
523 }
Florin Corasb384b542018-01-15 01:08:33 -0800524
Florin Corasa332c462018-01-31 06:52:17 -0800525 if (!application_verify_cfg (seg_type))
Florin Corasb384b542018-01-15 01:08:33 -0800526 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
Dave Barach68b0fb02017-02-28 15:15:56 -0500527
Florin Coras15531972018-08-12 23:50:53 -0700528 /* Check that the obvious things are properly set up */
529 application_verify_cb_fns (a->session_cb_vft);
530
Florin Coras15531972018-08-12 23:50:53 -0700531 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);
536
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;
541
Florin Corasa332c462018-01-31 06:52:17 -0800542 props = application_segment_manager_properties (app);
543 segment_manager_properties_init (props);
Florin Coras15531972018-08-12 23:50:53 -0700544 props->segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
545 props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
Florin Corasb384b542018-01-15 01:08:33 -0800546 if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
547 {
548 props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
549 props->add_segment = 1;
550 }
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];
Florin Corasf8f516a2018-02-08 15:10:09 -0800555 if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
556 props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
Florin Coras99368312018-08-02 10:45:44 -0700557 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
558 props->use_mq_eventfd = 1;
Florin Coras58d36f02018-03-09 13:05:53 -0800559 if (options[APP_OPTIONS_TLS_ENGINE])
560 app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
Florin Corasa332c462018-01-31 06:52:17 -0800561 props->segment_type = seg_type;
Dave Barach68b0fb02017-02-28 15:15:56 -0500562
Florin Coras15531972018-08-12 23:50:53 -0700563 /* Add app to lookup by api_client_index table */
Florin Corasc1f5a432018-11-20 11:31:26 -0800564 if (!application_is_builtin (app))
565 application_api_table_add (app->app_index, a->api_client_index);
566 else
567 application_name_table_add (app);
568
569 a->app_index = app->app_index;
Florin Corasa332c462018-01-31 06:52:17 -0800570
Florin Coras15531972018-08-12 23:50:53 -0700571 APP_DBG ("New app name: %v api index: %u index %u", app->name,
572 app->api_client_index, app->app_index);
573
574 return 0;
575}
576
Florin Corasc1a42652019-02-08 18:27:29 -0800577static void
Florin Coras15531972018-08-12 23:50:53 -0700578application_free (application_t * app)
579{
580 app_worker_map_t *wrk_map;
581 app_worker_t *app_wrk;
Florin Corasab2f6db2018-08-31 14:31:41 -0700582 u32 table_index;
583 local_session_t *ll;
584 session_endpoint_t sep;
Florin Coras15531972018-08-12 23:50:53 -0700585
586 /*
587 * The app event queue allocated in first segment is cleared with
588 * the segment manager. No need to explicitly free it.
589 */
590 APP_DBG ("Delete app name %v api index: %d index: %d", app->name,
591 app->api_client_index, app->app_index);
592
593 if (application_is_proxy (app))
594 application_remove_proxy (app);
595
Florin Corasab2f6db2018-08-31 14:31:41 -0700596 /*
597 * Free workers
598 */
599
Florin Coras15531972018-08-12 23:50:53 -0700600 /* *INDENT-OFF* */
601 pool_flush (wrk_map, app->worker_maps, ({
602 app_wrk = app_worker_get (wrk_map->wrk_index);
603 app_worker_free (app_wrk);
604 }));
605 /* *INDENT-ON* */
606 pool_free (app->worker_maps);
607
Florin Corasab2f6db2018-08-31 14:31:41 -0700608 /*
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.
613 */
614 table_index = application_local_session_table (app);
615 /* *INDENT-OFF* */
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);
619 }));
620 /* *INDENT-ON* */
621 pool_free (app->local_listen_sessions);
622
623 /*
624 * Cleanup remaining state
625 */
Florin Corasc1f5a432018-11-20 11:31:26 -0800626 if (application_is_builtin (app))
627 application_name_table_del (app);
Florin Coras15531972018-08-12 23:50:53 -0700628 vec_free (app->name);
629 vec_free (app->tls_cert);
630 vec_free (app->tls_key);
631 pool_put (app_main.app_pool, app);
632}
633
Florin Corasc1a42652019-02-08 18:27:29 -0800634static void
Florin Coras053a0e42018-11-13 15:52:38 -0800635application_detach_process (application_t * app, u32 api_client_index)
636{
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;
641
642 if (api_client_index == ~0)
643 {
644 application_free (app);
645 return;
646 }
647
648 APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
649 app->app_index, app->api_client_index);
650
651 /* *INDENT-OFF* */
652 pool_foreach (wrk_map, app->worker_maps, ({
653 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Corasc1f5a432018-11-20 11:31:26 -0800654 if (app_wrk->api_client_index == api_client_index)
Florin Coras053a0e42018-11-13 15:52:38 -0800655 vec_add1 (wrks, app_wrk->wrk_index);
656 }));
657 /* *INDENT-ON* */
658
659 if (!vec_len (wrks))
660 {
661 clib_warning ("no workers for app %u api_index %u", app->app_index,
662 api_client_index);
663 return;
664 }
665
666 args->app_index = app->app_index;
Florin Corasc1f5a432018-11-20 11:31:26 -0800667 args->api_client_index = api_client_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800668 vec_foreach (wrk_index, wrks)
669 {
670 app_wrk = app_worker_get (wrk_index[0]);
Florin Coras349f8ca2018-11-20 16:52:49 -0800671 args->wrk_map_index = app_wrk->wrk_map_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800672 args->is_add = 0;
673 vnet_app_worker_add_del (args);
674 }
675 vec_free (wrks);
676}
677
Florin Coras15531972018-08-12 23:50:53 -0700678app_worker_t *
679application_get_worker (application_t * app, u32 wrk_map_index)
680{
681 app_worker_map_t *map;
682 map = app_worker_map_get (app, wrk_map_index);
683 if (!map)
684 return 0;
685 return app_worker_get (map->wrk_index);
686}
687
688app_worker_t *
689application_get_default_worker (application_t * app)
690{
691 return application_get_worker (app, 0);
692}
693
Florin Coras053a0e42018-11-13 15:52:38 -0800694u32
695application_n_workers (application_t * app)
696{
697 return pool_elts (app->worker_maps);
698}
699
Florin Coras15531972018-08-12 23:50:53 -0700700app_worker_t *
Florin Corasc9940fc2019-02-05 20:55:11 -0800701application_listener_select_worker (session_t * ls)
Florin Corasab2f6db2018-08-31 14:31:41 -0700702{
Florin Corasc9940fc2019-02-05 20:55:11 -0800703 app_listener_t *al;
Florin Corasab2f6db2018-08-31 14:31:41 -0700704
Florin Corasc9940fc2019-02-05 20:55:11 -0800705 al = app_listener_get_w_session (ls);
706 return app_listener_select_worker (al);
Florin Corasab2f6db2018-08-31 14:31:41 -0700707}
708
Florin Coras15531972018-08-12 23:50:53 -0700709int
Florin Coras623eb562019-02-03 19:28:34 -0800710application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
Florin Coras15531972018-08-12 23:50:53 -0700711{
712 app_worker_map_t *wrk_map;
713 app_worker_t *app_wrk;
714 segment_manager_t *sm;
715 int rv;
716
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);
721
722 /*
723 * Setup first segment manager
724 */
725 sm = segment_manager_new ();
726 sm->app_wrk_index = app_wrk->wrk_index;
727
728 if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
729 app->sm_properties.prealloc_fifos)))
730 {
731 app_worker_free (app_wrk);
732 return rv;
733 }
Florin Corasc87c91d2017-08-16 19:55:49 -0700734 sm->first_is_protected = 1;
Dave Barach68b0fb02017-02-28 15:15:56 -0500735
Florin Corascea194d2017-10-02 00:18:51 -0700736 /*
Florin Coras15531972018-08-12 23:50:53 -0700737 * Setup app worker
Florin Corascea194d2017-10-02 00:18:51 -0700738 */
Florin Coras15531972018-08-12 23:50:53 -0700739 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);
Dave Barach68b0fb02017-02-28 15:15:56 -0500743
Florin Corasf8f516a2018-02-08 15:10:09 -0800744 /*
745 * Segment manager for local sessions
746 */
747 sm = segment_manager_new ();
Florin Coras15531972018-08-12 23:50:53 -0700748 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));
751
752 *wrk = app_wrk;
Florin Corasf8f516a2018-02-08 15:10:09 -0800753
Florin Coras6cf30ad2017-04-04 23:08:23 -0700754 return 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500755}
756
Florin Coras623eb562019-02-03 19:28:34 -0800757int
Florin Corasc1a42652019-02-08 18:27:29 -0800758vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
759{
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;
764 application_t *app;
765 int rv;
766
767 app = application_get (a->app_index);
768 if (!app)
769 return VNET_API_ERROR_INVALID_VALUE;
770
771 if (a->is_add)
772 {
773 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
774 return rv;
775
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);
779
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;
787 }
788 else
789 {
790 wrk_map = app_worker_map_get (app, a->wrk_map_index);
791 if (!wrk_map)
792 return VNET_API_ERROR_INVALID_VALUE;
793
794 app_wrk = app_worker_get (wrk_map->wrk_index);
795 if (!app_wrk)
796 return VNET_API_ERROR_INVALID_VALUE;
797
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);
803 }
804 return 0;
805}
806
807static int
808app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
809{
810 app_namespace_t *app_ns;
811 if (vec_len (namespace_id) == 0)
812 {
813 /* Use default namespace */
814 *app_ns_index = 0;
815 return 0;
816 }
817
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);
822 if (!app_ns)
823 return VNET_API_ERROR_APP_INVALID_NS;
824 if (app_ns->ns_secret != secret)
825 return VNET_API_ERROR_APP_WRONG_NS_SECRET;
826 return 0;
827}
828
829static u8 *
830app_name_from_api_index (u32 api_client_index)
831{
832 vl_api_registration_t *regp;
833 regp = vl_api_client_index_to_registration (api_client_index);
834 if (regp)
835 return format (0, "%s%c", regp->name, 0);
836
837 clib_warning ("api client index %u does not have an api registration!",
838 api_client_index);
839 return format (0, "unknown%c", 0);
840}
841
842/**
843 * Attach application to vpp
844 *
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.
848 */
849int
850vnet_application_attach (vnet_app_attach_args_t * a)
851{
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;
857 u8 *app_name = 0;
858 u64 secret;
859 int rv;
860
861 if (a->api_client_index != APP_INVALID_INDEX)
862 app = application_lookup (a->api_client_index);
863 else if (a->name)
864 app = application_lookup_name (a->name);
865 else
866 return VNET_API_ERROR_INVALID_VALUE;
867
868 if (app)
869 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
870
871 if (a->api_client_index != APP_INVALID_INDEX)
872 {
873 app_name = app_name_from_api_index (a->api_client_index);
874 a->name = app_name;
875 }
876
877 secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
878 if ((rv = app_validate_namespace (a->namespace_id, secret, &app_ns_index)))
879 return rv;
880 a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
881
882 if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
883 return rv;
884
885 app = application_get (a->app_index);
886 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
887 return rv;
888
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);
893
894 if (application_is_proxy (app))
895 application_setup_proxy (app);
896
897 ASSERT (vec_len (fs->ssvm.name) <= 128);
898 a->segment = &fs->ssvm;
899 a->segment_handle = segment_manager_segment_handle (sm, fs);
900
901 segment_manager_segment_reader_unlock (sm);
902 vec_free (app_name);
903 return 0;
904}
905
906/**
907 * Detach application from vpp
908 */
909int
910vnet_application_detach (vnet_app_detach_args_t * a)
911{
912 application_t *app;
913
914 app = application_get_if_valid (a->app_index);
915 if (!app)
916 {
917 clib_warning ("app not attached");
918 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
919 }
920
921 app_interface_check_thread_and_barrier (vnet_application_detach, a);
922 application_detach_process (app, a->api_client_index);
923 return 0;
924}
925
926
927static u8
928session_endpoint_in_ns (session_endpoint_t * sep)
929{
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))
933 {
934 clib_warning ("sw_if_index %u not configured with ip %U",
935 sep->sw_if_index, format_ip46_address, &sep->ip,
936 sep->is_ip4);
937 return 0;
938 }
939 return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
940}
941
942static void
943session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
944 application_t * app, u8 is_connect)
945{
946 app_namespace_t *app_ns;
947 u32 ns_index, fib_index;
948
949 ns_index = app->ns_index;
950
951 /* App is a transport proto, so fetch the calling app's ns */
952 if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
953 {
954 app_worker_t *owner_wrk;
955 application_t *owner_app;
956
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;
960 }
961 app_ns = app_namespace_get (ns_index);
962 if (!app_ns)
963 return;
964
965 /* Ask transport and network to bind to/connect using local interface
966 * that "supports" app's namespace. This will fix our local connection
967 * endpoint.
968 */
969
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;
973 else
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;
977
978 if (!is_connect)
979 {
980 sep->sw_if_index = app_ns->sw_if_index;
981 }
982 else
983 {
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");
988
989 sep->peer.sw_if_index = app_ns->sw_if_index;
990 }
991}
992
993int
994vnet_listen (vnet_listen_args_t * a)
995{
996 app_listener_t *app_listener;
997 app_worker_t *app_wrk;
998 application_t *app;
999 int rv;
1000
1001 app = application_get_if_valid (a->app_index);
1002 if (!app)
1003 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1004
1005 app_wrk = application_get_worker (app, a->wrk_map_index);
1006 if (!app_wrk)
1007 return VNET_API_ERROR_INVALID_VALUE;
1008
1009 a->sep_ext.app_wrk_index = app_wrk->wrk_index;
1010
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;
1014
1015 /*
1016 * Check if we already have an app listener
1017 */
1018 app_listener = app_listener_lookup (app, &a->sep_ext);
1019 if (app_listener)
1020 {
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))
1024 return -1;
1025 a->handle = app_listener_handle (app_listener);
1026 return 0;
1027 }
1028
1029 /*
1030 * Create new app listener
1031 */
1032 if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1033 return rv;
1034
1035 if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1036 {
1037 app_listener_cleanup (app_listener);
1038 return rv;
1039 }
1040
1041 a->handle = app_listener_handle (app_listener);
1042 return 0;
1043}
1044
1045int
1046vnet_connect (vnet_connect_args_t * a)
1047{
1048 app_worker_t *server_wrk, *client_wrk;
1049 application_t *client;
1050 local_session_t *ll;
1051 app_listener_t *al;
1052 u32 table_index;
1053 session_t *ls;
1054 u8 fib_proto;
1055 u64 lh;
1056
1057 if (session_endpoint_is_zero (&a->sep))
1058 return VNET_API_ERROR_INVALID_VALUE;
1059
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);
1063
1064 /*
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.
1068 */
1069 if (application_has_local_scope (client))
1070 {
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;
1075
1076 if (lh == SESSION_INVALID_HANDLE)
1077 goto global_scope;
1078
1079 ll = application_get_local_listener_w_handle (lh);
1080 al = app_listener_get_w_session ((session_t *) ll);
1081
1082 /*
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.
1086 */
1087 if (al->app_index == a->app_index)
1088 goto global_scope;
1089
1090 server_wrk = app_listener_select_worker (al);
1091 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1092 a->api_context);
1093 }
1094
1095 /*
1096 * If nothing found, check the global scope for locally attached
1097 * destinations. Make sure first that we're allowed to.
1098 */
1099
1100global_scope:
1101 if (session_endpoint_is_local (&a->sep))
1102 return VNET_API_ERROR_SESSION_CONNECT;
1103
1104 if (!application_has_global_scope (client))
1105 return VNET_API_ERROR_APP_CONNECT_SCOPE;
1106
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);
1110 if (ls)
1111 {
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,
1116 a->api_context);
1117 }
1118
1119 /*
1120 * Not connecting to a local server, propagate to transport
1121 */
1122 if (app_worker_connect_session (client_wrk, &a->sep, a->api_context))
1123 return VNET_API_ERROR_SESSION_CONNECT;
1124 return 0;
1125}
1126
1127int
1128vnet_unlisten (vnet_unlisten_args_t * a)
1129{
1130 app_worker_t *app_wrk;
1131 app_listener_t *al;
1132 application_t *app;
1133
1134 if (!(app = application_get_if_valid (a->app_index)))
1135 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1136
1137 al = app_listener_get_w_handle (a->handle);
1138 if (al->app_index != app->app_index)
1139 {
1140 clib_warning ("app doesn't own handle %llu!", a->handle);
1141 return -1;
1142 }
1143
1144 app_wrk = application_get_worker (app, a->wrk_map_index);
1145 if (!app_wrk)
1146 {
1147 clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1148 return -1;
1149 }
1150
1151 return app_worker_stop_listen (app_wrk, al);
1152}
1153
1154int
1155vnet_disconnect_session (vnet_disconnect_args_t * a)
1156{
1157 if (session_handle_is_local (a->handle))
1158 {
1159 local_session_t *ls;
1160
1161 /* Disconnect reply came to worker 1 not main thread */
1162 app_interface_check_thread_and_barrier (vnet_disconnect_session, a);
1163
1164 if (!(ls = app_worker_get_local_session_from_handle (a->handle)))
1165 return 0;
1166
1167 return app_worker_local_session_disconnect (a->app_index, ls);
1168 }
1169 else
1170 {
1171 app_worker_t *app_wrk;
1172 session_t *s;
1173
1174 s = session_get_from_handle_if_valid (a->handle);
1175 if (!s)
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;
1180
1181 /* We're peeking into another's thread pool. Make sure */
1182 ASSERT (s->session_index == session_index_from_handle (a->handle));
1183
1184 session_close (s);
1185 }
1186 return 0;
1187}
1188
1189int
Florin Coras623eb562019-02-03 19:28:34 -08001190application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1191{
1192 app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1193 app_listener_t *app_listener;
1194 application_t *app;
1195
1196 if (!old_wrk)
1197 return -1;
1198
1199 hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1200 if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1201 && s->rx_fifo)
1202 segment_manager_dealloc_fifos (s->rx_fifo->segment_index, s->rx_fifo,
1203 s->tx_fifo);
1204
Florin Coras623eb562019-02-03 19:28:34 -08001205 app = application_get (old_wrk->app_index);
1206 if (!app)
1207 return -1;
1208
Florin Corasc9940fc2019-02-05 20:55:11 -08001209 app_listener = app_listener_get (app, s->al_index);
1210
1211 /* Only remove from lb for now */
Florin Coras623eb562019-02-03 19:28:34 -08001212 app_listener->workers = clib_bitmap_set (app_listener->workers,
1213 old_wrk->wrk_map_index, 0);
Florin Coras623eb562019-02-03 19:28:34 -08001214
Florin Corasc9940fc2019-02-05 20:55:11 -08001215 if (app_worker_start_listen (app_wrk, app_listener))
1216 return -1;
Florin Corasab2f6db2018-08-31 14:31:41 -07001217
Florin Corasc9940fc2019-02-05 20:55:11 -08001218 s->app_wrk_index = app_wrk->wrk_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001219
Dave Barach68b0fb02017-02-28 15:15:56 -05001220 return 0;
1221}
1222
Dave Barach52851e62017-08-07 09:35:25 -04001223int
1224application_is_proxy (application_t * app)
1225{
Florin Coras7999e832017-10-31 01:51:04 -07001226 return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1227}
1228
1229int
1230application_is_builtin (application_t * app)
1231{
1232 return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1233}
1234
1235int
1236application_is_builtin_proxy (application_t * app)
1237{
1238 return (application_is_proxy (app) && application_is_builtin (app));
Dave Barach52851e62017-08-07 09:35:25 -04001239}
1240
Florin Corascea194d2017-10-02 00:18:51 -07001241u8
1242application_has_local_scope (application_t * app)
1243{
1244 return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1245}
1246
1247u8
1248application_has_global_scope (application_t * app)
1249{
1250 return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1251}
1252
Florin Coras60116992018-08-27 09:52:18 -07001253u8
1254application_use_mq_for_ctrl (application_t * app)
1255{
1256 return app->flags & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
1257}
1258
Florin Coras7999e832017-10-31 01:51:04 -07001259static clib_error_t *
1260application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1261 u8 transport_proto, u8 is_start)
1262{
Florin Coras7999e832017-10-31 01:51:04 -07001263 app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1264 u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
Florin Coras5665ced2018-10-25 18:03:45 -07001265 session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
Florin Coras7999e832017-10-31 01:51:04 -07001266 transport_connection_t *tc;
Florin Coras15531972018-08-12 23:50:53 -07001267 app_worker_t *app_wrk;
Florin Corasc9940fc2019-02-05 20:55:11 -08001268 app_listener_t *al;
Florin Coras288eaab2019-02-03 15:26:14 -08001269 session_t *s;
Florin Corasc9940fc2019-02-05 20:55:11 -08001270 u32 flags;
Florin Coras7999e832017-10-31 01:51:04 -07001271
Florin Coras15531972018-08-12 23:50:53 -07001272 /* TODO decide if we want proxy to be enabled for all workers */
1273 app_wrk = application_get_default_worker (app);
Florin Coras7999e832017-10-31 01:51:04 -07001274 if (is_start)
1275 {
Florin Coras15531972018-08-12 23:50:53 -07001276 s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001277 if (!s)
1278 {
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;
Florin Corasab2f6db2018-08-31 14:31:41 -07001283 sep.app_wrk_index = app_wrk->wrk_index; /* only default */
Florin Corasc9940fc2019-02-05 20:55:11 -08001284
1285 /* force global scope listener */
1286 flags = app->flags;
1287 app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1288 app_listener_alloc_and_init (app, &sep, &al);
1289 app->flags = flags;
1290
1291 app_worker_start_listen (app_wrk, al);
1292 s = listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -07001293 s->enqueue_epoch = SESSION_PROXY_LISTENER_INDEX;
Florin Coras19b1f6a2017-12-11 03:37:03 -08001294 }
Florin Coras7999e832017-10-31 01:51:04 -07001295 }
1296 else
1297 {
Florin Coras623eb562019-02-03 19:28:34 -08001298 s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001299 ASSERT (s);
Florin Coras7999e832017-10-31 01:51:04 -07001300 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001301
Florin Coras7999e832017-10-31 01:51:04 -07001302 tc = listen_session_get_transport (s);
1303
1304 if (!ip_is_zero (&tc->lcl_ip, 1))
1305 {
Florin Corasdbd44562017-11-09 19:30:17 -08001306 u32 sti;
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;
1310 sep.port = 0;
1311 sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001312 if (is_start)
Florin Corasab2f6db2018-08-31 14:31:41 -07001313 session_lookup_add_session_endpoint (sti,
1314 (session_endpoint_t *) & sep,
1315 s->session_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001316 else
Florin Corasab2f6db2018-08-31 14:31:41 -07001317 session_lookup_del_session_endpoint (sti,
1318 (session_endpoint_t *) & sep);
Florin Coras7999e832017-10-31 01:51:04 -07001319 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001320
Florin Coras7999e832017-10-31 01:51:04 -07001321 return 0;
1322}
1323
Florin Coras19b1f6a2017-12-11 03:37:03 -08001324static void
1325application_start_stop_proxy_local_scope (application_t * app,
1326 u8 transport_proto, u8 is_start)
1327{
1328 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1329 app_namespace_t *app_ns;
1330 app_ns = app_namespace_get (app->ns_index);
1331 sep.is_ip4 = 1;
1332 sep.transport_proto = transport_proto;
1333 sep.port = 0;
1334
1335 if (is_start)
1336 {
1337 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001338 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001339 sep.is_ip4 = 0;
1340 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001341 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001342 }
1343 else
1344 {
1345 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1346 sep.is_ip4 = 0;
1347 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1348 }
1349}
1350
Florin Coras7999e832017-10-31 01:51:04 -07001351void
Florin Coras561af9b2017-12-09 10:19:43 -08001352application_start_stop_proxy (application_t * app,
1353 transport_proto_t transport_proto, u8 is_start)
Florin Coras7999e832017-10-31 01:51:04 -07001354{
Florin Coras7999e832017-10-31 01:51:04 -07001355 if (application_has_local_scope (app))
Florin Coras19b1f6a2017-12-11 03:37:03 -08001356 application_start_stop_proxy_local_scope (app, transport_proto, is_start);
Florin Coras7999e832017-10-31 01:51:04 -07001357
1358 if (application_has_global_scope (app))
1359 {
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);
1364 }
1365}
1366
1367void
1368application_setup_proxy (application_t * app)
1369{
1370 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001371 transport_proto_t tp;
1372
Florin Coras7999e832017-10-31 01:51:04 -07001373 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001374
1375 /* *INDENT-OFF* */
1376 transport_proto_foreach (tp, ({
1377 if (transports & (1 << tp))
1378 application_start_stop_proxy (app, tp, 1);
1379 }));
1380 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001381}
1382
1383void
1384application_remove_proxy (application_t * app)
1385{
1386 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001387 transport_proto_t tp;
1388
Florin Coras7999e832017-10-31 01:51:04 -07001389 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001390
1391 /* *INDENT-OFF* */
1392 transport_proto_foreach (tp, ({
1393 if (transports & (1 << tp))
1394 application_start_stop_proxy (app, tp, 0);
1395 }));
1396 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001397}
1398
Florin Corasa332c462018-01-31 06:52:17 -08001399segment_manager_properties_t *
1400application_segment_manager_properties (application_t * app)
1401{
1402 return &app->sm_properties;
1403}
1404
1405segment_manager_properties_t *
1406application_get_segment_manager_properties (u32 app_index)
1407{
1408 application_t *app = application_get (app_index);
1409 return &app->sm_properties;
1410}
1411
Florin Coras371ca502018-02-21 12:07:41 -08001412clib_error_t *
1413vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1414{
1415 application_t *app;
1416 app = application_get (a->app_index);
1417 if (!app)
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);
1421 return 0;
1422}
1423
1424clib_error_t *
1425vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1426{
1427 application_t *app;
1428 app = application_get (a->app_index);
1429 if (!app)
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);
1433 return 0;
1434}
1435
Florin Coras15531972018-08-12 23:50:53 -07001436static void
1437application_format_listeners (application_t * app, int verbose)
1438{
1439 vlib_main_t *vm = vlib_get_main ();
1440 app_worker_map_t *wrk_map;
1441 app_worker_t *app_wrk;
1442 u32 sm_index;
1443 u64 handle;
1444
1445 if (!app)
1446 {
1447 vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1448 0, 0, verbose);
1449 return;
1450 }
1451
1452 /* *INDENT-OFF* */
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)
1456 continue;
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);
1460 }));
1461 }));
1462 /* *INDENT-ON* */
1463}
1464
1465static void
Florin Coras15531972018-08-12 23:50:53 -07001466application_format_connects (application_t * app, int verbose)
1467{
1468 app_worker_map_t *wrk_map;
1469 app_worker_t *app_wrk;
1470
1471 if (!app)
1472 {
1473 app_worker_format_connects (0, verbose);
1474 return;
1475 }
1476
1477 /* *INDENT-OFF* */
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);
1481 }));
1482 /* *INDENT-ON* */
1483}
1484
1485static void
Florin Coras15531972018-08-12 23:50:53 -07001486application_format_local_sessions (application_t * app, int verbose)
1487{
Florin Corasab2f6db2018-08-31 14:31:41 -07001488 vlib_main_t *vm = vlib_get_main ();
Florin Coras15531972018-08-12 23:50:53 -07001489 app_worker_map_t *wrk_map;
1490 app_worker_t *app_wrk;
Florin Corasab2f6db2018-08-31 14:31:41 -07001491 transport_proto_t tp;
1492 local_session_t *ls;
1493 u8 *conn = 0;
Florin Coras15531972018-08-12 23:50:53 -07001494
1495 if (!app)
1496 {
1497 app_worker_format_local_sessions (0, verbose);
1498 return;
1499 }
1500
Florin Corasab2f6db2018-08-31 14:31:41 -07001501 /*
1502 * Format local listeners
1503 */
1504
1505 /* *INDENT-OFF* */
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,
1509 ls->port);
1510 vlib_cli_output (vm, "%-40v%-15u%-20s", conn, ls->app_wrk_index, "*");
1511 vec_reset_length (conn);
1512 }));
1513 /* *INDENT-ON* */
1514
1515 /*
1516 * Format local accepted/connected sessions
1517 */
Florin Coras15531972018-08-12 23:50:53 -07001518 /* *INDENT-OFF* */
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);
1522 }));
1523 /* *INDENT-ON* */
1524}
1525
1526static void
Florin Coras15531972018-08-12 23:50:53 -07001527application_format_local_connects (application_t * app, int verbose)
1528{
1529 app_worker_map_t *wrk_map;
1530 app_worker_t *app_wrk;
1531
1532 if (!app)
1533 {
1534 app_worker_format_local_connects (0, verbose);
1535 return;
1536 }
1537
1538 /* *INDENT-OFF* */
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);
Florin Corasf8f516a2018-02-08 15:10:09 -08001542 }));
1543 /* *INDENT-ON* */
1544}
1545
Florin Coras6cf30ad2017-04-04 23:08:23 -07001546u8 *
1547format_application (u8 * s, va_list * args)
1548{
1549 application_t *app = va_arg (*args, application_t *);
1550 CLIB_UNUSED (int verbose) = va_arg (*args, int);
Florin Corasad0c77f2017-11-09 18:00:15 -08001551 segment_manager_properties_t *props;
Florin Coras053a0e42018-11-13 15:52:38 -08001552 const u8 *app_ns_name, *app_name;
Florin Coras349f8ca2018-11-20 16:52:49 -08001553 app_worker_map_t *wrk_map;
1554 app_worker_t *app_wrk;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001555
1556 if (app == 0)
1557 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001558 if (!verbose)
Florin Corasc1f5a432018-11-20 11:31:26 -08001559 s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
Florin Coras6cf30ad2017-04-04 23:08:23 -07001560 return s;
1561 }
1562
Florin Coras0bee9ce2018-03-22 21:24:31 -07001563 app_name = app_get_name (app);
Florin Corascea194d2017-10-02 00:18:51 -07001564 app_ns_name = app_namespace_id_from_index (app->ns_index);
Florin Corasa332c462018-01-31 06:52:17 -08001565 props = application_segment_manager_properties (app);
Florin Coras349f8ca2018-11-20 16:52:49 -08001566 if (!verbose)
1567 {
1568 s = format (s, "%-10u%-20s%-40s", app->app_index, app_name,
1569 app_ns_name);
1570 return s;
1571 }
1572
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);
1579
1580 /* *INDENT-OFF* */
1581 pool_foreach (wrk_map, app->worker_maps, ({
1582 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Coras623eb562019-02-03 19:28:34 -08001583 s = format (s, "%U", format_app_worker, app_wrk);
Florin Coras349f8ca2018-11-20 16:52:49 -08001584 }));
1585 /* *INDENT-ON* */
1586
Dave Barach68b0fb02017-02-28 15:15:56 -05001587 return s;
1588}
1589
Florin Corasf8f516a2018-02-08 15:10:09 -08001590void
1591application_format_all_listeners (vlib_main_t * vm, int do_local, int verbose)
1592{
1593 application_t *app;
Florin Corasf8f516a2018-02-08 15:10:09 -08001594
Florin Coras15531972018-08-12 23:50:53 -07001595 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001596 {
1597 vlib_cli_output (vm, "No active server bindings");
1598 return;
1599 }
1600
1601 if (do_local)
1602 {
1603 application_format_local_sessions (0, verbose);
1604 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001605 pool_foreach (app, app_main.app_pool, ({
Florin Corasf8f516a2018-02-08 15:10:09 -08001606 application_format_local_sessions (app, verbose);
1607 }));
1608 /* *INDENT-ON* */
1609 }
1610 else
1611 {
Florin Coras15531972018-08-12 23:50:53 -07001612 application_format_listeners (0, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001613
1614 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001615 pool_foreach (app, app_main.app_pool, ({
1616 application_format_listeners (app, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001617 }));
1618 /* *INDENT-ON* */
1619 }
1620}
1621
1622void
1623application_format_all_clients (vlib_main_t * vm, int do_local, int verbose)
1624{
1625 application_t *app;
1626
Florin Coras15531972018-08-12 23:50:53 -07001627 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001628 {
1629 vlib_cli_output (vm, "No active apps");
1630 return;
1631 }
1632
1633 if (do_local)
1634 {
1635 application_format_local_connects (0, verbose);
1636
1637 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001638 pool_foreach (app, app_main.app_pool, ({
1639 application_format_local_connects (app, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001640 }));
1641 /* *INDENT-ON* */
1642 }
1643 else
1644 {
1645 application_format_connects (0, verbose);
1646
1647 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001648 pool_foreach (app, app_main.app_pool, ({
Florin Corasf8f516a2018-02-08 15:10:09 -08001649 application_format_connects (app, verbose);
1650 }));
1651 /* *INDENT-ON* */
1652 }
1653}
1654
Dave Barach68b0fb02017-02-28 15:15:56 -05001655static clib_error_t *
1656show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1657 vlib_cli_command_t * cmd)
1658{
Florin Corasf8f516a2018-02-08 15:10:09 -08001659 int do_server = 0, do_client = 0, do_local = 0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001660 application_t *app;
Florin Coras349f8ca2018-11-20 16:52:49 -08001661 u32 app_index = ~0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001662 int verbose = 0;
1663
Florin Corascea194d2017-10-02 00:18:51 -07001664 session_cli_return_if_not_enabled ();
Florin Corase04c2992017-03-01 08:17:34 -08001665
Dave Barach68b0fb02017-02-28 15:15:56 -05001666 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1667 {
1668 if (unformat (input, "server"))
1669 do_server = 1;
1670 else if (unformat (input, "client"))
1671 do_client = 1;
Florin Corasf8f516a2018-02-08 15:10:09 -08001672 else if (unformat (input, "local"))
1673 do_local = 1;
Florin Coras349f8ca2018-11-20 16:52:49 -08001674 else if (unformat (input, "%u", &app_index))
1675 ;
Dave Barach68b0fb02017-02-28 15:15:56 -05001676 else if (unformat (input, "verbose"))
1677 verbose = 1;
1678 else
Florin Coras349f8ca2018-11-20 16:52:49 -08001679 return clib_error_return (0, "unknown input `%U'",
1680 format_unformat_error, input);
Dave Barach68b0fb02017-02-28 15:15:56 -05001681 }
1682
1683 if (do_server)
Florin Coras349f8ca2018-11-20 16:52:49 -08001684 {
1685 application_format_all_listeners (vm, do_local, verbose);
1686 return 0;
1687 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001688
1689 if (do_client)
Florin Coras349f8ca2018-11-20 16:52:49 -08001690 {
1691 application_format_all_clients (vm, do_local, verbose);
1692 return 0;
1693 }
1694
1695 if (app_index != ~0)
1696 {
Florin Coras47c40e22018-11-26 17:01:36 -08001697 app = application_get_if_valid (app_index);
Florin Coras349f8ca2018-11-20 16:52:49 -08001698 if (!app)
1699 return clib_error_return (0, "No app with index %u", app_index);
1700
1701 vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1702 return 0;
1703 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001704
Florin Coras6cf30ad2017-04-04 23:08:23 -07001705 /* Print app related info */
1706 if (!do_server && !do_client)
1707 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001708 vlib_cli_output (vm, "%U", format_application, 0, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001709 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001710 pool_foreach (app, app_main.app_pool, ({
Florin Coras349f8ca2018-11-20 16:52:49 -08001711 vlib_cli_output (vm, "%U", format_application, app, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001712 }));
1713 /* *INDENT-ON* */
Florin Coras6cf30ad2017-04-04 23:08:23 -07001714 }
1715
Dave Barach68b0fb02017-02-28 15:15:56 -05001716 return 0;
1717}
1718
Florin Corase04c2992017-03-01 08:17:34 -08001719/* *INDENT-OFF* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001720VLIB_CLI_COMMAND (show_app_command, static) =
1721{
Florin Corase04c2992017-03-01 08:17:34 -08001722 .path = "show app",
1723 .short_help = "show app [server|client] [verbose]",
1724 .function = show_app_command_fn,
1725};
1726/* *INDENT-ON* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001727
1728/*
1729 * fd.io coding-style-patch-verification: ON
1730 *
1731 * Local Variables:
1732 * eval: (c-set-style "gnu")
1733 * End:
1734 */