]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
bhyve: implement the domainGetMemoryParameters API
authorRoman Bogorodskiy <bogorodskiy@gmail.com>
Sat, 16 May 2026 08:30:32 +0000 (10:30 +0200)
committerRoman Bogorodskiy <bogorodskiy@gmail.com>
Wed, 20 May 2026 16:27:08 +0000 (18:27 +0200)
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 <bogorodskiy@gmail.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/bhyve/bhyve_driver.c
src/bhyve/bhyve_rctl.c [new file with mode: 0644]
src/bhyve/bhyve_rctl.h [new file with mode: 0644]
src/bhyve/meson.build

index c9b0caff7a13489a918afec7744c8f58943ebf2c..9c373d363be595bf120788828341734cd65c015e 100644 (file)
@@ -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(&params[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 (file)
index 0000000..69467d2
--- /dev/null
@@ -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 (file)
index 0000000..46f102c
--- /dev/null
@@ -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);
index 11920d9c3e42ed50d7b55c4b7c7fbbc719f837f7..c6dd5660da3fbc23a36aad112e228ab1f9f1e767 100644 (file)
@@ -9,6 +9,7 @@ bhyve_sources = files(
   'bhyve_driver.c',
   'bhyve_monitor.c',
   'bhyve_process.c',
+  'bhyve_rctl.c',
 )
 
 driver_source_files += bhyve_sources