Implement the domainGetMemoryParameters() API for the bhyve driver. To parse live limits execute rctl(8) to list the active rules and parse them.
Introduce the bhyve_rctl.c for working with rctl(8). Signed-off-by: Roman Bogorodskiy <[email protected]> --- src/bhyve/bhyve_driver.c | 59 +++++++++++++++++++++++ src/bhyve/bhyve_rctl.c | 101 +++++++++++++++++++++++++++++++++++++++ src/bhyve/bhyve_rctl.h | 24 ++++++++++ src/bhyve/meson.build | 1 + 4 files changed, 185 insertions(+) create mode 100644 src/bhyve/bhyve_rctl.c create mode 100644 src/bhyve/bhyve_rctl.h diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index c9b0caff7a..9c373d363b 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -70,6 +70,7 @@ #include "bhyve_domain.h" #include "bhyve_process.h" #include "bhyve_capabilities.h" +#include "bhyve_rctl.h" #define VIR_FROM_THIS VIR_FROM_BHYVE @@ -2167,6 +2168,63 @@ bhyveDomainGetHostname(virDomainPtr domain, return hostname; } + +#define BHYVE_NB_MEM_PARAM 1 +#define BHYVE_ASSIGN_MEM_PARAM(index, name, value) \ + if (index < *nparams && \ + virTypedParameterAssign(¶ms[index], name, VIR_TYPED_PARAM_ULLONG, \ + value) < 0) \ + goto cleanup + +static int +bhyveDomainGetMemoryParameters(virDomainPtr domain, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virDomainObj *vm = NULL; + virDomainDef *persistentDef = NULL; + int ret = -1; + unsigned long long mem_hard_limit; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG | + VIR_TYPED_PARAM_STRING_OKAY, -1); + + if (!(vm = bhyveDomObjFromDomain(domain))) + return -1; + + if (virDomainGetMemoryParametersEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + + if (virDomainObjGetDefs(vm, flags, NULL, &persistentDef) < 0) + goto cleanup; + + if ((*nparams) == 0) { + *nparams = BHYVE_NB_MEM_PARAM; + ret = 0; + goto cleanup; + } + + if (persistentDef) { + mem_hard_limit = persistentDef->mem.hard_limit; + } else { + if (bhyveRctlGetMemoryHardLimit(vm->pid, &mem_hard_limit) < 0) + goto cleanup; + } + + BHYVE_ASSIGN_MEM_PARAM(0, VIR_DOMAIN_MEMORY_HARD_LIMIT, mem_hard_limit); + + if (BHYVE_NB_MEM_PARAM < *nparams) + *nparams = BHYVE_NB_MEM_PARAM; + ret = 0; + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} +#undef BHYVE_ASSIGN_MEM_PARAM + static virHypervisorDriver bhyveHypervisorDriver = { .name = "bhyve", .connectURIProbe = bhyveConnectURIProbe, @@ -2236,6 +2294,7 @@ static virHypervisorDriver bhyveHypervisorDriver = { .domainInterfaceAddresses = bhyveDomainInterfaceAddresses, /* 12.3.0 */ .domainGetHostname = bhyveDomainGetHostname, /* 12.3.0 */ .domainQemuAgentCommand = bhyveDomainQemuAgentCommand, /* 12.4.0 */ + .domainGetMemoryParameters = bhyveDomainGetMemoryParameters, /* 12.4.0 */ }; diff --git a/src/bhyve/bhyve_rctl.c b/src/bhyve/bhyve_rctl.c new file mode 100644 index 0000000000..69467d2e34 --- /dev/null +++ b/src/bhyve/bhyve_rctl.c @@ -0,0 +1,101 @@ +/* + * bhyve_rctl.c: Resource limits management with rctl(8) + * + * Copyright (C) 2026 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <sys/wait.h> + +#include "bhyve_rctl.h" +#include "vircommand.h" +#include "viralloc.h" +#include "virerror.h" +#include "virfile.h" +#include "virlog.h" +#include "virobject.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_BHYVE + +VIR_LOG_INIT("bhyve.bhyve_rctl"); + + +static int +bhyveRctlGetAmountFromRule(const char *rule, unsigned long long *amount) +{ + /* From rctl(8): + * + * Syntax for a rule is subject:subject-id:resource:action=amount/per. + * A valid rule has all those fields specified, except for per, which + * defaults to the value of subject. + */ + g_auto(GStrv) tokens = NULL; + unsigned long long bytes; + + if (!(tokens = g_strsplit_set(rule, "=/", 0))) + return -1; + + if (g_strv_length(tokens) < 2) + return -1; + + if (virStrToLong_ull(tokens[1], NULL, 10, &bytes) < 0) + return -1; + + *amount = bytes / 1024; + + return 0; +} + +int +bhyveRctlGetMemoryHardLimit(pid_t pid, unsigned long long *kb) +{ + g_auto(GStrv) lines = NULL; + g_autofree char *outbuf = NULL; + g_autoptr(virCommand) cmd = NULL; + size_t i; + + cmd = virCommandNew("rctl"); + virCommandAddArgFormat(cmd, "process:%d:memoryuse", pid); + virCommandSetOutputBuffer(cmd, &outbuf); + if (virCommandRun(cmd, NULL) < 0) { + *kb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; + return -1; + } + + /* Empty output means no matching rules, thus no limits */ + if (strlen(outbuf) == 0) { + *kb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; + return 0; + } + + if (!(lines = g_strsplit(outbuf, "\n", 0))) + return -1; + + /* There could be multiple actions for a resource, such as + * 'log' for example, so we need to look for the 'deny' action + * specifically */ + for (i = 0; lines[i]; i++) + if (strstr(lines[i], ":deny=")) + return bhyveRctlGetAmountFromRule(lines[i], kb); + + return -1; +} diff --git a/src/bhyve/bhyve_rctl.h b/src/bhyve/bhyve_rctl.h new file mode 100644 index 0000000000..46f102c38e --- /dev/null +++ b/src/bhyve/bhyve_rctl.h @@ -0,0 +1,24 @@ +/* + * bhyve_rctl.h: Resource limits management with rctl(8) + * + * Copyright (C) 2026 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#pragma once + +int +bhyveRctlGetMemoryHardLimit(pid_t pid, unsigned long long *kb); diff --git a/src/bhyve/meson.build b/src/bhyve/meson.build index 11920d9c3e..c6dd5660da 100644 --- a/src/bhyve/meson.build +++ b/src/bhyve/meson.build @@ -9,6 +9,7 @@ bhyve_sources = files( 'bhyve_driver.c', 'bhyve_monitor.c', 'bhyve_process.c', + 'bhyve_rctl.c', ) driver_source_files += bhyve_sources -- 2.52.0
