tls: make tls engines pluggable
[vpp.git] / src / vnet / tls / tls.c
1 /*
2  * Copyright (c) 2018 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 DEFAULT_ENGINE 0
24 void tls_disconnect (u32 ctx_index, u32 thread_index);
25
26 int
27 tls_add_vpp_q_evt (svm_fifo_t * f, u8 evt_type)
28 {
29   session_fifo_event_t evt;
30   svm_queue_t *q;
31
32   if (svm_fifo_set_event (f))
33     {
34       evt.fifo = f;
35       evt.event_type = evt_type;
36
37       q = session_manager_get_vpp_event_queue (f->master_thread_index);
38       if (PREDICT_TRUE (q->cursize < q->maxsize))
39         {
40           svm_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
41         }
42       else
43         {
44           clib_warning ("vpp's evt q full");
45           return -1;
46         }
47     }
48   return 0;
49 }
50
51 static inline int
52 tls_add_app_q_evt (application_t * app, stream_session_t * app_session)
53 {
54   session_fifo_event_t evt;
55   svm_queue_t *q;
56
57   if (PREDICT_FALSE (app_session->session_state == SESSION_STATE_CLOSED))
58     {
59       /* Session is closed so app will never clean up. Flush rx fifo */
60       u32 to_dequeue = svm_fifo_max_dequeue (app_session->server_rx_fifo);
61       if (to_dequeue)
62         svm_fifo_dequeue_drop (app_session->server_rx_fifo, to_dequeue);
63       return 0;
64     }
65
66   if (app->cb_fns.builtin_app_rx_callback)
67     return app->cb_fns.builtin_app_rx_callback (app_session);
68
69   if (svm_fifo_set_event (app_session->server_rx_fifo))
70     {
71       evt.fifo = app_session->server_rx_fifo;
72       evt.event_type = FIFO_EVENT_APP_RX;
73       q = app->event_queue;
74
75       if (PREDICT_TRUE (q->cursize < q->maxsize))
76         {
77           svm_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
78         }
79       else
80         {
81           clib_warning ("app evt q full");
82           return -1;
83         }
84     }
85   return 0;
86 }
87
88 u32
89 tls_listener_ctx_alloc (void)
90 {
91   tls_main_t *tm = &tls_main;
92   tls_ctx_t *ctx;
93
94   pool_get (tm->listener_ctx_pool, ctx);
95   memset (ctx, 0, sizeof (*ctx));
96   return ctx - tm->listener_ctx_pool;
97 }
98
99 void
100 tls_listener_ctx_free (tls_ctx_t * ctx)
101 {
102   pool_put (tls_main.listener_ctx_pool, ctx);
103 }
104
105 tls_ctx_t *
106 tls_listener_ctx_get (u32 ctx_index)
107 {
108   return pool_elt_at_index (tls_main.listener_ctx_pool, ctx_index);
109 }
110
111 u32
112 tls_listener_ctx_index (tls_ctx_t * ctx)
113 {
114   return (ctx - tls_main.listener_ctx_pool);
115 }
116
117 u32
118 tls_ctx_half_open_alloc (void)
119 {
120   tls_main_t *tm = &tls_main;
121   u8 will_expand = 0;
122   tls_ctx_t *ctx;
123   u32 ctx_index;
124
125   pool_get_aligned_will_expand (tm->half_open_ctx_pool, will_expand, 0);
126   if (PREDICT_FALSE (will_expand && vlib_num_workers ()))
127     {
128       clib_rwlock_writer_lock (&tm->half_open_rwlock);
129       pool_get (tm->half_open_ctx_pool, ctx);
130       memset (ctx, 0, sizeof (*ctx));
131       ctx_index = ctx - tm->half_open_ctx_pool;
132       clib_rwlock_writer_unlock (&tm->half_open_rwlock);
133     }
134   else
135     {
136       pool_get (tm->half_open_ctx_pool, ctx);
137       memset (ctx, 0, sizeof (*ctx));
138       ctx_index = ctx - tm->half_open_ctx_pool;
139     }
140   return ctx_index;
141 }
142
143 void
144 tls_ctx_half_open_free (u32 ho_index)
145 {
146   tls_main_t *tm = &tls_main;
147   clib_rwlock_writer_lock (&tm->half_open_rwlock);
148   pool_put_index (tls_main.half_open_ctx_pool, ho_index);
149   clib_rwlock_writer_unlock (&tm->half_open_rwlock);
150 }
151
152 tls_ctx_t *
153 tls_ctx_half_open_get (u32 ctx_index)
154 {
155   tls_main_t *tm = &tls_main;
156   clib_rwlock_reader_lock (&tm->half_open_rwlock);
157   return pool_elt_at_index (tm->half_open_ctx_pool, ctx_index);
158 }
159
160 void
161 tls_ctx_half_open_reader_unlock ()
162 {
163   clib_rwlock_reader_unlock (&tls_main.half_open_rwlock);
164 }
165
166 u32
167 tls_ctx_half_open_index (tls_ctx_t * ctx)
168 {
169   return (ctx - tls_main.half_open_ctx_pool);
170 }
171
172 static int
173 tls_notify_app_accept (tls_ctx_t * ctx)
174 {
175   stream_session_t *app_listener, *app_session;
176   segment_manager_t *sm;
177   application_t *app;
178   tls_ctx_t *lctx;
179   int rv;
180
181   app = application_get (ctx->parent_app_index);
182   lctx = tls_listener_ctx_get (ctx->listener_ctx_index);
183   app_listener = listen_session_get_from_handle (lctx->app_session_handle);
184   sm = application_get_listen_segment_manager (app, app_listener);
185
186   app_session = session_alloc (vlib_get_thread_index ());
187   app_session->app_index = ctx->parent_app_index;
188   app_session->connection_index = ctx->tls_ctx_idx;
189   app_session->session_type = app_listener->session_type;
190   app_session->listener_index = app_listener->session_index;
191   if ((rv = session_alloc_fifos (sm, app_session)))
192     {
193       TLS_DBG (1, "failed to allocate fifos");
194       return rv;
195     }
196   ctx->c_s_index = app_session->session_index;
197   ctx->app_session_handle = session_handle (app_session);
198   return app->cb_fns.session_accept_callback (app_session);
199 }
200
201 static int
202 tls_notify_app_connected (tls_ctx_t * ctx, u8 is_failed)
203 {
204   int (*cb_fn) (u32, u32, stream_session_t *, u8);
205   stream_session_t *app_session;
206   segment_manager_t *sm;
207   application_t *app;
208
209   app = application_get (ctx->parent_app_index);
210   cb_fn = app->cb_fns.session_connected_callback;
211
212   if (is_failed)
213     goto failed;
214
215   sm = application_get_connect_segment_manager (app);
216   app_session = session_alloc (vlib_get_thread_index ());
217   app_session->app_index = ctx->parent_app_index;
218   app_session->connection_index = ctx->tls_ctx_idx;
219   app_session->session_type =
220     session_type_from_proto_and_ip (TRANSPORT_PROTO_TLS, ctx->tcp_is_ip4);
221   if (session_alloc_fifos (sm, app_session))
222     goto failed;
223
224   ctx->app_session_handle = session_handle (app_session);
225   ctx->c_s_index = app_session->session_index;
226   app_session->session_state = SESSION_STATE_READY;
227   if (cb_fn (ctx->parent_app_index, ctx->parent_app_api_context,
228              app_session, 0 /* not failed */ ))
229     {
230       TLS_DBG (1, "failed to notify app");
231       tls_disconnect (ctx->tls_ctx_idx, vlib_get_thread_index ());
232     }
233
234   return 0;
235
236 failed:
237   return cb_fn (ctx->parent_app_index, ctx->parent_app_api_context, 0,
238                 1 /* failed */ );
239 }
240
241 static inline u32
242 tls_ctx_alloc (void)
243 {
244   return tls_vfts[DEFAULT_ENGINE].ctx_alloc ();
245 }
246
247 static inline void
248 tls_ctx_free (tls_ctx_t * ctx)
249 {
250   vec_free (ctx->srv_hostname);
251   tls_vfts[DEFAULT_ENGINE].ctx_free (ctx);
252 }
253
254 static inline tls_ctx_t *
255 tls_ctx_get (u32 ctx_index)
256 {
257   return tls_vfts[DEFAULT_ENGINE].ctx_get (ctx_index);
258 }
259
260 static inline tls_ctx_t *
261 tls_ctx_get_w_thread (u32 ctx_index, u8 thread_index)
262 {
263   return tls_vfts[DEFAULT_ENGINE].ctx_get_w_thread (ctx_index, thread_index);
264 }
265
266 static inline int
267 tls_ctx_init_server (tls_ctx_t * ctx)
268 {
269   return tls_vfts[DEFAULT_ENGINE].ctx_init_server (ctx);
270 }
271
272 static inline int
273 tls_ctx_init_client (tls_ctx_t * ctx)
274 {
275   return tls_vfts[DEFAULT_ENGINE].ctx_init_client (ctx);
276 }
277
278 static inline int
279 tls_ctx_write (tls_ctx_t * ctx, u8 * buf, u32 len)
280 {
281   return tls_vfts[DEFAULT_ENGINE].ctx_write (ctx, buf, len);
282 }
283
284 static inline int
285 tls_ctx_read (tls_ctx_t * ctx, u8 * buf, u32 len)
286 {
287   return tls_vfts[DEFAULT_ENGINE].ctx_read (ctx, buf, len);
288 }
289
290 static inline u8
291 tls_ctx_handshake_is_over (tls_ctx_t * ctx)
292 {
293   return tls_vfts[DEFAULT_ENGINE].ctx_handshake_is_over (ctx);
294 }
295
296 static inline int
297 tls_handshake_rx (tls_ctx_t * ctx)
298 {
299   int rv;
300   rv = tls_vfts[DEFAULT_ENGINE].ctx_handshake_rx (ctx);
301
302   switch (rv)
303     {
304     case CLIENT_HANDSHAKE_OK:
305       tls_notify_app_connected (ctx, /* is failed */ 0);
306       break;
307     case CLIENT_HANDSHAKE_FAIL:
308       tls_disconnect (ctx->tls_ctx_idx, vlib_get_thread_index ());
309       tls_notify_app_connected (ctx, /* is failed */ 1);
310       break;
311     case SERVER_HANDSHAKE_OK:
312       tls_notify_app_accept (ctx);
313       break;
314     default:
315       return 0;
316     }
317   return 0;
318 }
319
320 void
321 tls_session_reset_callback (stream_session_t * s)
322 {
323   clib_warning ("called...");
324 }
325
326 int
327 tls_add_segment_callback (u32 client_index, const ssvm_private_t * fs)
328 {
329   /* No-op for builtin */
330   return 0;
331 }
332
333 int
334 tls_del_segment_callback (u32 client_index, const ssvm_private_t * fs)
335 {
336   return 0;
337 }
338
339 void
340 tls_session_disconnect_callback (stream_session_t * tls_session)
341 {
342   stream_session_t *app_session;
343   tls_ctx_t *ctx;
344   application_t *app;
345
346   ctx = tls_ctx_get (tls_session->opaque);
347   if (!tls_ctx_handshake_is_over (ctx))
348     {
349       stream_session_disconnect (tls_session);
350       return;
351     }
352   ctx->is_passive_close = 1;
353   app = application_get (ctx->parent_app_index);
354   app_session = session_get_from_handle (ctx->app_session_handle);
355   app->cb_fns.session_disconnect_callback (app_session);
356 }
357
358 int
359 tls_session_accept_callback (stream_session_t * tls_session)
360 {
361   stream_session_t *tls_listener;
362   tls_ctx_t *lctx, *ctx;
363   u32 ctx_index;
364
365   tls_listener = listen_session_get (tls_session->session_type,
366                                      tls_session->listener_index);
367   lctx = tls_listener_ctx_get (tls_listener->opaque);
368   ctx_index = tls_ctx_alloc ();
369   ctx = tls_ctx_get (ctx_index);
370   memcpy (ctx, lctx, sizeof (*lctx));
371   ctx->c_thread_index = vlib_get_thread_index ();
372   ctx->tls_ctx_idx = ctx_index;
373   tls_session->session_state = SESSION_STATE_READY;
374   tls_session->opaque = ctx_index;
375   ctx->tls_session_handle = session_handle (tls_session);
376   ctx->listener_ctx_index = tls_listener->opaque;
377
378   TLS_DBG (1, "Accept on listener %u new connection [%u]%u",
379            tls_listener->opaque, vlib_get_thread_index (), ctx_index);
380
381   return tls_ctx_init_server (ctx);
382 }
383
384 int
385 tls_app_tx_callback (stream_session_t * app_session)
386 {
387   stream_session_t *tls_session;
388   tls_ctx_t *ctx;
389   static u8 *tmp_buf;
390   u32 enq_max, deq_max, deq_now;
391   int wrote;
392
393   ctx = tls_ctx_get (app_session->connection_index);
394   if (!tls_ctx_handshake_is_over (ctx))
395     tls_add_vpp_q_evt (app_session->server_tx_fifo, FIFO_EVENT_APP_TX);
396
397   deq_max = svm_fifo_max_dequeue (app_session->server_tx_fifo);
398   if (!deq_max)
399     return 0;
400
401   tls_session = session_get_from_handle (ctx->tls_session_handle);
402   enq_max = svm_fifo_max_enqueue (tls_session->server_tx_fifo);
403   deq_now = clib_min (deq_max, TLS_CHUNK_SIZE);
404
405   if (PREDICT_FALSE (enq_max == 0))
406     {
407       tls_add_vpp_q_evt (app_session->server_tx_fifo, FIFO_EVENT_APP_TX);
408       return 0;
409     }
410
411   vec_validate (tmp_buf, deq_now);
412   svm_fifo_peek (app_session->server_tx_fifo, 0, deq_now, tmp_buf);
413   wrote = tls_ctx_write (ctx, tmp_buf, deq_now);
414   if (wrote <= 0)
415     {
416       tls_add_vpp_q_evt (app_session->server_tx_fifo, FIFO_EVENT_APP_TX);
417       return 0;
418     }
419
420   svm_fifo_dequeue_drop (app_session->server_tx_fifo, wrote);
421   vec_reset_length (tmp_buf);
422
423   tls_add_vpp_q_evt (tls_session->server_tx_fifo, FIFO_EVENT_APP_TX);
424
425   if (deq_now < deq_max)
426     tls_add_vpp_q_evt (app_session->server_tx_fifo, FIFO_EVENT_APP_TX);
427
428   return 0;
429 }
430
431 int
432 tls_app_rx_callback (stream_session_t * tls_session)
433 {
434   stream_session_t *app_session;
435   u32 deq_max, enq_max, enq_now;
436   application_t *app;
437   static u8 *tmp_buf;
438   tls_ctx_t *ctx;
439   int read, enq;
440
441   ctx = tls_ctx_get (tls_session->opaque);
442   if (!tls_ctx_handshake_is_over (ctx))
443     return tls_handshake_rx (ctx);
444
445   deq_max = svm_fifo_max_dequeue (tls_session->server_rx_fifo);
446   if (!deq_max)
447     return 0;
448
449   app_session = session_get_from_handle (ctx->app_session_handle);
450   enq_max = svm_fifo_max_enqueue (app_session->server_rx_fifo);
451   enq_now = clib_min (enq_max, TLS_CHUNK_SIZE);
452
453   if (PREDICT_FALSE (enq_now == 0))
454     {
455       tls_add_vpp_q_evt (tls_session->server_rx_fifo, FIFO_EVENT_BUILTIN_RX);
456       return 0;
457     }
458
459   vec_validate (tmp_buf, enq_now);
460   read = tls_ctx_read (ctx, tmp_buf, enq_now);
461   if (read <= 0)
462     {
463       tls_add_vpp_q_evt (tls_session->server_rx_fifo, FIFO_EVENT_BUILTIN_RX);
464       return 0;
465     }
466
467   enq = svm_fifo_enqueue_nowait (app_session->server_rx_fifo, read, tmp_buf);
468   ASSERT (enq == read);
469   vec_reset_length (tmp_buf);
470
471   if (svm_fifo_max_dequeue (tls_session->server_rx_fifo))
472     tls_add_vpp_q_evt (tls_session->server_rx_fifo, FIFO_EVENT_BUILTIN_RX);
473
474   app = application_get_if_valid (app_session->app_index);
475   return tls_add_app_q_evt (app, app_session);
476 }
477
478 int
479 tls_session_connected_callback (u32 tls_app_index, u32 ho_ctx_index,
480                                 stream_session_t * tls_session, u8 is_fail)
481 {
482   int (*cb_fn) (u32, u32, stream_session_t *, u8);
483   application_t *app;
484   tls_ctx_t *ho_ctx, *ctx;
485   u32 ctx_index;
486
487   ho_ctx = tls_ctx_half_open_get (ho_ctx_index);
488   app = application_get (ho_ctx->parent_app_index);
489   cb_fn = app->cb_fns.session_connected_callback;
490
491   if (is_fail)
492     {
493       tls_ctx_half_open_reader_unlock ();
494       tls_ctx_half_open_free (ho_ctx_index);
495       return cb_fn (ho_ctx->parent_app_index, ho_ctx->c_s_index, 0,
496                     1 /* failed */ );
497     }
498
499   ctx_index = tls_ctx_alloc ();
500   ctx = tls_ctx_get (ctx_index);
501   clib_memcpy (ctx, ho_ctx, sizeof (*ctx));
502   tls_ctx_half_open_reader_unlock ();
503   tls_ctx_half_open_free (ho_ctx_index);
504
505   ctx->c_thread_index = vlib_get_thread_index ();
506   ctx->tls_ctx_idx = ctx_index;
507
508   TLS_DBG (1, "TCP connect for %u returned %u. New connection [%u]%u",
509            ho_ctx_index, is_fail, vlib_get_thread_index (),
510            (ctx) ? ctx_index : ~0);
511
512   ctx->tls_session_handle = session_handle (tls_session);
513   tls_session->opaque = ctx_index;
514   tls_session->session_state = SESSION_STATE_READY;
515
516   return tls_ctx_init_client (ctx);
517 }
518
519 /* *INDENT-OFF* */
520 static session_cb_vft_t tls_app_cb_vft = {
521   .session_accept_callback = tls_session_accept_callback,
522   .session_disconnect_callback = tls_session_disconnect_callback,
523   .session_connected_callback = tls_session_connected_callback,
524   .session_reset_callback = tls_session_reset_callback,
525   .add_segment_callback = tls_add_segment_callback,
526   .del_segment_callback = tls_del_segment_callback,
527   .builtin_app_rx_callback = tls_app_rx_callback,
528   .builtin_app_tx_callback = tls_app_tx_callback,
529 };
530 /* *INDENT-ON* */
531
532 int
533 tls_connect (transport_endpoint_t * tep)
534 {
535   session_endpoint_extended_t *sep;
536   session_endpoint_t tls_sep;
537   tls_main_t *tm = &tls_main;
538   application_t *app;
539   tls_ctx_t *ctx;
540   u32 ctx_index;
541   int rv;
542
543   sep = (session_endpoint_extended_t *) tep;
544
545   ctx_index = tls_ctx_half_open_alloc ();
546   ctx = tls_ctx_half_open_get (ctx_index);
547   ctx->parent_app_index = sep->app_index;
548   ctx->parent_app_api_context = sep->opaque;
549   ctx->tcp_is_ip4 = sep->is_ip4;
550   if (sep->hostname)
551     {
552       ctx->srv_hostname = format (0, "%v", sep->hostname);
553       vec_terminate_c_string (ctx->srv_hostname);
554     }
555   tls_ctx_half_open_reader_unlock ();
556
557   app = application_get (sep->app_index);
558   application_alloc_connects_segment_manager (app);
559
560   clib_memcpy (&tls_sep, sep, sizeof (tls_sep));
561   tls_sep.transport_proto = TRANSPORT_PROTO_TCP;
562   if ((rv = application_connect (tm->app_index, ctx_index, &tls_sep)))
563     return rv;
564
565   TLS_DBG (1, "New connect request %u", ctx_index);
566   return 0;
567 }
568
569 void
570 tls_disconnect (u32 ctx_index, u32 thread_index)
571 {
572   stream_session_t *tls_session, *app_session;
573   tls_ctx_t *ctx;
574
575   TLS_DBG (1, "Disconnecting %u", ctx_index);
576
577   ctx = tls_ctx_get (ctx_index);
578   tls_session = session_get_from_handle (ctx->tls_session_handle);
579   stream_session_disconnect (tls_session);
580
581   app_session = session_get_from_handle_if_valid (ctx->app_session_handle);
582   if (app_session)
583     {
584       segment_manager_dealloc_fifos (app_session->svm_segment_index,
585                                      app_session->server_rx_fifo,
586                                      app_session->server_tx_fifo);
587       session_free (app_session);
588     }
589   tls_ctx_free (ctx);
590 }
591
592 u32
593 tls_start_listen (u32 app_listener_index, transport_endpoint_t * tep)
594 {
595   tls_main_t *tm = &tls_main;
596   application_t *tls_app;
597   session_handle_t tls_handle;
598   session_endpoint_extended_t *sep;
599   stream_session_t *tls_listener;
600   tls_ctx_t *lctx;
601   u32 lctx_index;
602   session_type_t st;
603   stream_session_t *app_listener;
604
605   sep = (session_endpoint_extended_t *) tep;
606   lctx_index = tls_listener_ctx_alloc ();
607   lctx = tls_listener_ctx_get (lctx_index);
608   st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
609   app_listener = listen_session_get (st, app_listener_index);
610
611   tls_app = application_get (tm->app_index);
612   sep->transport_proto = TRANSPORT_PROTO_TCP;
613   if (application_start_listen (tls_app, (session_endpoint_t *) sep,
614                                 &tls_handle))
615     return ~0;
616
617   tls_listener = listen_session_get_from_handle (tls_handle);
618   tls_listener->opaque = lctx_index;
619   lctx->parent_app_index = sep->app_index;
620   lctx->tls_session_handle = tls_handle;
621   lctx->app_session_handle = listen_session_get_handle (app_listener);
622   lctx->tcp_is_ip4 = sep->is_ip4;
623   return lctx_index;
624 }
625
626 u32
627 tls_stop_listen (u32 lctx_index)
628 {
629   tls_main_t *tm = &tls_main;
630   application_t *tls_app;
631   tls_ctx_t *lctx;
632   lctx = tls_listener_ctx_get (lctx_index);
633   tls_app = application_get (tm->app_index);
634   application_stop_listen (tls_app, lctx->tls_session_handle);
635   tls_listener_ctx_free (lctx);
636   return 0;
637 }
638
639 transport_connection_t *
640 tls_connection_get (u32 ctx_index, u32 thread_index)
641 {
642   tls_ctx_t *ctx;
643   ctx = tls_ctx_get_w_thread (ctx_index, thread_index);
644   return &ctx->connection;
645 }
646
647 transport_connection_t *
648 tls_listener_get (u32 listener_index)
649 {
650   tls_ctx_t *ctx;
651   ctx = tls_listener_ctx_get (listener_index);
652   return &ctx->connection;
653 }
654
655 u8 *
656 format_tls_ctx (u8 * s, va_list * args)
657 {
658   tls_ctx_t *ctx = va_arg (*args, tls_ctx_t *);
659   u32 thread_index = va_arg (*args, u32);
660   u32 child_si, child_ti;
661
662   session_parse_handle (ctx->tls_session_handle, &child_si, &child_ti);
663   if (thread_index != child_ti)
664     clib_warning ("app and tls sessions are on different threads!");
665
666   s = format (s, "[#%d][TLS] app %u child %u", child_ti,
667               ctx->parent_app_index, child_si);
668   return s;
669 }
670
671 u8 *
672 format_tls_connection (u8 * s, va_list * args)
673 {
674   u32 ctx_index = va_arg (*args, u32);
675   u32 thread_index = va_arg (*args, u32);
676   u32 verbose = va_arg (*args, u32);
677   tls_ctx_t *ctx;
678
679   ctx = tls_ctx_get_w_thread (ctx_index, thread_index);
680   if (!ctx)
681     return s;
682
683   s = format (s, "%-50U", format_tls_ctx, ctx, thread_index);
684   if (verbose)
685     {
686       s = format (s, "%-15s", "state");
687       if (verbose > 1)
688         s = format (s, "\n");
689     }
690   return s;
691 }
692
693 u8 *
694 format_tls_listener (u8 * s, va_list * args)
695 {
696   u32 tc_index = va_arg (*args, u32);
697   tls_ctx_t *ctx = tls_listener_ctx_get (tc_index);
698   u32 listener_index, type;
699
700   listen_session_parse_handle (ctx->tls_session_handle, &type,
701                                &listener_index);
702   return format (s, "[TLS] listener app %u child %u", ctx->parent_app_index,
703                  listener_index);
704 }
705
706 u8 *
707 format_tls_half_open (u8 * s, va_list * args)
708 {
709   u32 tc_index = va_arg (*args, u32);
710   tls_ctx_t *ctx = tls_ctx_half_open_get (tc_index);
711   s = format (s, "[TLS] half-open app %u", ctx->parent_app_index);
712   tls_ctx_half_open_reader_unlock ();
713   return s;
714 }
715
716 /* *INDENT-OFF* */
717 const static transport_proto_vft_t tls_proto = {
718   .open = tls_connect,
719   .close = tls_disconnect,
720   .bind = tls_start_listen,
721   .get_connection = tls_connection_get,
722   .get_listener = tls_listener_get,
723   .unbind = tls_stop_listen,
724   .tx_type = TRANSPORT_TX_INTERNAL,
725   .service_type = TRANSPORT_SERVICE_APP,
726   .format_connection = format_tls_connection,
727   .format_half_open = format_tls_half_open,
728   .format_listener = format_tls_listener,
729 };
730 /* *INDENT-ON* */
731
732 void
733 tls_register_engine (const tls_engine_vft_t * vft, tls_engine_type_t type)
734 {
735   vec_validate (tls_vfts, type);
736   tls_vfts[type] = *vft;
737 }
738
739 clib_error_t *
740 tls_init (vlib_main_t * vm)
741 {
742   vnet_app_attach_args_t _a, *a = &_a;
743   u64 options[APP_OPTIONS_N_OPTIONS];
744   u32 segment_size = 512 << 20;
745   tls_main_t *tm = &tls_main;
746   u32 fifo_size = 64 << 10;
747
748   memset (a, 0, sizeof (*a));
749   memset (options, 0, sizeof (options));
750
751   a->session_cb_vft = &tls_app_cb_vft;
752   a->api_client_index = (1 << 24) + 1;
753   a->options = options;
754   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
755   a->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
756   a->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
757   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
758   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
759
760   if (vnet_application_attach (a))
761     {
762       clib_warning ("failed to attach tls app");
763       return clib_error_return (0, "failed to attach tls app");
764     }
765
766   if (!tm->ca_cert_path)
767     tm->ca_cert_path = TLS_CA_CERT_PATH;
768
769   tm->app_index = a->app_index;
770   clib_rwlock_init (&tm->half_open_rwlock);
771
772   transport_register_protocol (TRANSPORT_PROTO_TLS, &tls_proto,
773                                FIB_PROTOCOL_IP4, ~0);
774   transport_register_protocol (TRANSPORT_PROTO_TLS, &tls_proto,
775                                FIB_PROTOCOL_IP6, ~0);
776
777   return 0;
778 }
779
780 VLIB_INIT_FUNCTION (tls_init);
781
782 static clib_error_t *
783 tls_config_fn (vlib_main_t * vm, unformat_input_t * input)
784 {
785   tls_main_t *tm = &tls_main;
786   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
787     {
788       if (unformat (input, "use-test-cert-in-ca"))
789         tm->use_test_cert_in_ca = 1;
790       else if (unformat (input, "ca-cert-path %s", &tm->ca_cert_path))
791         ;
792       else
793         return clib_error_return (0, "unknown input `%U'",
794                                   format_unformat_error, input);
795     }
796   return 0;
797 }
798
799 VLIB_EARLY_CONFIG_FUNCTION (tls_config_fn, "tls");
800
801 tls_main_t *
802 vnet_tls_get_main (void)
803 {
804   return &tls_main;
805 }
806
807 /*
808  * fd.io coding-style-patch-verification: ON
809  *
810  * Local Variables:
811  * eval: (c-set-style "gnu")
812  * End:
813  */