bhyve: implement the domainGetMemoryParameters API

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>
This commit is contained in:
Roman Bogorodskiy committed 2026-05-20 18:27:08 +02:00
1 parent dd34991f6e
commit 3c013d1627
4 files changed
+185

No files matched your search

+59
View 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 */
};
+101
View File
@@ -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;
}
+24
View File
@@ -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);
+1
View 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