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