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. --- Note that I don't really like the "name='vhost|qemu'" nomenclature, but am including it here just to get the patches on the list. I could live with it this way, or with any of the following (anyone have a strong opinion?) (note that in all cases, nothing specified means "try to use vhost, but fallback to userland if necessary") vhost='on|off' vhost='required|disabled' mode='vhost|qemu' mode='kernel|user' backend='kernel|user' (So far the strongest opinion has been for the current "name='vhost|qemu'") Oh, and also - sorry Eric, but I didn't have the brain cells left tonight to add this new bit to the documentation, and I really want to get the patch up/in now, so that will have to wait for a followup next week :-) docs/schemas/domain.rng | 13 ++++++++ src/conf/domain_conf.c | 27 +++++++++++++++++- src/conf/domain_conf.h | 10 ++++++ src/qemu/qemu_command.c | 71 +++++++++++++++++++++++++++++++++++++++-------- src/qemu/qemu_command.h | 3 -- 5 files changed, 108 insertions(+), 16 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index a524e4b..6d0654d 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 b4df38c..04ed502 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -184,6 +184,10 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST, "internal", "direct") +VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST, + "qemu", + "vhost") + VIR_ENUM_IMPL(virDomainChrChannelTarget, VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST, "guestfwd", @@ -2289,6 +2293,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; @@ -2371,6 +2376,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); @@ -2558,6 +2565,18 @@ virDomainNetDefParseXML(virCapsPtr caps, model = NULL; } + if ((backend != NULL) && + (def->model && STREQ(def->model, "virtio"))) { + int b; + if ((b = virDomainNetBackendTypeFromString(backend)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("Unkown interface <driver name='%s'> has been specified"), + backend); + goto error; + } + def->backend = b; + def->backend_specified = 1; + } if (filter != NULL) { switch (def->type) { case VIR_DOMAIN_NET_TYPE_ETHERNET: @@ -2584,6 +2603,7 @@ cleanup: VIR_FREE(script); VIR_FREE(bridge); VIR_FREE(model); + VIR_FREE(backend); VIR_FREE(filter); VIR_FREE(type); VIR_FREE(internal); @@ -6275,9 +6295,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_specified) { + 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 a459a22..451ccad 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -292,6 +292,13 @@ enum virDomainNetType { VIR_DOMAIN_NET_TYPE_LAST, }; +/* the backend driver used for virtio interfaces */ +enum virDomainNetBackendType { + 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 +317,8 @@ struct _virDomainNetDef { enum virDomainNetType type; unsigned char mac[VIR_MAC_BUFLEN]; char *model; + enum virDomainNetBackendType backend; + int backend_specified : 1; union { struct { char *dev; @@ -1264,6 +1273,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..9eb54a1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -302,24 +302,61 @@ 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_specified && + (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_specified && + (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_specified && + (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, 0); + + /* If the config says explicitly to use vhost and we couldn't open it, + * report an error. + */ + if ((*vhostfd < 0) && net->backend_specified && + (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 +3315,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 +4658,13 @@ 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; + } + def->backend_specified = 1; } } 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list