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 559 : evt_pool_init (vlib_main_t * vm)
90 : {
91 559 : vlib_thread_main_t *vtm = vlib_get_thread_main ();
92 559 : openssl_async_t *om = &openssl_async_main;
93 : int i, num_threads;
94 :
95 559 : num_threads = 1 /* main thread */ + vtm->n_threads;
96 :
97 : TLS_DBG (2, "Totally there is %d thread\n", num_threads);
98 :
99 559 : vec_validate (om->evt_pool, num_threads - 1);
100 559 : vec_validate (om->queue, num_threads - 1);
101 :
102 559 : om->start_polling = 0;
103 559 : om->engine = 0;
104 :
105 1172 : for (i = 0; i < num_threads; i++)
106 : {
107 613 : om->queue[i].evt_run_head = -1;
108 613 : om->queue[i].evt_run_tail = -1;
109 : }
110 559 : om->polling = NULL;
111 :
112 559 : 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 559 : tls_async_init (vlib_main_t * vm)
489 : {
490 559 : evt_pool_init (vm);
491 559 : 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 1119 : VLIB_INIT_FUNCTION (tls_async_init);
512 :
513 : /* *INDENT-OFF* */
514 27439 : 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 : */
|