FD.io VPP  v20.01-48-g3e0dafb74
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 
120  return;
121 }
122 
123 int
124 openssl_engine_register (char *engine_name, char *algorithm)
125 {
126  int i, registered = -1;
128  void (*p) (void);
129  ENGINE *engine;
130 
131  for (i = 0; i < ARRAY_LEN (engine_list); i++)
132  {
133  if (!strcmp (engine_list[i].engine, engine_name))
134  {
135  om->polling = engine_list[i].polling;
136  om->polling_conf = engine_list[i].polling_conf;
137 
138  registered = i;
139  }
140  }
141  if (registered < 0)
142  {
143  clib_error ("engine %s is not regisered in VPP", engine_name);
144  return -1;
145  }
146 
147  ENGINE_load_builtin_engines ();
148  ENGINE_load_dynamic ();
149  engine = ENGINE_by_id (engine_name);
150 
151  if (engine == NULL)
152  {
153  clib_warning ("Failed to find engine ENGINE_by_id %s", engine_name);
154  return -1;
155  }
156 
157  om->engine = engine;
158  /* call pre-init */
159  p = engine_list[registered].pre_init;
160  if (p)
161  (*p) ();
162 
163  if (algorithm)
164  {
165  if (!ENGINE_set_default_string (engine, algorithm))
166  {
167  clib_warning ("Failed to set engine %s algorithm %s\n",
168  engine_name, algorithm);
169  return -1;
170  }
171  }
172  else
173  {
174  if (!ENGINE_set_default (engine, ENGINE_METHOD_ALL))
175  {
176  clib_warning ("Failed to set engine %s to all algorithm",
177  engine_name);
178  return -1;
179  }
180  }
181 
182  om->start_polling = 1;
183 
184  return 0;
185 
186 }
187 
188 static openssl_evt_t *
189 openssl_evt_get (u32 evt_index)
190 {
191  openssl_evt_t **evt;
192  evt =
193  pool_elt_at_index (openssl_async_main.evt_pool[vlib_get_thread_index ()],
194  evt_index);
195  return *evt;
196 }
197 
198 static openssl_evt_t *
200 {
201  openssl_evt_t **evt;
202 
203  evt =
204  pool_elt_at_index (openssl_async_main.evt_pool[thread_index], evt_index);
205  return *evt;
206 }
207 
208 int
210 {
211  openssl_evt_t *evt;
213  int *evt_run_tail = &om->status[thread_index].evt_run_tail;
214 
215  if (event_idx < 0)
216  return 0;
217 
218  evt = openssl_evt_get_w_thread (event_idx, thread_index);
219 
220  evt->status = 0;
221 
222  /*pool operation */
223  pool_put_index (om->evt_pool[thread_index], event_idx);
224 
225  if (*evt_run_tail == event_idx)
226  *evt_run_tail = -1;
227 
228  return 1;
229 }
230 
231 static u32
233 {
236  openssl_evt_t **evt;
237 
238  pool_get (tm->evt_pool[thread_index], evt);
239  if (!(*evt))
240  *evt = clib_mem_alloc (sizeof (openssl_evt_t));
241 
242  clib_memset (*evt, 0, sizeof (openssl_evt_t));
243  (*evt)->event_index = evt - tm->evt_pool[thread_index];
244  return ((*evt)->event_index);
245 }
246 
247 int
248 tls_async_openssl_callback (SSL * s, void *evt)
249 {
250  openssl_evt_t *event, *event_tail;
253  int thread_index = args->thread_index;
254  int event_index = args->event_index;
255  int *evt_run_tail = &om->status[thread_index].evt_run_tail;
256  int *evt_run_head = &om->status[thread_index].evt_run_head;
257 
258  TLS_DBG (2, "Set event %d to run\n", event_index);
259 
260  event = openssl_evt_get_w_thread (event_index, thread_index);
261 
262  if (event->status == SSL_ASYNC_READY)
263  return 0;
264 
265  event->status = SSL_ASYNC_READY;
266  event->next = -1;
267 
268 
269  if (*evt_run_tail >= 0)
270  {
271  event_tail = openssl_evt_get_w_thread (*evt_run_tail, thread_index);
272  event_tail->next = event_index;
273  }
274  *evt_run_tail = event_index;
275  if (*evt_run_head < 0)
276  {
277  *evt_run_head = event_index;
278  }
279 
280  return 1;
281 }
282 
285  openssl_resume_handler * handler)
286 {
287  u32 eidx;
288  openssl_evt_t *event;
290  openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
291  int *evt_pending_head;
292  u32 thread_id = ctx->c_thread_index;
293 
294  eidx = openssl_evt_alloc ();
295  event = openssl_evt_get (eidx);
296 
297  event->ctx_index = oc->openssl_ctx_index;
298  event->status = SSL_ASYNC_PENDING;
299  event->handler = handler;
300  event->cb_args.event_index = eidx;
301  event->cb_args.thread_index = thread_id;
302  event->engine_callback.callback = tls_async_openssl_callback;
303  event->engine_callback.arg = &event->cb_args;
304 
305  /* add to pending list */
306  evt_pending_head = &om->status[thread_id].evt_pending_head;
307  event->next = *evt_pending_head;
308  *evt_pending_head = eidx;
309 
310  return &event->engine_callback;
311 }
312 
313 int
315 {
316  u32 eidx;
317  openssl_evt_t *event;
318  openssl_ctx_t *oc = (openssl_ctx_t *) ctx;
319  u32 thread_id = ctx->c_thread_index;
320 
321  eidx = openssl_evt_alloc ();
322  event = openssl_evt_get (eidx);
323 
324  event->ctx_index = oc->openssl_ctx_index;
325  event->status = SSL_ASYNC_PENDING;
326  event->handler = handler;
327  event->cb_args.event_index = eidx;
328  event->cb_args.thread_index = thread_id;
329  event->engine_callback.callback = tls_async_openssl_callback;
330  event->engine_callback.arg = &event->cb_args;
331 
332  /* This is a retry event, and need to put to ring to make it run again */
333  return tls_async_openssl_callback (NULL, &event->cb_args);
334 
335 }
336 
337 void
338 event_handler (void *tls_async)
339 {
340 
341  openssl_resume_handler *handler;
342  openssl_evt_t *callback;
343  session_t *tls_session;
344  int thread_index;
345  tls_ctx_t *ctx;
346 
347  callback = (openssl_evt_t *) tls_async;
348  thread_index = callback->cb_args.thread_index;
349  ctx = openssl_ctx_get_w_thread (callback->ctx_index, thread_index);
350  handler = callback->handler;
351  tls_session = session_get_from_handle (ctx->tls_session_handle);
352 
353  if (handler)
354  {
355  (*handler) (ctx, tls_session);
356  }
357 
358  /* Need to free the event */
359  openssl_evt_free (callback->cb_args.event_index, thread_index);
360 
361  return;
362 }
363 
364  /* engine specific code to polling the response ring */
365 void
367 {
368 /* dasync is a fake async device, and could not be polled.
369  * We have added code in the dasync engine to triggered the callback already,
370  * so nothing can be done here
371  */
372 }
373 
374 void
376 {
378 
379  ENGINE_ctrl_cmd (om->engine, "ENABLE_EXTERNAL_POLLING", 0, NULL, NULL, 0);
380 }
381 
382 /* Below code is spefic to QAT engine, and other vendors can refer to this code to enable a new engine */
383 void
385 {
388  int *config;
389 
390  config = &om->status[thread_index].poll_config;
391  if (PREDICT_TRUE (*config))
392  return;
393 
394  ENGINE_ctrl_cmd (om->engine, "SET_INSTANCE_FOR_THREAD", thread_index,
395  NULL, NULL, 0);
396  *config = 1;
397 
398  TLS_DBG (2, "set thread %d and instance %d mapping\n", thread_index,
399  thread_index);
400 
401 }
402 
403 void
405 {
407  int poll_status = 0;
408 
409  if (om->start_polling)
410  {
411  ENGINE_ctrl_cmd (om->engine, "POLL", 0, &poll_status, NULL, 0);
412  }
413 }
414 
415 void
417 {
419  if (om->polling)
420  {
421  (*om->polling) ();
422  }
423 }
424 
425 void
427 {
428  u8 state = is_en ? VLIB_NODE_STATE_POLLING : VLIB_NODE_STATE_DISABLED;
429  /* *INDENT-OFF* */
431  vlib_node_set_state (this_vlib_main, tls_async_process_node.index,
432  state);
433  }));
434  /* *INDENT-ON* */
435 }
436 
437 int
439 {
440  tls_ctx_t *ctx;
441  openssl_evt_t *event;
442 
443  /* do the real job */
444  event = openssl_evt_get_w_thread (eidx, thread_index);
445  ctx = openssl_ctx_get_w_thread (event->ctx_index, thread_index);
446 
447  if (ctx)
448  {
449  ctx->resume = 1;
450  session_send_rpc_evt_to_thread (thread_index, event_handler, event);
451  }
452  return 1;
453 }
454 
455 int
457 {
458  int i;
459 
461  openssl_evt_t *event;
462  int *evt_run_head = &om->status[thread_index].evt_run_head;
463 
464  if (*evt_run_head < 0)
465  return 0;
466 
467  for (i = 0; i < MAX_VECTOR_ASYNC; i++)
468  {
469  if (*evt_run_head >= 0)
470  {
471  event = openssl_evt_get_w_thread (*evt_run_head, thread_index);
472  TLS_DBG (2, "event run = %d\n", *evt_run_head);
473  tls_async_do_job (*evt_run_head, thread_index);
474 
475  *evt_run_head = event->next;
476 
477  }
478  else
479  {
480  break;
481  }
482  }
483 
484  return 0;
485 
486 }
487 
488 static clib_error_t *
490 {
491  evt_pool_init (vm);
492  return 0;
493 
494 }
495 
496 static uword
498  vlib_frame_t * f)
499 {
502 
503  if (om->polling_conf)
504  (*om->polling_conf) ();
505  thread_index = vlib_get_thread_index ();
506  if (pool_elts (om->evt_pool[thread_index]) > 0)
507  {
509  tls_resume_from_crypto (thread_index);
510  }
511 
512  return 0;
513 }
514 
516 
517 /* *INDENT-OFF* */
519  .function = tls_async_process,
520  .type = VLIB_NODE_TYPE_INPUT,
521  .name = "tls-async-process",
522  .state = VLIB_NODE_STATE_DISABLED,
523 };
524 
525 /* *INDENT-ON* */
526 
527 /*
528  * fd.io coding-style-patch-verification: ON
529  *
530  * Local Variables:
531  * eval: (c-set-style "gnu")
532  * End:
533  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
openssl_evt_t *** evt_pool
Definition: tls_async.c:61
void qat_polling()
Definition: tls_async.c:404
#define SSL_ASYNC_READY
Definition: tls_async.c:27
int openssl_evt_free(int event_idx, u8 thread_index)
Definition: tls_async.c:209
#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:438
#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:426
static clib_error_t * tls_async_init(vlib_main_t *vm)
Definition: tls_async.c:489
static openssl_evt_t * openssl_evt_get(u32 evt_index)
Definition: tls_async.c:189
int tls_async_openssl_callback(SSL *s, void *evt)
Definition: tls_async.c:248
int i
#define MAX_VECTOR_ASYNC
Definition: tls_async.c:23
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:237
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:199
static u32 openssl_evt_alloc(void)
Definition: tls_async.c:232
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:375
void qat_polling_config()
Definition: tls_async.c:384
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
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:124
unsigned int u32
Definition: types.h:88
void openssl_async_polling()
Definition: tls_async.c:416
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:519
int tls_resume_from_crypto(int thread_index)
Definition: tls_async.c:456
int vpp_add_async_run_event(tls_ctx_t *ctx, openssl_resume_handler *handler)
Definition: tls_async.c:314
static session_t * session_get_from_handle(session_handle_t handle)
Definition: session.h:315
long ctx[MAX_CONNS]
Definition: main.c:144
void(* polling_conf)(void)
Definition: tls_async.c:64
#define foreach_vlib_main(body)
Definition: threads.h:241
Definition: tls.h:58
vlib_main_t * vm
Definition: in2out_ed.c:1810
void dasync_polling()
Definition: tls_async.c:366
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:218
openssl_tls_callback_arg_t cb_args
Definition: tls_async.c:46
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:338
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:316
int openssl_resume_handler(tls_ctx_t *ctx, session_t *tls_session)
Definition: tls_openssl.h:63
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:153
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:77
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:284
u64 uword
Definition: types.h:112
void(* polling_conf)(void)
Definition: tls_async.c:80
u8 resume
Definition: tls.h:78
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
vl_api_dhcp_client_state_t state
Definition: dhcp.api:201
struct openssl_event_ openssl_evt_t
#define TLS_DBG(_lvl, _fmt, _args...)
Definition: tls.h:36
static uword tls_async_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: tls_async.c:497
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128