提交 1f24f682 编写于 作者: M Michal Privoznik

qemu: Adapt qemuBuildInterfaceCommandLine to to multiqueue net

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) Similarly, '/dev/vhost-net' must be opened as many times as in 1)
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.
上级 565c07f1
...@@ -2495,7 +2495,7 @@ networkStartNetworkVirtual(struct network_driver *driver, ...@@ -2495,7 +2495,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
/* Keep tun fd open and interface up to allow for IPv6 DAD to happen */ /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
if (virNetDevTapCreateInBridgePort(network->def->bridge, if (virNetDevTapCreateInBridgePort(network->def->bridge,
&macTapIfName, &network->def->mac, &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_USE_MAC_FOR_BRIDGE |
VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_IFUP |
VIR_NETDEV_TAP_CREATE_PERSIST) < 0) { VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
......
...@@ -281,11 +281,12 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, ...@@ -281,11 +281,12 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
virConnectPtr conn, virConnectPtr conn,
virQEMUDriverPtr driver, virQEMUDriverPtr driver,
virDomainNetDefPtr net, virDomainNetDefPtr net,
virQEMUCapsPtr qemuCaps) virQEMUCapsPtr qemuCaps,
int *tapfd,
int *tapfdSize)
{ {
char *brname = NULL; char *brname = NULL;
int err; int ret = -1;
int tapfd = -1;
unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP; unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
bool template_ifname = false; bool template_ifname = false;
int actualType = virDomainNetGetActualType(net); int actualType = virDomainNetGetActualType(net);
...@@ -297,7 +298,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, ...@@ -297,7 +298,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
virNetworkPtr network = virNetworkLookupByName(conn, virNetworkPtr network = virNetworkLookupByName(conn,
net->data.network.name); net->data.network.name);
if (!network) if (!network)
return -1; return ret;
active = virNetworkIsActive(network); active = virNetworkIsActive(network);
if (active != 1) { if (active != 1) {
...@@ -322,18 +323,18 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, ...@@ -322,18 +323,18 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
virFreeError(errobj); virFreeError(errobj);
if (fail) if (fail)
return -1; return ret;
} else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { } else if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
if (!(brname = strdup(virDomainNetGetActualBridgeName(net)))) { if (!(brname = strdup(virDomainNetGetActualBridgeName(net)))) {
virReportOOMError(); virReportOOMError();
return -1; return ret;
} }
} else { } else {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Network type %d is not supported"), _("Network type %d is not supported"),
virDomainNetGetActualType(net)); virDomainNetGetActualType(net));
return -1; return ret;
} }
if (!net->ifname || if (!net->ifname ||
...@@ -353,69 +354,98 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, ...@@ -353,69 +354,98 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR; tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
} }
if (cfg->privileged) if (cfg->privileged) {
err = virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac, if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
def->uuid, &tapfd, def->uuid, tapfd, *tapfdSize,
virDomainNetGetActualVirtPortProfile(net), virDomainNetGetActualVirtPortProfile(net),
virDomainNetGetActualVlan(net), virDomainNetGetActualVlan(net),
tap_create_flags); tap_create_flags) < 0) {
else virDomainAuditNetDevice(def, net, "/dev/net/tun", false);
err = qemuCreateInBridgePortWithHelper(cfg, brname, goto cleanup;
&net->ifname, }
&tapfd, tap_create_flags); } else {
if (qemuCreateInBridgePortWithHelper(cfg, brname,
virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0); &net->ifname,
if (err < 0) { tapfd, tap_create_flags) < 0) {
if (template_ifname) virDomainAuditNetDevice(def, net, "/dev/net/tun", false);
VIR_FREE(net->ifname); goto cleanup;
tapfd = -1; }
/* qemuCreateInBridgePortWithHelper can only create a single FD */
if (*tapfdSize > 1) {
VIR_WARN("Ignoring multiqueue network request");
*tapfdSize = 1;
}
} }
if (cfg->macFilter) { virDomainAuditNetDevice(def, net, "/dev/net/tun", true);
if ((err = networkAllowMacOnPort(driver, net->ifname, &net->mac))) {
virReportSystemError(err, if (cfg->macFilter &&
_("failed to add ebtables rule to allow MAC address on '%s'"), (ret = networkAllowMacOnPort(driver, net->ifname, &net->mac)) < 0) {
net->ifname); virReportSystemError(ret,
} _("failed to add ebtables rule "
"to allow MAC address on '%s'"),
net->ifname);
} }
if (tapfd >= 0 && if (virNetDevBandwidthSet(net->ifname,
virNetDevBandwidthSet(net->ifname,
virDomainNetGetActualBandwidth(net), virDomainNetGetActualBandwidth(net),
false) < 0) { false) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot set bandwidth limits on %s"), _("cannot set bandwidth limits on %s"),
net->ifname); net->ifname);
VIR_FORCE_CLOSE(tapfd);
goto cleanup; goto cleanup;
} }
if (tapfd >= 0) { if (net->filter && net->ifname &&
if ((net->filter) && (net->ifname)) { virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) {
if (virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) goto cleanup;
VIR_FORCE_CLOSE(tapfd);
}
} }
ret = 0;
cleanup: 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); VIR_FREE(brname);
virObjectUnref(cfg); 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 int
qemuOpenVhostNet(virDomainDefPtr def, qemuOpenVhostNet(virDomainDefPtr def,
virDomainNetDefPtr net, virDomainNetDefPtr net,
virQEMUCapsPtr qemuCaps, 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 the config says explicitly to not use vhost, return now */
if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_QEMU) { 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 /* If qemu doesn't support vhost-net mode (including the -netdev command
...@@ -430,6 +460,7 @@ qemuOpenVhostNet(virDomainDefPtr def, ...@@ -430,6 +460,7 @@ qemuOpenVhostNet(virDomainDefPtr def,
"this QEMU binary")); "this QEMU binary"));
return -1; return -1;
} }
*vhostfdSize = 0;
return 0; return 0;
} }
...@@ -441,23 +472,34 @@ qemuOpenVhostNet(virDomainDefPtr def, ...@@ -441,23 +472,34 @@ qemuOpenVhostNet(virDomainDefPtr def,
"virtio network interfaces")); "virtio network interfaces"));
return -1; return -1;
} }
*vhostfdSize = 0;
return 0; return 0;
} }
*vhostfd = open("/dev/vhost-net", O_RDWR); for (i = 0; i < *vhostfdSize; i++) {
virDomainAuditNetDevice(def, net, "/dev/vhost-net", *vhostfd >= 0); vhostfd[i] = open("/dev/vhost-net", O_RDWR);
/* If the config says explicitly to use vhost and we couldn't open it, /* If the config says explicitly to use vhost and we couldn't open it,
* report an error. * report an error.
*/ */
if ((*vhostfd < 0) && if (vhostfd[i] < 0) {
(net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) { virDomainAuditNetDevice(def, net, "/dev/vhost-net", false);
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) {
"%s", _("vhost-net was requested for an interface, " virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"but is unavailable")); "%s", _("vhost-net was requested for an interface, "
return -1; "but is unavailable"));
goto error;
}
}
} }
virDomainAuditNetDevice(def, net, "/dev/vhost-net", *vhostfdSize);
return 0; return 0;
error:
while (i--)
VIR_FORCE_CLOSE(vhostfd[i]);
return -1;
} }
int int
...@@ -4109,13 +4151,16 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, ...@@ -4109,13 +4151,16 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
virQEMUDriverPtr driver, virQEMUDriverPtr driver,
char type_sep, char type_sep,
int vlan, int vlan,
const char *tapfd, char **tapfd,
const char *vhostfd) int tapfdSize,
char **vhostfd,
int vhostfdSize)
{ {
bool is_tap = false; bool is_tap = false;
virBuffer buf = VIR_BUFFER_INITIALIZER; virBuffer buf = VIR_BUFFER_INITIALIZER;
enum virDomainNetType netType = virDomainNetGetActualType(net); enum virDomainNetType netType = virDomainNetGetActualType(net);
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
int i;
if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) { if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
...@@ -4134,7 +4179,19 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, ...@@ -4134,7 +4179,19 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_NETWORK:
case VIR_DOMAIN_NET_TYPE_DIRECT: 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 = ','; type_sep = ',';
is_tap = true; is_tap = true;
break; break;
...@@ -4194,8 +4251,19 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, ...@@ -4194,8 +4251,19 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
} }
if (is_tap) { if (is_tap) {
if (vhostfd && *vhostfd) if (vhostfdSize) {
virBufferAsprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd); 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) if (net->tune.sndbuf_specified)
virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf); virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf);
} }
...@@ -6431,12 +6499,15 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -6431,12 +6499,15 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
enum virNetDevVPortProfileOp vmop) enum virNetDevVPortProfileOp vmop)
{ {
int ret = -1; int ret = -1;
int tapfd = -1;
int vhostfd = -1;
char *nic = NULL, *host = NULL; char *nic = NULL, *host = NULL;
char *tapfdName = NULL; int *tapfd = NULL;
char *vhostfdName = NULL; int tapfdSize = 0;
int *vhostfd = NULL;
int vhostfdSize = 0;
char **tapfdName = NULL;
char **vhostfdName = NULL;
int actualType = virDomainNetGetActualType(net); int actualType = virDomainNetGetActualType(net);
int i;
if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* NET_TYPE_HOSTDEV devices are really hostdev devices, so /* NET_TYPE_HOSTDEV devices are really hostdev devices, so
...@@ -6450,12 +6521,24 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -6450,12 +6521,24 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
tapfd = qemuNetworkIfaceConnect(def, conn, driver, net, qemuCaps); if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(tapfdName) < 0) {
if (tapfd < 0) virReportOOMError();
goto cleanup;
}
tapfdSize = 1;
if (qemuNetworkIfaceConnect(def, conn, driver, net,
qemuCaps, tapfd, &tapfdSize) < 0)
goto cleanup; goto cleanup;
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
tapfd = qemuPhysIfaceConnect(def, driver, net, qemuCaps, vmop); if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(tapfdName) < 0) {
if (tapfd < 0) virReportOOMError();
goto cleanup;
}
tapfdSize = 1;
tapfd[0] = qemuPhysIfaceConnect(def, driver, net,
qemuCaps, vmop);
if (tapfd[0] < 0)
goto cleanup; goto cleanup;
} }
...@@ -6465,23 +6548,31 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -6465,23 +6548,31 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { actualType == 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 */
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; goto cleanup;
} }
if (tapfd >= 0) { for (i = 0; i < tapfdSize; i++) {
virCommandTransferFD(cmd, tapfd); virCommandTransferFD(cmd, tapfd[i]);
if (virAsprintf(&tapfdName, "%d", tapfd) < 0) { if (virAsprintf(&tapfdName[i], "%d", tapfd[i]) < 0) {
virReportOOMError(); virReportOOMError();
goto cleanup; goto cleanup;
} }
} }
if (vhostfd >= 0) { for (i = 0; i < vhostfdSize; i++) {
virCommandTransferFD(cmd, vhostfd); if (vhostfd[i] >= 0) {
if (virAsprintf(&vhostfdName, "%d", vhostfd) < 0) { virCommandTransferFD(cmd, vhostfd[i]);
virReportOOMError(); if (virAsprintf(&vhostfdName[i], "%d", vhostfd[i]) < 0) {
goto cleanup; virReportOOMError();
goto cleanup;
}
} }
} }
...@@ -6496,8 +6587,9 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -6496,8 +6587,9 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
if (!(host = qemuBuildHostNetStr(net, driver, if (!(host = qemuBuildHostNetStr(net, driver,
',', vlan, tapfdName, ',', vlan,
vhostfdName))) tapfdName, tapfdSize,
vhostfdName, vhostfdSize)))
goto cleanup; goto cleanup;
virCommandAddArgList(cmd, "-netdev", host, NULL); virCommandAddArgList(cmd, "-netdev", host, NULL);
} }
...@@ -6513,8 +6605,9 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -6513,8 +6605,9 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
if (!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && if (!(virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
if (!(host = qemuBuildHostNetStr(net, driver, if (!(host = qemuBuildHostNetStr(net, driver,
',', vlan, tapfdName, ',', vlan,
vhostfdName))) tapfdName, tapfdSize,
vhostfdName, vhostfdSize)))
goto cleanup; goto cleanup;
virCommandAddArgList(cmd, "-net", host, NULL); virCommandAddArgList(cmd, "-net", host, NULL);
} }
...@@ -6523,6 +6616,18 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -6523,6 +6616,18 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
cleanup: cleanup:
if (ret < 0) if (ret < 0)
virDomainConfNWFilterTeardown(net); 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(nic);
VIR_FREE(host); VIR_FREE(host);
VIR_FREE(tapfdName); VIR_FREE(tapfdName);
......
...@@ -87,8 +87,10 @@ char * qemuBuildHostNetStr(virDomainNetDefPtr net, ...@@ -87,8 +87,10 @@ char * qemuBuildHostNetStr(virDomainNetDefPtr net,
virQEMUDriverPtr driver, virQEMUDriverPtr driver,
char type_sep, char type_sep,
int vlan, int vlan,
const char *tapfd, char **tapfd,
const char *vhostfd); int tapfdSize,
char **vhostfd,
int vhostfdSize);
/* Legacy, pre device support */ /* Legacy, pre device support */
char * qemuBuildNicStr(virDomainNetDefPtr net, char * qemuBuildNicStr(virDomainNetDefPtr net,
...@@ -169,7 +171,9 @@ int qemuNetworkIfaceConnect(virDomainDefPtr def, ...@@ -169,7 +171,9 @@ int qemuNetworkIfaceConnect(virDomainDefPtr def,
virConnectPtr conn, virConnectPtr conn,
virQEMUDriverPtr driver, virQEMUDriverPtr driver,
virDomainNetDefPtr net, virDomainNetDefPtr net,
virQEMUCapsPtr qemuCaps) virQEMUCapsPtr qemuCaps,
int *tapfd,
int *tapfdSize)
ATTRIBUTE_NONNULL(2); ATTRIBUTE_NONNULL(2);
int qemuPhysIfaceConnect(virDomainDefPtr def, int qemuPhysIfaceConnect(virDomainDefPtr def,
...@@ -181,7 +185,8 @@ int qemuPhysIfaceConnect(virDomainDefPtr def, ...@@ -181,7 +185,8 @@ int qemuPhysIfaceConnect(virDomainDefPtr def,
int qemuOpenVhostNet(virDomainDefPtr def, int qemuOpenVhostNet(virDomainDefPtr def,
virDomainNetDefPtr net, virDomainNetDefPtr net,
virQEMUCapsPtr qemuCaps, virQEMUCapsPtr qemuCaps,
int *vhostfd); int *vhostfd,
int *vhostfdSize);
int qemuNetworkPrepareDevices(virDomainDefPtr def); int qemuNetworkPrepareDevices(virDomainDefPtr def);
......
...@@ -690,10 +690,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, ...@@ -690,10 +690,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
virDomainNetDefPtr net) virDomainNetDefPtr net)
{ {
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
char *tapfd_name = NULL; char **tapfdName = NULL;
int tapfd = -1; int *tapfd = NULL;
char *vhostfd_name = NULL; int tapfdSize = 0;
int vhostfd = -1; char **vhostfdName = NULL;
int *vhostfd = NULL;
int vhostfdSize = 0;
char *nicstr = NULL; char *nicstr = NULL;
char *netstr = NULL; char *netstr = NULL;
virNetDevVPortProfilePtr vport = NULL; virNetDevVPortProfilePtr vport = NULL;
...@@ -704,6 +706,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, ...@@ -704,6 +706,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
bool iface_connected = false; bool iface_connected = false;
int actualType; int actualType;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
int i;
/* preallocate new slot for device */ /* preallocate new slot for device */
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) { if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) {
...@@ -739,22 +742,37 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, ...@@ -739,22 +742,37 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net, if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(vhostfd) < 0) {
priv->qemuCaps)) < 0) virReportOOMError();
goto cleanup;
}
tapfdSize = vhostfdSize = 1;
if (qemuNetworkIfaceConnect(vm->def, conn, driver, net,
priv->qemuCaps, tapfd, &tapfdSize) < 0)
goto cleanup; goto cleanup;
iface_connected = true; iface_connected = true;
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
goto cleanup; goto cleanup;
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
if ((tapfd = qemuPhysIfaceConnect(vm->def, driver, net, if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(vhostfd) < 0) {
priv->qemuCaps, virReportOOMError();
VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0) goto cleanup;
}
tapfdSize = vhostfdSize = 1;
if ((tapfd[0] = qemuPhysIfaceConnect(vm->def, driver, net,
priv->qemuCaps,
VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0)
goto cleanup; goto cleanup;
iface_connected = true; iface_connected = true;
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
goto cleanup; goto cleanup;
} else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) { } 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; goto cleanup;
} }
...@@ -792,41 +810,51 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, ...@@ -792,41 +810,51 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
} }
} }
if (tapfd != -1) { if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 ||
if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 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; goto no_memory;
} }
if (vhostfd != -1) { for (i = 0; i < vhostfdSize; i++) {
if (virAsprintf(&vhostfd_name, "vhostfd-%s", net->info.alias) < 0) if (virAsprintf(&vhostfdName[i], "vhostfd-%s%d", net->info.alias, i) < 0)
goto no_memory; goto no_memory;
} }
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) && if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
if (!(netstr = qemuBuildHostNetStr(net, driver, if (!(netstr = qemuBuildHostNetStr(net, driver,
',', -1, tapfd_name, ',', -1,
vhostfd_name))) tapfdName, tapfdSize,
vhostfdName, vhostfdSize)))
goto cleanup; goto cleanup;
} else { } else {
if (!(netstr = qemuBuildHostNetStr(net, driver, if (!(netstr = qemuBuildHostNetStr(net, driver,
' ', vlan, tapfd_name, ' ', vlan,
vhostfd_name))) tapfdName, tapfdSize,
vhostfdName, vhostfdSize)))
goto cleanup; goto cleanup;
} }
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) && if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
if (qemuMonitorAddNetdev(priv->mon, netstr, tapfd, tapfd_name, if (qemuMonitorAddNetdev(priv->mon, netstr,
vhostfd, vhostfd_name) < 0) { tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize) < 0) {
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
virDomainAuditNet(vm, NULL, net, "attach", false); virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup; goto cleanup;
} }
} else { } else {
if (qemuMonitorAddHostNetwork(priv->mon, netstr, tapfd, tapfd_name, if (qemuMonitorAddHostNetwork(priv->mon, netstr,
vhostfd, vhostfd_name) < 0) { tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize) < 0) {
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
virDomainAuditNet(vm, NULL, net, "attach", false); virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup; goto cleanup;
...@@ -834,8 +862,10 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, ...@@ -834,8 +862,10 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
} }
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
VIR_FORCE_CLOSE(tapfd); for (i = 0; i < tapfdSize; i++)
VIR_FORCE_CLOSE(vhostfd); VIR_FORCE_CLOSE(tapfd[i]);
for (i = 0; i < vhostfdSize; i++)
VIR_FORCE_CLOSE(vhostfd[i]);
if (!virDomainObjIsActive(vm)) { if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
...@@ -931,10 +961,18 @@ cleanup: ...@@ -931,10 +961,18 @@ cleanup:
VIR_FREE(nicstr); VIR_FREE(nicstr);
VIR_FREE(netstr); VIR_FREE(netstr);
VIR_FREE(tapfd_name); for (i = 0; i < tapfdSize; i++) {
VIR_FORCE_CLOSE(tapfd); VIR_FORCE_CLOSE(tapfd[i]);
VIR_FREE(vhostfd_name); VIR_FREE(tapfdName[i]);
VIR_FORCE_CLOSE(vhostfd); }
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); virObjectUnref(cfg);
return ret; return ret;
......
...@@ -2477,14 +2477,16 @@ cleanup: ...@@ -2477,14 +2477,16 @@ cleanup:
int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, int qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
const char *netstr, const char *netstr,
int tapfd, const char *tapfd_name, int *tapfd, char **tapfdName, int tapfdSize,
int vhostfd, const char *vhostfd_name) int *vhostfd, char **vhostfdName, int vhostfdSize)
{ {
int ret = -1; int ret = -1;
VIR_DEBUG("mon=%p netstr=%s tapfd=%d tapfd_name=%s " int i = 0, j = 0;
"vhostfd=%d vhostfd_name=%s",
mon, netstr, tapfd, NULLSTR(tapfd_name), VIR_DEBUG("mon=%p netstr=%s tapfd=%p tapfdName=%p tapfdSize=%d "
vhostfd, NULLSTR(vhostfd_name)); "vhostfd=%p vhostfdName=%p vhostfdSize=%d",
mon, netstr, tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize);
if (!mon) { if (!mon) {
virReportError(VIR_ERR_INVALID_ARG, "%s", virReportError(VIR_ERR_INVALID_ARG, "%s",
...@@ -2492,12 +2494,13 @@ int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, ...@@ -2492,12 +2494,13 @@ int qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
return -1; return -1;
} }
if (tapfd >= 0 && qemuMonitorSendFileHandle(mon, tapfd_name, tapfd) < 0) for (i = 0; i < tapfdSize; i++) {
return -1; if (qemuMonitorSendFileHandle(mon, tapfdName[i], tapfd[i]) < 0)
if (vhostfd >= 0 && goto cleanup;
qemuMonitorSendFileHandle(mon, vhostfd_name, vhostfd) < 0) { }
vhostfd = -1; for (j = 0; j < vhostfdSize; j++) {
goto cleanup; if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0)
goto cleanup;
} }
if (mon->json) if (mon->json)
...@@ -2508,10 +2511,14 @@ int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, ...@@ -2508,10 +2511,14 @@ int qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
cleanup: cleanup:
if (ret < 0) { if (ret < 0) {
if (tapfd >= 0 && qemuMonitorCloseFileHandle(mon, tapfd_name) < 0) while (i--) {
VIR_WARN("failed to close device handle '%s'", tapfd_name); if (qemuMonitorCloseFileHandle(mon, tapfdName[i]) < 0)
if (vhostfd >= 0 && qemuMonitorCloseFileHandle(mon, vhostfd_name) < 0) VIR_WARN("failed to close device handle '%s'", tapfdName[i]);
VIR_WARN("failed to close device handle '%s'", vhostfd_name); }
while (j--) {
if (qemuMonitorCloseFileHandle(mon, vhostfdName[j]) < 0)
VIR_WARN("failed to close device handle '%s'", vhostfdName[j]);
}
} }
return ret; return ret;
...@@ -2543,14 +2550,16 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, ...@@ -2543,14 +2550,16 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
int qemuMonitorAddNetdev(qemuMonitorPtr mon, int qemuMonitorAddNetdev(qemuMonitorPtr mon,
const char *netdevstr, const char *netdevstr,
int tapfd, const char *tapfd_name, int *tapfd, char **tapfdName, int tapfdSize,
int vhostfd, const char *vhostfd_name) int *vhostfd, char **vhostfdName, int vhostfdSize)
{ {
int ret = -1; int ret = -1;
VIR_DEBUG("mon=%p netdevstr=%s tapfd=%d tapfd_name=%s " int i = 0, j = 0;
"vhostfd=%d vhostfd_name=%s",
mon, netdevstr, tapfd, NULLSTR(tapfd_name), VIR_DEBUG("mon=%p netdevstr=%s tapfd=%p tapfdName=%p tapfdSize=%d"
vhostfd, NULLSTR(vhostfd_name)); "vhostfd=%p vhostfdName=%p vhostfdSize=%d",
mon, netdevstr, tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, tapfdSize);
if (!mon) { if (!mon) {
virReportError(VIR_ERR_INVALID_ARG, "%s", virReportError(VIR_ERR_INVALID_ARG, "%s",
...@@ -2558,12 +2567,13 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon, ...@@ -2558,12 +2567,13 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon,
return -1; return -1;
} }
if (tapfd >= 0 && qemuMonitorSendFileHandle(mon, tapfd_name, tapfd) < 0) for (i = 0; i < tapfdSize; i++) {
return -1; if (qemuMonitorSendFileHandle(mon, tapfdName[i], tapfd[i]) < 0)
if (vhostfd >= 0 && goto cleanup;
qemuMonitorSendFileHandle(mon, vhostfd_name, vhostfd) < 0) { }
vhostfd = -1; for (j = 0; j < vhostfdSize; j++) {
goto cleanup; if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0)
goto cleanup;
} }
if (mon->json) if (mon->json)
...@@ -2573,10 +2583,14 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon, ...@@ -2573,10 +2583,14 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon,
cleanup: cleanup:
if (ret < 0) { if (ret < 0) {
if (tapfd >= 0 && qemuMonitorCloseFileHandle(mon, tapfd_name) < 0) while (i--) {
VIR_WARN("failed to close device handle '%s'", tapfd_name); if (qemuMonitorCloseFileHandle(mon, tapfdName[i]) < 0)
if (vhostfd >= 0 && qemuMonitorCloseFileHandle(mon, vhostfd_name) < 0) VIR_WARN("failed to close device handle '%s'", tapfdName[i]);
VIR_WARN("failed to close device handle '%s'", vhostfd_name); }
while (j--) {
if (qemuMonitorCloseFileHandle(mon, vhostfdName[j]) < 0)
VIR_WARN("failed to close device handle '%s'", vhostfdName[j]);
}
} }
return ret; return ret;
......
...@@ -501,8 +501,8 @@ int qemuMonitorRemoveFd(qemuMonitorPtr mon, int fdset, int fd); ...@@ -501,8 +501,8 @@ int qemuMonitorRemoveFd(qemuMonitorPtr mon, int fdset, int fd);
*/ */
int qemuMonitorAddHostNetwork(qemuMonitorPtr mon, int qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
const char *netstr, const char *netstr,
int tapfd, const char *tapfd_name, int *tapfd, char **tapfdName, int tapfdSize,
int vhostfd, const char *vhostfd_name); int *vhostfd, char **vhostfdName, int vhostfdSize);
int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
int vlan, int vlan,
...@@ -510,8 +510,8 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon, ...@@ -510,8 +510,8 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
int qemuMonitorAddNetdev(qemuMonitorPtr mon, int qemuMonitorAddNetdev(qemuMonitorPtr mon,
const char *netdevstr, const char *netdevstr,
int tapfd, const char *tapfd_name, int *tapfd, char **tapfdName, int tapfdSize,
int vhostfd, const char *vhostfd_name); int *vhostfd, char **vhostfdName, int vhostfdSize);
int qemuMonitorRemoveNetdev(qemuMonitorPtr mon, int qemuMonitorRemoveNetdev(qemuMonitorPtr mon,
const char *alias); const char *alias);
......
...@@ -109,6 +109,7 @@ umlConnectTapDevice(virConnectPtr conn, ...@@ -109,6 +109,7 @@ umlConnectTapDevice(virConnectPtr conn,
const char *bridge) const char *bridge)
{ {
bool template_ifname = false; bool template_ifname = false;
int tapfd;
if (!net->ifname || if (!net->ifname ||
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) || STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
...@@ -121,7 +122,7 @@ umlConnectTapDevice(virConnectPtr conn, ...@@ -121,7 +122,7 @@ umlConnectTapDevice(virConnectPtr conn,
} }
if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, &net->mac, if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, &net->mac,
vm->uuid, NULL, vm->uuid, &tapfd, 1,
virDomainNetGetActualVirtPortProfile(net), virDomainNetGetActualVirtPortProfile(net),
virDomainNetGetActualVlan(net), virDomainNetGetActualVlan(net),
VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_IFUP |
...@@ -139,9 +140,11 @@ umlConnectTapDevice(virConnectPtr conn, ...@@ -139,9 +140,11 @@ umlConnectTapDevice(virConnectPtr conn,
} }
} }
VIR_FORCE_CLOSE(tapfd);
return 0; return 0;
error: error:
VIR_FORCE_CLOSE(tapfd);
return -1; return -1;
} }
......
...@@ -140,7 +140,8 @@ virNetDevProbeVnetHdr(int tapfd) ...@@ -140,7 +140,8 @@ virNetDevProbeVnetHdr(int tapfd)
/** /**
* virNetDevTapCreate: * virNetDevTapCreate:
* @ifname: the interface name * @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: * @flags: OR of virNetDevTapCreateFlags. Only one flag is recognized:
* *
* VIR_NETDEV_TAP_CREATE_VNET_HDR * VIR_NETDEV_TAP_CREATE_VNET_HDR
...@@ -148,76 +149,85 @@ virNetDevProbeVnetHdr(int tapfd) ...@@ -148,76 +149,85 @@ virNetDevProbeVnetHdr(int tapfd)
* VIR_NETDEV_TAP_CREATE_PERSIST * VIR_NETDEV_TAP_CREATE_PERSIST
* - The device will persist after the file descriptor is closed * - The device will persist after the file descriptor is closed
* *
* Creates a tap interface. * Creates a tap interface. The caller must use virNetDevTapDelete to
* If the @tapfd parameter is supplied, the open tap device file descriptor * remove a persistent TAP device when it is no longer needed. In case
* will be returned, otherwise the TAP device will be closed. The caller must * @tapfdSize is greater than one, multiqueue extension is requested
* use virNetDevTapDelete to remove a persistent TAP device when it is no * from kernel.
* longer needed.
* *
* Returns 0 in case of success or -1 on failure. * Returns 0 in case of success or -1 on failure.
*/ */
int virNetDevTapCreate(char **ifname, int virNetDevTapCreate(char **ifname,
int *tapfd, int *tapfd,
int tapfdSize,
unsigned int flags) unsigned int flags)
{ {
int fd; int i;
struct ifreq ifr; struct ifreq ifr;
int ret = -1; int ret = -1;
int fd;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
virReportSystemError(errno, "%s",
_("Unable to open /dev/net/tun, is tun module loaded?"));
return -1;
}
memset(&ifr, 0, sizeof(ifr)); 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;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP|IFF_NO_PI; 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 # ifdef IFF_VNET_HDR
if ((flags & VIR_NETDEV_TAP_CREATE_VNET_HDR) && if ((flags & VIR_NETDEV_TAP_CREATE_VNET_HDR) &&
virNetDevProbeVnetHdr(fd)) virNetDevProbeVnetHdr(fd))
ifr.ifr_flags |= IFF_VNET_HDR; ifr.ifr_flags |= IFF_VNET_HDR;
# endif # endif
if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) { if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) {
virReportSystemError(ERANGE, virReportSystemError(ERANGE,
_("Network interface name '%s' is too long"), _("Network interface name '%s' is too long"),
*ifname); *ifname);
goto cleanup; goto cleanup;
} }
if (ioctl(fd, TUNSETIFF, &ifr) < 0) { if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Unable to create tap device %s"), _("Unable to create tap device %s"),
NULLSTR(*ifname)); NULLSTR(*ifname));
goto cleanup; goto cleanup;
} }
if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) && if (i == 0) {
(errno = ioctl(fd, TUNSETPERSIST, 1))) { /* In case we are looping more than once, set other
virReportSystemError(errno, * TAPs to have the same name */
_("Unable to set tap device %s to persistent"), VIR_FREE(*ifname);
NULLSTR(*ifname)); if (ifr.ifr_name && VIR_STRDUP(*ifname, ifr.ifr_name) < 0)
goto cleanup; goto cleanup;
} }
VIR_FREE(*ifname); if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) &&
if (!(*ifname = strdup(ifr.ifr_name))) { (errno = ioctl(fd, TUNSETPERSIST, 1))) {
virReportOOMError(); virReportSystemError(errno,
goto cleanup; _("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; ret = 0;
cleanup: cleanup:
if (ret < 0) if (ret < 0) {
VIR_FORCE_CLOSE(fd); VIR_FORCE_CLOSE(fd);
while (i--)
VIR_FORCE_CLOSE(tapfd[i]);
}
return ret; return ret;
} }
...@@ -266,6 +276,7 @@ cleanup: ...@@ -266,6 +276,7 @@ cleanup:
#else /* ! TUNSETIFF */ #else /* ! TUNSETIFF */
int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED, int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED,
int *tapfd ATTRIBUTE_UNUSED, int *tapfd ATTRIBUTE_UNUSED,
int tapfdSize ATTRIBUTE_UNUSED,
unsigned int flags ATTRIBUTE_UNUSED) unsigned int flags ATTRIBUTE_UNUSED)
{ {
virReportSystemError(ENOSYS, "%s", virReportSystemError(ENOSYS, "%s",
...@@ -286,7 +297,8 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED) ...@@ -286,7 +297,8 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
* @brname: the bridge name * @brname: the bridge name
* @ifname: the interface name (or name template) * @ifname: the interface name (or name template)
* @macaddr: desired MAC address * @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 * @virtPortProfile: bridge/port specific configuration
* @flags: OR of virNetDevTapCreateFlags: * @flags: OR of virNetDevTapCreateFlags:
...@@ -314,6 +326,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, ...@@ -314,6 +326,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
const virMacAddrPtr macaddr, const virMacAddrPtr macaddr,
const unsigned char *vmuuid, const unsigned char *vmuuid,
int *tapfd, int *tapfd,
int tapfdSize,
virNetDevVPortProfilePtr virtPortProfile, virNetDevVPortProfilePtr virtPortProfile,
virNetDevVlanPtr virtVlan, virNetDevVlanPtr virtVlan,
unsigned int flags) unsigned int flags)
...@@ -321,7 +334,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, ...@@ -321,7 +334,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
virMacAddr tapmac; virMacAddr tapmac;
char macaddrstr[VIR_MAC_STRING_BUFLEN]; char macaddrstr[VIR_MAC_STRING_BUFLEN];
if (virNetDevTapCreate(ifname, tapfd, flags) < 0) if (virNetDevTapCreate(ifname, tapfd, tapfdSize, flags) < 0)
return -1; return -1;
/* We need to set the interface MAC before adding it /* We need to set the interface MAC before adding it
...@@ -372,9 +385,9 @@ int virNetDevTapCreateInBridgePort(const char *brname, ...@@ -372,9 +385,9 @@ int virNetDevTapCreateInBridgePort(const char *brname,
return 0; return 0;
error: error:
if (tapfd) while (tapfdSize)
VIR_FORCE_CLOSE(*tapfd); VIR_FORCE_CLOSE(tapfd[--tapfdSize]);
return -1; return -1;
} }
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
int virNetDevTapCreate(char **ifname, int virNetDevTapCreate(char **ifname,
int *tapfd, int *tapfd,
int tapfdSize,
unsigned int flags) unsigned int flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
...@@ -55,6 +56,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, ...@@ -55,6 +56,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
const virMacAddrPtr macaddr, const virMacAddrPtr macaddr,
const unsigned char *vmuuid, const unsigned char *vmuuid,
int *tapfd, int *tapfd,
int tapfdSize,
virNetDevVPortProfilePtr virtPortProfile, virNetDevVPortProfilePtr virtPortProfile,
virNetDevVlanPtr virtVlan, virNetDevVlanPtr virtVlan,
unsigned int flags) unsigned int flags)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册