quic: don't crash when no quic engine is available 27/43227/18
authorDave Wallace <[email protected]>
Wed, 18 Jun 2025 20:20:51 +0000 (16:20 -0400)
committerFlorin Coras <[email protected]>
Tue, 15 Jul 2025 16:38:37 +0000 (16:38 +0000)
- When there is no quic engine available, vpp crashes with an
  assert on startup which is not production friendly.
  Instead, emit warning message to stderr.
- Fix crash in session_transport_closing_notify if
  a remote closed notification happens on an invalid
  session in the quicly engine.
- Fix compilation errors when QUIC_DEBUG is set to 2
- Fix crash in 'show quic crypto context' command when
  quic engine is not present.
- Add quic engine type to 'show quic' output.

Type: fix

Change-Id: I83b9e69873fa3cd61d1d852b78ed1ccd2112825c
Signed-off-by: Dave Wallace <[email protected]>
src/plugins/quic/quic.c
src/plugins/quic_quicly/quic_quicly.c
src/plugins/quic_quicly/quic_quicly_crypto.c
src/vnet/session/transport.c

index 1daf78b..3a6ae06 100644 (file)
@@ -74,6 +74,21 @@ quic_list_crypto_context_command_fn (vlib_main_t *vm, unformat_input_t *input,
   crypto_context_t *crctx;
   vlib_thread_main_t *vtm = vlib_get_thread_main ();
   int i, num_threads = 1 /* main thread */  + vtm->n_threads;
+  quic_main_t *qm = &quic_main;
+
+  session_cli_return_if_not_enabled ();
+  if (qm->engine_type == QUIC_ENGINE_NONE)
+    {
+      vlib_cli_output (vm, "No QUIC engine plugin enabled");
+      return 0;
+    }
+  if (qm->engine_is_initialized[qm->engine_type] == 0)
+    {
+      vlib_cli_output (vm, "quic engine %s not initialized",
+                      quic_engine_type_str (qm->engine_type));
+      return 0;
+    }
+
   for (i = 0; i < num_threads; i++)
     {
       pool_foreach (crctx, quic_wrk_ctx_get (&quic_main, i)->crypto_ctx_pool)
@@ -805,7 +820,10 @@ static session_cb_vft_t quic_app_cb_vft = {
   .app_cert_key_pair_delete_callback = quic_app_cert_key_pair_delete_callback,
 };
 
-static const transport_proto_vft_t quic_proto = {
+static clib_error_t *quic_enable (vlib_main_t *vm, u8 is_en);
+
+static transport_proto_vft_t quic_proto = {
+  .enable = quic_enable,
   .connect = quic_connect,
   .close = quic_proto_on_close,
   .start_listen = quic_start_listen,
@@ -828,6 +846,58 @@ static const transport_proto_vft_t quic_proto = {
   },
 };
 
+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_ctx_t *ctx;
+  crypto_context_t *crctx;
+  vlib_thread_main_t *vtm = vlib_get_thread_main ();
+  int i;
+
+  qm->engine_type =
+    quic_get_engine_type (QUIC_ENGINE_QUICLY, QUIC_ENGINE_OPENSSL);
+  if (qm->engine_type == QUIC_ENGINE_NONE)
+    {
+      /* Prevent crash in transport layer callbacks with no quic engine */
+      quic_proto.connect = 0;
+      quic_proto.start_listen = 0;
+      clib_warning (
+       "ERROR: NO QUIC ENGINE PLUGIN ENABLED!"
+       "\nEnable a quic engine plugin in the startup configuration.");
+      return clib_error_return (0, "No QUIC engine plugin enabled");
+    }
+
+  QUIC_DBG (1, "QUIC engine %s init", quic_engine_type_str (qm->engine_type));
+  if (!is_en || qm->engine_is_initialized[qm->engine_type])
+    return 0;
+
+  qm->quic_input_node = &quic_input_node;
+  qm->num_threads = 1 /* main thread */ + vtm->n_threads;
+  vec_validate (quic_main.wrk_ctx, qm->num_threads - 1);
+
+  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,
+                            CLIB_CACHE_LINE_BYTES);
+      pool_program_safe_realloc ((void **) &wrk_ctx->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,
+                                QUIC_CTX_POOL_PER_THREAD_SIZE,
+                                CLIB_CACHE_LINE_BYTES);
+    }
+
+  QUIC_DBG (1, "Initializing quic engine to %s",
+           quic_engine_type_str (qm->engine_type));
+  quic_eng_engine_init (qm);
+  qm->engine_is_initialized[qm->engine_type] = 1;
+  return 0;
+}
+
 static void
 quic_update_fifo_size ()
 {
@@ -849,22 +919,19 @@ quic_update_fifo_size ()
 static clib_error_t *
 quic_init (vlib_main_t * vm)
 {
-  u32 segment_size = 256 << 20;
-  vlib_thread_main_t *vtm = vlib_get_thread_main ();
+  quic_main_t *qm = &quic_main;
   vnet_app_attach_args_t _a, *a = &_a;
   u64 options[APP_OPTIONS_N_OPTIONS];
-  quic_main_t *qm = &quic_main;
+  // TODO: Don't use hard-coded values for segment_size and seed[]
+  u32 segment_size = 256 << 20;
   u8 seed[32];
 
   QUIC_DBG (1, "QUIC plugin init");
-  qm->quic_input_node = &quic_input_node;
 
   if (syscall (SYS_getrandom, &seed, sizeof (seed), 0) != sizeof (seed))
     return clib_error_return_unix (0, "getrandom() failed");
   RAND_seed (seed, sizeof (seed));
 
-  qm->num_threads = 1 /* main thread */ + vtm->n_threads;
-
   clib_memset (a, 0, sizeof (*a));
   clib_memset (options, 0, sizeof (options));
 
@@ -886,7 +953,6 @@ quic_init (vlib_main_t * vm)
       clib_warning ("failed to attach quic app");
       return clib_error_return (0, "failed to attach quic app");
     }
-
   qm->app_index = a->app_index;
 
   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
@@ -898,53 +964,7 @@ quic_init (vlib_main_t * vm)
   return 0;
 }
 
-static void
-quic_engine_init ()
-{
-  quic_main_t *qm = &quic_main;
-  quic_worker_ctx_t *wrk_ctx;
-  quic_ctx_t *ctx;
-  crypto_context_t *crctx;
-  int i;
-
-  vec_validate (quic_main.wrk_ctx, qm->num_threads - 1);
-
-  QUIC_DBG (1, "Initializing quic engine to %s",
-           quic_engine_type_str (qm->engine_type));
-
-  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,
-                            CLIB_CACHE_LINE_BYTES);
-      pool_program_safe_realloc ((void **) &wrk_ctx->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,
-                                QUIC_CTX_POOL_PER_THREAD_SIZE,
-                                CLIB_CACHE_LINE_BYTES);
-    }
-
-  quic_eng_engine_init (qm);
-  qm->engine_is_initialized[qm->engine_type] = 1;
-}
-
-static clib_error_t *
-quic_main_loop_init (vlib_main_t *vm)
-{
-  quic_main_t *qm = &quic_main;
-
-  qm->engine_type =
-    quic_get_engine_type (QUIC_ENGINE_QUICLY, QUIC_ENGINE_OPENSSL);
-  QUIC_ASSERT (qm->engine_type != QUIC_ENGINE_NONE);
-
-  quic_engine_init ();
-  return 0;
-}
-
 VLIB_INIT_FUNCTION (quic_init);
-VLIB_MAIN_LOOP_ENTER_FUNCTION (quic_main_loop_init);
 
 static clib_error_t *
 quic_plugin_crypto_command_fn (vlib_main_t *vm, unformat_input_t *input,
@@ -1159,9 +1179,22 @@ quic_show_connections_command_fn (vlib_main_t *vm, unformat_input_t *input,
   u32 num_workers = vlib_num_workers ();
   clib_error_t *error = 0;
   quic_ctx_t *ctx = NULL;
+  quic_main_t *qm = &quic_main;
 
   session_cli_return_if_not_enabled ();
+  if (qm->engine_type == QUIC_ENGINE_NONE)
+    {
+      vlib_cli_output (vm, "No QUIC engine plugin enabled");
+      return 0;
+    }
+  if (qm->engine_is_initialized[qm->engine_type] == 0)
+    {
+      vlib_cli_output (vm, "quic engine %s not initialized",
+                      quic_engine_type_str (qm->engine_type));
+      return 0;
+    }
 
+  vlib_cli_output (vm, "engine: %s", quic_engine_type_str (qm->engine_type));
   if (!unformat_user (input, unformat_line_input, line_input))
     {
       quic_show_aggregated_stats (vm);
index e621b04..3c076ae 100644 (file)
@@ -327,8 +327,9 @@ static void
 quic_quicly_expired_timers_dispatch (u32 *expired_timers)
 {
   int i;
-#if QUIC_DEBUG >= 4
-  int64_t time_now = quic_wrk_ctx_get(quic_quicly_main.qm, vlib_get_thread_index ())->time_now);
+#if QUIC_DEBUG >= 1
+  int64_t time_now =
+    quic_wrk_ctx_get (quic_quicly_main.qm, vlib_get_thread_index ())->time_now;
 #endif
   for (i = 0; i < vec_len (expired_timers); i++)
     {
@@ -1213,6 +1214,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");
   qm->default_crypto_engine = CRYPTO_ENGINE_PICOTLS;
   qm->default_quic_cc = QUIC_CC_RENO;
   qm->max_packets_per_key = DEFAULT_MAX_PACKETS_PER_KEY;
index 13c7e6d..cc2780f 100644 (file)
@@ -203,13 +203,25 @@ quic_quicly_on_closed_by_remote (quicly_closed_by_remote_t *self,
 {
   quic_ctx_t *ctx = quic_quicly_get_conn_ctx (conn);
 #if QUIC_DEBUG >= 2
-  session_t *quic_session = session_get (ctx->c_s_index, ctx->c_thread_index);
-  clib_warning ("Session 0x%lx closed by peer (%U) %.*s ",
-               session_handle (quic_session), quic_quicly_format_err, code,
-               reason_len, reason);
+  if (ctx->c_s_index == QUIC_SESSION_INVALID)
+    {
+      clib_warning ("Unopened Session closed by peer (%U) %.*S ",
+                   quic_quicly_format_err, code, reason_len, reason);
+    }
+  else
+    {
+      session_t *quic_session =
+       session_get (ctx->c_s_index, ctx->c_thread_index);
+      clib_warning ("Session 0x%lx closed by peer (%U) %.*s ",
+                   session_handle (quic_session), quic_quicly_format_err,
+                   code, reason_len, reason);
+    }
 #endif
   ctx->conn_state = QUIC_CONN_STATE_PASSIVE_CLOSING;
-  session_transport_closing_notify (&ctx->connection);
+  if (ctx->c_s_index != QUIC_SESSION_INVALID)
+    {
+      session_transport_closing_notify (&ctx->connection);
+    }
 }
 
 static int64_t
index edec182..fa3106a 100644 (file)
@@ -1015,7 +1015,8 @@ transport_enable_disable (vlib_main_t * vm, u8 is_en)
   vec_foreach (vft, tp_vfts)
   {
     if (vft->enable)
-      (vft->enable) (vm, is_en);
+      if ((vft->enable) (vm, is_en) != 0)
+         continue;
 
     if (vft->update_time)
       session_register_update_time_fn (vft->update_time, is_en);