blob: e79851cab4c83b783e7e467a1fd93799bd3cdb7c [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;
Florin Coras222e1f412019-02-16 20:47:32 -080076 ll->session_state = SESSION_STATE_LISTENING;
Florin Corasc9940fc2019-02-05 20:55:11 -080077 return ll;
Florin Corasab2f6db2018-08-31 14:31:41 -070078}
79
Florin Corasc9940fc2019-02-05 20:55:11 -080080void
81application_local_listen_session_free (application_t * app,
82 local_session_t * ll)
Florin Corasab2f6db2018-08-31 14:31:41 -070083{
Florin Corasc9940fc2019-02-05 20:55:11 -080084 pool_put (app->local_listen_sessions, ll);
85 if (CLIB_DEBUG)
86 clib_memset (ll, 0xfb, sizeof (*ll));
87}
88
89static u32
90app_listener_id (app_listener_t * al)
91{
92 ASSERT (al->app_index < 1 << 16 && al->al_index < 1 << 16);
93 return (al->app_index << 16 | al->al_index);
94}
95
96session_handle_t
97app_listener_handle (app_listener_t * al)
98{
99 return ((u64) SESSION_LISTENER_PREFIX << 32 | (u64) app_listener_id (al));
Florin Corasab2f6db2018-08-31 14:31:41 -0700100}
101
102static void
Florin Corasc9940fc2019-02-05 20:55:11 -0800103app_listener_id_parse (u32 listener_id, u32 * app_index,
104 u32 * app_listener_index)
Florin Corasab2f6db2018-08-31 14:31:41 -0700105{
Florin Corasc9940fc2019-02-05 20:55:11 -0800106 *app_index = listener_id >> 16;
107 *app_listener_index = listener_id & 0xFFFF;
108}
109
110void
111app_listener_handle_parse (session_handle_t handle, u32 * app_index,
112 u32 * app_listener_index)
113{
114 app_listener_id_parse (handle & 0xFFFFFFFF, app_index, app_listener_index);
115}
116
117static app_listener_t *
118app_listener_get_w_id (u32 listener_id)
119{
120 u32 app_index, app_listener_index;
121 application_t *app;
122
123 app_listener_id_parse (listener_id, &app_index, &app_listener_index);
124 app = application_get_if_valid (app_index);
125 if (!app)
126 return 0;
127 return app_listener_get (app, app_listener_index);
128}
129
130app_listener_t *
131app_listener_get_w_session (session_t * ls)
132{
133 application_t *app;
134
135 app = application_get_if_valid (ls->app_index);
136 if (!app)
137 return 0;
138 return app_listener_get (app, ls->al_index);
139}
140
141app_listener_t *
142app_listener_get_w_handle (session_handle_t handle)
143{
144
145 if (handle >> 32 != SESSION_LISTENER_PREFIX)
146 return 0;
147
148 return app_listener_get_w_id (handle & 0xFFFFFFFF);
149}
150
151app_listener_t *
152app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
153{
154 u32 table_index, fib_proto;
155 session_endpoint_t *sep;
156 session_handle_t handle;
157 local_session_t *ll;
158 session_t *ls;
159
160 sep = (session_endpoint_t *) sep_ext;
161 if (application_has_local_scope (app) && session_endpoint_is_local (sep))
162 {
163 table_index = application_local_session_table (app);
164 handle = session_lookup_endpoint_listener (table_index, sep, 1);
165 if (handle != SESSION_INVALID_HANDLE)
166 {
167 ll = application_get_local_listener_w_handle (handle);
168 return app_listener_get_w_session ((session_t *) ll);
169 }
170 }
171
172 fib_proto = session_endpoint_fib_proto (sep);
173 table_index = application_session_table (app, fib_proto);
174 handle = session_lookup_endpoint_listener (table_index, sep, 1);
175 if (handle != SESSION_INVALID_HANDLE)
176 {
177 ls = listen_session_get_from_handle (handle);
178 return app_listener_get_w_session ((session_t *) ls);
179 }
180
181 return 0;
182}
183
184int
185app_listener_alloc_and_init (application_t * app,
186 session_endpoint_cfg_t * sep,
187 app_listener_t ** listener)
188{
189 app_listener_t *app_listener;
190 local_session_t *ll = 0;
191 session_handle_t lh;
192 session_type_t st;
193 session_t *ls = 0;
Florin Corasa27a46e2019-02-18 13:02:28 -0800194 u32 al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800195 int rv;
196
197 app_listener = app_listener_alloc (app);
Florin Corasa27a46e2019-02-18 13:02:28 -0800198 al_index = app_listener->al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800199 st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
200
201 /*
202 * Add session endpoint to local session table. Only binds to "inaddr_any"
203 * (i.e., zero address) are added to local scope table.
204 */
205 if (application_has_local_scope (app)
206 && session_endpoint_is_local ((session_endpoint_t *) sep))
207 {
208 u32 table_index;
209
210 ll = application_local_listen_session_alloc (app);
211 ll->port = sep->port;
212 /* Store the original session type for the unbind */
213 ll->listener_session_type = st;
214 table_index = application_local_session_table (app);
215 lh = application_local_session_handle (ll);
216 session_lookup_add_session_endpoint (table_index,
217 (session_endpoint_t *) sep, lh);
218 app_listener->local_index = ll->session_index;
219 ll->al_index = app_listener->al_index;
220 }
221
222 if (application_has_global_scope (app))
223 {
224 /*
225 * Start listening on local endpoint for requested transport and scope.
226 * Creates a stream session with state LISTENING to be used in session
227 * lookups, prior to establishing connection. Requests transport to
228 * build it's own specific listening connection.
229 */
230 ls = listen_session_new (0, st);
231 ls->app_index = app->app_index;
232 ls->app_wrk_index = sep->app_wrk_index;
233
234 /* Listen pool can be reallocated if the transport is
235 * recursive (tls) */
236 lh = session_handle (ls);
237
238 if ((rv = session_listen (ls, sep)))
239 {
240 ls = session_get_from_handle (lh);
241 session_free (ls);
242 return rv;
243 }
Florin Corasa27a46e2019-02-18 13:02:28 -0800244 ls = session_get_from_handle (lh);
245 app_listener = app_listener_get (app, al_index);
Florin Corasc9940fc2019-02-05 20:55:11 -0800246 app_listener->session_index = ls->session_index;
Florin Corasa27a46e2019-02-18 13:02:28 -0800247 ls->al_index = al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800248 }
249
250 if (!ll && !ls)
251 {
252 app_listener_free (app, app_listener);
253 return -1;
254 }
255
256 *listener = app_listener;
257 return 0;
258}
259
260void
261app_listener_cleanup (app_listener_t * al)
262{
263 application_t *app = application_get (al->app_index);
264
265 if (al->session_index != SESSION_INVALID_INDEX)
266 {
267 session_t *ls = session_get (al->session_index, 0);
268 session_stop_listen (ls);
269 listen_session_del (ls);
270 }
271 if (al->local_index != SESSION_INVALID_INDEX)
272 {
273 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
274 local_session_t *ll;
275 u32 table_index;
276
277 table_index = application_local_session_table (app);
278 ll = application_get_local_listen_session (app, al->local_index);
279 application_local_listener_session_endpoint (ll, &sep);
280 session_lookup_del_session_endpoint (table_index, &sep);
281 application_local_listen_session_free (app, ll);
282 }
283 app_listener_free (app, al);
284}
285
286app_worker_t *
287app_listener_select_worker (app_listener_t * al)
288{
289 application_t *app;
290 u32 wrk_index;
291
292 app = application_get (al->app_index);
293 wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
294 if (wrk_index == ~0)
295 wrk_index = clib_bitmap_first_set (al->workers);
296
297 ASSERT (wrk_index != ~0);
298 al->accept_rotor = wrk_index;
299 return application_get_worker (app, wrk_index);
300}
301
302session_t *
303app_listener_get_session (app_listener_t * al)
304{
305 if (al->session_index == SESSION_INVALID_INDEX)
306 return 0;
307
308 return listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -0700309}
310
Florin Coras15531972018-08-12 23:50:53 -0700311static app_worker_map_t *
312app_worker_map_alloc (application_t * app)
313{
314 app_worker_map_t *map;
315 pool_get (app->worker_maps, map);
Dave Barachb7b92992018-10-17 10:38:51 -0400316 clib_memset (map, 0, sizeof (*map));
Florin Coras15531972018-08-12 23:50:53 -0700317 return map;
318}
Dave Barach68b0fb02017-02-28 15:15:56 -0500319
Florin Coras15531972018-08-12 23:50:53 -0700320static u32
321app_worker_map_index (application_t * app, app_worker_map_t * map)
322{
323 return (map - app->worker_maps);
324}
325
326static void
327app_worker_map_free (application_t * app, app_worker_map_t * map)
328{
329 pool_put (app->worker_maps, map);
330}
331
332static app_worker_map_t *
333app_worker_map_get (application_t * app, u32 map_index)
334{
Florin Coras01f3f892018-12-02 12:45:53 -0800335 if (pool_is_free_index (app->worker_maps, map_index))
336 return 0;
Florin Coras15531972018-08-12 23:50:53 -0700337 return pool_elt_at_index (app->worker_maps, map_index);
338}
Florin Coras0bee9ce2018-03-22 21:24:31 -0700339
Florin Coras053a0e42018-11-13 15:52:38 -0800340static const u8 *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700341app_get_name (application_t * app)
342{
Florin Coras0bee9ce2018-03-22 21:24:31 -0700343 return app->name;
344}
345
Florin Corascea194d2017-10-02 00:18:51 -0700346u32
347application_session_table (application_t * app, u8 fib_proto)
348{
349 app_namespace_t *app_ns;
350 app_ns = app_namespace_get (app->ns_index);
351 if (!application_has_global_scope (app))
352 return APP_INVALID_INDEX;
353 if (fib_proto == FIB_PROTOCOL_IP4)
354 return session_lookup_get_index_for_fib (fib_proto,
355 app_ns->ip4_fib_index);
356 else
357 return session_lookup_get_index_for_fib (fib_proto,
358 app_ns->ip6_fib_index);
359}
360
361u32
362application_local_session_table (application_t * app)
363{
364 app_namespace_t *app_ns;
365 if (!application_has_local_scope (app))
366 return APP_INVALID_INDEX;
367 app_ns = app_namespace_get (app->ns_index);
368 return app_ns->local_table_index;
369}
370
Florin Corascea194d2017-10-02 00:18:51 -0700371/**
Florin Coras053a0e42018-11-13 15:52:38 -0800372 * Returns app name for app-index
Florin Corascea194d2017-10-02 00:18:51 -0700373 */
Florin Coras053a0e42018-11-13 15:52:38 -0800374const u8 *
Florin Corascea194d2017-10-02 00:18:51 -0700375application_name_from_index (u32 app_index)
376{
377 application_t *app = application_get (app_index);
378 if (!app)
379 return 0;
Florin Coras053a0e42018-11-13 15:52:38 -0800380 return app_get_name (app);
381}
382
383static void
384application_api_table_add (u32 app_index, u32 api_client_index)
385{
Florin Corasc1f5a432018-11-20 11:31:26 -0800386 if (api_client_index != APP_INVALID_INDEX)
387 hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
Florin Coras053a0e42018-11-13 15:52:38 -0800388}
389
390static void
391application_api_table_del (u32 api_client_index)
392{
393 hash_unset (app_main.app_by_api_client_index, api_client_index);
Florin Corascea194d2017-10-02 00:18:51 -0700394}
395
Dave Barach68b0fb02017-02-28 15:15:56 -0500396static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800397application_name_table_add (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500398{
Florin Corasc1f5a432018-11-20 11:31:26 -0800399 hash_set_mem (app_main.app_by_name, app->name, app->app_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500400}
401
402static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800403application_name_table_del (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500404{
Florin Corasc1f5a432018-11-20 11:31:26 -0800405 hash_unset_mem (app_main.app_by_name, app->name);
Dave Barach68b0fb02017-02-28 15:15:56 -0500406}
407
408application_t *
409application_lookup (u32 api_client_index)
410{
411 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700412 p = hash_get (app_main.app_by_api_client_index, api_client_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500413 if (p)
Florin Coras053a0e42018-11-13 15:52:38 -0800414 return application_get_if_valid (p[0]);
Dave Barach68b0fb02017-02-28 15:15:56 -0500415
416 return 0;
417}
418
Florin Coras6cf30ad2017-04-04 23:08:23 -0700419application_t *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700420application_lookup_name (const u8 * name)
421{
422 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700423 p = hash_get_mem (app_main.app_by_name, name);
Florin Coras0bee9ce2018-03-22 21:24:31 -0700424 if (p)
425 return application_get (p[0]);
426
427 return 0;
428}
429
Florin Corasc1a42652019-02-08 18:27:29 -0800430static application_t *
Florin Coras15531972018-08-12 23:50:53 -0700431application_alloc (void)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700432{
433 application_t *app;
Florin Coras15531972018-08-12 23:50:53 -0700434 pool_get (app_main.app_pool, app);
Dave Barachb7b92992018-10-17 10:38:51 -0400435 clib_memset (app, 0, sizeof (*app));
Florin Coras15531972018-08-12 23:50:53 -0700436 app->app_index = app - app_main.app_pool;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700437 return app;
438}
439
Florin Coras15531972018-08-12 23:50:53 -0700440application_t *
441application_get (u32 app_index)
Dave Barach68b0fb02017-02-28 15:15:56 -0500442{
Florin Coras15531972018-08-12 23:50:53 -0700443 if (app_index == APP_INVALID_INDEX)
444 return 0;
445 return pool_elt_at_index (app_main.app_pool, app_index);
446}
Dave Barach68b0fb02017-02-28 15:15:56 -0500447
Florin Coras15531972018-08-12 23:50:53 -0700448application_t *
449application_get_if_valid (u32 app_index)
450{
451 if (pool_is_free_index (app_main.app_pool, app_index))
452 return 0;
Florin Corasa5464812017-04-19 13:00:05 -0700453
Florin Coras15531972018-08-12 23:50:53 -0700454 return pool_elt_at_index (app_main.app_pool, app_index);
455}
Florin Coras7999e832017-10-31 01:51:04 -0700456
Florin Corasd79b41e2017-03-04 05:37:52 -0800457static void
Florin Coras6cf30ad2017-04-04 23:08:23 -0700458application_verify_cb_fns (session_cb_vft_t * cb_fns)
Florin Corasd79b41e2017-03-04 05:37:52 -0800459{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700460 if (cb_fns->session_accept_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800461 clib_warning ("No accept callback function provided");
Florin Coras6cf30ad2017-04-04 23:08:23 -0700462 if (cb_fns->session_connected_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800463 clib_warning ("No session connected callback function provided");
464 if (cb_fns->session_disconnect_callback == 0)
465 clib_warning ("No session disconnect callback function provided");
466 if (cb_fns->session_reset_callback == 0)
467 clib_warning ("No session reset callback function provided");
468}
469
Florin Corasb384b542018-01-15 01:08:33 -0800470/**
471 * Check app config for given segment type
472 *
473 * Returns 1 on success and 0 otherwise
474 */
475static u8
476application_verify_cfg (ssvm_segment_type_t st)
477{
478 u8 is_valid;
479 if (st == SSVM_SEGMENT_MEMFD)
480 {
481 is_valid = (session_manager_get_evt_q_segment () != 0);
482 if (!is_valid)
483 clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
484 return is_valid;
485 }
486 else if (st == SSVM_SEGMENT_SHM)
487 {
488 is_valid = (session_manager_get_evt_q_segment () == 0);
489 if (!is_valid)
490 clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
491 return is_valid;
492 }
493 else
494 return 1;
495}
496
Florin Corasc1a42652019-02-08 18:27:29 -0800497static int
Florin Coras15531972018-08-12 23:50:53 -0700498application_alloc_and_init (app_init_args_t * a)
Dave Barach68b0fb02017-02-28 15:15:56 -0500499{
Florin Corasa332c462018-01-31 06:52:17 -0800500 ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
Florin Corasb384b542018-01-15 01:08:33 -0800501 segment_manager_properties_t *props;
502 vl_api_registration_t *reg;
Florin Coras15531972018-08-12 23:50:53 -0700503 application_t *app;
504 u64 *options;
Dave Barach68b0fb02017-02-28 15:15:56 -0500505
Florin Coras15531972018-08-12 23:50:53 -0700506 app = application_alloc ();
507 options = a->options;
Florin Corasb384b542018-01-15 01:08:33 -0800508 /*
509 * Make sure we support the requested configuration
510 */
Florin Corasa332c462018-01-31 06:52:17 -0800511 if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
512 {
Florin Coras15531972018-08-12 23:50:53 -0700513 reg = vl_api_client_index_to_registration (a->api_client_index);
Florin Corasa332c462018-01-31 06:52:17 -0800514 if (!reg)
515 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
516 if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
517 seg_type = SSVM_SEGMENT_SHM;
518 }
519 else
520 {
Florin Coras99368312018-08-02 10:45:44 -0700521 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
522 {
523 clib_warning ("mq eventfds can only be used if socket transport is "
524 "used for api");
525 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
526 }
Florin Corasa332c462018-01-31 06:52:17 -0800527 seg_type = SSVM_SEGMENT_PRIVATE;
528 }
Florin Corasb384b542018-01-15 01:08:33 -0800529
Florin Corasa332c462018-01-31 06:52:17 -0800530 if (!application_verify_cfg (seg_type))
Florin Corasb384b542018-01-15 01:08:33 -0800531 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
Dave Barach68b0fb02017-02-28 15:15:56 -0500532
Florin Coras15531972018-08-12 23:50:53 -0700533 /* Check that the obvious things are properly set up */
534 application_verify_cb_fns (a->session_cb_vft);
535
Florin Coras15531972018-08-12 23:50:53 -0700536 app->flags = options[APP_OPTIONS_FLAGS];
537 app->cb_fns = *a->session_cb_vft;
538 app->ns_index = options[APP_OPTIONS_NAMESPACE];
539 app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
540 app->name = vec_dup (a->name);
541
542 /* If no scope enabled, default to global */
543 if (!application_has_global_scope (app)
544 && !application_has_local_scope (app))
545 app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
546
Florin Corasa332c462018-01-31 06:52:17 -0800547 props = application_segment_manager_properties (app);
548 segment_manager_properties_init (props);
Florin Coras15531972018-08-12 23:50:53 -0700549 props->segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
550 props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
Florin Corasb384b542018-01-15 01:08:33 -0800551 if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
552 {
553 props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
554 props->add_segment = 1;
555 }
556 if (options[APP_OPTIONS_RX_FIFO_SIZE])
557 props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
558 if (options[APP_OPTIONS_TX_FIFO_SIZE])
559 props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
Florin Corasf8f516a2018-02-08 15:10:09 -0800560 if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
561 props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
Florin Coras99368312018-08-02 10:45:44 -0700562 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
563 props->use_mq_eventfd = 1;
Florin Coras58d36f02018-03-09 13:05:53 -0800564 if (options[APP_OPTIONS_TLS_ENGINE])
565 app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
Florin Corasa332c462018-01-31 06:52:17 -0800566 props->segment_type = seg_type;
Dave Barach68b0fb02017-02-28 15:15:56 -0500567
Florin Coras15531972018-08-12 23:50:53 -0700568 /* Add app to lookup by api_client_index table */
Florin Corasc1f5a432018-11-20 11:31:26 -0800569 if (!application_is_builtin (app))
570 application_api_table_add (app->app_index, a->api_client_index);
571 else
572 application_name_table_add (app);
573
574 a->app_index = app->app_index;
Florin Corasa332c462018-01-31 06:52:17 -0800575
Florin Coras15531972018-08-12 23:50:53 -0700576 APP_DBG ("New app name: %v api index: %u index %u", app->name,
577 app->api_client_index, app->app_index);
578
579 return 0;
580}
581
Florin Corasc1a42652019-02-08 18:27:29 -0800582static void
Florin Coras15531972018-08-12 23:50:53 -0700583application_free (application_t * app)
584{
585 app_worker_map_t *wrk_map;
586 app_worker_t *app_wrk;
Florin Corasab2f6db2018-08-31 14:31:41 -0700587 u32 table_index;
588 local_session_t *ll;
589 session_endpoint_t sep;
Florin Coras15531972018-08-12 23:50:53 -0700590
591 /*
592 * The app event queue allocated in first segment is cleared with
593 * the segment manager. No need to explicitly free it.
594 */
595 APP_DBG ("Delete app name %v api index: %d index: %d", app->name,
596 app->api_client_index, app->app_index);
597
598 if (application_is_proxy (app))
599 application_remove_proxy (app);
600
Florin Corasab2f6db2018-08-31 14:31:41 -0700601 /*
602 * Free workers
603 */
604
Florin Coras15531972018-08-12 23:50:53 -0700605 /* *INDENT-OFF* */
606 pool_flush (wrk_map, app->worker_maps, ({
607 app_wrk = app_worker_get (wrk_map->wrk_index);
608 app_worker_free (app_wrk);
609 }));
610 /* *INDENT-ON* */
611 pool_free (app->worker_maps);
612
Florin Corasab2f6db2018-08-31 14:31:41 -0700613 /*
614 * Free local listeners. Global table unbinds stop local listeners
615 * as well, but if we have only local binds, these won't be cleaned up.
616 * Don't bother with local accepted sessions, we clean them when
617 * cleaning up the worker.
618 */
619 table_index = application_local_session_table (app);
620 /* *INDENT-OFF* */
621 pool_foreach (ll, app->local_listen_sessions, ({
622 application_local_listener_session_endpoint (ll, &sep);
623 session_lookup_del_session_endpoint (table_index, &sep);
624 }));
625 /* *INDENT-ON* */
626 pool_free (app->local_listen_sessions);
627
628 /*
629 * Cleanup remaining state
630 */
Florin Corasc1f5a432018-11-20 11:31:26 -0800631 if (application_is_builtin (app))
632 application_name_table_del (app);
Florin Coras15531972018-08-12 23:50:53 -0700633 vec_free (app->name);
634 vec_free (app->tls_cert);
635 vec_free (app->tls_key);
636 pool_put (app_main.app_pool, app);
637}
638
Florin Corasc1a42652019-02-08 18:27:29 -0800639static void
Florin Coras053a0e42018-11-13 15:52:38 -0800640application_detach_process (application_t * app, u32 api_client_index)
641{
642 vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
643 app_worker_map_t *wrk_map;
644 u32 *wrks = 0, *wrk_index;
645 app_worker_t *app_wrk;
646
647 if (api_client_index == ~0)
648 {
649 application_free (app);
650 return;
651 }
652
653 APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
654 app->app_index, app->api_client_index);
655
656 /* *INDENT-OFF* */
657 pool_foreach (wrk_map, app->worker_maps, ({
658 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Corasc1f5a432018-11-20 11:31:26 -0800659 if (app_wrk->api_client_index == api_client_index)
Florin Coras053a0e42018-11-13 15:52:38 -0800660 vec_add1 (wrks, app_wrk->wrk_index);
661 }));
662 /* *INDENT-ON* */
663
664 if (!vec_len (wrks))
665 {
666 clib_warning ("no workers for app %u api_index %u", app->app_index,
667 api_client_index);
668 return;
669 }
670
671 args->app_index = app->app_index;
Florin Corasc1f5a432018-11-20 11:31:26 -0800672 args->api_client_index = api_client_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800673 vec_foreach (wrk_index, wrks)
674 {
675 app_wrk = app_worker_get (wrk_index[0]);
Florin Coras349f8ca2018-11-20 16:52:49 -0800676 args->wrk_map_index = app_wrk->wrk_map_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800677 args->is_add = 0;
678 vnet_app_worker_add_del (args);
679 }
680 vec_free (wrks);
681}
682
Florin Coras15531972018-08-12 23:50:53 -0700683app_worker_t *
684application_get_worker (application_t * app, u32 wrk_map_index)
685{
686 app_worker_map_t *map;
687 map = app_worker_map_get (app, wrk_map_index);
688 if (!map)
689 return 0;
690 return app_worker_get (map->wrk_index);
691}
692
693app_worker_t *
694application_get_default_worker (application_t * app)
695{
696 return application_get_worker (app, 0);
697}
698
Florin Coras053a0e42018-11-13 15:52:38 -0800699u32
700application_n_workers (application_t * app)
701{
702 return pool_elts (app->worker_maps);
703}
704
Florin Coras15531972018-08-12 23:50:53 -0700705app_worker_t *
Florin Corasc9940fc2019-02-05 20:55:11 -0800706application_listener_select_worker (session_t * ls)
Florin Corasab2f6db2018-08-31 14:31:41 -0700707{
Florin Corasc9940fc2019-02-05 20:55:11 -0800708 app_listener_t *al;
Florin Corasab2f6db2018-08-31 14:31:41 -0700709
Florin Corasc9940fc2019-02-05 20:55:11 -0800710 al = app_listener_get_w_session (ls);
711 return app_listener_select_worker (al);
Florin Corasab2f6db2018-08-31 14:31:41 -0700712}
713
Florin Coras15531972018-08-12 23:50:53 -0700714int
Florin Coras623eb562019-02-03 19:28:34 -0800715application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
Florin Coras15531972018-08-12 23:50:53 -0700716{
717 app_worker_map_t *wrk_map;
718 app_worker_t *app_wrk;
719 segment_manager_t *sm;
720 int rv;
721
722 app_wrk = app_worker_alloc (app);
723 wrk_map = app_worker_map_alloc (app);
724 wrk_map->wrk_index = app_wrk->wrk_index;
725 app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
726
727 /*
728 * Setup first segment manager
729 */
730 sm = segment_manager_new ();
731 sm->app_wrk_index = app_wrk->wrk_index;
732
733 if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
734 app->sm_properties.prealloc_fifos)))
735 {
736 app_worker_free (app_wrk);
737 return rv;
738 }
Florin Corasc87c91d2017-08-16 19:55:49 -0700739 sm->first_is_protected = 1;
Dave Barach68b0fb02017-02-28 15:15:56 -0500740
Florin Corascea194d2017-10-02 00:18:51 -0700741 /*
Florin Coras15531972018-08-12 23:50:53 -0700742 * Setup app worker
Florin Corascea194d2017-10-02 00:18:51 -0700743 */
Florin Coras15531972018-08-12 23:50:53 -0700744 app_wrk->first_segment_manager = segment_manager_index (sm);
745 app_wrk->listeners_table = hash_create (0, sizeof (u64));
746 app_wrk->event_queue = segment_manager_event_queue (sm);
747 app_wrk->app_is_builtin = application_is_builtin (app);
Dave Barach68b0fb02017-02-28 15:15:56 -0500748
Florin Corasf8f516a2018-02-08 15:10:09 -0800749 /*
750 * Segment manager for local sessions
751 */
752 sm = segment_manager_new ();
Florin Coras15531972018-08-12 23:50:53 -0700753 sm->app_wrk_index = app_wrk->wrk_index;
754 app_wrk->local_segment_manager = segment_manager_index (sm);
755 app_wrk->local_connects = hash_create (0, sizeof (u64));
756
757 *wrk = app_wrk;
Florin Corasf8f516a2018-02-08 15:10:09 -0800758
Florin Coras6cf30ad2017-04-04 23:08:23 -0700759 return 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500760}
761
Florin Coras623eb562019-02-03 19:28:34 -0800762int
Florin Corasc1a42652019-02-08 18:27:29 -0800763vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
764{
765 svm_fifo_segment_private_t *fs;
766 app_worker_map_t *wrk_map;
767 app_worker_t *app_wrk;
768 segment_manager_t *sm;
769 application_t *app;
770 int rv;
771
772 app = application_get (a->app_index);
773 if (!app)
774 return VNET_API_ERROR_INVALID_VALUE;
775
776 if (a->is_add)
777 {
778 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
779 return rv;
780
781 /* Map worker api index to the app */
782 app_wrk->api_client_index = a->api_client_index;
783 application_api_table_add (app->app_index, a->api_client_index);
784
785 sm = segment_manager_get (app_wrk->first_segment_manager);
786 fs = segment_manager_get_segment_w_lock (sm, 0);
787 a->segment = &fs->ssvm;
788 a->segment_handle = segment_manager_segment_handle (sm, fs);
789 segment_manager_segment_reader_unlock (sm);
790 a->evt_q = app_wrk->event_queue;
791 a->wrk_map_index = app_wrk->wrk_map_index;
792 }
793 else
794 {
795 wrk_map = app_worker_map_get (app, a->wrk_map_index);
796 if (!wrk_map)
797 return VNET_API_ERROR_INVALID_VALUE;
798
799 app_wrk = app_worker_get (wrk_map->wrk_index);
800 if (!app_wrk)
801 return VNET_API_ERROR_INVALID_VALUE;
802
803 application_api_table_del (app_wrk->api_client_index);
804 app_worker_free (app_wrk);
805 app_worker_map_free (app, wrk_map);
806 if (application_n_workers (app) == 0)
807 application_free (app);
808 }
809 return 0;
810}
811
812static int
813app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
814{
815 app_namespace_t *app_ns;
816 if (vec_len (namespace_id) == 0)
817 {
818 /* Use default namespace */
819 *app_ns_index = 0;
820 return 0;
821 }
822
823 *app_ns_index = app_namespace_index_from_id (namespace_id);
824 if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
825 return VNET_API_ERROR_APP_INVALID_NS;
826 app_ns = app_namespace_get (*app_ns_index);
827 if (!app_ns)
828 return VNET_API_ERROR_APP_INVALID_NS;
829 if (app_ns->ns_secret != secret)
830 return VNET_API_ERROR_APP_WRONG_NS_SECRET;
831 return 0;
832}
833
834static u8 *
835app_name_from_api_index (u32 api_client_index)
836{
837 vl_api_registration_t *regp;
838 regp = vl_api_client_index_to_registration (api_client_index);
839 if (regp)
840 return format (0, "%s%c", regp->name, 0);
841
842 clib_warning ("api client index %u does not have an api registration!",
843 api_client_index);
844 return format (0, "unknown%c", 0);
845}
846
847/**
848 * Attach application to vpp
849 *
850 * Allocates a vpp app, i.e., a structure that keeps back pointers
851 * to external app and a segment manager for shared memory fifo based
852 * communication with the external app.
853 */
854int
855vnet_application_attach (vnet_app_attach_args_t * a)
856{
857 svm_fifo_segment_private_t *fs;
858 application_t *app = 0;
859 app_worker_t *app_wrk;
860 segment_manager_t *sm;
861 u32 app_ns_index = 0;
862 u8 *app_name = 0;
863 u64 secret;
864 int rv;
865
866 if (a->api_client_index != APP_INVALID_INDEX)
867 app = application_lookup (a->api_client_index);
868 else if (a->name)
869 app = application_lookup_name (a->name);
870 else
871 return VNET_API_ERROR_INVALID_VALUE;
872
873 if (app)
874 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
875
876 if (a->api_client_index != APP_INVALID_INDEX)
877 {
878 app_name = app_name_from_api_index (a->api_client_index);
879 a->name = app_name;
880 }
881
882 secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
883 if ((rv = app_validate_namespace (a->namespace_id, secret, &app_ns_index)))
884 return rv;
885 a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
886
887 if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
888 return rv;
889
890 app = application_get (a->app_index);
891 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
892 return rv;
893
894 a->app_evt_q = app_wrk->event_queue;
895 app_wrk->api_client_index = a->api_client_index;
896 sm = segment_manager_get (app_wrk->first_segment_manager);
897 fs = segment_manager_get_segment_w_lock (sm, 0);
898
899 if (application_is_proxy (app))
900 application_setup_proxy (app);
901
902 ASSERT (vec_len (fs->ssvm.name) <= 128);
903 a->segment = &fs->ssvm;
904 a->segment_handle = segment_manager_segment_handle (sm, fs);
905
906 segment_manager_segment_reader_unlock (sm);
907 vec_free (app_name);
908 return 0;
909}
910
911/**
912 * Detach application from vpp
913 */
914int
915vnet_application_detach (vnet_app_detach_args_t * a)
916{
917 application_t *app;
918
919 app = application_get_if_valid (a->app_index);
920 if (!app)
921 {
922 clib_warning ("app not attached");
923 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
924 }
925
926 app_interface_check_thread_and_barrier (vnet_application_detach, a);
927 application_detach_process (app, a->api_client_index);
928 return 0;
929}
930
931
932static u8
933session_endpoint_in_ns (session_endpoint_t * sep)
934{
935 u8 is_lep = session_endpoint_is_local (sep);
936 if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
937 && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
938 {
939 clib_warning ("sw_if_index %u not configured with ip %U",
940 sep->sw_if_index, format_ip46_address, &sep->ip,
941 sep->is_ip4);
942 return 0;
943 }
944 return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
945}
946
947static void
948session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
949 application_t * app, u8 is_connect)
950{
951 app_namespace_t *app_ns;
952 u32 ns_index, fib_index;
953
954 ns_index = app->ns_index;
955
956 /* App is a transport proto, so fetch the calling app's ns */
957 if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
Florin Coras8a140612019-02-18 22:39:39 -0800958 ns_index = sep->ns_index;
Florin Corasc1a42652019-02-08 18:27:29 -0800959
Florin Corasc1a42652019-02-08 18:27:29 -0800960 app_ns = app_namespace_get (ns_index);
961 if (!app_ns)
962 return;
963
964 /* Ask transport and network to bind to/connect using local interface
965 * that "supports" app's namespace. This will fix our local connection
966 * endpoint.
967 */
968
969 /* If in default namespace and user requested a fib index use it */
970 if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
971 fib_index = sep->fib_index;
972 else
973 fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
974 sep->peer.fib_index = fib_index;
975 sep->fib_index = fib_index;
976
977 if (!is_connect)
978 {
979 sep->sw_if_index = app_ns->sw_if_index;
980 }
981 else
982 {
983 if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
984 && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
985 && sep->peer.sw_if_index != app_ns->sw_if_index)
986 clib_warning ("Local sw_if_index different from app ns sw_if_index");
987
988 sep->peer.sw_if_index = app_ns->sw_if_index;
989 }
990}
991
992int
993vnet_listen (vnet_listen_args_t * a)
994{
995 app_listener_t *app_listener;
996 app_worker_t *app_wrk;
997 application_t *app;
998 int rv;
999
1000 app = application_get_if_valid (a->app_index);
1001 if (!app)
1002 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1003
1004 app_wrk = application_get_worker (app, a->wrk_map_index);
1005 if (!app_wrk)
1006 return VNET_API_ERROR_INVALID_VALUE;
1007
1008 a->sep_ext.app_wrk_index = app_wrk->wrk_index;
1009
1010 session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
1011 if (!session_endpoint_in_ns (&a->sep))
1012 return VNET_API_ERROR_INVALID_VALUE_2;
1013
1014 /*
1015 * Check if we already have an app listener
1016 */
1017 app_listener = app_listener_lookup (app, &a->sep_ext);
1018 if (app_listener)
1019 {
1020 if (app_listener->app_index != app->app_index)
1021 return VNET_API_ERROR_ADDRESS_IN_USE;
1022 if (app_worker_start_listen (app_wrk, app_listener))
1023 return -1;
1024 a->handle = app_listener_handle (app_listener);
1025 return 0;
1026 }
1027
1028 /*
1029 * Create new app listener
1030 */
1031 if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1032 return rv;
1033
1034 if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1035 {
1036 app_listener_cleanup (app_listener);
1037 return rv;
1038 }
1039
1040 a->handle = app_listener_handle (app_listener);
1041 return 0;
1042}
1043
1044int
1045vnet_connect (vnet_connect_args_t * a)
1046{
1047 app_worker_t *server_wrk, *client_wrk;
1048 application_t *client;
1049 local_session_t *ll;
1050 app_listener_t *al;
1051 u32 table_index;
1052 session_t *ls;
1053 u8 fib_proto;
1054 u64 lh;
1055
1056 if (session_endpoint_is_zero (&a->sep))
1057 return VNET_API_ERROR_INVALID_VALUE;
1058
1059 client = application_get (a->app_index);
1060 session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1061 client_wrk = application_get_worker (client, a->wrk_map_index);
1062
1063 /*
1064 * First check the local scope for locally attached destinations.
1065 * If we have local scope, we pass *all* connects through it since we may
1066 * have special policy rules even for non-local destinations, think proxy.
1067 */
1068 if (application_has_local_scope (client))
1069 {
1070 table_index = application_local_session_table (client);
1071 lh = session_lookup_local_endpoint (table_index, &a->sep);
1072 if (lh == SESSION_DROP_HANDLE)
1073 return VNET_API_ERROR_APP_CONNECT_FILTERED;
1074
1075 if (lh == SESSION_INVALID_HANDLE)
1076 goto global_scope;
1077
1078 ll = application_get_local_listener_w_handle (lh);
1079 al = app_listener_get_w_session ((session_t *) ll);
1080
1081 /*
1082 * Break loop if rule in local table points to connecting app. This
1083 * can happen if client is a generic proxy. Route connect through
1084 * global table instead.
1085 */
1086 if (al->app_index == a->app_index)
1087 goto global_scope;
1088
1089 server_wrk = app_listener_select_worker (al);
1090 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1091 a->api_context);
1092 }
1093
1094 /*
1095 * If nothing found, check the global scope for locally attached
1096 * destinations. Make sure first that we're allowed to.
1097 */
1098
1099global_scope:
1100 if (session_endpoint_is_local (&a->sep))
1101 return VNET_API_ERROR_SESSION_CONNECT;
1102
1103 if (!application_has_global_scope (client))
1104 return VNET_API_ERROR_APP_CONNECT_SCOPE;
1105
1106 fib_proto = session_endpoint_fib_proto (&a->sep);
1107 table_index = application_session_table (client, fib_proto);
1108 ls = session_lookup_listener (table_index, &a->sep);
1109 if (ls)
1110 {
1111 al = app_listener_get_w_session (ls);
1112 server_wrk = app_listener_select_worker (al);
1113 ll = (local_session_t *) ls;
1114 return app_worker_local_session_connect (client_wrk, server_wrk, ll,
1115 a->api_context);
1116 }
1117
1118 /*
1119 * Not connecting to a local server, propagate to transport
1120 */
1121 if (app_worker_connect_session (client_wrk, &a->sep, a->api_context))
1122 return VNET_API_ERROR_SESSION_CONNECT;
1123 return 0;
1124}
1125
1126int
1127vnet_unlisten (vnet_unlisten_args_t * a)
1128{
1129 app_worker_t *app_wrk;
1130 app_listener_t *al;
1131 application_t *app;
1132
1133 if (!(app = application_get_if_valid (a->app_index)))
1134 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1135
1136 al = app_listener_get_w_handle (a->handle);
1137 if (al->app_index != app->app_index)
1138 {
1139 clib_warning ("app doesn't own handle %llu!", a->handle);
1140 return -1;
1141 }
1142
1143 app_wrk = application_get_worker (app, a->wrk_map_index);
1144 if (!app_wrk)
1145 {
1146 clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1147 return -1;
1148 }
1149
1150 return app_worker_stop_listen (app_wrk, al);
1151}
1152
1153int
1154vnet_disconnect_session (vnet_disconnect_args_t * a)
1155{
1156 if (session_handle_is_local (a->handle))
1157 {
1158 local_session_t *ls;
1159
1160 /* Disconnect reply came to worker 1 not main thread */
1161 app_interface_check_thread_and_barrier (vnet_disconnect_session, a);
1162
1163 if (!(ls = app_worker_get_local_session_from_handle (a->handle)))
1164 return 0;
1165
1166 return app_worker_local_session_disconnect (a->app_index, ls);
1167 }
1168 else
1169 {
1170 app_worker_t *app_wrk;
1171 session_t *s;
1172
1173 s = session_get_from_handle_if_valid (a->handle);
1174 if (!s)
1175 return VNET_API_ERROR_INVALID_VALUE;
1176 app_wrk = app_worker_get (s->app_wrk_index);
1177 if (app_wrk->app_index != a->app_index)
1178 return VNET_API_ERROR_INVALID_VALUE;
1179
1180 /* We're peeking into another's thread pool. Make sure */
1181 ASSERT (s->session_index == session_index_from_handle (a->handle));
1182
1183 session_close (s);
1184 }
1185 return 0;
1186}
1187
1188int
Florin Coras623eb562019-02-03 19:28:34 -08001189application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1190{
1191 app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1192 app_listener_t *app_listener;
1193 application_t *app;
1194
1195 if (!old_wrk)
1196 return -1;
1197
1198 hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1199 if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1200 && s->rx_fifo)
1201 segment_manager_dealloc_fifos (s->rx_fifo->segment_index, s->rx_fifo,
1202 s->tx_fifo);
1203
Florin Coras623eb562019-02-03 19:28:34 -08001204 app = application_get (old_wrk->app_index);
1205 if (!app)
1206 return -1;
1207
Florin Corasc9940fc2019-02-05 20:55:11 -08001208 app_listener = app_listener_get (app, s->al_index);
1209
1210 /* Only remove from lb for now */
Florin Coras623eb562019-02-03 19:28:34 -08001211 app_listener->workers = clib_bitmap_set (app_listener->workers,
1212 old_wrk->wrk_map_index, 0);
Florin Coras623eb562019-02-03 19:28:34 -08001213
Florin Corasc9940fc2019-02-05 20:55:11 -08001214 if (app_worker_start_listen (app_wrk, app_listener))
1215 return -1;
Florin Corasab2f6db2018-08-31 14:31:41 -07001216
Florin Corasc9940fc2019-02-05 20:55:11 -08001217 s->app_wrk_index = app_wrk->wrk_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001218
Dave Barach68b0fb02017-02-28 15:15:56 -05001219 return 0;
1220}
1221
Dave Barach52851e62017-08-07 09:35:25 -04001222int
1223application_is_proxy (application_t * app)
1224{
Florin Coras7999e832017-10-31 01:51:04 -07001225 return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1226}
1227
1228int
1229application_is_builtin (application_t * app)
1230{
1231 return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1232}
1233
1234int
1235application_is_builtin_proxy (application_t * app)
1236{
1237 return (application_is_proxy (app) && application_is_builtin (app));
Dave Barach52851e62017-08-07 09:35:25 -04001238}
1239
Florin Corascea194d2017-10-02 00:18:51 -07001240u8
1241application_has_local_scope (application_t * app)
1242{
1243 return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1244}
1245
1246u8
1247application_has_global_scope (application_t * app)
1248{
1249 return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1250}
1251
Florin Coras60116992018-08-27 09:52:18 -07001252u8
1253application_use_mq_for_ctrl (application_t * app)
1254{
1255 return app->flags & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
1256}
1257
Florin Coras7999e832017-10-31 01:51:04 -07001258static clib_error_t *
1259application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1260 u8 transport_proto, u8 is_start)
1261{
Florin Coras7999e832017-10-31 01:51:04 -07001262 app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1263 u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
Florin Coras5665ced2018-10-25 18:03:45 -07001264 session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
Florin Coras7999e832017-10-31 01:51:04 -07001265 transport_connection_t *tc;
Florin Coras15531972018-08-12 23:50:53 -07001266 app_worker_t *app_wrk;
Florin Corasc9940fc2019-02-05 20:55:11 -08001267 app_listener_t *al;
Florin Coras288eaab2019-02-03 15:26:14 -08001268 session_t *s;
Florin Corasc9940fc2019-02-05 20:55:11 -08001269 u32 flags;
Florin Coras7999e832017-10-31 01:51:04 -07001270
Florin Coras15531972018-08-12 23:50:53 -07001271 /* TODO decide if we want proxy to be enabled for all workers */
1272 app_wrk = application_get_default_worker (app);
Florin Coras7999e832017-10-31 01:51:04 -07001273 if (is_start)
1274 {
Florin Coras15531972018-08-12 23:50:53 -07001275 s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001276 if (!s)
1277 {
1278 sep.is_ip4 = is_ip4;
1279 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1280 sep.sw_if_index = app_ns->sw_if_index;
1281 sep.transport_proto = transport_proto;
Florin Corasab2f6db2018-08-31 14:31:41 -07001282 sep.app_wrk_index = app_wrk->wrk_index; /* only default */
Florin Corasc9940fc2019-02-05 20:55:11 -08001283
1284 /* force global scope listener */
1285 flags = app->flags;
1286 app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1287 app_listener_alloc_and_init (app, &sep, &al);
1288 app->flags = flags;
1289
1290 app_worker_start_listen (app_wrk, al);
1291 s = listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -07001292 s->enqueue_epoch = SESSION_PROXY_LISTENER_INDEX;
Florin Coras19b1f6a2017-12-11 03:37:03 -08001293 }
Florin Coras7999e832017-10-31 01:51:04 -07001294 }
1295 else
1296 {
Florin Coras623eb562019-02-03 19:28:34 -08001297 s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001298 ASSERT (s);
Florin Coras7999e832017-10-31 01:51:04 -07001299 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001300
Florin Coras7999e832017-10-31 01:51:04 -07001301 tc = listen_session_get_transport (s);
1302
1303 if (!ip_is_zero (&tc->lcl_ip, 1))
1304 {
Florin Corasdbd44562017-11-09 19:30:17 -08001305 u32 sti;
1306 sep.is_ip4 = is_ip4;
1307 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1308 sep.transport_proto = transport_proto;
1309 sep.port = 0;
1310 sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001311 if (is_start)
Florin Corasab2f6db2018-08-31 14:31:41 -07001312 session_lookup_add_session_endpoint (sti,
1313 (session_endpoint_t *) & sep,
1314 s->session_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001315 else
Florin Corasab2f6db2018-08-31 14:31:41 -07001316 session_lookup_del_session_endpoint (sti,
1317 (session_endpoint_t *) & sep);
Florin Coras7999e832017-10-31 01:51:04 -07001318 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001319
Florin Coras7999e832017-10-31 01:51:04 -07001320 return 0;
1321}
1322
Florin Coras19b1f6a2017-12-11 03:37:03 -08001323static void
1324application_start_stop_proxy_local_scope (application_t * app,
1325 u8 transport_proto, u8 is_start)
1326{
1327 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1328 app_namespace_t *app_ns;
1329 app_ns = app_namespace_get (app->ns_index);
1330 sep.is_ip4 = 1;
1331 sep.transport_proto = transport_proto;
1332 sep.port = 0;
1333
1334 if (is_start)
1335 {
1336 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001337 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001338 sep.is_ip4 = 0;
1339 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001340 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001341 }
1342 else
1343 {
1344 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1345 sep.is_ip4 = 0;
1346 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1347 }
1348}
1349
Florin Coras7999e832017-10-31 01:51:04 -07001350void
Florin Coras561af9b2017-12-09 10:19:43 -08001351application_start_stop_proxy (application_t * app,
1352 transport_proto_t transport_proto, u8 is_start)
Florin Coras7999e832017-10-31 01:51:04 -07001353{
Florin Coras7999e832017-10-31 01:51:04 -07001354 if (application_has_local_scope (app))
Florin Coras19b1f6a2017-12-11 03:37:03 -08001355 application_start_stop_proxy_local_scope (app, transport_proto, is_start);
Florin Coras7999e832017-10-31 01:51:04 -07001356
1357 if (application_has_global_scope (app))
1358 {
1359 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1360 transport_proto, is_start);
1361 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1362 transport_proto, is_start);
1363 }
1364}
1365
1366void
1367application_setup_proxy (application_t * app)
1368{
1369 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001370 transport_proto_t tp;
1371
Florin Coras7999e832017-10-31 01:51:04 -07001372 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001373
1374 /* *INDENT-OFF* */
1375 transport_proto_foreach (tp, ({
1376 if (transports & (1 << tp))
1377 application_start_stop_proxy (app, tp, 1);
1378 }));
1379 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001380}
1381
1382void
1383application_remove_proxy (application_t * app)
1384{
1385 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001386 transport_proto_t tp;
1387
Florin Coras7999e832017-10-31 01:51:04 -07001388 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001389
1390 /* *INDENT-OFF* */
1391 transport_proto_foreach (tp, ({
1392 if (transports & (1 << tp))
1393 application_start_stop_proxy (app, tp, 0);
1394 }));
1395 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001396}
1397
Florin Corasa332c462018-01-31 06:52:17 -08001398segment_manager_properties_t *
1399application_segment_manager_properties (application_t * app)
1400{
1401 return &app->sm_properties;
1402}
1403
1404segment_manager_properties_t *
1405application_get_segment_manager_properties (u32 app_index)
1406{
1407 application_t *app = application_get (app_index);
1408 return &app->sm_properties;
1409}
1410
Florin Coras371ca502018-02-21 12:07:41 -08001411clib_error_t *
1412vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1413{
1414 application_t *app;
1415 app = application_get (a->app_index);
1416 if (!app)
1417 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1418 0, "app %u doesn't exist", a->app_index);
1419 app->tls_cert = vec_dup (a->cert);
1420 return 0;
1421}
1422
1423clib_error_t *
1424vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1425{
1426 application_t *app;
1427 app = application_get (a->app_index);
1428 if (!app)
1429 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1430 0, "app %u doesn't exist", a->app_index);
1431 app->tls_key = vec_dup (a->key);
1432 return 0;
1433}
1434
Florin Coras15531972018-08-12 23:50:53 -07001435static void
1436application_format_listeners (application_t * app, int verbose)
1437{
1438 vlib_main_t *vm = vlib_get_main ();
1439 app_worker_map_t *wrk_map;
1440 app_worker_t *app_wrk;
1441 u32 sm_index;
1442 u64 handle;
1443
1444 if (!app)
1445 {
1446 vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1447 0, 0, verbose);
1448 return;
1449 }
1450
1451 /* *INDENT-OFF* */
1452 pool_foreach (wrk_map, app->worker_maps, ({
1453 app_wrk = app_worker_get (wrk_map->wrk_index);
1454 if (hash_elts (app_wrk->listeners_table) == 0)
1455 continue;
1456 hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1457 vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1458 handle, sm_index, verbose);
1459 }));
1460 }));
1461 /* *INDENT-ON* */
1462}
1463
1464static void
Florin Coras15531972018-08-12 23:50:53 -07001465application_format_connects (application_t * app, int verbose)
1466{
1467 app_worker_map_t *wrk_map;
1468 app_worker_t *app_wrk;
1469
1470 if (!app)
1471 {
1472 app_worker_format_connects (0, verbose);
1473 return;
1474 }
1475
1476 /* *INDENT-OFF* */
1477 pool_foreach (wrk_map, app->worker_maps, ({
1478 app_wrk = app_worker_get (wrk_map->wrk_index);
1479 app_worker_format_connects (app_wrk, verbose);
1480 }));
1481 /* *INDENT-ON* */
1482}
1483
1484static void
Florin Coras15531972018-08-12 23:50:53 -07001485application_format_local_sessions (application_t * app, int verbose)
1486{
Florin Corasab2f6db2018-08-31 14:31:41 -07001487 vlib_main_t *vm = vlib_get_main ();
Florin Coras15531972018-08-12 23:50:53 -07001488 app_worker_map_t *wrk_map;
1489 app_worker_t *app_wrk;
Florin Corasab2f6db2018-08-31 14:31:41 -07001490 transport_proto_t tp;
1491 local_session_t *ls;
1492 u8 *conn = 0;
Florin Coras15531972018-08-12 23:50:53 -07001493
1494 if (!app)
1495 {
1496 app_worker_format_local_sessions (0, verbose);
1497 return;
1498 }
1499
Florin Corasab2f6db2018-08-31 14:31:41 -07001500 /*
1501 * Format local listeners
1502 */
1503
1504 /* *INDENT-OFF* */
1505 pool_foreach (ls, app->local_listen_sessions, ({
1506 tp = session_type_transport_proto (ls->listener_session_type);
1507 conn = format (0, "[L][%U] *:%u", format_transport_proto_short, tp,
1508 ls->port);
1509 vlib_cli_output (vm, "%-40v%-15u%-20s", conn, ls->app_wrk_index, "*");
1510 vec_reset_length (conn);
1511 }));
1512 /* *INDENT-ON* */
1513
1514 /*
1515 * Format local accepted/connected sessions
1516 */
Florin Coras15531972018-08-12 23:50:53 -07001517 /* *INDENT-OFF* */
1518 pool_foreach (wrk_map, app->worker_maps, ({
1519 app_wrk = app_worker_get (wrk_map->wrk_index);
1520 app_worker_format_local_sessions (app_wrk, verbose);
1521 }));
1522 /* *INDENT-ON* */
1523}
1524
1525static void
Florin Coras15531972018-08-12 23:50:53 -07001526application_format_local_connects (application_t * app, int verbose)
1527{
1528 app_worker_map_t *wrk_map;
1529 app_worker_t *app_wrk;
1530
1531 if (!app)
1532 {
1533 app_worker_format_local_connects (0, verbose);
1534 return;
1535 }
1536
1537 /* *INDENT-OFF* */
1538 pool_foreach (wrk_map, app->worker_maps, ({
1539 app_wrk = app_worker_get (wrk_map->wrk_index);
1540 app_worker_format_local_connects (app_wrk, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001541 }));
1542 /* *INDENT-ON* */
1543}
1544
Florin Coras6cf30ad2017-04-04 23:08:23 -07001545u8 *
1546format_application (u8 * s, va_list * args)
1547{
1548 application_t *app = va_arg (*args, application_t *);
1549 CLIB_UNUSED (int verbose) = va_arg (*args, int);
Florin Corasad0c77f2017-11-09 18:00:15 -08001550 segment_manager_properties_t *props;
Florin Coras053a0e42018-11-13 15:52:38 -08001551 const u8 *app_ns_name, *app_name;
Florin Coras349f8ca2018-11-20 16:52:49 -08001552 app_worker_map_t *wrk_map;
1553 app_worker_t *app_wrk;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001554
1555 if (app == 0)
1556 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001557 if (!verbose)
Florin Corasc1f5a432018-11-20 11:31:26 -08001558 s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
Florin Coras6cf30ad2017-04-04 23:08:23 -07001559 return s;
1560 }
1561
Florin Coras0bee9ce2018-03-22 21:24:31 -07001562 app_name = app_get_name (app);
Florin Corascea194d2017-10-02 00:18:51 -07001563 app_ns_name = app_namespace_id_from_index (app->ns_index);
Florin Corasa332c462018-01-31 06:52:17 -08001564 props = application_segment_manager_properties (app);
Florin Coras349f8ca2018-11-20 16:52:49 -08001565 if (!verbose)
1566 {
1567 s = format (s, "%-10u%-20s%-40s", app->app_index, app_name,
1568 app_ns_name);
1569 return s;
1570 }
1571
1572 s = format (s, "app-name %s app-index %u ns-index %u seg-size %U\n",
1573 app_name, app->app_index, app->ns_index,
1574 format_memory_size, props->add_segment_size);
1575 s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1576 format_memory_size, props->rx_fifo_size,
1577 format_memory_size, props->tx_fifo_size);
1578
1579 /* *INDENT-OFF* */
1580 pool_foreach (wrk_map, app->worker_maps, ({
1581 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Coras623eb562019-02-03 19:28:34 -08001582 s = format (s, "%U", format_app_worker, app_wrk);
Florin Coras349f8ca2018-11-20 16:52:49 -08001583 }));
1584 /* *INDENT-ON* */
1585
Dave Barach68b0fb02017-02-28 15:15:56 -05001586 return s;
1587}
1588
Florin Corasf8f516a2018-02-08 15:10:09 -08001589void
1590application_format_all_listeners (vlib_main_t * vm, int do_local, int verbose)
1591{
1592 application_t *app;
Florin Corasf8f516a2018-02-08 15:10:09 -08001593
Florin Coras15531972018-08-12 23:50:53 -07001594 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001595 {
1596 vlib_cli_output (vm, "No active server bindings");
1597 return;
1598 }
1599
1600 if (do_local)
1601 {
1602 application_format_local_sessions (0, verbose);
1603 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001604 pool_foreach (app, app_main.app_pool, ({
Florin Corasf8f516a2018-02-08 15:10:09 -08001605 application_format_local_sessions (app, verbose);
1606 }));
1607 /* *INDENT-ON* */
1608 }
1609 else
1610 {
Florin Coras15531972018-08-12 23:50:53 -07001611 application_format_listeners (0, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001612
1613 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001614 pool_foreach (app, app_main.app_pool, ({
1615 application_format_listeners (app, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001616 }));
1617 /* *INDENT-ON* */
1618 }
1619}
1620
1621void
1622application_format_all_clients (vlib_main_t * vm, int do_local, int verbose)
1623{
1624 application_t *app;
1625
Florin Coras15531972018-08-12 23:50:53 -07001626 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001627 {
1628 vlib_cli_output (vm, "No active apps");
1629 return;
1630 }
1631
1632 if (do_local)
1633 {
1634 application_format_local_connects (0, verbose);
1635
1636 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001637 pool_foreach (app, app_main.app_pool, ({
1638 application_format_local_connects (app, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001639 }));
1640 /* *INDENT-ON* */
1641 }
1642 else
1643 {
1644 application_format_connects (0, verbose);
1645
1646 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001647 pool_foreach (app, app_main.app_pool, ({
Florin Corasf8f516a2018-02-08 15:10:09 -08001648 application_format_connects (app, verbose);
1649 }));
1650 /* *INDENT-ON* */
1651 }
1652}
1653
Dave Barach68b0fb02017-02-28 15:15:56 -05001654static clib_error_t *
1655show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1656 vlib_cli_command_t * cmd)
1657{
Florin Corasf8f516a2018-02-08 15:10:09 -08001658 int do_server = 0, do_client = 0, do_local = 0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001659 application_t *app;
Florin Coras349f8ca2018-11-20 16:52:49 -08001660 u32 app_index = ~0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001661 int verbose = 0;
1662
Florin Corascea194d2017-10-02 00:18:51 -07001663 session_cli_return_if_not_enabled ();
Florin Corase04c2992017-03-01 08:17:34 -08001664
Dave Barach68b0fb02017-02-28 15:15:56 -05001665 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1666 {
1667 if (unformat (input, "server"))
1668 do_server = 1;
1669 else if (unformat (input, "client"))
1670 do_client = 1;
Florin Corasf8f516a2018-02-08 15:10:09 -08001671 else if (unformat (input, "local"))
1672 do_local = 1;
Florin Coras349f8ca2018-11-20 16:52:49 -08001673 else if (unformat (input, "%u", &app_index))
1674 ;
Dave Barach68b0fb02017-02-28 15:15:56 -05001675 else if (unformat (input, "verbose"))
1676 verbose = 1;
1677 else
Florin Coras349f8ca2018-11-20 16:52:49 -08001678 return clib_error_return (0, "unknown input `%U'",
1679 format_unformat_error, input);
Dave Barach68b0fb02017-02-28 15:15:56 -05001680 }
1681
1682 if (do_server)
Florin Coras349f8ca2018-11-20 16:52:49 -08001683 {
1684 application_format_all_listeners (vm, do_local, verbose);
1685 return 0;
1686 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001687
1688 if (do_client)
Florin Coras349f8ca2018-11-20 16:52:49 -08001689 {
1690 application_format_all_clients (vm, do_local, verbose);
1691 return 0;
1692 }
1693
1694 if (app_index != ~0)
1695 {
Florin Coras47c40e22018-11-26 17:01:36 -08001696 app = application_get_if_valid (app_index);
Florin Coras349f8ca2018-11-20 16:52:49 -08001697 if (!app)
1698 return clib_error_return (0, "No app with index %u", app_index);
1699
1700 vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1701 return 0;
1702 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001703
Florin Coras6cf30ad2017-04-04 23:08:23 -07001704 /* Print app related info */
1705 if (!do_server && !do_client)
1706 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001707 vlib_cli_output (vm, "%U", format_application, 0, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001708 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001709 pool_foreach (app, app_main.app_pool, ({
Florin Coras349f8ca2018-11-20 16:52:49 -08001710 vlib_cli_output (vm, "%U", format_application, app, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001711 }));
1712 /* *INDENT-ON* */
Florin Coras6cf30ad2017-04-04 23:08:23 -07001713 }
1714
Dave Barach68b0fb02017-02-28 15:15:56 -05001715 return 0;
1716}
1717
Florin Corase04c2992017-03-01 08:17:34 -08001718/* *INDENT-OFF* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001719VLIB_CLI_COMMAND (show_app_command, static) =
1720{
Florin Corase04c2992017-03-01 08:17:34 -08001721 .path = "show app",
1722 .short_help = "show app [server|client] [verbose]",
1723 .function = show_app_command_fn,
1724};
1725/* *INDENT-ON* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001726
1727/*
1728 * fd.io coding-style-patch-verification: ON
1729 *
1730 * Local Variables:
1731 * eval: (c-set-style "gnu")
1732 * End:
1733 */