FD.io VPP  v18.10-32-g1161dda
Vector Packet Processing
application.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 
19 #include <vnet/session/session.h>
20 
22 
23 static app_listener_t *
25 {
26  app_listener_t *app_listener;
27  pool_get (app->listeners, app_listener);
28  memset (app_listener, 0, sizeof (*app_listener));
29  app_listener->al_index = app_listener - app->listeners;
30  return app_listener;
31 }
32 
33 static app_listener_t *
34 app_listener_get (application_t * app, u32 app_listener_index)
35 {
36  return pool_elt_at_index (app->listeners, app_listener_index);
37 }
38 
39 static void
41 {
42  clib_bitmap_free (app_listener->workers);
43  pool_put (app->listeners, app_listener);
44  if (CLIB_DEBUG)
45  memset (app_listener, 0xfa, sizeof (*app_listener));
46 }
47 
48 static app_listener_t *
50 {
51  app_listener_t *app_listener;
52  pool_get (app->local_listeners, app_listener);
53  memset (app_listener, 0, sizeof (*app_listener));
54  app_listener->al_index = app_listener - app->local_listeners;
55  return app_listener;
56 }
57 
58 static app_listener_t *
59 app_local_listener_get (application_t * app, u32 app_listener_index)
60 {
61  return pool_elt_at_index (app->local_listeners, app_listener_index);
62 }
63 
64 static void
66 {
67  clib_bitmap_free (app_listener->workers);
68  pool_put (app->local_listeners, app_listener);
69  if (CLIB_DEBUG)
70  memset (app_listener, 0xfa, sizeof (*app_listener));
71 }
72 
73 static app_worker_map_t *
75 {
76  app_worker_map_t *map;
77  pool_get (app->worker_maps, map);
78  memset (map, 0, sizeof (*map));
79  return map;
80 }
81 
82 static u32
84 {
85  return (map - app->worker_maps);
86 }
87 
88 static void
90 {
91  pool_put (app->worker_maps, map);
92 }
93 
94 static app_worker_map_t *
96 {
97  return pool_elt_at_index (app->worker_maps, map_index);
98 }
99 
100 static u8 *
102 {
103  u8 *app_name;
104 
105  vl_api_registration_t *regp;
107  if (!regp)
108  app_name = format (0, "builtin-%d%c", app->app_index, 0);
109  else
110  app_name = format (0, "%s%c", regp->name, 0);
111 
112  return app_name;
113 }
114 
115 static u8 *
117 {
118  if (!app->name)
119  return app_get_name_from_reg_index (app);
120  return app->name;
121 }
122 
123 u32
125 {
126  app_namespace_t *app_ns;
127  app_ns = app_namespace_get (app->ns_index);
128  if (!application_has_global_scope (app))
129  return APP_INVALID_INDEX;
130  if (fib_proto == FIB_PROTOCOL_IP4)
131  return session_lookup_get_index_for_fib (fib_proto,
132  app_ns->ip4_fib_index);
133  else
134  return session_lookup_get_index_for_fib (fib_proto,
135  app_ns->ip6_fib_index);
136 }
137 
138 u32
140 {
141  app_namespace_t *app_ns;
142  if (!application_has_local_scope (app))
143  return APP_INVALID_INDEX;
144  app_ns = app_namespace_get (app->ns_index);
145  return app_ns->local_table_index;
146 }
147 
148 static void
150  session_endpoint_t * sep)
151 {
152  sep->transport_proto =
154  sep->port = ll->port;
155  sep->is_ip4 = ll->listener_session_type & 1;
156 }
157 
158 int
160 {
161  svm_queue_t *q;
162 
163  /* builtin servers are always OK */
164  if (app->api_client_index == ~0)
165  return 0;
166 
168  if (!q)
169  return 1;
170 
171  if (q->cursize == q->maxsize)
172  return 1;
173  return 0;
174 }
175 
176 /**
177  * Returns app name
178  *
179  * Since the name is not stored per app, we generate it on the fly. It is
180  * the caller's responsibility to free the vector
181  */
182 u8 *
184 {
185  application_t *app = application_get (app_index);
186  if (!app)
187  return 0;
188  return app_get_name_from_reg_index (app);
189 }
190 
191 static void
193 {
196  app->app_index);
197  else if (app->name)
198  hash_set_mem (app_main.app_by_name, app->name, app->app_index);
199 }
200 
201 static void
203 {
206  else if (app->name)
207  hash_unset_mem (app_main.app_by_name, app->name);
208 }
209 
211 application_lookup (u32 api_client_index)
212 {
213  uword *p;
214  p = hash_get (app_main.app_by_api_client_index, api_client_index);
215  if (p)
216  return application_get (p[0]);
217 
218  return 0;
219 }
220 
223 {
224  uword *p;
225  p = hash_get_mem (app_main.app_by_name, name);
226  if (p)
227  return application_get (p[0]);
228 
229  return 0;
230 }
231 
234 {
235  application_t *app;
236  pool_get (app_main.app_pool, app);
237  memset (app, 0, sizeof (*app));
238  app->app_index = app - app_main.app_pool;
239  return app;
240 }
241 
243 application_get (u32 app_index)
244 {
245  if (app_index == APP_INVALID_INDEX)
246  return 0;
247  return pool_elt_at_index (app_main.app_pool, app_index);
248 }
249 
252 {
253  if (pool_is_free_index (app_main.app_pool, app_index))
254  return 0;
255 
256  return pool_elt_at_index (app_main.app_pool, app_index);
257 }
258 
259 u32
261 {
262  return app - app_main.app_pool;
263 }
264 
265 static void
267 {
268  if (cb_fns->session_accept_callback == 0)
269  clib_warning ("No accept callback function provided");
270  if (cb_fns->session_connected_callback == 0)
271  clib_warning ("No session connected callback function provided");
272  if (cb_fns->session_disconnect_callback == 0)
273  clib_warning ("No session disconnect callback function provided");
274  if (cb_fns->session_reset_callback == 0)
275  clib_warning ("No session reset callback function provided");
276 }
277 
278 /**
279  * Check app config for given segment type
280  *
281  * Returns 1 on success and 0 otherwise
282  */
283 static u8
285 {
286  u8 is_valid;
287  if (st == SSVM_SEGMENT_MEMFD)
288  {
289  is_valid = (session_manager_get_evt_q_segment () != 0);
290  if (!is_valid)
291  clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
292  return is_valid;
293  }
294  else if (st == SSVM_SEGMENT_SHM)
295  {
296  is_valid = (session_manager_get_evt_q_segment () == 0);
297  if (!is_valid)
298  clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
299  return is_valid;
300  }
301  else
302  return 1;
303 }
304 
305 int
307 {
311  application_t *app;
312  u64 *options;
313 
314  app = application_alloc ();
315  options = a->options;
316  /*
317  * Make sure we support the requested configuration
318  */
319  if (!(options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN))
320  {
321  reg = vl_api_client_index_to_registration (a->api_client_index);
322  if (!reg)
323  return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
325  seg_type = SSVM_SEGMENT_SHM;
326  }
327  else
328  {
329  if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
330  {
331  clib_warning ("mq eventfds can only be used if socket transport is "
332  "used for api");
333  return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
334  }
335  seg_type = SSVM_SEGMENT_PRIVATE;
336  }
337 
338  if (!application_verify_cfg (seg_type))
339  return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
340 
341  /* Check that the obvious things are properly set up */
342  application_verify_cb_fns (a->session_cb_vft);
343 
344  app->api_client_index = a->api_client_index;
345  app->flags = options[APP_OPTIONS_FLAGS];
346  app->cb_fns = *a->session_cb_vft;
347  app->ns_index = options[APP_OPTIONS_NAMESPACE];
349  app->name = vec_dup (a->name);
350 
351  /* If no scope enabled, default to global */
353  && !application_has_local_scope (app))
354  app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
355 
358  props->segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
359  props->prealloc_fifos = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
360  if (options[APP_OPTIONS_ADD_SEGMENT_SIZE])
361  {
362  props->add_segment_size = options[APP_OPTIONS_ADD_SEGMENT_SIZE];
363  props->add_segment = 1;
364  }
365  if (options[APP_OPTIONS_RX_FIFO_SIZE])
366  props->rx_fifo_size = options[APP_OPTIONS_RX_FIFO_SIZE];
367  if (options[APP_OPTIONS_TX_FIFO_SIZE])
368  props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
369  if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
370  props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
371  if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
372  props->use_mq_eventfd = 1;
373  if (options[APP_OPTIONS_TLS_ENGINE])
374  app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
375  props->segment_type = seg_type;
376 
377  /* Add app to lookup by api_client_index table */
378  application_table_add (app);
379  a->app_index = application_index (app);
380 
381  APP_DBG ("New app name: %v api index: %u index %u", app->name,
382  app->api_client_index, app->app_index);
383 
384  return 0;
385 }
386 
387 void
389 {
390  app_worker_map_t *wrk_map;
391  app_worker_t *app_wrk;
392  u32 table_index;
393  local_session_t *ll;
394  session_endpoint_t sep;
395 
396  /*
397  * The app event queue allocated in first segment is cleared with
398  * the segment manager. No need to explicitly free it.
399  */
400  APP_DBG ("Delete app name %v api index: %d index: %d", app->name,
401  app->api_client_index, app->app_index);
402 
403  if (application_is_proxy (app))
405 
406  /*
407  * Free workers
408  */
409 
410  /* *INDENT-OFF* */
411  pool_flush (wrk_map, app->worker_maps, ({
412  app_wrk = app_worker_get (wrk_map->wrk_index);
413  app_worker_free (app_wrk);
414  }));
415  /* *INDENT-ON* */
416  pool_free (app->worker_maps);
417 
418  /*
419  * Free local listeners. Global table unbinds stop local listeners
420  * as well, but if we have only local binds, these won't be cleaned up.
421  * Don't bother with local accepted sessions, we clean them when
422  * cleaning up the worker.
423  */
424  table_index = application_local_session_table (app);
425  /* *INDENT-OFF* */
426  pool_foreach (ll, app->local_listen_sessions, ({
427  application_local_listener_session_endpoint (ll, &sep);
428  session_lookup_del_session_endpoint (table_index, &sep);
429  }));
430  /* *INDENT-ON* */
432 
433  /*
434  * Cleanup remaining state
435  */
436  application_table_del (app);
437  vec_free (app->name);
438  vec_free (app->tls_cert);
439  vec_free (app->tls_key);
440  pool_put (app_main.app_pool, app);
441 }
442 
443 app_worker_t *
445 {
446  app_worker_map_t *map;
447  map = app_worker_map_get (app, wrk_map_index);
448  if (!map)
449  return 0;
450  return app_worker_get (map->wrk_index);
451 }
452 
453 app_worker_t *
455 {
456  return application_get_worker (app, 0);
457 }
458 
459 app_worker_t *
461 {
462  app_listener_t *app_listener;
463  application_t *app;
464  u32 wrk_index;
465 
466  app = application_get (ls->app_index);
467  if (!is_local)
468  app_listener = app_listener_get (app, ls->listener_db_index);
469  else
470  app_listener = app_local_listener_get (app, ls->listener_db_index);
471 
472  wrk_index = clib_bitmap_next_set (app_listener->workers,
473  app_listener->accept_rotor + 1);
474  if (wrk_index == ~0)
475  wrk_index = clib_bitmap_first_set (app_listener->workers);
476 
477  ASSERT (wrk_index != ~0);
478  app_listener->accept_rotor = wrk_index;
479  return application_get_worker (app, wrk_index);
480 }
481 
482 app_worker_t *
484 {
485  app_worker_t *app_wrk;
486  pool_get (app_main.workers, app_wrk);
487  memset (app_wrk, 0, sizeof (*app_wrk));
488  app_wrk->wrk_index = app_wrk - app_main.workers;
489  app_wrk->app_index = app->app_index;
490  app_wrk->wrk_map_index = ~0;
494  APP_DBG ("New app %v worker %u", app_get_name (app), app_wrk->wrk_index);
495  return app_wrk;
496 }
497 
498 app_worker_t *
499 app_worker_get (u32 wrk_index)
500 {
501  return pool_elt_at_index (app_main.workers, wrk_index);
502 }
503 
504 app_worker_t *
506 {
507  if (pool_is_free_index (app_main.workers, wrk_index))
508  return 0;
509  return pool_elt_at_index (app_main.workers, wrk_index);
510 }
511 
512 void
514 {
515  application_t *app = application_get (app_wrk->app_index);
516  vnet_unbind_args_t _a, *a = &_a;
517  u64 handle, *handles = 0;
518  segment_manager_t *sm;
519  u32 sm_index;
520  int i;
521 
522  /*
523  * Listener cleanup
524  */
525 
526  /* *INDENT-OFF* */
527  hash_foreach (handle, sm_index, app_wrk->listeners_table,
528  ({
529  vec_add1 (handles, handle);
530  sm = segment_manager_get (sm_index);
531  sm->app_wrk_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
532  }));
533  /* *INDENT-ON* */
534 
535  for (i = 0; i < vec_len (handles); i++)
536  {
537  a->app_index = app->app_index;
538  a->wrk_map_index = app_wrk->wrk_map_index;
539  a->handle = handles[i];
540  /* seg manager is removed when unbind completes */
541  vnet_unbind (a);
542  }
543 
544  /*
545  * Connects segment manager cleanup
546  */
547 
549  {
551  sm->app_wrk_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
553  }
554 
555  /* If first segment manager is used by a listener */
557  && app_wrk->first_segment_manager != app_wrk->connects_seg_manager)
558  {
560  sm->first_is_protected = 0;
561  sm->app_wrk_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
562  /* .. and has no fifos, e.g. it might be used for redirected sessions,
563  * remove it */
564  if (!segment_manager_has_fifos (sm))
565  segment_manager_del (sm);
566  }
567 
568  /*
569  * Local sessions
570  */
572 
573  pool_put (app_main.workers, app_wrk);
574  if (CLIB_DEBUG)
575  memset (app_wrk, 0xfe, sizeof (*app_wrk));
576 }
577 
578 int
580 {
581  app_worker_map_t *wrk_map;
582  app_worker_t *app_wrk;
583  segment_manager_t *sm;
584  int rv;
585 
586  app_wrk = app_worker_alloc (app);
587  wrk_map = app_worker_map_alloc (app);
588  wrk_map->wrk_index = app_wrk->wrk_index;
589  app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
590 
591  /*
592  * Setup first segment manager
593  */
594  sm = segment_manager_new ();
595  sm->app_wrk_index = app_wrk->wrk_index;
596 
597  if ((rv = segment_manager_init (sm, app->sm_properties.segment_size,
598  app->sm_properties.prealloc_fifos)))
599  {
600  app_worker_free (app_wrk);
601  return rv;
602  }
603  sm->first_is_protected = 1;
604 
605  /*
606  * Setup app worker
607  */
609  app_wrk->listeners_table = hash_create (0, sizeof (u64));
611  app_wrk->app_is_builtin = application_is_builtin (app);
612 
613  /*
614  * Segment manager for local sessions
615  */
616  sm = segment_manager_new ();
617  sm->app_wrk_index = app_wrk->wrk_index;
619  app_wrk->local_connects = hash_create (0, sizeof (u64));
620 
621  *wrk = app_wrk;
622 
623  return 0;
624 }
625 
628 {
629  app_worker_t *app_wrk;
630  app_wrk = app_worker_get_if_valid (wrk_index);
631  if (!app_wrk)
632  return 0;
633  return application_get_if_valid (app_wrk->app_index);
634 }
635 
636 static segment_manager_t *
638 {
639  segment_manager_t *sm = 0;
640 
641  /* If the first segment manager is not in use, don't allocate a new one */
643  && app_wrk->first_segment_manager_in_use == 0)
644  {
646  app_wrk->first_segment_manager_in_use = 1;
647  return sm;
648  }
649 
650  sm = segment_manager_new ();
651  sm->app_wrk_index = app_wrk->wrk_index;
652 
653  return sm;
654 }
655 
656 int
658 {
659  segment_manager_t *sm;
660 
661  /* Allocate segment manager. All sessions derived out of a listen session
662  * have fifos allocated by the same segment manager. */
663  if (!(sm = app_worker_alloc_segment_manager (app_wrk)))
664  return -1;
665 
666  /* Add to app's listener table. Useful to find all child listeners
667  * when app goes down, although, just for unbinding this is not needed */
669  segment_manager_index (sm));
670 
671  if (!ls->server_rx_fifo
673  {
674  if (session_alloc_fifos (sm, ls))
675  return -1;
676  }
677  return 0;
678 }
679 
680 int
682 {
683  segment_manager_t *sm;
684  uword *sm_indexp;
685 
686  sm_indexp = hash_get (app_wrk->listeners_table, handle);
687  if (PREDICT_FALSE (!sm_indexp))
688  {
689  clib_warning ("listener handle was removed %llu!", handle);
690  return -1;
691  }
692 
693  sm = segment_manager_get (*sm_indexp);
694  if (app_wrk->first_segment_manager == *sm_indexp)
695  {
696  /* Delete sessions but don't remove segment manager */
697  app_wrk->first_segment_manager_in_use = 0;
699  }
700  else
701  {
703  }
704  hash_unset (app_wrk->listeners_table, handle);
705 
706  return 0;
707 }
708 
709 /**
710  * Start listening local transport endpoint for requested transport.
711  *
712  * Creates a 'dummy' stream session with state LISTENING to be used in session
713  * lookups, prior to establishing connection. Requests transport to build
714  * it's own specific listening connection.
715  */
716 int
718  session_endpoint_extended_t * sep_ext,
719  session_handle_t * res)
720 {
721  app_listener_t *app_listener;
722  u32 table_index, fib_proto;
723  session_endpoint_t *sep;
724  app_worker_t *app_wrk;
725  stream_session_t *ls;
726  session_handle_t lh;
727  session_type_t sst;
728 
729  /*
730  * Check if sep is already listened on
731  */
732  sep = (session_endpoint_t *) sep_ext;
733  fib_proto = session_endpoint_fib_proto (sep);
734  table_index = application_session_table (app, fib_proto);
735  lh = session_lookup_endpoint_listener (table_index, sep, 1);
736  if (lh != SESSION_INVALID_HANDLE)
737  {
739  if (ls->app_index != app->app_index)
740  return VNET_API_ERROR_ADDRESS_IN_USE;
741 
742  app_wrk = app_worker_get (sep_ext->app_wrk_index);
743  if (ls->app_wrk_index == app_wrk->wrk_index)
744  return VNET_API_ERROR_ADDRESS_IN_USE;
745 
746  if (app_worker_start_listen (app_wrk, ls))
747  return -1;
748 
749  app_listener = app_listener_get (app, ls->listener_db_index);
750  app_listener->workers = clib_bitmap_set (app_listener->workers,
751  app_wrk->wrk_map_index, 1);
752 
753  *res = listen_session_get_handle (ls);
754  return 0;
755  }
756 
757  /*
758  * Allocate new listener for application
759  */
760  sst = session_type_from_proto_and_ip (sep_ext->transport_proto,
761  sep_ext->is_ip4);
762  ls = listen_session_new (0, sst);
763  ls->app_index = app->app_index;
764  lh = listen_session_get_handle (ls);
765  if (session_listen (ls, sep_ext))
766  goto err;
767 
768 
770  app_listener = app_listener_alloc (app);
771  ls->listener_db_index = app_listener->al_index;
772 
773  /*
774  * Setup app worker as a listener
775  */
776  app_wrk = app_worker_get (sep_ext->app_wrk_index);
777  ls->app_wrk_index = app_wrk->wrk_index;
778  if (app_worker_start_listen (app_wrk, ls))
779  goto err;
780  app_listener->workers = clib_bitmap_set (app_listener->workers,
781  app_wrk->wrk_map_index, 1);
782 
783  *res = lh;
784  return 0;
785 
786 err:
787  listen_session_del (ls);
788  return -1;
789 }
790 
791 /**
792  * Stop listening on session associated to handle
793  *
794  * @param handle listener handle
795  * @param app_index index of the app owning the handle.
796  * @param app_wrk_index index of the worker requesting the stop
797  */
798 int
799 application_stop_listen (u32 app_index, u32 app_wrk_index,
800  session_handle_t handle)
801 {
802  app_listener_t *app_listener;
803  stream_session_t *listener;
804  app_worker_t *app_wrk;
805  application_t *app;
806 
807  listener = listen_session_get_from_handle (handle);
808  app = application_get (app_index);
809  if (PREDICT_FALSE (!app || app->app_index != listener->app_index))
810  {
811  clib_warning ("app doesn't own handle %llu!", handle);
812  return -1;
813  }
814 
815  app_listener = app_listener_get (app, listener->listener_db_index);
816  if (!clib_bitmap_get (app_listener->workers, app_wrk_index))
817  {
818  clib_warning ("worker not listening on handle %lu", handle);
819  return 0;
820  }
821 
822  app_wrk = application_get_worker (app, app_wrk_index);
823  app_worker_stop_listen (app_wrk, handle);
824  clib_bitmap_set_no_check (app_listener->workers, app_wrk_index, 0);
825 
826  if (clib_bitmap_is_zero (app_listener->workers))
827  {
828  session_stop_listen (listener);
829  app_listener_free (app, app_listener);
830  listen_session_del (listener);
831  }
832 
833  return 0;
834 }
835 
836 int
838  u32 api_context)
839 {
840  int rv;
841 
842  /* Make sure we have a segment manager for connects */
844 
845  if ((rv = session_open (app->wrk_index, sep, api_context)))
846  return rv;
847 
848  return 0;
849 }
850 
851 int
853 {
854  segment_manager_t *sm;
855 
857  {
858  sm = app_worker_alloc_segment_manager (app_wrk);
859  if (sm == 0)
860  return -1;
862  }
863  return 0;
864 }
865 
868 {
869  ASSERT (app->connects_seg_manager != (u32) ~ 0);
871 }
872 
875  stream_session_t * listener)
876 {
877  uword *smp;
878  smp = hash_get (app->listeners_table, listen_session_get_handle (listener));
879  ASSERT (smp != 0);
880  return segment_manager_get (*smp);
881 }
882 
883 clib_error_t *
885 {
887  app_worker_map_t *wrk_map;
888  app_worker_t *app_wrk;
889  segment_manager_t *sm;
890  application_t *app;
891  int rv;
892 
893  app = application_get (a->app_index);
894  if (!app)
895  return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
896  "App %u does not exist", a->app_index);
897 
898  if (a->is_add)
899  {
900  if ((rv = app_worker_alloc_and_init (app, &app_wrk)))
901  return clib_error_return_code (0, rv, 0, "app wrk init: %d", rv);
904  a->segment = &fs->ssvm;
906  a->evt_q = app_wrk->event_queue;
907  a->wrk_index = app_wrk->wrk_map_index;
908  }
909  else
910  {
911  wrk_map = app_worker_map_get (app, a->wrk_index);
912  if (!wrk_map)
913  return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
914  "App %u does not have worker %u",
915  app->app_index, a->wrk_index);
916  app_wrk = app_worker_get (wrk_map->wrk_index);
917  app_worker_map_free (app, wrk_map);
918  if (!app_wrk)
919  return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
920  "No worker %u", a->wrk_index);
921  app_worker_free (app_wrk);
922  }
923  return 0;
924 }
925 
928 {
930 }
931 
934  local_session_t * ls)
935 {
936  stream_session_t *listener;
938  {
939  listener = listen_session_get (ls->listener_index);
940  return app_worker_get_listen_segment_manager (app, listener);
941  }
943 }
944 
945 int
947 {
948  return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
949 }
950 
951 int
953 {
954  return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
955 }
956 
957 int
959 {
960  return (application_is_proxy (app) && application_is_builtin (app));
961 }
962 
963 u8
965 {
966  return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
967 }
968 
969 u8
971 {
972  return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
973 }
974 
975 u8
977 {
978  return app->flags & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
979 }
980 
981 /**
982  * Send an API message to the external app, to map new segment
983  */
984 int
986 {
987  app_worker_t *app_wrk = app_worker_get (app_wrk_index);
988  application_t *app = application_get (app_wrk->app_index);
989  return app->cb_fns.add_segment_callback (app->api_client_index, fs);
990 }
991 
992 u32
994 {
995  return hash_elts (app->listeners_table);
996 }
997 
1000  u8 transport_proto)
1001 {
1002  stream_session_t *listener;
1003  u64 handle;
1004  u32 sm_index;
1005  u8 sst;
1006 
1007  sst = session_type_from_proto_and_ip (transport_proto,
1008  fib_proto == FIB_PROTOCOL_IP4);
1009 
1010  /* *INDENT-OFF* */
1011  hash_foreach (handle, sm_index, app->listeners_table, ({
1012  listener = listen_session_get_from_handle (handle);
1013  if (listener->session_type == sst
1014  && listener->enqueue_epoch != SESSION_PROXY_LISTENER_INDEX)
1015  return listener;
1016  }));
1017  /* *INDENT-ON* */
1018 
1019  return 0;
1020 }
1021 
1022 u8
1024 {
1025  return app_wrk->app_is_builtin;
1026 }
1027 
1030  u8 transport_proto)
1031 {
1032  stream_session_t *listener;
1033  u64 handle;
1034  u32 sm_index;
1035  u8 sst;
1036 
1037  sst = session_type_from_proto_and_ip (transport_proto,
1038  fib_proto == FIB_PROTOCOL_IP4);
1039 
1040  /* *INDENT-OFF* */
1041  hash_foreach (handle, sm_index, app->listeners_table, ({
1042  listener = listen_session_get_from_handle (handle);
1043  if (listener->session_type == sst
1044  && listener->enqueue_epoch == SESSION_PROXY_LISTENER_INDEX)
1045  return listener;
1046  }));
1047  /* *INDENT-ON* */
1048 
1049  return 0;
1050 }
1051 
1052 static clib_error_t *
1054  u8 transport_proto, u8 is_start)
1055 {
1056  app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1057  u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
1060  app_worker_t *app_wrk;
1061  stream_session_t *s;
1062  u64 handle;
1063 
1064  /* TODO decide if we want proxy to be enabled for all workers */
1065  app_wrk = application_get_default_worker (app);
1066  if (is_start)
1067  {
1068  s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
1069  if (!s)
1070  {
1071  sep.is_ip4 = is_ip4;
1072  sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1073  sep.sw_if_index = app_ns->sw_if_index;
1074  sep.transport_proto = transport_proto;
1075  sep.app_wrk_index = app_wrk->wrk_index; /* only default */
1076  application_start_listen (app, &sep, &handle);
1077  s = listen_session_get_from_handle (handle);
1078  s->enqueue_epoch = SESSION_PROXY_LISTENER_INDEX;
1079  }
1080  }
1081  else
1082  {
1083  s = application_proxy_listener (app_wrk, fib_proto, transport_proto);
1084  ASSERT (s);
1085  }
1086 
1088 
1089  if (!ip_is_zero (&tc->lcl_ip, 1))
1090  {
1091  u32 sti;
1092  sep.is_ip4 = is_ip4;
1093  sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1094  sep.transport_proto = transport_proto;
1095  sep.port = 0;
1096  sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
1097  if (is_start)
1099  (session_endpoint_t *) & sep,
1100  s->session_index);
1101  else
1103  (session_endpoint_t *) & sep);
1104  }
1105 
1106  return 0;
1107 }
1108 
1109 static void
1111  u8 transport_proto, u8 is_start)
1112 {
1114  app_namespace_t *app_ns;
1115  app_ns = app_namespace_get (app->ns_index);
1116  sep.is_ip4 = 1;
1117  sep.transport_proto = transport_proto;
1118  sep.port = 0;
1119 
1120  if (is_start)
1121  {
1122  session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1123  app->app_index);
1124  sep.is_ip4 = 0;
1125  session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1126  app->app_index);
1127  }
1128  else
1129  {
1130  session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1131  sep.is_ip4 = 0;
1132  session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1133  }
1134 }
1135 
1136 void
1138  transport_proto_t transport_proto, u8 is_start)
1139 {
1140  if (application_has_local_scope (app))
1141  application_start_stop_proxy_local_scope (app, transport_proto, is_start);
1142 
1143  if (application_has_global_scope (app))
1144  {
1146  transport_proto, is_start);
1148  transport_proto, is_start);
1149  }
1150 }
1151 
1152 void
1154 {
1155  u16 transports = app->proxied_transports;
1156  transport_proto_t tp;
1157 
1158  ASSERT (application_is_proxy (app));
1159 
1160  /* *INDENT-OFF* */
1161  transport_proto_foreach (tp, ({
1162  if (transports & (1 << tp))
1163  application_start_stop_proxy (app, tp, 1);
1164  }));
1165  /* *INDENT-ON* */
1166 }
1167 
1168 void
1170 {
1171  u16 transports = app->proxied_transports;
1172  transport_proto_t tp;
1173 
1174  ASSERT (application_is_proxy (app));
1175 
1176  /* *INDENT-OFF* */
1177  transport_proto_foreach (tp, ({
1178  if (transports & (1 << tp))
1179  application_start_stop_proxy (app, tp, 0);
1180  }));
1181  /* *INDENT-ON* */
1182 }
1183 
1186 {
1187  return &app->sm_properties;
1188 }
1189 
1192 {
1193  application_t *app = application_get (app_index);
1194  return &app->sm_properties;
1195 }
1196 
1197 static inline int
1199 {
1200  if (PREDICT_FALSE (svm_msg_q_is_full (mq)))
1201  {
1202  clib_warning ("evt q full");
1203  svm_msg_q_free_msg (mq, msg);
1204  if (lock)
1205  svm_msg_q_unlock (mq);
1206  return -1;
1207  }
1208 
1209  if (lock)
1210  {
1211  svm_msg_q_add_and_unlock (mq, msg);
1212  return 0;
1213  }
1214 
1215  /* Even when not locking the ring, we must wait for queue mutex */
1216  if (svm_msg_q_add (mq, msg, SVM_Q_WAIT))
1217  {
1218  clib_warning ("msg q add returned");
1219  return -1;
1220  }
1221  return 0;
1222 }
1223 
1224 static inline int
1226 {
1227  session_event_t *evt;
1228  svm_msg_q_msg_t msg;
1229  svm_msg_q_t *mq;
1230 
1231  if (PREDICT_FALSE (s->session_state != SESSION_STATE_READY
1232  && s->session_state != SESSION_STATE_LISTENING))
1233  {
1234  /* Session is closed so app will never clean up. Flush rx fifo */
1235  if (s->session_state == SESSION_STATE_CLOSED)
1236  svm_fifo_dequeue_drop_all (s->server_rx_fifo);
1237  return 0;
1238  }
1239 
1240  if (app_worker_application_is_builtin (app_wrk))
1241  {
1242  application_t *app = application_get (app_wrk->app_index);
1243  return app->cb_fns.builtin_app_rx_callback (s);
1244  }
1245 
1246  if (svm_fifo_has_event (s->server_rx_fifo)
1247  || svm_fifo_is_empty (s->server_rx_fifo))
1248  return 0;
1249 
1250  mq = app_wrk->event_queue;
1251  if (lock)
1252  svm_msg_q_lock (mq);
1253 
1255  {
1256  clib_warning ("evt q rings full");
1257  if (lock)
1258  svm_msg_q_unlock (mq);
1259  return -1;
1260  }
1261 
1263  ASSERT (!svm_msg_q_msg_is_invalid (&msg));
1264 
1265  evt = (session_event_t *) svm_msg_q_msg_data (mq, &msg);
1266  evt->fifo = s->server_rx_fifo;
1267  evt->event_type = FIFO_EVENT_APP_RX;
1268 
1269  (void) svm_fifo_set_event (s->server_rx_fifo);
1270 
1271  if (app_enqueue_evt (mq, &msg, lock))
1272  return -1;
1273  return 0;
1274 }
1275 
1276 static inline int
1278 {
1279  svm_msg_q_t *mq;
1280  session_event_t *evt;
1281  svm_msg_q_msg_t msg;
1282 
1283  if (app_worker_application_is_builtin (app_wrk))
1284  return 0;
1285 
1286  mq = app_wrk->event_queue;
1287  if (lock)
1288  svm_msg_q_lock (mq);
1289 
1291  {
1292  clib_warning ("evt q rings full");
1293  if (lock)
1294  svm_msg_q_unlock (mq);
1295  return -1;
1296  }
1297 
1299  ASSERT (!svm_msg_q_msg_is_invalid (&msg));
1300 
1301  evt = (session_event_t *) svm_msg_q_msg_data (mq, &msg);
1302  evt->event_type = FIFO_EVENT_APP_TX;
1303  evt->fifo = s->server_tx_fifo;
1304 
1305  return app_enqueue_evt (mq, &msg, lock);
1306 }
1307 
1308 /* *INDENT-OFF* */
1310  stream_session_t *s,
1311  u8 lock);
1314  0,
1316 };
1317 /* *INDENT-ON* */
1318 
1319 /**
1320  * Send event to application
1321  *
1322  * Logic from queue perspective is non-blocking. If there's
1323  * not enough space to enqueue a message, we return.
1324  */
1325 int
1327 {
1328  ASSERT (app && evt_type <= FIFO_EVENT_APP_TX);
1329  return app_send_evt_handler_fns[evt_type] (app, s, 0 /* lock */ );
1330 }
1331 
1332 /**
1333  * Send event to application
1334  *
1335  * Logic from queue perspective is blocking. However, if queue is full,
1336  * we return.
1337  */
1338 int
1340  u8 evt_type)
1341 {
1342  return app_send_evt_handler_fns[evt_type] (app, s, 1 /* lock */ );
1343 }
1344 
1347 {
1348  local_session_t *s;
1349  pool_get (app_wrk->local_sessions, s);
1350  memset (s, 0, sizeof (*s));
1351  s->app_wrk_index = app_wrk->wrk_index;
1352  s->session_index = s - app_wrk->local_sessions;
1354  return s;
1355 }
1356 
1357 void
1359 {
1360  pool_put (app->local_sessions, s);
1361  if (CLIB_DEBUG)
1362  memset (s, 0xfc, sizeof (*s));
1363 }
1364 
1367 {
1368  if (pool_is_free_index (app_wrk->local_sessions, session_index))
1369  return 0;
1370  return pool_elt_at_index (app_wrk->local_sessions, session_index);
1371 }
1372 
1375 {
1376  app_worker_t *server_wrk;
1377  u32 session_index, server_wrk_index;
1378  local_session_parse_handle (handle, &server_wrk_index, &session_index);
1379  server_wrk = app_worker_get_if_valid (server_wrk_index);
1380  if (!server_wrk)
1381  return 0;
1382  return application_get_local_session (server_wrk, session_index);
1383 }
1384 
1387 {
1388  local_session_t *ll;
1389  pool_get (app->local_listen_sessions, ll);
1390  memset (ll, 0, sizeof (*ll));
1391  return ll;
1392 }
1393 
1394 u32
1396 {
1397  return (ll - app->local_listen_sessions);
1398 }
1399 
1400 void
1402  local_session_t * ll)
1403 {
1404  pool_put (app->local_listen_sessions, ll);
1405  if (CLIB_DEBUG)
1406  memset (ll, 0xfb, sizeof (*ll));
1407 }
1408 
1409 int
1411  session_endpoint_extended_t * sep_ext,
1412  session_handle_t * handle)
1413 {
1414  app_listener_t *app_listener;
1415  session_endpoint_t *sep;
1416  app_worker_t *app_wrk;
1417  session_handle_t lh;
1418  local_session_t *ll;
1419  u32 table_index;
1420 
1421  sep = (session_endpoint_t *) sep_ext;
1422  table_index = application_local_session_table (app);
1423  app_wrk = app_worker_get (sep_ext->app_wrk_index);
1424 
1425  /* An exact sep match, as opposed to session_lookup_local_listener */
1426  lh = session_lookup_endpoint_listener (table_index, sep, 1);
1427  if (lh != SESSION_INVALID_HANDLE)
1428  {
1430  if (ll->app_index != app->app_index)
1431  return VNET_API_ERROR_ADDRESS_IN_USE;
1432 
1433  if (ll->app_wrk_index == app_wrk->wrk_index)
1434  return VNET_API_ERROR_ADDRESS_IN_USE;
1435 
1436  app_listener = app_local_listener_get (app, ll->listener_db_index);
1437  app_listener->workers = clib_bitmap_set (app_listener->workers,
1438  app_wrk->wrk_map_index, 1);
1439  *handle = application_local_session_handle (ll);
1440  return 0;
1441  }
1442 
1445  ll->app_wrk_index = app_wrk->app_index;
1447  ll->port = sep_ext->port;
1448  /* Store the original session type for the unbind */
1449  ll->listener_session_type =
1450  session_type_from_proto_and_ip (sep_ext->transport_proto,
1451  sep_ext->is_ip4);
1452  ll->transport_listener_index = ~0;
1453  ll->app_index = app->app_index;
1454 
1455  app_listener = app_local_listener_alloc (app);
1456  ll->listener_db_index = app_listener->al_index;
1457  app_listener->workers = clib_bitmap_set (app_listener->workers,
1458  app_wrk->wrk_map_index, 1);
1459 
1460  *handle = application_local_session_handle (ll);
1461  session_lookup_add_session_endpoint (table_index, sep, *handle);
1462 
1463  return 0;
1464 }
1465 
1466 /**
1467  * Clean up local session table. If we have a listener session use it to
1468  * find the port and proto. If not, the handle must be a local table handle
1469  * so parse it.
1470  */
1471 int
1472 application_stop_local_listen (u32 app_index, u32 wrk_map_index,
1473  session_handle_t lh)
1474 {
1476  u32 table_index, ll_index, server_index;
1477  app_listener_t *app_listener;
1478  app_worker_t *server_wrk;
1479  stream_session_t *sl = 0;
1480  local_session_t *ll, *ls;
1481  application_t *server;
1482 
1483  server = application_get (app_index);
1484  table_index = application_local_session_table (server);
1485 
1486  /* We have both local and global table binds. Figure from global what
1487  * the sep we should be cleaning up is.
1488  */
1489  if (!session_handle_is_local (lh))
1490  {
1492  if (!sl || listen_session_get_local_session_endpoint (sl, &sep))
1493  {
1494  clib_warning ("broken listener");
1495  return -1;
1496  }
1497  lh = session_lookup_endpoint_listener (table_index, &sep, 0);
1498  if (lh == SESSION_INVALID_HANDLE)
1499  return -1;
1500  }
1501 
1502  local_session_parse_handle (lh, &server_index, &ll_index);
1503  if (PREDICT_FALSE (server_index != app_index))
1504  {
1505  clib_warning ("app %u does not own local handle 0x%lx", app_index, lh);
1506  return -1;
1507  }
1508 
1509  ll = application_get_local_listen_session (server, ll_index);
1510  if (PREDICT_FALSE (!ll))
1511  {
1512  clib_warning ("no local listener");
1513  return -1;
1514  }
1515 
1516  app_listener = app_local_listener_get (server, ll->listener_db_index);
1517  if (!clib_bitmap_get (app_listener->workers, wrk_map_index))
1518  {
1519  clib_warning ("app wrk %u not listening on handle %lu", wrk_map_index,
1520  lh);
1521  return -1;
1522  }
1523 
1524  server_wrk = application_get_worker (server, wrk_map_index);
1525  /* *INDENT-OFF* */
1526  pool_foreach (ls, server_wrk->local_sessions, ({
1527  if (ls->listener_index == ll->session_index)
1528  application_local_session_disconnect (server_wrk->app_index, ls);
1529  }));
1530  /* *INDENT-ON* */
1531 
1532  clib_bitmap_set_no_check (app_listener->workers, wrk_map_index, 0);
1533  if (clib_bitmap_is_zero (app_listener->workers))
1534  {
1535  app_local_listener_free (server, app_listener);
1537  session_lookup_del_session_endpoint (table_index, &sep);
1539  }
1540 
1541  return 0;
1542 }
1543 
1544 static void
1546 {
1547  int fd;
1548 
1549  /*
1550  * segment manager initializes only the producer eventds, since vpp is
1551  * typically the producer. But for local sessions, we also pass to the
1552  * apps the mqs they listen on for events from peer apps, so they are also
1553  * consumer fds.
1554  */
1559 }
1560 
1561 int
1563  app_worker_t * server_wrk,
1564  local_session_t * ll, u32 opaque)
1565 {
1566  u32 seg_size, evt_q_sz, evt_q_elts, margin = 16 << 10;
1567  segment_manager_properties_t *props, *cprops;
1568  u32 round_rx_fifo_sz, round_tx_fifo_sz;
1569  int rv, has_transport, seg_index;
1571  application_t *server, *client;
1572  segment_manager_t *sm;
1573  local_session_t *ls;
1574  svm_msg_q_t *sq, *cq;
1575 
1576  ls = application_local_session_alloc (server_wrk);
1577  server = application_get (server_wrk->app_index);
1578  client = application_get (client_wrk->app_index);
1579 
1580  props = application_segment_manager_properties (server);
1581  cprops = application_segment_manager_properties (client);
1582  evt_q_elts = props->evt_q_size + cprops->evt_q_size;
1583  evt_q_sz = segment_manager_evt_q_expected_size (evt_q_elts);
1584  round_rx_fifo_sz = 1 << max_log2 (props->rx_fifo_size);
1585  round_tx_fifo_sz = 1 << max_log2 (props->tx_fifo_size);
1586  seg_size = round_rx_fifo_sz + round_tx_fifo_sz + evt_q_sz + margin;
1587 
1588  has_transport = session_has_transport ((stream_session_t *) ll);
1589  if (!has_transport)
1590  {
1591  /* Local sessions don't have backing transport */
1592  ls->port = ll->port;
1593  sm = application_get_local_segment_manager (server_wrk);
1594  }
1595  else
1596  {
1597  stream_session_t *sl = (stream_session_t *) ll;
1599  tc = listen_session_get_transport (sl);
1600  ls->port = tc->lcl_port;
1601  sm = app_worker_get_listen_segment_manager (server_wrk, sl);
1602  }
1603 
1604  seg_index = segment_manager_add_segment (sm, seg_size);
1605  if (seg_index < 0)
1606  {
1607  clib_warning ("failed to add new cut-through segment");
1608  return seg_index;
1609  }
1610  seg = segment_manager_get_segment_w_lock (sm, seg_index);
1611  sq = segment_manager_alloc_queue (seg, props);
1612  cq = segment_manager_alloc_queue (seg, cprops);
1613 
1614  if (props->use_mq_eventfd)
1616 
1617  ls->server_evt_q = pointer_to_uword (sq);
1618  ls->client_evt_q = pointer_to_uword (cq);
1619  rv = segment_manager_try_alloc_fifos (seg, props->rx_fifo_size,
1620  props->tx_fifo_size,
1621  &ls->server_rx_fifo,
1622  &ls->server_tx_fifo);
1623  if (rv)
1624  {
1625  clib_warning ("failed to add fifos in cut-through segment");
1627  goto failed;
1628  }
1629  ls->server_rx_fifo->ct_session_index = ls->session_index;
1630  ls->server_tx_fifo->ct_session_index = ls->session_index;
1631  ls->svm_segment_index = seg_index;
1632  ls->listener_index = ll->session_index;
1633  ls->client_wrk_index = client_wrk->wrk_index;
1634  ls->client_opaque = opaque;
1637 
1638  if ((rv = server->cb_fns.add_segment_callback (server->api_client_index,
1639  &seg->ssvm)))
1640  {
1641  clib_warning ("failed to notify server of new segment");
1643  goto failed;
1644  }
1646  if ((rv = server->cb_fns.session_accept_callback ((stream_session_t *) ls)))
1647  {
1648  clib_warning ("failed to send accept cut-through notify to server");
1649  goto failed;
1650  }
1651  if (server->flags & APP_OPTIONS_FLAGS_IS_BUILTIN)
1653 
1654  return 0;
1655 
1656 failed:
1657  if (!has_transport)
1658  segment_manager_del_segment (sm, seg);
1659  return rv;
1660 }
1661 
1662 static uword
1664 {
1665  return ((uword) ls->app_wrk_index << 32 | (uword) ls->session_index);
1666 }
1667 
1668 static void
1670  u32 * session_index)
1671 {
1672  *app_wrk_index = key >> 32;
1673  *session_index = key & 0xFFFFFFFF;
1674 }
1675 
1676 int
1678 {
1680  app_worker_t *client_wrk, *server_wrk;
1681  segment_manager_t *sm;
1682  application_t *client;
1683  int rv, is_fail = 0;
1684  uword client_key;
1685 
1686  client_wrk = app_worker_get (ls->client_wrk_index);
1687  server_wrk = app_worker_get (ls->app_wrk_index);
1688  client = application_get (client_wrk->app_index);
1689 
1692  if ((rv = client->cb_fns.add_segment_callback (client->api_client_index,
1693  &seg->ssvm)))
1694  {
1695  clib_warning ("failed to notify client %u of new segment",
1696  ls->client_wrk_index);
1699  is_fail = 1;
1700  }
1701  else
1702  {
1704  }
1705 
1706  client->cb_fns.session_connected_callback (client_wrk->wrk_index,
1707  ls->client_opaque,
1708  (stream_session_t *) ls,
1709  is_fail);
1710 
1711  client_key = application_client_local_connect_key (ls);
1712  hash_set (client_wrk->local_connects, client_key, client_key);
1713  return 0;
1714 }
1715 
1716 int
1718  app_worker_t * server_wrk,
1719  local_session_t * ls)
1720 {
1722  stream_session_t *listener;
1723  segment_manager_t *sm;
1724  uword client_key;
1725  u8 has_transport;
1726 
1727  /* Retrieve listener transport type as it is the one that decides where
1728  * the fifos are allocated */
1730  if (!has_transport)
1732  else
1733  {
1734  listener = listen_session_get (ls->listener_index);
1735  sm = app_worker_get_listen_segment_manager (server_wrk, listener);
1736  }
1737 
1739  if (client_wrk)
1740  {
1741  client_key = application_client_local_connect_key (ls);
1742  hash_unset (client_wrk->local_connects, client_key);
1743  }
1744 
1745  if (!has_transport)
1746  {
1747  application_t *server = application_get (server_wrk->app_index);
1748  server->cb_fns.del_segment_callback (server->api_client_index,
1749  &seg->ssvm);
1750  if (client_wrk)
1751  {
1752  application_t *client = application_get (client_wrk->app_index);
1753  client->cb_fns.del_segment_callback (client->api_client_index,
1754  &seg->ssvm);
1755  }
1756  segment_manager_del_segment (sm, seg);
1757  }
1758 
1759  application_local_session_free (server_wrk, ls);
1760 
1761  return 0;
1762 }
1763 
1764 int
1766 {
1767  app_worker_t *client_wrk, *server_wrk;
1768  u8 is_server = 0, is_client = 0;
1769  application_t *app;
1770 
1771  app = application_get_if_valid (app_index);
1772  if (!app)
1773  return 0;
1774 
1775  client_wrk = app_worker_get_if_valid (ls->client_wrk_index);
1776  server_wrk = app_worker_get (ls->app_wrk_index);
1777 
1778  if (server_wrk->app_index == app_index)
1779  is_server = 1;
1780  else if (client_wrk && client_wrk->app_index == app_index)
1781  is_client = 1;
1782 
1783  if (!is_server && !is_client)
1784  {
1785  clib_warning ("app %u is neither client nor server for session 0x%lx",
1786  app_index, application_local_session_handle (ls));
1787  return VNET_API_ERROR_INVALID_VALUE;
1788  }
1789 
1791  return application_local_session_cleanup (client_wrk, server_wrk, ls);
1792 
1793  if (app_index == ls->client_wrk_index)
1794  {
1796  }
1797  else
1798  {
1799  if (!client_wrk)
1800  {
1801  return application_local_session_cleanup (client_wrk, server_wrk,
1802  ls);
1803  }
1804  else if (ls->session_state < SESSION_STATE_READY)
1805  {
1806  application_t *client = application_get (client_wrk->app_index);
1807  client->cb_fns.session_connected_callback (client_wrk->wrk_index,
1808  ls->client_opaque,
1809  (stream_session_t *) ls,
1810  1 /* is_fail */ );
1812  return application_local_session_cleanup (client_wrk, server_wrk,
1813  ls);
1814  }
1815  else
1816  {
1818  }
1819  }
1820 
1822 
1823  return 0;
1824 }
1825 
1826 int
1828 {
1829  app_worker_t *app_wrk;
1830  local_session_t *ls;
1831  app_wrk = app_worker_get (app_wrk_index);
1832  ls = application_get_local_session (app_wrk, ls_index);
1833  return application_local_session_disconnect (app_wrk_index, ls);
1834 }
1835 
1836 void
1838 {
1839  u32 index, server_wrk_index, session_index;
1840  u64 handle, *handles = 0;
1841  app_worker_t *server_wrk;
1842  segment_manager_t *sm;
1843  local_session_t *ls;
1844  int i;
1845 
1846  /*
1847  * Local sessions
1848  */
1849  if (app_wrk->local_sessions)
1850  {
1851  /* *INDENT-OFF* */
1852  pool_foreach (ls, app_wrk->local_sessions, ({
1853  application_local_session_disconnect (app_wrk->wrk_index, ls);
1854  }));
1855  /* *INDENT-ON* */
1856  }
1857 
1858  /*
1859  * Local connects
1860  */
1861  vec_reset_length (handles);
1862  /* *INDENT-OFF* */
1863  hash_foreach (handle, index, app_wrk->local_connects, ({
1864  vec_add1 (handles, handle);
1865  }));
1866  /* *INDENT-ON* */
1867 
1868  for (i = 0; i < vec_len (handles); i++)
1869  {
1871  &server_wrk_index,
1872  &session_index);
1873  server_wrk = app_worker_get_if_valid (server_wrk_index);
1874  if (server_wrk)
1875  {
1876  ls = application_get_local_session (server_wrk, session_index);
1878  }
1879  }
1880 
1882  sm->app_wrk_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
1883  segment_manager_del (sm);
1884 }
1885 
1886 clib_error_t *
1888 {
1889  application_t *app;
1890  app = application_get (a->app_index);
1891  if (!app)
1892  return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1893  0, "app %u doesn't exist", a->app_index);
1894  app->tls_cert = vec_dup (a->cert);
1895  return 0;
1896 }
1897 
1898 clib_error_t *
1900 {
1901  application_t *app;
1902  app = application_get (a->app_index);
1903  if (!app)
1904  return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
1905  0, "app %u doesn't exist", a->app_index);
1906  app->tls_key = vec_dup (a->key);
1907  return 0;
1908 }
1909 
1910 u8 *
1911 format_app_worker_listener (u8 * s, va_list * args)
1912 {
1913  app_worker_t *app_wrk = va_arg (*args, app_worker_t *);
1914  u64 handle = va_arg (*args, u64);
1915  u32 sm_index = va_arg (*args, u32);
1916  int verbose = va_arg (*args, int);
1917  stream_session_t *listener;
1918  application_t *app;
1919  u8 *app_name, *str;
1920 
1921  if (!app_wrk)
1922  {
1923  if (verbose)
1924  s = format (s, "%-40s%-25s%=10s%-15s%-15s%-10s", "Connection", "App",
1925  "Wrk", "API Client", "ListenerID", "SegManager");
1926  else
1927  s = format (s, "%-40s%-25s%=10s", "Connection", "App", "Wrk");
1928 
1929  return s;
1930  }
1931 
1932  app = application_get (app_wrk->app_index);
1933  app_name = app_get_name_from_reg_index (app);
1934  listener = listen_session_get_from_handle (handle);
1935  str = format (0, "%U", format_stream_session, listener, verbose);
1936 
1937  if (verbose)
1938  {
1939  char buf[32];
1940  sprintf (buf, "%u(%u)", app_wrk->wrk_map_index, app_wrk->wrk_index);
1941  s = format (s, "%-40s%-25s%=10s%-15u%-15u%-10u", str, app_name,
1942  buf, app->api_client_index, handle, sm_index);
1943  }
1944  else
1945  s = format (s, "%-40s%-25s%=10u", str, app_name, app_wrk->wrk_map_index);
1946 
1947  vec_free (app_name);
1948  return s;
1949 }
1950 
1951 static void
1953 {
1955  app_worker_map_t *wrk_map;
1956  app_worker_t *app_wrk;
1957  u32 sm_index;
1958  u64 handle;
1959 
1960  if (!app)
1961  {
1962  vlib_cli_output (vm, "%U", format_app_worker_listener, 0 /* header */ ,
1963  0, 0, verbose);
1964  return;
1965  }
1966 
1967  /* *INDENT-OFF* */
1968  pool_foreach (wrk_map, app->worker_maps, ({
1969  app_wrk = app_worker_get (wrk_map->wrk_index);
1970  if (hash_elts (app_wrk->listeners_table) == 0)
1971  continue;
1972  hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1973  vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1974  handle, sm_index, verbose);
1975  }));
1976  }));
1977  /* *INDENT-ON* */
1978 }
1979 
1980 static void
1982 {
1983  svm_fifo_segment_private_t *fifo_segment;
1985  segment_manager_t *sm;
1986  u8 *app_name, *s = 0;
1987  application_t *app;
1988 
1989  /* Header */
1990  if (!app_wrk)
1991  {
1992  if (verbose)
1993  vlib_cli_output (vm, "%-40s%-20s%-15s%-10s", "Connection", "App",
1994  "API Client", "SegManager");
1995  else
1996  vlib_cli_output (vm, "%-40s%-20s", "Connection", "App");
1997  return;
1998  }
1999 
2000  app = application_get (app_wrk->app_index);
2001  if (app_wrk->connects_seg_manager == (u32) ~ 0)
2002  return;
2003 
2004  app_name = app_get_name_from_reg_index (app);
2005 
2006  /* Across all fifo segments */
2007  sm = segment_manager_get (app_wrk->connects_seg_manager);
2008 
2009  /* *INDENT-OFF* */
2010  segment_manager_foreach_segment_w_lock (fifo_segment, sm, ({
2011  svm_fifo_t *fifo;
2012  u8 *str;
2013 
2014  fifo = svm_fifo_segment_get_fifo_list (fifo_segment);
2015  while (fifo)
2016  {
2017  u32 session_index, thread_index;
2018  stream_session_t *session;
2019 
2020  session_index = fifo->master_session_index;
2021  thread_index = fifo->master_thread_index;
2022 
2023  session = session_get (session_index, thread_index);
2024  str = format (0, "%U", format_stream_session, session, verbose);
2025 
2026  if (verbose)
2027  s = format (s, "%-40s%-20s%-15u%-10u", str, app_name,
2028  app->api_client_index, app_wrk->connects_seg_manager);
2029  else
2030  s = format (s, "%-40s%-20s", str, app_name);
2031 
2032  vlib_cli_output (vm, "%v", s);
2033  vec_reset_length (s);
2034  vec_free (str);
2035 
2036  fifo = fifo->next;
2037  }
2038  vec_free (s);
2039  }));
2040  /* *INDENT-ON* */
2041 
2042  vec_free (app_name);
2043 }
2044 
2045 static void
2047 {
2048  app_worker_map_t *wrk_map;
2049  app_worker_t *app_wrk;
2050 
2051  if (!app)
2052  {
2053  app_worker_format_connects (0, verbose);
2054  return;
2055  }
2056 
2057  /* *INDENT-OFF* */
2058  pool_foreach (wrk_map, app->worker_maps, ({
2059  app_wrk = app_worker_get (wrk_map->wrk_index);
2060  app_worker_format_connects (app_wrk, verbose);
2061  }));
2062  /* *INDENT-ON* */
2063 }
2064 
2065 static void
2067 {
2069  local_session_t *ls;
2070  transport_proto_t tp;
2071  u8 *conn = 0;
2072 
2073  /* Header */
2074  if (app_wrk == 0)
2075  {
2076  vlib_cli_output (vm, "%-40s%-15s%-20s", "Connection", "ServerApp",
2077  "ClientApp");
2078  return;
2079  }
2080 
2081  if (!pool_elts (app_wrk->local_sessions)
2082  && !pool_elts (app_wrk->local_connects))
2083  return;
2084 
2085  /* *INDENT-OFF* */
2086  pool_foreach (ls, app_wrk->local_sessions, ({
2087  tp = session_type_transport_proto(ls->listener_session_type);
2088  conn = format (0, "[L][%U] *:%u", format_transport_proto_short, tp,
2089  ls->port);
2090  vlib_cli_output (vm, "%-40v%-15u%-20u", conn, ls->app_wrk_index,
2091  ls->client_wrk_index);
2092  vec_reset_length (conn);
2093  }));
2094  /* *INDENT-ON* */
2095 
2096  vec_free (conn);
2097 }
2098 
2099 static void
2101 {
2103  app_worker_map_t *wrk_map;
2104  app_worker_t *app_wrk;
2105  transport_proto_t tp;
2106  local_session_t *ls;
2107  u8 *conn = 0;
2108 
2109  if (!app)
2110  {
2111  app_worker_format_local_sessions (0, verbose);
2112  return;
2113  }
2114 
2115  /*
2116  * Format local listeners
2117  */
2118 
2119  /* *INDENT-OFF* */
2120  pool_foreach (ls, app->local_listen_sessions, ({
2121  tp = session_type_transport_proto (ls->listener_session_type);
2122  conn = format (0, "[L][%U] *:%u", format_transport_proto_short, tp,
2123  ls->port);
2124  vlib_cli_output (vm, "%-40v%-15u%-20s", conn, ls->app_wrk_index, "*");
2125  vec_reset_length (conn);
2126  }));
2127  /* *INDENT-ON* */
2128 
2129  /*
2130  * Format local accepted/connected sessions
2131  */
2132  /* *INDENT-OFF* */
2133  pool_foreach (wrk_map, app->worker_maps, ({
2134  app_wrk = app_worker_get (wrk_map->wrk_index);
2135  app_worker_format_local_sessions (app_wrk, verbose);
2136  }));
2137  /* *INDENT-ON* */
2138 }
2139 
2140 static void
2142 {
2144  u32 app_wrk_index, session_index;
2145  app_worker_t *server_wrk;
2146  local_session_t *ls;
2147  uword client_key;
2148  u64 value;
2149 
2150  /* Header */
2151  if (app == 0)
2152  {
2153  if (verbose)
2154  vlib_cli_output (vm, "%-40s%-15s%-20s%-10s", "Connection", "App",
2155  "Peer App", "SegManager");
2156  else
2157  vlib_cli_output (vm, "%-40s%-15s%-20s", "Connection", "App",
2158  "Peer App");
2159  return;
2160  }
2161 
2162  if (!app->local_connects)
2163  return;
2164 
2165  /* *INDENT-OFF* */
2166  hash_foreach (client_key, value, app->local_connects, ({
2167  application_client_local_connect_key_parse (client_key, &app_wrk_index,
2168  &session_index);
2169  server_wrk = app_worker_get (app_wrk_index);
2170  ls = application_get_local_session (server_wrk, session_index);
2171  vlib_cli_output (vm, "%-40s%-15s%-20s", "TODO", ls->app_wrk_index,
2172  ls->client_wrk_index);
2173  }));
2174  /* *INDENT-ON* */
2175 }
2176 
2177 static void
2179 {
2180  app_worker_map_t *wrk_map;
2181  app_worker_t *app_wrk;
2182 
2183  if (!app)
2184  {
2185  app_worker_format_local_connects (0, verbose);
2186  return;
2187  }
2188 
2189  /* *INDENT-OFF* */
2190  pool_foreach (wrk_map, app->worker_maps, ({
2191  app_wrk = app_worker_get (wrk_map->wrk_index);
2192  app_worker_format_local_connects (app_wrk, verbose);
2193  }));
2194  /* *INDENT-ON* */
2195 }
2196 
2197 u8 *
2198 format_application (u8 * s, va_list * args)
2199 {
2200  application_t *app = va_arg (*args, application_t *);
2201  CLIB_UNUSED (int verbose) = va_arg (*args, int);
2203  const u8 *app_ns_name;
2204  u8 *app_name;
2205 
2206  if (app == 0)
2207  {
2208  if (verbose)
2209  s = format (s, "%-10s%-20s%-15s%-15s%-15s%-15s%-15s", "Index", "Name",
2210  "API Client", "Namespace", "Add seg size", "Rx-f size",
2211  "Tx-f size");
2212  else
2213  s = format (s, "%-10s%-20s%-15s%-40s", "Index", "Name", "API Client",
2214  "Namespace");
2215  return s;
2216  }
2217 
2218  app_name = app_get_name (app);
2219  app_ns_name = app_namespace_id_from_index (app->ns_index);
2221  if (verbose)
2222  s = format (s, "%-10u%-20s%-15d%-15u%-15U%-15U%-15U", app->app_index,
2223  app_name, app->api_client_index, app->ns_index,
2224  format_memory_size, props->add_segment_size,
2225  format_memory_size, props->rx_fifo_size, format_memory_size,
2226  props->tx_fifo_size);
2227  else
2228  s = format (s, "%-10u%-20s%-15d%-40s", app->app_index, app_name,
2229  app->api_client_index, app_ns_name);
2230  return s;
2231 }
2232 
2233 void
2234 application_format_all_listeners (vlib_main_t * vm, int do_local, int verbose)
2235 {
2236  application_t *app;
2237 
2238  if (!pool_elts (app_main.app_pool))
2239  {
2240  vlib_cli_output (vm, "No active server bindings");
2241  return;
2242  }
2243 
2244  if (do_local)
2245  {
2246  application_format_local_sessions (0, verbose);
2247  /* *INDENT-OFF* */
2248  pool_foreach (app, app_main.app_pool, ({
2249  application_format_local_sessions (app, verbose);
2250  }));
2251  /* *INDENT-ON* */
2252  }
2253  else
2254  {
2255  application_format_listeners (0, verbose);
2256 
2257  /* *INDENT-OFF* */
2258  pool_foreach (app, app_main.app_pool, ({
2259  application_format_listeners (app, verbose);
2260  }));
2261  /* *INDENT-ON* */
2262  }
2263 }
2264 
2265 void
2266 application_format_all_clients (vlib_main_t * vm, int do_local, int verbose)
2267 {
2268  application_t *app;
2269 
2270  if (!pool_elts (app_main.app_pool))
2271  {
2272  vlib_cli_output (vm, "No active apps");
2273  return;
2274  }
2275 
2276  if (do_local)
2277  {
2278  application_format_local_connects (0, verbose);
2279 
2280  /* *INDENT-OFF* */
2281  pool_foreach (app, app_main.app_pool, ({
2282  application_format_local_connects (app, verbose);
2283  }));
2284  /* *INDENT-ON* */
2285  }
2286  else
2287  {
2288  application_format_connects (0, verbose);
2289 
2290  /* *INDENT-OFF* */
2291  pool_foreach (app, app_main.app_pool, ({
2292  application_format_connects (app, verbose);
2293  }));
2294  /* *INDENT-ON* */
2295  }
2296 }
2297 
2298 static clib_error_t *
2300  vlib_cli_command_t * cmd)
2301 {
2302  int do_server = 0, do_client = 0, do_local = 0;
2303  application_t *app;
2304  int verbose = 0;
2305 
2307 
2308  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2309  {
2310  if (unformat (input, "server"))
2311  do_server = 1;
2312  else if (unformat (input, "client"))
2313  do_client = 1;
2314  else if (unformat (input, "local"))
2315  do_local = 1;
2316  else if (unformat (input, "verbose"))
2317  verbose = 1;
2318  else
2319  break;
2320  }
2321 
2322  if (do_server)
2323  application_format_all_listeners (vm, do_local, verbose);
2324 
2325  if (do_client)
2326  application_format_all_clients (vm, do_local, verbose);
2327 
2328  /* Print app related info */
2329  if (!do_server && !do_client)
2330  {
2331  vlib_cli_output (vm, "%U", format_application, 0, verbose);
2332  /* *INDENT-OFF* */
2333  pool_foreach (app, app_main.app_pool, ({
2334  vlib_cli_output (vm, "%U", format_application, app, verbose);
2335  }));
2336  /* *INDENT-ON* */
2337  }
2338 
2339  return 0;
2340 }
2341 
2342 /* *INDENT-OFF* */
2343 VLIB_CLI_COMMAND (show_app_command, static) =
2344 {
2345  .path = "show app",
2346  .short_help = "show app [server|client] [verbose]",
2347  .function = show_app_command_fn,
2348 };
2349 /* *INDENT-ON* */
2350 
2351 /*
2352  * fd.io coding-style-patch-verification: ON
2353  *
2354  * Local Variables:
2355  * eval: (c-set-style "gnu")
2356  * End:
2357  */
static void application_table_add(application_t *app)
Definition: application.c:192
u32 flags
Flags.
Definition: application.h:128
static app_listener_t * app_local_listener_alloc(application_t *app)
Definition: application.c:49
int application_stop_listen(u32 app_index, u32 app_wrk_index, session_handle_t handle)
Stop listening on session associated to handle.
Definition: application.c:799
struct _vnet_app_worker_add_del_args vnet_app_worker_add_del_args_t
session_type_t listener_session_type
Has transport embedded when listener not purely local.
app_worker_t * app_worker_get(u32 wrk_index)
Definition: application.c:499
static int app_send_io_evt_rx(app_worker_t *app_wrk, stream_session_t *s, u8 lock)
Definition: application.c:1225
static u8 svm_msg_q_msg_is_invalid(svm_msg_q_msg_t *msg)
Check if message is invalid.
u8 * name
Client name.
Definition: api_common.h:51
int application_local_session_disconnect_w_index(u32 app_wrk_index, u32 ls_index)
Definition: application.c:1827
#define hash_set(h, key, value)
Definition: hash.h:255
void segment_manager_segment_reader_unlock(segment_manager_t *sm)
void * svm_msg_q_msg_data(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Get data for message in queue.
static u8 svm_msg_q_ring_is_full(svm_msg_q_t *mq, u32 ring_index)
application_t * app_worker_get_app(u32 wrk_index)
Definition: application.c:627
int session_open(u32 app_wrk_index, session_endpoint_t *rmt, u32 opaque)
Ask transport to open connection to remote transport endpoint.
Definition: session.c:992
#define CLIB_UNUSED(x)
Definition: clib.h:81
static session_handle_t application_local_session_handle(local_session_t *ls)
Definition: application.h:350
int app_worker_alloc_and_init(application_t *app, app_worker_t **wrk)
Definition: application.c:579
#define hash_unset(h, key)
Definition: hash.h:261
a
Definition: bitmap.h:538
u64 session_lookup_endpoint_listener(u32 table_index, session_endpoint_t *sep, u8 use_rules)
Lookup listener for session endpoint in table.
u32 ns_index
Namespace the application belongs to.
Definition: application.h:143
u8 application_has_global_scope(application_t *app)
Definition: application.c:970
u8 app_worker_application_is_builtin(app_worker_t *app_wrk)
Definition: application.c:1023
struct _transport_connection transport_connection_t
struct _segment_manager_properties segment_manager_properties_t
int app_worker_stop_listen(app_worker_t *app_wrk, session_handle_t handle)
Definition: application.c:681
app_worker_t * app_worker_alloc(application_t *app)
Definition: application.c:483
void app_worker_free(app_worker_t *app_wrk)
Definition: application.c:513
#define session_cli_return_if_not_enabled()
Definition: session.h:654
segment_manager_properties_t * application_get_segment_manager_properties(u32 app_index)
Definition: application.c:1191
static clib_error_t * show_app_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: application.c:2299
unsigned long u64
Definition: types.h:89
clib_error_t * vnet_unbind(vnet_unbind_args_t *a)
svm_msg_q_t * segment_manager_alloc_queue(svm_fifo_segment_private_t *segment, segment_manager_properties_t *props)
Allocates shm queue in the first segment.
app_worker_t * application_listener_select_worker(stream_session_t *ls, u8 is_local)
Definition: application.c:460
#define SESSION_PROXY_LISTENER_INDEX
Definition: session.h:27
static app_listener_t * app_listener_get(application_t *app, u32 app_listener_index)
Definition: application.c:34
application_t * application_lookup_name(const u8 *name)
Definition: application.c:222
u32 session_lookup_get_index_for_fib(u32 fib_proto, u32 fib_index)
local_session_t * local_listen_sessions
Pool of local listen sessions.
Definition: application.h:154
local_session_t * application_get_local_session_from_handle(session_handle_t handle)
Definition: application.c:1374
int application_local_session_connect(app_worker_t *client_wrk, app_worker_t *server_wrk, local_session_t *ll, u32 opaque)
Definition: application.c:1562
static int svm_msg_q_get_producer_eventfd(svm_msg_q_t *mq)
static void application_client_local_connect_key_parse(uword key, u32 *app_wrk_index, u32 *session_index)
Definition: application.c:1669
application_t * application_lookup(u32 api_client_index)
Definition: application.c:211
void application_free(application_t *app)
Definition: application.c:388
app_listener_t * listeners
Pool of listeners for the app.
Definition: application.h:148
u32 wrk_map_index
Worker index in app&#39;s map pool.
Definition: application.h:69
int i
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
#define hash_set_mem(h, key, value)
Definition: hash.h:275
static app_send_evt_handler_fn *const app_send_evt_handler_fns[3]
Definition: application.c:1312
void svm_fifo_dequeue_drop_all(svm_fifo_t *f)
Definition: svm_fifo.c:766
svm_fifo_t * server_tx_fifo
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
void app_worker_local_sessions_free(app_worker_t *app_wrk)
Definition: application.c:1837
u64 session_handle_t
Definition: session.h:107
segment_manager_properties_t * segment_manager_properties_init(segment_manager_properties_t *props)
uword * listeners_table
Lookup tables for listeners.
Definition: application.h:81
#define segment_manager_foreach_segment_w_lock(VAR, SM, BODY)
struct _vnet_application_add_tls_cert_args_t vnet_app_add_tls_cert_args_t
int app_worker_start_listen(app_worker_t *app_wrk, stream_session_t *ls)
Definition: application.c:657
#define SESSION_ENDPOINT_EXT_NULL
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:228
u32 connects_seg_manager
Segment manager used for outgoing connects issued by the app.
Definition: application.h:78
u8 application_use_mq_for_ctrl(application_t *app)
Definition: application.c:976
u32 segment_manager_evt_q_expected_size(u32 q_len)
clib_error_t * vnet_app_add_tls_cert(vnet_app_add_tls_cert_args_t *a)
Definition: application.c:1887
unsigned char u8
Definition: types.h:56
static stream_session_t * listen_session_get_from_handle(session_handle_t handle)
Definition: session.h:606
app_worker_t * application_get_worker(application_t *app, u32 wrk_map_index)
Definition: application.c:444
void application_local_session_free(app_worker_t *app, local_session_t *s)
Definition: application.c:1358
int segment_manager_init(segment_manager_t *sm, u32 first_seg_size, u32 prealloc_fifo_pairs)
Initializes segment manager based on options provided.
application_t * application_get_if_valid(u32 app_index)
Definition: application.c:251
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define SESSION_ENDPOINT_NULL
struct _svm_fifo svm_fifo_t
static uword clib_bitmap_set_no_check(uword *a, uword i, uword new_value)
Sets the ith bit of a bitmap to new_value.
Definition: bitmap.h:141
segment_manager_t * app_worker_get_listen_segment_manager(app_worker_t *app, stream_session_t *listener)
Definition: application.c:874
int session_stop_listen(stream_session_t *s)
Ask transport to stop listening on local transport endpoint.
Definition: session.c:1037
connectionless service
int application_is_proxy(application_t *app)
Definition: application.c:946
static int svm_fifo_is_empty(svm_fifo_t *f)
Definition: svm_fifo.h:126
enum ssvm_segment_type_ ssvm_segment_type_t
memset(h->entries, 0, sizeof(h->entries[0])*entries)
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:443
u32 first_segment_manager
First segment manager has in the the first segment the application&#39;s event fifo.
Definition: application.h:88
static void application_table_del(application_t *app)
Definition: application.c:202
static uword clib_bitmap_is_zero(uword *ai)
predicate function; is an entire bitmap empty?
Definition: bitmap.h:57
int application_local_session_connect_notify(local_session_t *ls)
Definition: application.c:1677
u32 transport_listener_index
Transport listener index.
struct _stream_session_cb_vft session_cb_vft_t
struct _vnet_unbind_args_t vnet_unbind_args_t
svm_fifo_segment_private_t * segment_manager_get_segment_w_lock(segment_manager_t *sm, u32 segment_index)
Reads a segment from the segment manager&#39;s pool and acquires reader lock.
app_listener_t * local_listeners
Pool of local listeners for app.
Definition: application.h:151
#define hash_foreach(key_var, value_var, h, body)
Definition: hash.h:442
session_type_t session_type
Type.
u8 * format_memory_size(u8 *s, va_list *va)
Definition: std-formats.c:193
static stream_session_t * listen_session_get(u32 index)
Definition: session.h:629
#define transport_proto_foreach(VAR, BODY)
static u8 * app_get_name_from_reg_index(application_t *app)
Definition: application.c:101
u32 application_index(application_t *app)
Definition: application.c:260
unsigned int u32
Definition: types.h:88
static local_session_t * application_get_local_listen_session(application_t *app, u32 session_index)
Definition: application.h:357
u16 proxied_transports
Definition: application.h:145
struct _stream_session_t stream_session_t
u8 tls_engine
Preferred tls engine.
Definition: application.h:167
segment_manager_t * segment_manager_new()
#define pool_flush(VAR, POOL, BODY)
Remove all elements from a pool in a safe way.
Definition: pool.h:503
static app_main_t app_main
Definition: application.c:21
static void application_verify_cb_fns(session_cb_vft_t *cb_fns)
Definition: application.c:266
clib_error_t * vnet_app_add_tls_key(vnet_app_add_tls_key_args_t *a)
Definition: application.c:1899
app_worker_t * workers
Pool of workers associated to apps.
Definition: application.h:181
static void listen_session_del(stream_session_t *s)
Definition: session.h:635
static int app_enqueue_evt(svm_msg_q_t *mq, svm_msg_q_msg_t *msg, u8 lock)
Definition: application.c:1198
int application_is_builtin(application_t *app)
Definition: application.c:952
#define hash_get(h, key)
Definition: hash.h:249
u32 app_namespace_get_fib_index(app_namespace_t *app_ns, u8 fib_proto)
static svm_fifo_t * svm_fifo_segment_get_fifo_list(svm_fifo_segment_private_t *fifo_segment)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
#define hash_unset_mem(h, key)
Definition: hash.h:291
#define VL_API_INVALID_FI
Definition: api_common.h:75
struct _session_endpoint session_endpoint_t
static uword clib_bitmap_first_set(uword *ai)
Return the lowest numbered set bit in a bitmap.
Definition: bitmap.h:385
static u8 * app_get_name(application_t *app)
Definition: application.c:116
int application_start_listen(application_t *app, session_endpoint_extended_t *sep_ext, session_handle_t *res)
Start listening local transport endpoint for requested transport.
Definition: application.c:717
stream_session_t * application_proxy_listener(app_worker_t *app, u8 fib_proto, u8 transport_proto)
Definition: application.c:1029
svm_fifo_t * server_rx_fifo
fifo pointers.
app_worker_t * app_worker_get_if_valid(u32 wrk_index)
Definition: application.c:505
static u8 session_handle_is_local(session_handle_t handle)
Definition: session.h:377
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static u32 app_worker_map_index(application_t *app, app_worker_map_t *map)
Definition: application.c:83
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:274
#define APP_INVALID_INDEX
Definition: application.h:218
local_session_t * application_local_listen_session_alloc(application_t *app)
Definition: application.c:1386
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:373
u32 application_local_listener_index(application_t *app, local_session_t *ll)
Definition: application.c:1395
svm_fifo_segment_private_t * segment_manager_get_segment(segment_manager_t *sm, u32 segment_index)
Reads a segment from the segment manager&#39;s pool without lock.
u8 segment_manager_has_fifos(segment_manager_t *sm)
#define PREDICT_FALSE(x)
Definition: clib.h:107
u32 svm_segment_index
Segment index where fifos were allocated.
static u8 application_local_session_listener_has_transport(local_session_t *ls)
Definition: application.h:373
app_namespace_t * app_namespace_get(u32 index)
u32 wrk_index
Worker index in global worker pool.
Definition: application.h:66
u32 application_session_table(application_t *app, u8 fib_proto)
Definition: application.c:124
static void application_local_session_fix_eventds(svm_msg_q_t *sq, svm_msg_q_t *cq)
Definition: application.c:1545
stream_session_t * app_worker_first_listener(app_worker_t *app, u8 fib_proto, u8 transport_proto)
Definition: application.c:999
void segment_manager_del_segment(segment_manager_t *sm, svm_fifo_segment_private_t *fs)
Remove segment without lock.
u8 * application_name_from_index(u32 app_index)
Returns app name.
Definition: application.c:183
int segment_manager_add_segment(segment_manager_t *sm, u32 segment_size)
Adds segment to segment manager&#39;s pool.
u8 name[64]
Definition: memclnt.api:151
volatile u8 session_state
State.
static stream_session_t * session_get(u32 si, u32 thread_index)
Definition: session.h:314
app_worker_map_t * worker_maps
Pool of mappings that keep track of workers associated to this app.
Definition: application.h:137
int session_alloc_fifos(segment_manager_t *sm, stream_session_t *s)
Definition: session.c:165
#define SEGMENT_MANAGER_INVALID_APP_INDEX
#define pool_free(p)
Free a pool.
Definition: pool.h:357
static u8 svm_fifo_set_event(svm_fifo_t *f)
Sets fifo event flag.
Definition: svm_fifo.h:157
An API client registration, only in vpp/vlib.
Definition: api_common.h:44
u32 application_local_session_table(application_t *app)
Definition: application.c:139
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
static int app_send_io_evt_tx(app_worker_t *app_wrk, stream_session_t *s, u8 lock)
Definition: application.c:1277
uword * app_by_name
Hash table of builtin apps by name.
Definition: application.h:191
static session_type_t session_type_from_proto_and_ip(transport_proto_t proto, u8 is_ip4)
Definition: session.h:410
vlib_main_t * vm
Definition: buffer.c:294
static void svm_msg_q_unlock(svm_msg_q_t *mq)
Unlock message queue.
static void app_listener_free(application_t *app, app_listener_t *app_listener)
Definition: application.c:40
static transport_proto_t session_type_transport_proto(session_type_t st)
Definition: session.h:385
static segment_manager_t * app_worker_alloc_segment_manager(app_worker_t *app_wrk)
Definition: application.c:637
int session_listen(stream_session_t *ls, session_endpoint_extended_t *sep)
Ask transport to listen on session endpoint.
Definition: session.c:1007
svm_queue_t * vl_api_client_index_to_input_queue(u32 index)
Definition: memory_api.c:759
u8 * format_stream_session(u8 *s, va_list *args)
Format stream session as per the following format.
Definition: session_cli.c:57
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
transport_service_type_t session_transport_service_type(stream_session_t *s)
Definition: session.c:1141
int session_lookup_del_session_endpoint(u32 table_index, session_endpoint_t *sep)
#define clib_warning(format, args...)
Definition: error.h:59
#define SESSION_INVALID_HANDLE
Definition: session_table.h:59
int svm_msg_q_add(svm_msg_q_t *mq, svm_msg_q_msg_t *msg, int nowait)
Producer enqueue one message to queue.
u32 local_segment_manager
Segment manager used for incoming "cut through" connects.
Definition: application.h:96
clib_bitmap_t * workers
workers accepting connections
Definition: application.h:114
segment_manager_properties_t sm_properties
Segment manager properties.
Definition: application.h:134
u16 port
Port for connection.
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:271
const u8 * app_namespace_id_from_index(u32 index)
static uword clib_bitmap_get(uword *ai, uword i)
Gets the ith bit value from a bitmap.
Definition: bitmap.h:197
blocking call - best used in combination with condvars, for eventfds we don&#39;t yield the cpu ...
Definition: queue.h:42
void application_local_listen_session_free(application_t *app, local_session_t *ll)
Definition: application.c:1401
static vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
Definition: api.h:56
int session_lookup_add_session_endpoint(u32 table_index, session_endpoint_t *sep, u64 value)
u32 app_wrk_index
Server index.
static u32 vl_api_registration_file_index(vl_api_registration_t *reg)
Definition: api.h:64
static u8 session_has_transport(stream_session_t *s)
Definition: session.h:416
int segment_manager_try_alloc_fifos(svm_fifo_segment_private_t *fifo_segment, u32 rx_fifo_size, u32 tx_fifo_size, svm_fifo_t **rx_fifo, svm_fifo_t **tx_fifo)
struct _app_namespace app_namespace_t
application_t * application_get(u32 app_index)
Definition: application.c:243
application_t * application_alloc(void)
Definition: application.c:233
static u32 segment_manager_index(segment_manager_t *sm)
int app_worker_lock_and_send_event(app_worker_t *app, stream_session_t *s, u8 evt_type)
Send event to application.
Definition: application.c:1339
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
#define hash_create(elts, value_bytes)
Definition: hash.h:696
ssvm_private_t * session_manager_get_evt_q_segment(void)
Definition: session.c:1236
void segment_manager_init_del(segment_manager_t *sm)
local_session_t * application_local_session_alloc(app_worker_t *app_wrk)
Definition: application.c:1346
static void app_local_listener_free(application_t *app, app_listener_t *app_listener)
Definition: application.c:65
static uword hash_elts(void *v)
Definition: hash.h:118
#define ASSERT(truth)
u32 client_wrk_index
Client data.
void svm_msg_q_add_and_unlock(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Producer enqueue one message to queue with mutex held.
u8 session_type_t
static local_session_t * application_get_local_listener_w_handle(session_handle_t handle)
Definition: application.h:363
static void application_format_local_connects(application_t *app, int verbose)
Definition: application.c:2178
static u8 session_endpoint_fib_proto(session_endpoint_t *sep)
int application_start_local_listen(application_t *app, session_endpoint_extended_t *sep_ext, session_handle_t *handle)
Definition: application.c:1410
uword * app_by_api_client_index
Hash table of apps by api client index.
Definition: application.h:186
static app_listener_t * app_local_listener_get(application_t *app, u32 app_listener_index)
Definition: application.c:59
void application_remove_proxy(application_t *app)
Definition: application.c:1169
session_cb_vft_t cb_fns
Callbacks: shoulder-taps for the server/client.
Definition: application.h:131
struct _vnet_application_add_tls_key_args_t vnet_app_add_tls_key_args_t
int app_worker_alloc_connects_segment_manager(app_worker_t *app_wrk)
Definition: application.c:852
int listen_session_get_local_session_endpoint(stream_session_t *listener, session_endpoint_t *sep)
Definition: session.c:1309
u8 * tls_key
PEM encoded key.
Definition: application.h:164
#define clib_bitmap_free(v)
Free a bitmap.
Definition: bitmap.h:92
int application_local_session_disconnect(u32 app_index, local_session_t *ls)
Definition: application.c:1765
void application_format_all_listeners(vlib_main_t *vm, int do_local, int verbose)
Definition: application.c:2234
segment_manager_t * application_get_local_segment_manager(app_worker_t *app)
Definition: application.c:927
u32 accept_rotor
last worker to accept a connection
Definition: application.h:115
u32 api_client_index
Binary API connection index, ~0 if internal.
Definition: application.h:125
static svm_msg_q_t * segment_manager_event_queue(segment_manager_t *sm)
static uword pointer_to_uword(const void *p)
Definition: types.h:131
int application_alloc_and_init(app_init_args_t *a)
Definition: application.c:306
void svm_msg_q_set_consumer_eventfd(svm_msg_q_t *mq, int fd)
Set event fd for queue consumer.
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u8 * format_app_worker_listener(u8 *s, va_list *args)
Definition: application.c:1911
static void app_worker_format_connects(app_worker_t *app_wrk, int verbose)
Definition: application.c:1981
static void app_worker_format_local_sessions(app_worker_t *app_wrk, int verbose)
Definition: application.c:2066
u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
Definition: ip.c:20
u32 application_n_listeners(app_worker_t *app)
Definition: application.c:993
u32 app_index
App index in app pool.
Definition: application.h:122
void segment_manager_del(segment_manager_t *sm)
Removes segment manager.
int application_local_session_cleanup(app_worker_t *client_wrk, app_worker_t *server_wrk, local_session_t *ls)
Definition: application.c:1717
local_session_t * application_get_local_session(app_worker_t *app_wrk, u32 session_index)
Definition: application.c:1366
application_t * app_pool
Pool from which we allocate all applications.
Definition: application.h:176
void svm_msg_q_free_msg(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Free message buffer.
enum _transport_proto transport_proto_t
transport_connection_t * listen_session_get_transport(stream_session_t *s)
Definition: session.c:1302
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u8 * format_application(u8 *s, va_list *args)
Definition: application.c:2198
u8 * name
Name registered by builtin apps.
Definition: application.h:140
static uword max_log2(uword x)
Definition: clib.h:187
static stream_session_t * listen_session_new(u8 thread_index, session_type_t type)
Definition: session.h:619
u64 uword
Definition: types.h:112
u32 session_index
Session index.
void segment_manager_del_sessions(segment_manager_t *sm)
Initiate disconnects for all sessions &#39;owned&#39; by a segment manager.
static app_worker_map_t * app_worker_map_alloc(application_t *app)
Definition: application.c:74
int app_worker_open_session(app_worker_t *app, session_endpoint_t *sep, u32 api_context)
Definition: application.c:837
app_worker_t * application_get_default_worker(application_t *app)
Definition: application.c:454
struct _segment_manager segment_manager_t
struct _svm_queue svm_queue_t
static void application_format_listeners(application_t *app, int verbose)
Definition: application.c:1952
static clib_error_t * application_start_stop_proxy_fib_proto(application_t *app, u8 fib_proto, u8 transport_proto, u8 is_start)
Definition: application.c:1053
#define hash_get_mem(h, key)
Definition: hash.h:269
static void application_format_local_sessions(application_t *app, int verbose)
Definition: application.c:2100
static uword application_client_local_connect_key(local_session_t *ls)
Definition: application.c:1663
u32 app_index
Index of owning app.
Definition: application.h:72
int( app_send_evt_handler_fn)(app_worker_t *app, stream_session_t *s, u8 lock)
Definition: application.c:1309
static void application_start_stop_proxy_local_scope(application_t *app, u8 transport_proto, u8 is_start)
Definition: application.c:1110
uword * local_connects
Hash table of the app&#39;s local connects.
Definition: application.h:102
int application_stop_local_listen(u32 app_index, u32 wrk_map_index, session_handle_t lh)
Clean up local session table.
Definition: application.c:1472
local_session_t * local_sessions
Pool of local sessions the app owns (as a server)
Definition: application.h:99
segment_manager_t * application_get_local_segment_manager_w_session(app_worker_t *app, local_session_t *ls)
Definition: application.c:933
int app_worker_add_segment_notify(u32 app_wrk_index, ssvm_private_t *fs)
Send an API message to the external app, to map new segment.
Definition: application.c:985
#define clib_error_return_code(e, code, flags, args...)
Definition: error.h:93
u8 * tls_cert
Certificate to be used for listen sessions.
Definition: application.h:161
static app_worker_map_t * app_worker_map_get(application_t *app, u32 map_index)
Definition: application.c:95
static int svm_fifo_has_event(svm_fifo_t *f)
Definition: svm_fifo.h:138
void application_setup_proxy(application_t *app)
Definition: application.c:1153
static u8 application_verify_cfg(ssvm_segment_type_t st)
Check app config for given segment type.
Definition: application.c:284
static void application_format_connects(application_t *app, int verbose)
Definition: application.c:2046
int application_is_builtin_proxy(application_t *app)
Definition: application.c:958
segment_manager_t * app_worker_get_connect_segment_manager(app_worker_t *app)
Definition: application.c:867
static void app_worker_map_free(application_t *app, app_worker_map_t *map)
Definition: application.c:89
int app_worker_send_event(app_worker_t *app, stream_session_t *s, u8 evt_type)
Send event to application.
Definition: application.c:1326
void application_start_stop_proxy(application_t *app, transport_proto_t transport_proto, u8 is_start)
Definition: application.c:1137
int application_api_queue_is_full(application_t *app)
Definition: application.c:159
static int svm_msg_q_lock(svm_msg_q_t *mq)
Lock, or block trying, the message queue.
segment_manager_properties_t * application_segment_manager_properties(application_t *app)
Definition: application.c:1185
svm_msg_q_t * event_queue
Application listens for events on this svm queue.
Definition: application.h:75
static void application_local_listener_session_endpoint(local_session_t *ll, session_endpoint_t *sep)
Definition: application.c:149
#define APP_INVALID_SEGMENT_MANAGER_INDEX
Definition: application.h:220
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:725
static u8 svm_msg_q_is_full(svm_msg_q_t *mq)
Check if message queue is full.
#define APP_DBG(_fmt, _args...)
Definition: application.h:28
static segment_manager_t * segment_manager_get(u32 index)
svm_msg_q_msg_t svm_msg_q_alloc_msg_w_ring(svm_msg_q_t *mq, u32 ring_index)
Allocate message buffer on ring.
static u64 listen_session_get_handle(stream_session_t *s)
Definition: session.h:599
struct _session_endpoint_extended session_endpoint_extended_t
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u8 first_segment_manager_in_use
Definition: application.h:89
static void local_session_parse_handle(session_handle_t handle, u32 *app_or_wrk_index, u32 *session_index)
Definition: application.h:340
clib_error_t * vnet_app_worker_add_del(vnet_app_worker_add_del_args_t *a)
Definition: application.c:884
void application_format_all_clients(vlib_main_t *vm, int do_local, int verbose)
Definition: application.c:2266
void mq_send_local_session_disconnected_cb(u32 app_or_wrk, local_session_t *ls)
Definition: session_api.c:531
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
static void app_worker_format_local_connects(app_worker_t *app, int verbose)
Definition: application.c:2141
static app_listener_t * app_listener_alloc(application_t *app)
Definition: application.c:24
u8 application_has_local_scope(application_t *app)
Definition: application.c:964
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128