tls: report error if connected cannot be initialized
[vpp.git] / src / vnet / tls / tls.c
1 /*
2  * Copyright (c) 2018-2019 Cisco 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
16 #include <vnet/session/application_interface.h>
17 #include <vppinfra/lock.h>
18 #include <vnet/tls/tls.h>
19
20 static tls_main_t tls_main;
21 static tls_engine_vft_t *tls_vfts;
22
23 #define TLS_INVALID_HANDLE      ~0
24 #define TLS_IDX_MASK            0x00FFFFFF
25 #define TLS_ENGINE_TYPE_SHIFT   28
26
27 void tls_disconnect (u32 ctx_handle, u32 thread_index);
28
29 void
30 tls_disconnect_transport (tls_ctx_t * ctx)
31 {
32   vnet_disconnect_args_t a = {
33     .handle = ctx->tls_session_handle,
34     .app_index = tls_main.app_index,
35   };
36
37   if (vnet_disconnect_session (&a))
38     clib_warning ("disconnect returned");
39 }
40
41 crypto_engine_type_t
42 tls_get_available_engine (void)
43 {
44   int i;
45   for (i = 0; i < vec_len (tls_vfts); i++)
46     {
47       if (tls_vfts[i].ctx_alloc)
48         return i;
49     }
50   return CRYPTO_ENGINE_NONE;
51 }
52
53 int
54 tls_add_vpp_q_rx_evt (session_t * s)
55 {
56   if (svm_fifo_set_event (s->rx_fifo))
57     session_send_io_evt_to_thread (s->rx_fifo, SESSION_IO_EVT_RX);
58   return 0;
59 }
60
61 int
62 tls_add_vpp_q_builtin_rx_evt (session_t * s)
63 {
64   session_enqueue_notify (s);
65   return 0;
66 }
67
68 int
69 tls_add_vpp_q_tx_evt (session_t * s)
70 {
71   if (svm_fifo_set_event (s->tx_fifo))
72     session_send_io_evt_to_thread (s->tx_fifo, SESSION_IO_EVT_TX);
73   return 0;
74 }
75
76 static inline int
77 tls_add_app_q_evt (app_worker_t *app_wrk, session_t *app_session)
78 {
79   app_worker_add_event (app_wrk, app_session, SESSION_IO_EVT_RX);
80   return 0;
81 }
82
83 u32
84 tls_listener_ctx_alloc (void)
85 {
86   tls_main_t *tm = &tls_main;
87   tls_ctx_t *ctx;
88
89   pool_get (tm->listener_ctx_pool, ctx);
90   clib_memset (ctx, 0, sizeof (*ctx));
91   return ctx - tm->listener_ctx_pool;
92 }
93
94 void
95 tls_listener_ctx_free (tls_ctx_t * ctx)
96 {
97   if (CLIB_DEBUG)
98     memset (ctx, 0xfb, sizeof (*ctx));
99   pool_put (tls_main.listener_ctx_pool, ctx);
100 }
101
102 tls_ctx_t *
103 tls_listener_ctx_get (u32 ctx_index)
104 {
105   return pool_elt_at_index (tls_main.listener_ctx_pool, ctx_index);
106 }
107
108 u32
109 tls_listener_ctx_index (tls_ctx_t * ctx)
110 {
111   return (ctx - tls_main.listener_ctx_pool);
112 }
113
114 u32
115 tls_ctx_half_open_alloc (void)
116 {
117   tls_main_t *tm = &tls_main;
118   tls_ctx_t *ctx;
119
120   pool_get_aligned_safe (tm->half_open_ctx_pool, ctx, CLIB_CACHE_LINE_BYTES);
121
122   clib_memset (ctx, 0, sizeof (*ctx));
123   ctx->c_c_index = ctx - tm->half_open_ctx_pool;
124   ctx->c_thread_index = transport_cl_thread ();
125
126   return ctx->c_c_index;
127 }
128
129 void
130 tls_ctx_half_open_free (u32 ho_index)
131 {
132   pool_put_index (tls_main.half_open_ctx_pool, ho_index);
133 }
134
135 tls_ctx_t *
136 tls_ctx_half_open_get (u32 ctx_index)
137 {
138   tls_main_t *tm = &tls_main;
139   return pool_elt_at_index (tm->half_open_ctx_pool, ctx_index);
140 }
141
142 void
143 tls_notify_app_enqueue (tls_ctx_t * ctx, session_t * app_session)
144 {
145   app_worker_t *app_wrk;
146   app_wrk = app_worker_get_if_valid (app_session->app_wrk_index);
147   if (PREDICT_TRUE (app_wrk != 0))
148     tls_add_app_q_evt (app_wrk, app_session);
149 }
150
151 int
152 tls_notify_app_accept (tls_ctx_t * ctx)
153 {
154   session_t *app_listener, *app_session;
155   app_worker_t *app_wrk;
156   tls_ctx_t *lctx;
157   int rv;
158
159   lctx = tls_listener_ctx_get (ctx->listener_ctx_index);
160   app_listener = listen_session_get_from_handle (lctx->app_session_handle);
161
162   app_session = session_get (ctx->c_s_index, ctx->c_thread_index);
163   app_session->app_wrk_index = ctx->parent_app_wrk_index;
164   app_session->connection_index = ctx->tls_ctx_handle;
165   app_session->session_type = app_listener->session_type;
166   app_session->listener_handle = listen_session_get_handle (app_listener);
167   app_session->session_state = SESSION_STATE_ACCEPTING;
168
169   if ((rv = app_worker_init_accepted (app_session)))
170     {
171       TLS_DBG (1, "failed to allocate fifos");
172       session_free (app_session);
173       return rv;
174     }
175   ctx->app_session_handle = session_handle (app_session);
176   ctx->parent_app_wrk_index = app_session->app_wrk_index;
177   app_wrk = app_worker_get (app_session->app_wrk_index);
178   return app_worker_accept_notify (app_wrk, app_session);
179 }
180
181 int
182 tls_notify_app_connected (tls_ctx_t * ctx, session_error_t err)
183 {
184   u32 parent_app_api_ctx;
185   session_t *app_session;
186   app_worker_t *app_wrk;
187
188   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_index);
189   if (!app_wrk)
190     {
191       if (ctx->tls_type == TRANSPORT_PROTO_TLS)
192         session_free (session_get (ctx->c_s_index, ctx->c_thread_index));
193       ctx->no_app_session = 1;
194       return -1;
195     }
196
197   if (err)
198     {
199       /* Free app session pre-allocated when transport was established */
200       if (ctx->tls_type == TRANSPORT_PROTO_TLS)
201         session_free (session_get (ctx->c_s_index, ctx->c_thread_index));
202       ctx->no_app_session = 1;
203       goto send_reply;
204     }
205
206   /* For DTLS the app session is not preallocated because the underlying udp
207    * session might migrate to a different worker during the handshake */
208   if (ctx->tls_type == TRANSPORT_PROTO_DTLS)
209     {
210       session_type_t st;
211       /* Cleanup half-open session as we don't get notification from udp */
212       session_half_open_delete_notify (&ctx->connection);
213       app_session = session_alloc (ctx->c_thread_index);
214       app_session->session_state = SESSION_STATE_CREATED;
215       ctx->c_s_index = app_session->session_index;
216       st =
217         session_type_from_proto_and_ip (TRANSPORT_PROTO_DTLS, ctx->tcp_is_ip4);
218       app_session->session_type = st;
219       app_session->connection_index = ctx->tls_ctx_handle;
220     }
221   else
222     {
223       app_session = session_get (ctx->c_s_index, ctx->c_thread_index);
224     }
225
226   app_session->app_wrk_index = ctx->parent_app_wrk_index;
227   app_session->opaque = ctx->parent_app_api_context;
228
229   if ((err = app_worker_init_connected (app_wrk, app_session)))
230     {
231       app_worker_connect_notify (app_wrk, 0, err, ctx->parent_app_api_context);
232       ctx->no_app_session = 1;
233       session_free (app_session);
234       return -1;
235     }
236
237   app_session->session_state = SESSION_STATE_READY;
238   parent_app_api_ctx = ctx->parent_app_api_context;
239   ctx->app_session_handle = session_handle (app_session);
240
241   if (app_worker_connect_notify (app_wrk, app_session, SESSION_E_NONE,
242                                  parent_app_api_ctx))
243     {
244       TLS_DBG (1, "failed to notify app");
245       session_free (session_get (ctx->c_s_index, ctx->c_thread_index));
246       ctx->no_app_session = 1;
247       return -1;
248     }
249
250   return 0;
251
252 send_reply:
253   return app_worker_connect_notify (app_wrk, 0, err,
254                                     ctx->parent_app_api_context);
255 }
256
257 static inline void
258 tls_ctx_parse_handle (u32 ctx_handle, u32 * ctx_index, u32 * engine_type)
259 {
260   *ctx_index = ctx_handle & TLS_IDX_MASK;
261   *engine_type = ctx_handle >> TLS_ENGINE_TYPE_SHIFT;
262 }
263
264 static inline crypto_engine_type_t
265 tls_get_engine_type (crypto_engine_type_t requested,
266                      crypto_engine_type_t preferred)
267 {
268   if (requested != CRYPTO_ENGINE_NONE)
269     {
270       if (tls_vfts[requested].ctx_alloc)
271         return requested;
272       return CRYPTO_ENGINE_NONE;
273     }
274   if (!tls_vfts[preferred].ctx_alloc)
275     return tls_get_available_engine ();
276   return preferred;
277 }
278
279 static inline u32
280 tls_ctx_alloc (crypto_engine_type_t engine_type)
281 {
282   u32 ctx_index;
283   ctx_index = tls_vfts[engine_type].ctx_alloc ();
284   return (((u32) engine_type << TLS_ENGINE_TYPE_SHIFT) | ctx_index);
285 }
286
287 static inline u32
288 tls_ctx_alloc_w_thread (crypto_engine_type_t engine_type, u32 thread_index)
289 {
290   u32 ctx_index;
291   ctx_index = tls_vfts[engine_type].ctx_alloc_w_thread (thread_index);
292   return (((u32) engine_type << TLS_ENGINE_TYPE_SHIFT) | ctx_index);
293 }
294
295 static inline u32
296 tls_ctx_attach (crypto_engine_type_t engine_type, u32 thread_index, void *ctx)
297 {
298   u32 ctx_index;
299   ctx_index = tls_vfts[engine_type].ctx_attach (thread_index, ctx);
300   return (((u32) engine_type << TLS_ENGINE_TYPE_SHIFT) | ctx_index);
301 }
302
303 static inline void *
304 tls_ctx_detach (tls_ctx_t *ctx)
305 {
306   return tls_vfts[ctx->tls_ctx_engine].ctx_detach (ctx);
307 }
308
309 static inline tls_ctx_t *
310 tls_ctx_get (u32 ctx_handle)
311 {
312   u32 ctx_index, engine_type;
313   tls_ctx_parse_handle (ctx_handle, &ctx_index, &engine_type);
314   return tls_vfts[engine_type].ctx_get (ctx_index);
315 }
316
317 static inline tls_ctx_t *
318 tls_ctx_get_w_thread (u32 ctx_handle, u8 thread_index)
319 {
320   u32 ctx_index, engine_type;
321   tls_ctx_parse_handle (ctx_handle, &ctx_index, &engine_type);
322   return tls_vfts[engine_type].ctx_get_w_thread (ctx_index, thread_index);
323 }
324
325 static inline int
326 tls_ctx_init_server (tls_ctx_t * ctx)
327 {
328   return tls_vfts[ctx->tls_ctx_engine].ctx_init_server (ctx);
329 }
330
331 static inline int
332 tls_ctx_init_client (tls_ctx_t * ctx)
333 {
334   return tls_vfts[ctx->tls_ctx_engine].ctx_init_client (ctx);
335 }
336
337 static inline int
338 tls_ctx_write (tls_ctx_t * ctx, session_t * app_session,
339                transport_send_params_t * sp)
340 {
341   u32 n_wrote;
342
343   sp->max_burst_size = sp->max_burst_size * TRANSPORT_PACER_MIN_MSS;
344   n_wrote = tls_vfts[ctx->tls_ctx_engine].ctx_write (ctx, app_session, sp);
345   sp->bytes_dequeued = n_wrote;
346   return n_wrote > 0 ? clib_max (n_wrote / TRANSPORT_PACER_MIN_MSS, 1) : 0;
347 }
348
349 static inline int
350 tls_ctx_read (tls_ctx_t * ctx, session_t * tls_session)
351 {
352   return tls_vfts[ctx->tls_ctx_engine].ctx_read (ctx, tls_session);
353 }
354
355 static inline int
356 tls_ctx_transport_close (tls_ctx_t * ctx)
357 {
358   return tls_vfts[ctx->tls_ctx_engine].ctx_transport_close (ctx);
359 }
360
361 static inline int
362 tls_ctx_app_close (tls_ctx_t * ctx)
363 {
364   return tls_vfts[ctx->tls_ctx_engine].ctx_app_close (ctx);
365 }
366
367 void
368 tls_ctx_free (tls_ctx_t * ctx)
369 {
370   tls_vfts[ctx->tls_ctx_engine].ctx_free (ctx);
371 }
372
373 u8
374 tls_ctx_handshake_is_over (tls_ctx_t * ctx)
375 {
376   return tls_vfts[ctx->tls_ctx_engine].ctx_handshake_is_over (ctx);
377 }
378
379 int
380 tls_reinit_ca_chain (crypto_engine_type_t tls_engine_id)
381 {
382   return tls_vfts[tls_engine_id].ctx_reinit_cachain ();
383 }
384
385 void
386 tls_notify_app_io_error (tls_ctx_t *ctx)
387 {
388   ASSERT (tls_ctx_handshake_is_over (ctx));
389
390   session_transport_reset_notify (&ctx->connection);
391   session_transport_closed_notify (&ctx->connection);
392   tls_disconnect_transport (ctx);
393 }
394
395 void
396 tls_session_reset_callback (session_t * s)
397 {
398   tls_ctx_t *ctx;
399   transport_connection_t *tc;
400   session_t *app_session;
401
402   ctx = tls_ctx_get (s->opaque);
403   ctx->is_passive_close = 1;
404   tc = &ctx->connection;
405   if (tls_ctx_handshake_is_over (ctx))
406     {
407       session_transport_reset_notify (tc);
408       session_transport_closed_notify (tc);
409       tls_disconnect_transport (ctx);
410     }
411   else
412     if ((app_session =
413          session_get_if_valid (ctx->c_s_index, ctx->c_thread_index)))
414     {
415       session_free (app_session);
416       ctx->c_s_index = SESSION_INVALID_INDEX;
417       tls_disconnect_transport (ctx);
418     }
419 }
420
421 static void
422 tls_session_cleanup_ho (session_t *s)
423 {
424   tls_ctx_t *ctx;
425   u32 ho_index;
426
427   /* session opaque stores the opaque passed on connect */
428   ho_index = s->opaque;
429   ctx = tls_ctx_half_open_get (ho_index);
430   session_half_open_delete_notify (&ctx->connection);
431   tls_ctx_half_open_free (ho_index);
432 }
433
434 int
435 tls_add_segment_callback (u32 client_index, u64 segment_handle)
436 {
437   /* No-op for builtin */
438   return 0;
439 }
440
441 int
442 tls_del_segment_callback (u32 client_index, u64 segment_handle)
443 {
444   return 0;
445 }
446
447 void
448 tls_session_disconnect_callback (session_t * tls_session)
449 {
450   tls_ctx_t *ctx;
451
452   TLS_DBG (1, "TCP disconnecting handle %x session %u", tls_session->opaque,
453            tls_session->session_index);
454
455   ASSERT (tls_session->thread_index == vlib_get_thread_index ()
456           || vlib_thread_is_main_w_barrier ());
457
458   ctx = tls_ctx_get_w_thread (tls_session->opaque, tls_session->thread_index);
459   ctx->is_passive_close = 1;
460   tls_ctx_transport_close (ctx);
461 }
462
463 int
464 tls_session_accept_callback (session_t * tls_session)
465 {
466   session_t *tls_listener, *app_session;
467   tls_ctx_t *lctx, *ctx;
468   u32 ctx_handle;
469   int rv;
470
471   tls_listener =
472     listen_session_get_from_handle (tls_session->listener_handle);
473   lctx = tls_listener_ctx_get (tls_listener->opaque);
474
475   ctx_handle = tls_ctx_alloc (lctx->tls_ctx_engine);
476   ctx = tls_ctx_get (ctx_handle);
477   memcpy (ctx, lctx, sizeof (*lctx));
478   ctx->c_thread_index = vlib_get_thread_index ();
479   ctx->tls_ctx_handle = ctx_handle;
480   tls_session->session_state = SESSION_STATE_READY;
481   tls_session->opaque = ctx_handle;
482   ctx->tls_session_handle = session_handle (tls_session);
483   ctx->listener_ctx_index = tls_listener->opaque;
484   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
485   ctx->ckpair_index = lctx->ckpair_index;
486
487   /* Preallocate app session. Avoids allocating a session post handshake
488    * on tls_session rx and potentially invalidating the session pool */
489   app_session = session_alloc (ctx->c_thread_index);
490   app_session->session_state = SESSION_STATE_CREATED;
491   app_session->session_type =
492     session_type_from_proto_and_ip (TRANSPORT_PROTO_TLS, ctx->tcp_is_ip4);
493   app_session->connection_index = ctx->tls_ctx_handle;
494   ctx->c_s_index = app_session->session_index;
495
496   TLS_DBG (1, "Accept on listener %u new connection [%u]%x",
497            tls_listener->opaque, vlib_get_thread_index (), ctx_handle);
498
499   rv = tls_ctx_init_server (ctx);
500   if (rv)
501     {
502       session_free (app_session);
503       tls_ctx_free (ctx);
504     }
505
506   return rv;
507 }
508
509 int
510 tls_app_rx_callback (session_t * tls_session)
511 {
512   tls_ctx_t *ctx;
513
514   /* DTLS session migrating, wait for next notification */
515   if (PREDICT_FALSE (tls_session->flags & SESSION_F_IS_MIGRATING))
516     return 0;
517
518   ctx = tls_ctx_get (tls_session->opaque);
519   if (PREDICT_FALSE (ctx->no_app_session || ctx->app_closed))
520     {
521       TLS_DBG (1, "Local App closed");
522       return 0;
523     }
524   tls_ctx_read (ctx, tls_session);
525   return 0;
526 }
527
528 int
529 tls_app_tx_callback (session_t * tls_session)
530 {
531   tls_ctx_t *ctx;
532
533   ctx = tls_ctx_get (tls_session->opaque);
534   transport_connection_reschedule (&ctx->connection);
535
536   return 0;
537 }
538
539 int
540 tls_session_connected_cb (u32 tls_app_index, u32 ho_ctx_index,
541                           session_t *tls_session, session_error_t err)
542 {
543   session_t *app_session;
544   tls_ctx_t *ho_ctx, *ctx;
545   session_type_t st;
546   u32 ctx_handle;
547   int rv;
548
549   ho_ctx = tls_ctx_half_open_get (ho_ctx_index);
550
551   ctx_handle = tls_ctx_alloc (ho_ctx->tls_ctx_engine);
552   ctx = tls_ctx_get (ctx_handle);
553   clib_memcpy_fast (ctx, ho_ctx, sizeof (*ctx));
554   /* Half-open freed on tcp half-open cleanup notification */
555
556   ctx->c_thread_index = vlib_get_thread_index ();
557   ctx->tls_ctx_handle = ctx_handle;
558   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
559
560   TLS_DBG (1, "TCP connect for %u returned %u. New connection [%u]%x",
561            ho_ctx_index, err, vlib_get_thread_index (),
562            (ctx) ? ctx_handle : ~0);
563
564   ctx->tls_session_handle = session_handle (tls_session);
565   tls_session->opaque = ctx_handle;
566   tls_session->session_state = SESSION_STATE_READY;
567
568   /* Preallocate app session. Avoids allocating a session post handshake
569    * on tls_session rx and potentially invalidating the session pool */
570   app_session = session_alloc (ctx->c_thread_index);
571   app_session->session_state = SESSION_STATE_CREATED;
572   ctx->c_s_index = app_session->session_index;
573   st = session_type_from_proto_and_ip (TRANSPORT_PROTO_TLS, ctx->tcp_is_ip4);
574   app_session->session_type = st;
575   app_session->connection_index = ctx->tls_ctx_handle;
576
577   rv = tls_ctx_init_client (ctx);
578   if (rv)
579     {
580       session_free (app_session);
581       tls_ctx_free (ctx);
582     }
583
584   return rv;
585 }
586
587 int
588 dtls_session_connected_cb (u32 app_wrk_index, u32 ctx_handle, session_t *us,
589                            session_error_t err)
590 {
591   tls_ctx_t *ctx;
592
593   ctx = tls_ctx_get_w_thread (ctx_handle, transport_cl_thread ());
594
595   ctx->tls_session_handle = session_handle (us);
596   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
597   us->opaque = ctx_handle;
598
599   /* We don't preallocate the app session because the udp session might
600    * actually migrate to a different worker at the end of the handshake */
601
602   return tls_ctx_init_client (ctx);
603 }
604
605 int
606 tls_session_connected_callback (u32 tls_app_index, u32 ho_ctx_index,
607                                 session_t *tls_session, session_error_t err)
608 {
609   if (err)
610     {
611       app_worker_t *app_wrk;
612       tls_ctx_t *ho_ctx;
613       u32 api_context;
614
615       ho_ctx = tls_ctx_half_open_get (ho_ctx_index);
616       app_wrk = app_worker_get_if_valid (ho_ctx->parent_app_wrk_index);
617       if (app_wrk)
618         {
619           api_context = ho_ctx->parent_app_api_context;
620           app_worker_connect_notify (app_wrk, 0, err, api_context);
621         }
622
623       return 0;
624     }
625
626   if (session_get_transport_proto (tls_session) == TRANSPORT_PROTO_TCP)
627     return tls_session_connected_cb (tls_app_index, ho_ctx_index, tls_session,
628                                      err);
629   else
630     return dtls_session_connected_cb (tls_app_index, ho_ctx_index, tls_session,
631                                       err);
632 }
633
634 static void
635 tls_app_session_cleanup (session_t * s, session_cleanup_ntf_t ntf)
636 {
637   tls_ctx_t *ctx;
638
639   if (ntf == SESSION_CLEANUP_TRANSPORT)
640     {
641       /* Allow cleanup of tcp session */
642       if (s->session_state == SESSION_STATE_TRANSPORT_DELETED)
643         session_close (s);
644       return;
645     }
646
647   ctx = tls_ctx_get (s->opaque);
648   if (!ctx->no_app_session)
649     session_transport_delete_notify (&ctx->connection);
650   tls_ctx_free (ctx);
651 }
652
653 static void
654 dtls_migrate_ctx (void *arg)
655 {
656   tls_ctx_t *ctx = (tls_ctx_t *) arg;
657   u32 ctx_handle, thread_index;
658   session_t *us;
659
660   thread_index = session_thread_from_handle (ctx->tls_session_handle);
661   ASSERT (thread_index == vlib_get_thread_index ());
662
663   ctx_handle = tls_ctx_attach (ctx->tls_ctx_engine, thread_index, ctx);
664   ctx = tls_ctx_get_w_thread (ctx_handle, thread_index);
665   ctx->tls_ctx_handle = ctx_handle;
666
667   us = session_get_from_handle (ctx->tls_session_handle);
668   us->opaque = ctx_handle;
669   us->flags &= ~SESSION_F_IS_MIGRATING;
670
671   /* Probably the app detached while the session was migrating. Cleanup */
672   if (session_half_open_migrated_notify (&ctx->connection))
673     {
674       ctx->no_app_session = 1;
675       tls_disconnect (ctx->tls_ctx_handle, vlib_get_thread_index ());
676       return;
677     }
678
679   if (svm_fifo_max_dequeue (us->tx_fifo))
680     session_send_io_evt_to_thread (us->tx_fifo, SESSION_IO_EVT_TX);
681 }
682
683 static void
684 dtls_session_migrate_callback (session_t *us, session_handle_t new_sh)
685 {
686   u32 new_thread = session_thread_from_handle (new_sh);
687   tls_ctx_t *ctx, *cloned_ctx;
688
689   /* Migrate dtls context to new thread */
690   ctx = tls_ctx_get_w_thread (us->opaque, us->thread_index);
691   ctx->tls_session_handle = new_sh;
692   cloned_ctx = tls_ctx_detach (ctx);
693   ctx->is_migrated = 1;
694   session_half_open_migrate_notify (&ctx->connection);
695
696   session_send_rpc_evt_to_thread (new_thread, dtls_migrate_ctx,
697                                   (void *) cloned_ctx);
698
699   tls_ctx_free (ctx);
700 }
701
702 static session_cb_vft_t tls_app_cb_vft = {
703   .session_accept_callback = tls_session_accept_callback,
704   .session_disconnect_callback = tls_session_disconnect_callback,
705   .session_connected_callback = tls_session_connected_callback,
706   .session_reset_callback = tls_session_reset_callback,
707   .half_open_cleanup_callback = tls_session_cleanup_ho,
708   .add_segment_callback = tls_add_segment_callback,
709   .del_segment_callback = tls_del_segment_callback,
710   .builtin_app_rx_callback = tls_app_rx_callback,
711   .builtin_app_tx_callback = tls_app_tx_callback,
712   .session_migrate_callback = dtls_session_migrate_callback,
713   .session_cleanup_callback = tls_app_session_cleanup,
714 };
715
716 int
717 tls_connect (transport_endpoint_cfg_t * tep)
718 {
719   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
720   transport_endpt_crypto_cfg_t *ccfg;
721   crypto_engine_type_t engine_type;
722   session_endpoint_cfg_t *sep;
723   tls_main_t *tm = &tls_main;
724   app_worker_t *app_wrk;
725   application_t *app;
726   tls_ctx_t *ctx;
727   u32 ctx_index;
728   int rv;
729
730   sep = (session_endpoint_cfg_t *) tep;
731   if (!sep->ext_cfg)
732     return SESSION_E_NOEXTCFG;
733
734   app_wrk = app_worker_get (sep->app_wrk_index);
735   app = application_get (app_wrk->app_index);
736
737   ccfg = &sep->ext_cfg->crypto;
738   engine_type = tls_get_engine_type (ccfg->crypto_engine, app->tls_engine);
739   if (engine_type == CRYPTO_ENGINE_NONE)
740     {
741       clib_warning ("No tls engine_type available");
742       return SESSION_E_NOCRYPTOENG;
743     }
744
745   ctx_index = tls_ctx_half_open_alloc ();
746   ctx = tls_ctx_half_open_get (ctx_index);
747   ctx->parent_app_wrk_index = sep->app_wrk_index;
748   ctx->parent_app_api_context = sep->opaque;
749   ctx->tcp_is_ip4 = sep->is_ip4;
750   ctx->tls_type = sep->transport_proto;
751   ctx->ckpair_index = ccfg->ckpair_index;
752   ctx->c_proto = TRANSPORT_PROTO_TLS;
753   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
754   if (ccfg->hostname[0])
755     {
756       ctx->srv_hostname = format (0, "%s", ccfg->hostname);
757       vec_terminate_c_string (ctx->srv_hostname);
758     }
759
760   ctx->tls_ctx_engine = engine_type;
761
762   clib_memcpy_fast (&cargs->sep, sep, sizeof (session_endpoint_t));
763   cargs->sep.transport_proto = TRANSPORT_PROTO_TCP;
764   cargs->app_index = tm->app_index;
765   cargs->api_context = ctx_index;
766   cargs->sep_ext.ns_index = app->ns_index;
767   if ((rv = vnet_connect (cargs)))
768     return rv;
769
770   /* Track half-open tcp session in case we need to clean it up */
771   ctx->tls_session_handle = cargs->sh;
772
773   TLS_DBG (1, "New connect request %u engine %d", ctx_index, engine_type);
774   return ctx_index;
775 }
776
777 void
778 tls_disconnect (u32 ctx_handle, u32 thread_index)
779 {
780   tls_ctx_t *ctx;
781
782   TLS_DBG (1, "Disconnecting %x", ctx_handle);
783
784   ctx = tls_ctx_get (ctx_handle);
785   tls_ctx_app_close (ctx);
786 }
787
788 u32
789 tls_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep)
790 {
791   vnet_listen_args_t _bargs, *args = &_bargs;
792   transport_endpt_crypto_cfg_t *ccfg;
793   app_worker_t *app_wrk;
794   tls_main_t *tm = &tls_main;
795   session_handle_t tls_al_handle;
796   session_endpoint_cfg_t *sep;
797   session_t *tls_listener;
798   session_t *app_listener;
799   crypto_engine_type_t engine_type;
800   application_t *app;
801   app_listener_t *al;
802   tls_ctx_t *lctx;
803   u32 lctx_index;
804   int rv;
805
806   sep = (session_endpoint_cfg_t *) tep;
807   if (!sep->ext_cfg)
808     return SESSION_E_NOEXTCFG;
809
810   app_wrk = app_worker_get (sep->app_wrk_index);
811   app = application_get (app_wrk->app_index);
812
813   ccfg = &sep->ext_cfg->crypto;
814   engine_type = tls_get_engine_type (ccfg->crypto_engine, app->tls_engine);
815   if (engine_type == CRYPTO_ENGINE_NONE)
816     {
817       clib_warning ("No tls engine_type available");
818       return SESSION_E_NOCRYPTOENG;
819     }
820
821   clib_memset (args, 0, sizeof (*args));
822   args->app_index = tm->app_index;
823   args->sep_ext = *sep;
824   args->sep_ext.ns_index = app->ns_index;
825   args->sep_ext.transport_proto = TRANSPORT_PROTO_TCP;
826   if (sep->transport_proto == TRANSPORT_PROTO_DTLS)
827     {
828       args->sep_ext.transport_proto = TRANSPORT_PROTO_UDP;
829       args->sep_ext.transport_flags = TRANSPORT_CFG_F_CONNECTED;
830     }
831   if ((rv = vnet_listen (args)))
832     return rv;
833
834   lctx_index = tls_listener_ctx_alloc ();
835   tls_al_handle = args->handle;
836   al = app_listener_get_w_handle (tls_al_handle);
837   tls_listener = app_listener_get_session (al);
838   tls_listener->opaque = lctx_index;
839
840   app_listener = listen_session_get (app_listener_index);
841
842   lctx = tls_listener_ctx_get (lctx_index);
843   lctx->parent_app_wrk_index = sep->app_wrk_index;
844   lctx->tls_session_handle = tls_al_handle;
845   lctx->app_session_handle = listen_session_get_handle (app_listener);
846   lctx->tcp_is_ip4 = sep->is_ip4;
847   lctx->tls_ctx_engine = engine_type;
848   lctx->tls_type = sep->transport_proto;
849   lctx->ckpair_index = ccfg->ckpair_index;
850   lctx->c_s_index = app_listener_index;
851   lctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
852
853   if (tls_vfts[engine_type].ctx_start_listen (lctx))
854     {
855       vnet_unlisten_args_t a = {
856         .handle = lctx->tls_session_handle,
857         .app_index = tls_main.app_index,
858         .wrk_map_index = 0
859       };
860       if ((vnet_unlisten (&a)))
861         clib_warning ("unlisten returned");
862       tls_listener_ctx_free (lctx);
863       lctx_index = SESSION_INVALID_INDEX;
864     }
865
866   TLS_DBG (1, "Started listening %d, engine type %d", lctx_index,
867            engine_type);
868   return lctx_index;
869 }
870
871 u32
872 tls_stop_listen (u32 lctx_index)
873 {
874   session_endpoint_t sep = SESSION_ENDPOINT_NULL;
875   crypto_engine_type_t engine_type;
876   transport_connection_t *lc;
877   tls_ctx_t *lctx;
878   session_t *ls;
879   int rv;
880
881   lctx = tls_listener_ctx_get (lctx_index);
882
883   /* Cleanup listener from session lookup table */
884   ls = session_get_from_handle (lctx->tls_session_handle);
885   lc = session_get_transport (ls);
886
887   sep.fib_index = lc->fib_index;
888   sep.port = lc->lcl_port;
889   sep.is_ip4 = lc->is_ip4;
890   sep.transport_proto = lctx->tls_type;
891   clib_memcpy (&sep.ip, &lc->lcl_ip, sizeof (lc->lcl_ip));
892   session_lookup_del_session_endpoint2 (&sep);
893
894   vnet_unlisten_args_t a = {
895     .handle = lctx->tls_session_handle,
896     .app_index = tls_main.app_index,
897     .wrk_map_index = 0          /* default wrk */
898   };
899   if ((rv = vnet_unlisten (&a)))
900     clib_warning ("unlisten returned %d", rv);
901
902   engine_type = lctx->tls_ctx_engine;
903   tls_vfts[engine_type].ctx_stop_listen (lctx);
904
905   tls_listener_ctx_free (lctx);
906   return 0;
907 }
908
909 transport_connection_t *
910 tls_connection_get (u32 ctx_index, u32 thread_index)
911 {
912   tls_ctx_t *ctx;
913   ctx = tls_ctx_get_w_thread (ctx_index, thread_index);
914   return &ctx->connection;
915 }
916
917 transport_connection_t *
918 tls_listener_get (u32 listener_index)
919 {
920   tls_ctx_t *ctx;
921   ctx = tls_listener_ctx_get (listener_index);
922   return &ctx->connection;
923 }
924
925 static transport_connection_t *
926 tls_half_open_get (u32 ho_index)
927 {
928   tls_ctx_t *ctx;
929   ctx = tls_ctx_half_open_get (ho_index);
930   return &ctx->connection;
931 }
932
933 static void
934 tls_cleanup_ho (u32 ho_index)
935 {
936   tls_ctx_t *ctx;
937
938   ctx = tls_ctx_half_open_get (ho_index);
939   session_cleanup_half_open (ctx->tls_session_handle);
940   tls_ctx_half_open_free (ho_index);
941 }
942
943 int
944 tls_custom_tx_callback (void *session, transport_send_params_t * sp)
945 {
946   session_t *as = (session_t *) session;
947   tls_ctx_t *ctx;
948
949   if (PREDICT_FALSE (as->session_state >= SESSION_STATE_TRANSPORT_CLOSED ||
950                      as->session_state <= SESSION_STATE_ACCEPTING))
951     {
952       sp->flags |= TRANSPORT_SND_F_DESCHED;
953       return 0;
954     }
955
956   ctx = tls_ctx_get (as->connection_index);
957   return tls_ctx_write (ctx, as, sp);
958 }
959
960 u8 *
961 format_tls_ctx (u8 * s, va_list * args)
962 {
963   u32 tcp_si, tcp_ti, ctx_index, ctx_engine;
964   tls_ctx_t *ctx = va_arg (*args, tls_ctx_t *);
965   char *proto;
966
967   proto = ctx->tls_type == TRANSPORT_PROTO_TLS ? "TLS" : "DTLS";
968   session_parse_handle (ctx->tls_session_handle, &tcp_si, &tcp_ti);
969   tls_ctx_parse_handle (ctx->tls_ctx_handle, &ctx_index, &ctx_engine);
970   s =
971     format (s, "[%d:%d][%s] app_wrk %u index %u engine %u ts %d:%d",
972             ctx->c_thread_index, ctx->c_s_index, proto,
973             ctx->parent_app_wrk_index, ctx_index, ctx_engine, tcp_ti, tcp_si);
974
975   return s;
976 }
977
978 static u8 *
979 format_tls_listener_ctx (u8 * s, va_list * args)
980 {
981   session_t *tls_listener;
982   app_listener_t *al;
983   tls_ctx_t *ctx;
984   char *proto;
985
986   ctx = va_arg (*args, tls_ctx_t *);
987
988   proto = ctx->tls_type == TRANSPORT_PROTO_TLS ? "TLS" : "DTLS";
989   al = app_listener_get_w_handle (ctx->tls_session_handle);
990   tls_listener = app_listener_get_session (al);
991   s = format (s, "[%d:%d][%s] app_wrk %u engine %u ts %d:%d",
992               ctx->c_thread_index, ctx->c_s_index, proto,
993               ctx->parent_app_wrk_index, ctx->tls_ctx_engine,
994               tls_listener->thread_index, tls_listener->session_index);
995
996   return s;
997 }
998
999 static u8 *
1000 format_tls_ctx_state (u8 * s, va_list * args)
1001 {
1002   tls_ctx_t *ctx;
1003   session_t *ts;
1004
1005   ctx = va_arg (*args, tls_ctx_t *);
1006   ts = session_get (ctx->c_s_index, ctx->c_thread_index);
1007   if (ts->session_state == SESSION_STATE_LISTENING)
1008     s = format (s, "%s", "LISTEN");
1009   else
1010     {
1011       if (ts->session_state >= SESSION_STATE_TRANSPORT_CLOSED)
1012         s = format (s, "%s", "CLOSED");
1013       else if (ts->session_state == SESSION_STATE_APP_CLOSED)
1014         s = format (s, "%s", "APP-CLOSED");
1015       else if (ts->session_state >= SESSION_STATE_TRANSPORT_CLOSING)
1016         s = format (s, "%s", "CLOSING");
1017       else if (tls_ctx_handshake_is_over (ctx))
1018         s = format (s, "%s", "ESTABLISHED");
1019       else
1020         s = format (s, "%s", "HANDSHAKE");
1021     }
1022
1023   return s;
1024 }
1025
1026 u8 *
1027 format_tls_connection (u8 * s, va_list * args)
1028 {
1029   u32 ctx_index = va_arg (*args, u32);
1030   u32 thread_index = va_arg (*args, u32);
1031   u32 verbose = va_arg (*args, u32);
1032   tls_ctx_t *ctx;
1033
1034   ctx = tls_ctx_get_w_thread (ctx_index, thread_index);
1035   if (!ctx)
1036     return s;
1037
1038   s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_tls_ctx, ctx);
1039   if (verbose)
1040     {
1041       s = format (s, "%-" SESSION_CLI_STATE_LEN "U", format_tls_ctx_state,
1042                   ctx);
1043       if (verbose > 1)
1044         s = format (s, "\n");
1045     }
1046   return s;
1047 }
1048
1049 u8 *
1050 format_tls_listener (u8 * s, va_list * args)
1051 {
1052   u32 tc_index = va_arg (*args, u32);
1053   u32 __clib_unused thread_index = va_arg (*args, u32);
1054   u32 verbose = va_arg (*args, u32);
1055   tls_ctx_t *ctx = tls_listener_ctx_get (tc_index);
1056
1057   s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_tls_listener_ctx, ctx);
1058   if (verbose)
1059     s = format (s, "%-" SESSION_CLI_STATE_LEN "U", format_tls_ctx_state, ctx);
1060   return s;
1061 }
1062
1063 u8 *
1064 format_tls_half_open (u8 * s, va_list * args)
1065 {
1066   u32 ho_index = va_arg (*args, u32);
1067   u32 __clib_unused thread_index = va_arg (*args, u32);
1068   u32 __clib_unused verbose = va_arg (*args, u32);
1069   session_t *tcp_ho;
1070   tls_ctx_t *ho_ctx;
1071
1072   ho_ctx = tls_ctx_half_open_get (ho_index);
1073
1074   tcp_ho = session_get_from_handle (ho_ctx->tls_session_handle);
1075   s = format (s, "[%d:%d][%s] half-open app_wrk %u engine %u ts %d:%d",
1076               ho_ctx->c_thread_index, ho_ctx->c_s_index, "TLS",
1077               ho_ctx->parent_app_wrk_index, ho_ctx->tls_ctx_engine,
1078               tcp_ho->thread_index, tcp_ho->session_index);
1079
1080   return s;
1081 }
1082
1083 static void
1084 tls_transport_endpoint_get (u32 ctx_handle, u32 thread_index,
1085                             transport_endpoint_t * tep, u8 is_lcl)
1086 {
1087   tls_ctx_t *ctx = tls_ctx_get_w_thread (ctx_handle, thread_index);
1088   session_t *tcp_session;
1089
1090   tcp_session = session_get_from_handle (ctx->tls_session_handle);
1091   session_get_endpoint (tcp_session, tep, is_lcl);
1092 }
1093
1094 static void
1095 tls_transport_listener_endpoint_get (u32 ctx_handle,
1096                                      transport_endpoint_t * tep, u8 is_lcl)
1097 {
1098   session_t *tls_listener;
1099   app_listener_t *al;
1100   tls_ctx_t *ctx = tls_listener_ctx_get (ctx_handle);
1101
1102   al = app_listener_get_w_handle (ctx->tls_session_handle);
1103   tls_listener = app_listener_get_session (al);
1104   session_get_endpoint (tls_listener, tep, is_lcl);
1105 }
1106
1107 static clib_error_t *
1108 tls_enable (vlib_main_t * vm, u8 is_en)
1109 {
1110   vnet_app_detach_args_t _da, *da = &_da;
1111   vnet_app_attach_args_t _a, *a = &_a;
1112   u64 options[APP_OPTIONS_N_OPTIONS];
1113   tls_main_t *tm = &tls_main;
1114   u32 fifo_size = 512 << 10;
1115
1116   if (!is_en)
1117     {
1118       da->app_index = tm->app_index;
1119       da->api_client_index = APP_INVALID_INDEX;
1120       vnet_application_detach (da);
1121       return 0;
1122     }
1123
1124   fifo_size = tm->fifo_size ? tm->fifo_size : fifo_size;
1125
1126   clib_memset (a, 0, sizeof (*a));
1127   clib_memset (options, 0, sizeof (options));
1128
1129   a->session_cb_vft = &tls_app_cb_vft;
1130   a->api_client_index = APP_INVALID_INDEX;
1131   a->options = options;
1132   a->name = format (0, "tls");
1133   a->options[APP_OPTIONS_SEGMENT_SIZE] = tm->first_seg_size;
1134   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = tm->add_seg_size;
1135   a->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
1136   a->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
1137   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1138   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1139   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
1140
1141   if (vnet_application_attach (a))
1142     {
1143       clib_warning ("failed to attach tls app");
1144       return clib_error_return (0, "failed to attach tls app");
1145     }
1146
1147   tm->app_index = a->app_index;
1148   vec_free (a->name);
1149
1150   return 0;
1151 }
1152
1153 static const transport_proto_vft_t tls_proto = {
1154   .enable = tls_enable,
1155   .connect = tls_connect,
1156   .close = tls_disconnect,
1157   .start_listen = tls_start_listen,
1158   .stop_listen = tls_stop_listen,
1159   .get_connection = tls_connection_get,
1160   .get_listener = tls_listener_get,
1161   .get_half_open = tls_half_open_get,
1162   .cleanup_ho = tls_cleanup_ho,
1163   .custom_tx = tls_custom_tx_callback,
1164   .format_connection = format_tls_connection,
1165   .format_half_open = format_tls_half_open,
1166   .format_listener = format_tls_listener,
1167   .get_transport_endpoint = tls_transport_endpoint_get,
1168   .get_transport_listener_endpoint = tls_transport_listener_endpoint_get,
1169   .transport_options = {
1170     .name = "tls",
1171     .short_name = "J",
1172     .tx_type = TRANSPORT_TX_INTERNAL,
1173     .service_type = TRANSPORT_SERVICE_VC,
1174   },
1175 };
1176
1177 int
1178 dtls_connect (transport_endpoint_cfg_t *tep)
1179 {
1180   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
1181   transport_endpt_crypto_cfg_t *ccfg;
1182   crypto_engine_type_t engine_type;
1183   session_endpoint_cfg_t *sep;
1184   tls_main_t *tm = &tls_main;
1185   app_worker_t *app_wrk;
1186   application_t *app;
1187   tls_ctx_t *ctx;
1188   u32 ctx_handle;
1189   int rv;
1190
1191   sep = (session_endpoint_cfg_t *) tep;
1192   if (!sep->ext_cfg)
1193     return -1;
1194
1195   app_wrk = app_worker_get (sep->app_wrk_index);
1196   app = application_get (app_wrk->app_index);
1197
1198   ccfg = &sep->ext_cfg->crypto;
1199   engine_type = tls_get_engine_type (ccfg->crypto_engine, app->tls_engine);
1200   if (engine_type == CRYPTO_ENGINE_NONE)
1201     {
1202       clib_warning ("No tls engine_type available");
1203       return -1;
1204     }
1205
1206   ctx_handle = tls_ctx_alloc_w_thread (engine_type, transport_cl_thread ());
1207   ctx = tls_ctx_get_w_thread (ctx_handle, transport_cl_thread ());
1208   ctx->parent_app_wrk_index = sep->app_wrk_index;
1209   ctx->parent_app_api_context = sep->opaque;
1210   ctx->tcp_is_ip4 = sep->is_ip4;
1211   ctx->ckpair_index = ccfg->ckpair_index;
1212   ctx->tls_type = sep->transport_proto;
1213   ctx->tls_ctx_handle = ctx_handle;
1214   ctx->c_proto = TRANSPORT_PROTO_DTLS;
1215   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1216   if (ccfg->hostname[0])
1217     {
1218       ctx->srv_hostname = format (0, "%s", ccfg->hostname);
1219       vec_terminate_c_string (ctx->srv_hostname);
1220     }
1221
1222   ctx->tls_ctx_engine = engine_type;
1223
1224   clib_memcpy_fast (&cargs->sep, sep, sizeof (session_endpoint_t));
1225   cargs->sep.transport_proto = TRANSPORT_PROTO_UDP;
1226   cargs->app_index = tm->app_index;
1227   cargs->api_context = ctx_handle;
1228   cargs->sep_ext.ns_index = app->ns_index;
1229   cargs->sep_ext.transport_flags = TRANSPORT_CFG_F_CONNECTED;
1230   if ((rv = vnet_connect (cargs)))
1231     return rv;
1232
1233   TLS_DBG (1, "New DTLS connect request %x engine %d", ctx_handle,
1234            engine_type);
1235   return ctx_handle;
1236 }
1237
1238 static transport_connection_t *
1239 dtls_half_open_get (u32 ho_index)
1240 {
1241   tls_ctx_t *ho_ctx;
1242   ho_ctx = tls_ctx_get_w_thread (ho_index, transport_cl_thread ());
1243   return &ho_ctx->connection;
1244 }
1245
1246 static void
1247 dtls_cleanup_callback (u32 ctx_index, u32 thread_index)
1248 {
1249   /* No op */
1250 }
1251
1252 static void
1253 dtls_cleanup_ho (u32 ho_index)
1254 {
1255   tls_ctx_t *ctx;
1256   ctx = tls_ctx_get_w_thread (ho_index, transport_cl_thread ());
1257   tls_ctx_free (ctx);
1258 }
1259
1260 u8 *
1261 format_dtls_half_open (u8 *s, va_list *args)
1262 {
1263   u32 ho_index = va_arg (*args, u32);
1264   u32 __clib_unused thread_index = va_arg (*args, u32);
1265   tls_ctx_t *ho_ctx;
1266   session_t *us;
1267
1268   ho_ctx = tls_ctx_get_w_thread (ho_index, transport_cl_thread ());
1269
1270   us = session_get_from_handle (ho_ctx->tls_session_handle);
1271   s = format (s, "[%d:%d][%s] half-open app_wrk %u engine %u us %d:%d",
1272               ho_ctx->c_thread_index, ho_ctx->c_s_index, "DTLS",
1273               ho_ctx->parent_app_wrk_index, ho_ctx->tls_ctx_engine,
1274               us->thread_index, us->session_index);
1275
1276   return s;
1277 }
1278
1279 static const transport_proto_vft_t dtls_proto = {
1280   .enable = 0,
1281   .connect = dtls_connect,
1282   .close = tls_disconnect,
1283   .start_listen = tls_start_listen,
1284   .stop_listen = tls_stop_listen,
1285   .get_connection = tls_connection_get,
1286   .get_listener = tls_listener_get,
1287   .get_half_open = dtls_half_open_get,
1288   .custom_tx = tls_custom_tx_callback,
1289   .cleanup = dtls_cleanup_callback,
1290   .cleanup_ho = dtls_cleanup_ho,
1291   .format_connection = format_tls_connection,
1292   .format_half_open = format_dtls_half_open,
1293   .format_listener = format_tls_listener,
1294   .get_transport_endpoint = tls_transport_endpoint_get,
1295   .get_transport_listener_endpoint = tls_transport_listener_endpoint_get,
1296   .transport_options = {
1297     .name = "dtls",
1298     .short_name = "D",
1299     .tx_type = TRANSPORT_TX_INTERNAL,
1300     .service_type = TRANSPORT_SERVICE_VC,
1301   },
1302 };
1303
1304 void
1305 tls_register_engine (const tls_engine_vft_t * vft, crypto_engine_type_t type)
1306 {
1307   vec_validate (tls_vfts, type);
1308   tls_vfts[type] = *vft;
1309 }
1310
1311 static clib_error_t *
1312 tls_init (vlib_main_t * vm)
1313 {
1314   vlib_thread_main_t *vtm = vlib_get_thread_main ();
1315   tls_main_t *tm = &tls_main;
1316   u32 num_threads;
1317
1318   num_threads = 1 /* main thread */  + vtm->n_threads;
1319
1320   if (!tm->ca_cert_path)
1321     tm->ca_cert_path = TLS_CA_CERT_PATH;
1322
1323   vec_validate (tm->rx_bufs, num_threads - 1);
1324   vec_validate (tm->tx_bufs, num_threads - 1);
1325
1326   tm->first_seg_size = 32 << 20;
1327   tm->add_seg_size = 256 << 20;
1328
1329   transport_register_protocol (TRANSPORT_PROTO_TLS, &tls_proto,
1330                                FIB_PROTOCOL_IP4, ~0);
1331   transport_register_protocol (TRANSPORT_PROTO_TLS, &tls_proto,
1332                                FIB_PROTOCOL_IP6, ~0);
1333
1334   transport_register_protocol (TRANSPORT_PROTO_DTLS, &dtls_proto,
1335                                FIB_PROTOCOL_IP4, ~0);
1336   transport_register_protocol (TRANSPORT_PROTO_DTLS, &dtls_proto,
1337                                FIB_PROTOCOL_IP6, ~0);
1338   return 0;
1339 }
1340
1341 VLIB_INIT_FUNCTION (tls_init);
1342
1343 static clib_error_t *
1344 tls_config_fn (vlib_main_t * vm, unformat_input_t * input)
1345 {
1346   tls_main_t *tm = &tls_main;
1347   uword tmp;
1348   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1349     {
1350       if (unformat (input, "use-test-cert-in-ca"))
1351         tm->use_test_cert_in_ca = 1;
1352       else if (unformat (input, "ca-cert-path %s", &tm->ca_cert_path))
1353         ;
1354       else if (unformat (input, "first-segment-size %U", unformat_memory_size,
1355                          &tm->first_seg_size))
1356         ;
1357       else if (unformat (input, "add-segment-size %U", unformat_memory_size,
1358                          &tm->add_seg_size))
1359         ;
1360       else if (unformat (input, "fifo-size %U", unformat_memory_size, &tmp))
1361         {
1362           if (tmp >= 0x100000000ULL)
1363             {
1364               return clib_error_return
1365                 (0, "fifo-size %llu (0x%llx) too large", tmp, tmp);
1366             }
1367           tm->fifo_size = tmp;
1368         }
1369       else
1370         return clib_error_return (0, "unknown input `%U'",
1371                                   format_unformat_error, input);
1372     }
1373   return 0;
1374 }
1375
1376 VLIB_CONFIG_FUNCTION (tls_config_fn, "tls");
1377
1378 tls_main_t *
1379 vnet_tls_get_main (void)
1380 {
1381   return &tls_main;
1382 }
1383
1384 /*
1385  * fd.io coding-style-patch-verification: ON
1386  *
1387  * Local Variables:
1388  * eval: (c-set-style "gnu")
1389  * End:
1390  */