session: ensure detach is done with worker barrier
[vpp.git] / src / vnet / session / application_interface.c
index ab87def..72a9985 100644 (file)
@@ -81,6 +81,15 @@ const char test_srv_key_rsa[] =
   "oEjPLVNtx8SOj/M4rhaPT3I=\r\n" "-----END PRIVATE KEY-----\r\n";
 const u32 test_srv_key_rsa_len = sizeof (test_srv_key_rsa);
 
+#define app_interface_check_thread_and_barrier(_fn, _arg)              \
+  if (PREDICT_FALSE (vlib_get_thread_index () != 0 ||                  \
+                     (vlib_worker_threads[0].wait_at_barrier &&                \
+                     !vlib_worker_threads[0].wait_at_barrier[0])))     \
+    {                                                                  \
+      vlib_rpc_call_main_thread (_fn, (u8 *) _arg, sizeof(*_arg));     \
+      return 0;                                                                \
+    }
+
 static u8
 session_endpoint_is_local (session_endpoint_t * sep)
 {
@@ -130,11 +139,25 @@ api_parse_session_handle (u64 handle, u32 * session_index, u32 * thread_index)
 }
 
 static void
-session_endpoint_update_for_app (session_endpoint_t * sep,
+session_endpoint_update_for_app (session_endpoint_extended_t * sep,
                                 application_t * app)
 {
   app_namespace_t *app_ns;
-  app_ns = app_namespace_get (app->ns_index);
+  u32 ns_index;
+
+  ns_index = app->ns_index;
+
+  /* App is a transport proto, so fetch the calling app's ns */
+  if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
+    {
+      app_worker_t *owner_wrk;
+      application_t *owner_app;
+
+      owner_wrk = app_worker_get (sep->app_wrk_index);
+      owner_app = application_get (owner_wrk->app_index);
+      ns_index = owner_app->ns_index;
+    }
+  app_ns = app_namespace_get (ns_index);
   if (app_ns)
     {
       /* Ask transport and network to bind to/connect using local interface
@@ -164,7 +187,7 @@ vnet_bind_inline (vnet_bind_args_t * a)
   app_wrk = application_get_worker (app, a->wrk_map_index);
   a->sep_ext.app_wrk_index = app_wrk->wrk_index;
 
-  session_endpoint_update_for_app (&a->sep, app);
+  session_endpoint_update_for_app (&a->sep_ext, app);
   if (!session_endpoint_in_ns (&a->sep))
     return VNET_API_ERROR_INVALID_VALUE_2;
 
@@ -257,7 +280,7 @@ application_connect (vnet_connect_args_t * a)
     return VNET_API_ERROR_INVALID_VALUE;
 
   client = application_get (a->app_index);
-  session_endpoint_update_for_app (&a->sep, client);
+  session_endpoint_update_for_app (&a->sep_ext, client);
   client_wrk = application_get_worker (client, a->wrk_map_index);
 
   /*
@@ -511,14 +534,15 @@ int
 vnet_application_detach (vnet_app_detach_args_t * a)
 {
   application_t *app;
-  app = application_get_if_valid (a->app_index);
 
+  app = application_get_if_valid (a->app_index);
   if (!app)
     {
       clib_warning ("app not attached");
       return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
     }
 
+  app_interface_check_thread_and_barrier (vnet_application_detach, a);
   application_free (app);
   return 0;
 }
@@ -532,6 +556,7 @@ vnet_bind_uri (vnet_bind_args_t * a)
   rv = parse_uri (a->uri, &sep);
   if (rv)
     return rv;
+  sep.app_wrk_index = 0;
   clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
   return vnet_bind_inline (a);
 }
@@ -584,12 +609,7 @@ vnet_disconnect_session (vnet_disconnect_args_t * a)
       local_session_t *ls;
 
       /* Disconnect reply came to worker 1 not main thread */
-      if (vlib_get_thread_index () == 1)
-       {
-         vlib_rpc_call_main_thread (vnet_disconnect_session, (u8 *) a,
-                                    sizeof (*a));
-         return 0;
-       }
+      app_interface_check_thread_and_barrier (vnet_disconnect_session, a);
 
       if (!(ls = application_get_local_session_from_handle (a->handle)))
        return 0;
@@ -598,9 +618,14 @@ vnet_disconnect_session (vnet_disconnect_args_t * a)
     }
   else
     {
+      app_worker_t *app_wrk;
       stream_session_t *s;
+
       s = session_get_from_handle_if_valid (a->handle);
-      if (!s || s->app_wrk_index != a->app_index)
+      if (!s)
+       return VNET_API_ERROR_INVALID_VALUE;
+      app_wrk = app_worker_get (s->app_wrk_index);
+      if (app_wrk->app_index != a->app_index)
        return VNET_API_ERROR_INVALID_VALUE;
 
       /* We're peeking into another's thread pool. Make sure */