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