]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
bhyve: implement timeout for bhyveload
authorRoman Bogorodskiy <bogorodskiy@gmail.com>
Sun, 13 Jul 2025 08:17:11 +0000 (10:17 +0200)
committerRoman Bogorodskiy <bogorodskiy@gmail.com>
Mon, 21 Jul 2025 16:29:21 +0000 (18:29 +0200)
The bhyveload(8) command does not have a native non-interactive mode.
It means that in case of errors, e.g. invalid boot media, it
just drops into a loader prompt and waits for user input. This behaviour
makes it tricky for users to understand what's going on.

To address that, run it with the timeout(1) tool which sends SIGTERM
after a certain timeout, and then optionally sends SIGKILL if the
command keeps hanging.

These timeout values could be configured in the bhyve.conf. Setting
timeout to 0 mean that bhyveload(8) will be executed directly, without
timeout(1).

Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/bhyve/bhyve.conf
src/bhyve/bhyve_command.c
src/bhyve/bhyve_conf.c
src/bhyve/bhyve_utils.h
src/bhyve/libvirtd_bhyve.aug
src/bhyve/test_libvirtd_bhyve.aug.in
tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.args [new file with mode: 0644]
tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.ldargs [new file with mode: 0644]
tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.xml [new file with mode: 0644]
tests/bhyvexml2argvtest.c

index 2a8baacff332bfe95d01669054756f8a1693ccb1..dc8d3d8fd898aee978b3e8f00ac9ab66d38de1b7 100644 (file)
@@ -5,3 +5,12 @@
 # Path to a directory with firmware files. By default it's pointing
 # to the directory that sysutils/bhyve-firmware installs files into.
 #firmware_dir = "/usr/local/share/uefi-firmware"
+
+# Set timeout for the bhyveload(8) command. This might be necessary
+# because in case of errors bhyveload(8) drops to an interactive
+# loader and hangs indefinitely. These timeout values are passed
+# to the timeout(1) command. Please refer to its manual page for more
+# details. When timeout is 0, bhyveload is executed directly.
+# Units are seconds.
+#bhyveload_timeout = 300
+#bhyveload_timeout_kill = 15
index 5757a41e7ef2b836a70a04c5727e52ec0a1e5a48..ab6d6e92e4b288df35647d0283721f0b203dd14b 100644 (file)
@@ -921,11 +921,28 @@ virAppendBootloaderArgs(virCommand *cmd, virDomainDef *def)
 }
 
 static virCommand *
-virBhyveProcessBuildBhyveloadCmd(virDomainDef *def, virDomainDiskDef *disk)
+virBhyveProcessBuildBhyveloadCmd(virDomainDef *def,
+                                 struct _bhyveConn *driver,
+                                 virDomainDiskDef *disk)
 {
     virCommand *cmd;
-
-    cmd = virCommandNew("bhyveload");
+    g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(driver);
+
+    if (cfg->bhyveloadTimeout > 0) {
+        /* TODO: update bhyve_process.c to interpret timeout(1) exit
+         * codes 124-127 to produce more meaningful error messages */
+        cmd = virCommandNew("timeout");
+        virCommandAddArg(cmd, "--foreground");
+        virCommandAddArg(cmd, "--verbose");
+        if (cfg->bhyveloadTimeoutKill > 0) {
+            virCommandAddArg(cmd, "-k");
+            virCommandAddArgFormat(cmd, "%ds", cfg->bhyveloadTimeoutKill);
+        }
+        virCommandAddArgFormat(cmd, "%ds", cfg->bhyveloadTimeout);
+        virCommandAddArg(cmd, "bhyveload");
+    } else {
+        cmd = virCommandNew("bhyveload");
+    }
 
     if (def->os.bootloaderArgs == NULL) {
         VIR_DEBUG("bhyveload with default arguments");
@@ -1212,7 +1229,7 @@ virBhyveProcessBuildLoadCmd(struct _bhyveConn *driver, virDomainDef *def,
         if (disk == NULL)
             return NULL;
 
-        return virBhyveProcessBuildBhyveloadCmd(def, disk);
+        return virBhyveProcessBuildBhyveloadCmd(def, driver, disk);
     } else if (strstr(def->os.bootloader, "grub-bhyve") != NULL) {
         return virBhyveProcessBuildGrubbhyveCmd(def, driver, devmap_file,
                                                 devicesmap_out);
index f18b24f91d16067e6e60ab99e26ce8f7bb6626cf..182e00ee1d676bd1a45de29ba55ca391e95752cf 100644 (file)
@@ -2,6 +2,7 @@
  * bhyve_conf.c: bhyve config file
  *
  * Copyright (C) 2017 Roman Bogorodskiy
+ * Copyright (C) 2025 The FreeBSD Foundation
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -60,6 +61,9 @@ virBhyveDriverConfigNew(void)
     cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR);
     cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir);
 
+    cfg->bhyveloadTimeout = 300;
+    cfg->bhyveloadTimeoutKill = 15;
+
     return cfg;
 }
 
@@ -81,6 +85,14 @@ virBhyveLoadDriverConfig(struct _virBhyveDriverConfig *cfg,
                               &cfg->firmwareDir) < 0)
         return -1;
 
+    if (virConfGetValueInt(conf, "bhyveload_timeout",
+                           &cfg->bhyveloadTimeout) < 0)
+        return -1;
+
+    if (virConfGetValueInt(conf, "bhyveload_timeout_kill",
+                           &cfg->bhyveloadTimeoutKill) < 0)
+        return -1;
+
     return 0;
 }
 
index 9c9ea0a01af27a8e08abcc97797d7b5d6bbc48b8..8ed1fa550944b6c6b32c428a4ce8ce6e7ec766dd 100644 (file)
@@ -41,6 +41,9 @@ struct _virBhyveDriverConfig {
     char *firmwareDir;
     char *libDir;
     char *nvramDir;
+
+    int bhyveloadTimeout;
+    int bhyveloadTimeoutKill;
 };
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virBhyveDriverConfig, virObjectUnref);
index b6bee261a6dedb3637ad7b44831552b756331d67..0fd74d4bb3f6759cad8530ce2d2c5370766abcae 100644 (file)
@@ -23,9 +23,11 @@ module Libvirtd_bhyve =
    let str_array_entry (kw:string) = [ key kw . value_sep . str_array_val ]
 
    let log_entry = str_entry "firmware_dir"
+   let bhyveload_timeout = int_entry "bhyveload_timeout"
+   let bhyveload_timeout_kill = int_entry "bhyveload_timeout_kill"
 
    (* Each entry in the config is one of the following three ... *)
-   let entry = log_entry
+   let entry = log_entry | bhyveload_timeout | bhyveload_timeout_kill
    let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
    let empty = [ label "#empty" . eol ]
 
index ec932b4b11dcbfd5ef9a4d39ca128c9b64de5811..391648e71fa8d1392ff2c85903ccaac8104a09bc 100644 (file)
@@ -3,3 +3,5 @@ module Test_libvirtd_bhyve =
 
   test Libvirtd_bhyve.lns get conf =
 { "firmware_dir" = "/usr/local/share/uefi-firmware" }
+{ "bhyveload_timeout" = "300" }
+{ "bhyveload_timeout_kill" = "15" }
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.args b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.args
new file mode 100644 (file)
index 0000000..153a1d5
--- /dev/null
@@ -0,0 +1,10 @@
+bhyve \
+-c 1 \
+-m 214 \
+-u \
+-H \
+-P \
+-s 0:0,hostbridge \
+-s 2:0,ahci-hd,/tmp/freebsd.img \
+-s 3:0,virtio-net,faketapdev,mac=52:54:00:b9:94:02 \
+bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.ldargs b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.ldargs
new file mode 100644 (file)
index 0000000..264ae48
--- /dev/null
@@ -0,0 +1,7 @@
+timeout \
+--foreground \
+--verbose \
+-k 20s 300s bhyveload \
+-m 214 \
+-d /tmp/freebsd.img \
+bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.xml
new file mode 100644 (file)
index 0000000..0b80667
--- /dev/null
@@ -0,0 +1,23 @@
+<domain type='bhyve'>
+  <name>bhyve</name>
+  <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+  <memory>219136</memory>
+  <vcpu>1</vcpu>
+  <os>
+    <type>hvm</type>
+  </os>
+  <devices>
+    <disk type='file'>
+      <driver name='file' type='raw'/>
+      <source file='/tmp/freebsd.img'/>
+      <target dev='hda' bus='sata'/>
+      <address type='drive' controller='0' bus='0' target='2' unit='0'/>
+    </disk>
+    <interface type='bridge'>
+      <mac address='52:54:00:b9:94:02'/>
+      <model type='virtio'/>
+      <source bridge="virbr0"/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </interface>
+  </devices>
+</domain>
index 2838b20c293351de0b4b789517d0d6131e2f3e5f..cc6b17233dd073c6f2085189ce1f9880b8a7a1eb 100644 (file)
@@ -165,6 +165,8 @@ mymain(void)
 
     driver.config->firmwareDir = fakefirmwaredir;
     driver.config->nvramDir = fakenvramdir;
+    driver.config->bhyveloadTimeout = 0;
+    driver.config->bhyveloadTimeoutKill = 0;
 
 # define DO_TEST_FULL(name, flags) \
     do { \
@@ -305,6 +307,10 @@ mymain(void)
     driver.bhyvecaps &= ~BHYVE_CAP_VNC_PASSWORD;
     DO_TEST_FAILURE("vnc-password");
 
+    driver.config->bhyveloadTimeout = 300;
+    driver.config->bhyveloadTimeoutKill = 20;
+    DO_TEST("bhyveload-timeout");
+
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);
     virPortAllocatorRangeFree(driver.remotePorts);