]> xenbits.xensource.com Git - libvirt.git/commitdiff
hypervisor: Move domain interface mgmt methods
authorPraveen K Paladugu <prapal@linux.microsoft.com>
Tue, 16 Jan 2024 21:25:40 +0000 (15:25 -0600)
committerMichal Privoznik <mprivozn@redhat.com>
Fri, 2 Feb 2024 09:58:26 +0000 (10:58 +0100)
Move domain interface management methods from qemu to hypervisor. This
refactoring allows the domain management methods to be shared between CH and
qemu drivers.

This commit does not introduce any functional changes.

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
po/POTFILES
src/hypervisor/domain_interface.c [new file with mode: 0644]
src/hypervisor/domain_interface.h [new file with mode: 0644]
src/hypervisor/meson.build
src/libvirt_private.syms
src/qemu/qemu_command.c
src/qemu/qemu_hotplug.c
src/qemu/qemu_interface.c
src/qemu/qemu_interface.h
src/qemu/qemu_process.c

index 3a51aea5cbf728551dfaee55fdda6df02c50dcb3..023c041f611b422f5d43f9bc429777a4325bc3b0 100644 (file)
@@ -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 (file)
index 0000000..853814f
--- /dev/null
@@ -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
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#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 (file)
index 0000000..3d15e00
--- /dev/null
@@ -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
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#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);
index f35565b16b0b7b1315acec871b1bbf08b13f6c49..819a9a82a291e877956295cd3fe26557ea9c886d 100644 (file)
@@ -1,6 +1,7 @@
 hypervisor_sources = [
   'domain_cgroup.c',
   'domain_driver.c',
+  'domain_interface.c',
   'virclosecallbacks.c',
   'virhostdev.c',
 ]
index 2ebc0de212746875164feacaf1c83f652e1762de..1a7d80ddf4819b8759c19e84f653932baba990ba 100644 (file)
@@ -1631,6 +1631,15 @@ virDomainDriverNodeDeviceReset;
 virDomainDriverParseBlkioDeviceStr;
 virDomainDriverSetupPersistentDefBlkioParams;
 
+# hypervisor/domain_interface.h
+virDomainInterfaceDeleteDevice;
+virDomainInterfaceEthernetConnect;
+virDomainInterfaceIsVnetCompatModel;
+virDomainInterfaceStartDevice;
+virDomainInterfaceStartDevices;
+virDomainInterfaceStopDevice;
+virDomainInterfaceStopDevices;
+
 
 # hypervisor/virclosecallbacks.h
 virCloseCallbacksDomainAdd;
index aa77821331a9c6dfd0805f5cc71818ed6cf10f76..2719574fb58d993b39008c81f1fc0ee8a4d53f93 100644 (file)
@@ -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;
index 62436680c316d326188ee97d13e7ffa1d505715c..06323c253506c8586091da395febadebf1f310b6 100644 (file)
@@ -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) {
index 8856bb95a8fc6298848baffea0558d8073343994..c2007c7043d1bae0c8d27a32bc92b76e1e4ca174 100644 (file)
@@ -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"
 
 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)
index 67cbada36edadea84d3d446a2e004c2003b13525..aee5f9efb039960501280f3b913cfeb12bedebf4 100644 (file)
 #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,
index fa8d8306d5d819ab01b183413d2b11edc47d7901..0a6c18a67133c3a16f88c65c04347a2942d45815 100644 (file)
@@ -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: