On 05/21/2013 10:18 AM, Michal Privoznik wrote: > In order to learn libvirt multiqueue several things must be done: > > 1) The '/dev/net/tun' device needs to be opened multiple times with > IFF_MULTI_QUEUE flag passed to ioctl(fd, TUNSETIFF, &ifr); > > 2) Similar, the '/dev/vhost-net' must be opened as many times as in 1) s/Similar, the/Similarly,/ > in order to keep 1:1 ratio recommended by qemu and kernel folks. > > 3) The command line construction code needs to switch from 'fd=X' to > 'fds=X:Y:...:Z' and from 'vhostfd=X' to 'vhostfds=X:Y:...:Z'. > > 4) The monitor handling code needs to learn to pass multiple FDs. > --- > src/network/bridge_driver.c | 2 +- > src/qemu/qemu_command.c | 260 ++++++++++++++++++++++++++++++-------------- > src/qemu/qemu_command.h | 13 ++- > src/qemu/qemu_hotplug.c | 98 ++++++++++++----- > src/qemu/qemu_monitor.c | 78 +++++++------ > src/qemu/qemu_monitor.h | 8 +- > src/uml/uml_conf.c | 5 +- > src/util/virnetdevtap.c | 113 ++++++++++--------- > src/util/virnetdevtap.h | 2 + > 9 files changed, 378 insertions(+), 201 deletions(-) > > diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c > index 6c6ce6d..ad4ab00 100644 > --- a/src/network/bridge_driver.c > +++ b/src/network/bridge_driver.c > @@ -2495,7 +2495,7 @@ networkStartNetworkVirtual(struct network_driver *driver, > /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */ > if (virNetDevTapCreateInBridgePort(network->def->bridge, > &macTapIfName, &network->def->mac, > - NULL, &tapfd, NULL, NULL, > + NULL, &tapfd, 1, NULL, NULL, > VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE | > VIR_NETDEV_TAP_CREATE_IFUP | > VIR_NETDEV_TAP_CREATE_PERSIST) < 0) { > diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > index 6f4028e..7059b08 100644 > --- a/src/qemu/qemu_command.c > +++ b/src/qemu/qemu_command.c > @@ -281,11 +281,12 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, > virConnectPtr conn, > virQEMUDriverPtr driver, > virDomainNetDefPtr net, > - virQEMUCapsPtr qemuCaps) > + virQEMUCapsPtr qemuCaps, > + int *tapfd, > + int *tapfdSize) > { > char *brname = NULL; > - int err; > - int tapfd = -1; > + int ret = -1; > unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP; > bool template_ifname = false; > int actualType = virDomainNetGetActualType(net); > @@ -297,7 +298,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, > virNetworkPtr network = virNetworkLookupByName(conn, > net->data.network.name); > if (!network) > - return -1; > + return ret; > > active = virNetworkIsActive(network); > if (active != 1) { > @@ -322,18 +323,18 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, > virFreeError(errobj); > > if (fail) > - return -1; > + return ret; > > } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { > if (!(brname = strdup(virDomainNetGetActualBridgeName(net)))) { > virReportOOMError(); > - return -1; > + return ret; > } > } else { > virReportError(VIR_ERR_INTERNAL_ERROR, > _("Network type %d is not supported"), > virDomainNetGetActualType(net)); > - return -1; > + return ret; > } > > if (!net->ifname || > @@ -353,69 +354,95 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, > tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; > } > > - if (cfg->privileged) > - err = virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, > - def->uuid, &tapfd, > - virDomainNetGetActualVirtPortProfile(net), > - virDomainNetGetActualVlan(net), > - tap_create_flags); > - else > - err = qemuCreateInBridgePortWithHelper(cfg, brname, > - &net->ifname, > - &tapfd, tap_create_flags); > - > - virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0); > - if (err < 0) { > - if (template_ifname) > - VIR_FREE(net->ifname); > - tapfd = -1; > + if (cfg->privileged) { > + if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, > + def->uuid, tapfd, *tapfdSize, > + virDomainNetGetActualVirtPortProfile(net), > + virDomainNetGetActualVlan(net), > + tap_create_flags) < 0) { > + virDomainAuditNetDevice(def, net, "/dev/net/tun", false); > + goto cleanup; > + } > + } else { > + if (qemuCreateInBridgePortWithHelper(cfg, brname, > + &net->ifname, > + tapfd, tap_create_flags) < 0) { > + virDomainAuditNetDevice(def, net, "/dev/net/tun", false); > + goto cleanup; > + } > + /* qemuCreateInBridgePortWithHelper can only create a single FD */ > + *tapfdSize = 1; Should we let this slide by silently? Or should we log an error and fail? > } > > - if (cfg->macFilter) { > - if ((err = networkAllowMacOnPort(driver, net->ifname, &net->mac))) { > - virReportSystemError(err, > - _("failed to add ebtables rule to allow MAC address on '%s'"), > - net->ifname); > - } > + virDomainAuditNetDevice(def, net, "/dev/net/tun", true); > + > + if (cfg->macFilter && > + (ret = networkAllowMacOnPort(driver, net->ifname, &net->mac)) < 0) { > + virReportSystemError(ret, > + _("failed to add ebtables rule " > + "to allow MAC address on '%s'"), > + net->ifname); I know this is existing code, but it's strange that this reports an error then just continues. > } > > - if (tapfd >= 0 && > - virNetDevBandwidthSet(net->ifname, > + if (virNetDevBandwidthSet(net->ifname, > virDomainNetGetActualBandwidth(net), > false) < 0) { > virReportError(VIR_ERR_INTERNAL_ERROR, > _("cannot set bandwidth limits on %s"), > net->ifname); > - VIR_FORCE_CLOSE(tapfd); > goto cleanup; > } > > - if (tapfd >= 0) { > - if ((net->filter) && (net->ifname)) { > - if (virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) > - VIR_FORCE_CLOSE(tapfd); > - } > - } > + if (net->filter && net->ifname && > + virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) > + goto cleanup; I may be in the minority here, but I like putting braces around the body when the conditional takes multiple lines too. > + > + > + ret = 0; > > cleanup: > + if (ret < 0) { > + int i; > + for (i = 0; i < *tapfdSize; i++) > + VIR_FORCE_CLOSE(tapfd[i]); > + if (template_ifname) > + VIR_FREE(net->ifname); > + } > VIR_FREE(brname); > virObjectUnref(cfg); > > - return tapfd; > + return ret; > } > > > +/** > + * qemuOpenVhostNet: > + * @def: domain definition > + * @net: network definition > + * @qemuCaps: qemu binary capabilities > + * @vhostfd: array of opened vhost-net device > + * @vhostfdSize: number of file descriptors in @vhostfd array > + * > + * Open vhost-net, multiple times - if requested. > + * In case, no vhost-net is needed, @vhostfdSize is set to 0 > + * and 0 is returned. > + * > + * Returns: 0 on success > + * -1 on failure > + */ > int > qemuOpenVhostNet(virDomainDefPtr def, > virDomainNetDefPtr net, > virQEMUCapsPtr qemuCaps, > - int *vhostfd) > + int *vhostfd, > + int *vhostfdSize) > { > - *vhostfd = -1; /* assume we won't use vhost */ > + int i; > > /* If the config says explicitly to not use vhost, return now */ > if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_QEMU) { > - return 0; > + *vhostfdSize = 0; > + return 0; > } > > /* If qemu doesn't support vhost-net mode (including the -netdev command > @@ -430,6 +457,7 @@ qemuOpenVhostNet(virDomainDefPtr def, > "this QEMU binary")); > return -1; > } > + *vhostfdSize = 0; > return 0; > } > > @@ -441,23 +469,34 @@ qemuOpenVhostNet(virDomainDefPtr def, > "virtio network interfaces")); > return -1; > } > + *vhostfdSize = 0; > return 0; > } > > - *vhostfd = open("/dev/vhost-net", O_RDWR); > - virDomainAuditNetDevice(def, net, "/dev/vhost-net", *vhostfd >= 0); > + for (i = 0; i < *vhostfdSize; i++) { > + vhostfd[i] = 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->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) { > - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > - "%s", _("vhost-net was requested for an interface, " > - "but is unavailable")); > - return -1; > + /* If the config says explicitly to use vhost and we couldn't open it, > + * report an error. > + */ > + if (vhostfd[i] < 0) { > + virDomainAuditNetDevice(def, net, "/dev/vhost-net", false); > + if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + "%s", _("vhost-net was requested for an interface, " > + "but is unavailable")); > + goto error; > + } > + } > } > + virDomainAuditNetDevice(def, net, "/dev/vhost-net", *vhostfdSize); > return 0; > + > +error: > + while (i--) > + VIR_FORCE_CLOSE(vhostfd[i]); > + > + return -1; > } > > int > @@ -4109,13 +4148,16 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, > virQEMUDriverPtr driver, > char type_sep, > int vlan, > - const char *tapfd, > - const char *vhostfd) > + char **tapfd, > + int tapfdSize, > + char **vhostfd, > + int vhostfdSize) > { > bool is_tap = false; > virBuffer buf = VIR_BUFFER_INITIALIZER; > enum virDomainNetType netType = virDomainNetGetActualType(net); > virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); > + int i; > > if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) { > virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > @@ -4134,7 +4176,19 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, > case VIR_DOMAIN_NET_TYPE_BRIDGE: > case VIR_DOMAIN_NET_TYPE_NETWORK: > case VIR_DOMAIN_NET_TYPE_DIRECT: > - virBufferAsprintf(&buf, "tap%cfd=%s", type_sep, tapfd); > + virBufferAsprintf(&buf, "tap%c", type_sep); > + /* for one tapfd 'fd=' shall be used, > + * for more than one 'fds=' is the right choice */ > + if (tapfdSize == 1) { > + virBufferAsprintf(&buf, "fd=%s", tapfd[0]); > + } else { > + virBufferAddLit(&buf, "fds="); > + for (i = 0; i < tapfdSize; i++) { > + if (i) > + virBufferAddChar(&buf, ':'); > + virBufferAdd(&buf, tapfd[i], -1); > + } > + } > type_sep = ','; > is_tap = true; > break; > @@ -4194,8 +4248,19 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, > } > > if (is_tap) { > - if (vhostfd && *vhostfd) > - virBufferAsprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd); > + if (vhostfdSize) { > + virBufferAddLit(&buf, ",vhost=on,"); > + if (vhostfdSize == 1) { > + virBufferAsprintf(&buf, "vhostfd=%s", vhostfd[0]); > + } else { > + virBufferAddLit(&buf, "vhostfds="); > + for (i = 0; i < vhostfdSize; i++) { > + if (i) > + virBufferAddChar(&buf, ':'); > + virBufferAdd(&buf, vhostfd[i], -1); > + } > + } > + } > if (net->tune.sndbuf_specified) > virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf); > } > @@ -6418,12 +6483,15 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, > enum virNetDevVPortProfileOp vmop) > { > int ret = -1; > - int tapfd = -1; > - int vhostfd = -1; > char *nic = NULL, *host = NULL; > - char *tapfdName = NULL; > - char *vhostfdName = NULL; > + int *tapfd = NULL; > + int tapfdSize = 0; > + int *vhostfd = NULL; > + int vhostfdSize = 0; > + char **tapfdName = NULL; > + char **vhostfdName = NULL; > int actualType = virDomainNetGetActualType(net); > + int i; > > if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { > /* NET_TYPE_HOSTDEV devices are really hostdev devices, so > @@ -6437,12 +6505,24 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, > > if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || > actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { > - tapfd = qemuNetworkIfaceConnect(def, conn, driver, net, qemuCaps); > - if (tapfd < 0) > + if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(tapfdName) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + > + tapfdSize = 1; > + if (qemuNetworkIfaceConnect(def, conn, driver, net, > + qemuCaps, tapfd, &tapfdSize) < 0) > goto cleanup; > } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { > - tapfd = qemuPhysIfaceConnect(def, driver, net, qemuCaps, vmop); > - if (tapfd < 0) > + if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(tapfdName) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + tapfdSize = 1; > + tapfd[0] = qemuPhysIfaceConnect(def, driver, net, > + qemuCaps, vmop); > + if (tapfd[0] < 0) > goto cleanup; > } > > @@ -6452,23 +6532,31 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, > actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { > /* Attempt to use vhost-net mode for these types of > network device */ > - if (qemuOpenVhostNet(def, net, qemuCaps, &vhostfd) < 0) > + if (VIR_ALLOC(vhostfd) < 0 || VIR_ALLOC(vhostfdName)) { > + virReportOOMError(); > + goto cleanup; > + } > + vhostfdSize = 1; > + > + if (qemuOpenVhostNet(def, net, qemuCaps, vhostfd, &vhostfdSize) < 0) > goto cleanup; > } > > - if (tapfd >= 0) { > - virCommandTransferFD(cmd, tapfd); > - if (virAsprintf(&tapfdName, "%d", tapfd) < 0) { > + for (i = 0; i < tapfdSize; i++) { > + virCommandTransferFD(cmd, tapfd[i]); > + if (virAsprintf(&tapfdName[i], "%d", tapfd[i]) < 0) { > virReportOOMError(); > goto cleanup; > } > } > > - if (vhostfd >= 0) { > - virCommandTransferFD(cmd, vhostfd); > - if (virAsprintf(&vhostfdName, "%d", vhostfd) < 0) { > - virReportOOMError(); > - goto cleanup; > + for (i = 0; i < vhostfdSize; i++) { > + if (vhostfd[i] >= 0) { > + virCommandTransferFD(cmd, vhostfd[i]); > + if (virAsprintf(&vhostfdName[i], "%d", vhostfd[i]) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > } > } > > @@ -6483,8 +6571,9 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, > if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && > virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { > if (!(host = qemuBuildHostNetStr(net, driver, > - ',', vlan, tapfdName, > - vhostfdName))) > + ',', vlan, > + tapfdName, tapfdSize, > + vhostfdName, vhostfdSize))) > goto cleanup; > virCommandAddArgList(cmd, "-netdev", host, NULL); > } > @@ -6500,8 +6589,9 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, > if (!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && > virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { > if (!(host = qemuBuildHostNetStr(net, driver, > - ',', vlan, tapfdName, > - vhostfdName))) > + ',', vlan, > + tapfdName, tapfdSize, > + vhostfdName, vhostfdSize))) > goto cleanup; > virCommandAddArgList(cmd, "-net", host, NULL); > } > @@ -6510,6 +6600,18 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, > cleanup: > if (ret < 0) > virDomainConfNWFilterTeardown(net); > + for (i = 0; i < tapfdSize; i++) { > + if (ret < 0) > + VIR_FORCE_CLOSE(tapfd[i]); > + VIR_FREE(tapfdName[i]); > + } > + for (i = 0; i < vhostfdSize; i++) { > + if (ret < 0) > + VIR_FORCE_CLOSE(vhostfd[i]); > + VIR_FREE(vhostfdName[i]); > + } > + VIR_FREE(tapfd); > + VIR_FREE(vhostfd); > VIR_FREE(nic); > VIR_FREE(host); > VIR_FREE(tapfdName); > diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h > index 133e0b2..2993448 100644 > --- a/src/qemu/qemu_command.h > +++ b/src/qemu/qemu_command.h > @@ -87,8 +87,10 @@ char * qemuBuildHostNetStr(virDomainNetDefPtr net, > virQEMUDriverPtr driver, > char type_sep, > int vlan, > - const char *tapfd, > - const char *vhostfd); > + char **tapfd, > + int tapfdSize, > + char **vhostfd, > + int vhostfdSize); > > /* Legacy, pre device support */ > char * qemuBuildNicStr(virDomainNetDefPtr net, > @@ -169,7 +171,9 @@ int qemuNetworkIfaceConnect(virDomainDefPtr def, > virConnectPtr conn, > virQEMUDriverPtr driver, > virDomainNetDefPtr net, > - virQEMUCapsPtr qemuCaps) > + virQEMUCapsPtr qemuCaps, > + int *tapfd, > + int *tapfdSize) > ATTRIBUTE_NONNULL(2); > > int qemuPhysIfaceConnect(virDomainDefPtr def, > @@ -181,7 +185,8 @@ int qemuPhysIfaceConnect(virDomainDefPtr def, > int qemuOpenVhostNet(virDomainDefPtr def, > virDomainNetDefPtr net, > virQEMUCapsPtr qemuCaps, > - int *vhostfd); > + int *vhostfd, > + int *vhostfdSize); > > int qemuNetworkPrepareDevices(virDomainDefPtr def); > > diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c > index 88c3a6c..7e50592 100644 > --- a/src/qemu/qemu_hotplug.c > +++ b/src/qemu/qemu_hotplug.c > @@ -690,10 +690,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, > virDomainNetDefPtr net) > { > qemuDomainObjPrivatePtr priv = vm->privateData; > - char *tapfd_name = NULL; > - int tapfd = -1; > - char *vhostfd_name = NULL; > - int vhostfd = -1; > + char **tapfdName = NULL; > + int *tapfd = NULL; > + int tapfdSize = 0; > + char **vhostfdName = NULL; > + int *vhostfd = NULL; > + int vhostfdSize = 0; > char *nicstr = NULL; > char *netstr = NULL; > virNetDevVPortProfilePtr vport = NULL; > @@ -704,6 +706,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, > bool iface_connected = false; > int actualType; > virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); > + int i; > > /* preallocate new slot for device */ > if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) { > @@ -739,22 +742,37 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, > > if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || > actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { > - if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net, > - priv->qemuCaps)) < 0) > + if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(vhostfd) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + tapfdSize = vhostfdSize = 1; > + if (qemuNetworkIfaceConnect(vm->def, conn, driver, net, > + priv->qemuCaps, tapfd, &tapfdSize) < 0) > goto cleanup; > iface_connected = true; > - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) > + if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) > goto cleanup; > } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { > - if ((tapfd = qemuPhysIfaceConnect(vm->def, driver, net, > - priv->qemuCaps, > - VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0) > + if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(vhostfd) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + tapfdSize = vhostfdSize = 1; > + if ((tapfd[0] = qemuPhysIfaceConnect(vm->def, driver, net, > + priv->qemuCaps, > + VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0) > goto cleanup; > iface_connected = true; > - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) > + if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) > goto cleanup; > } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { > - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) > + if (VIR_ALLOC(vhostfd) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + vhostfdSize = 1; > + if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) > goto cleanup; > } > > @@ -792,41 +810,51 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, > } > } > > - if (tapfd != -1) { > - if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0) > + if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 || > + VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + > + for (i = 0; i < tapfdSize; i++) { > + if (virAsprintf(&tapfdName[i], "fd-%s%d", net->info.alias, i) < 0) > goto no_memory; > } > > - if (vhostfd != -1) { > - if (virAsprintf(&vhostfd_name, "vhostfd-%s", net->info.alias) < 0) > + for (i = 0; i < vhostfdSize; i++) { > + if (virAsprintf(&vhostfdName[i], "vhostfd-%s%d", net->info.alias, i) < 0) > goto no_memory; > } > > if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) && > virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { > if (!(netstr = qemuBuildHostNetStr(net, driver, > - ',', -1, tapfd_name, > - vhostfd_name))) > + ',', -1, > + tapfdName, tapfdSize, > + vhostfdName, vhostfdSize))) > goto cleanup; > } else { > if (!(netstr = qemuBuildHostNetStr(net, driver, > - ' ', vlan, tapfd_name, > - vhostfd_name))) > + ' ', vlan, > + tapfdName, tapfdSize, > + vhostfdName, vhostfdSize))) > goto cleanup; > } > > qemuDomainObjEnterMonitor(driver, vm); > if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) && > virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { > - if (qemuMonitorAddNetdev(priv->mon, netstr, tapfd, tapfd_name, > - vhostfd, vhostfd_name) < 0) { > + if (qemuMonitorAddNetdev(priv->mon, netstr, > + tapfd, tapfdName, tapfdSize, > + vhostfd, vhostfdName, vhostfdSize) < 0) { > qemuDomainObjExitMonitor(driver, vm); > virDomainAuditNet(vm, NULL, net, "attach", false); > goto cleanup; > } > } else { > - if (qemuMonitorAddHostNetwork(priv->mon, netstr, tapfd, tapfd_name, > - vhostfd, vhostfd_name) < 0) { > + if (qemuMonitorAddHostNetwork(priv->mon, netstr, > + tapfd, tapfdName, tapfdSize, > + vhostfd, vhostfdName, vhostfdSize) < 0) { > qemuDomainObjExitMonitor(driver, vm); > virDomainAuditNet(vm, NULL, net, "attach", false); > goto cleanup; > @@ -834,8 +862,10 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, > } > qemuDomainObjExitMonitor(driver, vm); > > - VIR_FORCE_CLOSE(tapfd); > - VIR_FORCE_CLOSE(vhostfd); > + for (i = 0; i < tapfdSize; i++) > + VIR_FORCE_CLOSE(tapfd[i]); > + for (i = 0; i < vhostfdSize; i++) > + VIR_FORCE_CLOSE(vhostfd[i]); > > if (!virDomainObjIsActive(vm)) { > virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > @@ -931,10 +961,18 @@ cleanup: > > VIR_FREE(nicstr); > VIR_FREE(netstr); > - VIR_FREE(tapfd_name); > - VIR_FORCE_CLOSE(tapfd); > - VIR_FREE(vhostfd_name); > - VIR_FORCE_CLOSE(vhostfd); > + for (i = 0; i < tapfdSize; i++) { > + VIR_FORCE_CLOSE(tapfd[i]); > + VIR_FREE(tapfdName[i]); > + } > + VIR_FREE(tapfd); > + VIR_FREE(tapfdName); > + for (i = 0; i < vhostfdSize; i++) { > + VIR_FORCE_CLOSE(vhostfd[i]); > + VIR_FREE(vhostfdName[i]); > + } > + VIR_FREE(vhostfd); > + VIR_FREE(vhostfdName); > virObjectUnref(cfg); > > return ret; > diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c > index f6d8ef4..524eb9d 100644 > --- a/src/qemu/qemu_monitor.c > +++ b/src/qemu/qemu_monitor.c > @@ -2477,14 +2477,16 @@ cleanup: > > int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, > const char *netstr, > - int tapfd, const char *tapfd_name, > - int vhostfd, const char *vhostfd_name) > + int *tapfd, char **tapfdName, int tapfdSize, > + int *vhostfd, char **vhostfdName, int vhostfdSize) > { > int ret = -1; > - VIR_DEBUG("mon=%p netstr=%s tapfd=%d tapfd_name=%s " > - "vhostfd=%d vhostfd_name=%s", > - mon, netstr, tapfd, NULLSTR(tapfd_name), > - vhostfd, NULLSTR(vhostfd_name)); > + int i = 0, j = 0; > + > + VIR_DEBUG("mon=%p netstr=%s tapfd=%p tapfdName=%p tapfdSize=%d " > + "vhostfd=%p vhostfdName=%p vhostfdSize=%d", > + mon, netstr, tapfd, tapfdName, tapfdSize, > + vhostfd, vhostfdName, vhostfdSize); > > if (!mon) { > virReportError(VIR_ERR_INVALID_ARG, "%s", > @@ -2492,12 +2494,13 @@ int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, > return -1; > } > > - if (tapfd >= 0 && qemuMonitorSendFileHandle(mon, tapfd_name, tapfd) < 0) > - return -1; > - if (vhostfd >= 0 && > - qemuMonitorSendFileHandle(mon, vhostfd_name, vhostfd) < 0) { > - vhostfd = -1; > - goto cleanup; > + for (i = 0; i < tapfdSize; i++) { > + if (qemuMonitorSendFileHandle(mon, tapfdName[i], tapfd[i]) < 0) > + goto cleanup; > + } > + for (j = 0; j < vhostfdSize; j++) { > + if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0) > + goto cleanup; > } > > if (mon->json) > @@ -2508,10 +2511,14 @@ int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, > > cleanup: > if (ret < 0) { > - if (tapfd >= 0 && qemuMonitorCloseFileHandle(mon, tapfd_name) < 0) > - VIR_WARN("failed to close device handle '%s'", tapfd_name); > - if (vhostfd >= 0 && qemuMonitorCloseFileHandle(mon, vhostfd_name) < 0) > - VIR_WARN("failed to close device handle '%s'", vhostfd_name); > + while (i--) { > + if (qemuMonitorCloseFileHandle(mon, tapfdName[i]) < 0) > + VIR_WARN("failed to close device handle '%s'", tapfdName[i]); > + } > + while (j--) { > + if (qemuMonitorCloseFileHandle(mon, vhostfdName[j]) < 0) > + VIR_WARN("failed to close device handle '%s'", vhostfdName[j]); > + } > } > > return ret; > @@ -2543,14 +2550,16 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, > > int qemuMonitorAddNetdev(qemuMonitorPtr mon, > const char *netdevstr, > - int tapfd, const char *tapfd_name, > - int vhostfd, const char *vhostfd_name) > + int *tapfd, char **tapfdName, int tapfdSize, > + int *vhostfd, char **vhostfdName, int vhostfdSize) > { > int ret = -1; > - VIR_DEBUG("mon=%p netdevstr=%s tapfd=%d tapfd_name=%s " > - "vhostfd=%d vhostfd_name=%s", > - mon, netdevstr, tapfd, NULLSTR(tapfd_name), > - vhostfd, NULLSTR(vhostfd_name)); > + int i = 0, j = 0; > + > + VIR_DEBUG("mon=%p netdevstr=%s tapfd=%p tapfdName=%p tapfdSize=%d" > + "vhostfd=%p vhostfdName=%p vhostfdSize=%d", > + mon, netdevstr, tapfd, tapfdName, tapfdSize, > + vhostfd, vhostfdName, tapfdSize); > > if (!mon) { > virReportError(VIR_ERR_INVALID_ARG, "%s", > @@ -2558,12 +2567,13 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon, > return -1; > } > > - if (tapfd >= 0 && qemuMonitorSendFileHandle(mon, tapfd_name, tapfd) < 0) > - return -1; > - if (vhostfd >= 0 && > - qemuMonitorSendFileHandle(mon, vhostfd_name, vhostfd) < 0) { > - vhostfd = -1; > - goto cleanup; > + for (i = 0; i < tapfdSize; i++) { > + if (qemuMonitorSendFileHandle(mon, tapfdName[i], tapfd[i]) < 0) > + goto cleanup; > + } > + for (j = 0; j < vhostfdSize; j++) { > + if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0) > + goto cleanup; > } > > if (mon->json) > @@ -2573,10 +2583,14 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon, > > cleanup: > if (ret < 0) { > - if (tapfd >= 0 && qemuMonitorCloseFileHandle(mon, tapfd_name) < 0) > - VIR_WARN("failed to close device handle '%s'", tapfd_name); > - if (vhostfd >= 0 && qemuMonitorCloseFileHandle(mon, vhostfd_name) < 0) > - VIR_WARN("failed to close device handle '%s'", vhostfd_name); > + while (i--) { > + if (qemuMonitorCloseFileHandle(mon, tapfdName[i]) < 0) > + VIR_WARN("failed to close device handle '%s'", tapfdName[i]); > + } > + while (j--) { > + if (qemuMonitorCloseFileHandle(mon, vhostfdName[j]) < 0) > + VIR_WARN("failed to close device handle '%s'", vhostfdName[j]); > + } > } > > return ret; > diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h > index 8f9c182..a607712 100644 > --- a/src/qemu/qemu_monitor.h > +++ b/src/qemu/qemu_monitor.h > @@ -501,8 +501,8 @@ int qemuMonitorRemoveFd(qemuMonitorPtr mon, int fdset, int fd); > */ > int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, > const char *netstr, > - int tapfd, const char *tapfd_name, > - int vhostfd, const char *vhostfd_name); > + int *tapfd, char **tapfdName, int tapfdSize, > + int *vhostfd, char **vhostfdName, int vhostfdSize); > > int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, > int vlan, > @@ -510,8 +510,8 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, > > int qemuMonitorAddNetdev(qemuMonitorPtr mon, > const char *netdevstr, > - int tapfd, const char *tapfd_name, > - int vhostfd, const char *vhostfd_name); > + int *tapfd, char **tapfdName, int tapfdSize, > + int *vhostfd, char **vhostfdName, int vhostfdSize); > > int qemuMonitorRemoveNetdev(qemuMonitorPtr mon, > const char *alias); > diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c > index 52b705c..3fda7e4 100644 > --- a/src/uml/uml_conf.c > +++ b/src/uml/uml_conf.c > @@ -109,6 +109,7 @@ umlConnectTapDevice(virConnectPtr conn, > const char *bridge) > { > bool template_ifname = false; > + int tapfd; > > if (!net->ifname || > STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) || > @@ -121,7 +122,7 @@ umlConnectTapDevice(virConnectPtr conn, > } > > if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, &net->mac, > - vm->uuid, NULL, > + vm->uuid, &tapfd, 1, > virDomainNetGetActualVirtPortProfile(net), > virDomainNetGetActualVlan(net), > VIR_NETDEV_TAP_CREATE_IFUP | > @@ -139,9 +140,11 @@ umlConnectTapDevice(virConnectPtr conn, > } > } > > + VIR_FORCE_CLOSE(tapfd); > return 0; > > error: > + VIR_FORCE_CLOSE(tapfd); > return -1; > } > > diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c > index 75599db..aa41b9c 100644 > --- a/src/util/virnetdevtap.c > +++ b/src/util/virnetdevtap.c > @@ -140,7 +140,8 @@ virNetDevProbeVnetHdr(int tapfd) > /** > * virNetDevTapCreate: > * @ifname: the interface name > - * @tapfd: file descriptor return value for the new tap device > + * @tapfds: array of file descriptors return value for the new tap device > + * @tapfdSize: number of file descriptors in @tapfd > * @flags: OR of virNetDevTapCreateFlags. Only one flag is recognized: > * > * VIR_NETDEV_TAP_CREATE_VNET_HDR > @@ -148,76 +149,85 @@ virNetDevProbeVnetHdr(int tapfd) > * VIR_NETDEV_TAP_CREATE_PERSIST > * - The device will persist after the file descriptor is closed > * > - * Creates a tap interface. > - * If the @tapfd parameter is supplied, the open tap device file descriptor > - * will be returned, otherwise the TAP device will be closed. The caller must > - * use virNetDevTapDelete to remove a persistent TAP device when it is no > - * longer needed. > + * Creates a tap interface. The caller must use virNetDevTapDelete to > + * remove a persistent TAP device when it is no longer needed. In case > + * @tapfdSize is greater than one, multiqueue extension is requested > + * from kernel. > * > * Returns 0 in case of success or -1 on failure. > */ > int virNetDevTapCreate(char **ifname, > int *tapfd, > + int tapfdSize, > unsigned int flags) > { > - int fd; > + int i; > struct ifreq ifr; > int ret = -1; > - > - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { > - virReportSystemError(errno, "%s", > - _("Unable to open /dev/net/tun, is tun module loaded?")); > - return -1; > - } > + int fd; > > memset(&ifr, 0, sizeof(ifr)); > + for (i = 0; i < tapfdSize; i++) { > + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { > + virReportSystemError(errno, "%s", > + _("Unable to open /dev/net/tun, is tun module loaded?")); > + goto cleanup; > + } > > - ifr.ifr_flags = IFF_TAP|IFF_NO_PI; > + memset(&ifr, 0, sizeof(ifr)); > + > + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; > + /* If tapfdSize is greater than one, request multiqueue */ > + if (tapfdSize > 1) > + ifr.ifr_flags |= IFF_MULTI_QUEUE; > > # ifdef IFF_VNET_HDR > - if ((flags & VIR_NETDEV_TAP_CREATE_VNET_HDR) && > - virNetDevProbeVnetHdr(fd)) > - ifr.ifr_flags |= IFF_VNET_HDR; > + if ((flags & VIR_NETDEV_TAP_CREATE_VNET_HDR) && > + virNetDevProbeVnetHdr(fd)) > + ifr.ifr_flags |= IFF_VNET_HDR; > # endif > > - if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) { > - virReportSystemError(ERANGE, > - _("Network interface name '%s' is too long"), > - *ifname); > - goto cleanup; > + if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) { > + virReportSystemError(ERANGE, > + _("Network interface name '%s' is too long"), > + *ifname); > + goto cleanup; > > - } > + } > > - if (ioctl(fd, TUNSETIFF, &ifr) < 0) { > - virReportSystemError(errno, > - _("Unable to create tap device %s"), > - NULLSTR(*ifname)); > - goto cleanup; > - } > + if (ioctl(fd, TUNSETIFF, &ifr) < 0) { > + virReportSystemError(errno, > + _("Unable to create tap device %s"), > + NULLSTR(*ifname)); > + goto cleanup; > + } > > - if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) && > - (errno = ioctl(fd, TUNSETPERSIST, 1))) { > - virReportSystemError(errno, > - _("Unable to set tap device %s to persistent"), > - NULLSTR(*ifname)); > - goto cleanup; > - } > + if (i == 0) { > + /* In case we are looping more than once, set other > + * TAPs to have the same name */ > + VIR_FREE(*ifname); > + if (ifr.ifr_name && VIR_STRDUP(*ifname, ifr.ifr_name) < 0) > + goto cleanup; > + } > > - VIR_FREE(*ifname); > - if (!(*ifname = strdup(ifr.ifr_name))) { > - virReportOOMError(); > - goto cleanup; > + if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) && > + (errno = ioctl(fd, TUNSETPERSIST, 1))) { > + virReportSystemError(errno, > + _("Unable to set tap device %s to persistent"), > + NULLSTR(*ifname)); > + goto cleanup; > + } > + tapfd[i] = fd; > } > - if (tapfd) > - *tapfd = fd; > - else > - VIR_FORCE_CLOSE(fd); > > ret = 0; > > cleanup: > - if (ret < 0) > + if (ret < 0) { > VIR_FORCE_CLOSE(fd); > + while (i--) > + VIR_FORCE_CLOSE(tapfd[i]); > + } > > return ret; > } > @@ -266,6 +276,7 @@ cleanup: > #else /* ! TUNSETIFF */ > int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED, > int *tapfd ATTRIBUTE_UNUSED, > + int tapfdSize ATTRIBUTE_UNUSED, > unsigned int flags ATTRIBUTE_UNUSED) > { > virReportSystemError(ENOSYS, "%s", > @@ -286,7 +297,8 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED) > * @brname: the bridge name > * @ifname: the interface name (or name template) > * @macaddr: desired MAC address > - * @tapfd: file descriptor return value for the new tap device > + * @tapfd: array of file descriptor return value for the new tap device > + * @tapfdSize: number of file descriptors in @tapfd > * @virtPortProfile: bridge/port specific configuration > * @flags: OR of virNetDevTapCreateFlags: > > @@ -314,6 +326,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, > const virMacAddrPtr macaddr, > const unsigned char *vmuuid, > int *tapfd, > + int tapfdSize, > virNetDevVPortProfilePtr virtPortProfile, > virNetDevVlanPtr virtVlan, > unsigned int flags) > @@ -321,7 +334,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, > virMacAddr tapmac; > char macaddrstr[VIR_MAC_STRING_BUFLEN]; > > - if (virNetDevTapCreate(ifname, tapfd, flags) < 0) > + if (virNetDevTapCreate(ifname, tapfd, tapfdSize, flags) < 0) > return -1; > > /* We need to set the interface MAC before adding it > @@ -372,9 +385,9 @@ int virNetDevTapCreateInBridgePort(const char *brname, > > return 0; > > - error: > - if (tapfd) > - VIR_FORCE_CLOSE(*tapfd); > +error: > + while (tapfdSize) > + VIR_FORCE_CLOSE(tapfd[--tapfdSize]); > > return -1; > } > diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h > index 6bfc80c..cb6c284 100644 > --- a/src/util/virnetdevtap.h > +++ b/src/util/virnetdevtap.h > @@ -29,6 +29,7 @@ > > int virNetDevTapCreate(char **ifname, > int *tapfd, > + int tapfdSize, > unsigned int flags) > ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; > > @@ -55,6 +56,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, > const virMacAddrPtr macaddr, > const unsigned char *vmuuid, > int *tapfd, > + int tapfdSize, > virNetDevVPortProfilePtr virtPortProfile, > virNetDevVlanPtr virtVlan, > unsigned int flags) ACK. (I'm undecided if we should error out if multi-queue is requested when running non-privileged, and I don't care enough about the extra braces to require you to add them (and it's not in the official coding style)) -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list