X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fquic%2Fquic.c;h=435113a8cd2a24fbaa6c021005c154bdfa741565;hb=26dd6de91b4d36ac04154c7eb6339684db6684a0;hp=8e29e74e9657e2542b939bd547da9d1ea99fc35b;hpb=bec771b879c2eae31ecef61891405c1570aae2b1;p=vpp.git diff --git a/src/plugins/quic/quic.c b/src/plugins/quic/quic.c index 8e29e74e965..435113a8cd2 100644 --- a/src/plugins/quic/quic.c +++ b/src/plugins/quic/quic.c @@ -30,6 +30,8 @@ #include #include +#include + static quic_main_t quic_main; static void quic_update_timer (quic_ctx_t * ctx); @@ -83,8 +85,8 @@ quic_format_err (u8 * s, va_list * args) case QUICLY_TRANSPORT_ERROR_FLOW_CONTROL: s = format (s, "QUICLY_TRANSPORT_ERROR_FLOW_CONTROL"); break; - case QUICLY_TRANSPORT_ERROR_STREAM_ID: - s = format (s, "QUICLY_TRANSPORT_ERROR_STREAM_ID"); + case QUICLY_TRANSPORT_ERROR_STREAM_LIMIT: + s = format (s, "QUICLY_TRANSPORT_ERROR_STREAM_LIMIT"); break; case QUICLY_TRANSPORT_ERROR_STREAM_STATE: s = format (s, "QUICLY_TRANSPORT_ERROR_STREAM_STATE"); @@ -410,42 +412,88 @@ quic_disconnect_transport (quic_ctx_t * ctx) } static void -quic_connection_closed (u32 ctx_index, u32 thread_index, u8 notify_transport) +quic_connection_delete (quic_ctx_t * ctx) { - QUIC_DBG (2, "QUIC connection closed"); tw_timer_wheel_1t_3w_1024sl_ov_t *tw; clib_bihash_kv_16_8_t kv; quicly_conn_t *conn; - quic_ctx_t *ctx; - ctx = quic_ctx_get (ctx_index, thread_index); + QUIC_DBG (2, "Deleting connection %u", ctx->c_c_index); + ASSERT (!quic_ctx_is_stream (ctx)); - /* TODO if connection is not established, just delete the session? */ /* Stop the timer */ if (ctx->timer_handle != QUIC_TIMER_HANDLE_INVALID) { - tw = &quic_main.wrk_ctx[thread_index].timer_wheel; + tw = &quic_main.wrk_ctx[ctx->c_thread_index].timer_wheel; tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle); } /* Delete the connection from the connection map */ conn = ctx->c_quic_ctx_id.conn; quic_make_connection_key (&kv, quicly_get_master_id (conn)); - QUIC_DBG (2, "Deleting conn with id %lu %lu", kv.key[0], kv.key[1]); + QUIC_DBG (2, "Deleting conn with id %lu %lu from map", kv.key[0], + kv.key[1]); clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 0 /* is_add */ ); quic_disconnect_transport (ctx); - if (notify_transport) - session_transport_closing_notify (&ctx->connection); - else - session_transport_delete_notify (&ctx->connection); - /* Do not try to send anything anymore */ - quicly_free (ctx->c_quic_ctx_id.conn); + + if (ctx->c_quic_ctx_id.conn) + quicly_free (ctx->c_quic_ctx_id.conn); ctx->c_quic_ctx_id.conn = NULL; + + session_transport_delete_notify (&ctx->connection); quic_ctx_free (ctx); } +/** + * Called when quicly return an error + * This function interacts tightly with quic_proto_on_close + */ +static void +quic_connection_closed (quic_ctx_t * ctx) +{ + QUIC_DBG (2, "QUIC connection %u/%u closed", ctx->c_thread_index, + ctx->c_c_index); + + /* TODO if connection is not established, just delete the session? */ + /* Actually should send connect or accept error */ + + switch (ctx->c_quic_ctx_id.conn_state) + { + case QUIC_CONN_STATE_READY: + /* Error on an opened connection (timeout...) + This puts the session in closing state, we should receive a notification + when the app has closed its session */ + session_transport_reset_notify (&ctx->connection); + /* This ensures we delete the connection when the app confirms the close */ + ctx->c_quic_ctx_id.conn_state = + QUIC_CONN_STATE_PASSIVE_CLOSING_QUIC_CLOSED; + break; + case QUIC_CONN_STATE_PASSIVE_CLOSING: + ctx->c_quic_ctx_id.conn_state = + QUIC_CONN_STATE_PASSIVE_CLOSING_QUIC_CLOSED; + /* quic_proto_on_close will eventually be called when the app confirms the close + , we delete the connection at that point */ + break; + case QUIC_CONN_STATE_PASSIVE_CLOSING_APP_CLOSED: + /* App already confirmed close, we can delete the connection */ + session_transport_delete_notify (&ctx->connection); + quic_connection_delete (ctx); + break; + case QUIC_CONN_STATE_PASSIVE_CLOSING_QUIC_CLOSED: + QUIC_DBG (0, "BUG"); + break; + case QUIC_CONN_STATE_ACTIVE_CLOSING: + session_transport_delete_notify (&ctx->connection); + quic_connection_delete (ctx); + break; + default: + QUIC_DBG (0, "BUG"); + break; + } +} + static int quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet) { @@ -542,8 +590,7 @@ quic_send_packets (quic_ctx_t * ctx) { clib_warning ("Tried to send packets on non existing app worker %u", ctx->parent_app_wrk_id); - quic_connection_closed (ctx->c_c_index, ctx->c_thread_index, - 1 /* notify_transport */ ); + quic_connection_delete (ctx); return 1; } app = application_get (app_wrk->app_index); @@ -585,8 +632,7 @@ quicly_error: if (err && err != QUICLY_ERROR_PACKET_IGNORED && err != QUICLY_ERROR_FREE_CONNECTION) clib_warning ("Quic error '%U'.", quic_format_err, err); - quic_connection_closed (ctx->c_c_index, ctx->c_thread_index, - 1 /* notify_transport */ ); + quic_connection_closed (ctx); return 1; } @@ -1306,8 +1352,8 @@ allocate_quicly_ctx (application_t * app, u8 is_client) quicly_ctx->event_log.cb = quicly_new_default_event_logger (stderr); quicly_ctx->transport_params.max_data = QUIC_INT_MAX; - quicly_ctx->transport_params.max_streams_uni = QUIC_INT_MAX; - quicly_ctx->transport_params.max_streams_bidi = QUIC_INT_MAX; + quicly_ctx->transport_params.max_streams_uni = (uint64_t) 1 << 60; + quicly_ctx->transport_params.max_streams_bidi = (uint64_t) 1 << 60; quicly_ctx->transport_params.max_stream_data.bidi_local = (QUIC_FIFO_SIZE - 1); /* max_enq is SIZE - 1 */ quicly_ctx->transport_params.max_stream_data.bidi_remote = (QUIC_FIFO_SIZE - 1); /* max_enq is SIZE - 1 */ quicly_ctx->transport_params.max_stream_data.uni = QUIC_INT_MAX; @@ -1332,10 +1378,10 @@ allocate_quicly_ctx (application_t * app, u8 is_client) *****************************************************************************/ static int -quic_connect_new_stream (session_endpoint_cfg_t * sep) +quic_connect_new_stream (session_t * quic_session, u32 opaque) { uint64_t quic_session_handle; - session_t *quic_session, *stream_session; + session_t *stream_session; quic_stream_data_t *stream_data; quicly_stream_t *stream; quicly_conn_t *conn; @@ -1345,12 +1391,11 @@ quic_connect_new_stream (session_endpoint_cfg_t * sep) int rv; /* Find base session to which the user want to attach a stream */ - quic_session_handle = sep->transport_opts; - QUIC_DBG (2, "Opening new stream (qsession %u)", sep->transport_opts); - quic_session = session_get_from_handle (quic_session_handle); + quic_session_handle = session_handle (quic_session); + QUIC_DBG (2, "Opening new stream (qsession %u)", quic_session_handle); - if (quic_session->session_type != - session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC, sep->is_ip4)) + if (session_type_transport_proto (quic_session->session_type) != + TRANSPORT_PROTO_QUIC) { QUIC_DBG (1, "received incompatible session"); return -1; @@ -1413,7 +1458,7 @@ quic_connect_new_stream (session_endpoint_cfg_t * sep) quicly_reset_stream (stream, QUIC_APP_ALLOCATION_ERROR); session_free_w_fifos (stream_session); quic_ctx_free (sctx); - return app_worker_connect_notify (app_wrk, NULL, sep->opaque); + return app_worker_connect_notify (app_wrk, NULL, opaque); } svm_fifo_add_want_deq_ntf (stream_session->rx_fifo, @@ -1421,7 +1466,7 @@ quic_connect_new_stream (session_endpoint_cfg_t * sep) SVM_FIFO_WANT_DEQ_NOTIF_IF_EMPTY); stream_session->session_state = SESSION_STATE_READY; - if (app_worker_connect_notify (app_wrk, stream_session, sep->opaque)) + if (app_worker_connect_notify (app_wrk, stream_session, opaque)) { QUIC_DBG (1, "failed to notify app"); quicly_reset_stream (stream, QUIC_APP_CONNECT_NOTIFY_ERROR); @@ -1492,9 +1537,12 @@ quic_connect (transport_endpoint_cfg_t * tep) { QUIC_DBG (2, "Called quic_connect"); session_endpoint_cfg_t *sep = (session_endpoint_cfg_t *) tep; + session_t *quic_session; sep = (session_endpoint_cfg_t *) tep; - if (sep->transport_opts) - return quic_connect_new_stream (sep); + + quic_session = session_get_from_handle_if_valid (sep->parent_handle); + if (quic_session) + return quic_connect_new_stream (quic_session, sep->opaque); else return quic_connect_new_connection (sep); } @@ -1516,17 +1564,30 @@ quic_proto_on_close (u32 ctx_index, u32 thread_index) quicly_reset_stream (stream, QUIC_APP_ERROR_CLOSE_NOTIFY); quic_send_packets (ctx); } - else if (ctx->c_quic_ctx_id.conn_state == QUIC_CONN_STATE_PASSIVE_CLOSING) - quic_connection_closed (ctx->c_c_index, ctx->c_thread_index, - 0 /* notify_transport */ ); - else + + switch (ctx->c_quic_ctx_id.conn_state) { + case QUIC_CONN_STATE_READY: + ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_ACTIVE_CLOSING; quicly_conn_t *conn = ctx->c_quic_ctx_id.conn; /* Start connection closing. Keep sending packets until quicly_send returns QUICLY_ERROR_FREE_CONNECTION */ quicly_close (conn, QUIC_APP_ERROR_CLOSE_NOTIFY, "Closed by peer"); /* This also causes all streams to be closed (and the cb called) */ quic_send_packets (ctx); + break; + case QUIC_CONN_STATE_PASSIVE_CLOSING: + ctx->c_quic_ctx_id.conn_state = + QUIC_CONN_STATE_PASSIVE_CLOSING_APP_CLOSED; + /* send_packets will eventually return an error, we delete the conn at + that point */ + break; + case QUIC_CONN_STATE_PASSIVE_CLOSING_QUIC_CLOSED: + quic_connection_delete (ctx); + break; + default: + QUIC_DBG (0, "BUG"); + break; } } @@ -1632,32 +1693,30 @@ format_quic_ctx (u8 * s, va_list * args) { quic_ctx_t *ctx = va_arg (*args, quic_ctx_t *); u32 verbose = va_arg (*args, u32); + u8 *str = 0; if (!ctx) return s; - s = format (s, "[#%d][Q] ", ctx->c_thread_index); + str = format (str, "[#%d][Q] ", ctx->c_thread_index); - if (!quic_ctx_is_listener (ctx)) - { - s = format (s, "%s Session: ", quic_ctx_is_stream (ctx) ? - "Stream" : "Quic"); - if (verbose) - s = format (s, "app %d wrk %d", ctx->parent_app_id, - ctx->parent_app_wrk_id); - } + if (quic_ctx_is_listener (ctx)) + str = format (str, "Listener, UDP %ld", ctx->udp_session_handle); + else if (quic_ctx_is_stream (ctx)) + str = format (str, "Stream %ld conn %d", + ctx->c_quic_ctx_id.stream->stream_id, + ctx->c_quic_ctx_id.quic_connection_ctx_id); + else /* connection */ + str = format (str, "Conn %d UDP %d", ctx->c_c_index, + ctx->udp_session_handle); + + str = format (str, " app %d wrk %d", ctx->parent_app_id, + ctx->parent_app_wrk_id); + + if (verbose == 1) + s = format (s, "%-50s%-15d", str, ctx->c_quic_ctx_id.conn_state); else - { - if (ctx->c_is_ip4) - s = format (s, "%U:%d->%U:%d", format_ip4_address, &ctx->c_lcl_ip4, - clib_net_to_host_u16 (ctx->c_lcl_port), - format_ip4_address, &ctx->c_rmt_ip4, - clib_net_to_host_u16 (ctx->c_rmt_port)); - else - s = format (s, "%U:%d->%U:%d", format_ip6_address, &ctx->c_lcl_ip6, - clib_net_to_host_u16 (ctx->c_lcl_port), - format_ip6_address, &ctx->c_rmt_ip6, - clib_net_to_host_u16 (ctx->c_rmt_port)); - } + s = format (s, "%s\n", str); + vec_free (str); return s; } @@ -1668,8 +1727,7 @@ format_quic_connection (u8 * s, va_list * args) u32 thread_index = va_arg (*args, u32); u32 verbose = va_arg (*args, u32); quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index); - if (ctx) - s = format (s, "%-50U", format_quic_ctx, ctx, verbose); + s = format (s, "%U", format_quic_ctx, ctx, verbose); return s; } @@ -1679,7 +1737,8 @@ format_quic_half_open (u8 * s, va_list * args) u32 qc_index = va_arg (*args, u32); u32 thread_index = va_arg (*args, u32); quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index); - s = format (s, "[QUIC] half-open app %u", ctx->parent_app_id); + s = + format (s, "[#%d][Q] half-open app %u", thread_index, ctx->parent_app_id); return s; } @@ -1691,11 +1750,7 @@ format_quic_listener (u8 * s, va_list * args) u32 thread_index = va_arg (*args, u32); u32 verbose = va_arg (*args, u32); quic_ctx_t *ctx = quic_ctx_get (tci, thread_index); - if (ctx) - { - ASSERT (quic_ctx_is_listener (ctx)); - s = format (s, "%-50U", format_quic_ctx, ctx, verbose); - } + s = format (s, "%U", format_quic_ctx, ctx, verbose); return s; } @@ -2045,7 +2100,7 @@ quic_custom_app_rx_callback (transport_connection_t * tc) } static int -quic_custom_tx_callback (void *s) +quic_custom_tx_callback (void *s, u32 max_burst_size) { session_t *stream_session = (session_t *) s; quicly_stream_t *stream; @@ -2545,7 +2600,40 @@ quic_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (quic_init); +static clib_error_t * +quic_plugin_crypto_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "vpp")) + { + quic_tlsctx.cipher_suites = vpp_crypto_cipher_suites; + return 0; + } + else if (unformat (input, "picotls")) + { + quic_tlsctx.cipher_suites = ptls_openssl_cipher_suites; + return 0; + } + else + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); + } + + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, input); +} + /* *INDENT-OFF* */ +VLIB_CLI_COMMAND(quic_plugin_crypto_command, static)= +{ + .path = "quic set crypto api", + .short_help = "quic set crypto api [picotls, vpp]", + .function = quic_plugin_crypto_command_fn, +}; + VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER,