#include <picotls/openssl.h>
#include <picotls/pembase64.h>
+#include <quic/quic_crypto.h>
+
static quic_main_t quic_main;
static void quic_update_timer (quic_ctx_t * ctx);
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");
}
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)
{
{
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);
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;
}
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;
*****************************************************************************/
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;
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;
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,
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);
{
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);
}
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;
}
}
{
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;
}
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;
}
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;
}
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;
}
}
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;
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,