From nobody Mon Sep 8 17:08:17 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=gmail.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1752924863942307.401206047522; Sat, 19 Jul 2025 04:34:23 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 8D24E13D7; Sat, 19 Jul 2025 07:34:22 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 5BFF51186; Sat, 19 Jul 2025 07:33:49 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 5EBBA1183; Sat, 19 Jul 2025 07:33:45 -0400 (EDT) Received: from mail-ed1-f45.google.com (mail-ed1-f45.google.com [209.85.208.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 113EEE98 for ; Sat, 19 Jul 2025 07:33:44 -0400 (EDT) Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-607cf70b00aso5160405a12.2 for ; Sat, 19 Jul 2025 04:33:44 -0700 (PDT) Received: from tulp.my.domain (80-115-115-199.cable.dynamic.v4.ziggo.nl. [80.115.115.199]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aec6c7d524asm292997466b.45.2025.07.19.04.33.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 19 Jul 2025 04:33:41 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1752924822; x=1753529622; darn=lists.libvirt.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=DAnKd3NPZrJnOspdKdEe3+vfkklS4TfjlXB0n3fFEBc=; b=hzdaMVBj4W/viYKaaRPmM5WvpxfqR2+GovP2E7LqrgxtCEEnix+YEVgJfrxiNNCZVX 0pIzq+5y2Tl480V92n7ydDL0sPNM0a+Zp4Nvz/qu0NvchaQX8OSrtJimGMHG0T5BHmA6 cjxAYhjccq0R0cgaJ356Xom5D8PqXWw0hwCgH/olTPBa2Zi9P0t15154xXSVGvPyDgKY D08GwelJMsADRsnMb0v2vFTfnASGdZyJm6FCQu8JFc1LABgrN1AjzOJeFOs1i4w4jxxu QMNWUlJDT3JuIhFz7AHBjRe1Ab/kg6Xxv0Ri7KZiUyZIt5I4RVUIl9CbHfUHRfZO5KtZ i7Ew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752924822; x=1753529622; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=DAnKd3NPZrJnOspdKdEe3+vfkklS4TfjlXB0n3fFEBc=; b=YF+IzTMt/BIf+0j/5kVhQnHT0OqefiDkCDCQlunggkwfYzZMd0haHxRc3J2NkdeENZ X72xnAP+QvkE5XgDAhVVkd7Ux3mRCACbey6bz8ZxK/vv0t9G/M2BX0AfgKb7otAaDxzI fyXm8hhy6/bnqa94rrlouUjYLMrdl4bwqfBPJ1yvwseeWShmY5C94hfiAUrZzU3xv1Yo qOOhxGRR+0HwUIVptHHQmJ8HgkSls7FZW1lvNq6vPfpfKm4Js7ZXzKe8xqZZZYizxdpd oU7JMVcH2huQXm0JfqDpL41cSlJLjsWzn5MSt6cl8zsza3sYkDEOI5WFucwrGLTVNmaL tejA== X-Gm-Message-State: AOJu0Ywa0yu2F3KEj/n2zmB2JPKu37RwNiOn5PGM0Xl1TJGb4KWcQHv/ nLPTplOsck0uku/7s9kL2DiogbBtFW386AnTaxblD3dV7q+ovGXeOfILlr3yqUsYrWI4dA== X-Gm-Gg: ASbGncuMzACDfT2GsiIsowIqVu9dmDOq6zpwod0wQhrH3CkpNTjyEHbnQ+rZbfO1sqX hyIUHgUz6LDLkp7rGIfOF4IvtdqZfsrJEIraTn4+G2zFpHM/hzKkWEQOaL+0nABkMxnb/M31mYq vRfqcE2kRsklcj/xF9neyPELuBQyH3AkM6g2oijQxp7eIC94Yz/pDEXidLcM+PM1CjEnImm6wYV k1OEiD93aArD1TwdfL4jKggfpZPt+oS7kOPj4ODrXeHVYvA/WY3vg5IzAnwTHA2OnLC4HVjJsqR QUfyrT7PirmXkA5u3+k1QHQiqQvpt2Q5vq2ky+ypDZaJ0bKKJPpfajxw6jcLnPGzCUqNCoYvbd2 JBVNKshBsDkXHCcNE52bGT564xrjMhKmo0zyGWqYuW4Wr06LWdini0a46UtRhaByI3dTiZiQ= X-Google-Smtp-Source: AGHT+IHvHgRtNZ4pflvmo/DlV4pJ1OSmdlCvVz+zSEL7KHnibsn/gW29GqZu/uiz863Ter3+utKmQg== X-Received: by 2002:a17:907:1c15:b0:ae0:d201:a333 with SMTP id a640c23a62f3a-aec4fbea40fmr944903566b.30.1752924822055; Sat, 19 Jul 2025 04:33:42 -0700 (PDT) From: Roman Bogorodskiy To: devel@lists.libvirt.org Subject: [PATCH] bhyve: implement timeout for bhyveload Date: Sat, 19 Jul 2025 13:30:57 +0200 Message-ID: <20250719113057.33356-1-bogorodskiy@gmail.com> X-Mailer: git-send-email 2.49.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: NY3ZRK3QBUTMWUPJMQRMKMRF4X2V4IXY X-Message-ID-Hash: NY3ZRK3QBUTMWUPJMQRMKMRF4X2V4IXY X-MailFrom: bogorodskiy@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: Roman Bogorodskiy X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1752924866874116600 Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Michal Privoznik --- src/bhyve/bhyve.conf | 9 +++++++ src/bhyve/bhyve_command.c | 25 ++++++++++++++++--- src/bhyve/bhyve_conf.c | 12 +++++++++ src/bhyve/bhyve_utils.h | 3 +++ src/bhyve/libvirtd_bhyve.aug | 4 ++- src/bhyve/test_libvirtd_bhyve.aug.in | 2 ++ .../bhyvexml2argv-bhyveload-timeout.args | 10 ++++++++ .../bhyvexml2argv-bhyveload-timeout.ldargs | 7 ++++++ .../bhyvexml2argv-bhyveload-timeout.xml | 23 +++++++++++++++++ tests/bhyvexml2argvtest.c | 6 +++++ 10 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout= .args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout= .ldargs create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout= .xml diff --git a/src/bhyve/bhyve.conf b/src/bhyve/bhyve.conf index 2a8baacff3..dc8d3d8fd8 100644 --- a/src/bhyve/bhyve.conf +++ b/src/bhyve/bhyve.conf @@ -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 =3D "/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 =3D 300 +#bhyveload_timeout_kill =3D 15 diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 5757a41e7e..ab6d6e92e4 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -921,11 +921,28 @@ virAppendBootloaderArgs(virCommand *cmd, virDomainDef= *def) } =20 static virCommand * -virBhyveProcessBuildBhyveloadCmd(virDomainDef *def, virDomainDiskDef *disk) +virBhyveProcessBuildBhyveloadCmd(virDomainDef *def, + struct _bhyveConn *driver, + virDomainDiskDef *disk) { virCommand *cmd; - - cmd =3D virCommandNew("bhyveload"); + g_autoptr(virBhyveDriverConfig) cfg =3D 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 =3D 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 =3D virCommandNew("bhyveload"); + } =20 if (def->os.bootloaderArgs =3D=3D NULL) { VIR_DEBUG("bhyveload with default arguments"); @@ -1212,7 +1229,7 @@ virBhyveProcessBuildLoadCmd(struct _bhyveConn *driver= , virDomainDef *def, if (disk =3D=3D NULL) return NULL; =20 - return virBhyveProcessBuildBhyveloadCmd(def, disk); + return virBhyveProcessBuildBhyveloadCmd(def, driver, disk); } else if (strstr(def->os.bootloader, "grub-bhyve") !=3D NULL) { return virBhyveProcessBuildGrubbhyveCmd(def, driver, devmap_file, devicesmap_out); diff --git a/src/bhyve/bhyve_conf.c b/src/bhyve/bhyve_conf.c index f18b24f91d..182e00ee1d 100644 --- a/src/bhyve/bhyve_conf.c +++ b/src/bhyve/bhyve_conf.c @@ -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 =3D g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR); cfg->nvramDir =3D g_strdup_printf("%s/nvram", cfg->libDir); =20 + cfg->bhyveloadTimeout =3D 300; + cfg->bhyveloadTimeoutKill =3D 15; + return cfg; } =20 @@ -81,6 +85,14 @@ virBhyveLoadDriverConfig(struct _virBhyveDriverConfig *c= fg, &cfg->firmwareDir) < 0) return -1; =20 + if (virConfGetValueInt(conf, "bhyveload_timeout", + &cfg->bhyveloadTimeout) < 0) + return -1; + + if (virConfGetValueInt(conf, "bhyveload_timeout_kill", + &cfg->bhyveloadTimeoutKill) < 0) + return -1; + return 0; } =20 diff --git a/src/bhyve/bhyve_utils.h b/src/bhyve/bhyve_utils.h index 9c9ea0a01a..8ed1fa5509 100644 --- a/src/bhyve/bhyve_utils.h +++ b/src/bhyve/bhyve_utils.h @@ -41,6 +41,9 @@ struct _virBhyveDriverConfig { char *firmwareDir; char *libDir; char *nvramDir; + + int bhyveloadTimeout; + int bhyveloadTimeoutKill; }; =20 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virBhyveDriverConfig, virObjectUnref); diff --git a/src/bhyve/libvirtd_bhyve.aug b/src/bhyve/libvirtd_bhyve.aug index b6bee261a6..0fd74d4bb3 100644 --- a/src/bhyve/libvirtd_bhyve.aug +++ b/src/bhyve/libvirtd_bhyve.aug @@ -23,9 +23,11 @@ module Libvirtd_bhyve =3D let str_array_entry (kw:string) =3D [ key kw . value_sep . str_array_va= l ] =20 let log_entry =3D str_entry "firmware_dir" + let bhyveload_timeout =3D int_entry "bhyveload_timeout" + let bhyveload_timeout_kill =3D int_entry "bhyveload_timeout_kill" =20 (* Each entry in the config is one of the following three ... *) - let entry =3D log_entry + let entry =3D log_entry | bhyveload_timeout | bhyveload_timeout_kill let comment =3D [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \= t\n][^\n]*)?/ . del /\n/ "\n" ] let empty =3D [ label "#empty" . eol ] =20 diff --git a/src/bhyve/test_libvirtd_bhyve.aug.in b/src/bhyve/test_libvirtd= _bhyve.aug.in index ec932b4b11..391648e71f 100644 --- a/src/bhyve/test_libvirtd_bhyve.aug.in +++ b/src/bhyve/test_libvirtd_bhyve.aug.in @@ -3,3 +3,5 @@ module Test_libvirtd_bhyve =3D =20 test Libvirtd_bhyve.lns get conf =3D { "firmware_dir" =3D "/usr/local/share/uefi-firmware" } +{ "bhyveload_timeout" =3D "300" } +{ "bhyveload_timeout_kill" =3D "15" } diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.args b= /tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.args new file mode 100644 index 0000000000..153a1d5035 --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.args @@ -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=3D52: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 index 0000000000..264ae48441 --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.ldargs @@ -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 index 0000000000..0b8066733d --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload-timeout.xml @@ -0,0 +1,23 @@ + + bhyve + df3be7e7-a104-11e3-aeb0-50e5492bd3dc + 219136 + 1 + + hvm + + + + + + +
+ + + + + +
+ + + diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index 2838b20c29..cc6b17233d 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -165,6 +165,8 @@ mymain(void) =20 driver.config->firmwareDir =3D fakefirmwaredir; driver.config->nvramDir =3D fakenvramdir; + driver.config->bhyveloadTimeout =3D 0; + driver.config->bhyveloadTimeoutKill =3D 0; =20 # define DO_TEST_FULL(name, flags) \ do { \ @@ -305,6 +307,10 @@ mymain(void) driver.bhyvecaps &=3D ~BHYVE_CAP_VNC_PASSWORD; DO_TEST_FAILURE("vnc-password"); =20 + driver.config->bhyveloadTimeout =3D 300; + driver.config->bhyveloadTimeoutKill =3D 20; + DO_TEST("bhyveload-timeout"); + virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt); virPortAllocatorRangeFree(driver.remotePorts); --=20 2.49.0