session: send ctrl msg over mq
[vpp.git] / src / vnet / session / session_api.c
index 11fa0fa..724aff1 100755 (executable)
@@ -56,6 +56,8 @@ _(SESSION_ENABLE_DISABLE, session_enable_disable)                     \
 _(APP_NAMESPACE_ADD_DEL, app_namespace_add_del)                                \
 _(SESSION_RULE_ADD_DEL, session_rule_add_del)                          \
 _(SESSION_RULES_DUMP, session_rules_dump)                              \
+_(APPLICATION_TLS_CERT_ADD, application_tls_cert_add)                  \
+_(APPLICATION_TLS_KEY_ADD, application_tls_key_add)                    \
 
 static int
 session_send_memfd_fd (vl_api_registration_t * reg, const ssvm_private_t * sp)
@@ -153,7 +155,7 @@ send_session_accept_callback (stream_session_t * s)
   vl_api_registration_t *reg;
   transport_connection_t *tc;
   stream_session_t *listener;
-  svm_queue_t *vpp_queue;
+  svm_msg_q_t *vpp_queue;
 
   reg = vl_mem_api_client_index_to_registration (server->api_client_index);
   if (!reg)
@@ -172,7 +174,7 @@ send_session_accept_callback (stream_session_t * s)
 
   if (session_has_transport (s))
     {
-      listener = listen_session_get (s->session_type, s->listener_index);
+      listener = listen_session_get (s->listener_index);
       mp->listener_handle = listen_session_get_handle (listener);
       if (application_is_proxy (server))
        {
@@ -197,15 +199,24 @@ send_session_accept_callback (stream_session_t * s)
       local_session_t *ll;
       if (application_local_session_listener_has_transport (ls))
        {
-         listener = listen_session_get (ls->listener_session_type,
-                                        ls->listener_index);
+         listener = listen_session_get (ls->listener_index);
          mp->listener_handle = listen_session_get_handle (listener);
+         mp->is_ip4 = session_type_is_ip4 (listener->session_type);
        }
       else
        {
          ll = application_get_local_listen_session (server,
                                                     ls->listener_index);
-         mp->listener_handle = application_local_session_handle (ll);
+         if (ll->transport_listener_index != ~0)
+           {
+             listener = listen_session_get (ll->transport_listener_index);
+             mp->listener_handle = listen_session_get_handle (listener);
+           }
+         else
+           {
+             mp->listener_handle = application_local_session_handle (ll);
+           }
+         mp->is_ip4 = session_type_is_ip4 (ll->listener_session_type);
        }
       mp->handle = application_local_session_handle (ls);
       mp->port = ls->port;
@@ -289,7 +300,7 @@ send_session_connected_callback (u32 app_index, u32 api_context,
   vl_api_connect_session_reply_t *mp;
   transport_connection_t *tc;
   vl_api_registration_t *reg;
-  svm_queue_t *vpp_queue;
+  svm_msg_q_t *vpp_queue;
   application_t *app;
 
   app = application_get (app_index);
@@ -352,6 +363,207 @@ static session_cb_vft_t session_cb_vft = {
   .del_segment_callback = send_del_segment_callback,
 };
 
+static int
+mq_send_session_accepted_cb (stream_session_t * s)
+{
+  application_t *app = application_get (s->app_index);
+  svm_msg_q_msg_t _msg, *msg = &_msg;
+  svm_msg_q_t *vpp_queue, *app_mq;
+  transport_proto_vft_t *tp_vft;
+  transport_connection_t *tc;
+  stream_session_t *listener;
+  session_accepted_msg_t *mp;
+  session_event_t *evt;
+
+  app_mq = app->event_queue;
+  svm_msg_q_lock_and_alloc_msg_w_ring (app_mq, SESSION_MQ_CTRL_EVT_RING,
+                                      SVM_Q_WAIT, msg);
+  svm_msg_q_unlock (app_mq);
+
+  evt = svm_msg_q_msg_data (app_mq, msg);
+  memset (evt, 0, sizeof (*evt));
+  evt->event_type = SESSION_CTRL_EVT_ACCEPTED;
+  mp = (session_accepted_msg_t *) evt->data;
+  mp->context = app->index;
+  mp->server_rx_fifo = pointer_to_uword (s->server_rx_fifo);
+  mp->server_tx_fifo = pointer_to_uword (s->server_tx_fifo);
+
+  if (session_has_transport (s))
+    {
+      listener = listen_session_get (s->listener_index);
+      mp->listener_handle = listen_session_get_handle (listener);
+      if (application_is_proxy (app))
+       {
+         listener =
+           application_first_listener (app, session_get_fib_proto (s),
+                                       session_get_transport_proto (s));
+         if (listener)
+           mp->listener_handle = listen_session_get_handle (listener);
+       }
+      vpp_queue = session_manager_get_vpp_event_queue (s->thread_index);
+      mp->vpp_event_queue_address = pointer_to_uword (vpp_queue);
+      mp->handle = session_handle (s);
+      tp_vft = transport_protocol_get_vft (session_get_transport_proto (s));
+      tc = tp_vft->get_connection (s->connection_index, s->thread_index);
+      mp->port = tc->rmt_port;
+      mp->is_ip4 = tc->is_ip4;
+      clib_memcpy (&mp->ip, &tc->rmt_ip, sizeof (tc->rmt_ip));
+    }
+  else
+    {
+      local_session_t *ls = (local_session_t *) s;
+      local_session_t *ll;
+      if (application_local_session_listener_has_transport (ls))
+       {
+         listener = listen_session_get (ls->listener_index);
+         mp->listener_handle = listen_session_get_handle (listener);
+         mp->is_ip4 = session_type_is_ip4 (listener->session_type);
+       }
+      else
+       {
+         ll = application_get_local_listen_session (app, ls->listener_index);
+         if (ll->transport_listener_index != ~0)
+           {
+             listener = listen_session_get (ll->transport_listener_index);
+             mp->listener_handle = listen_session_get_handle (listener);
+           }
+         else
+           {
+             mp->listener_handle = application_local_session_handle (ll);
+           }
+         mp->is_ip4 = session_type_is_ip4 (ll->listener_session_type);
+       }
+      mp->handle = application_local_session_handle (ls);
+      mp->port = ls->port;
+      mp->vpp_event_queue_address = ls->client_evt_q;
+      mp->server_event_queue_address = ls->server_evt_q;
+    }
+  svm_msg_q_add (app_mq, msg, SVM_Q_WAIT);
+
+  return 0;
+}
+
+static void
+mq_send_session_disconnected_cb (stream_session_t * s)
+{
+  application_t *app = application_get (s->app_index);
+  svm_msg_q_msg_t _msg, *msg = &_msg;
+  session_disconnected_msg_t *mp;
+  svm_msg_q_t *app_mq;
+  session_event_t *evt;
+
+  app_mq = app->event_queue;
+  svm_msg_q_lock_and_alloc_msg_w_ring (app_mq, SESSION_MQ_CTRL_EVT_RING,
+                                      SVM_Q_WAIT, msg);
+  svm_msg_q_unlock (app_mq);
+  evt = svm_msg_q_msg_data (app_mq, msg);
+  memset (evt, 0, sizeof (*evt));
+  evt->event_type = SESSION_CTRL_EVT_DISCONNECTED;
+  mp = (session_disconnected_msg_t *) evt->data;
+  mp->handle = session_handle (s);
+  mp->context = app->api_client_index;
+  svm_msg_q_add (app_mq, msg, SVM_Q_WAIT);
+}
+
+static void
+mq_send_session_reset_cb (stream_session_t * s)
+{
+  application_t *app = application_get (s->app_index);
+  svm_msg_q_msg_t _msg, *msg = &_msg;
+  session_reset_msg_t *mp;
+  svm_msg_q_t *app_mq;
+  session_event_t *evt;
+
+  app_mq = app->event_queue;
+  svm_msg_q_lock_and_alloc_msg_w_ring (app_mq, SESSION_MQ_CTRL_EVT_RING,
+                                      SVM_Q_WAIT, msg);
+  svm_msg_q_unlock (app_mq);
+  evt = svm_msg_q_msg_data (app_mq, msg);
+  memset (evt, 0, sizeof (*evt));
+  evt->event_type = SESSION_CTRL_EVT_RESET;
+  mp = (session_reset_msg_t *) evt->data;
+  mp->handle = session_handle (s);
+  svm_msg_q_add (app_mq, msg, SVM_Q_WAIT);
+}
+
+static int
+mq_send_session_connected_cb (u32 app_index, u32 api_context,
+                             stream_session_t * s, u8 is_fail)
+{
+  svm_msg_q_msg_t _msg, *msg = &_msg;
+  session_connected_msg_t *mp;
+  svm_msg_q_t *vpp_mq, *app_mq;
+  transport_connection_t *tc;
+  session_event_t *evt;
+  application_t *app;
+
+  app = application_get (app_index);
+  app_mq = app->event_queue;
+  if (!app_mq)
+    {
+      clib_warning ("app %u with api index: %u not attached", app->index,
+                   app->api_client_index);
+      return -1;
+    }
+
+  svm_msg_q_lock_and_alloc_msg_w_ring (app_mq, SESSION_MQ_CTRL_EVT_RING,
+                                      SVM_Q_WAIT, msg);
+  svm_msg_q_unlock (app_mq);
+  evt = svm_msg_q_msg_data (app_mq, msg);
+  memset (evt, 0, sizeof (*evt));
+  evt->event_type = SESSION_CTRL_EVT_CONNECTED;
+  mp = (session_connected_msg_t *) evt->data;
+  mp->context = api_context;
+
+  if (is_fail)
+    goto done;
+
+  if (session_has_transport (s))
+    {
+      tc = session_get_transport (s);
+      if (!tc)
+       {
+         is_fail = 1;
+         goto done;
+       }
+
+      vpp_mq = session_manager_get_vpp_event_queue (s->thread_index);
+      mp->handle = session_handle (s);
+      mp->vpp_event_queue_address = pointer_to_uword (vpp_mq);
+      clib_memcpy (mp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
+      mp->is_ip4 = tc->is_ip4;
+      mp->lcl_port = tc->lcl_port;
+      mp->server_rx_fifo = pointer_to_uword (s->server_rx_fifo);
+      mp->server_tx_fifo = pointer_to_uword (s->server_tx_fifo);
+    }
+  else
+    {
+      local_session_t *ls = (local_session_t *) s;
+      mp->handle = application_local_session_handle (ls);
+      mp->lcl_port = ls->port;
+      mp->vpp_event_queue_address = ls->server_evt_q;
+      mp->client_event_queue_address = ls->client_evt_q;
+      mp->server_rx_fifo = pointer_to_uword (s->server_tx_fifo);
+      mp->server_tx_fifo = pointer_to_uword (s->server_rx_fifo);
+    }
+
+done:
+  mp->retval = is_fail ?
+    clib_host_to_net_u32 (VNET_API_ERROR_SESSION_CONNECT) : 0;
+
+  svm_msg_q_add (app_mq, msg, SVM_Q_WAIT);
+  return 0;
+}
+
+static session_cb_vft_t session_mq_cb_vft = {
+  .session_accept_callback = mq_send_session_accepted_cb,
+  .session_disconnect_callback = mq_send_session_disconnected_cb,
+  .session_connected_callback = mq_send_session_connected_cb,
+  .session_reset_callback = mq_send_session_reset_cb,
+  .add_segment_callback = send_add_segment_callback,
+  .del_segment_callback = send_del_segment_callback,
+};
+
 static void
 vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
 {
@@ -390,7 +602,11 @@ vl_api_application_attach_t_handler (vl_api_application_attach_t * mp)
   memset (a, 0, sizeof (*a));
   a->api_client_index = mp->client_index;
   a->options = mp->options;
-  a->session_cb_vft = &session_cb_vft;
+
+  if (a->options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS)
+    a->session_cb_vft = &session_mq_cb_vft;
+  else
+    a->session_cb_vft = &session_cb_vft;
 
   if (mp->namespace_id_len > 64)
     {
@@ -469,9 +685,12 @@ done:
 static void
 vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
 {
-  vl_api_bind_uri_reply_t *rmp;
+  transport_connection_t *tc = 0;
   vnet_bind_args_t _a, *a = &_a;
-  application_t *app;
+  vl_api_bind_uri_reply_t *rmp;
+  stream_session_t *s;
+  application_t *app = 0;
+  svm_msg_q_t *vpp_evt_q;
   int rv;
 
   if (session_manager_is_enabled () == 0)
@@ -494,7 +713,30 @@ vl_api_bind_uri_t_handler (vl_api_bind_uri_t * mp)
     }
 
 done:
-  REPLY_MACRO (VL_API_BIND_URI_REPLY);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_BIND_URI_REPLY, ({
+    if (!rv)
+      {
+        rmp->handle = a->handle;
+        if (app && application_has_global_scope (app))
+            {
+              s = listen_session_get_from_handle (a->handle);
+              tc = listen_session_get_transport (s);
+              rmp->lcl_is_ip4 = tc->is_ip4;
+              rmp->lcl_port = tc->lcl_port;
+              clib_memcpy (rmp->lcl_ip, &tc->lcl_ip, sizeof(tc->lcl_ip));
+              if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL)
+                {
+                  rmp->rx_fifo = pointer_to_uword (s->server_rx_fifo);
+                  rmp->tx_fifo = pointer_to_uword (s->server_tx_fifo);
+                  vpp_evt_q = session_manager_get_vpp_event_queue (0);
+                  rmp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
+                }
+            }
+      }
+  }));
+  /* *INDENT-ON* */
 }
 
 static void
@@ -548,12 +790,10 @@ vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
       a->uri = (char *) mp->uri;
       a->api_context = mp->context;
       a->app_index = app->index;
-      a->mp = mp;
       if ((error = vnet_connect_uri (a)))
        {
          rv = clib_error_get_code (error);
-         if (rv != VNET_API_ERROR_SESSION_REDIRECT)
-           clib_error_report (error);
+         clib_error_report (error);
        }
     }
   else
@@ -566,7 +806,7 @@ vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
    * the connection is established. In case of the redirects, the reply
    * will come from the server app.
    */
-  if (rv == 0 || rv == VNET_API_ERROR_SESSION_REDIRECT)
+  if (rv == 0)
     return;
 
 done:
@@ -724,6 +964,7 @@ vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp)
   stream_session_t *s;
   transport_connection_t *tc = 0;
   ip46_address_t *ip46;
+  svm_msg_q_t *vpp_evt_q;
 
   if (session_manager_is_enabled () == 0)
     {
@@ -761,12 +1002,19 @@ done:
       {
        rmp->handle = a->handle;
         rmp->lcl_port = mp->port;
+       rmp->lcl_is_ip4 = mp->is_ip4;
        if (app && application_has_global_scope (app))
          {
            s = listen_session_get_from_handle (a->handle);
            tc = listen_session_get_transport (s);
-            rmp->lcl_is_ip4 = tc->is_ip4;
             clib_memcpy (rmp->lcl_ip, &tc->lcl_ip, sizeof (tc->lcl_ip));
+            if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL)
+              {
+               rmp->rx_fifo = pointer_to_uword (s->server_rx_fifo);
+               rmp->tx_fifo = pointer_to_uword (s->server_tx_fifo);
+               vpp_evt_q = session_manager_get_vpp_event_queue (0);
+               rmp->vpp_evt_q = pointer_to_uword (vpp_evt_q);
+              }
          }
       }
   }));
@@ -825,6 +1073,7 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
       svm_queue_t *client_q;
       ip46_address_t *ip46 = (ip46_address_t *) mp->ip;
 
+      memset (a, 0, sizeof (*a));
       client_q = vl_api_client_index_to_input_queue (mp->client_index);
       mp->client_queue_address = pointer_to_uword (client_q);
       a->sep.is_ip4 = mp->is_ip4;
@@ -833,22 +1082,26 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
       a->sep.transport_proto = mp->proto;
       a->sep.fib_index = mp->vrf;
       a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
+      if (mp->hostname_len)
+       {
+         vec_validate (a->sep.hostname, mp->hostname_len - 1);
+         clib_memcpy (a->sep.hostname, mp->hostname, mp->hostname_len);
+       }
       a->api_context = mp->context;
       a->app_index = app->index;
-      a->mp = mp;
       if ((error = vnet_connect (a)))
        {
          rv = clib_error_get_code (error);
-         if (rv != VNET_API_ERROR_SESSION_REDIRECT)
-           clib_error_report (error);
+         clib_error_report (error);
        }
+      vec_free (a->sep.hostname);
     }
   else
     {
       rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
     }
 
-  if (rv == 0 || rv == VNET_API_ERROR_SESSION_REDIRECT)
+  if (rv == 0)
     return;
 
   /* Got some error, relay it */
@@ -1091,6 +1344,86 @@ vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp)
   /* *INDENT-ON* */
 }
 
+static void
+vl_api_application_tls_cert_add_t_handler (vl_api_application_tls_cert_add_t *
+                                          mp)
+{
+  vl_api_app_namespace_add_del_reply_t *rmp;
+  vnet_app_add_tls_cert_args_t _a, *a = &_a;
+  clib_error_t *error;
+  application_t *app;
+  u32 cert_len;
+  int rv = 0;
+  if (!session_manager_is_enabled ())
+    {
+      rv = VNET_API_ERROR_FEATURE_DISABLED;
+      goto done;
+    }
+  if (!(app = application_lookup (mp->client_index)))
+    {
+      rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
+      goto done;
+    }
+  memset (a, 0, sizeof (*a));
+  a->app_index = app->index;
+  cert_len = clib_net_to_host_u16 (mp->cert_len);
+  if (cert_len > 10000)
+    {
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto done;
+    }
+  vec_validate (a->cert, cert_len);
+  clib_memcpy (a->cert, mp->cert, cert_len);
+  if ((error = vnet_app_add_tls_cert (a)))
+    {
+      rv = clib_error_get_code (error);
+      clib_error_report (error);
+    }
+  vec_free (a->cert);
+done:
+  REPLY_MACRO (VL_API_APPLICATION_TLS_CERT_ADD_REPLY);
+}
+
+static void
+vl_api_application_tls_key_add_t_handler (vl_api_application_tls_key_add_t *
+                                         mp)
+{
+  vl_api_app_namespace_add_del_reply_t *rmp;
+  vnet_app_add_tls_key_args_t _a, *a = &_a;
+  clib_error_t *error;
+  application_t *app;
+  u32 key_len;
+  int rv = 0;
+  if (!session_manager_is_enabled ())
+    {
+      rv = VNET_API_ERROR_FEATURE_DISABLED;
+      goto done;
+    }
+  if (!(app = application_lookup (mp->client_index)))
+    {
+      rv = VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
+      goto done;
+    }
+  memset (a, 0, sizeof (*a));
+  a->app_index = app->index;
+  key_len = clib_net_to_host_u16 (mp->key_len);
+  if (key_len > 10000)
+    {
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto done;
+    }
+  vec_validate (a->key, key_len);
+  clib_memcpy (a->key, mp->key, key_len);
+  if ((error = vnet_app_add_tls_key (a)))
+    {
+      rv = clib_error_get_code (error);
+      clib_error_report (error);
+    }
+  vec_free (a->key);
+done:
+  REPLY_MACRO (VL_API_APPLICATION_TLS_KEY_ADD_REPLY);
+}
+
 static clib_error_t *
 application_reaper_cb (u32 client_index)
 {