LCOV - code coverage report
Current view: top level - plugins/tlsopenssl - tls_async.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 18 193 9.3 %
Date: 2023-10-26 01:39:38 Functions: 6 25 24.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Intel 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             : #include <vnet/vnet.h>
      16             : #include <vnet/api_errno.h>
      17             : #include <vlib/node_funcs.h>
      18             : #include <openssl/engine.h>
      19             : #include <tlsopenssl/tls_openssl.h>
      20             : 
      21             : #define SSL_ASYNC_INFLIGHT    1
      22             : #define SSL_ASYNC_READY       2
      23             : #define SSL_ASYNC_REENTER     3
      24             : #define MAX_VECTOR_ASYNC    256
      25             : 
      26             : typedef struct openssl_tls_callback_arg_
      27             : {
      28             :   int thread_index;
      29             :   int event_index;
      30             : } openssl_tls_callback_arg_t;
      31             : 
      32             : typedef struct openssl_event_
      33             : {
      34             :   u32 ctx_index;
      35             :   int session_index;
      36             :   u8 status;
      37             : 
      38             :   openssl_resume_handler *handler;
      39             :   openssl_tls_callback_arg_t cb_args;
      40             : #define thread_idx cb_args.thread_index
      41             : #define event_idx cb_args.event_index
      42             :   int next;
      43             : } openssl_evt_t;
      44             : 
      45             : typedef struct openssl_async_queue_
      46             : {
      47             :   int evt_run_head;
      48             :   int evt_run_tail;
      49             : } openssl_async_queue_t;
      50             : 
      51             : typedef struct openssl_async_
      52             : {
      53             :   openssl_evt_t ***evt_pool;
      54             :   openssl_async_queue_t *queue;
      55             :   void (*polling) (void);
      56             :   u8 start_polling;
      57             :   ENGINE *engine;
      58             : 
      59             : } openssl_async_t;
      60             : 
      61             : void qat_polling ();
      62             : void qat_pre_init ();
      63             : void qat_polling_config ();
      64             : void dasync_polling ();
      65             : 
      66             : struct engine_polling
      67             : {
      68             :   char *engine;
      69             :   void (*polling) (void);
      70             :   void (*pre_init) (void);
      71             :   void (*thread_init) (void *);
      72             : };
      73             : 
      74             : void qat_init_thread (void *arg);
      75             : 
      76             : struct engine_polling engine_list[] = {
      77             :   {"qat", qat_polling, qat_pre_init, qat_init_thread},
      78             :   {"dasync", dasync_polling, NULL, NULL}
      79             : };
      80             : 
      81             : openssl_async_t openssl_async_main;
      82             : static vlib_node_registration_t tls_async_process_node;
      83             : 
      84             : /* to avoid build warning */
      85             : void session_send_rpc_evt_to_thread (u32 thread_index, void *fp,
      86             :                                      void *rpc_args);
      87             : 
      88             : void
      89         575 : evt_pool_init (vlib_main_t * vm)
      90             : {
      91         575 :   vlib_thread_main_t *vtm = vlib_get_thread_main ();
      92         575 :   openssl_async_t *om = &openssl_async_main;
      93             :   int i, num_threads;
      94             : 
      95         575 :   num_threads = 1 /* main thread */  + vtm->n_threads;
      96             : 
      97             :   TLS_DBG (2, "Totally there is %d thread\n", num_threads);
      98             : 
      99         575 :   vec_validate (om->evt_pool, num_threads - 1);
     100         575 :   vec_validate (om->queue, num_threads - 1);
     101             : 
     102         575 :   om->start_polling = 0;
     103         575 :   om->engine = 0;
     104             : 
     105        1205 :   for (i = 0; i < num_threads; i++)
     106             :     {
     107         630 :       om->queue[i].evt_run_head = -1;
     108         630 :       om->queue[i].evt_run_tail = -1;
     109             :     }
     110         575 :   om->polling = NULL;
     111             : 
     112         575 :   return;
     113             : }
     114             : 
     115             : int
     116           0 : openssl_engine_register (char *engine_name, char *algorithm, int async)
     117             : {
     118           0 :   int i, registered = -1;
     119           0 :   openssl_async_t *om = &openssl_async_main;
     120             :   void (*p) (void);
     121             :   ENGINE *engine;
     122             : 
     123           0 :   for (i = 0; i < ARRAY_LEN (engine_list); i++)
     124             :     {
     125           0 :       if (!strcmp (engine_list[i].engine, engine_name))
     126             :         {
     127           0 :           om->polling = engine_list[i].polling;
     128           0 :           registered = i;
     129             :         }
     130             :     }
     131           0 :   if (registered < 0)
     132             :     {
     133           0 :       clib_error ("engine %s is not regisered in VPP", engine_name);
     134           0 :       return -1;
     135             :     }
     136             : 
     137           0 :   ENGINE_load_builtin_engines ();
     138           0 :   ENGINE_load_dynamic ();
     139           0 :   engine = ENGINE_by_id (engine_name);
     140             : 
     141           0 :   if (engine == NULL)
     142             :     {
     143           0 :       clib_warning ("Failed to find engine ENGINE_by_id %s", engine_name);
     144           0 :       return -1;
     145             :     }
     146             : 
     147           0 :   om->engine = engine;
     148             :   /* call pre-init */
     149           0 :   p = engine_list[registered].pre_init;
     150           0 :   if (p)
     151           0 :     (*p) ();
     152             : 
     153           0 :   if (algorithm)
     154             :     {
     155           0 :       if (!ENGINE_set_default_string (engine, algorithm))
     156             :         {
     157           0 :           clib_warning ("Failed to set engine %s algorithm %s\n",
     158             :                         engine_name, algorithm);
     159           0 :           return -1;
     160             :         }
     161             :     }
     162             :   else
     163             :     {
     164           0 :       if (!ENGINE_set_default (engine, ENGINE_METHOD_ALL))
     165             :         {
     166           0 :           clib_warning ("Failed to set engine %s to all algorithm",
     167             :                         engine_name);
     168           0 :           return -1;
     169             :         }
     170             :     }
     171             : 
     172           0 :   if (async)
     173             :     {
     174           0 :       openssl_async_node_enable_disable (1);
     175             :     }
     176             : 
     177           0 :   for (i = 0; i < vlib_num_workers (); i++)
     178             :     {
     179           0 :       if (engine_list[registered].thread_init)
     180           0 :         session_send_rpc_evt_to_thread (i + 1,
     181           0 :                                         engine_list[registered].thread_init,
     182           0 :                                         uword_to_pointer (i, void *));
     183             :     }
     184             : 
     185           0 :   om->start_polling = 1;
     186             : 
     187           0 :   return 0;
     188             : 
     189             : }
     190             : 
     191             : static openssl_evt_t *
     192           0 : openssl_evt_get (u32 evt_index)
     193             : {
     194             :   openssl_evt_t **evt;
     195           0 :   evt =
     196           0 :     pool_elt_at_index (openssl_async_main.evt_pool[vlib_get_thread_index ()],
     197             :                        evt_index);
     198           0 :   return *evt;
     199             : }
     200             : 
     201             : static openssl_evt_t *
     202           0 : openssl_evt_get_w_thread (int evt_index, u8 thread_index)
     203             : {
     204             :   openssl_evt_t **evt;
     205             : 
     206           0 :   evt =
     207           0 :     pool_elt_at_index (openssl_async_main.evt_pool[thread_index], evt_index);
     208           0 :   return *evt;
     209             : }
     210             : 
     211             : int
     212           0 : openssl_evt_free (int event_index, u8 thread_index)
     213             : {
     214           0 :   openssl_async_t *om = &openssl_async_main;
     215             : 
     216             :   /*pool operation */
     217           0 :   pool_put_index (om->evt_pool[thread_index], event_index);
     218             : 
     219           0 :   return 1;
     220             : }
     221             : 
     222             : static u32
     223           0 : openssl_evt_alloc (void)
     224             : {
     225           0 :   u8 thread_index = vlib_get_thread_index ();
     226           0 :   openssl_async_t *tm = &openssl_async_main;
     227             :   openssl_evt_t **evt;
     228             : 
     229           0 :   pool_get (tm->evt_pool[thread_index], evt);
     230           0 :   if (!(*evt))
     231           0 :     *evt = clib_mem_alloc (sizeof (openssl_evt_t));
     232             : 
     233           0 :   clib_memset (*evt, 0, sizeof (openssl_evt_t));
     234           0 :   (*evt)->event_idx = evt - tm->evt_pool[thread_index];
     235           0 :   return ((*evt)->event_idx);
     236             : }
     237             : 
     238             : 
     239             : /* In most cases, tls_async_openssl_callback is called by HW to make event active
     240             :  * When EAGAIN received, VPP will call this callback to retry
     241             :  */
     242             : int
     243           0 : tls_async_openssl_callback (SSL * s, void *cb_arg)
     244             : {
     245             :   openssl_evt_t *event, *event_tail;
     246           0 :   openssl_async_t *om = &openssl_async_main;
     247           0 :   openssl_tls_callback_arg_t *args = (openssl_tls_callback_arg_t *) cb_arg;
     248           0 :   int thread_index = args->thread_index;
     249           0 :   int event_index = args->event_index;
     250           0 :   int *evt_run_tail = &om->queue[thread_index].evt_run_tail;
     251           0 :   int *evt_run_head = &om->queue[thread_index].evt_run_head;
     252             : 
     253             :   TLS_DBG (2, "Set event %d to run\n", event_index);
     254           0 :   event = openssl_evt_get_w_thread (event_index, thread_index);
     255             : 
     256             :   /* Happend when a recursive case, especially in SW simulation */
     257           0 :   if (PREDICT_FALSE (event->status == SSL_ASYNC_READY))
     258             :     {
     259           0 :       event->status = SSL_ASYNC_REENTER;
     260           0 :       return 0;
     261             :     }
     262           0 :   event->status = SSL_ASYNC_READY;
     263           0 :   event->next = -1;
     264             : 
     265           0 :   if (*evt_run_tail >= 0)
     266             :     {
     267           0 :       event_tail = openssl_evt_get_w_thread (*evt_run_tail, thread_index);
     268           0 :       event_tail->next = event_index;
     269             :     }
     270           0 :   *evt_run_tail = event_index;
     271           0 :   if (*evt_run_head < 0)
     272             :     {
     273           0 :       *evt_run_head = event_index;
     274             :     }
     275             : 
     276           0 :   return 1;
     277             : }
     278             : 
     279             : int
     280           0 : vpp_tls_async_init_event (tls_ctx_t * ctx,
     281             :                           openssl_resume_handler * handler,
     282             :                           session_t * session)
     283             : {
     284             :   u32 eidx;
     285             :   openssl_evt_t *event;
     286           0 :   openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
     287           0 :   u32 thread_id = ctx->c_thread_index;
     288             : 
     289           0 :   eidx = openssl_evt_alloc ();
     290           0 :   event = openssl_evt_get (eidx);
     291           0 :   event->ctx_index = oc->openssl_ctx_index;
     292           0 :   event->event_idx = eidx;
     293           0 :   event->thread_idx = thread_id;
     294           0 :   event->handler = handler;
     295           0 :   event->session_index = session->session_index;
     296           0 :   event->status = 0;
     297           0 :   ctx->evt_index = eidx;
     298             : #ifdef HAVE_OPENSSL_ASYNC
     299             :   SSL_set_async_callback_arg (oc->ssl, &event->cb_args);
     300             : #endif
     301             : 
     302           0 :   return 1;
     303             : }
     304             : 
     305             : int
     306           0 : vpp_openssl_is_inflight (tls_ctx_t * ctx)
     307             : {
     308             :   u32 eidx;
     309             :   openssl_evt_t *event;
     310           0 :   eidx = ctx->evt_index;
     311           0 :   event = openssl_evt_get (eidx);
     312             : 
     313           0 :   if (event->status == SSL_ASYNC_INFLIGHT)
     314           0 :     return 1;
     315           0 :   return 0;
     316             : }
     317             : 
     318             : int
     319           0 : vpp_tls_async_update_event (tls_ctx_t * ctx, int eagain)
     320             : {
     321             :   u32 eidx;
     322             :   openssl_evt_t *event;
     323             : 
     324           0 :   eidx = ctx->evt_index;
     325           0 :   event = openssl_evt_get (eidx);
     326           0 :   event->status = SSL_ASYNC_INFLIGHT;
     327           0 :   if (eagain)
     328           0 :     return tls_async_openssl_callback (0, &event->cb_args);
     329             : 
     330           0 :   return 1;
     331             : }
     332             : 
     333             : void
     334           0 : event_handler (void *tls_async)
     335             : {
     336             :   openssl_resume_handler *handler;
     337             :   openssl_evt_t *event;
     338             :   session_t *session;
     339             :   int thread_index;
     340             :   tls_ctx_t *ctx;
     341             : 
     342           0 :   event = (openssl_evt_t *) tls_async;
     343           0 :   thread_index = event->thread_idx;
     344           0 :   ctx = openssl_ctx_get_w_thread (event->ctx_index, thread_index);
     345           0 :   handler = event->handler;
     346           0 :   session = session_get (event->session_index, thread_index);
     347             : 
     348           0 :   if (handler)
     349             :     {
     350           0 :       (*handler) (ctx, session);
     351             :     }
     352             : 
     353           0 :   return;
     354             : }
     355             : 
     356             :  /* engine specific code to polling the response ring */
     357             : void
     358           0 : dasync_polling ()
     359             : {
     360             : /* dasync is a fake async device, and could not be polled.
     361             :  * We have added code in the dasync engine to triggered the callback already,
     362             :  * so nothing can be done here
     363             :  */
     364           0 : }
     365             : 
     366             : void
     367           0 : qat_pre_init ()
     368             : {
     369           0 :   openssl_async_t *om = &openssl_async_main;
     370             : 
     371           0 :   ENGINE_ctrl_cmd (om->engine, "ENABLE_EXTERNAL_POLLING", 0, NULL, NULL, 0);
     372           0 : }
     373             : 
     374             : /* Below code is spefic to QAT engine, and other vendors can refer to this code to enable a new engine */
     375             : void
     376           0 : qat_init_thread (void *arg)
     377             : {
     378           0 :   openssl_async_t *om = &openssl_async_main;
     379           0 :   int thread_index = pointer_to_uword (arg);
     380             : 
     381           0 :   ENGINE_ctrl_cmd (om->engine, "SET_INSTANCE_FOR_THREAD", thread_index,
     382             :                    NULL, NULL, 0);
     383             : 
     384             :   TLS_DBG (2, "set thread %d and instance %d mapping\n", thread_index,
     385             :            thread_index);
     386             : 
     387           0 : }
     388             : 
     389             : void
     390           0 : qat_polling ()
     391             : {
     392           0 :   openssl_async_t *om = &openssl_async_main;
     393           0 :   int poll_status = 0;
     394             : 
     395           0 :   if (om->start_polling)
     396             :     {
     397           0 :       ENGINE_ctrl_cmd (om->engine, "POLL", 0, &poll_status, NULL, 0);
     398             :     }
     399           0 : }
     400             : 
     401             : void
     402           0 : openssl_async_polling ()
     403             : {
     404           0 :   openssl_async_t *om = &openssl_async_main;
     405           0 :   if (om->polling)
     406             :     {
     407           0 :       (*om->polling) ();
     408             :     }
     409           0 : }
     410             : 
     411             : void
     412           0 : openssl_async_node_enable_disable (u8 is_en)
     413             : {
     414           0 :   u8 state = is_en ? VLIB_NODE_STATE_POLLING : VLIB_NODE_STATE_DISABLED;
     415           0 :   vlib_thread_main_t *vtm = vlib_get_thread_main ();
     416           0 :   u8 have_workers = vtm->n_threads != 0;
     417             : 
     418           0 :   foreach_vlib_main ()
     419             :     {
     420           0 :       if (have_workers && this_vlib_main->thread_index)
     421             :         {
     422           0 :           vlib_node_set_state (this_vlib_main, tls_async_process_node.index,
     423             :                                state);
     424             :         }
     425             :     }
     426           0 : }
     427             : 
     428             : int
     429           0 : tls_async_do_job (int eidx, u32 thread_index)
     430             : {
     431             :   tls_ctx_t *ctx;
     432             :   openssl_evt_t *event;
     433             : 
     434             :   /* do the real job */
     435           0 :   event = openssl_evt_get_w_thread (eidx, thread_index);
     436           0 :   ctx = openssl_ctx_get_w_thread (event->ctx_index, thread_index);
     437             : 
     438           0 :   if (ctx)
     439             :     {
     440           0 :       ctx->resume = 1;
     441           0 :       session_send_rpc_evt_to_thread (thread_index, event_handler, event);
     442             :     }
     443           0 :   return 1;
     444             : }
     445             : 
     446             : int
     447           0 : tls_resume_from_crypto (int thread_index)
     448             : {
     449             :   int i;
     450             : 
     451           0 :   openssl_async_t *om = &openssl_async_main;
     452             :   openssl_evt_t *event;
     453           0 :   int *evt_run_head = &om->queue[thread_index].evt_run_head;
     454           0 :   int *evt_run_tail = &om->queue[thread_index].evt_run_tail;
     455             : 
     456           0 :   if (*evt_run_head < 0)
     457           0 :     return 0;
     458             : 
     459           0 :   for (i = 0; i < MAX_VECTOR_ASYNC; i++)
     460             :     {
     461           0 :       if (*evt_run_head >= 0)
     462             :         {
     463           0 :           event = openssl_evt_get_w_thread (*evt_run_head, thread_index);
     464           0 :           tls_async_do_job (*evt_run_head, thread_index);
     465           0 :           if (PREDICT_FALSE (event->status == SSL_ASYNC_REENTER))
     466             :             {
     467             :               /* recusive event triggered */
     468           0 :               event->status = SSL_ASYNC_READY;
     469           0 :               continue;
     470             :             }
     471             : 
     472           0 :           event->status = 0;
     473           0 :           *evt_run_head = event->next;
     474             : 
     475           0 :           if (event->next < 0)
     476             :             {
     477           0 :               *evt_run_tail = -1;
     478           0 :               break;
     479             :             }
     480             :         }
     481             :     }
     482             : 
     483           0 :   return 0;
     484             : 
     485             : }
     486             : 
     487             : static clib_error_t *
     488         575 : tls_async_init (vlib_main_t * vm)
     489             : {
     490         575 :   evt_pool_init (vm);
     491         575 :   return 0;
     492             : }
     493             : 
     494             : static uword
     495           0 : tls_async_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
     496             :                    vlib_frame_t * f)
     497             : {
     498             :   u8 thread_index;
     499           0 :   openssl_async_t *om = &openssl_async_main;
     500             : 
     501           0 :   thread_index = vlib_get_thread_index ();
     502           0 :   if (pool_elts (om->evt_pool[thread_index]) > 0)
     503             :     {
     504           0 :       openssl_async_polling ();
     505           0 :       tls_resume_from_crypto (thread_index);
     506             :     }
     507             : 
     508           0 :   return 0;
     509             : }
     510             : 
     511        1151 : VLIB_INIT_FUNCTION (tls_async_init);
     512             : 
     513             : /* *INDENT-OFF* */
     514       29375 : VLIB_REGISTER_NODE (tls_async_process_node,static) = {
     515             :     .function = tls_async_process,
     516             :     .type = VLIB_NODE_TYPE_INPUT,
     517             :     .name = "tls-async-process",
     518             :     .state = VLIB_NODE_STATE_DISABLED,
     519             : };
     520             : 
     521             : /* *INDENT-ON* */
     522             : 
     523             : /*
     524             :  * fd.io coding-style-patch-verification: ON
     525             :  *
     526             :  * Local Variables:
     527             :  * eval: (c-set-style "gnu")
     528             :  * End:
     529             :  */

Generated by: LCOV version 1.14