From: Dave Wallace Date: Sat, 27 Sep 2025 02:22:00 +0000 (-0400) Subject: quic: fix quicly plugin to use vpp crypto engine. X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F82%2F43782%2F12;p=vpp.git quic: fix quicly plugin to use vpp crypto engine. - Make picotls the default crypto engine - Improve debug output - Fix vpp native crypto engine issues introduced during quic engine api & quic_quicly plugin development - Convert c++ style comments to c-style - Refactor 'quic set crypto api' command to remove quicly engine specific terminology and make it work properly. Type: fix Change-Id: I6b60b7b51e8b666fc075373d432b1031b8e5d9e3 Signed-off-by: Dave Wallace --- diff --git a/src/plugins/quic/quic.c b/src/plugins/quic/quic.c index 0ad0389aeb1..f0f66fd0951 100644 --- a/src/plugins/quic/quic.c +++ b/src/plugins/quic/quic.c @@ -179,7 +179,8 @@ quic_connect_stream (session_t * quic_session, session_endpoint_cfg_t * sep) /* Find base session to which the user want to attach a stream */ quic_session_handle = session_handle (quic_session); - QUIC_DBG (2, "Opening new stream (qsession %u)", quic_session_handle); + QUIC_DBG (2, "Connect stream: quic_session_handle 0x%lx", + quic_session_handle); if (session_type_transport_proto (quic_session->session_type) != TRANSPORT_PROTO_QUIC) @@ -221,10 +222,10 @@ quic_connect_stream (session_t * quic_session, session_endpoint_cfg_t * sep) rv = quic_eng_connect_stream (conn, &stream, &stream_data, is_unidir); if (rv) { - QUIC_DBG (2, - "quic_eng_connect_stream (c=0x%lx, s=0x%lx, sd=0x%lx, u=%d) " - "failed (rv=%d)", - conn, &stream, &stream_data, is_unidir, rv); + QUIC_DBG (1, + "Connect stream: failed %d, conn %p, stream %p, stream_data " + "%p, unidir %d", + rv, conn, &stream, &stream_data, is_unidir); return -1; } quic_increment_counter (qm, QUIC_ERROR_OPENED_STREAM, 1); @@ -233,8 +234,9 @@ quic_connect_stream (session_t * quic_session, session_endpoint_cfg_t * sep) sctx->crypto_context_index = qctx->crypto_context_index; stream_session = session_alloc (qctx->c_thread_index); - QUIC_DBG (2, "Allocated stream_session 0x%lx ctx %u", - session_handle (stream_session), sctx_index); + QUIC_DBG ( + 2, "Connect stream: stream_session handle 0x%lx, sctx_index %u, thread %u", + session_handle (stream_session), sctx_index, qctx->c_thread_index); stream_session->app_wrk_index = app_wrk->wrk_index; stream_session->connection_index = sctx_index; stream_session->listener_handle = quic_session_handle; @@ -254,7 +256,7 @@ quic_connect_stream (session_t * quic_session, session_endpoint_cfg_t * sep) /* For now we only reset streams. Cleanup will be triggered by timers */ if ((rv = app_worker_init_connected (app_wrk, stream_session))) { - QUIC_ERR ("failed to app_worker_init_connected"); + QUIC_ERR ("Connect stream: failed app_worker_init_connected %d", rv); quic_eng_connect_stream_error_reset (stream); return app_worker_connect_notify (app_wrk, NULL, rv, sep->opaque); } @@ -268,7 +270,7 @@ quic_connect_stream (session_t * quic_session, session_endpoint_cfg_t * sep) if (app_worker_connect_notify (app_wrk, stream_session, SESSION_E_NONE, sep->opaque)) { - QUIC_ERR ("failed to notify app"); + QUIC_ERR ("Connect stream: failed to notify app"); quic_increment_counter (qm, QUIC_ERROR_CLOSED_STREAM, 1); quic_eng_connect_stream_error_reset (stream); return -1; @@ -578,7 +580,7 @@ quic_udp_session_connected_callback (u32 quic_app_index, u32 ctx_index, clib_thread_index_t thread_index; int ret; - QUIC_DBG (2, "UDP Session connect callback: session_index %u, thread %u", + QUIC_DBG (2, "UDP Session connected: session_index %u, thread %u", udp_session->session_index, udp_session->thread_index); /* Allocate session on whatever thread udp used, i.e., probably first @@ -601,8 +603,8 @@ quic_udp_session_connected_callback (u32 quic_app_index, u32 ctx_index, return 0; } - QUIC_DBG (2, "New ctx [thread=0x%x] ctx_index=0x%x", thread_index, - (ctx) ? ctx_index : ~0); + QUIC_DBG (2, "UDP Session connected: quic ctx_index %u, thread %u", + (ctx) ? ctx_index : ~0, thread_index); ctx->udp_session_handle = session_handle (udp_session); udp_session->opaque = ctx_index; @@ -749,17 +751,16 @@ quic_custom_tx_callback (void *s, transport_send_params_t * sp) stream_session->thread_index); if (PREDICT_FALSE (!quic_ctx_is_stream (ctx))) { + QUIC_DBG (1, "NOT a stream: ctx_index %u, thread %u", + stream_session->connection_index, + stream_session->thread_index); goto tx_end; /* Most probably a reschedule */ } QUIC_DBG (3, "Stream TX event"); quic_eng_ack_rx_data (stream_session); - if (PREDICT_FALSE (!quic_eng_stream_tx (ctx, stream_session))) - { - QUIC_DBG (3, "quic_eng_stream_tx(ctx=0x%lx) failed!", ctx); - return 0; - } + return 0; tx_end: return quic_eng_send_packets (ctx); @@ -852,11 +853,11 @@ static clib_error_t * quic_enable (vlib_main_t *vm, u8 is_en) { quic_main_t *qm = &quic_main; - quic_worker_ctx_t *wrk_ctx; + quic_worker_ctx_t *qwc; quic_ctx_t *ctx; crypto_context_t *crctx; vlib_thread_main_t *vtm = vlib_get_thread_main (); - int i; + u64 i; qm->engine_type = quic_get_engine_type (QUIC_ENGINE_QUICLY, QUIC_ENGINE_OPENSSL); @@ -886,14 +887,14 @@ quic_enable (vlib_main_t *vm, u8 is_en) for (i = 0; i < qm->num_threads; i++) { - wrk_ctx = quic_wrk_ctx_get (qm, i); - pool_get_aligned_safe (wrk_ctx->crypto_ctx_pool, crctx, + qwc = quic_wrk_ctx_get (qm, i); + pool_get_aligned_safe (qwc->crypto_ctx_pool, crctx, CLIB_CACHE_LINE_BYTES); - pool_program_safe_realloc ((void **) &wrk_ctx->crypto_ctx_pool, + pool_program_safe_realloc ((void **) &qwc->crypto_ctx_pool, QUIC_CRYPTO_CTX_POOL_PER_THREAD_SIZE, CLIB_CACHE_LINE_BYTES); - pool_get_aligned_safe (wrk_ctx->ctx_pool, ctx, CLIB_CACHE_LINE_BYTES); - pool_program_safe_realloc ((void **) &wrk_ctx->ctx_pool, + pool_get_aligned_safe (qwc->ctx_pool, ctx, CLIB_CACHE_LINE_BYTES); + pool_program_safe_realloc ((void **) &qwc->ctx_pool, QUIC_CTX_POOL_PER_THREAD_SIZE, CLIB_CACHE_LINE_BYTES); } @@ -929,7 +930,7 @@ quic_init (vlib_main_t * vm) quic_main_t *qm = &quic_main; vnet_app_attach_args_t _a, *a = &_a; u64 options[APP_OPTIONS_N_OPTIONS]; - // TODO: Don't use hard-coded values for segment_size and seed[] + /* TODO: Don't use hard-coded values for segment_size and seed[] */ u32 segment_size = 256 << 20; u8 seed[32]; @@ -987,9 +988,33 @@ quic_plugin_crypto_command_fn (vlib_main_t *vm, unformat_input_t *input, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "vpp")) - qm->default_crypto_engine = CRYPTO_ENGINE_VPP; - else if (unformat (line_input, "picotls")) - qm->default_crypto_engine = CRYPTO_ENGINE_PICOTLS; + { + qm->default_crypto_engine = CRYPTO_ENGINE_VPP; + qm->vnet_crypto_init = 0; + } + else if (unformat (line_input, "engine-lib")) + { + qm->default_crypto_engine = + (qm->engine_type == QUIC_ENGINE_QUICLY) ? + CRYPTO_ENGINE_PICOTLS : + ((qm->engine_type == QUIC_ENGINE_OPENSSL) ? + CRYPTO_ENGINE_OPENSSL : + CRYPTO_ENGINE_NONE); + if (qm->default_crypto_engine != CRYPTO_ENGINE_NONE) + { + qm->vnet_crypto_init = 0; + } + else + { + e = clib_error_return (0, + "No quic engine available, using default " + "crypto engine '%U' (%u)", + format_crypto_engine, + qm->default_crypto_engine, + qm->default_crypto_engine); + goto done; + } + } else { e = clib_error_return (0, "unknown input '%U'", @@ -1201,7 +1226,13 @@ quic_show_connections_command_fn (vlib_main_t *vm, unformat_input_t *input, return 0; } - vlib_cli_output (vm, "engine: %s", quic_engine_type_str (qm->engine_type)); + vlib_cli_output (vm, "quic engine: %s", + quic_engine_type_str (qm->engine_type)); + vlib_cli_output ( + vm, "crypto engine: %s", + qm->default_crypto_engine == CRYPTO_ENGINE_PICOTLS ? + "picotls" : + (qm->default_crypto_engine == CRYPTO_ENGINE_VPP ? "vpp" : "none")); if (!unformat_user (input, unformat_line_input, line_input)) { quic_show_aggregated_stats (vm); @@ -1242,9 +1273,13 @@ done: return error; } +/* TODO: This command should not be engine specific. + * Current implementation is for quicly engine! + * Fix quicly specific syntax (e.g. picotls) to be generic. + */ VLIB_CLI_COMMAND (quic_plugin_crypto_command, static) = { .path = "quic set crypto api", - .short_help = "quic set crypto api [picotls|vpp]", + .short_help = "quic set crypto api [engine-lib|vpp]", .function = quic_plugin_crypto_command_fn, }; VLIB_CLI_COMMAND(quic_plugin_set_fifo_size_command, static)= @@ -1277,8 +1312,8 @@ VLIB_CLI_COMMAND (quic_set_cc, static) = { .function = quic_set_cc_fn, }; VLIB_PLUGIN_REGISTER () = { - .version = VPP_BUILD_VER, .description = "Quic transport protocol", - // .default_disabled = 1, + .version = VPP_BUILD_VER, + .description = "Quic transport protocol", }; static clib_error_t * @@ -1313,7 +1348,7 @@ quic_config_fn (vlib_main_t * vm, unformat_input_t * input) qm->connection_timeout = i; else if (unformat (line_input, "fifo-prealloc %u", &i)) qm->udp_fifo_prealloc = i; - // TODO: add cli selection of quic_eng_ + /* TODO: add cli selection of quic_eng_ */ else { error = clib_error_return (0, "unknown input '%U'", diff --git a/src/plugins/quic/quic.h b/src/plugins/quic/quic.h index 5f17a9b8f29..b98310d100b 100644 --- a/src/plugins/quic/quic.h +++ b/src/plugins/quic/quic.h @@ -84,13 +84,13 @@ quic_engine_type_str (quic_engine_type_t engine_type) switch (engine_type) { case QUIC_ENGINE_NONE: - return ("QUIC_ENGINE_NONE"); + return ("none"); case QUIC_ENGINE_QUICLY: - return ("QUIC_ENGINE_QUICLY"); + return ("quicly"); case QUIC_ENGINE_OPENSSL: - return ("QUIC_ENGINE_OPENSSL"); + return ("openssl"); default: - return ("UNKNOWN"); + return ("unknown"); } } extern vlib_node_registration_t quic_input_node; @@ -224,7 +224,7 @@ typedef struct quic_rx_packet_ctx_ #define _(type, name) type name; foreach_quic_rx_pkt_ctx_field #undef _ - u8 padding[1024 * 128]; // FIXME: remove hardcoded size + u8 padding[1024 * 128]; /* FIXME: remove hardcoded size */ } quic_rx_packet_ctx_t; typedef struct quic_worker_ctx_ @@ -241,7 +241,7 @@ typedef struct quic_main_ vlib_node_registration_t *quic_input_node; u32 app_index; quic_worker_ctx_t *wrk_ctx; - + u8 vnet_crypto_init; u8 default_crypto_engine; /**< Used if you do connect with CRYPTO_ENGINE_NONE (0) */ u64 max_packets_per_key; /**< number of packets that can be sent without a @@ -359,7 +359,8 @@ typedef enum quic_session_connected_ QUIC_SESSION_CONNECTED_SERVER, } quic_session_connected_t; -// TODO: Define appropriate QUIC return values for quic_engine_vft functions! +/* TODO: Define appropriate QUIC return values for quic_engine_vft functions! + */ typedef struct quic_engine_vft_ { void (*engine_init) (quic_main_t *qm); @@ -375,7 +376,7 @@ typedef struct quic_engine_vft_ void (*connection_get_stats) (void *conn, quic_stats_t *conn_stats); int (*udp_session_rx_packets) (session_t *udp_session); void (*ack_rx_data) (session_t *stream_session); - int (*stream_tx) (quic_ctx_t *ctx, session_t *stream_session); + u64 (*stream_tx) (quic_ctx_t *ctx, session_t *stream_session); int (*send_packets) (quic_ctx_t *ctx); u8 *(*format_connection_stats) (u8 *s, va_list *args); u8 *(*format_stream_connection) (u8 *s, va_list *args); diff --git a/src/plugins/quic_quicly/quic_quicly.c b/src/plugins/quic_quicly/quic_quicly.c index 3c076ae2e70..f77d86396e8 100644 --- a/src/plugins/quic_quicly/quic_quicly.c +++ b/src/plugins/quic_quicly/quic_quicly.c @@ -223,21 +223,18 @@ quic_quicly_addr_to_ip46_addr (quicly_address_t *quicly_addr, static int quic_quicly_send_packets (quic_ctx_t *ctx) { - // TODO: GET THIS IOVEC OFF OF THE STACK!!! - struct iovec - packets[QUIC_SEND_PACKET_VEC_SIZE]; // TODO: GET THIS OFF OF THE STACK - - uint8_t buf[QUIC_SEND_PACKET_VEC_SIZE * - quic_quicly_get_quicly_ctx_from_ctx (ctx) - ->transport_params.max_udp_payload_size]; // TODO: GET THIS OFF - // OF THE STACK + /* TODO: GET packetsp[], buf[], next_timeout OFF OF THE STACK!!! */ + struct iovec packets[QUIC_SEND_PACKET_VEC_SIZE]; + uint64_t max_udp_payload_size = quic_quicly_get_quicly_ctx_from_ctx (ctx) + ->transport_params.max_udp_payload_size; + uint8_t buf[QUIC_SEND_PACKET_VEC_SIZE * max_udp_payload_size]; session_t *udp_session; quicly_conn_t *conn; size_t num_packets, i, max_packets; u32 n_sent = 0; int err = 0; quicly_address_t quicly_rmt_ip, quicly_lcl_ip; - int64_t next_timeout; // TODO: GET THIS OFF OF THE STACK + int64_t next_timeout; /* We have sctx, get qctx */ if (quic_ctx_is_stream (ctx)) @@ -270,6 +267,8 @@ quic_quicly_send_packets (quic_ctx_t *ctx) } num_packets = max_packets; + QUIC_DBG (3, "num_packets %u, packets %p, buf %p, buf_size %u", + num_packets, packets, buf, sizeof (buf)); if ((err = quicly_send (conn, &quicly_rmt_ip, &quicly_lcl_ip, packets, &num_packets, buf, sizeof (buf)))) { @@ -618,7 +617,7 @@ quic_quicly_update_conn_ctx (quicly_conn_t *conn, static void quic_quicly_connection_migrate (quic_ctx_t *ctx) { - u32 new_ctx_id, thread_index = vlib_get_thread_index (); + u32 new_ctx_index, thread_index = vlib_get_thread_index (); quic_ctx_t *new_ctx; clib_bihash_kv_16_8_t kv; quicly_conn_t *conn; @@ -626,16 +625,18 @@ quic_quicly_connection_migrate (quic_ctx_t *ctx) session_t *udp_session; int64_t next_timeout; - new_ctx_id = quic_ctx_alloc (quic_quicly_main.qm, thread_index); - new_ctx = quic_quicly_get_quic_ctx (new_ctx_id, thread_index); + new_ctx_index = quic_ctx_alloc (quic_quicly_main.qm, thread_index); + new_ctx = quic_quicly_get_quic_ctx (new_ctx_index, thread_index); - QUIC_DBG (2, "Received conn %u (now %u)", ctx->c_thread_index, new_ctx_id); + QUIC_DBG ( + 2, "Migrate conn (ctx_index %u, thread %u) to new_ctx_index %u, thread %u", + ctx->c_c_index, ctx->c_thread_index, new_ctx_index, thread_index); clib_memcpy (new_ctx, ctx, sizeof (quic_ctx_t)); clib_mem_free (ctx); new_ctx->c_thread_index = thread_index; - new_ctx->c_c_index = new_ctx_id; + new_ctx->c_c_index = new_ctx_index; quic_quicly_crypto_context_acquire (new_ctx); conn = new_ctx->conn; @@ -644,8 +645,10 @@ quic_quicly_connection_migrate (quic_ctx_t *ctx) quic_quicly_store_conn_ctx (conn, new_ctx); quic_quicly_make_connection_key (&kv, quicly_get_master_id (conn)); - kv.value = ((u64) thread_index) << 32 | (u64) new_ctx_id; - QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]); + kv.value = ((u64) thread_index) << 32 | (u64) new_ctx_index; + QUIC_DBG (2, "Registering conn: key value 0x%llx, ctx_index %u, thread %u", + kv.value, new_ctx_index, thread_index); + clib_bihash_add_del_16_8 (&quic_quicly_main.connection_hash, &kv, 1 /* is_add */); new_ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID; @@ -656,7 +659,7 @@ quic_quicly_connection_migrate (quic_ctx_t *ctx) /* Trigger write on this connection if necessary */ udp_session = session_get_from_handle (new_ctx->udp_session_handle); - udp_session->opaque = new_ctx_id; + udp_session->opaque = new_ctx_index; udp_session->flags &= ~SESSION_F_IS_MIGRATING; if (svm_fifo_max_dequeue (udp_session->tx_fifo)) { @@ -807,7 +810,7 @@ quic_quicly_find_packet_ctx (quic_quicly_rx_packet_ctx_t *pctx, h = &qqm->connection_hash; quic_quicly_make_connection_key (&kv, &pctx->packet.cid.dest.plaintext); - QUIC_DBG (3, "Searching conn with id %lu %lu", kv.key[0], kv.key[1]); + QUIC_DBG (3, "Searching conn with id 0x%llx", *(u64 *) kv.key); if (clib_bihash_search_16_8 (h, &kv, &kv)) { @@ -857,12 +860,17 @@ quic_quicly_accept_connection (quic_quicly_rx_packet_ctx_t *pctx) int rv; quic_quicly_main_t *qqm = &quic_quicly_main; + QUIC_DBG (2, "Accept connection: pkt ctx_index %u, thread %u", + pctx->ctx_index, pctx->thread_index); + /* new connection, accept and create context if packet is valid * TODO: check if socket is actually listening? */ ctx = quic_quicly_get_quic_ctx (pctx->ctx_index, pctx->thread_index); if (ctx->c_s_index != QUIC_SESSION_INVALID) { - QUIC_DBG (2, "already accepted ctx 0x%x", ctx->c_s_index); + QUIC_DBG ( + 2, "Accept connection (already accepted): session_index %u, thread %u", + ctx->c_s_index, ctx->c_thread_index); return; } @@ -873,11 +881,12 @@ quic_quicly_accept_connection (quic_quicly_rx_packet_ctx_t *pctx) { /* Invalid packet, pass */ assert (conn == NULL); - QUIC_ERR ("Accept failed with %U", quic_quicly_format_err, rv); + QUIC_ERR ("Accept connection: failed with %U", quic_quicly_format_err, + rv); /* TODO: cleanup created quic ctx and UDP session */ return; } - assert (conn != NULL); // TODO: why this is in release image??? + ASSERT (conn != NULL); ++qqm->next_cid[pctx->thread_index].master_id; /* Save ctx handle in quicly connection */ @@ -885,8 +894,11 @@ quic_quicly_accept_connection (quic_quicly_rx_packet_ctx_t *pctx) ctx->conn = conn; quic_session = session_alloc (ctx->c_thread_index); - QUIC_DBG (2, "Allocated quic_session, 0x%lx ctx %u", - session_handle (quic_session), ctx->c_c_index); + QUIC_DBG (2, + "Accept connection (new quic_session): session_handle 0x%lx, " + "session_index %u, ctx_index %u, thread %u", + session_handle (quic_session), quic_session->session_index, + ctx->c_c_index, ctx->c_thread_index); ctx->c_s_index = quic_session->session_index; lctx = quic_quicly_get_quic_ctx (ctx->listener_ctx_id, 0); @@ -901,13 +913,15 @@ quic_quicly_accept_connection (quic_quicly_rx_packet_ctx_t *pctx) quic_quicly_make_connection_key (&kv, quicly_get_master_id (conn)); kv.value = ((u64) pctx->thread_index) << 32 | (u64) pctx->ctx_index; clib_bihash_add_del_16_8 (&qqm->connection_hash, &kv, 1 /* is_add */); - QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]); + QUIC_DBG ( + 2, "Accept connection: conn key value 0x%llx, ctx_index %u, thread %u", + kv.value, pctx->ctx_index, pctx->thread_index); /* If notify fails, reset connection immediatly */ rv = app_worker_init_accepted (quic_session); if (rv) { - QUIC_ERR ("failed to allocate fifos"); + QUIC_ERR ("Accept connection: failed to allocate fifos"); quic_quicly_proto_on_close (pctx->ctx_index, pctx->thread_index); return; } @@ -920,7 +934,7 @@ quic_quicly_accept_connection (quic_quicly_rx_packet_ctx_t *pctx) rv = app_worker_accept_notify (app_wrk, quic_session); if (rv) { - QUIC_ERR ("failed to notify accept worker app"); + QUIC_ERR ("Accept connection: failed to notify accept worker app"); quic_quicly_proto_on_close (pctx->ctx_index, pctx->thread_index); return; } @@ -1024,13 +1038,15 @@ quic_quicly_connect (quic_ctx_t *ctx, u32 ctx_index, ++qqm->next_cid[thread_index].master_id; /* save context handle in quicly connection */ quic_quicly_store_conn_ctx (ctx->conn, ctx); - assert (ret == 0); // TODO: why is this in the release image??? + ASSERT (ret == 0); /* Register connection in connections map */ quic_quicly_make_connection_key ( &kv, quicly_get_master_id ((quicly_conn_t *) ctx->conn)); kv.value = ((u64) thread_index) << 32 | (u64) ctx_index; - QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]); + QUIC_DBG ( + 2, "UDP Session connected: conn key value 0x%llx, ctx_index %u, thread %u", + kv.value, ctx_index, thread_index); clib_bihash_add_del_16_8 (&qqm->connection_hash, &kv, 1 /* is_add */); return (ret); @@ -1133,8 +1149,9 @@ quic_quicly_receive_a_packet (quic_ctx_t *ctx, QUIC_ERR ("quicly_receive return error %U", quic_quicly_format_err, rv); } - // FIXME: Don't return quicly error codes here. - // TODO: Define appropriate QUIC return values for QUIC VFT's! + /* FIXME: Don't return quicly error codes here. + * TODO: Define appropriate QUIC return values for QUIC VFT's! + */ return rv; } @@ -1149,14 +1166,18 @@ quic_quicly_connect_stream (void *quic_conn, void **quic_stream, if (!quicly_connection_is_ready (conn)) { - return -1; // TODO: Define appropriate QUIC return values for QUIC VFT's! + /* TODO: Define appropriate QUIC return values for QUIC VFT's! + */ + return -1; } rv = quicly_open_stream (conn, (quicly_stream_t **) quic_stream, is_unidir); if (rv) { QUIC_DBG (2, "quicly_open_stream() failed with %d", rv); - return -1; // TODO: Define appropriate QUIC return values for QUIC VFT's! + /* TODO: Define appropriate QUIC return values for QUIC VFT's! + */ + return -1; } quicly_stream = *(quicly_stream_t **) quic_stream; @@ -1174,13 +1195,12 @@ quic_quicly_connect_stream_error_reset (void *quic_stream) QUIC_QUICLY_APP_CONNECT_NOTIFY_ERROR); } -static_always_inline int +static_always_inline u64 quic_quicly_stream_tx (quic_ctx_t *ctx, session_t *stream_session) { quic_stream_data_t *stream_data; quicly_stream_t *stream; u32 max_deq; - int rv = 0; stream = ctx->stream; if (!quicly_sendstate_is_open (&stream->sendstate)) @@ -1194,15 +1214,16 @@ quic_quicly_stream_tx (quic_ctx_t *ctx, session_t *stream_session) QUIC_ASSERT (max_deq >= stream_data->app_tx_data_len); if (max_deq == stream_data->app_tx_data_len) { - QUIC_DBG (3, "TX but no data %d / %d", max_deq, - stream_data->app_tx_data_len); + QUIC_DBG (3, + "No data: max_deq %d, app_tx_data_len %d, ctx_index " + "%u, thread %u", + max_deq, stream_data->app_tx_data_len, + stream_session->connection_index, + stream_session->thread_index); return 0; } stream_data->app_tx_data_len = max_deq; - rv = quicly_stream_sync_sendbuf (stream, 1); - QUIC_ASSERT (!rv); - - return (rv); + return quicly_stream_sync_sendbuf (stream, 1); } static void @@ -1214,7 +1235,7 @@ quic_quicly_engine_init (quic_main_t *qm) tw_timer_wheel_1t_3w_1024sl_ov_t *tw; u32 i; - QUIC_DBG (2, "quic_quicly_engine_init -- start"); + QUIC_DBG (2, "Quic engine init: quicly"); qm->default_crypto_engine = CRYPTO_ENGINE_PICOTLS; qm->default_quic_cc = QUIC_CC_RENO; qm->max_packets_per_key = DEFAULT_MAX_PACKETS_PER_KEY; @@ -1246,10 +1267,6 @@ quic_quicly_engine_init (quic_main_t *qm) next_cid[i].thread_id = i; clib_bihash_init_24_8 (&crctx_hash[i], "quic crypto contexts", 64, 128 << 10); - QUIC_DBG (2, - "Initialized crctx_hash[%u] " - "(buckets = 0x%lx)", - i, crctx_hash[i].buckets); } } @@ -1329,8 +1346,9 @@ quic_quicly_udp_session_rx_packets (session_t *udp_session) int rv = 0; clib_thread_index_t thread_index = vlib_get_thread_index (); u32 cur_deq, fifo_offset, max_packets, i; - // TODO: move packet buffer off of the stack and - // allocate a vector of packet_ct_t. + /* TODO: move packet buffer off of the stack and + * allocate a vector of packet_ct_t. + */ quic_quicly_rx_packet_ctx_t packets_ctx[QUIC_RCV_MAX_PACKETS]; if (udp_session->flags & SESSION_F_IS_MIGRATING) @@ -1392,15 +1410,15 @@ rx_start: case QUIC_PACKET_TYPE_RECEIVE: ctx = quic_quicly_get_quic_ctx (packets_ctx[i].ctx_index, thread_index); - // FIXME: Process return value and handle errors. + /* FIXME: Process return value and handle errors. */ quic_quicly_receive_a_packet (ctx, &packets_ctx[i]); break; case QUIC_PACKET_TYPE_ACCEPT: - // FIXME: Process return value and handle errors. + /* FIXME: Process return value and handle errors. */ quic_quicly_accept_connection (&packets_ctx[i]); break; case QUIC_PACKET_TYPE_RESET: - // FIXME: Process return value and handle errors. + /* FIXME: Process return value and handle errors. */ quic_quicly_reset_connection (udp_session_handle, &packets_ctx[i]); break; } diff --git a/src/plugins/quic_quicly/quic_quicly.h b/src/plugins/quic_quicly/quic_quicly.h index 516e542064c..d5610bf84e2 100644 --- a/src/plugins/quic_quicly/quic_quicly.h +++ b/src/plugins/quic_quicly/quic_quicly.h @@ -54,8 +54,7 @@ typedef struct quic_quicly_session_cache_ typedef struct quic_quicly_main_ { quic_main_t *qm; - ptls_cipher_suite_t ** - *quic_ciphers; /**< available ciphers by crypto engine */ + ptls_cipher_suite_t ***quic_ciphers; u32 *per_thread_crypto_key_indices; ptls_handshake_properties_t hs_properties; clib_bihash_16_8_t connection_hash; /**< quic connection id -> conn handle */ diff --git a/src/plugins/quic_quicly/quic_quicly_crypto.c b/src/plugins/quic_quicly/quic_quicly_crypto.c index 12f07c12b07..dc3a16a9582 100644 --- a/src/plugins/quic_quicly/quic_quicly_crypto.c +++ b/src/plugins/quic_quicly/quic_quicly_crypto.c @@ -72,8 +72,8 @@ quic_quicly_crypto_context_alloc (u8 thread_index) clib_memset (crctx, 0, sizeof (*crctx)); idx = (crctx - wc->crypto_ctx_pool); crctx->ctx_index = QUIC_CRCTX_CTX_INDEX_ENCODE (thread_index, idx); - QUIC_DBG (2, "Allocated crctx_ndx 0x%08lx (%u) on thread %u", - crctx->ctx_index, crctx->ctx_index, thread_index); + QUIC_DBG (2, "Allocated crctx: crctx_ndx 0x%08lx, index %u, thread %u", + crctx->ctx_index, idx, thread_index); return crctx; } @@ -250,37 +250,48 @@ quic_quicly_init_crypto_context (crypto_context_t *crctx, quic_ctx_t *ctx) application_t *app; quic_quicly_crypto_context_data_t *data; ptls_context_t *ptls_ctx; - u32 i; ASSERT (QUIC_CRCTX_CTX_INDEX_DECODE_THREAD (crctx->ctx_index) == ctx->c_thread_index); ASSERT (QUIC_CRCTX_CTX_INDEX_DECODE_THREAD (crctx->ctx_index) == vlib_get_thread_index ()); - QUIC_DBG (2, "Init crypto context: crctx_ndx 0x%08lx (%u), thread %d", - crctx->ctx_index, crctx->ctx_index, ctx->c_thread_index); - quic_quicly_register_cipher_suite (CRYPTO_ENGINE_PICOTLS, - ptls_openssl_cipher_suites); - - vnet_crypto_main_t *cm = &crypto_main; - if (vec_len (cm->engines) > 0) - qqm->vnet_crypto_enabled = 0; - else + QUIC_DBG (2, "Init crctx: crctx_ndx 0x%08lx, thread %d", crctx->ctx_index, + ctx->c_thread_index); + + if (PREDICT_FALSE (!qm->vnet_crypto_init)) { - qqm->vnet_crypto_enabled = 1; - u8 empty_key[32] = {}; - quic_quicly_register_cipher_suite (CRYPTO_ENGINE_VPP, - quic_quicly_crypto_cipher_suites); - qm->default_crypto_engine = CRYPTO_ENGINE_VPP; - vec_validate (qqm->per_thread_crypto_key_indices, qm->num_threads); - for (i = 0; i < qm->num_threads; i++) + qm->vnet_crypto_init = 1; + if ((vec_len (cm->engines) == 0) || + (qm->default_crypto_engine == CRYPTO_ENGINE_PICOTLS)) { - qqm->per_thread_crypto_key_indices[i] = vnet_crypto_key_add ( - vlib_get_main (), VNET_CRYPTO_ALG_AES_256_CTR, empty_key, 32); + qqm->vnet_crypto_enabled = 0; + (void) quic_quicly_register_cipher_suite ( + CRYPTO_ENGINE_PICOTLS, ptls_openssl_cipher_suites); + } + else + { + qqm->vnet_crypto_enabled = 1; + if (quic_quicly_register_cipher_suite ( + CRYPTO_ENGINE_VPP, quic_quicly_crypto_cipher_suites)) + { + u8 empty_key[32] = {}; + u32 i; + qm->default_crypto_engine = ctx->crypto_engine = + CRYPTO_ENGINE_VPP; + vec_validate (qqm->per_thread_crypto_key_indices, + qm->num_threads); + for (i = 0; i < qm->num_threads; i++) + { + qqm->per_thread_crypto_key_indices[i] = vnet_crypto_key_add ( + vlib_get_main (), VNET_CRYPTO_ALG_AES_256_CTR, empty_key, + 32); + } + } } - } /* TODO: Remove this and clean up legacy provider code in quicly */ quic_quicly_load_openssl3_legacy_provider (); + } data = clib_mem_alloc (sizeof (*data)); /* picotls depends on data being zeroed */ @@ -293,6 +304,9 @@ quic_quicly_init_crypto_context (crypto_context_t *crctx, quic_ctx_t *ctx) ptls_ctx->get_time = &ptls_get_time; ptls_ctx->key_exchanges = ptls_openssl_key_exchanges; ptls_ctx->cipher_suites = qqm->quic_ciphers[ctx->crypto_engine]; + QUIC_DBG (2, "Init crctx: engine_type %U (%u), cipher_suites %p", + format_crypto_engine, ctx->crypto_engine, ctx->crypto_engine, + ptls_ctx->cipher_suites); ptls_ctx->certificates.list = NULL; ptls_ctx->certificates.count = 0; ptls_ctx->on_client_hello = NULL; @@ -313,11 +327,19 @@ quic_quicly_init_crypto_context (crypto_context_t *crctx, quic_ctx_t *ctx) quicly_ctx->now = &quicly_vpp_now_cb; quicly_amend_ptls_context (quicly_ctx->tls); - if (qqm->vnet_crypto_enabled && - qm->default_crypto_engine == CRYPTO_ENGINE_VPP) - quicly_ctx->crypto_engine = &quic_quicly_crypto_engine; + if (qqm->vnet_crypto_enabled && ctx->crypto_engine == CRYPTO_ENGINE_VPP) + { + QUIC_DBG (2, "Init crctx: crypto engine vpp, crctx_ndx 0x%08lx, thread %d", + crctx->ctx_index, ctx->c_thread_index); + quicly_ctx->crypto_engine = &quic_quicly_crypto_engine; + } else - quicly_ctx->crypto_engine = &quicly_default_crypto_engine; + { + QUIC_DBG (2, + "Init crctx: crypto engine quicly, crctx_ndx 0x%08lx, thread %d", + crctx->ctx_index, ctx->c_thread_index); + quicly_ctx->crypto_engine = &quicly_default_crypto_engine; + } quicly_ctx->transport_params.max_data = QUIC_INT_MAX; quicly_ctx->transport_params.max_streams_uni = (uint64_t) 1 << 60; @@ -369,10 +391,12 @@ quic_quicly_init_crypto_context (crypto_context_t *crctx, quic_ctx_t *ctx) } void -quic_quicly_crypto_context_release (u32 crypto_context_index, u8 thread_index) +quic_quicly_crypto_context_release (u32 crctx_ndx, u8 thread_index) { crypto_context_t *crctx; - crctx = quic_quicly_crypto_context_get (crypto_context_index, thread_index); + QUIC_DBG (3, "crctx_ndx 0x%x (%u), thread %u", crctx_ndx, crctx_ndx, + thread_index); + crctx = quic_quicly_crypto_context_get (crctx_ndx, thread_index); crctx->n_subscribers--; quic_quicly_crypto_context_free_if_needed (crctx, thread_index); } @@ -389,18 +413,9 @@ quic_quicly_crypto_context_acquire (quic_ctx_t *ctx) crypto_context_t *crctx; clib_bihash_kv_24_8_t kv; - if (ctx->crypto_engine == CRYPTO_ENGINE_NONE) - { - QUIC_DBG (2, "No crypto engine specified, using %U", - format_crypto_engine, qm->default_crypto_engine); - ctx->crypto_engine = qm->default_crypto_engine; - } - if (!clib_bitmap_get (qqm->available_crypto_engines, ctx->crypto_engine)) - { - QUIC_DBG (1, "Quic does not support crypto engine %U", - format_crypto_engine, ctx->crypto_engine); - return SESSION_E_NOCRYPTOENG; - } + ctx->crypto_engine = (ctx->crypto_engine == CRYPTO_ENGINE_NONE) ? + qm->default_crypto_engine : + ctx->crypto_engine; /* Check for exisiting crypto ctx */ quic_quicly_crypto_context_make_key_from_ctx (&kv, ctx); if (clib_bihash_search_24_8 (&crctx_hash[ctx->c_thread_index], &kv, &kv) == @@ -515,12 +530,13 @@ quic_quicly_crypto_set_key (crypto_key_t *key) u32 key_id = qqm->per_thread_crypto_key_indices[thread_index]; vnet_crypto_key_t *vnet_key = vnet_crypto_get_key (key_id); vnet_crypto_engine_t *engine; - vnet_crypto_main_t *cm = &crypto_main; vec_foreach (engine, cm->engines) if (engine->key_op_handler) engine->key_op_handler (VNET_CRYPTO_KEY_OP_DEL, key_id); + ASSERT (key->algo); + ASSERT (key->key_len); vnet_key->alg = key->algo; clib_memcpy (vnet_key->data, key->key, key->key_len); @@ -544,7 +560,7 @@ quic_quicly_crypto_encrypt_packet (struct st_quicly_crypto_engine_t *engine, struct cipher_context_t *hp_ctx = (struct cipher_context_t *) header_protect_ctx; - struct aead_crypto_context_t *aead_ctx = + struct aead_crypto_context_t *aead_crctx = (struct aead_crypto_context_t *) packet_protect_ctx; void *input = datagram.base + payload_from; @@ -555,20 +571,26 @@ quic_quicly_crypto_encrypt_packet (struct st_quicly_crypto_engine_t *engine, size_t aadlen = payload_from - first_byte_at; /* Build AEAD encrypt crypto operation */ - vnet_crypto_op_init (&aead_ctx->op, aead_ctx->id); - aead_ctx->op.aad = (u8 *) aad; - aead_ctx->op.aad_len = aadlen; - aead_ctx->op.iv = aead_ctx->iv; - ptls_aead__build_iv (aead_ctx->super.algo, aead_ctx->op.iv, - aead_ctx->static_iv, packet_number); - aead_ctx->op.key_index = quic_quicly_crypto_set_key (&aead_ctx->key); - aead_ctx->op.src = (u8 *) input; - aead_ctx->op.dst = output; - aead_ctx->op.len = inlen; - aead_ctx->op.tag_len = aead_ctx->super.algo->tag_size; - aead_ctx->op.tag = aead_ctx->op.src + inlen; - vnet_crypto_process_ops (vm, &(aead_ctx->op), 1); - assert (aead_ctx->op.status == VNET_CRYPTO_OP_STATUS_COMPLETED); + vnet_crypto_op_init (&aead_crctx->op, aead_crctx->id); + aead_crctx->op.aad = (u8 *) aad; + aead_crctx->op.aad_len = aadlen; + aead_crctx->op.iv = aead_crctx->iv; + ptls_aead__build_iv (aead_crctx->super.algo, aead_crctx->op.iv, + aead_crctx->static_iv, packet_number); + QUIC_DBG ( + 3, "id %u, key %p, algo %u, key_len %u, key 0x%llx 0x%llx 0x%llx 0x%llx ", + aead_crctx->id, &aead_crctx->key, aead_crctx->key.algo, + aead_crctx->key.key_len, *(u64 *) &aead_crctx->key.key[0], + *(u64 *) &aead_crctx->key.key[8], *(u64 *) &aead_crctx->key.key[16], + *(u64 *) &aead_crctx->key.key[24]); + aead_crctx->op.key_index = quic_quicly_crypto_set_key (&aead_crctx->key); + aead_crctx->op.src = (u8 *) input; + aead_crctx->op.dst = output; + aead_crctx->op.len = inlen; + aead_crctx->op.tag_len = aead_crctx->super.algo->tag_size; + aead_crctx->op.tag = aead_crctx->op.src + inlen; + vnet_crypto_process_ops (vm, &(aead_crctx->op), 1); + assert (aead_crctx->op.status == VNET_CRYPTO_OP_STATUS_COMPLETED); /* Build Header protection crypto operation */ ptls_aead_supplementary_encryption_t supp = { @@ -605,24 +627,31 @@ quic_quicly_crypto_aead_decrypt (quic_ctx_t *qctx, ptls_aead_context_t *_ctx, { vlib_main_t *vm = vlib_get_main (); - struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; - - vnet_crypto_op_init (&ctx->op, ctx->id); - ctx->op.aad = (u8 *) aad; - ctx->op.aad_len = aadlen; - ctx->op.iv = ctx->iv; - ptls_aead__build_iv (ctx->super.algo, ctx->op.iv, ctx->static_iv, - decrypted_pn); - ctx->op.src = (u8 *) input; - ctx->op.dst = _output; - ctx->op.key_index = quic_quicly_crypto_set_key (&ctx->key); - ctx->op.len = inlen - ctx->super.algo->tag_size; - ctx->op.tag_len = ctx->super.algo->tag_size; - ctx->op.tag = ctx->op.src + ctx->op.len; - - vnet_crypto_process_ops (vm, &(ctx->op), 1); - - return ctx->op.len; + struct aead_crypto_context_t *aead_crctx = + (struct aead_crypto_context_t *) _ctx; + + vnet_crypto_op_init (&aead_crctx->op, aead_crctx->id); + aead_crctx->op.aad = (u8 *) aad; + aead_crctx->op.aad_len = aadlen; + aead_crctx->op.iv = aead_crctx->iv; + ptls_aead__build_iv (aead_crctx->super.algo, aead_crctx->op.iv, + aead_crctx->static_iv, decrypted_pn); + aead_crctx->op.src = (u8 *) input; + aead_crctx->op.dst = _output; + QUIC_DBG ( + 3, "id %u, key %p, algo %u, key_len %u, key 0x%llx 0x%llx 0x%llx 0x%llx ", + aead_crctx->id, &aead_crctx->key, aead_crctx->key.algo, + aead_crctx->key.key_len, *(u64 *) &aead_crctx->key.key[0], + *(u64 *) &aead_crctx->key.key[8], *(u64 *) &aead_crctx->key.key[16], + *(u64 *) &aead_crctx->key.key[24]); + aead_crctx->op.key_index = quic_quicly_crypto_set_key (&aead_crctx->key); + aead_crctx->op.len = inlen - aead_crctx->super.algo->tag_size; + aead_crctx->op.tag_len = aead_crctx->super.algo->tag_size; + aead_crctx->op.tag = aead_crctx->op.src + aead_crctx->op.len; + + vnet_crypto_process_ops (vm, &(aead_crctx->op), 1); + + return aead_crctx->op.len; } void @@ -630,7 +659,7 @@ quic_quicly_crypto_decrypt_packet (quic_ctx_t *qctx, quic_quicly_rx_packet_ctx_t *pctx) { ptls_cipher_context_t *header_protection = NULL; - ptls_aead_context_t *aead = NULL; + ptls_aead_context_t *ptls_aead_ctx = NULL; int pn; /* Long Header packets are not decrypted by vpp */ @@ -642,10 +671,10 @@ quic_quicly_crypto_decrypt_packet (quic_ctx_t *qctx, if (next_expected_packet_number == UINT64_MAX) return; - aead = (ptls_aead_context_t *) qctx->ingress_keys.aead_ctx; + ptls_aead_ctx = (ptls_aead_context_t *) qctx->ingress_keys.aead_ctx; header_protection = (ptls_cipher_context_t *) qctx->ingress_keys.hp_ctx; - if (!aead || !header_protection) + if (!ptls_aead_ctx || !header_protection) return; size_t encrypted_len = pctx->packet.octets.len - pctx->packet.encrypted_off; @@ -695,7 +724,7 @@ quic_quicly_crypto_decrypt_packet (quic_ctx_t *qctx, } if ((ptlen = quic_quicly_crypto_aead_decrypt ( - qctx, aead, pctx->packet.octets.base + aead_off, + qctx, ptls_aead_ctx, pctx->packet.octets.base + aead_off, pctx->packet.octets.base + aead_off, pctx->packet.octets.len - aead_off, pn, pctx->packet.octets.base, aead_off)) == SIZE_MAX) @@ -743,15 +772,17 @@ quic_quicly_crypto_cipher_setup_crypto (ptls_cipher_context_t *_ctx, if (qqm->vnet_crypto_enabled) { - // TODO: why is this commented out (from original quic plugin)? - // ctx->key_index = - // quic_quicly_crypto_go_setup_key (algo, key, _ctx->algo->key_size); ctx->key.algo = algo; ctx->key.key_len = _ctx->algo->key_size; assert (ctx->key.key_len <= 32); clib_memcpy (&ctx->key.key, key, ctx->key.key_len); } + QUIC_DBG ( + 2, "id %u, key %p, algo %u, key_len %u, key 0x%llx 0x%llx 0x%llx 0x%llx ", + ctx->id, &ctx->key, ctx->key.algo, ctx->key.key_len, + *(u64 *) &ctx->key.key[0], *(u64 *) &ctx->key.key[8], + *(u64 *) &ctx->key.key[16], *(u64 *) &ctx->key.key[24]); return 0; } @@ -803,15 +834,17 @@ quic_quicly_crypto_aead_setup_crypto (ptls_aead_context_t *_ctx, int is_enc, if (qqm->vnet_crypto_enabled) { clib_memcpy (ctx->static_iv, iv, ctx->super.algo->iv_size); - // TODO: why is this commented out (from original quic plugin)? - // ctx->key_index = - // quic_quicly_crypto_go_setup_key (algo, key, _ctx->algo->key_size); ctx->key.algo = algo; ctx->key.key_len = _ctx->algo->key_size; assert (ctx->key.key_len <= 32); clib_memcpy (&ctx->key.key, key, ctx->key.key_len); } + QUIC_DBG ( + 3, "id %u, key %p, algo %u, key_len %u, key 0x%llx 0x%llx 0x%llx 0x%llx ", + ctx->id, &ctx->key, ctx->key.algo, ctx->key.key_len, + *(u64 *) &ctx->key.key[0], *(u64 *) &ctx->key.key[8], + *(u64 *) &ctx->key.key[16], *(u64 *) &ctx->key.key[24]); return 0; } diff --git a/src/plugins/quic_quicly/quic_quicly_crypto.h b/src/plugins/quic_quicly/quic_quicly_crypto.h index c4e09bfef60..75abab28ce3 100644 --- a/src/plugins/quic_quicly/quic_quicly_crypto.h +++ b/src/plugins/quic_quicly/quic_quicly_crypto.h @@ -37,8 +37,6 @@ quic_quicly_crypto_context_get (u32 cr_index, u32 thread_index) #define quic_quicly_load_openssl3_legacy_provider() #endif -extern vnet_crypto_main_t *cm; - typedef struct crypto_key_ { vnet_crypto_alg_t algo; @@ -73,14 +71,34 @@ typedef struct quic_quicly_crypto_context_data_ ptls_context_t ptls_ctx; } quic_quicly_crypto_context_data_t; -static_always_inline void +static_always_inline u8 quic_quicly_register_cipher_suite (crypto_engine_type_t type, ptls_cipher_suite_t **ciphers) { quic_quicly_main_t *qqm = &quic_quicly_main; - vec_validate (qqm->quic_ciphers, type); - clib_bitmap_set (qqm->available_crypto_engines, type, 1); - qqm->quic_ciphers[type] = ciphers; + u8 rv = 1; + + if (!qqm->quic_ciphers) + { + vec_validate (qqm->quic_ciphers, type); + } + if (!qqm->quic_ciphers[type]) + { + QUIC_DBG (3, + "Register cipher suite: engine_type %U (%u), cipher_suites %p", + format_crypto_engine, type, type, ciphers); + clib_bitmap_set (qqm->available_crypto_engines, type, 1); + qqm->quic_ciphers[type] = ciphers; + } + else + { + QUIC_DBG (3, + "Cipher suite already registered: engine_type %U (%u), " + "cipher_suites %p", + format_crypto_engine, type, type, ciphers); + rv = 0; + } + return rv; } extern quicly_crypto_engine_t quic_quicly_crypto_engine; diff --git a/test/asf/test_quic.py b/test/asf/test_quic.py index 9f8d75e5ed3..c769f972675 100644 --- a/test/asf/test_quic.py +++ b/test/asf/test_quic.py @@ -116,8 +116,13 @@ class QUICTestCase(VppAsfTestCase): self.ip_t01.add_vpp_config() self.ip_t10.add_vpp_config() self.logger.debug(self.vapi.cli("show ip fib")) + # TODO: refactor test suites to use all crypto cipher suites + # self.vapi.cli("quic set crypto api vpp") + # self.vapi.cli("quic set crypto api engine-lib") + self.logger.debug(self.vapi.cli("show quic")) def tearDown(self): + self.logger.debug(self.vapi.cli("show quic")) self.vapi.app_namespace_add_del_v4( is_add=0, namespace_id=self.server_appns,