mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-09-10 21:45:18 +03:00
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.
This commit is contained in:
@@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,68 +354,97 @@ 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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (qemuCreateInBridgePortWithHelper(cfg, brname,
|
||||||
&net->ifname,
|
&net->ifname,
|
||||||
&tapfd, tap_create_flags);
|
tapfd, tap_create_flags) < 0) {
|
||||||
|
virDomainAuditNetDevice(def, net, "/dev/net/tun", false);
|
||||||
virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
|
goto cleanup;
|
||||||
if (err < 0) {
|
}
|
||||||
if (template_ifname)
|
/* qemuCreateInBridgePortWithHelper can only create a single FD */
|
||||||
VIR_FREE(net->ifname);
|
if (*tapfdSize > 1) {
|
||||||
tapfd = -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) {
|
||||||
|
virReportSystemError(ret,
|
||||||
|
_("failed to add ebtables rule "
|
||||||
|
"to allow MAC address on '%s'"),
|
||||||
net->ifname);
|
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) {
|
||||||
|
*vhostfdSize = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,
|
|||||||
"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);
|
||||||
|
if (net->driver.virtio.name == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
"%s", _("vhost-net was requested for an interface, "
|
"%s", _("vhost-net was requested for an interface, "
|
||||||
"but is unavailable"));
|
"but is unavailable"));
|
||||||
return -1;
|
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,25 +6548,33 @@ 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]);
|
||||||
|
if (virAsprintf(&vhostfdName[i], "%d", vhostfd[i]) < 0) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Possible combinations:
|
/* Possible combinations:
|
||||||
*
|
*
|
||||||
@@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
tapfdSize = vhostfdSize = 1;
|
||||||
|
if ((tapfd[0] = qemuPhysIfaceConnect(vm->def, driver, net,
|
||||||
priv->qemuCaps,
|
priv->qemuCaps,
|
||||||
VIR_NETDEV_VPORT_PROFILE_OP_CREATE)) < 0)
|
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
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:
|
|||||||
|
|
||||||
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:
|
|||||||
|
|
||||||
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,11 +2494,12 @@ 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++) {
|
||||||
|
if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,
|
|||||||
|
|
||||||
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,11 +2567,12 @@ 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++) {
|
||||||
|
if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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);
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
/**
|
/**
|
||||||
* 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,31 +149,37 @@ 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;
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
for (i = 0; i < tapfdSize; i++) {
|
||||||
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||||
virReportSystemError(errno, "%s",
|
virReportSystemError(errno, "%s",
|
||||||
_("Unable to open /dev/net/tun, is tun module loaded?"));
|
_("Unable to open /dev/net/tun, is tun module loaded?"));
|
||||||
return -1;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
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) &&
|
||||||
@@ -195,6 +202,14 @@ int virNetDevTapCreate(char **ifname,
|
|||||||
goto cleanup;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) &&
|
if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) &&
|
||||||
(errno = ioctl(fd, TUNSETPERSIST, 1))) {
|
(errno = ioctl(fd, TUNSETPERSIST, 1))) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
@@ -202,22 +217,17 @@ int virNetDevTapCreate(char **ifname,
|
|||||||
NULLSTR(*ifname));
|
NULLSTR(*ifname));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
tapfd[i] = fd;
|
||||||
VIR_FREE(*ifname);
|
|
||||||
if (!(*ifname = strdup(ifr.ifr_name))) {
|
|
||||||
virReportOOMError();
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
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:
|
|||||||
#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)
|
|||||||
* @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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
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,
|
|||||||
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)
|
||||||
|
Reference in New Issue
Block a user