<empty/>
</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>
"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",
char *address = NULL;
char *port = NULL;
char *model = NULL;
+ char *backend = NULL;
char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
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);
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) {
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_ETHERNET:
VIR_FREE(script);
VIR_FREE(bridge);
VIR_FREE(model);
+ VIR_FREE(backend);
VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
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);
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 {
enum virDomainNetType type;
unsigned char mac[VIR_MAC_BUFLEN];
char *model;
+ enum virDomainNetBackendType backend;
union {
struct {
char *dev;
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)
}
-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;
}
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);
} 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;
+ }
}
}
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,