session: Add certificate store
[vpp.git] / src / vnet / session / application.c
1 /*
2  * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
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>
17 #include <vnet/session/application_interface.h>
18 #include <vnet/session/application_namespace.h>
19 #include <vnet/session/application_local.h>
20 #include <vnet/session/session.h>
21
22 static app_main_t app_main;
23
24 #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
31 static app_listener_t *
32 app_listener_alloc (application_t * app)
33 {
34   app_listener_t *app_listener;
35   pool_get (app->listeners, app_listener);
36   clib_memset (app_listener, 0, sizeof (*app_listener));
37   app_listener->al_index = app_listener - app->listeners;
38   app_listener->app_index = app->app_index;
39   app_listener->session_index = SESSION_INVALID_INDEX;
40   app_listener->local_index = SESSION_INVALID_INDEX;
41   app_listener->ls_handle = SESSION_INVALID_HANDLE;
42   return app_listener;
43 }
44
45 app_listener_t *
46 app_listener_get (application_t * app, u32 app_listener_index)
47 {
48   return pool_elt_at_index (app->listeners, app_listener_index);
49 }
50
51 static void
52 app_listener_free (application_t * app, app_listener_t * app_listener)
53 {
54   clib_bitmap_free (app_listener->workers);
55   if (CLIB_DEBUG)
56     clib_memset (app_listener, 0xfa, sizeof (*app_listener));
57   pool_put (app->listeners, app_listener);
58 }
59
60 session_handle_t
61 app_listener_handle (app_listener_t * al)
62 {
63   return al->ls_handle;
64 }
65
66 app_listener_t *
67 app_listener_get_w_session (session_t * ls)
68 {
69   application_t *app;
70
71   app = application_get_if_valid (ls->app_index);
72   if (!app)
73     return 0;
74   return app_listener_get (app, ls->al_index);
75 }
76
77 session_handle_t
78 app_listen_session_handle (session_t * ls)
79 {
80   app_listener_t *al;
81   al = app_listener_get_w_session (ls);
82   if (!al)
83     return listen_session_get_handle (ls);
84   return al->ls_handle;
85 }
86
87 app_listener_t *
88 app_listener_get_w_handle (session_handle_t handle)
89 {
90   session_t *ls;
91   ls = session_get_from_handle_if_valid (handle);
92   if (!ls)
93     return 0;
94   return app_listener_get_w_session (ls);
95 }
96
97 app_listener_t *
98 app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
99 {
100   u32 table_index, fib_proto;
101   session_endpoint_t *sep;
102   session_handle_t handle;
103   session_t *ls;
104
105   sep = (session_endpoint_t *) sep_ext;
106   if (application_has_local_scope (app) && session_endpoint_is_local (sep))
107     {
108       table_index = application_local_session_table (app);
109       handle = session_lookup_endpoint_listener (table_index, sep, 1);
110       if (handle != SESSION_INVALID_HANDLE)
111         {
112           ls = listen_session_get_from_handle (handle);
113           return app_listener_get_w_session (ls);
114         }
115     }
116
117   fib_proto = session_endpoint_fib_proto (sep);
118   table_index = application_session_table (app, fib_proto);
119   handle = session_lookup_endpoint_listener (table_index, sep, 1);
120   if (handle != SESSION_INVALID_HANDLE)
121     {
122       ls = listen_session_get_from_handle (handle);
123       return app_listener_get_w_session ((session_t *) ls);
124     }
125
126   return 0;
127 }
128
129 int
130 app_listener_alloc_and_init (application_t * app,
131                              session_endpoint_cfg_t * sep,
132                              app_listener_t ** listener)
133 {
134   app_listener_t *app_listener;
135   transport_connection_t *tc;
136   session_handle_t lh;
137   session_type_t st;
138   session_t *ls = 0;
139   u32 al_index;
140   int rv;
141
142   app_listener = app_listener_alloc (app);
143   al_index = app_listener->al_index;
144   st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
145
146   /*
147    * Add session endpoint to local session table. Only binds to "inaddr_any"
148    * (i.e., zero address) are added to local scope table.
149    */
150   if (application_has_local_scope (app)
151       && session_endpoint_is_local ((session_endpoint_t *) sep))
152     {
153       session_type_t local_st;
154       u32 table_index;
155
156       local_st = session_type_from_proto_and_ip (TRANSPORT_PROTO_NONE,
157                                                  sep->is_ip4);
158       ls = listen_session_alloc (0, local_st);
159       ls->app_index = app->app_index;
160       ls->app_wrk_index = sep->app_wrk_index;
161       lh = session_handle (ls);
162
163       if ((rv = session_listen (ls, sep)))
164         {
165           ls = session_get_from_handle (lh);
166           session_free (ls);
167           return rv;
168         }
169
170       ls = session_get_from_handle (lh);
171       app_listener = app_listener_get (app, al_index);
172       app_listener->local_index = ls->session_index;
173       app_listener->ls_handle = lh;
174       ls->al_index = al_index;
175
176       table_index = application_local_session_table (app);
177       session_lookup_add_session_endpoint (table_index,
178                                            (session_endpoint_t *) sep, lh);
179     }
180
181   if (application_has_global_scope (app))
182     {
183       /*
184        * Start listening on local endpoint for requested transport and scope.
185        * Creates a stream session with state LISTENING to be used in session
186        * lookups, prior to establishing connection. Requests transport to
187        * build it's own specific listening connection.
188        */
189       ls = listen_session_alloc (0, st);
190       ls->app_index = app->app_index;
191       ls->app_wrk_index = sep->app_wrk_index;
192
193       /* Listen pool can be reallocated if the transport is
194        * recursive (tls) */
195       lh = listen_session_get_handle (ls);
196
197       if ((rv = session_listen (ls, sep)))
198         {
199           ls = listen_session_get_from_handle (lh);
200           session_free (ls);
201           return rv;
202         }
203       ls = listen_session_get_from_handle (lh);
204       app_listener = app_listener_get (app, al_index);
205       app_listener->session_index = ls->session_index;
206       app_listener->ls_handle = lh;
207       ls->al_index = al_index;
208
209       /* Add to the global lookup table after transport was initialized.
210        * Lookup table needs to be populated only now because sessions
211        * with cut-through transport are are added to app local tables that
212        * are not related to network fibs, i.e., cannot be added as
213        * connections */
214       tc = session_get_transport (ls);
215       if (!(tc->flags & TRANSPORT_CONNECTION_F_NO_LOOKUP))
216         session_lookup_add_connection (tc, lh);
217     }
218
219   if (!ls)
220     {
221       app_listener_free (app, app_listener);
222       return -1;
223     }
224
225   *listener = app_listener;
226   return 0;
227 }
228
229 void
230 app_listener_cleanup (app_listener_t * al)
231 {
232   application_t *app = application_get (al->app_index);
233   session_t *ls;
234
235   if (al->session_index != SESSION_INVALID_INDEX)
236     {
237       ls = session_get (al->session_index, 0);
238       session_stop_listen (ls);
239       listen_session_free (ls);
240     }
241   if (al->local_index != SESSION_INVALID_INDEX)
242     {
243       session_endpoint_t sep = SESSION_ENDPOINT_NULL;
244       u32 table_index;
245
246       table_index = application_local_session_table (app);
247       ls = listen_session_get (al->local_index);
248       ct_session_endpoint (ls, &sep);
249       session_lookup_del_session_endpoint (table_index, &sep);
250       session_stop_listen (ls);
251       listen_session_free (ls);
252     }
253   app_listener_free (app, al);
254 }
255
256 static app_worker_t *
257 app_listener_select_worker (application_t * app, app_listener_t * al)
258 {
259   u32 wrk_index;
260
261   app = application_get (al->app_index);
262   wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
263   if (wrk_index == ~0)
264     wrk_index = clib_bitmap_first_set (al->workers);
265
266   ASSERT (wrk_index != ~0);
267   al->accept_rotor = wrk_index;
268   return application_get_worker (app, wrk_index);
269 }
270
271 session_t *
272 app_listener_get_session (app_listener_t * al)
273 {
274   if (al->session_index == SESSION_INVALID_INDEX)
275     return 0;
276
277   return listen_session_get (al->session_index);
278 }
279
280 session_t *
281 app_listener_get_local_session (app_listener_t * al)
282 {
283   if (al->local_index == SESSION_INVALID_INDEX)
284     return 0;
285   return listen_session_get (al->local_index);
286 }
287
288 static app_worker_map_t *
289 app_worker_map_alloc (application_t * app)
290 {
291   app_worker_map_t *map;
292   pool_get (app->worker_maps, map);
293   clib_memset (map, 0, sizeof (*map));
294   return map;
295 }
296
297 static u32
298 app_worker_map_index (application_t * app, app_worker_map_t * map)
299 {
300   return (map - app->worker_maps);
301 }
302
303 static void
304 app_worker_map_free (application_t * app, app_worker_map_t * map)
305 {
306   pool_put (app->worker_maps, map);
307 }
308
309 static app_worker_map_t *
310 app_worker_map_get (application_t * app, u32 map_index)
311 {
312   if (pool_is_free_index (app->worker_maps, map_index))
313     return 0;
314   return pool_elt_at_index (app->worker_maps, map_index);
315 }
316
317 static const u8 *
318 app_get_name (application_t * app)
319 {
320   return app->name;
321 }
322
323 u32
324 application_session_table (application_t * app, u8 fib_proto)
325 {
326   app_namespace_t *app_ns;
327   app_ns = app_namespace_get (app->ns_index);
328   if (!application_has_global_scope (app))
329     return APP_INVALID_INDEX;
330   if (fib_proto == FIB_PROTOCOL_IP4)
331     return session_lookup_get_index_for_fib (fib_proto,
332                                              app_ns->ip4_fib_index);
333   else
334     return session_lookup_get_index_for_fib (fib_proto,
335                                              app_ns->ip6_fib_index);
336 }
337
338 u32
339 application_local_session_table (application_t * app)
340 {
341   app_namespace_t *app_ns;
342   if (!application_has_local_scope (app))
343     return APP_INVALID_INDEX;
344   app_ns = app_namespace_get (app->ns_index);
345   return app_ns->local_table_index;
346 }
347
348 /**
349  * Returns app name for app-index
350  */
351 const u8 *
352 application_name_from_index (u32 app_index)
353 {
354   application_t *app = application_get (app_index);
355   if (!app)
356     return 0;
357   return app_get_name (app);
358 }
359
360 static void
361 application_api_table_add (u32 app_index, u32 api_client_index)
362 {
363   if (api_client_index != APP_INVALID_INDEX)
364     hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
365 }
366
367 static void
368 application_api_table_del (u32 api_client_index)
369 {
370   hash_unset (app_main.app_by_api_client_index, api_client_index);
371 }
372
373 static void
374 application_name_table_add (application_t * app)
375 {
376   hash_set_mem (app_main.app_by_name, app->name, app->app_index);
377 }
378
379 static void
380 application_name_table_del (application_t * app)
381 {
382   hash_unset_mem (app_main.app_by_name, app->name);
383 }
384
385 application_t *
386 application_lookup (u32 api_client_index)
387 {
388   uword *p;
389   p = hash_get (app_main.app_by_api_client_index, api_client_index);
390   if (p)
391     return application_get_if_valid (p[0]);
392
393   return 0;
394 }
395
396 application_t *
397 application_lookup_name (const u8 * name)
398 {
399   uword *p;
400   p = hash_get_mem (app_main.app_by_name, name);
401   if (p)
402     return application_get (p[0]);
403
404   return 0;
405 }
406
407 static application_t *
408 application_alloc (void)
409 {
410   application_t *app;
411   pool_get (app_main.app_pool, app);
412   clib_memset (app, 0, sizeof (*app));
413   app->app_index = app - app_main.app_pool;
414   return app;
415 }
416
417 application_t *
418 application_get (u32 app_index)
419 {
420   if (app_index == APP_INVALID_INDEX)
421     return 0;
422   return pool_elt_at_index (app_main.app_pool, app_index);
423 }
424
425 application_t *
426 application_get_if_valid (u32 app_index)
427 {
428   if (pool_is_free_index (app_main.app_pool, app_index))
429     return 0;
430
431   return pool_elt_at_index (app_main.app_pool, app_index);
432 }
433
434 static void
435 application_verify_cb_fns (session_cb_vft_t * cb_fns)
436 {
437   if (cb_fns->session_accept_callback == 0)
438     clib_warning ("No accept callback function provided");
439   if (cb_fns->session_connected_callback == 0)
440     clib_warning ("No session connected callback function provided");
441   if (cb_fns->session_disconnect_callback == 0)
442     clib_warning ("No session disconnect callback function provided");
443   if (cb_fns->session_reset_callback == 0)
444     clib_warning ("No session reset callback function provided");
445 }
446
447 /**
448  * Check app config for given segment type
449  *
450  * Returns 1 on success and 0 otherwise
451  */
452 static u8
453 application_verify_cfg (ssvm_segment_type_t st)
454 {
455   u8 is_valid;
456   if (st == SSVM_SEGMENT_MEMFD)
457     {
458       is_valid = (session_main_get_evt_q_segment () != 0);
459       if (!is_valid)
460         clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
461       return is_valid;
462     }
463   else if (st == SSVM_SEGMENT_SHM)
464     {
465       is_valid = (session_main_get_evt_q_segment () == 0);
466       if (!is_valid)
467         clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
468       return is_valid;
469     }
470   else
471     return 1;
472 }
473
474 static int
475 application_alloc_and_init (app_init_args_t * a)
476 {
477   ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
478   segment_manager_props_t *props;
479   vl_api_registration_t *reg;
480   application_t *app;
481   u64 *options;
482
483   app = application_alloc ();
484   options = a->options;
485   /*
486    * Make sure we support the requested configuration
487    */
488   if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
489     {
490       reg = vl_api_client_index_to_registration (a->api_client_index);
491       if (!reg)
492         return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
493       if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
494         seg_type = SSVM_SEGMENT_SHM;
495     }
496   else
497     {
498       seg_type = SSVM_SEGMENT_PRIVATE;
499     }
500
501   if ((options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
502       && seg_type != SSVM_SEGMENT_MEMFD)
503     {
504       clib_warning ("mq eventfds can only be used if socket transport is "
505                     "used for binary api");
506       return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
507     }
508
509   if (!application_verify_cfg (seg_type))
510     return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
511
512   /* Check that the obvious things are properly set up */
513   application_verify_cb_fns (a->session_cb_vft);
514
515   app->flags = options[APP_OPTIONS_FLAGS];
516   app->cb_fns = *a->session_cb_vft;
517   app->ns_index = options[APP_OPTIONS_NAMESPACE];
518   app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
519   app->name = vec_dup (a->name);
520
521   /* If no scope enabled, default to global */
522   if (!application_has_global_scope (app)
523       && !application_has_local_scope (app))
524     app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
525
526   props = application_segment_manager_properties (app);
527   segment_manager_props_init (props);
528   props->segment_size = options[APP_OPTIONS_SEGMENT_SIZE];
529   props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
530   if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
531     {
532       props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
533       props->add_segment = 1;
534     }
535   if (options[APP_OPTIONS_RX_FIFO_SIZE])
536     props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
537   if (options[APP_OPTIONS_TX_FIFO_SIZE])
538     props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
539   if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
540     props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
541   if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
542     props->use_mq_eventfd = 1;
543   if (options[APP_OPTIONS_TLS_ENGINE])
544     app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
545   props->segment_type = seg_type;
546
547   /* Add app to lookup by api_client_index table */
548   if (!application_is_builtin (app))
549     application_api_table_add (app->app_index, a->api_client_index);
550   else
551     application_name_table_add (app);
552
553   a->app_index = app->app_index;
554
555   APP_DBG ("New app name: %v api index: %u index %u", app->name,
556            a->api_client_index, app->app_index);
557
558   return 0;
559 }
560
561 static void
562 application_free (application_t * app)
563 {
564   app_worker_map_t *wrk_map;
565   app_worker_t *app_wrk;
566
567   /*
568    * The app event queue allocated in first segment is cleared with
569    * the segment manager. No need to explicitly free it.
570    */
571   APP_DBG ("Delete app name %v index: %d", app->name, app->app_index);
572
573   if (application_is_proxy (app))
574     application_remove_proxy (app);
575
576   /*
577    * Free workers
578    */
579
580   /* *INDENT-OFF* */
581   pool_flush (wrk_map, app->worker_maps, ({
582     app_wrk = app_worker_get (wrk_map->wrk_index);
583     app_worker_free (app_wrk);
584   }));
585   /* *INDENT-ON* */
586   pool_free (app->worker_maps);
587
588   /*
589    * Cleanup remaining state
590    */
591   if (application_is_builtin (app))
592     application_name_table_del (app);
593   vec_free (app->name);
594   pool_put (app_main.app_pool, app);
595 }
596
597 static void
598 application_detach_process (application_t * app, u32 api_client_index)
599 {
600   vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
601   app_worker_map_t *wrk_map;
602   u32 *wrks = 0, *wrk_index;
603   app_worker_t *app_wrk;
604
605   if (api_client_index == ~0)
606     {
607       application_free (app);
608       return;
609     }
610
611   APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
612            app->app_index, api_client_index);
613
614   /* *INDENT-OFF* */
615   pool_foreach (wrk_map, app->worker_maps, ({
616     app_wrk = app_worker_get (wrk_map->wrk_index);
617     if (app_wrk->api_client_index == api_client_index)
618       vec_add1 (wrks, app_wrk->wrk_index);
619   }));
620   /* *INDENT-ON* */
621
622   if (!vec_len (wrks))
623     {
624       clib_warning ("no workers for app %u api_index %u", app->app_index,
625                     api_client_index);
626       return;
627     }
628
629   args->app_index = app->app_index;
630   args->api_client_index = api_client_index;
631   vec_foreach (wrk_index, wrks)
632   {
633     app_wrk = app_worker_get (wrk_index[0]);
634     args->wrk_map_index = app_wrk->wrk_map_index;
635     args->is_add = 0;
636     vnet_app_worker_add_del (args);
637   }
638   vec_free (wrks);
639 }
640
641 app_worker_t *
642 application_get_worker (application_t * app, u32 wrk_map_index)
643 {
644   app_worker_map_t *map;
645   map = app_worker_map_get (app, wrk_map_index);
646   if (!map)
647     return 0;
648   return app_worker_get (map->wrk_index);
649 }
650
651 app_worker_t *
652 application_get_default_worker (application_t * app)
653 {
654   return application_get_worker (app, 0);
655 }
656
657 u32
658 application_n_workers (application_t * app)
659 {
660   return pool_elts (app->worker_maps);
661 }
662
663 app_worker_t *
664 application_listener_select_worker (session_t * ls)
665 {
666   application_t *app;
667   app_listener_t *al;
668
669   app = application_get (ls->app_index);
670   al = app_listener_get (app, ls->al_index);
671   return app_listener_select_worker (app, al);
672 }
673
674 int
675 application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
676 {
677   app_worker_map_t *wrk_map;
678   app_worker_t *app_wrk;
679   segment_manager_t *sm;
680   int rv;
681
682   app_wrk = app_worker_alloc (app);
683   wrk_map = app_worker_map_alloc (app);
684   wrk_map->wrk_index = app_wrk->wrk_index;
685   app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
686
687   /*
688    * Setup first segment manager
689    */
690   sm = segment_manager_alloc ();
691   sm->app_wrk_index = app_wrk->wrk_index;
692
693   if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
694                                   app->sm_properties.prealloc_fifos)))
695     {
696       app_worker_free (app_wrk);
697       return rv;
698     }
699   sm->first_is_protected = 1;
700
701   /*
702    * Setup app worker
703    */
704   app_wrk->first_segment_manager = segment_manager_index (sm);
705   app_wrk->listeners_table = hash_create (0, sizeof (u64));
706   app_wrk->event_queue = segment_manager_event_queue (sm);
707   app_wrk->app_is_builtin = application_is_builtin (app);
708
709   *wrk = app_wrk;
710
711   return 0;
712 }
713
714 int
715 vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
716 {
717   fifo_segment_t *fs;
718   app_worker_map_t *wrk_map;
719   app_worker_t *app_wrk;
720   segment_manager_t *sm;
721   application_t *app;
722   int rv;
723
724   app = application_get (a->app_index);
725   if (!app)
726     return VNET_API_ERROR_INVALID_VALUE;
727
728   if (a->is_add)
729     {
730       if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
731         return rv;
732
733       /* Map worker api index to the app */
734       app_wrk->api_client_index = a->api_client_index;
735       application_api_table_add (app->app_index, a->api_client_index);
736
737       sm = segment_manager_get (app_wrk->first_segment_manager);
738       fs = segment_manager_get_segment_w_lock (sm, 0);
739       a->segment = &fs->ssvm;
740       a->segment_handle = segment_manager_segment_handle (sm, fs);
741       segment_manager_segment_reader_unlock (sm);
742       a->evt_q = app_wrk->event_queue;
743       a->wrk_map_index = app_wrk->wrk_map_index;
744     }
745   else
746     {
747       wrk_map = app_worker_map_get (app, a->wrk_map_index);
748       if (!wrk_map)
749         return VNET_API_ERROR_INVALID_VALUE;
750
751       app_wrk = app_worker_get (wrk_map->wrk_index);
752       if (!app_wrk)
753         return VNET_API_ERROR_INVALID_VALUE;
754
755       application_api_table_del (app_wrk->api_client_index);
756       app_worker_free (app_wrk);
757       app_worker_map_free (app, wrk_map);
758       if (application_n_workers (app) == 0)
759         application_free (app);
760     }
761   return 0;
762 }
763
764 static int
765 app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
766 {
767   app_namespace_t *app_ns;
768   if (vec_len (namespace_id) == 0)
769     {
770       /* Use default namespace */
771       *app_ns_index = 0;
772       return 0;
773     }
774
775   *app_ns_index = app_namespace_index_from_id (namespace_id);
776   if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
777     return VNET_API_ERROR_APP_INVALID_NS;
778   app_ns = app_namespace_get (*app_ns_index);
779   if (!app_ns)
780     return VNET_API_ERROR_APP_INVALID_NS;
781   if (app_ns->ns_secret != secret)
782     return VNET_API_ERROR_APP_WRONG_NS_SECRET;
783   return 0;
784 }
785
786 static u8 *
787 app_name_from_api_index (u32 api_client_index)
788 {
789   vl_api_registration_t *regp;
790   regp = vl_api_client_index_to_registration (api_client_index);
791   if (regp)
792     return format (0, "%s", regp->name);
793
794   clib_warning ("api client index %u does not have an api registration!",
795                 api_client_index);
796   return format (0, "unknown");
797 }
798
799 /**
800  * Attach application to vpp
801  *
802  * Allocates a vpp app, i.e., a structure that keeps back pointers
803  * to external app and a segment manager for shared memory fifo based
804  * communication with the external app.
805  */
806 int
807 vnet_application_attach (vnet_app_attach_args_t * a)
808 {
809   fifo_segment_t *fs;
810   application_t *app = 0;
811   app_worker_t *app_wrk;
812   segment_manager_t *sm;
813   u32 app_ns_index = 0;
814   u8 *app_name = 0;
815   u64 secret;
816   int rv;
817
818   if (a->api_client_index != APP_INVALID_INDEX)
819     app = application_lookup (a->api_client_index);
820   else if (a->name)
821     app = application_lookup_name (a->name);
822   else
823     return VNET_API_ERROR_INVALID_VALUE;
824
825   if (app)
826     return VNET_API_ERROR_APP_ALREADY_ATTACHED;
827
828   if (a->api_client_index != APP_INVALID_INDEX)
829     {
830       app_name = app_name_from_api_index (a->api_client_index);
831       a->name = app_name;
832     }
833
834   secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
835   if ((rv = app_validate_namespace (a->namespace_id, secret, &app_ns_index)))
836     return rv;
837   a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
838
839   if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
840     return rv;
841
842   app = application_get (a->app_index);
843   if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
844     return rv;
845
846   a->app_evt_q = app_wrk->event_queue;
847   app_wrk->api_client_index = a->api_client_index;
848   sm = segment_manager_get (app_wrk->first_segment_manager);
849   fs = segment_manager_get_segment_w_lock (sm, 0);
850
851   if (application_is_proxy (app))
852     application_setup_proxy (app);
853
854   ASSERT (vec_len (fs->ssvm.name) <= 128);
855   a->segment = &fs->ssvm;
856   a->segment_handle = segment_manager_segment_handle (sm, fs);
857
858   segment_manager_segment_reader_unlock (sm);
859   vec_free (app_name);
860   return 0;
861 }
862
863 /**
864  * Detach application from vpp
865  */
866 int
867 vnet_application_detach (vnet_app_detach_args_t * a)
868 {
869   application_t *app;
870
871   app = application_get_if_valid (a->app_index);
872   if (!app)
873     {
874       clib_warning ("app not attached");
875       return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
876     }
877
878   app_interface_check_thread_and_barrier (vnet_application_detach, a);
879   application_detach_process (app, a->api_client_index);
880   return 0;
881 }
882
883
884 static u8
885 session_endpoint_in_ns (session_endpoint_t * sep)
886 {
887   u8 is_lep = session_endpoint_is_local (sep);
888   if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
889       && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
890     {
891       clib_warning ("sw_if_index %u not configured with ip %U",
892                     sep->sw_if_index, format_ip46_address, &sep->ip,
893                     sep->is_ip4);
894       return 0;
895     }
896   return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
897 }
898
899 static void
900 session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
901                                  application_t * app, u8 is_connect)
902 {
903   app_namespace_t *app_ns;
904   u32 ns_index, fib_index;
905
906   ns_index = app->ns_index;
907
908   /* App is a transport proto, so fetch the calling app's ns */
909   if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
910     ns_index = sep->ns_index;
911
912   app_ns = app_namespace_get (ns_index);
913   if (!app_ns)
914     return;
915
916   /* Ask transport and network to bind to/connect using local interface
917    * that "supports" app's namespace. This will fix our local connection
918    * endpoint.
919    */
920
921   /* If in default namespace and user requested a fib index use it */
922   if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
923     fib_index = sep->fib_index;
924   else
925     fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
926   sep->peer.fib_index = fib_index;
927   sep->fib_index = fib_index;
928
929   if (!is_connect)
930     {
931       sep->sw_if_index = app_ns->sw_if_index;
932     }
933   else
934     {
935       if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
936           && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
937           && sep->peer.sw_if_index != app_ns->sw_if_index)
938         clib_warning ("Local sw_if_index different from app ns sw_if_index");
939
940       sep->peer.sw_if_index = app_ns->sw_if_index;
941     }
942 }
943
944 int
945 vnet_listen (vnet_listen_args_t * a)
946 {
947   app_listener_t *app_listener;
948   app_worker_t *app_wrk;
949   application_t *app;
950   int rv;
951
952   ASSERT (vlib_thread_is_main_w_barrier ());
953
954   app = application_get_if_valid (a->app_index);
955   if (!app)
956     return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
957
958   app_wrk = application_get_worker (app, a->wrk_map_index);
959   if (!app_wrk)
960     return VNET_API_ERROR_INVALID_VALUE;
961
962   a->sep_ext.app_wrk_index = app_wrk->wrk_index;
963
964   session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
965   if (!session_endpoint_in_ns (&a->sep))
966     return VNET_API_ERROR_INVALID_VALUE_2;
967
968   /*
969    * Check if we already have an app listener
970    */
971   app_listener = app_listener_lookup (app, &a->sep_ext);
972   if (app_listener)
973     {
974       if (app_listener->app_index != app->app_index)
975         return VNET_API_ERROR_ADDRESS_IN_USE;
976       if (app_worker_start_listen (app_wrk, app_listener))
977         return -1;
978       a->handle = app_listener_handle (app_listener);
979       return 0;
980     }
981
982   /*
983    * Create new app listener
984    */
985   if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
986     return rv;
987
988   if ((rv = app_worker_start_listen (app_wrk, app_listener)))
989     {
990       app_listener_cleanup (app_listener);
991       return rv;
992     }
993
994   a->handle = app_listener_handle (app_listener);
995   return 0;
996 }
997
998 int
999 vnet_connect (vnet_connect_args_t * a)
1000 {
1001   app_worker_t *client_wrk;
1002   application_t *client;
1003
1004   ASSERT (vlib_thread_is_main_w_barrier ());
1005
1006   if (session_endpoint_is_zero (&a->sep))
1007     return VNET_API_ERROR_INVALID_VALUE;
1008
1009   client = application_get (a->app_index);
1010   session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1011   client_wrk = application_get_worker (client, a->wrk_map_index);
1012
1013   /*
1014    * First check the local scope for locally attached destinations.
1015    * If we have local scope, we pass *all* connects through it since we may
1016    * have special policy rules even for non-local destinations, think proxy.
1017    */
1018   if (application_has_local_scope (client))
1019     {
1020       int rv;
1021
1022       a->sep_ext.original_tp = a->sep_ext.transport_proto;
1023       a->sep_ext.transport_proto = TRANSPORT_PROTO_NONE;
1024       rv = app_worker_connect_session (client_wrk, &a->sep, a->api_context);
1025       if (rv <= 0)
1026         return rv;
1027     }
1028   /*
1029    * Not connecting to a local server, propagate to transport
1030    */
1031   if (app_worker_connect_session (client_wrk, &a->sep, a->api_context))
1032     return VNET_API_ERROR_SESSION_CONNECT;
1033   return 0;
1034 }
1035
1036 int
1037 vnet_unlisten (vnet_unlisten_args_t * a)
1038 {
1039   app_worker_t *app_wrk;
1040   app_listener_t *al;
1041   application_t *app;
1042
1043   ASSERT (vlib_thread_is_main_w_barrier ());
1044
1045   if (!(app = application_get_if_valid (a->app_index)))
1046     return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1047
1048   if (!(al = app_listener_get_w_handle (a->handle)))
1049     return -1;
1050
1051   if (al->app_index != app->app_index)
1052     {
1053       clib_warning ("app doesn't own handle %llu!", a->handle);
1054       return -1;
1055     }
1056
1057   app_wrk = application_get_worker (app, a->wrk_map_index);
1058   if (!app_wrk)
1059     {
1060       clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1061       return -1;
1062     }
1063
1064   return app_worker_stop_listen (app_wrk, al);
1065 }
1066
1067 int
1068 vnet_disconnect_session (vnet_disconnect_args_t * a)
1069 {
1070   app_worker_t *app_wrk;
1071   session_t *s;
1072
1073   s = session_get_from_handle_if_valid (a->handle);
1074   if (!s)
1075     return VNET_API_ERROR_INVALID_VALUE;
1076   app_wrk = app_worker_get (s->app_wrk_index);
1077   if (app_wrk->app_index != a->app_index)
1078     return VNET_API_ERROR_INVALID_VALUE;
1079
1080   /* We're peeking into another's thread pool. Make sure */
1081   ASSERT (s->session_index == session_index_from_handle (a->handle));
1082
1083   session_close (s);
1084   return 0;
1085 }
1086
1087 int
1088 application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1089 {
1090   app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1091   app_listener_t *app_listener;
1092   application_t *app;
1093
1094   if (!old_wrk)
1095     return -1;
1096
1097   hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1098   if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1099       && s->rx_fifo)
1100     segment_manager_dealloc_fifos (s->rx_fifo, s->tx_fifo);
1101
1102   app = application_get (old_wrk->app_index);
1103   if (!app)
1104     return -1;
1105
1106   app_listener = app_listener_get (app, s->al_index);
1107
1108   /* Only remove from lb for now */
1109   app_listener->workers = clib_bitmap_set (app_listener->workers,
1110                                            old_wrk->wrk_map_index, 0);
1111
1112   if (app_worker_start_listen (app_wrk, app_listener))
1113     return -1;
1114
1115   s->app_wrk_index = app_wrk->wrk_index;
1116
1117   return 0;
1118 }
1119
1120 int
1121 application_is_proxy (application_t * app)
1122 {
1123   return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1124 }
1125
1126 int
1127 application_is_builtin (application_t * app)
1128 {
1129   return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1130 }
1131
1132 int
1133 application_is_builtin_proxy (application_t * app)
1134 {
1135   return (application_is_proxy (app) && application_is_builtin (app));
1136 }
1137
1138 u8
1139 application_has_local_scope (application_t * app)
1140 {
1141   return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1142 }
1143
1144 u8
1145 application_has_global_scope (application_t * app)
1146 {
1147   return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1148 }
1149
1150 static clib_error_t *
1151 application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1152                                         u8 transport_proto, u8 is_start)
1153 {
1154   app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1155   u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
1156   session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
1157   transport_connection_t *tc;
1158   app_worker_t *app_wrk;
1159   app_listener_t *al;
1160   session_t *s;
1161   u32 flags;
1162
1163   /* TODO decide if we want proxy to be enabled for all workers */
1164   app_wrk = application_get_default_worker (app);
1165   if (is_start)
1166     {
1167       s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
1168       if (!s)
1169         {
1170           sep.is_ip4 = is_ip4;
1171           sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1172           sep.sw_if_index = app_ns->sw_if_index;
1173           sep.transport_proto = transport_proto;
1174           sep.app_wrk_index = app_wrk->wrk_index;       /* only default */
1175
1176           /* force global scope listener */
1177           flags = app->flags;
1178           app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1179           app_listener_alloc_and_init (app, &sep, &al);
1180           app->flags = flags;
1181
1182           app_worker_start_listen (app_wrk, al);
1183           s = listen_session_get (al->session_index);
1184           s->flags |= SESSION_F_PROXY;
1185         }
1186     }
1187   else
1188     {
1189       s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
1190       ASSERT (s);
1191     }
1192
1193   tc = listen_session_get_transport (s);
1194
1195   if (!ip_is_zero (&tc->lcl_ip, 1))
1196     {
1197       u32 sti;
1198       sep.is_ip4 = is_ip4;
1199       sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1200       sep.transport_proto = transport_proto;
1201       sep.port = 0;
1202       sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
1203       if (is_start)
1204         session_lookup_add_session_endpoint (sti,
1205                                              (session_endpoint_t *) & sep,
1206                                              s->session_index);
1207       else
1208         session_lookup_del_session_endpoint (sti,
1209                                              (session_endpoint_t *) & sep);
1210     }
1211
1212   return 0;
1213 }
1214
1215 static void
1216 application_start_stop_proxy_local_scope (application_t * app,
1217                                           u8 transport_proto, u8 is_start)
1218 {
1219   session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1220   app_namespace_t *app_ns;
1221   app_ns = app_namespace_get (app->ns_index);
1222   sep.is_ip4 = 1;
1223   sep.transport_proto = transport_proto;
1224   sep.port = 0;
1225
1226   if (is_start)
1227     {
1228       session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1229                                            app->app_index);
1230       sep.is_ip4 = 0;
1231       session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1232                                            app->app_index);
1233     }
1234   else
1235     {
1236       session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1237       sep.is_ip4 = 0;
1238       session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1239     }
1240 }
1241
1242 void
1243 application_start_stop_proxy (application_t * app,
1244                               transport_proto_t transport_proto, u8 is_start)
1245 {
1246   if (application_has_local_scope (app))
1247     application_start_stop_proxy_local_scope (app, transport_proto, is_start);
1248
1249   if (application_has_global_scope (app))
1250     {
1251       application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1252                                               transport_proto, is_start);
1253       application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1254                                               transport_proto, is_start);
1255     }
1256 }
1257
1258 void
1259 application_setup_proxy (application_t * app)
1260 {
1261   u16 transports = app->proxied_transports;
1262   transport_proto_t tp;
1263
1264   ASSERT (application_is_proxy (app));
1265
1266   /* *INDENT-OFF* */
1267   transport_proto_foreach (tp, ({
1268     if (transports & (1 << tp))
1269       application_start_stop_proxy (app, tp, 1);
1270   }));
1271   /* *INDENT-ON* */
1272 }
1273
1274 void
1275 application_remove_proxy (application_t * app)
1276 {
1277   u16 transports = app->proxied_transports;
1278   transport_proto_t tp;
1279
1280   ASSERT (application_is_proxy (app));
1281
1282   /* *INDENT-OFF* */
1283   transport_proto_foreach (tp, ({
1284     if (transports & (1 << tp))
1285       application_start_stop_proxy (app, tp, 0);
1286   }));
1287   /* *INDENT-ON* */
1288 }
1289
1290 segment_manager_props_t *
1291 application_segment_manager_properties (application_t * app)
1292 {
1293   return &app->sm_properties;
1294 }
1295
1296 segment_manager_props_t *
1297 application_get_segment_manager_properties (u32 app_index)
1298 {
1299   application_t *app = application_get (app_index);
1300   return &app->sm_properties;
1301 }
1302
1303 clib_error_t *
1304 vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
1305 {
1306   /* Deprected, will be remove after 20.01 */
1307   app_cert_key_pair_t *ckpair;
1308   ckpair = app_cert_key_pair_get_default ();
1309   ckpair->cert = vec_dup (a->cert);
1310   return 0;
1311 }
1312
1313 clib_error_t *
1314 vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
1315 {
1316   /* Deprected, will be remove after 20.01 */
1317   app_cert_key_pair_t *ckpair;
1318   ckpair = app_cert_key_pair_get_default ();
1319   ckpair->key = vec_dup (a->key);
1320   return 0;
1321 }
1322
1323 static void
1324 application_format_listeners (application_t * app, int verbose)
1325 {
1326   vlib_main_t *vm = vlib_get_main ();
1327   app_worker_map_t *wrk_map;
1328   app_worker_t *app_wrk;
1329   u32 sm_index;
1330   u64 handle;
1331
1332   if (!app)
1333     {
1334       vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1335                        0, 0, verbose);
1336       return;
1337     }
1338
1339   /* *INDENT-OFF* */
1340   pool_foreach (wrk_map, app->worker_maps, ({
1341     app_wrk = app_worker_get (wrk_map->wrk_index);
1342     if (hash_elts (app_wrk->listeners_table) == 0)
1343       continue;
1344     hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1345       vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1346                        handle, sm_index, verbose);
1347     }));
1348   }));
1349   /* *INDENT-ON* */
1350 }
1351
1352 static void
1353 application_format_connects (application_t * app, int verbose)
1354 {
1355   app_worker_map_t *wrk_map;
1356   app_worker_t *app_wrk;
1357
1358   if (!app)
1359     {
1360       app_worker_format_connects (0, verbose);
1361       return;
1362     }
1363
1364   /* *INDENT-OFF* */
1365   pool_foreach (wrk_map, app->worker_maps, ({
1366     app_wrk = app_worker_get (wrk_map->wrk_index);
1367     app_worker_format_connects (app_wrk, verbose);
1368   }));
1369   /* *INDENT-ON* */
1370 }
1371
1372 u8 *
1373 format_cert_key_pair (u8 * s, va_list * args)
1374 {
1375   app_cert_key_pair_t *ckpair = va_arg (*args, app_cert_key_pair_t *);
1376   int key_len = 0, cert_len = 0;
1377   cert_len = vec_len (ckpair->cert);
1378   key_len = vec_len (ckpair->key);
1379   if (ckpair->cert_key_index == 0)
1380     s = format (s, "DEFAULT (cert:%d, key:%d)", cert_len, key_len);
1381   else
1382     s =
1383       format (s, "%d (cert:%d, key:%d)", ckpair->cert_key_index, cert_len,
1384               key_len);
1385   return s;
1386 }
1387
1388 u8 *
1389 format_application (u8 * s, va_list * args)
1390 {
1391   application_t *app = va_arg (*args, application_t *);
1392   CLIB_UNUSED (int verbose) = va_arg (*args, int);
1393   segment_manager_props_t *props;
1394   const u8 *app_ns_name, *app_name;
1395   app_worker_map_t *wrk_map;
1396   app_worker_t *app_wrk;
1397
1398   if (app == 0)
1399     {
1400       if (!verbose)
1401         s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
1402       return s;
1403     }
1404
1405   app_name = app_get_name (app);
1406   app_ns_name = app_namespace_id_from_index (app->ns_index);
1407   props = application_segment_manager_properties (app);
1408   if (!verbose)
1409     {
1410       s = format (s, "%-10u%-20v%-40s", app->app_index, app_name,
1411                   app_ns_name);
1412       return s;
1413     }
1414
1415   s = format (s, "app-name %v app-index %u ns-index %u seg-size %U\n",
1416               app_name, app->app_index, app->ns_index,
1417               format_memory_size, props->add_segment_size);
1418   s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1419               format_memory_size, props->rx_fifo_size,
1420               format_memory_size, props->tx_fifo_size);
1421
1422   /* *INDENT-OFF* */
1423   pool_foreach (wrk_map, app->worker_maps, ({
1424       app_wrk = app_worker_get (wrk_map->wrk_index);
1425       s = format (s, "%U", format_app_worker, app_wrk);
1426   }));
1427   /* *INDENT-ON* */
1428
1429   return s;
1430 }
1431
1432 void
1433 application_format_all_listeners (vlib_main_t * vm, int verbose)
1434 {
1435   application_t *app;
1436
1437   if (!pool_elts (app_main.app_pool))
1438     {
1439       vlib_cli_output (vm, "No active server bindings");
1440       return;
1441     }
1442
1443   application_format_listeners (0, verbose);
1444
1445   /* *INDENT-OFF* */
1446   pool_foreach (app, app_main.app_pool, ({
1447     application_format_listeners (app, verbose);
1448   }));
1449   /* *INDENT-ON* */
1450 }
1451
1452 void
1453 application_format_all_clients (vlib_main_t * vm, int verbose)
1454 {
1455   application_t *app;
1456
1457   if (!pool_elts (app_main.app_pool))
1458     {
1459       vlib_cli_output (vm, "No active apps");
1460       return;
1461     }
1462
1463   application_format_connects (0, verbose);
1464
1465   /* *INDENT-OFF* */
1466   pool_foreach (app, app_main.app_pool, ({
1467     application_format_connects (app, verbose);
1468   }));
1469   /* *INDENT-ON* */
1470 }
1471
1472 static clib_error_t *
1473 show_certificate_command_fn (vlib_main_t * vm, unformat_input_t * input,
1474                              vlib_cli_command_t * cmd)
1475 {
1476   app_cert_key_pair_t *ckpair;
1477   session_cli_return_if_not_enabled ();
1478
1479   /* *INDENT-OFF* */
1480   pool_foreach (ckpair, app_main.cert_key_pair_store, ({
1481     vlib_cli_output (vm, "%U", format_cert_key_pair, ckpair);
1482   }));
1483   /* *INDENT-ON* */
1484   return 0;
1485 }
1486
1487 static clib_error_t *
1488 show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1489                      vlib_cli_command_t * cmd)
1490 {
1491   int do_server = 0, do_client = 0;
1492   application_t *app;
1493   u32 app_index = ~0;
1494   int verbose = 0;
1495
1496   session_cli_return_if_not_enabled ();
1497
1498   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1499     {
1500       if (unformat (input, "server"))
1501         do_server = 1;
1502       else if (unformat (input, "client"))
1503         do_client = 1;
1504       else if (unformat (input, "%u", &app_index))
1505         ;
1506       else if (unformat (input, "verbose"))
1507         verbose = 1;
1508       else
1509         return clib_error_return (0, "unknown input `%U'",
1510                                   format_unformat_error, input);
1511     }
1512
1513   if (do_server)
1514     {
1515       application_format_all_listeners (vm, verbose);
1516       return 0;
1517     }
1518
1519   if (do_client)
1520     {
1521       application_format_all_clients (vm, verbose);
1522       return 0;
1523     }
1524
1525   if (app_index != ~0)
1526     {
1527       app = application_get_if_valid (app_index);
1528       if (!app)
1529         return clib_error_return (0, "No app with index %u", app_index);
1530
1531       vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1532       return 0;
1533     }
1534
1535   /* Print app related info */
1536   if (!do_server && !do_client)
1537     {
1538       vlib_cli_output (vm, "%U", format_application, 0, 0);
1539       /* *INDENT-OFF* */
1540       pool_foreach (app, app_main.app_pool, ({
1541         vlib_cli_output (vm, "%U", format_application, app, 0);
1542       }));
1543       /* *INDENT-ON* */
1544     }
1545
1546   return 0;
1547 }
1548
1549 /*
1550  * Certificate store
1551  *
1552  */
1553
1554 static app_cert_key_pair_t *
1555 app_cert_key_pair_alloc ()
1556 {
1557   app_cert_key_pair_t *ckpair;
1558   pool_get (app_main.cert_key_pair_store, ckpair);
1559   clib_memset (ckpair, 0, sizeof (*ckpair));
1560   ckpair->cert_key_index = ckpair - app_main.cert_key_pair_store;
1561   return ckpair;
1562 }
1563
1564 app_cert_key_pair_t *
1565 app_cert_key_pair_get_if_valid (u32 index)
1566 {
1567   if (pool_is_free_index (app_main.cert_key_pair_store, index))
1568     return 0;
1569   return app_cert_key_pair_get (index);
1570 }
1571
1572 app_cert_key_pair_t *
1573 app_cert_key_pair_get (u32 index)
1574 {
1575   return pool_elt_at_index (app_main.cert_key_pair_store, index);
1576 }
1577
1578 app_cert_key_pair_t *
1579 app_cert_key_pair_get_default ()
1580 {
1581   /* To maintain legacy bapi */
1582   return app_cert_key_pair_get (0);
1583 }
1584
1585 int
1586 vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t * a)
1587 {
1588   app_cert_key_pair_t *ckpair = app_cert_key_pair_alloc ();
1589   ckpair->cert = vec_dup (a->cert);
1590   ckpair->key = vec_dup (a->key);
1591   a->index = ckpair->cert_key_index;
1592   return 0;
1593 }
1594
1595 int
1596 vent_app_add_cert_key_interest (u32 index, u32 app_index)
1597 {
1598   app_cert_key_pair_t *ckpair;
1599   if (!(ckpair = app_cert_key_pair_get_if_valid (index)))
1600     return -1;
1601   vec_add1 (ckpair->app_interests, app_index);
1602   return 0;
1603 }
1604
1605 int
1606 vnet_app_del_cert_key_pair (u32 index)
1607 {
1608   app_cert_key_pair_t *ckpair;
1609   application_t *app;
1610   u32 *app_index;
1611
1612   if (!(ckpair = app_cert_key_pair_get_if_valid (index)))
1613     return (VNET_API_ERROR_INVALID_VALUE);
1614
1615   vec_foreach (app_index, ckpair->app_interests)
1616   {
1617     if ((app = application_get_if_valid (*app_index))
1618         && app->cb_fns.app_cert_key_pair_delete_callback)
1619       app->cb_fns.app_cert_key_pair_delete_callback (ckpair);
1620   }
1621
1622   vec_free (ckpair->cert);
1623   vec_free (ckpair->key);
1624   pool_put (app_main.cert_key_pair_store, ckpair);
1625   return 0;
1626 }
1627
1628 clib_error_t *
1629 cert_key_pair_store_init (vlib_main_t * vm)
1630 {
1631   /* Add a certificate with index 0 to support legacy apis */
1632   (void) app_cert_key_pair_alloc ();
1633   return 0;
1634 }
1635
1636 /* *INDENT-OFF* */
1637 VLIB_INIT_FUNCTION (cert_key_pair_store_init) =
1638 {
1639   .runs_after = VLIB_INITS("unix_physmem_init"),
1640 };
1641
1642 VLIB_CLI_COMMAND (show_app_command, static) =
1643 {
1644   .path = "show app",
1645   .short_help = "show app [server|client] [verbose]",
1646   .function = show_app_command_fn,
1647 };
1648
1649 VLIB_CLI_COMMAND (show_certificate_command, static) =
1650 {
1651   .path = "show app certificate",
1652   .short_help = "list app certs and keys present in store",
1653   .function = show_certificate_command_fn,
1654 };
1655 /* *INDENT-ON* */
1656
1657 /*
1658  * fd.io coding-style-patch-verification: ON
1659  *
1660  * Local Variables:
1661  * eval: (c-set-style "gnu")
1662  * End:
1663  */