Attempt to turn on vhost-net mode for devices of type NETWORK, BRIDGE,
and DIRECT (macvtap).
* src/qemu/qemu_conf.h: add vhostfd to qemuBuildHostNetStr prototype
add qemudOpenVhostNet prototype
new flag to set when :,vhost=" found in qemu help
* src/qemu/qemu_conf.c: * set QEMUD_CMD_FLAG_VNET_HOST is ",vhost=" found
in qemu help
* qemudOpenVhostNet - opens /dev/vhost-net to pass
to qemu if everything is in place to use it.
* qemuBuildHostNetStr - add vhostfd to commandline
if it's not empty (higher levels decide whether
or not to fill it in)
* qemudBuildCommandLine - if /dev/vhost-net is
successfully opened, add its fd to tapfds array
so it isn't closed on qemu exec, and populate
vhostfd_name to be passed in to commandline
builder.
* src/qemu/qemu_driver.c: add filler 0 for new arg to qemuBuildHostNetStr,
along with a note that this must be implemented
in order for hot-plug of vhost-net virtio devices
to work properly (once qemu "netdev_add" monitor
command is implemented).
---
The original version of this patch was doing a double close of tapfd
in case of error, now fixed.
In the meantime, similarities in the code made me wonder if vhost-net
mode was supported by macvtap. I asked and found that it should work,
so I tried, and it does! This version adds support for that type of
interface.
Note that these changes are still a NOP until the bit of code checking for
"-netdev" in the qemu help and enabling QEMUD_CMD_FLAG_NETDEV in
(qemu_conf.c:qemudComputeCmdFlags()) is uncommented. You can already
do this by hand if you don't care about hot-plug/unplug of network
devices, but checking in that change needs to wait until the
netdev_add command is available in qemu (patches are
submitted/in-process of submission to upstream qemu for that).
Also, I've found that only a single network device per qemu process
can take advantage of vhost-net. Any beyond that will result in qemu
printing out the following warning:
Error binding host notifier: 28
unable to start vhost net: 28: falling back on userspace virtio
src/qemu/qemu_conf.c | 59 +++++++++++++++++++++++++++++++++++++++++++----
src/qemu/qemu_conf.h | 8 +++++-
src/qemu/qemu_driver.c | 3 +-
3 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index fb23c52..f2d36f7 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1183,6 +1183,10 @@ static unsigned long long qemudComputeCmdFlags(const char *help,
if (is_kvm && (version >= 10000 || kvm_version >= 74))
flags |= QEMUD_CMD_FLAG_VNET_HDR;
+ if (is_kvm && strstr(help, ",vhost=")) {
+ flags |= QEMUD_CMD_FLAG_VNET_HOST;
+ }
+
/*
* Handling of -incoming arg with varying features
* -incoming tcp (kvm >= 79, qemu >= 0.10.0)
@@ -1597,6 +1601,27 @@ cleanup:
}
+int
+qemudOpenVhostNet(virDomainNetDefPtr net,
+ unsigned long long qemuCmdFlags)
+{
+
+ /* 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.
+ */
+
+ 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;
+
+ return open("/dev/vhost-net", O_RDWR, 0);
+}
+
+
static int qemuDomainDeviceAliasIndex(virDomainDeviceInfoPtr info,
const char *prefix)
{
@@ -2611,7 +2636,8 @@ char *
qemuBuildHostNetStr(virDomainNetDefPtr net,
char type_sep,
int vlan,
- const char *tapfd)
+ const char *tapfd,
+ const char *vhostfd)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -2680,6 +2706,10 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
type_sep, net->info.alias);
}
+ if (vhostfd && *vhostfd) {
+ virBufferVSprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd);
+ }
+
if (virBufferError(&buf)) {
virBufferFreeAndReset(&buf);
virReportOOMError();
@@ -3828,6 +3858,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
virDomainNetDefPtr net = def->nets[i];
char *nic, *host;
char tapfd_name[50];
+ char vhostfd_name[50] = "";
int vlan;
/* VLANs are not used with -netdev, so don't record them */
@@ -3871,6 +3902,24 @@ int qemudBuildCommandLine(virConnectPtr conn,
goto no_memory;
}
+ if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
+ net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
+ /* Attempt to use vhost-net mode for these types of
+ network device */
+ int vhostfd = qemudOpenVhostNet(net, qemuCmdFlags);
+ if (vhostfd >= 0) {
+ if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
+ close(vhostfd);
+ goto no_memory;
+ }
+
+ (*tapfds)[(*ntapfds)++] = vhostfd;
+ if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d",
vhostfd)
+ >= sizeof(vhostfd_name))
+ goto no_memory;
+ }
+ }
/* Possible combinations:
*
* 1. Old way: -net nic,model=e1000,vlan=1 -net tap,vlan=1
@@ -3882,8 +3931,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
ADD_ARG_LIT("-netdev");
- if (!(host = qemuBuildHostNetStr(net, ',',
- vlan, tapfd_name)))
+ if (!(host = qemuBuildHostNetStr(net, ',', vlan,
+ tapfd_name, vhostfd_name)))
goto error;
ADD_ARG(host);
}
@@ -3901,8 +3950,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
if (!((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))) {
ADD_ARG_LIT("-net");
- if (!(host = qemuBuildHostNetStr(net, ',',
- vlan, tapfd_name)))
+ if (!(host = qemuBuildHostNetStr(net, ',', vlan,
+ tapfd_name, vhostfd_name)))
goto error;
ADD_ARG(host);
}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 6a9de5e..2d62cc4 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -83,6 +83,7 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_SMP_TOPOLOGY = (1 << 28), /* Is sockets=s,cores=c,threads=t
available for -smp? */
QEMUD_CMD_FLAG_NETDEV = (1 << 29), /* The -netdev flag &
netdev_add/remove monitor commands */
QEMUD_CMD_FLAG_RTC = (1 << 30), /* The -rtc flag for clock options
*/
+ QEMUD_CMD_FLAG_VNET_HOST = (1 << 31), /* vnet-host support is available in
qemu */
};
/* Main driver state */
@@ -200,7 +201,8 @@ int qemudBuildCommandLine (virConnectPtr conn,
char * qemuBuildHostNetStr(virDomainNetDefPtr net,
char type_sep,
int vlan,
- const char *tapfd);
+ const char *tapfd,
+ const char *vhostfd);
/* Legacy, pre device support */
char * qemuBuildNicStr(virDomainNetDefPtr net,
@@ -252,6 +254,10 @@ int qemudNetworkIfaceConnect (virConnectPtr conn,
unsigned long long qemuCmdFlags)
ATTRIBUTE_NONNULL(1);
+int
+qemudOpenVhostNet(virDomainNetDefPtr net,
+ unsigned long long qemuCmdFlags);
+
int qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 67d9ade..a5bf396 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6370,8 +6370,9 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
qemuDomainObjExitMonitorWithDriver(driver, vm);
}
+ /* FIXME - need to support vhost-net here (5th arg) */
if (!(netstr = qemuBuildHostNetStr(net, ' ',
- vlan, tapfd_name)))
+ vlan, tapfd_name, 0)))
goto try_tapfd_close;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
--
1.7.0.1