mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
qemu: Move qemuNetworkIfaceConnect to qemu_interface.c and rename
Move the misplaced function from qemu_command.c to qemu_interface.c since it's closer in functionality there and had less to do with building the command line. Rename function to qemuInterfaceBridgeConnect and modify callers. Signed-off-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
parent
5937241328
commit
a1a1e44798
@ -128,6 +128,7 @@ src/qemu/qemu_domain.c
|
|||||||
src/qemu/qemu_driver.c
|
src/qemu/qemu_driver.c
|
||||||
src/qemu/qemu_hostdev.c
|
src/qemu/qemu_hostdev.c
|
||||||
src/qemu/qemu_hotplug.c
|
src/qemu/qemu_hotplug.c
|
||||||
|
src/qemu/qemu_interface.c
|
||||||
src/qemu/qemu_migration.c
|
src/qemu/qemu_migration.c
|
||||||
src/qemu/qemu_monitor.c
|
src/qemu/qemu_monitor.c
|
||||||
src/qemu/qemu_monitor_json.c
|
src/qemu/qemu_monitor_json.c
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
#include "qemu_interface.h"
|
#include "qemu_interface.h"
|
||||||
#include "cpu/cpu.h"
|
#include "cpu/cpu.h"
|
||||||
#include "dirname.h"
|
#include "dirname.h"
|
||||||
#include "passfd.h"
|
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "virlog.h"
|
#include "virlog.h"
|
||||||
#include "virarch.h"
|
#include "virarch.h"
|
||||||
@ -154,214 +153,6 @@ VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
|
|||||||
"preferred",
|
"preferred",
|
||||||
"interleave");
|
"interleave");
|
||||||
|
|
||||||
/**
|
|
||||||
* qemuCreateInBridgePortWithHelper:
|
|
||||||
* @cfg: the configuration object in which the helper name is looked up
|
|
||||||
* @brname: the bridge name
|
|
||||||
* @ifname: the returned interface name
|
|
||||||
* @macaddr: the returned MAC address
|
|
||||||
* @tapfd: file descriptor return value for the new tap device
|
|
||||||
* @flags: OR of virNetDevTapCreateFlags:
|
|
||||||
|
|
||||||
* VIR_NETDEV_TAP_CREATE_VNET_HDR
|
|
||||||
* - Enable IFF_VNET_HDR on the tap device
|
|
||||||
*
|
|
||||||
* This function creates a new tap device on a bridge using an external
|
|
||||||
* helper. The final name for the bridge will be stored in @ifname.
|
|
||||||
*
|
|
||||||
* Returns 0 in case of success or -1 on failure
|
|
||||||
*/
|
|
||||||
static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,
|
|
||||||
const char *brname,
|
|
||||||
char **ifname,
|
|
||||||
int *tapfd,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
virCommandPtr cmd;
|
|
||||||
char *errbuf = NULL, *cmdstr = NULL;
|
|
||||||
int pair[2] = { -1, -1 };
|
|
||||||
|
|
||||||
if ((flags & ~VIR_NETDEV_TAP_CREATE_VNET_HDR) != VIR_NETDEV_TAP_CREATE_IFUP)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
|
|
||||||
virReportSystemError(errno, "%s", _("failed to create socket"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!virFileIsExecutable(cfg->bridgeHelperName)) {
|
|
||||||
virReportSystemError(errno, _("'%s' is not a suitable bridge helper"),
|
|
||||||
cfg->bridgeHelperName);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd = virCommandNew(cfg->bridgeHelperName);
|
|
||||||
if (flags & VIR_NETDEV_TAP_CREATE_VNET_HDR)
|
|
||||||
virCommandAddArgFormat(cmd, "--use-vnet");
|
|
||||||
virCommandAddArgFormat(cmd, "--br=%s", brname);
|
|
||||||
virCommandAddArgFormat(cmd, "--fd=%d", pair[1]);
|
|
||||||
virCommandSetErrorBuffer(cmd, &errbuf);
|
|
||||||
virCommandDoAsyncIO(cmd);
|
|
||||||
virCommandPassFD(cmd, pair[1],
|
|
||||||
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
|
||||||
virCommandClearCaps(cmd);
|
|
||||||
#ifdef CAP_NET_ADMIN
|
|
||||||
virCommandAllowCap(cmd, CAP_NET_ADMIN);
|
|
||||||
#endif
|
|
||||||
if (virCommandRunAsync(cmd, NULL) < 0) {
|
|
||||||
*tapfd = -1;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
*tapfd = recvfd(pair[0], 0);
|
|
||||||
} while (*tapfd < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
if (*tapfd < 0) {
|
|
||||||
char ebuf[1024];
|
|
||||||
char *errstr = NULL;
|
|
||||||
|
|
||||||
if (!(cmdstr = virCommandToString(cmd)))
|
|
||||||
goto cleanup;
|
|
||||||
virCommandAbort(cmd);
|
|
||||||
|
|
||||||
if (errbuf && *errbuf &&
|
|
||||||
virAsprintf(&errstr, "\nstderr=%s", errbuf) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
||||||
_("%s: failed to communicate with bridge helper: %s%s"),
|
|
||||||
cmdstr, virStrerror(errno, ebuf, sizeof(ebuf)),
|
|
||||||
errstr ? errstr : "");
|
|
||||||
VIR_FREE(errstr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virNetDevTapGetName(*tapfd, ifname) < 0 ||
|
|
||||||
virCommandWait(cmd, NULL) < 0) {
|
|
||||||
VIR_FORCE_CLOSE(*tapfd);
|
|
||||||
*tapfd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
VIR_FREE(cmdstr);
|
|
||||||
VIR_FREE(errbuf);
|
|
||||||
virCommandFree(cmd);
|
|
||||||
VIR_FORCE_CLOSE(pair[0]);
|
|
||||||
return *tapfd < 0 ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* qemuNetworkIfaceConnect - *only* called if actualType is
|
|
||||||
* VIR_DOMAIN_NET_TYPE_NETWORK or VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if
|
|
||||||
* the connection is made with a tap device connecting to a bridge
|
|
||||||
* device)
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
qemuNetworkIfaceConnect(virDomainDefPtr def,
|
|
||||||
virQEMUDriverPtr driver,
|
|
||||||
virDomainNetDefPtr net,
|
|
||||||
int *tapfd,
|
|
||||||
size_t *tapfdSize)
|
|
||||||
{
|
|
||||||
const char *brname;
|
|
||||||
int ret = -1;
|
|
||||||
unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
|
|
||||||
bool template_ifname = false;
|
|
||||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
||||||
const char *tunpath = "/dev/net/tun";
|
|
||||||
|
|
||||||
if (net->backend.tap) {
|
|
||||||
tunpath = net->backend.tap;
|
|
||||||
if (!(virQEMUDriverIsPrivileged(driver))) {
|
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
||||||
_("cannot use custom tap device in session mode"));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(brname = virDomainNetGetActualBridgeName(net))) {
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!net->ifname ||
|
|
||||||
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
|
|
||||||
strchr(net->ifname, '%')) {
|
|
||||||
VIR_FREE(net->ifname);
|
|
||||||
if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0)
|
|
||||||
goto cleanup;
|
|
||||||
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
|
||||||
template_ifname = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (net->model && STREQ(net->model, "virtio"))
|
|
||||||
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
|
|
||||||
|
|
||||||
if (virQEMUDriverIsPrivileged(driver)) {
|
|
||||||
if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
|
|
||||||
def->uuid, tunpath, tapfd, *tapfdSize,
|
|
||||||
virDomainNetGetActualVirtPortProfile(net),
|
|
||||||
virDomainNetGetActualVlan(net),
|
|
||||||
tap_create_flags) < 0) {
|
|
||||||
virDomainAuditNetDevice(def, net, tunpath, false);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
if (virDomainNetGetActualBridgeMACTableManager(net)
|
|
||||||
== VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
|
|
||||||
/* libvirt is managing the FDB of the bridge this device
|
|
||||||
* is attaching to, so we need to turn off learning and
|
|
||||||
* unicast_flood on the device to prevent the kernel from
|
|
||||||
* adding any FDB entries for it. We will add add an fdb
|
|
||||||
* entry ourselves (during qemuInterfaceStartDevices(),
|
|
||||||
* using the MAC address from the interface config.
|
|
||||||
*/
|
|
||||||
if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (qemuCreateInBridgePortWithHelper(cfg, brname,
|
|
||||||
&net->ifname,
|
|
||||||
tapfd, tap_create_flags) < 0) {
|
|
||||||
virDomainAuditNetDevice(def, net, tunpath, false);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
/* qemuCreateInBridgePortWithHelper can only create a single FD */
|
|
||||||
if (*tapfdSize > 1) {
|
|
||||||
VIR_WARN("Ignoring multiqueue network request");
|
|
||||||
*tapfdSize = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virDomainAuditNetDevice(def, net, tunpath, true);
|
|
||||||
|
|
||||||
if (cfg->macFilter &&
|
|
||||||
ebtablesAddForwardAllowIn(driver->ebtables,
|
|
||||||
net->ifname,
|
|
||||||
&net->mac) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (net->filter &&
|
|
||||||
virDomainConfNWFilterInstantiate(def->uuid, net) < 0) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (ret < 0) {
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < *tapfdSize && tapfd[i] >= 0; i++)
|
|
||||||
VIR_FORCE_CLOSE(tapfd[i]);
|
|
||||||
if (template_ifname)
|
|
||||||
VIR_FREE(net->ifname);
|
|
||||||
}
|
|
||||||
virObjectUnref(cfg);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
qemuDomainSupportsNicdev(virDomainDefPtr def,
|
qemuDomainSupportsNicdev(virDomainDefPtr def,
|
||||||
virQEMUCapsPtr qemuCaps,
|
virQEMUCapsPtr qemuCaps,
|
||||||
@ -8425,8 +8216,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
|
|||||||
|
|
||||||
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
|
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
|
||||||
|
|
||||||
if (qemuNetworkIfaceConnect(def, driver, net,
|
if (qemuInterfaceBridgeConnect(def, driver, net,
|
||||||
tapfd, &tapfdSize) < 0)
|
tapfd, &tapfdSize) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
||||||
tapfdSize = net->driver.virtio.queues;
|
tapfdSize = net->driver.virtio.queues;
|
||||||
|
@ -223,12 +223,6 @@ char *qemuBuildHubDevStr(virDomainDefPtr def,
|
|||||||
char *qemuBuildRedirdevDevStr(virDomainDefPtr def,
|
char *qemuBuildRedirdevDevStr(virDomainDefPtr def,
|
||||||
virDomainRedirdevDefPtr dev,
|
virDomainRedirdevDefPtr dev,
|
||||||
virQEMUCapsPtr qemuCaps);
|
virQEMUCapsPtr qemuCaps);
|
||||||
int qemuNetworkIfaceConnect(virDomainDefPtr def,
|
|
||||||
virQEMUDriverPtr driver,
|
|
||||||
virDomainNetDefPtr net,
|
|
||||||
int *tapfd,
|
|
||||||
size_t *tapfdSize)
|
|
||||||
ATTRIBUTE_NONNULL(2);
|
|
||||||
|
|
||||||
int qemuOpenVhostNet(virDomainDefPtr def,
|
int qemuOpenVhostNet(virDomainDefPtr def,
|
||||||
virDomainNetDefPtr net,
|
virDomainNetDefPtr net,
|
||||||
|
@ -922,8 +922,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
|
|||||||
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
|
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
|
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
|
||||||
if (qemuNetworkIfaceConnect(vm->def, driver, net,
|
if (qemuInterfaceBridgeConnect(vm->def, driver, net,
|
||||||
tapfd, &tapfdSize) < 0)
|
tapfd, &tapfdSize) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
iface_connected = true;
|
iface_connected = true;
|
||||||
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
|
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
|
||||||
|
@ -26,14 +26,22 @@
|
|||||||
|
|
||||||
#include "network_conf.h"
|
#include "network_conf.h"
|
||||||
#include "domain_audit.h"
|
#include "domain_audit.h"
|
||||||
|
#include "domain_nwfilter.h"
|
||||||
#include "qemu_interface.h"
|
#include "qemu_interface.h"
|
||||||
|
#include "passfd.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
|
#include "virlog.h"
|
||||||
|
#include "virstring.h"
|
||||||
#include "virnetdev.h"
|
#include "virnetdev.h"
|
||||||
#include "virnetdevtap.h"
|
#include "virnetdevtap.h"
|
||||||
#include "virnetdevmacvlan.h"
|
#include "virnetdevmacvlan.h"
|
||||||
#include "virnetdevbridge.h"
|
#include "virnetdevbridge.h"
|
||||||
#include "virnetdevvportprofile.h"
|
#include "virnetdevvportprofile.h"
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
|
|
||||||
|
VIR_LOG_INIT("qemu.qemu_interface");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemuInterfaceStartDevice:
|
* qemuInterfaceStartDevice:
|
||||||
* @net: net device to start
|
* @net: net device to start
|
||||||
@ -276,3 +284,219 @@ qemuInterfaceDirectConnect(virDomainDefPtr def,
|
|||||||
virObjectUnref(cfg);
|
virObjectUnref(cfg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemuCreateInBridgePortWithHelper:
|
||||||
|
* @cfg: the configuration object in which the helper name is looked up
|
||||||
|
* @brname: the bridge name
|
||||||
|
* @ifname: the returned interface name
|
||||||
|
* @macaddr: the returned MAC address
|
||||||
|
* @tapfd: file descriptor return value for the new tap device
|
||||||
|
* @flags: OR of virNetDevTapCreateFlags:
|
||||||
|
|
||||||
|
* VIR_NETDEV_TAP_CREATE_VNET_HDR
|
||||||
|
* - Enable IFF_VNET_HDR on the tap device
|
||||||
|
*
|
||||||
|
* This function creates a new tap device on a bridge using an external
|
||||||
|
* helper. The final name for the bridge will be stored in @ifname.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or -1 on failure
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,
|
||||||
|
const char *brname,
|
||||||
|
char **ifname,
|
||||||
|
int *tapfd,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
virCommandPtr cmd;
|
||||||
|
char *errbuf = NULL, *cmdstr = NULL;
|
||||||
|
int pair[2] = { -1, -1 };
|
||||||
|
|
||||||
|
if ((flags & ~VIR_NETDEV_TAP_CREATE_VNET_HDR) != VIR_NETDEV_TAP_CREATE_IFUP)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
|
||||||
|
virReportSystemError(errno, "%s", _("failed to create socket"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!virFileIsExecutable(cfg->bridgeHelperName)) {
|
||||||
|
virReportSystemError(errno, _("'%s' is not a suitable bridge helper"),
|
||||||
|
cfg->bridgeHelperName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = virCommandNew(cfg->bridgeHelperName);
|
||||||
|
if (flags & VIR_NETDEV_TAP_CREATE_VNET_HDR)
|
||||||
|
virCommandAddArgFormat(cmd, "--use-vnet");
|
||||||
|
virCommandAddArgFormat(cmd, "--br=%s", brname);
|
||||||
|
virCommandAddArgFormat(cmd, "--fd=%d", pair[1]);
|
||||||
|
virCommandSetErrorBuffer(cmd, &errbuf);
|
||||||
|
virCommandDoAsyncIO(cmd);
|
||||||
|
virCommandPassFD(cmd, pair[1],
|
||||||
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
||||||
|
virCommandClearCaps(cmd);
|
||||||
|
#ifdef CAP_NET_ADMIN
|
||||||
|
virCommandAllowCap(cmd, CAP_NET_ADMIN);
|
||||||
|
#endif
|
||||||
|
if (virCommandRunAsync(cmd, NULL) < 0) {
|
||||||
|
*tapfd = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
*tapfd = recvfd(pair[0], 0);
|
||||||
|
} while (*tapfd < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (*tapfd < 0) {
|
||||||
|
char ebuf[1024];
|
||||||
|
char *errstr = NULL;
|
||||||
|
|
||||||
|
if (!(cmdstr = virCommandToString(cmd)))
|
||||||
|
goto cleanup;
|
||||||
|
virCommandAbort(cmd);
|
||||||
|
|
||||||
|
if (errbuf && *errbuf &&
|
||||||
|
virAsprintf(&errstr, "\nstderr=%s", errbuf) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("%s: failed to communicate with bridge helper: %s%s"),
|
||||||
|
cmdstr, virStrerror(errno, ebuf, sizeof(ebuf)),
|
||||||
|
errstr ? errstr : "");
|
||||||
|
VIR_FREE(errstr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNetDevTapGetName(*tapfd, ifname) < 0 ||
|
||||||
|
virCommandWait(cmd, NULL) < 0) {
|
||||||
|
VIR_FORCE_CLOSE(*tapfd);
|
||||||
|
*tapfd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(cmdstr);
|
||||||
|
VIR_FREE(errbuf);
|
||||||
|
virCommandFree(cmd);
|
||||||
|
VIR_FORCE_CLOSE(pair[0]);
|
||||||
|
return *tapfd < 0 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qemuInterfaceBridgeConnect:
|
||||||
|
* @def: the definition of the VM
|
||||||
|
* @driver: qemu driver data
|
||||||
|
* @net: pointer to the VM's interface description
|
||||||
|
* @tapfd: array of file descriptor return value for the new device
|
||||||
|
* @tapfdsize: number of file descriptors in @tapfd
|
||||||
|
*
|
||||||
|
* Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_NETWORK or
|
||||||
|
* VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if the connection is made with a tap
|
||||||
|
* device connecting to a bridge device)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
||||||
|
virQEMUDriverPtr driver,
|
||||||
|
virDomainNetDefPtr net,
|
||||||
|
int *tapfd,
|
||||||
|
size_t *tapfdSize)
|
||||||
|
{
|
||||||
|
const char *brname;
|
||||||
|
int ret = -1;
|
||||||
|
unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
|
||||||
|
bool template_ifname = false;
|
||||||
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||||
|
const char *tunpath = "/dev/net/tun";
|
||||||
|
|
||||||
|
if (net->backend.tap) {
|
||||||
|
tunpath = net->backend.tap;
|
||||||
|
if (!(virQEMUDriverIsPrivileged(driver))) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("cannot use custom tap device in session mode"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(brname = virDomainNetGetActualBridgeName(net))) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!net->ifname ||
|
||||||
|
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
|
||||||
|
strchr(net->ifname, '%')) {
|
||||||
|
VIR_FREE(net->ifname);
|
||||||
|
if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0)
|
||||||
|
goto cleanup;
|
||||||
|
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
||||||
|
template_ifname = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net->model && STREQ(net->model, "virtio"))
|
||||||
|
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
|
||||||
|
|
||||||
|
if (virQEMUDriverIsPrivileged(driver)) {
|
||||||
|
if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
|
||||||
|
def->uuid, tunpath, tapfd, *tapfdSize,
|
||||||
|
virDomainNetGetActualVirtPortProfile(net),
|
||||||
|
virDomainNetGetActualVlan(net),
|
||||||
|
tap_create_flags) < 0) {
|
||||||
|
virDomainAuditNetDevice(def, net, tunpath, false);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (virDomainNetGetActualBridgeMACTableManager(net)
|
||||||
|
== VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
|
||||||
|
/* libvirt is managing the FDB of the bridge this device
|
||||||
|
* is attaching to, so we need to turn off learning and
|
||||||
|
* unicast_flood on the device to prevent the kernel from
|
||||||
|
* adding any FDB entries for it. We will add add an fdb
|
||||||
|
* entry ourselves (during qemuInterfaceStartDevices(),
|
||||||
|
* using the MAC address from the interface config.
|
||||||
|
*/
|
||||||
|
if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (qemuCreateInBridgePortWithHelper(cfg, brname,
|
||||||
|
&net->ifname,
|
||||||
|
tapfd, tap_create_flags) < 0) {
|
||||||
|
virDomainAuditNetDevice(def, net, tunpath, false);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
/* qemuCreateInBridgePortWithHelper can only create a single FD */
|
||||||
|
if (*tapfdSize > 1) {
|
||||||
|
VIR_WARN("Ignoring multiqueue network request");
|
||||||
|
*tapfdSize = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virDomainAuditNetDevice(def, net, tunpath, true);
|
||||||
|
|
||||||
|
if (cfg->macFilter &&
|
||||||
|
ebtablesAddForwardAllowIn(driver->ebtables,
|
||||||
|
net->ifname,
|
||||||
|
&net->mac) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (net->filter &&
|
||||||
|
virDomainConfNWFilterInstantiate(def->uuid, net) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (ret < 0) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < *tapfdSize && tapfd[i] >= 0; i++)
|
||||||
|
VIR_FORCE_CLOSE(tapfd[i]);
|
||||||
|
if (template_ifname)
|
||||||
|
VIR_FREE(net->ifname);
|
||||||
|
}
|
||||||
|
virObjectUnref(cfg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -40,4 +40,10 @@ int qemuInterfaceDirectConnect(virDomainDefPtr def,
|
|||||||
size_t tapfdSize,
|
size_t tapfdSize,
|
||||||
virNetDevVPortProfileOp vmop);
|
virNetDevVPortProfileOp vmop);
|
||||||
|
|
||||||
|
int qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
||||||
|
virQEMUDriverPtr driver,
|
||||||
|
virDomainNetDefPtr net,
|
||||||
|
int *tapfd,
|
||||||
|
size_t *tapfdSize)
|
||||||
|
ATTRIBUTE_NONNULL(2);
|
||||||
#endif /* __QEMU_INTERFACE_H__ */
|
#endif /* __QEMU_INTERFACE_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user