FD.io VPP  v18.10-32-g1161dda
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 <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 
33 {
37 
38 typedef struct openssl_event_
39 {
40  int status;
44 
48 
49  int next;
51 
52 typedef struct openssl_async_status_
53 {
59 
60 typedef struct openssl_async_
61 {
64  void (*polling) (void);
65  void (*polling_conf) (void);
67  ENGINE *engine;
68 
70 
71 void qat_polling ();
72 void qat_pre_init ();
73 void qat_polling_config ();
74 void dasync_polling ();
75 
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[] = {
86  {"dasync", dasync_polling, NULL, NULL}
87 };
88 
91 
92 /* to avoid build warning */
94  void *rpc_args);
95 
96 void
98 {
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 
122 
123  return;
124 }
125 
126 int
127 openssl_engine_register (char *engine_name, char *algorithm)
128 {
129  int i, registered = -1;
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 *
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
211 {
212  openssl_evt_t *evt;
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
234 {
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  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;
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 
286  openssl_resume_handler * handler)
287 {
288  u32 eidx;
289  openssl_evt_t *event;
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
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
368 {
370  openssl_evt_t *event;
371  int *evt_pending;
372  openssl_tls_callback_t *engine_cb;
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
393 {
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
402 {
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
422 {
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
434 {
436  if (om->polling)
437  {
438  (*om->polling) ();
439  }
440 }
441 
442 void
444 {
445  u8 state = is_en ? VLIB_NODE_STATE_POLLING : VLIB_NODE_STATE_DISABLED;
446  /* *INDENT-OFF* */
448  vlib_node_set_state (this_vlib_main, tls_async_process_node.index,
449  state);
450  }));
451  /* *INDENT-ON* */
452 }
453 
454 int
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
474 {
475  int i;
476 
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 *
507 {
508  evt_pool_init (vm);
509  return 0;
510 
511 }
512 
513 static uword
515  vlib_frame_t * f)
516 {
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  {
526  tls_resume_from_crypto (thread_index);
527  }
528 
529  return 0;
530 }
531 
533 
534 /* *INDENT-OFF* */
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  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
openssl_evt_t *** evt_pool
Definition: tls_async.c:62
void qat_polling()
Definition: tls_async.c:421
#define SSL_ASYNC_READY
Definition: tls_async.c:28
int openssl_evt_free(int event_idx, u8 thread_index)
Definition: tls_async.c:210
#define PREDICT_TRUE(x)
Definition: clib.h:108
int tls_async_do_job(int eidx, u32 thread_index)
Definition: tls_async.c:455
#define NULL
Definition: clib.h:57
void openssl_async_node_enable_disable(u8 is_en)
Definition: tls_async.c:443
static clib_error_t * tls_async_init(vlib_main_t *vm)
Definition: tls_async.c:506
static openssl_evt_t * openssl_evt_get(u32 evt_index)
Definition: tls_async.c:190
int i
#define MAX_VECTOR_ASYNC
Definition: tls_async.c:24
int(* callback)(void *arg)
Definition: tls_openssl.h:56
static stream_session_t * session_get_from_handle(session_handle_t handle)
Definition: session.h:360
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:228
char * engine
Definition: tls_async.c:78
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:200
static u32 openssl_evt_alloc(void)
Definition: tls_async.c:233
void(* polling)(void)
Definition: tls_async.c:79
static vlib_node_registration_t tls_async_process_node
(constructor) VLIB_REGISTER_NODE (tls_async_process_node)
Definition: tls_async.c:90
void qat_pre_init()
Definition: tls_async.c:392
memset(h->entries, 0, sizeof(h->entries[0])*entries)
void qat_polling_config()
Definition: tls_async.c:401
#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:110
struct openssl_async_ openssl_async_t
int openssl_engine_register(char *engine_name, char *algorithm)
Definition: tls_async.c:127
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:433
int openssl_async_run(void *evt)
Definition: tls_async.c:249
struct _stream_session_t stream_session_t
ENGINE * engine
Definition: tls_async.c:67
openssl_async_status_t * status
Definition: tls_async.c:63
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
int tls_resume_from_crypto(int thread_index)
Definition: tls_async.c:473
int vpp_add_async_run_event(tls_ctx_t *ctx, openssl_resume_handler *handler)
Definition: tls_async.c:315
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:65
#define foreach_vlib_main(body)
Definition: threads.h:234
Definition: tls.h:53
void dasync_polling()
Definition: tls_async.c:367
vlib node functions
openssl_resume_handler * handler
Definition: tls_async.c:45
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:211
openssl_tls_callback_arg_t cb_args
Definition: tls_async.c:47
vlib_main_t * vm
Definition: buffer.c:294
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:61
void evt_pool_init(vlib_main_t *vm)
Definition: tls_async.c:97
void event_handler(void *tls_async)
Definition: tls_async.c:339
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:299
void(* polling)(void)
Definition: tls_async.c:64
#define SSL_ASYNC_PENDING
Definition: tls_async.c:27
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:147
static void * clib_mem_alloc(uword size)
Definition: mem.h:132
openssl_async_t openssl_async_main
Definition: tls_async.c:89
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:285
u64 uword
Definition: types.h:112
void(* polling_conf)(void)
Definition: tls_async.c:81
u8 resume
Definition: tls.h:73
void(* pre_init)(void)
Definition: tls_async.c:80
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
openssl_tls_callback_t engine_callback
Definition: tls_async.c:46
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:514
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128