FreeBSD supports resource limiting with the rctl(4) framework.
It supports various resource types, including I/O resources.
It allows to limit resources for users, processes, login classes,
and jails.
To apply blkiotune limits set limits for the bhyve process.
I/O related resources supported by rctl(4) are:
readbps filesystem reads, in bytes per second
writebps filesystem writes, in bytes per second
readiops filesystem reads, in operations per second
writeiops filesystem writes, in operations per second
Thus, the actual commands look like:
rctl -a process:$bhyvepid:writebps:throttle=
10000000
rctl -a process:$bhyvepid:readbps:throttle=
10000000
rctl -a process:$bhyvepid:writeiops:throttle=20000
rctl -a process:$bhyvepid:readiops:throttle=20000
This is different from the current blkiotune modeling in libvirt as
it requires specific device to apply limits to. To adapt this model
to per-domain I/O limits, update domain schema to specify "*" as a
device name.
The rctl(8) may be not available or not enabled, so add a capability
check for that.
Per process rules get removed when the process disappears, so no special
clean up is necessary.
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
associated with each guest disk device (contrast this to the <iotune>
element of a disk definition (See `Hard drives, floppy disks, CDROMs`_)
which can applies to an individual disk). Each ``device`` element has
- two mandatory sub-elements, ``path`` describing the absolute path of the
- device, and ``weight`` giving the relative weight of that device, in the
- range [100, 1000]. After kernel 2.6.39, the value could be in the range [10,
- 1000]. :since:`Since 0.9.8`
+ a mandatory ``path`` sub-element describing the absolute path of the
+ device.
+
+ A special value ``*`` can be used to throttle all domain
+ devices. :since:`Since 12.3.0, bhyve`
+
+ An optional ``weight`` sub-element specifies the relative
+ weight of the device, in the range [100, 1000]. After kernel 2.6.39,
+ the value could be in the range [10, 1000]. :since:`Since 0.9.8`
Additionally, the following optional sub-elements can be used:
``read_bytes_sec``
#include <config.h>
#include <sys/utsname.h>
#include <dirent.h>
+#include <sys/sysctl.h>
#include <sys/types.h>
#include "viralloc.h"
}
+static void
+bhyveProbeCapsRctl(unsigned int *caps)
+{
+ bool racct_enable;
+ size_t racct_enable_len;
+ g_autofree char *rctl = NULL;
+
+ if (!(rctl = virFindFileInPath("rctl")))
+ return;
+
+ racct_enable_len = sizeof(racct_enable);
+ if (sysctlbyname("kern.racct.enable", &racct_enable,
+ &racct_enable_len, NULL, 0) < 0)
+ return;
+
+ if (racct_enable)
+ *caps |= BHYVE_CAP_RCTL;
+
+ return;
+}
+
int
virBhyveProbeCaps(unsigned int *caps)
{
if ((ret = bhyveProbeCapsVNCPassword(caps, binary)))
goto out;
+ bhyveProbeCapsRctl(caps);
out:
VIR_FREE(binary);
BHYVE_CAP_NVME = 1 << 11,
BHYVE_CAP_ACPI = 1 << 12,
BHYVE_CAP_NUMA = 1 << 13,
+ BHYVE_CAP_RCTL = 1 << 14,
} virBhyveCapsFlags;
int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps);
}
}
+ if (def->blkio.ndevices > 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Per device I/O tuning is not supported"));
+ return -1;
+ } else if (def->blkio.ndevices == 1) {
+ virBlkioDevice *device = &def->blkio.devices[0];
+
+ if (STRNEQ(device->path, "*")) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Per device I/O tuning is not supported"));
+ return -1;
+ }
+
+ if (device->weight != 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("The 'weight' I/O tuning setting does not make sense with '*'"));
+ return -1;
+ }
+ }
+
if (!def->os.loader)
return 0;
#include "bhyve_device.h"
#include "bhyve_driver.h"
+#include "bhyve_capabilities.h"
#include "bhyve_command.h"
#include "bhyve_firmware.h"
#include "bhyve_monitor.h"
VIR_HOOK_SUBOP_END, NULL, xml, NULL);
}
+static int
+bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm)
+{
+ virBlkioDevice *device;
+
+ if (vm->def->blkio.ndevices != 1)
+ return 0;
+
+ if ((bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_RCTL) == 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Cannot set resource limits: RACCT/RCTL is either not supported or not enabled"));
+ return -1;
+ }
+
+ device = &vm->def->blkio.devices[0];
+
+#define BHYVE_APPLY_RCTL_RULE(field, type, format) \
+ do { \
+ if ((field)) { \
+ g_autofree char *rule = NULL; \
+ g_autoptr(virCommand) cmd = virCommandNewArgList("rctl", "-a", NULL); \
+ virCommandAddArgFormat(cmd, "process:%d:" type ":throttle=" 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");
+
+#undef BHYVE_APPLY_RCTL_RULE
+
+ return 0;
+}
+
static int
virBhyveProcessStartImpl(struct _bhyveConn *driver,
virDomainObj *vm,
BHYVE_STATE_DIR) < 0)
goto cleanup;
+ if (bhyveSetResourceLimits(driver, vm) < 0)
+ goto cleanup;
+
if (bhyveProcessStartHook(driver, vm, VIR_HOOK_BHYVE_OP_STARTED) < 0)
goto cleanup;
<element name="device">
<interleave>
<element name="path">
- <ref name="absFilePath"/>
+ <choice>
+ <ref name="absFilePath"/>
+ <value>*</value>
+ </choice>
</element>
<optional>
<element name="weight">
--- /dev/null
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <blkiotune>
+ <device>
+ <path>/dev/sda</path>
+ <read_bytes_sec>10000</read_bytes_sec>
+ <write_bytes_sec>10000</write_bytes_sec>
+ <read_iops_sec>20000</read_iops_sec>
+ <write_iops_sec>20000</write_iops_sec>
+ </device>
+ </blkiotune>
+ <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>
--- /dev/null
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <blkiotune>
+ <device>
+ <path>*</path>
+ <read_bytes_sec>10000</read_bytes_sec>
+ <write_bytes_sec>10000</write_bytes_sec>
+ <read_iops_sec>20000</read_iops_sec>
+ <write_iops_sec>20000</write_iops_sec>
+ </device>
+ <device>
+ <path>/dev/hda</path>
+ <read_bytes_sec>10000</read_bytes_sec>
+ <write_bytes_sec>10000</write_bytes_sec>
+ <read_iops_sec>20000</read_iops_sec>
+ <write_iops_sec>20000</write_iops_sec>
+ </device>
+ </blkiotune>
+ <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>
--- /dev/null
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <blkiotune>
+ <device>
+ <path>*</path>
+ <weight>100</weight>
+ <read_bytes_sec>10000</read_bytes_sec>
+ <write_bytes_sec>10000</write_bytes_sec>
+ <read_iops_sec>20000</read_iops_sec>
+ <write_iops_sec>20000</write_iops_sec>
+ </device>
+ </blkiotune>
+ <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>
--- /dev/null
+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
--- /dev/null
+bhyveload \
+-m 214 \
+-d /tmp/freebsd.img \
+bhyve
--- /dev/null
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory>219136</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type>hvm</type>
+ </os>
+ <blkiotune>
+ <device>
+ <path>*</path>
+ <read_bytes_sec>10000</read_bytes_sec>
+ <write_bytes_sec>10000</write_bytes_sec>
+ <read_iops_sec>20000</read_iops_sec>
+ <write_iops_sec>20000</write_iops_sec>
+ </device>
+ </blkiotune>
+ <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>
DO_TEST_FAILURE("slirp-ip");
DO_TEST("virtio-scsi");
DO_TEST("vcpupin");
+ DO_TEST("blkiotune");
+ DO_TEST_FAILURE("blkiotune-invalid-device");
+ DO_TEST_FAILURE("blkiotune-multiple-devices");
+ DO_TEST_FAILURE("blkiotune-weight");
/* Address allocation tests */
DO_TEST("addr-single-sata-disk");
--- /dev/null
+<domain type='bhyve'>
+ <name>bhyve</name>
+ <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <blkiotune>
+ <device>
+ <path>*</path>
+ <read_iops_sec>20000</read_iops_sec>
+ <write_iops_sec>20000</write_iops_sec>
+ <read_bytes_sec>10000</read_bytes_sec>
+ <write_bytes_sec>10000</write_bytes_sec>
+ </device>
+ </blkiotune>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <disk type='file' device='disk'>
+ <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>
+ <controller type='pci' index='0' model='pci-root'/>
+ <controller type='sata' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </controller>
+ <interface type='bridge'>
+ <mac address='52:54:00:b9:94:02'/>
+ <source bridge='virbr0'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ </devices>
+</domain>
DO_TEST_DIFFERENT("slirp");
DO_TEST_DIFFERENT("virtio-scsi");
DO_TEST_DIFFERENT("numa");
+ DO_TEST_DIFFERENT("blkiotune");
+ DO_TEST_FAILURE("blkiotune-invalid-device");
+ DO_TEST_FAILURE("blkiotune-weight");
+ DO_TEST_FAILURE("blkiotune-multiple-devices");
/* Address allocation tests */
DO_TEST_DIFFERENT("addr-single-sata-disk");