diff --git a/po/POTFILES b/po/POTFILES
index 3a51aea5cb..023c041f61 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -92,6 +92,7 @@ src/hyperv/hyperv_util.c
src/hyperv/hyperv_wmi.c
src/hypervisor/domain_cgroup.c
src/hypervisor/domain_driver.c
+src/hypervisor/domain_interface.c
src/hypervisor/virhostdev.c
src/interface/interface_backend_netcf.c
src/interface/interface_backend_udev.c
diff --git a/src/hypervisor/domain_interface.c b/src/hypervisor/domain_interface.c
new file mode 100644
index 0000000000..853814fe78
--- /dev/null
+++ b/src/hypervisor/domain_interface.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright IBM Corp. 2014
+ *
+ * domain_interface.c: methods to manage guest/domain interfaces
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include
+
+#include "datatypes.h"
+#include "domain_audit.h"
+#include "domain_conf.h"
+#include "domain_driver.h"
+#include "domain_interface.h"
+#include "domain_nwfilter.h"
+#include "network_conf.h"
+#include "viralloc.h"
+#include "virconftypes.h"
+#include "virebtables.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virmacaddr.h"
+#include "virnetdevbridge.h"
+#include "virnetdevmidonet.h"
+#include "virnetdevopenvswitch.h"
+#include "virnetdevtap.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_DOMAIN
+
+VIR_LOG_INIT("domain.interface");
+
+bool
+virDomainInterfaceIsVnetCompatModel(const virDomainNetDef *net)
+{
+ return (virDomainNetIsVirtioModel(net) ||
+ net->model == VIR_DOMAIN_NET_MODEL_E1000E ||
+ net->model == VIR_DOMAIN_NET_MODEL_IGB ||
+ net->model == VIR_DOMAIN_NET_MODEL_VMXNET3);
+}
+
+/* virDomainInterfaceEthernetConnect:
+ * @def: the definition of the VM
+ * @net: a net definition in the VM
+ * @ebtables: ebtales context
+ * @macFilter: whether driver support mac Filtering
+ * @privileged: whether running as privileged user
+ * @tapfd: returned array of file descriptors for the domain interface
+ * @tapfdsize: returned number of file descriptors in @tapfd
+ *
+ * Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_ETHERNET
+ * (i.e. if the connection is made with a tap device)
+ */
+int
+virDomainInterfaceEthernetConnect(virDomainDef *def,
+ virDomainNetDef *net,
+ ebtablesContext *ebtables,
+ bool macFilter,
+ bool privileged,
+ int *tapfd,
+ size_t tapfdSize)
+{
+ virMacAddr tapmac;
+ int ret = -1;
+ unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
+ bool template_ifname = false;
+ const char *tunpath = "/dev/net/tun";
+ const char *auditdev = tunpath;
+
+ if (net->backend.tap) {
+ tunpath = net->backend.tap;
+ if (!privileged) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot use custom tap device in session mode"));
+ goto cleanup;
+ }
+ }
+
+ if (virDomainInterfaceIsVnetCompatModel(net))
+ tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
+
+ if (net->managed_tap == VIR_TRISTATE_BOOL_NO) {
+ if (!net->ifname) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("target dev must be supplied when managed='no'"));
+ goto cleanup;
+ }
+ if (virNetDevExists(net->ifname) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("target managed='no' but specified dev doesn't exist"));
+ goto cleanup;
+ }
+
+ tap_create_flags |= VIR_NETDEV_TAP_CREATE_ALLOW_EXISTING;
+
+ if (virNetDevMacVLanIsMacvtap(net->ifname)) {
+ auditdev = net->ifname;
+ if (virNetDevMacVLanTapOpen(net->ifname, tapfd, tapfdSize) < 0)
+ goto cleanup;
+ if (virNetDevMacVLanTapSetup(tapfd, tapfdSize,
+ virDomainInterfaceIsVnetCompatModel(net)) < 0) {
+ goto cleanup;
+ }
+ } else {
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
+ tap_create_flags) < 0)
+ goto cleanup;
+ }
+ } else {
+
+ if (!net->ifname)
+ template_ifname = true;
+
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
+ tap_create_flags) < 0) {
+ goto cleanup;
+ }
+
+ /* The tap device's MAC address cannot match the MAC address
+ * used by the guest. This results in "received packet on
+ * vnetX with own address as source address" error logs from
+ * the kernel.
+ */
+ virMacAddrSet(&tapmac, &net->mac);
+ if (tapmac.addr[0] == 0xFE)
+ tapmac.addr[0] = 0xFA;
+ else
+ tapmac.addr[0] = 0xFE;
+
+ if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
+ goto cleanup;
+
+ if (virNetDevSetOnline(net->ifname, true) < 0)
+ goto cleanup;
+ }
+
+ if (net->script &&
+ virNetDevRunEthernetScript(net->ifname, net->script) < 0)
+ goto cleanup;
+
+ if (macFilter &&
+ ebtablesAddForwardAllowIn(ebtables,
+ net->ifname,
+ &net->mac) < 0)
+ goto cleanup;
+
+ if (net->filter &&
+ virDomainConfNWFilterInstantiate(def->name, def->uuid, net, false) < 0) {
+ goto cleanup;
+ }
+
+ virDomainAuditNetDevice(def, net, auditdev, true);
+
+ ret = 0;
+
+ cleanup:
+ if (ret < 0) {
+ size_t i;
+
+ virDomainAuditNetDevice(def, net, auditdev, false);
+ for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
+ VIR_FORCE_CLOSE(tapfd[i]);
+ if (template_ifname)
+ VIR_FREE(net->ifname);
+ }
+
+ return ret;
+}
+
+/**
+ * virDomainInterfaceStartDevice:
+ * @net: net device to start
+ *
+ * Based upon the type of device provided, perform the appropriate
+ * work to completely activate the device and make it reachable from
+ * the rest of the network.
+ */
+int
+virDomainInterfaceStartDevice(virDomainNetDef *net)
+{
+ virDomainNetType actualType = virDomainNetGetActualType(net);
+
+ switch (actualType) {
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ 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 have turned off learning and
+ * unicast_flood on the device to prevent the kernel from
+ * adding any FDB entries for it. This means we need to
+ * add an fdb entry ourselves, using the MAC address from
+ * the interface config.
+ */
+ if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
+ VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
+ VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_DIRECT: {
+ const char *physdev = virDomainNetGetActualDirectDev(net);
+ bool isOnline = true;
+
+ /* set the physdev online if necessary. It may already be up,
+ * in which case we shouldn't re-up it just in case that causes
+ * some sort of "blip" in the physdev's status.
+ */
+ if (physdev && virNetDevGetOnline(physdev, &isOnline) < 0)
+ return -1;
+ if (!isOnline && virNetDevSetOnline(physdev, true) < 0)
+ return -1;
+
+ /* macvtap devices share their MAC address with the guest
+ * domain, and if they are set online prior to the domain CPUs
+ * being started, the host may send out traffic from this
+ * device that could confuse other entities on the network (in
+ * particular, if this new domain is the destination of a
+ * migration, and the source domain is still running, another
+ * host may mistakenly direct traffic for the guest to the
+ * destination domain rather than source domain). To prevent
+ * this, we create the macvtap device with IFF_UP false
+ * (i.e. "offline") then wait to bring it online until just as
+ * we are starting the domain CPUs.
+ */
+ if (virNetDevSetOnline(net->ifname, true) < 0)
+ return -1;
+ break;
+ }
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (virNetDevIPInfoAddToDev(net->ifname, &net->hostIP) < 0)
+ return -1;
+
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_USER:
+ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ case VIR_DOMAIN_NET_TYPE_UDP:
+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ case VIR_DOMAIN_NET_TYPE_VDPA:
+ case VIR_DOMAIN_NET_TYPE_NULL:
+ case VIR_DOMAIN_NET_TYPE_VDS:
+ case VIR_DOMAIN_NET_TYPE_LAST:
+ /* these types all require no action */
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * virDomainInterfaceStartDevices:
+ * @def: domain definition
+ *
+ * Set all ifaces associated with this domain to the online state.
+ */
+int
+virDomainInterfaceStartDevices(virDomainDef *def)
+{
+ size_t i;
+
+ for (i = 0; i < def->nnets; i++) {
+ if (virDomainInterfaceStartDevice(def->nets[i]) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * virDomainInterfaceStopDevice:
+ * @net: net device to stop
+ *
+ * Based upon the type of device provided, perform the appropriate
+ * work to deactivate the device so that packets aren't forwarded to
+ * it from the rest of the network.
+ */
+int
+virDomainInterfaceStopDevice(virDomainNetDef *net)
+{
+ virDomainNetType actualType = virDomainNetGetActualType(net);
+
+ switch (actualType) {
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (virDomainNetGetActualBridgeMACTableManager(net) ==
+ VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
+ /* remove the FDB entries that were added during
+ * virDomainInterfaceStartDevices()
+ */
+ if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
+ VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
+ VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_DIRECT: {
+ const char *physdev = virDomainNetGetActualDirectDev(net);
+
+ /* macvtap interfaces need to be marked !IFF_UP (ie "down") to
+ * prevent any host-generated traffic sent from this interface
+ * from putting bad info into the arp caches of other machines
+ * on this network.
+ */
+ if (virNetDevSetOnline(net->ifname, false) < 0)
+ return -1;
+
+ /* also mark the physdev down for passthrough macvtap, as the
+ * physdev has the same MAC address as the macvtap device.
+ */
+ if (virDomainNetGetActualDirectMode(net) ==
+ VIR_NETDEV_MACVLAN_MODE_PASSTHRU &&
+ physdev && virNetDevSetOnline(physdev, false) < 0)
+ return -1;
+ break;
+ }
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ case VIR_DOMAIN_NET_TYPE_USER:
+ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ case VIR_DOMAIN_NET_TYPE_UDP:
+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ case VIR_DOMAIN_NET_TYPE_VDPA:
+ case VIR_DOMAIN_NET_TYPE_NULL:
+ case VIR_DOMAIN_NET_TYPE_VDS:
+ case VIR_DOMAIN_NET_TYPE_LAST:
+ /* these types all require no action */
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * virDomainInterfaceStopDevices:
+ * @def: domain definition
+ *
+ * Make all interfaces associated with this domain inaccessible from
+ * the rest of the network.
+ */
+int
+virDomainInterfaceStopDevices(virDomainDef *def)
+{
+ size_t i;
+
+ for (i = 0; i < def->nnets; i++) {
+ if (virDomainInterfaceStopDevice(def->nets[i]) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * virDomainInterfaceDeleteDevice:
+ * @def: domain definition
+ * @net: a net definition in the VM
+ * @priv_net_created: whether private network created
+ * @stateDir: driver's stateDir
+ *
+ * Disconnect and delete domain interfaces.
+ */
+
+void
+virDomainInterfaceDeleteDevice(virDomainDef *def,
+ virDomainNetDef *net,
+ bool priv_net_created,
+ char *stateDir)
+{
+ const virNetDevVPortProfile *vport = NULL;
+ g_autoptr(virConnect) conn = NULL;
+
+ vport = virDomainNetGetActualVirtPortProfile(net);
+ switch (virDomainNetGetActualType(net)) {
+ case VIR_DOMAIN_NET_TYPE_DIRECT:
+ if (priv_net_created) {
+ virNetDevMacVLanDeleteWithVPortProfile(net->ifname, &net->mac,
+ virDomainNetGetActualDirectDev(net),
+ virDomainNetGetActualDirectMode(net),
+ virDomainNetGetActualVirtPortProfile(net),
+ stateDir);
+ }
+ break;
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (net->managed_tap != VIR_TRISTATE_BOOL_NO && net->ifname) {
+ ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
+ VIR_FREE(net->ifname);
+ }
+ break;
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP
+ if (!(vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))
+ ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
+#endif
+ break;
+ case VIR_DOMAIN_NET_TYPE_USER:
+ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ case VIR_DOMAIN_NET_TYPE_UDP:
+ case VIR_DOMAIN_NET_TYPE_VDPA:
+ case VIR_DOMAIN_NET_TYPE_NULL:
+ case VIR_DOMAIN_NET_TYPE_VDS:
+ case VIR_DOMAIN_NET_TYPE_LAST:
+ /* No special cleanup procedure for these types. */
+ break;
+ }
+ /* release the physical device (or any other resources used by
+ * this interface in the network driver
+ */
+ if (vport) {
+ if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_MIDONET) {
+ ignore_value(virNetDevMidonetUnbindPort(vport));
+ } else if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
+ ignore_value(virNetDevOpenvswitchRemovePort(
+ virDomainNetGetActualBridgeName(net),
+ net->ifname));
+ }
+ }
+
+ /* kick the device out of the hostdev list too */
+ virDomainNetRemoveHostdev(def, net);
+ if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
+ if (conn || (conn = virGetConnectNetwork()))
+ virDomainNetReleaseActualDevice(conn, net);
+ else
+ VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
+ }
+
+}
diff --git a/src/hypervisor/domain_interface.h b/src/hypervisor/domain_interface.h
new file mode 100644
index 0000000000..3d15e000cc
--- /dev/null
+++ b/src/hypervisor/domain_interface.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright IBM Corp. 2014
+ *
+ * domain_interface.h: methods to manage guest/domain interfaces
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#pragma once
+
+#include "virebtables.h"
+
+int
+virDomainInterfaceEthernetConnect(virDomainDef *def,
+ virDomainNetDef *net,
+ ebtablesContext *ebtables,
+ bool macFilter,
+ bool privileged,
+ int *tapfd,
+ size_t tapfdSize);
+
+bool
+virDomainInterfaceIsVnetCompatModel(const virDomainNetDef *net);
+
+int virDomainInterfaceStartDevice(virDomainNetDef *net);
+int virDomainInterfaceStartDevices(virDomainDef *def);
+int virDomainInterfaceStopDevice(virDomainNetDef *net);
+int virDomainInterfaceStopDevices(virDomainDef *def);
+void virDomainInterfaceDeleteDevice(virDomainDef *def,
+ virDomainNetDef *net,
+ bool priv_net_created,
+ char *stateDir);
diff --git a/src/hypervisor/meson.build b/src/hypervisor/meson.build
index f35565b16b..819a9a82a2 100644
--- a/src/hypervisor/meson.build
+++ b/src/hypervisor/meson.build
@@ -1,6 +1,7 @@
hypervisor_sources = [
'domain_cgroup.c',
'domain_driver.c',
+ 'domain_interface.c',
'virclosecallbacks.c',
'virhostdev.c',
]
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2ebc0de212..1a7d80ddf4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1631,6 +1631,15 @@ virDomainDriverNodeDeviceReset;
virDomainDriverParseBlkioDeviceStr;
virDomainDriverSetupPersistentDefBlkioParams;
+# hypervisor/domain_interface.h
+virDomainInterfaceDeleteDevice;
+virDomainInterfaceEthernetConnect;
+virDomainInterfaceIsVnetCompatModel;
+virDomainInterfaceStartDevice;
+virDomainInterfaceStartDevices;
+virDomainInterfaceStopDevice;
+virDomainInterfaceStopDevices;
+
# hypervisor/virclosecallbacks.h
virCloseCallbacksDomainAdd;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index aa77821331..2719574fb5 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -43,6 +43,7 @@
#include "domain_nwfilter.h"
#include "domain_addr.h"
#include "domain_conf.h"
+#include "domain_interface.h"
#include "netdev_bandwidth_conf.h"
#include "virnetdevopenvswitch.h"
#include "device_conf.h"
@@ -8644,8 +8645,11 @@ qemuBuildInterfaceConnect(virDomainObj *vm,
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (qemuInterfaceEthernetConnect(vm->def, priv->driver, net,
- tapfd, tapfdSize) < 0)
+ if (virDomainInterfaceEthernetConnect(vm->def, net,
+ priv->driver->ebtables,
+ priv->driver->config->macFilter,
+ priv->driver->privileged,
+ tapfd, tapfdSize) < 0)
return -1;
vhostfd = true;
break;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 62436680c3..06323c2535 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -39,6 +39,7 @@
#include "qemu_virtiofs.h"
#include "domain_audit.h"
#include "domain_cgroup.h"
+#include "domain_interface.h"
#include "netdev_bandwidth_conf.h"
#include "domain_nwfilter.h"
#include "virlog.h"
@@ -1283,7 +1284,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
}
/* Set device online immediately */
- if (qemuInterfaceStartDevice(net) < 0)
+ if (virDomainInterfaceStartDevice(net) < 0)
goto cleanup;
qemuDomainInterfaceSetDefaultQDisc(driver, net);
@@ -4839,7 +4840,7 @@ qemuDomainRemoveNetDevice(virQEMUDriver *driver,
* affect the parent device (e.g. macvtap passthrough mode sets
* the parent device offline)
*/
- ignore_value(qemuInterfaceStopDevice(net));
+ ignore_value(virDomainInterfaceStopDevice(net));
qemuDomainObjEnterMonitor(vm);
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index 8856bb95a8..c2007c7043 100644
--- a/src/qemu/qemu_interface.c
+++ b/src/qemu/qemu_interface.c
@@ -24,6 +24,7 @@
#include "network_conf.h"
#include "domain_audit.h"
#include "domain_nwfilter.h"
+#include "domain_interface.h"
#include "qemu_interface.h"
#include "viralloc.h"
#include "virlog.h"
@@ -41,211 +42,6 @@
VIR_LOG_INIT("qemu.qemu_interface");
-/**
- * qemuInterfaceStartDevice:
- * @net: net device to start
- *
- * Based upon the type of device provided, perform the appropriate
- * work to completely activate the device and make it reachable from
- * the rest of the network.
- */
-int
-qemuInterfaceStartDevice(virDomainNetDef *net)
-{
- virDomainNetType actualType = virDomainNetGetActualType(net);
-
- switch (actualType) {
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- case VIR_DOMAIN_NET_TYPE_NETWORK:
- 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 have turned off learning and
- * unicast_flood on the device to prevent the kernel from
- * adding any FDB entries for it. This means we need to
- * add an fdb entry ourselves, using the MAC address from
- * the interface config.
- */
- if (virNetDevBridgeFDBAdd(&net->mac, net->ifname,
- VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
- VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
- return -1;
- }
- break;
-
- case VIR_DOMAIN_NET_TYPE_DIRECT: {
- const char *physdev = virDomainNetGetActualDirectDev(net);
- bool isOnline = true;
-
- /* set the physdev online if necessary. It may already be up,
- * in which case we shouldn't re-up it just in case that causes
- * some sort of "blip" in the physdev's status.
- */
- if (physdev && virNetDevGetOnline(physdev, &isOnline) < 0)
- return -1;
- if (!isOnline && virNetDevSetOnline(physdev, true) < 0)
- return -1;
-
- /* macvtap devices share their MAC address with the guest
- * domain, and if they are set online prior to the domain CPUs
- * being started, the host may send out traffic from this
- * device that could confuse other entities on the network (in
- * particular, if this new domain is the destination of a
- * migration, and the source domain is still running, another
- * host may mistakenly direct traffic for the guest to the
- * destination domain rather than source domain). To prevent
- * this, we create the macvtap device with IFF_UP false
- * (i.e. "offline") then wait to bring it online until just as
- * we are starting the domain CPUs.
- */
- if (virNetDevSetOnline(net->ifname, true) < 0)
- return -1;
- break;
- }
-
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (virNetDevIPInfoAddToDev(net->ifname, &net->hostIP) < 0)
- return -1;
-
- break;
-
- case VIR_DOMAIN_NET_TYPE_USER:
- case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
- case VIR_DOMAIN_NET_TYPE_SERVER:
- case VIR_DOMAIN_NET_TYPE_CLIENT:
- case VIR_DOMAIN_NET_TYPE_MCAST:
- case VIR_DOMAIN_NET_TYPE_UDP:
- case VIR_DOMAIN_NET_TYPE_INTERNAL:
- case VIR_DOMAIN_NET_TYPE_HOSTDEV:
- case VIR_DOMAIN_NET_TYPE_VDPA:
- case VIR_DOMAIN_NET_TYPE_NULL:
- case VIR_DOMAIN_NET_TYPE_VDS:
- case VIR_DOMAIN_NET_TYPE_LAST:
- /* these types all require no action */
- break;
- }
-
- return 0;
-}
-
-/**
- * qemuInterfaceStartDevices:
- * @def: domain definition
- *
- * Set all ifaces associated with this domain to the online state.
- */
-int
-qemuInterfaceStartDevices(virDomainDef *def)
-{
- size_t i;
-
- for (i = 0; i < def->nnets; i++) {
- if (qemuInterfaceStartDevice(def->nets[i]) < 0)
- return -1;
- }
- return 0;
-}
-
-
-/**
- * qemuInterfaceStopDevice:
- * @net: net device to stop
- *
- * Based upon the type of device provided, perform the appropriate
- * work to deactivate the device so that packets aren't forwarded to
- * it from the rest of the network.
- */
-int
-qemuInterfaceStopDevice(virDomainNetDef *net)
-{
- virDomainNetType actualType = virDomainNetGetActualType(net);
-
- switch (actualType) {
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- case VIR_DOMAIN_NET_TYPE_NETWORK:
- if (virDomainNetGetActualBridgeMACTableManager(net)
- == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
- /* remove the FDB entries that were added during
- * qemuInterfaceStartDevices()
- */
- if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
- VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
- VIR_NETDEVBRIDGE_FDB_FLAG_TEMP) < 0)
- return -1;
- }
- break;
-
- case VIR_DOMAIN_NET_TYPE_DIRECT: {
- const char *physdev = virDomainNetGetActualDirectDev(net);
-
- /* macvtap interfaces need to be marked !IFF_UP (ie "down") to
- * prevent any host-generated traffic sent from this interface
- * from putting bad info into the arp caches of other machines
- * on this network.
- */
- if (virNetDevSetOnline(net->ifname, false) < 0)
- return -1;
-
- /* also mark the physdev down for passthrough macvtap, as the
- * physdev has the same MAC address as the macvtap device.
- */
- if (virDomainNetGetActualDirectMode(net) ==
- VIR_NETDEV_MACVLAN_MODE_PASSTHRU &&
- physdev && virNetDevSetOnline(physdev, false) < 0)
- return -1;
- break;
- }
-
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- case VIR_DOMAIN_NET_TYPE_USER:
- case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
- case VIR_DOMAIN_NET_TYPE_SERVER:
- case VIR_DOMAIN_NET_TYPE_CLIENT:
- case VIR_DOMAIN_NET_TYPE_MCAST:
- case VIR_DOMAIN_NET_TYPE_UDP:
- case VIR_DOMAIN_NET_TYPE_INTERNAL:
- case VIR_DOMAIN_NET_TYPE_HOSTDEV:
- case VIR_DOMAIN_NET_TYPE_VDPA:
- case VIR_DOMAIN_NET_TYPE_NULL:
- case VIR_DOMAIN_NET_TYPE_VDS:
- case VIR_DOMAIN_NET_TYPE_LAST:
- /* these types all require no action */
- break;
- }
-
- return 0;
-}
-
-/**
- * qemuInterfaceStopDevices:
- * @def: domain definition
- *
- * Make all interfaces associated with this domain inaccessible from
- * the rest of the network.
- */
-int
-qemuInterfaceStopDevices(virDomainDef *def)
-{
- size_t i;
-
- for (i = 0; i < def->nnets; i++) {
- if (qemuInterfaceStopDevice(def->nets[i]) < 0)
- return -1;
- }
- return 0;
-}
-
-
-static bool
-qemuInterfaceIsVnetCompatModel(const virDomainNetDef *net)
-{
- return (virDomainNetIsVirtioModel(net) ||
- net->model == VIR_DOMAIN_NET_MODEL_E1000E ||
- net->model == VIR_DOMAIN_NET_MODEL_IGB ||
- net->model == VIR_DOMAIN_NET_MODEL_VMXNET3);
-}
-
-
/**
* qemuInterfaceDirectConnect:
* @def: the definition of the VM (needed by 802.1Qbh and audit)
@@ -271,7 +67,7 @@ qemuInterfaceDirectConnect(virDomainDef *def,
unsigned int macvlan_create_flags = VIR_NETDEV_MACVLAN_CREATE_WITH_TAP;
qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
- if (qemuInterfaceIsVnetCompatModel(net))
+ if (virDomainInterfaceIsVnetCompatModel(net))
macvlan_create_flags |= VIR_NETDEV_MACVLAN_VNET_HDR;
if (virNetDevMacVLanCreateWithVPortProfile(net->ifname,
@@ -409,133 +205,6 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfig *cfg,
return *tapfd < 0 ? -1 : 0;
}
-
-/* qemuInterfaceEthernetConnect:
- * @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_ETHERNET
- * (i.e. if the connection is made with a tap device)
- */
-int
-qemuInterfaceEthernetConnect(virDomainDef *def,
- virQEMUDriver *driver,
- virDomainNetDef *net,
- int *tapfd,
- size_t tapfdSize)
-{
- virMacAddr tapmac;
- int ret = -1;
- unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
- bool template_ifname = false;
- g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
- const char *tunpath = "/dev/net/tun";
- const char *auditdev = tunpath;
-
- if (net->backend.tap) {
- tunpath = net->backend.tap;
- if (!driver->privileged) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("cannot use custom tap device in session mode"));
- goto cleanup;
- }
- }
-
- if (qemuInterfaceIsVnetCompatModel(net))
- tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
-
- if (net->managed_tap == VIR_TRISTATE_BOOL_NO) {
- if (!net->ifname) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("target dev must be supplied when managed='no'"));
- goto cleanup;
- }
- if (virNetDevExists(net->ifname) != 1) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("target managed='no' but specified dev doesn't exist"));
- goto cleanup;
- }
-
- tap_create_flags |= VIR_NETDEV_TAP_CREATE_ALLOW_EXISTING;
-
- if (virNetDevMacVLanIsMacvtap(net->ifname)) {
- auditdev = net->ifname;
- if (virNetDevMacVLanTapOpen(net->ifname, tapfd, tapfdSize) < 0)
- goto cleanup;
- if (virNetDevMacVLanTapSetup(tapfd, tapfdSize,
- qemuInterfaceIsVnetCompatModel(net)) < 0) {
- goto cleanup;
- }
- } else {
- if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
- tap_create_flags) < 0)
- goto cleanup;
- }
- } else {
-
- if (!net->ifname)
- template_ifname = true;
-
- if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
- tap_create_flags) < 0) {
- goto cleanup;
- }
-
- /* The tap device's MAC address cannot match the MAC address
- * used by the guest. This results in "received packet on
- * vnetX with own address as source address" error logs from
- * the kernel.
- */
- virMacAddrSet(&tapmac, &net->mac);
- if (tapmac.addr[0] == 0xFE)
- tapmac.addr[0] = 0xFA;
- else
- tapmac.addr[0] = 0xFE;
-
- if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
- goto cleanup;
-
- if (virNetDevSetOnline(net->ifname, true) < 0)
- goto cleanup;
- }
-
- if (net->script &&
- virNetDevRunEthernetScript(net->ifname, net->script) < 0)
- goto cleanup;
-
- if (cfg->macFilter &&
- ebtablesAddForwardAllowIn(driver->ebtables,
- net->ifname,
- &net->mac) < 0)
- goto cleanup;
-
- if (net->filter &&
- virDomainConfNWFilterInstantiate(def->name, def->uuid, net, false) < 0) {
- goto cleanup;
- }
-
- virDomainAuditNetDevice(def, net, auditdev, true);
-
- ret = 0;
-
- cleanup:
- if (ret < 0) {
- size_t i;
-
- virDomainAuditNetDevice(def, net, auditdev, false);
- for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
- VIR_FORCE_CLOSE(tapfd[i]);
- if (template_ifname)
- VIR_FREE(net->ifname);
- }
-
- return ret;
-}
-
-
/* qemuInterfaceBridgeConnect:
* @def: the definition of the VM
* @driver: qemu driver data
@@ -578,7 +247,7 @@ qemuInterfaceBridgeConnect(virDomainDef *def,
if (!net->ifname)
template_ifname = true;
- if (qemuInterfaceIsVnetCompatModel(net))
+ if (virDomainInterfaceIsVnetCompatModel(net))
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
if (driver->privileged) {
@@ -598,7 +267,7 @@ qemuInterfaceBridgeConnect(virDomainDef *def,
* 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 an fdb
- * entry ourselves (during qemuInterfaceStartDevices(),
+ * entry ourselves (during virDomainInterfaceStartDevices(),
* using the MAC address from the interface config.
*/
if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h
index 67cbada36e..aee5f9efb0 100644
--- a/src/qemu/qemu_interface.h
+++ b/src/qemu/qemu_interface.h
@@ -25,11 +25,6 @@
#include "qemu_domain.h"
#include "qemu_slirp.h"
-int qemuInterfaceStartDevice(virDomainNetDef *net);
-int qemuInterfaceStartDevices(virDomainDef *def);
-int qemuInterfaceStopDevice(virDomainNetDef *net);
-int qemuInterfaceStopDevices(virDomainDef *def);
-
int qemuInterfaceDirectConnect(virDomainDef *def,
virQEMUDriver *driver,
virDomainNetDef *net,
@@ -37,12 +32,6 @@ int qemuInterfaceDirectConnect(virDomainDef *def,
size_t tapfdSize,
virNetDevVPortProfileOp vmop);
-int qemuInterfaceEthernetConnect(virDomainDef *def,
- virQEMUDriver *driver,
- virDomainNetDef *net,
- int *tapfd,
- size_t tapfdSize);
-
int qemuInterfaceBridgeConnect(virDomainDef *def,
virQEMUDriver *driver,
virDomainNetDef *net,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index fa8d8306d5..0a6c18a671 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -74,6 +74,7 @@
#include "virhostcpu.h"
#include "domain_audit.h"
#include "domain_cgroup.h"
+#include "domain_interface.h"
#include "domain_nwfilter.h"
#include "domain_postparse.h"
#include "domain_validate.h"
@@ -3120,7 +3121,7 @@ qemuProcessStartCPUs(virQEMUDriver *driver, virDomainObj *vm,
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
/* Bring up netdevs before starting CPUs */
- if (qemuInterfaceStartDevices(vm->def) < 0)
+ if (virDomainInterfaceStartDevices(vm->def) < 0)
return -1;
VIR_DEBUG("Using lock state '%s'", NULLSTR(priv->lockState));
@@ -3183,7 +3184,7 @@ int qemuProcessStopCPUs(virQEMUDriver *driver,
goto cleanup;
/* de-activate netdevs after stopping CPUs */
- ignore_value(qemuInterfaceStopDevices(vm->def));
+ ignore_value(virDomainInterfaceStopDevices(vm->def));
if (vm->job->current)
ignore_value(virTimeMillisNow(&vm->job->current->stopped));
@@ -8404,11 +8405,9 @@ void qemuProcessStop(virQEMUDriver *driver,
qemuDomainObjPrivate *priv = vm->privateData;
virErrorPtr orig_err;
virDomainDef *def = vm->def;
- const virNetDevVPortProfile *vport = NULL;
size_t i;
g_autofree char *timestamp = NULL;
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
- g_autoptr(virConnect) conn = NULL;
bool outgoingMigration;
VIR_DEBUG("Shutting down vm=%p name=%s id=%d pid=%lld, "
@@ -8547,69 +8546,12 @@ void qemuProcessStop(virQEMUDriver *driver,
}
qemuHostdevReAttachDomainDevices(driver, vm->def);
-
for (i = 0; i < def->nnets; i++) {
virDomainNetDef *net = def->nets[i];
- vport = virDomainNetGetActualVirtPortProfile(net);
- switch (virDomainNetGetActualType(net)) {
- case VIR_DOMAIN_NET_TYPE_DIRECT:
- if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->created) {
- virNetDevMacVLanDeleteWithVPortProfile(net->ifname, &net->mac,
- virDomainNetGetActualDirectDev(net),
- virDomainNetGetActualDirectMode(net),
- virDomainNetGetActualVirtPortProfile(net),
- cfg->stateDir);
- }
- break;
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (net->managed_tap != VIR_TRISTATE_BOOL_NO && net->ifname) {
- ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
- VIR_FREE(net->ifname);
- }
- break;
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- case VIR_DOMAIN_NET_TYPE_NETWORK:
-#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP
- if (!(vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))
- ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
-#endif
- break;
- case VIR_DOMAIN_NET_TYPE_USER:
- case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
- case VIR_DOMAIN_NET_TYPE_SERVER:
- case VIR_DOMAIN_NET_TYPE_CLIENT:
- case VIR_DOMAIN_NET_TYPE_MCAST:
- case VIR_DOMAIN_NET_TYPE_INTERNAL:
- case VIR_DOMAIN_NET_TYPE_HOSTDEV:
- case VIR_DOMAIN_NET_TYPE_UDP:
- case VIR_DOMAIN_NET_TYPE_VDPA:
- case VIR_DOMAIN_NET_TYPE_NULL:
- case VIR_DOMAIN_NET_TYPE_VDS:
- case VIR_DOMAIN_NET_TYPE_LAST:
- /* No special cleanup procedure for these types. */
- break;
- }
- /* release the physical device (or any other resources used by
- * this interface in the network driver
- */
- if (vport) {
- if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_MIDONET) {
- ignore_value(virNetDevMidonetUnbindPort(vport));
- } else if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
- ignore_value(virNetDevOpenvswitchRemovePort(
- virDomainNetGetActualBridgeName(net),
- net->ifname));
- }
- }
-
- /* kick the device out of the hostdev list too */
- virDomainNetRemoveHostdev(def, net);
- if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
- if (conn || (conn = virGetConnectNetwork()))
- virDomainNetReleaseActualDevice(conn, net);
- else
- VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
- }
+ virDomainInterfaceDeleteDevice(def,
+ net,
+ QEMU_DOMAIN_NETWORK_PRIVATE(net)->created,
+ cfg->stateDir);
}
retry: