vcl/session: add api for changing session app worker
[vpp.git] / src / vnet / session / application.c
index a70625a..85b5f93 100644 (file)
@@ -94,6 +94,8 @@ app_worker_map_free (application_t * app, app_worker_map_t * map)
 static app_worker_map_t *
 app_worker_map_get (application_t * app, u32 map_index)
 {
+  if (pool_is_free_index (app->worker_maps, map_index))
+    return 0;
   return pool_elt_at_index (app->worker_maps, map_index);
 }
 
@@ -443,7 +445,7 @@ application_detach_process (application_t * app, u32 api_client_index)
   vec_foreach (wrk_index, wrks)
   {
     app_wrk = app_worker_get (wrk_index[0]);
-    args->wrk_index = app_wrk->wrk_map_index;
+    args->wrk_map_index = app_wrk->wrk_map_index;
     args->is_add = 0;
     vnet_app_worker_add_del (args);
   }
@@ -722,6 +724,48 @@ app_worker_stop_listen (app_worker_t * app_wrk, session_handle_t handle)
   return 0;
 }
 
+int
+app_worker_own_session (app_worker_t * app_wrk, stream_session_t * s)
+{
+  segment_manager_t *sm;
+  svm_fifo_t *rxf, *txf;
+
+  s->app_wrk_index = app_wrk->wrk_index;
+
+  rxf = s->server_rx_fifo;
+  txf = s->server_tx_fifo;
+
+  if (!rxf || !txf)
+    return 0;
+
+  s->server_rx_fifo = 0;
+  s->server_tx_fifo = 0;
+
+  sm = app_worker_get_or_alloc_connect_segment_manager (app_wrk);
+  if (session_alloc_fifos (sm, s))
+    return -1;
+
+  if (!svm_fifo_is_empty (rxf))
+    {
+      clib_memcpy_fast (s->server_rx_fifo->data, rxf->data, rxf->nitems);
+      s->server_rx_fifo->head = rxf->head;
+      s->server_rx_fifo->tail = rxf->tail;
+      s->server_rx_fifo->cursize = rxf->cursize;
+    }
+
+  if (!svm_fifo_is_empty (txf))
+    {
+      clib_memcpy_fast (s->server_tx_fifo->data, txf->data, txf->nitems);
+      s->server_tx_fifo->head = txf->head;
+      s->server_tx_fifo->tail = txf->tail;
+      s->server_tx_fifo->cursize = txf->cursize;
+    }
+
+  segment_manager_dealloc_fifos (rxf->segment_index, rxf, txf);
+
+  return 0;
+}
+
 /**
  * Start listening local transport endpoint for requested transport.
  *
@@ -887,6 +931,14 @@ app_worker_get_connect_segment_manager (app_worker_t * app)
   return segment_manager_get (app->connects_seg_manager);
 }
 
+segment_manager_t *
+app_worker_get_or_alloc_connect_segment_manager (app_worker_t * app_wrk)
+{
+  if (app_wrk->connects_seg_manager == (u32) ~ 0)
+    app_worker_alloc_connects_segment_manager (app_wrk);
+  return segment_manager_get (app_wrk->connects_seg_manager);
+}
+
 segment_manager_t *
 app_worker_get_listen_segment_manager (app_worker_t * app,
                                       stream_session_t * listener)
@@ -924,21 +976,22 @@ vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
       sm = segment_manager_get (app_wrk->first_segment_manager);
       fs = segment_manager_get_segment_w_lock (sm, 0);
       a->segment = &fs->ssvm;
+      a->segment_handle = segment_manager_segment_handle (sm, fs);
       segment_manager_segment_reader_unlock (sm);
       a->evt_q = app_wrk->event_queue;
-      a->wrk_index = app_wrk->wrk_map_index;
+      a->wrk_map_index = app_wrk->wrk_map_index;
     }
   else
     {
-      wrk_map = app_worker_map_get (app, a->wrk_index);
+      wrk_map = app_worker_map_get (app, a->wrk_map_index);
       if (!wrk_map)
        return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
                                       "App %u does not have worker %u",
-                                      app->app_index, a->wrk_index);
+                                      app->app_index, a->wrk_map_index);
       app_wrk = app_worker_get (wrk_map->wrk_index);
       if (!app_wrk)
        return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0,
-                                      "No worker %u", a->wrk_index);
+                                      "No worker %u", a->wrk_map_index);
       application_api_table_del (app_wrk->api_client_index);
       app_worker_free (app_wrk);
       app_worker_map_free (app, wrk_map);
@@ -1007,11 +1060,12 @@ application_use_mq_for_ctrl (application_t * app)
  * Send an API message to the external app, to map new segment
  */
 int
-app_worker_add_segment_notify (u32 app_wrk_index, ssvm_private_t * fs)
+app_worker_add_segment_notify (u32 app_wrk_index, u64 segment_handle)
 {
   app_worker_t *app_wrk = app_worker_get (app_wrk_index);
   application_t *app = application_get (app_wrk->app_index);
-  return app->cb_fns.add_segment_callback (app_wrk->api_client_index, fs);
+  return app->cb_fns.add_segment_callback (app_wrk->api_client_index,
+                                          segment_handle);
 }
 
 u32
@@ -1589,14 +1643,15 @@ application_local_session_connect (app_worker_t * client_wrk,
                                   local_session_t * ll, u32 opaque)
 {
   u32 seg_size, evt_q_sz, evt_q_elts, margin = 16 << 10;
+  u32 round_rx_fifo_sz, round_tx_fifo_sz, sm_index;
   segment_manager_properties_t *props, *cprops;
-  u32 round_rx_fifo_sz, round_tx_fifo_sz;
   int rv, has_transport, seg_index;
   svm_fifo_segment_private_t *seg;
   application_t *server, *client;
   segment_manager_t *sm;
   local_session_t *ls;
   svm_msg_q_t *sq, *cq;
+  u64 segment_handle;
 
   ls = application_local_session_alloc (server_wrk);
   server = application_get (server_wrk->app_index);
@@ -1651,8 +1706,13 @@ application_local_session_connect (app_worker_t * client_wrk,
       segment_manager_segment_reader_unlock (sm);
       goto failed;
     }
+  sm_index = segment_manager_index (sm);
   ls->server_rx_fifo->ct_session_index = ls->session_index;
   ls->server_tx_fifo->ct_session_index = ls->session_index;
+  ls->server_rx_fifo->segment_manager = sm_index;
+  ls->server_tx_fifo->segment_manager = sm_index;
+  ls->server_rx_fifo->segment_index = seg_index;
+  ls->server_tx_fifo->segment_index = seg_index;
   ls->svm_segment_index = seg_index;
   ls->listener_index = ll->session_index;
   ls->client_wrk_index = client_wrk->wrk_index;
@@ -1660,8 +1720,9 @@ application_local_session_connect (app_worker_t * client_wrk,
   ls->listener_session_type = ll->session_type;
   ls->session_state = SESSION_STATE_READY;
 
+  segment_handle = segment_manager_segment_handle (sm, seg);
   if ((rv = server->cb_fns.add_segment_callback (server_wrk->api_client_index,
-                                                &seg->ssvm)))
+                                                segment_handle)))
     {
       clib_warning ("failed to notify server of new segment");
       segment_manager_segment_reader_unlock (sm);
@@ -1684,14 +1745,14 @@ failed:
   return rv;
 }
 
-static uword
+static u64
 application_client_local_connect_key (local_session_t * ls)
 {
-  return ((uword) ls->app_wrk_index << 32 | (uword) ls->session_index);
+  return (((u64) ls->app_wrk_index) << 32 | (u64) ls->session_index);
 }
 
 static void
-application_client_local_connect_key_parse (uword key, u32 * app_wrk_index,
+application_client_local_connect_key_parse (u64 key, u32 * app_wrk_index,
                                            u32 * session_index)
 {
   *app_wrk_index = key >> 32;
@@ -1706,7 +1767,8 @@ application_local_session_connect_notify (local_session_t * ls)
   segment_manager_t *sm;
   application_t *client;
   int rv, is_fail = 0;
-  uword client_key;
+  u64 segment_handle;
+  u64 client_key;
 
   client_wrk = app_worker_get (ls->client_wrk_index);
   server_wrk = app_worker_get (ls->app_wrk_index);
@@ -1714,8 +1776,9 @@ application_local_session_connect_notify (local_session_t * ls)
 
   sm = application_get_local_segment_manager_w_session (server_wrk, ls);
   seg = segment_manager_get_segment_w_lock (sm, ls->svm_segment_index);
+  segment_handle = segment_manager_segment_handle (sm, seg);
   if ((rv = client->cb_fns.add_segment_callback (client_wrk->api_client_index,
-                                                &seg->ssvm)))
+                                                segment_handle)))
     {
       clib_warning ("failed to notify client %u of new segment",
                    ls->client_wrk_index);
@@ -1746,7 +1809,7 @@ application_local_session_cleanup (app_worker_t * client_wrk,
   svm_fifo_segment_private_t *seg;
   stream_session_t *listener;
   segment_manager_t *sm;
-  uword client_key;
+  u64 client_key;
   u8 has_transport;
 
   /* Retrieve listener transport type as it is the one that decides where
@@ -1770,13 +1833,14 @@ application_local_session_cleanup (app_worker_t * client_wrk,
   if (!has_transport)
     {
       application_t *server = application_get (server_wrk->app_index);
+      u64 segment_handle = segment_manager_segment_handle (sm, seg);
       server->cb_fns.del_segment_callback (server_wrk->api_client_index,
-                                          &seg->ssvm);
+                                          segment_handle);
       if (client_wrk)
        {
          application_t *client = application_get (client_wrk->app_index);
          client->cb_fns.del_segment_callback (client_wrk->api_client_index,
-                                              &seg->ssvm);
+                                              segment_handle);
        }
       segment_manager_del_segment (sm, seg);
     }
@@ -2165,7 +2229,7 @@ app_worker_format_local_connects (app_worker_t * app, int verbose)
   u32 app_wrk_index, session_index;
   app_worker_t *server_wrk;
   local_session_t *ls;
-  uword client_key;
+  u64 client_key;
   u64 value;
 
   /* Header */
@@ -2215,6 +2279,19 @@ application_format_local_connects (application_t * app, int verbose)
   /* *INDENT-ON* */
 }
 
+u8 *
+format_application_worker (u8 * s, va_list * args)
+{
+  app_worker_t *app_wrk = va_arg (*args, app_worker_t *);
+  u32 indent = 1;
+
+  s = format (s, "%U wrk-index %u app-index %u map-index %u "
+             "api-client-index %d\n", format_white_space, indent,
+             app_wrk->wrk_index, app_wrk->app_index, app_wrk->wrk_map_index,
+             app_wrk->api_client_index);
+  return s;
+}
+
 u8 *
 format_application (u8 * s, va_list * args)
 {
@@ -2222,13 +2299,12 @@ format_application (u8 * s, va_list * args)
   CLIB_UNUSED (int verbose) = va_arg (*args, int);
   segment_manager_properties_t *props;
   const u8 *app_ns_name, *app_name;
+  app_worker_map_t *wrk_map;
+  app_worker_t *app_wrk;
 
   if (app == 0)
     {
-      if (verbose)
-       s = format (s, "%-10s%-20s%-15s%-15s%-15s%-15s", "Index", "Name",
-                   "Namespace", "Add seg size", "Rx-f size", "Tx-f size");
-      else
+      if (!verbose)
        s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
       return s;
     }
@@ -2236,14 +2312,27 @@ format_application (u8 * s, va_list * args)
   app_name = app_get_name (app);
   app_ns_name = app_namespace_id_from_index (app->ns_index);
   props = application_segment_manager_properties (app);
-  if (verbose)
-    s = format (s, "%-10u%-20s%-15u%-15U%-15U%-15U", app->app_index,
-               app_name, app->ns_index,
-               format_memory_size, props->add_segment_size,
-               format_memory_size, props->rx_fifo_size, format_memory_size,
-               props->tx_fifo_size);
-  else
-    s = format (s, "%-10u%-20s%-40s", app->app_index, app_name, app_ns_name);
+  if (!verbose)
+    {
+      s = format (s, "%-10u%-20s%-40s", app->app_index, app_name,
+                 app_ns_name);
+      return s;
+    }
+
+  s = format (s, "app-name %s app-index %u ns-index %u seg-size %U\n",
+             app_name, app->app_index, app->ns_index,
+             format_memory_size, props->add_segment_size);
+  s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
+             format_memory_size, props->rx_fifo_size,
+             format_memory_size, props->tx_fifo_size);
+
+  /* *INDENT-OFF* */
+  pool_foreach (wrk_map, app->worker_maps, ({
+      app_wrk = app_worker_get (wrk_map->wrk_index);
+      s = format (s, "%U", format_application_worker, app_wrk);
+  }));
+  /* *INDENT-ON* */
+
   return s;
 }
 
@@ -2318,6 +2407,7 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
 {
   int do_server = 0, do_client = 0, do_local = 0;
   application_t *app;
+  u32 app_index = ~0;
   int verbose = 0;
 
   session_cli_return_if_not_enabled ();
@@ -2330,25 +2420,44 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
        do_client = 1;
       else if (unformat (input, "local"))
        do_local = 1;
+      else if (unformat (input, "%u", &app_index))
+       ;
       else if (unformat (input, "verbose"))
        verbose = 1;
       else
-       break;
+       return clib_error_return (0, "unknown input `%U'",
+                                 format_unformat_error, input);
     }
 
   if (do_server)
-    application_format_all_listeners (vm, do_local, verbose);
+    {
+      application_format_all_listeners (vm, do_local, verbose);
+      return 0;
+    }
 
   if (do_client)
-    application_format_all_clients (vm, do_local, verbose);
+    {
+      application_format_all_clients (vm, do_local, verbose);
+      return 0;
+    }
+
+  if (app_index != ~0)
+    {
+      app = application_get_if_valid (app_index);
+      if (!app)
+       return clib_error_return (0, "No app with index %u", app_index);
+
+      vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
+      return 0;
+    }
 
   /* Print app related info */
   if (!do_server && !do_client)
     {
-      vlib_cli_output (vm, "%U", format_application, 0, verbose);
+      vlib_cli_output (vm, "%U", format_application, 0, 0);
       /* *INDENT-OFF* */
       pool_foreach (app, app_main.app_pool, ({
-       vlib_cli_output (vm, "%U", format_application, app, verbose);
+       vlib_cli_output (vm, "%U", format_application, app, 0);
       }));
       /* *INDENT-ON* */
     }