blob: 30957870860ff763590d5b460ee00eb2e893fac9 [file] [log] [blame]
Dave Barach68b0fb02017-02-28 15:15:56 -05001/*
Florin Coras288eaab2019-02-03 15:26:14 -08002 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
Dave Barach68b0fb02017-02-28 15:15:56 -05003 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vnet/session/application.h>
Florin Coras6cf30ad2017-04-04 23:08:23 -070017#include <vnet/session/application_interface.h>
Florin Corascea194d2017-10-02 00:18:51 -070018#include <vnet/session/application_namespace.h>
Florin Corasba7d8f52019-02-22 13:11:38 -080019#include <vnet/session/application_local.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050020#include <vnet/session/session.h>
21
Florin Coras15531972018-08-12 23:50:53 -070022static app_main_t app_main;
Dave Barach68b0fb02017-02-28 15:15:56 -050023
Florin Corasc1a42652019-02-08 18:27:29 -080024#define app_interface_check_thread_and_barrier(_fn, _arg) \
25 if (PREDICT_FALSE (!vlib_thread_is_main_w_barrier ())) \
26 { \
27 vlib_rpc_call_main_thread (_fn, (u8 *) _arg, sizeof(*_arg)); \
28 return 0; \
29 }
30
Florin Corasab2f6db2018-08-31 14:31:41 -070031static app_listener_t *
32app_listener_alloc (application_t * app)
33{
34 app_listener_t *app_listener;
35 pool_get (app->listeners, app_listener);
Dave Barachb7b92992018-10-17 10:38:51 -040036 clib_memset (app_listener, 0, sizeof (*app_listener));
Florin Corasab2f6db2018-08-31 14:31:41 -070037 app_listener->al_index = app_listener - app->listeners;
Florin Corasc9940fc2019-02-05 20:55:11 -080038 app_listener->app_index = app->app_index;
39 app_listener->session_index = SESSION_INVALID_INDEX;
40 app_listener->local_index = SESSION_INVALID_INDEX;
Florin Corasab2f6db2018-08-31 14:31:41 -070041 return app_listener;
42}
43
Florin Corasc9940fc2019-02-05 20:55:11 -080044app_listener_t *
Florin Corasab2f6db2018-08-31 14:31:41 -070045app_listener_get (application_t * app, u32 app_listener_index)
46{
47 return pool_elt_at_index (app->listeners, app_listener_index);
48}
49
Florin Coras92311f62019-03-01 19:26:31 -080050static app_listener_t *
51app_listener_get_if_valid (application_t * app, u32 app_listener_index)
52{
53 if (pool_is_free_index (app->listeners, app_listener_index))
54 return 0;
55 return pool_elt_at_index (app->listeners, app_listener_index);
56}
57
Florin Corasab2f6db2018-08-31 14:31:41 -070058static void
59app_listener_free (application_t * app, app_listener_t * app_listener)
60{
61 clib_bitmap_free (app_listener->workers);
62 pool_put (app->listeners, app_listener);
63 if (CLIB_DEBUG)
Dave Barachb7b92992018-10-17 10:38:51 -040064 clib_memset (app_listener, 0xfa, sizeof (*app_listener));
Florin Corasab2f6db2018-08-31 14:31:41 -070065}
66
Florin Corasc9940fc2019-02-05 20:55:11 -080067static u32
68app_listener_id (app_listener_t * al)
69{
70 ASSERT (al->app_index < 1 << 16 && al->al_index < 1 << 16);
71 return (al->app_index << 16 | al->al_index);
72}
73
74session_handle_t
75app_listener_handle (app_listener_t * al)
76{
77 return ((u64) SESSION_LISTENER_PREFIX << 32 | (u64) app_listener_id (al));
Florin Corasab2f6db2018-08-31 14:31:41 -070078}
79
80static void
Florin Corasc9940fc2019-02-05 20:55:11 -080081app_listener_id_parse (u32 listener_id, u32 * app_index,
82 u32 * app_listener_index)
Florin Corasab2f6db2018-08-31 14:31:41 -070083{
Florin Corasc9940fc2019-02-05 20:55:11 -080084 *app_index = listener_id >> 16;
85 *app_listener_index = listener_id & 0xFFFF;
86}
87
88void
89app_listener_handle_parse (session_handle_t handle, u32 * app_index,
90 u32 * app_listener_index)
91{
92 app_listener_id_parse (handle & 0xFFFFFFFF, app_index, app_listener_index);
93}
94
95static app_listener_t *
96app_listener_get_w_id (u32 listener_id)
97{
98 u32 app_index, app_listener_index;
99 application_t *app;
100
101 app_listener_id_parse (listener_id, &app_index, &app_listener_index);
102 app = application_get_if_valid (app_index);
103 if (!app)
104 return 0;
Florin Coras92311f62019-03-01 19:26:31 -0800105 return app_listener_get_if_valid (app, app_listener_index);
Florin Corasc9940fc2019-02-05 20:55:11 -0800106}
107
108app_listener_t *
109app_listener_get_w_session (session_t * ls)
110{
111 application_t *app;
112
113 app = application_get_if_valid (ls->app_index);
114 if (!app)
115 return 0;
116 return app_listener_get (app, ls->al_index);
117}
118
119app_listener_t *
120app_listener_get_w_handle (session_handle_t handle)
121{
122
123 if (handle >> 32 != SESSION_LISTENER_PREFIX)
124 return 0;
125
126 return app_listener_get_w_id (handle & 0xFFFFFFFF);
127}
128
129app_listener_t *
130app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
131{
132 u32 table_index, fib_proto;
133 session_endpoint_t *sep;
134 session_handle_t handle;
Florin Corasc9940fc2019-02-05 20:55:11 -0800135 session_t *ls;
136
137 sep = (session_endpoint_t *) sep_ext;
138 if (application_has_local_scope (app) && session_endpoint_is_local (sep))
139 {
140 table_index = application_local_session_table (app);
141 handle = session_lookup_endpoint_listener (table_index, sep, 1);
142 if (handle != SESSION_INVALID_HANDLE)
143 {
Florin Corasd4295e62019-02-22 13:11:38 -0800144 ls = listen_session_get_from_handle (handle);
145 return app_listener_get_w_session (ls);
Florin Corasc9940fc2019-02-05 20:55:11 -0800146 }
147 }
148
149 fib_proto = session_endpoint_fib_proto (sep);
150 table_index = application_session_table (app, fib_proto);
151 handle = session_lookup_endpoint_listener (table_index, sep, 1);
152 if (handle != SESSION_INVALID_HANDLE)
153 {
154 ls = listen_session_get_from_handle (handle);
155 return app_listener_get_w_session ((session_t *) ls);
156 }
157
158 return 0;
159}
160
161int
162app_listener_alloc_and_init (application_t * app,
163 session_endpoint_cfg_t * sep,
164 app_listener_t ** listener)
165{
166 app_listener_t *app_listener;
Florin Corasd4295e62019-02-22 13:11:38 -0800167 transport_connection_t *tc;
Florin Corasc9940fc2019-02-05 20:55:11 -0800168 session_handle_t lh;
169 session_type_t st;
170 session_t *ls = 0;
Florin Corasa27a46e2019-02-18 13:02:28 -0800171 u32 al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800172 int rv;
173
174 app_listener = app_listener_alloc (app);
Florin Corasa27a46e2019-02-18 13:02:28 -0800175 al_index = app_listener->al_index;
Florin Corasc9940fc2019-02-05 20:55:11 -0800176 st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
177
178 /*
179 * Add session endpoint to local session table. Only binds to "inaddr_any"
180 * (i.e., zero address) are added to local scope table.
181 */
182 if (application_has_local_scope (app)
183 && session_endpoint_is_local ((session_endpoint_t *) sep))
184 {
Florin Corasd4295e62019-02-22 13:11:38 -0800185 session_type_t local_st;
Florin Corasc9940fc2019-02-05 20:55:11 -0800186 u32 table_index;
187
Florin Corasd4295e62019-02-22 13:11:38 -0800188 local_st = session_type_from_proto_and_ip (TRANSPORT_PROTO_NONE,
189 sep->is_ip4);
190 ls = listen_session_alloc (0, local_st);
191 ls->app_index = app->app_index;
192 ls->app_wrk_index = sep->app_wrk_index;
193 lh = session_handle (ls);
194
195 if ((rv = session_listen (ls, sep)))
196 {
197 ls = session_get_from_handle (lh);
198 session_free (ls);
199 return rv;
200 }
201
202 ls = session_get_from_handle (lh);
203 app_listener = app_listener_get (app, al_index);
204 app_listener->local_index = ls->session_index;
205 ls->al_index = al_index;
206
Florin Corasc9940fc2019-02-05 20:55:11 -0800207 table_index = application_local_session_table (app);
Florin Corasc9940fc2019-02-05 20:55:11 -0800208 session_lookup_add_session_endpoint (table_index,
209 (session_endpoint_t *) sep, lh);
Florin Corasc9940fc2019-02-05 20:55:11 -0800210 }
211
212 if (application_has_global_scope (app))
213 {
214 /*
215 * Start listening on local endpoint for requested transport and scope.
216 * Creates a stream session with state LISTENING to be used in session
217 * lookups, prior to establishing connection. Requests transport to
218 * build it's own specific listening connection.
219 */
Florin Corasba7d8f52019-02-22 13:11:38 -0800220 ls = listen_session_alloc (0, st);
Florin Corasc9940fc2019-02-05 20:55:11 -0800221 ls->app_index = app->app_index;
222 ls->app_wrk_index = sep->app_wrk_index;
223
224 /* Listen pool can be reallocated if the transport is
225 * recursive (tls) */
Florin Corasd4295e62019-02-22 13:11:38 -0800226 lh = listen_session_get_handle (ls);
Florin Corasc9940fc2019-02-05 20:55:11 -0800227
228 if ((rv = session_listen (ls, sep)))
229 {
Florin Corasd4295e62019-02-22 13:11:38 -0800230 ls = listen_session_get_from_handle (lh);
Florin Corasc9940fc2019-02-05 20:55:11 -0800231 session_free (ls);
232 return rv;
233 }
Florin Corasd4295e62019-02-22 13:11:38 -0800234 ls = listen_session_get_from_handle (lh);
Florin Corasa27a46e2019-02-18 13:02:28 -0800235 app_listener = app_listener_get (app, al_index);
Florin Corasc9940fc2019-02-05 20:55:11 -0800236 app_listener->session_index = ls->session_index;
Florin Corasa27a46e2019-02-18 13:02:28 -0800237 ls->al_index = al_index;
Florin Corasd4295e62019-02-22 13:11:38 -0800238
239 /* Add to the global lookup table after transport was initialized.
240 * Lookup table needs to be populated only now because sessions
241 * with cut-through transport are are added to app local tables that
242 * are not related to network fibs, i.e., cannot be added as
243 * connections */
244 tc = session_get_transport (ls);
245 session_lookup_add_connection (tc, lh);
Florin Corasc9940fc2019-02-05 20:55:11 -0800246 }
247
Florin Coras2b81e3c2019-02-27 07:55:46 -0800248 if (!ls)
Florin Corasc9940fc2019-02-05 20:55:11 -0800249 {
250 app_listener_free (app, app_listener);
251 return -1;
252 }
253
254 *listener = app_listener;
255 return 0;
256}
257
258void
259app_listener_cleanup (app_listener_t * al)
260{
261 application_t *app = application_get (al->app_index);
Florin Corasd4295e62019-02-22 13:11:38 -0800262 session_t *ls;
Florin Corasc9940fc2019-02-05 20:55:11 -0800263
264 if (al->session_index != SESSION_INVALID_INDEX)
265 {
Florin Corasd4295e62019-02-22 13:11:38 -0800266 ls = session_get (al->session_index, 0);
Florin Corasc9940fc2019-02-05 20:55:11 -0800267 session_stop_listen (ls);
Florin Corasba7d8f52019-02-22 13:11:38 -0800268 listen_session_free (ls);
Florin Corasc9940fc2019-02-05 20:55:11 -0800269 }
270 if (al->local_index != SESSION_INVALID_INDEX)
271 {
272 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
Florin Corasc9940fc2019-02-05 20:55:11 -0800273 u32 table_index;
274
275 table_index = application_local_session_table (app);
Florin Corasd4295e62019-02-22 13:11:38 -0800276 ls = listen_session_get (al->local_index);
Florin Coras2b81e3c2019-02-27 07:55:46 -0800277 ct_session_endpoint (ls, &sep);
Florin Corasc9940fc2019-02-05 20:55:11 -0800278 session_lookup_del_session_endpoint (table_index, &sep);
Florin Coras2b81e3c2019-02-27 07:55:46 -0800279 session_stop_listen (ls);
Florin Corasd4295e62019-02-22 13:11:38 -0800280 listen_session_free (ls);
Florin Corasc9940fc2019-02-05 20:55:11 -0800281 }
282 app_listener_free (app, al);
283}
284
Florin Coras11e2cf52019-03-06 12:04:24 -0800285static app_worker_t *
286app_listener_select_worker (application_t * app, app_listener_t * al)
Florin Corasc9940fc2019-02-05 20:55:11 -0800287{
Florin Corasc9940fc2019-02-05 20:55:11 -0800288 u32 wrk_index;
289
290 app = application_get (al->app_index);
291 wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
292 if (wrk_index == ~0)
293 wrk_index = clib_bitmap_first_set (al->workers);
294
295 ASSERT (wrk_index != ~0);
296 al->accept_rotor = wrk_index;
297 return application_get_worker (app, wrk_index);
298}
299
300session_t *
301app_listener_get_session (app_listener_t * al)
302{
303 if (al->session_index == SESSION_INVALID_INDEX)
304 return 0;
305
306 return listen_session_get (al->session_index);
Florin Corasab2f6db2018-08-31 14:31:41 -0700307}
308
Florin Corasd4295e62019-02-22 13:11:38 -0800309session_t *
310app_listener_get_local_session (app_listener_t * al)
311{
312 if (al->local_index == SESSION_INVALID_INDEX)
313 return 0;
314 return listen_session_get (al->local_index);
315}
316
Florin Coras15531972018-08-12 23:50:53 -0700317static app_worker_map_t *
318app_worker_map_alloc (application_t * app)
319{
320 app_worker_map_t *map;
321 pool_get (app->worker_maps, map);
Dave Barachb7b92992018-10-17 10:38:51 -0400322 clib_memset (map, 0, sizeof (*map));
Florin Coras15531972018-08-12 23:50:53 -0700323 return map;
324}
Dave Barach68b0fb02017-02-28 15:15:56 -0500325
Florin Coras15531972018-08-12 23:50:53 -0700326static u32
327app_worker_map_index (application_t * app, app_worker_map_t * map)
328{
329 return (map - app->worker_maps);
330}
331
332static void
333app_worker_map_free (application_t * app, app_worker_map_t * map)
334{
335 pool_put (app->worker_maps, map);
336}
337
338static app_worker_map_t *
339app_worker_map_get (application_t * app, u32 map_index)
340{
Florin Coras01f3f892018-12-02 12:45:53 -0800341 if (pool_is_free_index (app->worker_maps, map_index))
342 return 0;
Florin Coras15531972018-08-12 23:50:53 -0700343 return pool_elt_at_index (app->worker_maps, map_index);
344}
Florin Coras0bee9ce2018-03-22 21:24:31 -0700345
Florin Coras053a0e42018-11-13 15:52:38 -0800346static const u8 *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700347app_get_name (application_t * app)
348{
Florin Coras0bee9ce2018-03-22 21:24:31 -0700349 return app->name;
350}
351
Florin Corascea194d2017-10-02 00:18:51 -0700352u32
353application_session_table (application_t * app, u8 fib_proto)
354{
355 app_namespace_t *app_ns;
356 app_ns = app_namespace_get (app->ns_index);
357 if (!application_has_global_scope (app))
358 return APP_INVALID_INDEX;
359 if (fib_proto == FIB_PROTOCOL_IP4)
360 return session_lookup_get_index_for_fib (fib_proto,
361 app_ns->ip4_fib_index);
362 else
363 return session_lookup_get_index_for_fib (fib_proto,
364 app_ns->ip6_fib_index);
365}
366
367u32
368application_local_session_table (application_t * app)
369{
370 app_namespace_t *app_ns;
371 if (!application_has_local_scope (app))
372 return APP_INVALID_INDEX;
373 app_ns = app_namespace_get (app->ns_index);
374 return app_ns->local_table_index;
375}
376
Florin Corascea194d2017-10-02 00:18:51 -0700377/**
Florin Coras053a0e42018-11-13 15:52:38 -0800378 * Returns app name for app-index
Florin Corascea194d2017-10-02 00:18:51 -0700379 */
Florin Coras053a0e42018-11-13 15:52:38 -0800380const u8 *
Florin Corascea194d2017-10-02 00:18:51 -0700381application_name_from_index (u32 app_index)
382{
383 application_t *app = application_get (app_index);
384 if (!app)
385 return 0;
Florin Coras053a0e42018-11-13 15:52:38 -0800386 return app_get_name (app);
387}
388
389static void
390application_api_table_add (u32 app_index, u32 api_client_index)
391{
Florin Corasc1f5a432018-11-20 11:31:26 -0800392 if (api_client_index != APP_INVALID_INDEX)
393 hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
Florin Coras053a0e42018-11-13 15:52:38 -0800394}
395
396static void
397application_api_table_del (u32 api_client_index)
398{
399 hash_unset (app_main.app_by_api_client_index, api_client_index);
Florin Corascea194d2017-10-02 00:18:51 -0700400}
401
Dave Barach68b0fb02017-02-28 15:15:56 -0500402static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800403application_name_table_add (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500404{
Florin Corasc1f5a432018-11-20 11:31:26 -0800405 hash_set_mem (app_main.app_by_name, app->name, app->app_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500406}
407
408static void
Florin Corasc1f5a432018-11-20 11:31:26 -0800409application_name_table_del (application_t * app)
Dave Barach68b0fb02017-02-28 15:15:56 -0500410{
Florin Corasc1f5a432018-11-20 11:31:26 -0800411 hash_unset_mem (app_main.app_by_name, app->name);
Dave Barach68b0fb02017-02-28 15:15:56 -0500412}
413
414application_t *
415application_lookup (u32 api_client_index)
416{
417 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700418 p = hash_get (app_main.app_by_api_client_index, api_client_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500419 if (p)
Florin Coras053a0e42018-11-13 15:52:38 -0800420 return application_get_if_valid (p[0]);
Dave Barach68b0fb02017-02-28 15:15:56 -0500421
422 return 0;
423}
424
Florin Coras6cf30ad2017-04-04 23:08:23 -0700425application_t *
Florin Coras0bee9ce2018-03-22 21:24:31 -0700426application_lookup_name (const u8 * name)
427{
428 uword *p;
Florin Coras15531972018-08-12 23:50:53 -0700429 p = hash_get_mem (app_main.app_by_name, name);
Florin Coras0bee9ce2018-03-22 21:24:31 -0700430 if (p)
431 return application_get (p[0]);
432
433 return 0;
434}
435
Florin Corasc1a42652019-02-08 18:27:29 -0800436static application_t *
Florin Coras15531972018-08-12 23:50:53 -0700437application_alloc (void)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700438{
439 application_t *app;
Florin Coras15531972018-08-12 23:50:53 -0700440 pool_get (app_main.app_pool, app);
Dave Barachb7b92992018-10-17 10:38:51 -0400441 clib_memset (app, 0, sizeof (*app));
Florin Coras15531972018-08-12 23:50:53 -0700442 app->app_index = app - app_main.app_pool;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700443 return app;
444}
445
Florin Coras15531972018-08-12 23:50:53 -0700446application_t *
447application_get (u32 app_index)
Dave Barach68b0fb02017-02-28 15:15:56 -0500448{
Florin Coras15531972018-08-12 23:50:53 -0700449 if (app_index == APP_INVALID_INDEX)
450 return 0;
451 return pool_elt_at_index (app_main.app_pool, app_index);
452}
Dave Barach68b0fb02017-02-28 15:15:56 -0500453
Florin Coras15531972018-08-12 23:50:53 -0700454application_t *
455application_get_if_valid (u32 app_index)
456{
457 if (pool_is_free_index (app_main.app_pool, app_index))
458 return 0;
Florin Corasa5464812017-04-19 13:00:05 -0700459
Florin Coras15531972018-08-12 23:50:53 -0700460 return pool_elt_at_index (app_main.app_pool, app_index);
461}
Florin Coras7999e832017-10-31 01:51:04 -0700462
Florin Corasd79b41e2017-03-04 05:37:52 -0800463static void
Florin Coras6cf30ad2017-04-04 23:08:23 -0700464application_verify_cb_fns (session_cb_vft_t * cb_fns)
Florin Corasd79b41e2017-03-04 05:37:52 -0800465{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700466 if (cb_fns->session_accept_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800467 clib_warning ("No accept callback function provided");
Florin Coras6cf30ad2017-04-04 23:08:23 -0700468 if (cb_fns->session_connected_callback == 0)
Florin Corasd79b41e2017-03-04 05:37:52 -0800469 clib_warning ("No session connected callback function provided");
470 if (cb_fns->session_disconnect_callback == 0)
471 clib_warning ("No session disconnect callback function provided");
472 if (cb_fns->session_reset_callback == 0)
473 clib_warning ("No session reset callback function provided");
474}
475
Florin Corasb384b542018-01-15 01:08:33 -0800476/**
477 * Check app config for given segment type
478 *
479 * Returns 1 on success and 0 otherwise
480 */
481static u8
482application_verify_cfg (ssvm_segment_type_t st)
483{
484 u8 is_valid;
485 if (st == SSVM_SEGMENT_MEMFD)
486 {
Florin Coras31c99552019-03-01 13:00:58 -0800487 is_valid = (session_main_get_evt_q_segment () != 0);
Florin Corasb384b542018-01-15 01:08:33 -0800488 if (!is_valid)
489 clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
490 return is_valid;
491 }
492 else if (st == SSVM_SEGMENT_SHM)
493 {
Florin Coras31c99552019-03-01 13:00:58 -0800494 is_valid = (session_main_get_evt_q_segment () == 0);
Florin Corasb384b542018-01-15 01:08:33 -0800495 if (!is_valid)
496 clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
497 return is_valid;
498 }
499 else
500 return 1;
501}
502
Florin Corasc1a42652019-02-08 18:27:29 -0800503static int
Florin Coras15531972018-08-12 23:50:53 -0700504application_alloc_and_init (app_init_args_t * a)
Dave Barach68b0fb02017-02-28 15:15:56 -0500505{
Florin Corasa332c462018-01-31 06:52:17 -0800506 ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
Florin Coras88001c62019-04-24 14:44:46 -0700507 segment_manager_props_t *props;
Florin Corasb384b542018-01-15 01:08:33 -0800508 vl_api_registration_t *reg;
Florin Coras15531972018-08-12 23:50:53 -0700509 application_t *app;
510 u64 *options;
Dave Barach68b0fb02017-02-28 15:15:56 -0500511
Florin Coras15531972018-08-12 23:50:53 -0700512 app = application_alloc ();
513 options = a->options;
Florin Corasb384b542018-01-15 01:08:33 -0800514 /*
515 * Make sure we support the requested configuration
516 */
Florin Corasa332c462018-01-31 06:52:17 -0800517 if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
518 {
Florin Coras15531972018-08-12 23:50:53 -0700519 reg = vl_api_client_index_to_registration (a->api_client_index);
Florin Corasa332c462018-01-31 06:52:17 -0800520 if (!reg)
521 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
522 if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
523 seg_type = SSVM_SEGMENT_SHM;
524 }
525 else
526 {
527 seg_type = SSVM_SEGMENT_PRIVATE;
528 }
Florin Corasb384b542018-01-15 01:08:33 -0800529
Florin Corasd8402ae2019-03-03 16:46:52 -0800530 if ((options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
531 && seg_type != SSVM_SEGMENT_MEMFD)
532 {
533 clib_warning ("mq eventfds can only be used if socket transport is "
534 "used for binary api");
535 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
536 }
537
Florin Corasa332c462018-01-31 06:52:17 -0800538 if (!application_verify_cfg (seg_type))
Florin Corasb384b542018-01-15 01:08:33 -0800539 return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
Dave Barach68b0fb02017-02-28 15:15:56 -0500540
Florin Coras15531972018-08-12 23:50:53 -0700541 /* Check that the obvious things are properly set up */
542 application_verify_cb_fns (a->session_cb_vft);
543
Florin Coras15531972018-08-12 23:50:53 -0700544 app->flags = options[APP_OPTIONS_FLAGS];
545 app->cb_fns = *a->session_cb_vft;
546 app->ns_index = options[APP_OPTIONS_NAMESPACE];
547 app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
548 app->name = vec_dup (a->name);
549
550 /* If no scope enabled, default to global */
551 if (!application_has_global_scope (app)
552 && !application_has_local_scope (app))
553 app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
554
Florin Corasa332c462018-01-31 06:52:17 -0800555 props = application_segment_manager_properties (app);
Florin Coras88001c62019-04-24 14:44:46 -0700556 segment_manager_props_init (props);
Florin Coras404b8a32019-05-09 12:08:06 -0700557 props->segment_size = options[APP_OPTIONS_SEGMENT_SIZE];
Florin Coras15531972018-08-12 23:50:53 -0700558 props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
Florin Corasb384b542018-01-15 01:08:33 -0800559 if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
560 {
561 props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
562 props->add_segment = 1;
563 }
564 if (options[APP_OPTIONS_RX_FIFO_SIZE])
565 props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
566 if (options[APP_OPTIONS_TX_FIFO_SIZE])
567 props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
Florin Corasf8f516a2018-02-08 15:10:09 -0800568 if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
569 props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
Florin Coras99368312018-08-02 10:45:44 -0700570 if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
571 props->use_mq_eventfd = 1;
Florin Coras58d36f02018-03-09 13:05:53 -0800572 if (options[APP_OPTIONS_TLS_ENGINE])
573 app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
Florin Corasa332c462018-01-31 06:52:17 -0800574 props->segment_type = seg_type;
Dave Barach68b0fb02017-02-28 15:15:56 -0500575
Florin Coras15531972018-08-12 23:50:53 -0700576 /* Add app to lookup by api_client_index table */
Florin Corasc1f5a432018-11-20 11:31:26 -0800577 if (!application_is_builtin (app))
578 application_api_table_add (app->app_index, a->api_client_index);
579 else
580 application_name_table_add (app);
581
582 a->app_index = app->app_index;
Florin Corasa332c462018-01-31 06:52:17 -0800583
Florin Coras15531972018-08-12 23:50:53 -0700584 APP_DBG ("New app name: %v api index: %u index %u", app->name,
Nathan Skrzypczakba65ca42019-05-16 16:35:40 +0200585 a->api_client_index, app->app_index);
Florin Coras15531972018-08-12 23:50:53 -0700586
587 return 0;
588}
589
Florin Corasc1a42652019-02-08 18:27:29 -0800590static void
Florin Coras15531972018-08-12 23:50:53 -0700591application_free (application_t * app)
592{
593 app_worker_map_t *wrk_map;
594 app_worker_t *app_wrk;
595
596 /*
597 * The app event queue allocated in first segment is cleared with
598 * the segment manager. No need to explicitly free it.
599 */
Nathan Skrzypczakba65ca42019-05-16 16:35:40 +0200600 APP_DBG ("Delete app name %v index: %d", app->name, app->app_index);
Florin Coras15531972018-08-12 23:50:53 -0700601
602 if (application_is_proxy (app))
603 application_remove_proxy (app);
604
Florin Corasab2f6db2018-08-31 14:31:41 -0700605 /*
606 * Free workers
607 */
608
Florin Coras15531972018-08-12 23:50:53 -0700609 /* *INDENT-OFF* */
610 pool_flush (wrk_map, app->worker_maps, ({
611 app_wrk = app_worker_get (wrk_map->wrk_index);
612 app_worker_free (app_wrk);
613 }));
614 /* *INDENT-ON* */
615 pool_free (app->worker_maps);
616
Florin Corasab2f6db2018-08-31 14:31:41 -0700617 /*
Florin Corasab2f6db2018-08-31 14:31:41 -0700618 * Cleanup remaining state
619 */
Florin Corasc1f5a432018-11-20 11:31:26 -0800620 if (application_is_builtin (app))
621 application_name_table_del (app);
Florin Coras15531972018-08-12 23:50:53 -0700622 vec_free (app->name);
623 vec_free (app->tls_cert);
624 vec_free (app->tls_key);
625 pool_put (app_main.app_pool, app);
626}
627
Florin Corasc1a42652019-02-08 18:27:29 -0800628static void
Florin Coras053a0e42018-11-13 15:52:38 -0800629application_detach_process (application_t * app, u32 api_client_index)
630{
631 vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
632 app_worker_map_t *wrk_map;
633 u32 *wrks = 0, *wrk_index;
634 app_worker_t *app_wrk;
635
636 if (api_client_index == ~0)
637 {
638 application_free (app);
639 return;
640 }
641
642 APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
Nathan Skrzypczakba65ca42019-05-16 16:35:40 +0200643 app->app_index, api_client_index);
Florin Coras053a0e42018-11-13 15:52:38 -0800644
645 /* *INDENT-OFF* */
646 pool_foreach (wrk_map, app->worker_maps, ({
647 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Corasc1f5a432018-11-20 11:31:26 -0800648 if (app_wrk->api_client_index == api_client_index)
Florin Coras053a0e42018-11-13 15:52:38 -0800649 vec_add1 (wrks, app_wrk->wrk_index);
650 }));
651 /* *INDENT-ON* */
652
653 if (!vec_len (wrks))
654 {
655 clib_warning ("no workers for app %u api_index %u", app->app_index,
656 api_client_index);
657 return;
658 }
659
660 args->app_index = app->app_index;
Florin Corasc1f5a432018-11-20 11:31:26 -0800661 args->api_client_index = api_client_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800662 vec_foreach (wrk_index, wrks)
663 {
664 app_wrk = app_worker_get (wrk_index[0]);
Florin Coras349f8ca2018-11-20 16:52:49 -0800665 args->wrk_map_index = app_wrk->wrk_map_index;
Florin Coras053a0e42018-11-13 15:52:38 -0800666 args->is_add = 0;
667 vnet_app_worker_add_del (args);
668 }
669 vec_free (wrks);
670}
671
Florin Coras15531972018-08-12 23:50:53 -0700672app_worker_t *
673application_get_worker (application_t * app, u32 wrk_map_index)
674{
675 app_worker_map_t *map;
676 map = app_worker_map_get (app, wrk_map_index);
677 if (!map)
678 return 0;
679 return app_worker_get (map->wrk_index);
680}
681
682app_worker_t *
683application_get_default_worker (application_t * app)
684{
685 return application_get_worker (app, 0);
686}
687
Florin Coras053a0e42018-11-13 15:52:38 -0800688u32
689application_n_workers (application_t * app)
690{
691 return pool_elts (app->worker_maps);
692}
693
Florin Coras15531972018-08-12 23:50:53 -0700694app_worker_t *
Florin Corasc9940fc2019-02-05 20:55:11 -0800695application_listener_select_worker (session_t * ls)
Florin Corasab2f6db2018-08-31 14:31:41 -0700696{
Florin Coras11e2cf52019-03-06 12:04:24 -0800697 application_t *app;
Florin Corasc9940fc2019-02-05 20:55:11 -0800698 app_listener_t *al;
Florin Corasab2f6db2018-08-31 14:31:41 -0700699
Florin Coras11e2cf52019-03-06 12:04:24 -0800700 app = application_get (ls->app_index);
701 al = app_listener_get (app, ls->al_index);
702 return app_listener_select_worker (app, al);
Florin Corasab2f6db2018-08-31 14:31:41 -0700703}
704
Florin Coras15531972018-08-12 23:50:53 -0700705int
Florin Coras623eb562019-02-03 19:28:34 -0800706application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
Florin Coras15531972018-08-12 23:50:53 -0700707{
708 app_worker_map_t *wrk_map;
709 app_worker_t *app_wrk;
710 segment_manager_t *sm;
711 int rv;
712
713 app_wrk = app_worker_alloc (app);
714 wrk_map = app_worker_map_alloc (app);
715 wrk_map->wrk_index = app_wrk->wrk_index;
716 app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
717
718 /*
719 * Setup first segment manager
720 */
Florin Coras88001c62019-04-24 14:44:46 -0700721 sm = segment_manager_alloc ();
Florin Coras15531972018-08-12 23:50:53 -0700722 sm->app_wrk_index = app_wrk->wrk_index;
723
724 if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
725 app->sm_properties.prealloc_fifos)))
726 {
727 app_worker_free (app_wrk);
728 return rv;
729 }
Florin Corasc87c91d2017-08-16 19:55:49 -0700730 sm->first_is_protected = 1;
Dave Barach68b0fb02017-02-28 15:15:56 -0500731
Florin Corascea194d2017-10-02 00:18:51 -0700732 /*
Florin Coras15531972018-08-12 23:50:53 -0700733 * Setup app worker
Florin Corascea194d2017-10-02 00:18:51 -0700734 */
Florin Coras15531972018-08-12 23:50:53 -0700735 app_wrk->first_segment_manager = segment_manager_index (sm);
736 app_wrk->listeners_table = hash_create (0, sizeof (u64));
737 app_wrk->event_queue = segment_manager_event_queue (sm);
738 app_wrk->app_is_builtin = application_is_builtin (app);
Dave Barach68b0fb02017-02-28 15:15:56 -0500739
Florin Coras15531972018-08-12 23:50:53 -0700740 *wrk = app_wrk;
Florin Corasf8f516a2018-02-08 15:10:09 -0800741
Florin Coras6cf30ad2017-04-04 23:08:23 -0700742 return 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500743}
744
Florin Coras623eb562019-02-03 19:28:34 -0800745int
Florin Corasc1a42652019-02-08 18:27:29 -0800746vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
747{
Florin Coras88001c62019-04-24 14:44:46 -0700748 fifo_segment_t *fs;
Florin Corasc1a42652019-02-08 18:27:29 -0800749 app_worker_map_t *wrk_map;
750 app_worker_t *app_wrk;
751 segment_manager_t *sm;
752 application_t *app;
753 int rv;
754
755 app = application_get (a->app_index);
756 if (!app)
757 return VNET_API_ERROR_INVALID_VALUE;
758
759 if (a->is_add)
760 {
761 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
762 return rv;
763
764 /* Map worker api index to the app */
765 app_wrk->api_client_index = a->api_client_index;
766 application_api_table_add (app->app_index, a->api_client_index);
767
768 sm = segment_manager_get (app_wrk->first_segment_manager);
769 fs = segment_manager_get_segment_w_lock (sm, 0);
770 a->segment = &fs->ssvm;
771 a->segment_handle = segment_manager_segment_handle (sm, fs);
772 segment_manager_segment_reader_unlock (sm);
773 a->evt_q = app_wrk->event_queue;
774 a->wrk_map_index = app_wrk->wrk_map_index;
775 }
776 else
777 {
778 wrk_map = app_worker_map_get (app, a->wrk_map_index);
779 if (!wrk_map)
780 return VNET_API_ERROR_INVALID_VALUE;
781
782 app_wrk = app_worker_get (wrk_map->wrk_index);
783 if (!app_wrk)
784 return VNET_API_ERROR_INVALID_VALUE;
785
786 application_api_table_del (app_wrk->api_client_index);
787 app_worker_free (app_wrk);
788 app_worker_map_free (app, wrk_map);
789 if (application_n_workers (app) == 0)
790 application_free (app);
791 }
792 return 0;
793}
794
795static int
796app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
797{
798 app_namespace_t *app_ns;
799 if (vec_len (namespace_id) == 0)
800 {
801 /* Use default namespace */
802 *app_ns_index = 0;
803 return 0;
804 }
805
806 *app_ns_index = app_namespace_index_from_id (namespace_id);
807 if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
808 return VNET_API_ERROR_APP_INVALID_NS;
809 app_ns = app_namespace_get (*app_ns_index);
810 if (!app_ns)
811 return VNET_API_ERROR_APP_INVALID_NS;
812 if (app_ns->ns_secret != secret)
813 return VNET_API_ERROR_APP_WRONG_NS_SECRET;
814 return 0;
815}
816
817static u8 *
818app_name_from_api_index (u32 api_client_index)
819{
820 vl_api_registration_t *regp;
821 regp = vl_api_client_index_to_registration (api_client_index);
822 if (regp)
Florin Corasbee97682019-04-09 16:13:18 -0700823 return format (0, "%s", regp->name);
Florin Corasc1a42652019-02-08 18:27:29 -0800824
825 clib_warning ("api client index %u does not have an api registration!",
826 api_client_index);
Florin Corasbee97682019-04-09 16:13:18 -0700827 return format (0, "unknown");
Florin Corasc1a42652019-02-08 18:27:29 -0800828}
829
830/**
831 * Attach application to vpp
832 *
833 * Allocates a vpp app, i.e., a structure that keeps back pointers
834 * to external app and a segment manager for shared memory fifo based
835 * communication with the external app.
836 */
837int
838vnet_application_attach (vnet_app_attach_args_t * a)
839{
Florin Coras88001c62019-04-24 14:44:46 -0700840 fifo_segment_t *fs;
Florin Corasc1a42652019-02-08 18:27:29 -0800841 application_t *app = 0;
842 app_worker_t *app_wrk;
843 segment_manager_t *sm;
844 u32 app_ns_index = 0;
845 u8 *app_name = 0;
846 u64 secret;
847 int rv;
848
849 if (a->api_client_index != APP_INVALID_INDEX)
850 app = application_lookup (a->api_client_index);
851 else if (a->name)
852 app = application_lookup_name (a->name);
853 else
854 return VNET_API_ERROR_INVALID_VALUE;
855
856 if (app)
857 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
858
859 if (a->api_client_index != APP_INVALID_INDEX)
860 {
861 app_name = app_name_from_api_index (a->api_client_index);
862 a->name = app_name;
863 }
864
865 secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
866 if ((rv = app_validate_namespace (a->namespace_id, secret, &app_ns_index)))
867 return rv;
868 a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
869
870 if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
871 return rv;
872
873 app = application_get (a->app_index);
874 if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
875 return rv;
876
877 a->app_evt_q = app_wrk->event_queue;
878 app_wrk->api_client_index = a->api_client_index;
879 sm = segment_manager_get (app_wrk->first_segment_manager);
880 fs = segment_manager_get_segment_w_lock (sm, 0);
881
882 if (application_is_proxy (app))
883 application_setup_proxy (app);
884
885 ASSERT (vec_len (fs->ssvm.name) <= 128);
886 a->segment = &fs->ssvm;
887 a->segment_handle = segment_manager_segment_handle (sm, fs);
888
889 segment_manager_segment_reader_unlock (sm);
890 vec_free (app_name);
891 return 0;
892}
893
894/**
895 * Detach application from vpp
896 */
897int
898vnet_application_detach (vnet_app_detach_args_t * a)
899{
900 application_t *app;
901
902 app = application_get_if_valid (a->app_index);
903 if (!app)
904 {
905 clib_warning ("app not attached");
906 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
907 }
908
909 app_interface_check_thread_and_barrier (vnet_application_detach, a);
910 application_detach_process (app, a->api_client_index);
911 return 0;
912}
913
914
915static u8
916session_endpoint_in_ns (session_endpoint_t * sep)
917{
918 u8 is_lep = session_endpoint_is_local (sep);
919 if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
920 && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
921 {
922 clib_warning ("sw_if_index %u not configured with ip %U",
923 sep->sw_if_index, format_ip46_address, &sep->ip,
924 sep->is_ip4);
925 return 0;
926 }
927 return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
928}
929
930static void
931session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
932 application_t * app, u8 is_connect)
933{
934 app_namespace_t *app_ns;
935 u32 ns_index, fib_index;
936
937 ns_index = app->ns_index;
938
939 /* App is a transport proto, so fetch the calling app's ns */
940 if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
Florin Coras8a140612019-02-18 22:39:39 -0800941 ns_index = sep->ns_index;
Florin Corasc1a42652019-02-08 18:27:29 -0800942
Florin Corasc1a42652019-02-08 18:27:29 -0800943 app_ns = app_namespace_get (ns_index);
944 if (!app_ns)
945 return;
946
947 /* Ask transport and network to bind to/connect using local interface
948 * that "supports" app's namespace. This will fix our local connection
949 * endpoint.
950 */
951
952 /* If in default namespace and user requested a fib index use it */
953 if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
954 fib_index = sep->fib_index;
955 else
956 fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
957 sep->peer.fib_index = fib_index;
958 sep->fib_index = fib_index;
959
960 if (!is_connect)
961 {
962 sep->sw_if_index = app_ns->sw_if_index;
963 }
964 else
965 {
966 if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
967 && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
968 && sep->peer.sw_if_index != app_ns->sw_if_index)
969 clib_warning ("Local sw_if_index different from app ns sw_if_index");
970
971 sep->peer.sw_if_index = app_ns->sw_if_index;
972 }
973}
974
975int
976vnet_listen (vnet_listen_args_t * a)
977{
978 app_listener_t *app_listener;
979 app_worker_t *app_wrk;
980 application_t *app;
981 int rv;
982
983 app = application_get_if_valid (a->app_index);
984 if (!app)
985 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
986
987 app_wrk = application_get_worker (app, a->wrk_map_index);
988 if (!app_wrk)
989 return VNET_API_ERROR_INVALID_VALUE;
990
991 a->sep_ext.app_wrk_index = app_wrk->wrk_index;
992
993 session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
994 if (!session_endpoint_in_ns (&a->sep))
995 return VNET_API_ERROR_INVALID_VALUE_2;
996
997 /*
998 * Check if we already have an app listener
999 */
1000 app_listener = app_listener_lookup (app, &a->sep_ext);
1001 if (app_listener)
1002 {
1003 if (app_listener->app_index != app->app_index)
1004 return VNET_API_ERROR_ADDRESS_IN_USE;
1005 if (app_worker_start_listen (app_wrk, app_listener))
1006 return -1;
1007 a->handle = app_listener_handle (app_listener);
1008 return 0;
1009 }
1010
1011 /*
1012 * Create new app listener
1013 */
1014 if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1015 return rv;
1016
1017 if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1018 {
1019 app_listener_cleanup (app_listener);
1020 return rv;
1021 }
1022
1023 a->handle = app_listener_handle (app_listener);
1024 return 0;
1025}
1026
1027int
1028vnet_connect (vnet_connect_args_t * a)
1029{
Florin Coras2b81e3c2019-02-27 07:55:46 -08001030 app_worker_t *client_wrk;
Florin Corasc1a42652019-02-08 18:27:29 -08001031 application_t *client;
Florin Corasc1a42652019-02-08 18:27:29 -08001032
1033 if (session_endpoint_is_zero (&a->sep))
1034 return VNET_API_ERROR_INVALID_VALUE;
1035
1036 client = application_get (a->app_index);
1037 session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1038 client_wrk = application_get_worker (client, a->wrk_map_index);
1039
1040 /*
1041 * First check the local scope for locally attached destinations.
1042 * If we have local scope, we pass *all* connects through it since we may
1043 * have special policy rules even for non-local destinations, think proxy.
1044 */
1045 if (application_has_local_scope (client))
1046 {
Florin Coras2b81e3c2019-02-27 07:55:46 -08001047 int rv;
Florin Corasc1a42652019-02-08 18:27:29 -08001048
Florin Coras2b81e3c2019-02-27 07:55:46 -08001049 a->sep_ext.original_tp = a->sep_ext.transport_proto;
1050 a->sep_ext.transport_proto = TRANSPORT_PROTO_NONE;
1051 rv = app_worker_connect_session (client_wrk, &a->sep, a->api_context);
1052 if (rv <= 0)
1053 return rv;
Florin Corasc1a42652019-02-08 18:27:29 -08001054 }
Florin Corasc1a42652019-02-08 18:27:29 -08001055 /*
1056 * Not connecting to a local server, propagate to transport
1057 */
1058 if (app_worker_connect_session (client_wrk, &a->sep, a->api_context))
1059 return VNET_API_ERROR_SESSION_CONNECT;
1060 return 0;
1061}
1062
1063int
1064vnet_unlisten (vnet_unlisten_args_t * a)
1065{
1066 app_worker_t *app_wrk;
1067 app_listener_t *al;
1068 application_t *app;
1069
1070 if (!(app = application_get_if_valid (a->app_index)))
1071 return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1072
Florin Coras92311f62019-03-01 19:26:31 -08001073 if (!(al = app_listener_get_w_handle (a->handle)))
1074 return -1;
1075
Florin Corasc1a42652019-02-08 18:27:29 -08001076 if (al->app_index != app->app_index)
1077 {
1078 clib_warning ("app doesn't own handle %llu!", a->handle);
1079 return -1;
1080 }
1081
1082 app_wrk = application_get_worker (app, a->wrk_map_index);
1083 if (!app_wrk)
1084 {
1085 clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1086 return -1;
1087 }
1088
1089 return app_worker_stop_listen (app_wrk, al);
1090}
1091
1092int
1093vnet_disconnect_session (vnet_disconnect_args_t * a)
1094{
Florin Coras2b81e3c2019-02-27 07:55:46 -08001095 app_worker_t *app_wrk;
1096 session_t *s;
Florin Corasc1a42652019-02-08 18:27:29 -08001097
Florin Coras2b81e3c2019-02-27 07:55:46 -08001098 s = session_get_from_handle_if_valid (a->handle);
1099 if (!s)
1100 return VNET_API_ERROR_INVALID_VALUE;
1101 app_wrk = app_worker_get (s->app_wrk_index);
1102 if (app_wrk->app_index != a->app_index)
1103 return VNET_API_ERROR_INVALID_VALUE;
Florin Corasc1a42652019-02-08 18:27:29 -08001104
Florin Coras2b81e3c2019-02-27 07:55:46 -08001105 /* We're peeking into another's thread pool. Make sure */
1106 ASSERT (s->session_index == session_index_from_handle (a->handle));
Florin Corasc1a42652019-02-08 18:27:29 -08001107
Florin Coras2b81e3c2019-02-27 07:55:46 -08001108 session_close (s);
Florin Corasc1a42652019-02-08 18:27:29 -08001109 return 0;
1110}
1111
1112int
Florin Coras623eb562019-02-03 19:28:34 -08001113application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1114{
1115 app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1116 app_listener_t *app_listener;
1117 application_t *app;
1118
1119 if (!old_wrk)
1120 return -1;
1121
1122 hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1123 if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1124 && s->rx_fifo)
Florin Coras19223e02019-03-03 14:56:05 -08001125 segment_manager_dealloc_fifos (s->rx_fifo, s->tx_fifo);
Florin Coras623eb562019-02-03 19:28:34 -08001126
Florin Coras623eb562019-02-03 19:28:34 -08001127 app = application_get (old_wrk->app_index);
1128 if (!app)
1129 return -1;
1130
Florin Corasc9940fc2019-02-05 20:55:11 -08001131 app_listener = app_listener_get (app, s->al_index);
1132
1133 /* Only remove from lb for now */
Florin Coras623eb562019-02-03 19:28:34 -08001134 app_listener->workers = clib_bitmap_set (app_listener->workers,
1135 old_wrk->wrk_map_index, 0);
Florin Coras623eb562019-02-03 19:28:34 -08001136
Florin Corasc9940fc2019-02-05 20:55:11 -08001137 if (app_worker_start_listen (app_wrk, app_listener))
1138 return -1;
Florin Corasab2f6db2018-08-31 14:31:41 -07001139
Florin Corasc9940fc2019-02-05 20:55:11 -08001140 s->app_wrk_index = app_wrk->wrk_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001141
Dave Barach68b0fb02017-02-28 15:15:56 -05001142 return 0;
1143}
1144
Dave Barach52851e62017-08-07 09:35:25 -04001145int
1146application_is_proxy (application_t * app)
1147{
Florin Coras7999e832017-10-31 01:51:04 -07001148 return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1149}
1150
1151int
1152application_is_builtin (application_t * app)
1153{
1154 return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1155}
1156
1157int
1158application_is_builtin_proxy (application_t * app)
1159{
1160 return (application_is_proxy (app) && application_is_builtin (app));
Dave Barach52851e62017-08-07 09:35:25 -04001161}
1162
Florin Corascea194d2017-10-02 00:18:51 -07001163u8
1164application_has_local_scope (application_t * app)
1165{
1166 return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1167}
1168
1169u8
1170application_has_global_scope (application_t * app)
1171{
1172 return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1173}
1174
Florin Coras7999e832017-10-31 01:51:04 -07001175static clib_error_t *
1176application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1177 u8 transport_proto, u8 is_start)
1178{
Florin Coras7999e832017-10-31 01:51:04 -07001179 app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1180 u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
Florin Coras5665ced2018-10-25 18:03:45 -07001181 session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
Florin Coras7999e832017-10-31 01:51:04 -07001182 transport_connection_t *tc;
Florin Coras15531972018-08-12 23:50:53 -07001183 app_worker_t *app_wrk;
Florin Corasc9940fc2019-02-05 20:55:11 -08001184 app_listener_t *al;
Florin Coras288eaab2019-02-03 15:26:14 -08001185 session_t *s;
Florin Corasc9940fc2019-02-05 20:55:11 -08001186 u32 flags;
Florin Coras7999e832017-10-31 01:51:04 -07001187
Florin Coras15531972018-08-12 23:50:53 -07001188 /* TODO decide if we want proxy to be enabled for all workers */
1189 app_wrk = application_get_default_worker (app);
Florin Coras7999e832017-10-31 01:51:04 -07001190 if (is_start)
1191 {
Florin Coras15531972018-08-12 23:50:53 -07001192 s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001193 if (!s)
1194 {
1195 sep.is_ip4 = is_ip4;
1196 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1197 sep.sw_if_index = app_ns->sw_if_index;
1198 sep.transport_proto = transport_proto;
Florin Corasab2f6db2018-08-31 14:31:41 -07001199 sep.app_wrk_index = app_wrk->wrk_index; /* only default */
Florin Corasc9940fc2019-02-05 20:55:11 -08001200
1201 /* force global scope listener */
1202 flags = app->flags;
1203 app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1204 app_listener_alloc_and_init (app, &sep, &al);
1205 app->flags = flags;
1206
1207 app_worker_start_listen (app_wrk, al);
1208 s = listen_session_get (al->session_index);
Florin Corasd5c604d2019-03-18 09:06:35 -07001209 s->flags |= SESSION_F_PROXY;
Florin Coras19b1f6a2017-12-11 03:37:03 -08001210 }
Florin Coras7999e832017-10-31 01:51:04 -07001211 }
1212 else
1213 {
Florin Coras623eb562019-02-03 19:28:34 -08001214 s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001215 ASSERT (s);
Florin Coras7999e832017-10-31 01:51:04 -07001216 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001217
Florin Coras7999e832017-10-31 01:51:04 -07001218 tc = listen_session_get_transport (s);
1219
1220 if (!ip_is_zero (&tc->lcl_ip, 1))
1221 {
Florin Corasdbd44562017-11-09 19:30:17 -08001222 u32 sti;
1223 sep.is_ip4 = is_ip4;
1224 sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1225 sep.transport_proto = transport_proto;
1226 sep.port = 0;
1227 sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001228 if (is_start)
Florin Corasab2f6db2018-08-31 14:31:41 -07001229 session_lookup_add_session_endpoint (sti,
1230 (session_endpoint_t *) & sep,
1231 s->session_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001232 else
Florin Corasab2f6db2018-08-31 14:31:41 -07001233 session_lookup_del_session_endpoint (sti,
1234 (session_endpoint_t *) & sep);
Florin Coras7999e832017-10-31 01:51:04 -07001235 }
Florin Coras19b1f6a2017-12-11 03:37:03 -08001236
Florin Coras7999e832017-10-31 01:51:04 -07001237 return 0;
1238}
1239
Florin Coras19b1f6a2017-12-11 03:37:03 -08001240static void
1241application_start_stop_proxy_local_scope (application_t * app,
1242 u8 transport_proto, u8 is_start)
1243{
1244 session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1245 app_namespace_t *app_ns;
1246 app_ns = app_namespace_get (app->ns_index);
1247 sep.is_ip4 = 1;
1248 sep.transport_proto = transport_proto;
1249 sep.port = 0;
1250
1251 if (is_start)
1252 {
1253 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001254 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001255 sep.is_ip4 = 0;
1256 session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
Florin Coras15531972018-08-12 23:50:53 -07001257 app->app_index);
Florin Coras19b1f6a2017-12-11 03:37:03 -08001258 }
1259 else
1260 {
1261 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1262 sep.is_ip4 = 0;
1263 session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1264 }
1265}
1266
Florin Coras7999e832017-10-31 01:51:04 -07001267void
Florin Coras561af9b2017-12-09 10:19:43 -08001268application_start_stop_proxy (application_t * app,
1269 transport_proto_t transport_proto, u8 is_start)
Florin Coras7999e832017-10-31 01:51:04 -07001270{
Florin Coras7999e832017-10-31 01:51:04 -07001271 if (application_has_local_scope (app))
Florin Coras19b1f6a2017-12-11 03:37:03 -08001272 application_start_stop_proxy_local_scope (app, transport_proto, is_start);
Florin Coras7999e832017-10-31 01:51:04 -07001273
1274 if (application_has_global_scope (app))
1275 {
1276 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1277 transport_proto, is_start);
1278 application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1279 transport_proto, is_start);
1280 }
1281}
1282
1283void
1284application_setup_proxy (application_t * app)
1285{
1286 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001287 transport_proto_t tp;
1288
Florin Coras7999e832017-10-31 01:51:04 -07001289 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001290
1291 /* *INDENT-OFF* */
1292 transport_proto_foreach (tp, ({
1293 if (transports & (1 << tp))
1294 application_start_stop_proxy (app, tp, 1);
1295 }));
1296 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001297}
1298
1299void
1300application_remove_proxy (application_t * app)
1301{
1302 u16 transports = app->proxied_transports;
Florin Coras561af9b2017-12-09 10:19:43 -08001303 transport_proto_t tp;
1304
Florin Coras7999e832017-10-31 01:51:04 -07001305 ASSERT (application_is_proxy (app));
Florin Coras561af9b2017-12-09 10:19:43 -08001306
1307 /* *INDENT-OFF* */
1308 transport_proto_foreach (tp, ({
1309 if (transports & (1 << tp))
1310 application_start_stop_proxy (app, tp, 0);
1311 }));
1312 /* *INDENT-ON* */
Florin Coras7999e832017-10-31 01:51:04 -07001313}
1314
Florin Coras88001c62019-04-24 14:44:46 -07001315segment_manager_props_t *
Florin Corasa332c462018-01-31 06:52:17 -08001316application_segment_manager_properties (application_t * app)
1317{
1318 return &app->sm_properties;
1319}
1320
Florin Coras88001c62019-04-24 14:44:46 -07001321segment_manager_props_t *
Florin Corasa332c462018-01-31 06:52:17 -08001322application_get_segment_manager_properties (u32 app_index)
1323{
1324 application_t *app = application_get (app_index);
1325 return &app->sm_properties;
1326}
1327
Florin Coras371ca502018-02-21 12:07:41 -08001328clib_error_t *
1329vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1330{
1331 application_t *app;
1332 app = application_get (a->app_index);
1333 if (!app)
1334 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1335 0, "app %u doesn't exist", a->app_index);
1336 app->tls_cert = vec_dup (a->cert);
1337 return 0;
1338}
1339
1340clib_error_t *
1341vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1342{
1343 application_t *app;
1344 app = application_get (a->app_index);
1345 if (!app)
1346 return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1347 0, "app %u doesn't exist", a->app_index);
1348 app->tls_key = vec_dup (a->key);
1349 return 0;
1350}
1351
Florin Coras15531972018-08-12 23:50:53 -07001352static void
1353application_format_listeners (application_t * app, int verbose)
1354{
1355 vlib_main_t *vm = vlib_get_main ();
1356 app_worker_map_t *wrk_map;
1357 app_worker_t *app_wrk;
1358 u32 sm_index;
1359 u64 handle;
1360
1361 if (!app)
1362 {
1363 vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1364 0, 0, verbose);
1365 return;
1366 }
1367
1368 /* *INDENT-OFF* */
1369 pool_foreach (wrk_map, app->worker_maps, ({
1370 app_wrk = app_worker_get (wrk_map->wrk_index);
1371 if (hash_elts (app_wrk->listeners_table) == 0)
1372 continue;
1373 hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1374 vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1375 handle, sm_index, verbose);
1376 }));
1377 }));
1378 /* *INDENT-ON* */
1379}
1380
1381static void
Florin Coras15531972018-08-12 23:50:53 -07001382application_format_connects (application_t * app, int verbose)
1383{
1384 app_worker_map_t *wrk_map;
1385 app_worker_t *app_wrk;
1386
1387 if (!app)
1388 {
1389 app_worker_format_connects (0, verbose);
1390 return;
1391 }
1392
1393 /* *INDENT-OFF* */
1394 pool_foreach (wrk_map, app->worker_maps, ({
1395 app_wrk = app_worker_get (wrk_map->wrk_index);
1396 app_worker_format_connects (app_wrk, verbose);
1397 }));
1398 /* *INDENT-ON* */
1399}
1400
Florin Coras6cf30ad2017-04-04 23:08:23 -07001401u8 *
1402format_application (u8 * s, va_list * args)
1403{
1404 application_t *app = va_arg (*args, application_t *);
1405 CLIB_UNUSED (int verbose) = va_arg (*args, int);
Florin Coras88001c62019-04-24 14:44:46 -07001406 segment_manager_props_t *props;
Florin Coras053a0e42018-11-13 15:52:38 -08001407 const u8 *app_ns_name, *app_name;
Florin Coras349f8ca2018-11-20 16:52:49 -08001408 app_worker_map_t *wrk_map;
1409 app_worker_t *app_wrk;
Florin Coras6cf30ad2017-04-04 23:08:23 -07001410
1411 if (app == 0)
1412 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001413 if (!verbose)
Florin Corasc1f5a432018-11-20 11:31:26 -08001414 s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
Florin Coras6cf30ad2017-04-04 23:08:23 -07001415 return s;
1416 }
1417
Florin Coras0bee9ce2018-03-22 21:24:31 -07001418 app_name = app_get_name (app);
Florin Corascea194d2017-10-02 00:18:51 -07001419 app_ns_name = app_namespace_id_from_index (app->ns_index);
Florin Corasa332c462018-01-31 06:52:17 -08001420 props = application_segment_manager_properties (app);
Florin Coras349f8ca2018-11-20 16:52:49 -08001421 if (!verbose)
1422 {
Florin Corasfa7512e2019-04-04 22:31:50 -07001423 s = format (s, "%-10u%-20v%-40s", app->app_index, app_name,
Florin Coras349f8ca2018-11-20 16:52:49 -08001424 app_ns_name);
1425 return s;
1426 }
1427
Florin Corasfa7512e2019-04-04 22:31:50 -07001428 s = format (s, "app-name %v app-index %u ns-index %u seg-size %U\n",
Florin Coras349f8ca2018-11-20 16:52:49 -08001429 app_name, app->app_index, app->ns_index,
1430 format_memory_size, props->add_segment_size);
1431 s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1432 format_memory_size, props->rx_fifo_size,
1433 format_memory_size, props->tx_fifo_size);
1434
1435 /* *INDENT-OFF* */
1436 pool_foreach (wrk_map, app->worker_maps, ({
1437 app_wrk = app_worker_get (wrk_map->wrk_index);
Florin Coras623eb562019-02-03 19:28:34 -08001438 s = format (s, "%U", format_app_worker, app_wrk);
Florin Coras349f8ca2018-11-20 16:52:49 -08001439 }));
1440 /* *INDENT-ON* */
1441
Dave Barach68b0fb02017-02-28 15:15:56 -05001442 return s;
1443}
1444
Florin Corasf8f516a2018-02-08 15:10:09 -08001445void
Florin Coras2b81e3c2019-02-27 07:55:46 -08001446application_format_all_listeners (vlib_main_t * vm, int verbose)
Florin Corasf8f516a2018-02-08 15:10:09 -08001447{
1448 application_t *app;
Florin Corasf8f516a2018-02-08 15:10:09 -08001449
Florin Coras15531972018-08-12 23:50:53 -07001450 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001451 {
1452 vlib_cli_output (vm, "No active server bindings");
1453 return;
1454 }
1455
Florin Coras2b81e3c2019-02-27 07:55:46 -08001456 application_format_listeners (0, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001457
Florin Coras2b81e3c2019-02-27 07:55:46 -08001458 /* *INDENT-OFF* */
1459 pool_foreach (app, app_main.app_pool, ({
1460 application_format_listeners (app, verbose);
1461 }));
1462 /* *INDENT-ON* */
Florin Corasf8f516a2018-02-08 15:10:09 -08001463}
1464
1465void
Florin Coras2b81e3c2019-02-27 07:55:46 -08001466application_format_all_clients (vlib_main_t * vm, int verbose)
Florin Corasf8f516a2018-02-08 15:10:09 -08001467{
1468 application_t *app;
1469
Florin Coras15531972018-08-12 23:50:53 -07001470 if (!pool_elts (app_main.app_pool))
Florin Corasf8f516a2018-02-08 15:10:09 -08001471 {
1472 vlib_cli_output (vm, "No active apps");
1473 return;
1474 }
1475
Florin Coras2b81e3c2019-02-27 07:55:46 -08001476 application_format_connects (0, verbose);
Florin Corasf8f516a2018-02-08 15:10:09 -08001477
Florin Coras2b81e3c2019-02-27 07:55:46 -08001478 /* *INDENT-OFF* */
1479 pool_foreach (app, app_main.app_pool, ({
1480 application_format_connects (app, verbose);
1481 }));
1482 /* *INDENT-ON* */
Florin Corasf8f516a2018-02-08 15:10:09 -08001483}
1484
Dave Barach68b0fb02017-02-28 15:15:56 -05001485static clib_error_t *
1486show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1487 vlib_cli_command_t * cmd)
1488{
Florin Coras2b81e3c2019-02-27 07:55:46 -08001489 int do_server = 0, do_client = 0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001490 application_t *app;
Florin Coras349f8ca2018-11-20 16:52:49 -08001491 u32 app_index = ~0;
Dave Barach68b0fb02017-02-28 15:15:56 -05001492 int verbose = 0;
1493
Florin Corascea194d2017-10-02 00:18:51 -07001494 session_cli_return_if_not_enabled ();
Florin Corase04c2992017-03-01 08:17:34 -08001495
Dave Barach68b0fb02017-02-28 15:15:56 -05001496 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1497 {
1498 if (unformat (input, "server"))
1499 do_server = 1;
1500 else if (unformat (input, "client"))
1501 do_client = 1;
Florin Coras349f8ca2018-11-20 16:52:49 -08001502 else if (unformat (input, "%u", &app_index))
1503 ;
Dave Barach68b0fb02017-02-28 15:15:56 -05001504 else if (unformat (input, "verbose"))
1505 verbose = 1;
1506 else
Florin Coras349f8ca2018-11-20 16:52:49 -08001507 return clib_error_return (0, "unknown input `%U'",
1508 format_unformat_error, input);
Dave Barach68b0fb02017-02-28 15:15:56 -05001509 }
1510
1511 if (do_server)
Florin Coras349f8ca2018-11-20 16:52:49 -08001512 {
Florin Coras2b81e3c2019-02-27 07:55:46 -08001513 application_format_all_listeners (vm, verbose);
Florin Coras349f8ca2018-11-20 16:52:49 -08001514 return 0;
1515 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001516
1517 if (do_client)
Florin Coras349f8ca2018-11-20 16:52:49 -08001518 {
Florin Coras2b81e3c2019-02-27 07:55:46 -08001519 application_format_all_clients (vm, verbose);
Florin Coras349f8ca2018-11-20 16:52:49 -08001520 return 0;
1521 }
1522
1523 if (app_index != ~0)
1524 {
Florin Coras47c40e22018-11-26 17:01:36 -08001525 app = application_get_if_valid (app_index);
Florin Coras349f8ca2018-11-20 16:52:49 -08001526 if (!app)
1527 return clib_error_return (0, "No app with index %u", app_index);
1528
1529 vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1530 return 0;
1531 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001532
Florin Coras6cf30ad2017-04-04 23:08:23 -07001533 /* Print app related info */
1534 if (!do_server && !do_client)
1535 {
Florin Coras349f8ca2018-11-20 16:52:49 -08001536 vlib_cli_output (vm, "%U", format_application, 0, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001537 /* *INDENT-OFF* */
Florin Coras15531972018-08-12 23:50:53 -07001538 pool_foreach (app, app_main.app_pool, ({
Florin Coras349f8ca2018-11-20 16:52:49 -08001539 vlib_cli_output (vm, "%U", format_application, app, 0);
Florin Corascea194d2017-10-02 00:18:51 -07001540 }));
1541 /* *INDENT-ON* */
Florin Coras6cf30ad2017-04-04 23:08:23 -07001542 }
1543
Dave Barach68b0fb02017-02-28 15:15:56 -05001544 return 0;
1545}
1546
Florin Corase04c2992017-03-01 08:17:34 -08001547/* *INDENT-OFF* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001548VLIB_CLI_COMMAND (show_app_command, static) =
1549{
Florin Corase04c2992017-03-01 08:17:34 -08001550 .path = "show app",
1551 .short_help = "show app [server|client] [verbose]",
1552 .function = show_app_command_fn,
1553};
1554/* *INDENT-ON* */
Dave Barach68b0fb02017-02-28 15:15:56 -05001555
1556/*
1557 * fd.io coding-style-patch-verification: ON
1558 *
1559 * Local Variables:
1560 * eval: (c-set-style "gnu")
1561 * End:
1562 */