This patch is in response to
https://bugzilla.redhat.com/show_bug.cgi?id=643050
The existing libvirt support for the vhost-net backend to the virtio
network driver happens automatically - if the vhost-net device is
available, it is always enabled, otherwise the standard userland
virtio backend is used.
This patch makes it possible to force whether or not vhost-net is used
with a bit of XML. Adding a <driver> element to the interface XML, eg:
<interface type="network">
<model type="virtio"/>
<driver name="vhost"/>
will force use of vhost-net (if it's not available, the domain will
fail to start). if driver name="qemu", vhost-net will not be used even
if it is available.
If there is no <driver name='xxx'/> in the config, libvirt will revert
to the pre-existing automatic behavior - use vhost-net if it's
available, and userland backend if vhost-net isn't available.
---
Changes from V1:
enum now starts at 0 instead of -1. I just disallow "default" when
parsing. This eliminates the need for vhost_specified.
Removed superfluous 3rd arg to open().
docs/schemas/domain.rng | 13 +++++++++
src/conf/domain_conf.c | 29 +++++++++++++++++++-
src/conf/domain_conf.h | 10 +++++++
src/qemu/qemu_command.c | 67 ++++++++++++++++++++++++++++++++++++++--------
src/qemu/qemu_command.h | 3 --
5 files changed, 106 insertions(+), 16 deletions(-)
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 6de85fd..5e140fb 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -1005,6 +1005,19 @@
</element>
</optional>
<optional>
+ <element name="driver">
+ <optional>
+ <attribute name="name">
+ <choice>
+ <value>qemu</value>
+ <value>vhost</value>
+ </choice>
+ </attribute>
+ </optional>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
<ref name="address"/>
</optional>
<optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2c54683..1cef112 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -185,6 +185,11 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
"internal",
"direct")
+VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
+ "default",
+ "qemu",
+ "vhost")
+
VIR_ENUM_IMPL(virDomainChrChannelTarget,
VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
"guestfwd",
@@ -2290,6 +2295,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *address = NULL;
char *port = NULL;
char *model = NULL;
+ char *backend = NULL;
char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
@@ -2372,6 +2378,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
script = virXMLPropString(cur, "path");
} else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
model = virXMLPropString(cur, "type");
+ } else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
+ backend = virXMLPropString(cur, "name");
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
filter = virXMLPropString(cur, "filter");
VIR_FREE(filterparams);
@@ -2559,6 +2567,19 @@ virDomainNetDefParseXML(virCapsPtr caps,
model = NULL;
}
+ if ((backend != NULL) &&
+ (def->model && STREQ(def->model, "virtio"))) {
+ int b;
+ if (((b = virDomainNetBackendTypeFromString(backend)) < 0) ||
+ (b == 0)) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown interface <driver
name='%s'> "
+ "has been specified"),
+ backend);
+ goto error;
+ }
+ def->backend = b;
+ }
if (filter != NULL) {
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_ETHERNET:
@@ -2585,6 +2606,7 @@ cleanup:
VIR_FREE(script);
VIR_FREE(bridge);
VIR_FREE(model);
+ VIR_FREE(backend);
VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
@@ -6276,9 +6298,14 @@ virDomainNetDefFormat(virBufferPtr buf,
if (def->ifname)
virBufferEscapeString(buf, " <target dev='%s'/>\n",
def->ifname);
- if (def->model)
+ if (def->model) {
virBufferEscapeString(buf, " <model type='%s'/>\n",
def->model);
+ if (STREQ(def->model, "virtio") && def->backend) {
+ virBufferVSprintf(buf, " <driver
name='%s'/>\n",
+ virDomainNetBackendTypeToString(def->backend));
+ }
+ }
if (def->filter) {
virBufferEscapeString(buf, " <filterref filter='%s'",
def->filter);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6a8ec64..a73fd14 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -292,6 +292,14 @@ enum virDomainNetType {
VIR_DOMAIN_NET_TYPE_LAST,
};
+/* the backend driver used for virtio interfaces */
+enum virDomainNetBackendType {
+ VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT, /* prefer kernel, fall back to user */
+ VIR_DOMAIN_NET_BACKEND_TYPE_QEMU, /* userland */
+ VIR_DOMAIN_NET_BACKEND_TYPE_VHOST, /* kernel */
+
+ VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
+};
/* the mode type for macvtap devices */
enum virDomainNetdevMacvtapType {
@@ -310,6 +318,7 @@ struct _virDomainNetDef {
enum virDomainNetType type;
unsigned char mac[VIR_MAC_BUFLEN];
char *model;
+ enum virDomainNetBackendType backend;
union {
struct {
char *dev;
@@ -1265,6 +1274,7 @@ VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
VIR_ENUM_DECL(virDomainFSAccessMode)
VIR_ENUM_DECL(virDomainNet)
+VIR_ENUM_DECL(virDomainNetBackend)
VIR_ENUM_DECL(virDomainChrDevice)
VIR_ENUM_DECL(virDomainChrChannelTarget)
VIR_ENUM_DECL(virDomainChrConsoleTarget)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 86c5bb5..a3b5ff3 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -302,24 +302,58 @@ cleanup:
}
-int
+static int
qemuOpenVhostNet(virDomainNetDefPtr net,
- unsigned long long qemuCmdFlags)
+ unsigned long long qemuCmdFlags,
+ int *vhostfd)
{
- /* If qemu supports vhost-net mode (including the -netdev command
- * option), the nic model is virtio, and we can open
- * /dev/vhost_net, assume that vhost-net mode is available and
- * return the fd to /dev/vhost_net. Otherwise, return -1.
- */
+ *vhostfd = -1; /* assume we won't use vhost */
+ /* If the config says explicitly to not use vhost, return now */
+ if (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_QEMU) {
+ return 0;
+ }
+
+ /* If qemu doesn't support vhost-net mode (including the -netdev command
+ * option), don't try to open the device.
+ */
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HOST &&
qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV &&
- qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE &&
- net->model && STREQ(net->model, "virtio")))
- return -1;
+ qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+ if (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("vhost-net is not supported with
"
+ "this QEMU binary"));
+ return -1;
+ }
+ return 0;
+ }
- return open("/dev/vhost-net", O_RDWR, 0);
+ /* If the nic model isn't virtio, don't try to open. */
+ if (!(net->model && STREQ(net->model, "virtio"))) {
+ if (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("vhost-net is only supported for
"
+ "virtio network interfaces"));
+ return -1;
+ }
+ return 0;
+ }
+
+ *vhostfd = open("/dev/vhost-net", O_RDWR);
+
+ /* If the config says explicitly to use vhost and we couldn't open it,
+ * report an error.
+ */
+ if ((*vhostfd < 0) &&
+ (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("vhost-net was requested for an interface,
"
+ "but is unavailable"));
+ return -1;
+ }
+ return 0;
}
@@ -3278,7 +3312,10 @@ qemuBuildCommandLine(virConnectPtr conn,
net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
/* Attempt to use vhost-net mode for these types of
network device */
- int vhostfd = qemuOpenVhostNet(net, qemuCmdFlags);
+ int vhostfd;
+
+ if (qemuOpenVhostNet(net, qemuCmdFlags, &vhostfd) < 0)
+ goto error;
if (vhostfd >= 0) {
virCommandTransferFD(cmd, vhostfd);
@@ -4618,6 +4655,12 @@ qemuParseCommandLineNet(virCapsPtr caps,
} else if (STREQ(keywords[i], "model")) {
def->model = values[i];
values[i] = NULL;
+ } else if (STREQ(keywords[i], "vhost")) {
+ if ((values[i] == NULL) || STREQ(values[i], "on")) {
+ def->backend = VIR_DOMAIN_NET_BACKEND_TYPE_VHOST;
+ } else if (STREQ(keywords[i], "off")) {
+ def->backend = VIR_DOMAIN_NET_BACKEND_TYPE_QEMU;
+ }
}
}
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 4c42a10..5439184 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -116,9 +116,6 @@ int qemuNetworkIfaceConnect(virConnectPtr conn,
unsigned long long qemCmdFlags)
ATTRIBUTE_NONNULL(1);
-int qemuOpenVhostNet(virDomainNetDefPtr net,
- unsigned long long qemuCmdFlags);
-
int qemuPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
--
1.7.3.4