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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list