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