mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-08 12:41:29 +00:00
Add XML config switch to enable/disable vhost-net support
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.
This commit is contained in:
parent
9d73efdbe3
commit
175077fd70
@ -1004,6 +1004,19 @@
|
|||||||
<empty/>
|
<empty/>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<element name="driver">
|
||||||
|
<optional>
|
||||||
|
<attribute name="name">
|
||||||
|
<choice>
|
||||||
|
<value>qemu</value>
|
||||||
|
<value>vhost</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<ref name="address"/>
|
<ref name="address"/>
|
||||||
</optional>
|
</optional>
|
||||||
|
@ -185,6 +185,11 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
|
|||||||
"internal",
|
"internal",
|
||||||
"direct")
|
"direct")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
|
||||||
|
"default",
|
||||||
|
"qemu",
|
||||||
|
"vhost")
|
||||||
|
|
||||||
VIR_ENUM_IMPL(virDomainChrChannelTarget,
|
VIR_ENUM_IMPL(virDomainChrChannelTarget,
|
||||||
VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
|
VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
|
||||||
"guestfwd",
|
"guestfwd",
|
||||||
@ -2304,6 +2309,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
|
|||||||
char *address = NULL;
|
char *address = NULL;
|
||||||
char *port = NULL;
|
char *port = NULL;
|
||||||
char *model = NULL;
|
char *model = NULL;
|
||||||
|
char *backend = NULL;
|
||||||
char *filter = NULL;
|
char *filter = NULL;
|
||||||
char *internal = NULL;
|
char *internal = NULL;
|
||||||
char *devaddr = NULL;
|
char *devaddr = NULL;
|
||||||
@ -2386,6 +2392,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
|
|||||||
script = virXMLPropString(cur, "path");
|
script = virXMLPropString(cur, "path");
|
||||||
} else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
|
} else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
|
||||||
model = virXMLPropString(cur, "type");
|
model = virXMLPropString(cur, "type");
|
||||||
|
} else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
|
||||||
|
backend = virXMLPropString(cur, "name");
|
||||||
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
|
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
|
||||||
filter = virXMLPropString(cur, "filter");
|
filter = virXMLPropString(cur, "filter");
|
||||||
VIR_FREE(filterparams);
|
VIR_FREE(filterparams);
|
||||||
@ -2573,6 +2581,19 @@ virDomainNetDefParseXML(virCapsPtr caps,
|
|||||||
model = NULL;
|
model = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((backend != NULL) &&
|
||||||
|
(def->model && STREQ(def->model, "virtio"))) {
|
||||||
|
int b;
|
||||||
|
if (((b = virDomainNetBackendTypeFromString(backend)) < 0) ||
|
||||||
|
(b == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT)) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Unknown interface <driver name='%s'> "
|
||||||
|
"has been specified"),
|
||||||
|
backend);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
def->backend = b;
|
||||||
|
}
|
||||||
if (filter != NULL) {
|
if (filter != NULL) {
|
||||||
switch (def->type) {
|
switch (def->type) {
|
||||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||||
@ -2599,6 +2620,7 @@ cleanup:
|
|||||||
VIR_FREE(script);
|
VIR_FREE(script);
|
||||||
VIR_FREE(bridge);
|
VIR_FREE(bridge);
|
||||||
VIR_FREE(model);
|
VIR_FREE(model);
|
||||||
|
VIR_FREE(backend);
|
||||||
VIR_FREE(filter);
|
VIR_FREE(filter);
|
||||||
VIR_FREE(type);
|
VIR_FREE(type);
|
||||||
VIR_FREE(internal);
|
VIR_FREE(internal);
|
||||||
@ -6318,9 +6340,14 @@ virDomainNetDefFormat(virBufferPtr buf,
|
|||||||
if (def->ifname)
|
if (def->ifname)
|
||||||
virBufferEscapeString(buf, " <target dev='%s'/>\n",
|
virBufferEscapeString(buf, " <target dev='%s'/>\n",
|
||||||
def->ifname);
|
def->ifname);
|
||||||
if (def->model)
|
if (def->model) {
|
||||||
virBufferEscapeString(buf, " <model type='%s'/>\n",
|
virBufferEscapeString(buf, " <model type='%s'/>\n",
|
||||||
def->model);
|
def->model);
|
||||||
|
if (STREQ(def->model, "virtio") && def->backend) {
|
||||||
|
virBufferVSprintf(buf, " <driver name='%s'/>\n",
|
||||||
|
virDomainNetBackendTypeToString(def->backend));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (def->filter) {
|
if (def->filter) {
|
||||||
virBufferEscapeString(buf, " <filterref filter='%s'",
|
virBufferEscapeString(buf, " <filterref filter='%s'",
|
||||||
def->filter);
|
def->filter);
|
||||||
|
@ -292,6 +292,14 @@ enum virDomainNetType {
|
|||||||
VIR_DOMAIN_NET_TYPE_LAST,
|
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 */
|
/* the mode type for macvtap devices */
|
||||||
enum virDomainNetdevMacvtapType {
|
enum virDomainNetdevMacvtapType {
|
||||||
@ -310,6 +318,7 @@ struct _virDomainNetDef {
|
|||||||
enum virDomainNetType type;
|
enum virDomainNetType type;
|
||||||
unsigned char mac[VIR_MAC_BUFLEN];
|
unsigned char mac[VIR_MAC_BUFLEN];
|
||||||
char *model;
|
char *model;
|
||||||
|
enum virDomainNetBackendType backend;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
char *dev;
|
char *dev;
|
||||||
@ -1273,6 +1282,7 @@ VIR_ENUM_DECL(virDomainControllerModel)
|
|||||||
VIR_ENUM_DECL(virDomainFS)
|
VIR_ENUM_DECL(virDomainFS)
|
||||||
VIR_ENUM_DECL(virDomainFSAccessMode)
|
VIR_ENUM_DECL(virDomainFSAccessMode)
|
||||||
VIR_ENUM_DECL(virDomainNet)
|
VIR_ENUM_DECL(virDomainNet)
|
||||||
|
VIR_ENUM_DECL(virDomainNetBackend)
|
||||||
VIR_ENUM_DECL(virDomainChrDevice)
|
VIR_ENUM_DECL(virDomainChrDevice)
|
||||||
VIR_ENUM_DECL(virDomainChrChannelTarget)
|
VIR_ENUM_DECL(virDomainChrChannelTarget)
|
||||||
VIR_ENUM_DECL(virDomainChrConsoleTarget)
|
VIR_ENUM_DECL(virDomainChrConsoleTarget)
|
||||||
|
@ -302,24 +302,58 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static int
|
||||||
qemuOpenVhostNet(virDomainNetDefPtr net,
|
qemuOpenVhostNet(virDomainNetDefPtr net,
|
||||||
unsigned long long qemuCmdFlags)
|
unsigned long long qemuCmdFlags,
|
||||||
|
int *vhostfd)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* If qemu supports vhost-net mode (including the -netdev command
|
*vhostfd = -1; /* assume we won't use vhost */
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* 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 &&
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HOST &&
|
||||||
qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV &&
|
qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV &&
|
||||||
qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE &&
|
qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
||||||
net->model && STREQ(net->model, "virtio")))
|
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 -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3281,7 +3315,10 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||||||
net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
||||||
/* Attempt to use vhost-net mode for these types of
|
/* Attempt to use vhost-net mode for these types of
|
||||||
network device */
|
network device */
|
||||||
int vhostfd = qemuOpenVhostNet(net, qemuCmdFlags);
|
int vhostfd;
|
||||||
|
|
||||||
|
if (qemuOpenVhostNet(net, qemuCmdFlags, &vhostfd) < 0)
|
||||||
|
goto error;
|
||||||
if (vhostfd >= 0) {
|
if (vhostfd >= 0) {
|
||||||
virCommandTransferFD(cmd, vhostfd);
|
virCommandTransferFD(cmd, vhostfd);
|
||||||
|
|
||||||
@ -4626,6 +4663,12 @@ qemuParseCommandLineNet(virCapsPtr caps,
|
|||||||
} else if (STREQ(keywords[i], "model")) {
|
} else if (STREQ(keywords[i], "model")) {
|
||||||
def->model = values[i];
|
def->model = values[i];
|
||||||
values[i] = NULL;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,9 +111,6 @@ int qemuNetworkIfaceConnect(virConnectPtr conn,
|
|||||||
unsigned long long qemCmdFlags)
|
unsigned long long qemCmdFlags)
|
||||||
ATTRIBUTE_NONNULL(1);
|
ATTRIBUTE_NONNULL(1);
|
||||||
|
|
||||||
int qemuOpenVhostNet(virDomainNetDefPtr net,
|
|
||||||
unsigned long long qemuCmdFlags);
|
|
||||||
|
|
||||||
int qemuPhysIfaceConnect(virConnectPtr conn,
|
int qemuPhysIfaceConnect(virConnectPtr conn,
|
||||||
struct qemud_driver *driver,
|
struct qemud_driver *driver,
|
||||||
virDomainNetDefPtr net,
|
virDomainNetDefPtr net,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user