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