tls: need to use thread id to fetch the event
[vpp.git] / src / plugins / tlsopenssl / tls_async.c
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 evt_pool_init (vlib_main_t * vm)
90 {
91   vlib_thread_main_t *vtm = vlib_get_thread_main ();
92   openssl_async_t *om = &openssl_async_main;
93   int i, num_threads;
94
95   num_threads = 1 /* main thread */  + vtm->n_threads;
96
97   TLS_DBG (2, "Totally there is %d thread\n", num_threads);
98
99   vec_validate (om->evt_pool, num_threads - 1);
100   vec_validate (om->queue, num_threads - 1);
101
102   om->start_polling = 0;
103   om->engine = 0;
104
105   for (i = 0; i < num_threads; i++)
106     {
107       om->queue[i].evt_run_head = -1;
108       om->queue[i].evt_run_tail = -1;
109     }
110   om->polling = NULL;
111
112   return;
113 }
114
115 int
116 openssl_engine_register (char *engine_name, char *algorithm, int async)
117 {
118   int i, registered = -1;
119   openssl_async_t *om = &openssl_async_main;
120   void (*p) (void);
121   ENGINE *engine;
122
123   for (i = 0; i < ARRAY_LEN (engine_list); i++)
124     {
125       if (!strcmp (engine_list[i].engine, engine_name))
126         {
127           om->polling = engine_list[i].polling;
128           registered = i;
129         }
130     }
131   if (registered < 0)
132     {
133       clib_error ("engine %s is not regisered in VPP", engine_name);
134       return -1;
135     }
136
137   ENGINE_load_builtin_engines ();
138   ENGINE_load_dynamic ();
139   engine = ENGINE_by_id (engine_name);
140
141   if (engine == NULL)
142     {
143       clib_warning ("Failed to find engine ENGINE_by_id %s", engine_name);
144       return -1;
145     }
146
147   om->engine = engine;
148   /* call pre-init */
149   p = engine_list[registered].pre_init;
150   if (p)
151     (*p) ();
152
153   if (algorithm)
154     {
155       if (!ENGINE_set_default_string (engine, algorithm))
156         {
157           clib_warning ("Failed to set engine %s algorithm %s\n",
158                         engine_name, algorithm);
159           return -1;
160         }
161     }
162   else
163     {
164       if (!ENGINE_set_default (engine, ENGINE_METHOD_ALL))
165         {
166           clib_warning ("Failed to set engine %s to all algorithm",
167                         engine_name);
168           return -1;
169         }
170     }
171
172   if (async)
173     {
174       openssl_async_node_enable_disable (1);
175     }
176
177   for (i = 0; i < vlib_num_workers (); i++)
178     {
179       if (engine_list[registered].thread_init)
180         session_send_rpc_evt_to_thread (i + 1,
181                                         engine_list[registered].thread_init,
182                                         (void *) &i);
183     }
184
185   om->start_polling = 1;
186
187   return 0;
188
189 }
190
191 static openssl_evt_t *
192 openssl_evt_get (u32 evt_index)
193 {
194   openssl_evt_t **evt;
195   evt =
196     pool_elt_at_index (openssl_async_main.evt_pool[vlib_get_thread_index ()],
197                        evt_index);
198   return *evt;
199 }
200
201 static openssl_evt_t *
202 openssl_evt_get_w_thread (int evt_index, u8 thread_index)
203 {
204   openssl_evt_t **evt;
205
206   evt =
207     pool_elt_at_index (openssl_async_main.evt_pool[thread_index], evt_index);
208   return *evt;
209 }
210
211 int
212 openssl_evt_free (int event_index, u8 thread_index)
213 {
214   openssl_async_t *om = &openssl_async_main;
215
216   /*pool operation */
217   pool_put_index (om->evt_pool[thread_index], event_index);
218
219   return 1;
220 }
221
222 static u32
223 openssl_evt_alloc (void)
224 {
225   u8 thread_index = vlib_get_thread_index ();
226   openssl_async_t *tm = &openssl_async_main;
227   openssl_evt_t **evt;
228
229   pool_get (tm->evt_pool[thread_index], evt);
230   if (!(*evt))
231     *evt = clib_mem_alloc (sizeof (openssl_evt_t));
232
233   clib_memset (*evt, 0, sizeof (openssl_evt_t));
234   (*evt)->event_idx = evt - tm->evt_pool[thread_index];
235   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 tls_async_openssl_callback (SSL * s, void *cb_arg)
244 {
245   openssl_evt_t *event, *event_tail;
246   openssl_async_t *om = &openssl_async_main;
247   openssl_tls_callback_arg_t *args = (openssl_tls_callback_arg_t *) cb_arg;
248   int thread_index = args->thread_index;
249   int event_index = args->event_index;
250   int *evt_run_tail = &om->queue[thread_index].evt_run_tail;
251   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   event = openssl_evt_get_w_thread (event_index, thread_index);
255
256   /* Happend when a recursive case, especially in SW simulation */
257   if (PREDICT_FALSE (event->status == SSL_ASYNC_READY))
258     {
259       event->status = SSL_ASYNC_REENTER;
260       return 0;
261     }
262   event->status = SSL_ASYNC_READY;
263   event->next = -1;
264
265   if (*evt_run_tail >= 0)
266     {
267       event_tail = openssl_evt_get_w_thread (*evt_run_tail, thread_index);
268       event_tail->next = event_index;
269     }
270   *evt_run_tail = event_index;
271   if (*evt_run_head < 0)
272     {
273       *evt_run_head = event_index;
274     }
275
276   return 1;
277 }
278
279 int
280 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   openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
287   u32 thread_id = ctx->c_thread_index;
288
289   eidx = openssl_evt_alloc ();
290   event = openssl_evt_get (eidx);
291   event->ctx_index = oc->openssl_ctx_index;
292   event->event_idx = eidx;
293   event->thread_idx = thread_id;
294   event->handler = handler;
295   event->session_index = session->session_index;
296   event->status = 0;
297   ctx->evt_index = eidx;
298 #ifdef HAVE_OPENSSL_ASYNC
299   SSL_set_async_callback_arg (oc->ssl, &event->cb_args);
300 #endif
301
302   return 1;
303 }
304
305 int
306 vpp_openssl_is_inflight (tls_ctx_t * ctx)
307 {
308   u32 eidx;
309   openssl_evt_t *event;
310   eidx = ctx->evt_index;
311   event = openssl_evt_get (eidx);
312
313   if (event->status == SSL_ASYNC_INFLIGHT)
314     return 1;
315   return 0;
316 }
317
318 int
319 vpp_tls_async_update_event (tls_ctx_t * ctx, int eagain)
320 {
321   u32 eidx;
322   openssl_evt_t *event;
323
324   eidx = ctx->evt_index;
325   event = openssl_evt_get (eidx);
326   event->status = SSL_ASYNC_INFLIGHT;
327   if (eagain)
328     return tls_async_openssl_callback (0, &event->cb_args);
329
330   return 1;
331 }
332
333 void
334 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   event = (openssl_evt_t *) tls_async;
343   thread_index = event->thread_idx;
344   ctx = openssl_ctx_get_w_thread (event->ctx_index, thread_index);
345   handler = event->handler;
346   session = session_get (event->session_index, thread_index);
347
348   if (handler)
349     {
350       (*handler) (ctx, session);
351     }
352
353   return;
354 }
355
356  /* engine specific code to polling the response ring */
357 void
358 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 }
365
366 void
367 qat_pre_init ()
368 {
369   openssl_async_t *om = &openssl_async_main;
370
371   ENGINE_ctrl_cmd (om->engine, "ENABLE_EXTERNAL_POLLING", 0, NULL, NULL, 0);
372 }
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 qat_init_thread (void *arg)
377 {
378   openssl_async_t *om = &openssl_async_main;
379   int thread_index = *(int *) arg;
380
381   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 }
388
389 void
390 qat_polling ()
391 {
392   openssl_async_t *om = &openssl_async_main;
393   int poll_status = 0;
394
395   if (om->start_polling)
396     {
397       ENGINE_ctrl_cmd (om->engine, "POLL", 0, &poll_status, NULL, 0);
398     }
399 }
400
401 void
402 openssl_async_polling ()
403 {
404   openssl_async_t *om = &openssl_async_main;
405   if (om->polling)
406     {
407       (*om->polling) ();
408     }
409 }
410
411 void
412 openssl_async_node_enable_disable (u8 is_en)
413 {
414   u8 state = is_en ? VLIB_NODE_STATE_POLLING : VLIB_NODE_STATE_DISABLED;
415   vlib_thread_main_t *vtm = vlib_get_thread_main ();
416   u8 have_workers = vtm->n_threads != 0;
417
418   /* *INDENT-OFF* */
419   foreach_vlib_main (({
420     if (have_workers && ii != 0)
421       {
422         vlib_node_set_state (this_vlib_main, tls_async_process_node.index,
423                          state);
424       }
425   }));
426   /* *INDENT-ON* */
427 }
428
429 int
430 tls_async_do_job (int eidx, u32 thread_index)
431 {
432   tls_ctx_t *ctx;
433   openssl_evt_t *event;
434
435   /* do the real job */
436   event = openssl_evt_get_w_thread (eidx, thread_index);
437   ctx = openssl_ctx_get_w_thread (event->ctx_index, thread_index);
438
439   if (ctx)
440     {
441       ctx->resume = 1;
442       session_send_rpc_evt_to_thread (thread_index, event_handler, event);
443     }
444   return 1;
445 }
446
447 int
448 tls_resume_from_crypto (int thread_index)
449 {
450   int i;
451
452   openssl_async_t *om = &openssl_async_main;
453   openssl_evt_t *event;
454   int *evt_run_head = &om->queue[thread_index].evt_run_head;
455   int *evt_run_tail = &om->queue[thread_index].evt_run_tail;
456
457   if (*evt_run_head < 0)
458     return 0;
459
460   for (i = 0; i < MAX_VECTOR_ASYNC; i++)
461     {
462       if (*evt_run_head >= 0)
463         {
464           event = openssl_evt_get_w_thread (*evt_run_head, thread_index);
465           tls_async_do_job (*evt_run_head, thread_index);
466           if (PREDICT_FALSE (event->status == SSL_ASYNC_REENTER))
467             {
468               /* recusive event triggered */
469               event->status = SSL_ASYNC_READY;
470               continue;
471             }
472
473           event->status = 0;
474           *evt_run_head = event->next;
475
476           if (event->next < 0)
477             {
478               *evt_run_tail = -1;
479               break;
480             }
481         }
482     }
483
484   return 0;
485
486 }
487
488 static clib_error_t *
489 tls_async_init (vlib_main_t * vm)
490 {
491   evt_pool_init (vm);
492   return 0;
493 }
494
495 static uword
496 tls_async_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
497                    vlib_frame_t * f)
498 {
499   u8 thread_index;
500   openssl_async_t *om = &openssl_async_main;
501
502   thread_index = vlib_get_thread_index ();
503   if (pool_elts (om->evt_pool[thread_index]) > 0)
504     {
505       openssl_async_polling ();
506       tls_resume_from_crypto (thread_index);
507     }
508
509   return 0;
510 }
511
512 VLIB_INIT_FUNCTION (tls_async_init);
513
514 /* *INDENT-OFF* */
515 VLIB_REGISTER_NODE (tls_async_process_node,static) = {
516     .function = tls_async_process,
517     .type = VLIB_NODE_TYPE_INPUT,
518     .name = "tls-async-process",
519     .state = VLIB_NODE_STATE_DISABLED,
520 };
521
522 /* *INDENT-ON* */
523
524 /*
525  * fd.io coding-style-patch-verification: ON
526  *
527  * Local Variables:
528  * eval: (c-set-style "gnu")
529  * End:
530  */