[PATCH 0/4] bhyve: add memtune support
Roman Bogorodskiy (4): bhyve: add memtune support bhyve: implement the domainGetMemoryParameters API bhyve: process: factor out rctl(8) code bhyve: implement the domainSetMemoryParameters API src/bhyve/bhyve_domain.c | 8 ++ src/bhyve/bhyve_driver.c | 130 +++++++++++++++++ src/bhyve/bhyve_process.c | 32 ++--- src/bhyve/bhyve_rctl.c | 135 ++++++++++++++++++ src/bhyve/bhyve_rctl.h | 32 +++++ src/bhyve/meson.build | 1 + ...vexml2argv-memtune-unsupported-params.args | 10 ++ ...xml2argv-memtune-unsupported-params.ldargs | 4 + ...yvexml2argv-memtune-unsupported-params.xml | 28 ++++ .../x86_64/bhyvexml2argv-memtune.args | 10 ++ .../x86_64/bhyvexml2argv-memtune.ldargs | 4 + .../x86_64/bhyvexml2argv-memtune.xml | 26 ++++ tests/bhyvexml2argvtest.c | 2 + 13 files changed, 402 insertions(+), 20 deletions(-) create mode 100644 src/bhyve/bhyve_rctl.c create mode 100644 src/bhyve/bhyve_rctl.h create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.args create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.ldargs create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.xml create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.args create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.ldargs create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.xml -- 2.52.0
Add support of the memtune's hard_limit configuration: <memtune> <hard_limit ... > </memtune> to the bhyve driver. Just like in the block I/O tuning case, memory limits are set using the rctl(8) tool. Syntax for that is: rctl -a process:<pid>:memoryuse:deny=1073741824 Extend bhyveSetResourceLimits() to execute this command if it's requested by the domain XML. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_domain.c | 8 ++++++ src/bhyve/bhyve_process.c | 26 +++++++++++------ ...vexml2argv-memtune-unsupported-params.args | 10 +++++++ ...xml2argv-memtune-unsupported-params.ldargs | 4 +++ ...yvexml2argv-memtune-unsupported-params.xml | 28 +++++++++++++++++++ .../x86_64/bhyvexml2argv-memtune.args | 10 +++++++ .../x86_64/bhyvexml2argv-memtune.ldargs | 4 +++ .../x86_64/bhyvexml2argv-memtune.xml | 26 +++++++++++++++++ tests/bhyvexml2argvtest.c | 2 ++ 9 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.args create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.ldargs create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.xml create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.args create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.ldargs create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.xml diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 6367985efc..86e4de1fd8 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -541,6 +541,14 @@ bhyveDomainDefValidate(const virDomainDef *def, } } + if (virMemoryLimitIsSet(def->mem.soft_limit) || + virMemoryLimitIsSet(def->mem.swap_hard_limit) || + def->mem.min_guarantee) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only 'hard_limit' memory tuning parameter is supported by bhyve")); + return -1; + } + if (!def->os.loader) return 0; diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 7652a998e5..7baefeb63b 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -53,6 +53,7 @@ #include "virnetdevbridge.h" #include "virnetdevtap.h" #include "virtime.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_BHYVE @@ -138,7 +139,8 @@ bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm) { virBlkioDevice *device; - if (vm->def->blkio.ndevices != 1) + if ((vm->def->blkio.ndevices != 1) && + !virMemoryLimitIsSet(vm->def->mem.hard_limit)) return 0; if ((bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_RCTL) == 0) { @@ -147,24 +149,30 @@ bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm) return -1; } - device = &vm->def->blkio.devices[0]; - -#define BHYVE_APPLY_RCTL_RULE(field, type, format) \ +#define BHYVE_APPLY_RCTL_RULE(field, type, action, format) \ do { \ if ((field)) { \ g_autofree char *rule = NULL; \ g_autoptr(virCommand) cmd = virCommandNewArgList("rctl", "-a", NULL); \ - virCommandAddArgFormat(cmd, "process:%d:" type ":throttle=" format, \ + virCommandAddArgFormat(cmd, "process:%d:" type ":" action "=" format, \ vm->pid, (field)); \ if (virCommandRun(cmd, NULL) < 0) \ return -1; \ } \ } while (0) - BHYVE_APPLY_RCTL_RULE(device->riops, "readiops", "%u"); - BHYVE_APPLY_RCTL_RULE(device->wiops, "writeiops", "%u"); - BHYVE_APPLY_RCTL_RULE(device->rbps, "readbps", "%llu"); - BHYVE_APPLY_RCTL_RULE(device->wbps, "writebps", "%llu"); + if (vm->def->blkio.ndevices == 1) { + device = &vm->def->blkio.devices[0]; + + BHYVE_APPLY_RCTL_RULE(device->riops, "readiops", "throttle", "%u"); + BHYVE_APPLY_RCTL_RULE(device->wiops, "writeiops", "throttle", "%u"); + BHYVE_APPLY_RCTL_RULE(device->rbps, "readbps", "throttle", "%llu"); + BHYVE_APPLY_RCTL_RULE(device->wbps, "writebps", "throttle", "%llu"); + } + + /* rctl(8) uses bytes for these values and def->mem.* uses kibibytes */ + if (virMemoryLimitIsSet(vm->def->mem.hard_limit)) + BHYVE_APPLY_RCTL_RULE(vm->def->mem.hard_limit * 1024, "memoryuse", "deny", "%llu"); #undef BHYVE_APPLY_RCTL_RULE diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.args b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.args new file mode 100644 index 0000000000..507e0be668 --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.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=52:54:00:b9:94:02 \ +bhyve diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.ldargs b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.ldargs new file mode 100644 index 0000000000..5905f4b3e6 --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.ldargs @@ -0,0 +1,4 @@ +bhyveload \ +-m 214 \ +-d /tmp/freebsd.img \ +bhyve diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.xml b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.xml new file mode 100644 index 0000000000..af1e25805d --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.xml @@ -0,0 +1,28 @@ +<domain type='bhyve'> + <name>bhyve</name> + <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid> + <memory>219136</memory> + <memtune> + <soft_limit unit='M'>512</soft_limit> + <swap_hard_limit unit='G'>1</swap_hard_limit> + <min_guarantee unit='M'>128</min_guarantee> + </memtune> + <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> diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.args b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.args new file mode 100644 index 0000000000..507e0be668 --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.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=52:54:00:b9:94:02 \ +bhyve diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.ldargs b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.ldargs new file mode 100644 index 0000000000..5905f4b3e6 --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.ldargs @@ -0,0 +1,4 @@ +bhyveload \ +-m 214 \ +-d /tmp/freebsd.img \ +bhyve diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.xml b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.xml new file mode 100644 index 0000000000..f8bcd23296 --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.xml @@ -0,0 +1,26 @@ +<domain type='bhyve'> + <name>bhyve</name> + <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid> + <memory>219136</memory> + <memtune> + <hard_limit unit='M'>512</hard_limit> + </memtune> + <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> diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index eb2c1d33b8..818b51e178 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -301,6 +301,8 @@ mymain(void) DO_TEST_FAILURE("virtio-console-too-many-ports"); DO_TEST_FAILURE("virtio-console-invalid-name"); DO_TEST_FAILURE("virtio-console-invalid-path"); + DO_TEST("memtune"); + DO_TEST_FAILURE("memtune-unsupported-params"); /* Address allocation tests */ DO_TEST("addr-single-sata-disk"); -- 2.52.0
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> --- 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
Factor out all rctl(8) execution code to bhyve_rctl.c. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_process.c | 24 ++++-------------------- src/bhyve/bhyve_rctl.c | 34 ++++++++++++++++++++++++++++++++++ src/bhyve/bhyve_rctl.h | 8 ++++++++ 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 7baefeb63b..92665419d4 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -39,13 +39,13 @@ #include "bhyve_firmware.h" #include "bhyve_monitor.h" #include "bhyve_process.h" +#include "bhyve_rctl.h" #include "datatypes.h" #include "virerror.h" #include "virhook.h" #include "virlog.h" #include "virfile.h" #include "viralloc.h" -#include "vircommand.h" #include "virstring.h" #include "virpidfile.h" #include "virprocess.h" @@ -149,32 +149,16 @@ bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm) return -1; } -#define BHYVE_APPLY_RCTL_RULE(field, type, action, format) \ - do { \ - if ((field)) { \ - g_autofree char *rule = NULL; \ - g_autoptr(virCommand) cmd = virCommandNewArgList("rctl", "-a", NULL); \ - virCommandAddArgFormat(cmd, "process:%d:" type ":" action "=" format, \ - vm->pid, (field)); \ - if (virCommandRun(cmd, NULL) < 0) \ - return -1; \ - } \ - } while (0) - if (vm->def->blkio.ndevices == 1) { device = &vm->def->blkio.devices[0]; - BHYVE_APPLY_RCTL_RULE(device->riops, "readiops", "throttle", "%u"); - BHYVE_APPLY_RCTL_RULE(device->wiops, "writeiops", "throttle", "%u"); - BHYVE_APPLY_RCTL_RULE(device->rbps, "readbps", "throttle", "%llu"); - BHYVE_APPLY_RCTL_RULE(device->wbps, "writebps", "throttle", "%llu"); + bhyveRctlSetIoLimits(vm->pid, device); } /* rctl(8) uses bytes for these values and def->mem.* uses kibibytes */ if (virMemoryLimitIsSet(vm->def->mem.hard_limit)) - BHYVE_APPLY_RCTL_RULE(vm->def->mem.hard_limit * 1024, "memoryuse", "deny", "%llu"); - -#undef BHYVE_APPLY_RCTL_RULE + if (bhyveRctlSetMemoryHardLimit(vm->pid, vm->def->mem.hard_limit) < 0) + return -1; return 0; } diff --git a/src/bhyve/bhyve_rctl.c b/src/bhyve/bhyve_rctl.c index 69467d2e34..c9e8e26cc4 100644 --- a/src/bhyve/bhyve_rctl.c +++ b/src/bhyve/bhyve_rctl.c @@ -99,3 +99,37 @@ bhyveRctlGetMemoryHardLimit(pid_t pid, unsigned long long *kb) return -1; } + +#define BHYVE_APPLY_RCTL_RULE(pid, field, type, action, format) \ + do { \ + if ((field)) { \ + g_autofree char *rule = NULL; \ + g_autoptr(virCommand) cmd = virCommandNewArgList("rctl", "-a", NULL); \ + virCommandAddArgFormat(cmd, "process:%d:" type ":" action "=" format, \ + pid, (field)); \ + if (virCommandRun(cmd, NULL) < 0) \ + return -1; \ + } \ + } while (0) + +int +bhyveRctlSetMemoryHardLimit(pid_t pid, unsigned long long kb) +{ + /* rctl(8) uses bytes for these values and def->mem.* uses kibibytes */ + BHYVE_APPLY_RCTL_RULE(pid, kb * 1024, "memoryuse", "deny", "%llu"); + + return 0; +} + +int +bhyveRctlSetIoLimits(pid_t pid, const virBlkioDevice *device) +{ + BHYVE_APPLY_RCTL_RULE(pid, device->riops, "readiops", "throttle", "%u"); + BHYVE_APPLY_RCTL_RULE(pid, device->wiops, "writeiops", "throttle", "%u"); + BHYVE_APPLY_RCTL_RULE(pid, device->rbps, "readbps", "throttle", "%llu"); + BHYVE_APPLY_RCTL_RULE(pid, device->wbps, "writebps", "throttle", "%llu"); + + return 0; +} + +#undef BHYVE_APPLY_RCTL_RULE diff --git a/src/bhyve/bhyve_rctl.h b/src/bhyve/bhyve_rctl.h index 46f102c38e..83d4a32013 100644 --- a/src/bhyve/bhyve_rctl.h +++ b/src/bhyve/bhyve_rctl.h @@ -20,5 +20,13 @@ #pragma once +#include "domain_conf.h" + int bhyveRctlGetMemoryHardLimit(pid_t pid, unsigned long long *kb); + +int +bhyveRctlSetMemoryHardLimit(pid_t pid, unsigned long long kb); + +int +bhyveRctlSetIoLimits(pid_t pid, const virBlkioDevice *device); -- 2.52.0
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_driver.c | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 9c373d363b..331d9eb439 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -2225,6 +2225,76 @@ bhyveDomainGetMemoryParameters(virDomainPtr domain, } #undef BHYVE_ASSIGN_MEM_PARAM +static int +bhyveDomainSetMemoryParameters(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + struct _bhyveConn *privconn = domain->conn->privateData; + virDomainDef *def = NULL; + virDomainDef *persistentDef = NULL; + virDomainObj *vm = NULL; + int ret = -1; + unsigned long long hard_limit = 0; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (virTypedParamsValidate(params, nparams, + VIR_DOMAIN_MEMORY_HARD_LIMIT, + VIR_TYPED_PARAM_ULLONG, + NULL) < 0) + return -1; + + + if (!(vm = bhyveDomObjFromDomain(domain))) + return -1; + + if (virDomainSetMemoryParametersEnsureACL(domain->conn, vm->def, flags) < 0) + goto cleanup; + + if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) + goto endjob; + + if (virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_MEMORY_HARD_LIMIT, &hard_limit) < 0) + return -1; + + if (def) { + if ((bhyveDriverGetBhyveCaps(privconn) & BHYVE_CAP_RCTL) == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Cannot set resource limits: RACCT/RCTL is either not supported or not enabled")); + goto endjob; + } + + if (bhyveRctlSetMemoryHardLimit(vm->pid, hard_limit) < 0) + goto endjob; + + def->mem.hard_limit = hard_limit; + if (virDomainObjSave(vm, privconn->xmlopt, BHYVE_STATE_DIR) < 0) + VIR_WARN("Failed to save status on vm %s", vm->def->name); + } + + if (persistentDef) { + persistentDef->mem.hard_limit = hard_limit; + + if (virDomainDefSave(persistentDef, privconn->xmlopt, BHYVE_CONFIG_DIR) < 0) + goto endjob; + } + + ret = 0; + + endjob: + virDomainObjEndJob(vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + static virHypervisorDriver bhyveHypervisorDriver = { .name = "bhyve", .connectURIProbe = bhyveConnectURIProbe, @@ -2295,6 +2365,7 @@ static virHypervisorDriver bhyveHypervisorDriver = { .domainGetHostname = bhyveDomainGetHostname, /* 12.3.0 */ .domainQemuAgentCommand = bhyveDomainQemuAgentCommand, /* 12.4.0 */ .domainGetMemoryParameters = bhyveDomainGetMemoryParameters, /* 12.4.0 */ + .domainSetMemoryParameters = bhyveDomainSetMemoryParameters, /* 12.4.0 */ }; -- 2.52.0
On 5/19/26 19:21, Roman Bogorodskiy wrote:
Roman Bogorodskiy (4): bhyve: add memtune support bhyve: implement the domainGetMemoryParameters API bhyve: process: factor out rctl(8) code bhyve: implement the domainSetMemoryParameters API
src/bhyve/bhyve_domain.c | 8 ++ src/bhyve/bhyve_driver.c | 130 +++++++++++++++++ src/bhyve/bhyve_process.c | 32 ++--- src/bhyve/bhyve_rctl.c | 135 ++++++++++++++++++ src/bhyve/bhyve_rctl.h | 32 +++++ src/bhyve/meson.build | 1 + ...vexml2argv-memtune-unsupported-params.args | 10 ++ ...xml2argv-memtune-unsupported-params.ldargs | 4 + ...yvexml2argv-memtune-unsupported-params.xml | 28 ++++ .../x86_64/bhyvexml2argv-memtune.args | 10 ++ .../x86_64/bhyvexml2argv-memtune.ldargs | 4 + .../x86_64/bhyvexml2argv-memtune.xml | 26 ++++ tests/bhyvexml2argvtest.c | 2 + 13 files changed, 402 insertions(+), 20 deletions(-) create mode 100644 src/bhyve/bhyve_rctl.c create mode 100644 src/bhyve/bhyve_rctl.h create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.args create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.ldargs create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune-unsupported-params.xml create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.args create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.ldargs create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-memtune.xml
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (2)
-
Michal Prívozník -
Roman Bogorodskiy