[libvirt PATCH] hypervisor: Move interface mgmt methods to hypervisor

Praveen K Paladugu posted 1 patch 6 months, 2 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20231012193742.64794-1-prapal@linux.microsoft.com
There is a newer version of this series
po/POTFILES                       |   1 +
src/hypervisor/domain_interface.c | 279 ++++++++++++++++++++++++++++++
src/hypervisor/domain_interface.h |  38 ++++
src/hypervisor/meson.build        |   1 +
src/libvirt_private.syms          |   6 +
src/qemu/qemu_command.c           |   7 +-
src/qemu/qemu_hotplug.c           |   3 +-
src/qemu/qemu_interface.c         | 246 +-------------------------
src/qemu/qemu_interface.h         |   6 -
src/qemu/qemu_process.c           |   3 +-
10 files changed, 341 insertions(+), 249 deletions(-)
create mode 100644 src/hypervisor/domain_interface.c
create mode 100644 src/hypervisor/domain_interface.h
[libvirt PATCH] hypervisor: Move interface mgmt methods to hypervisor
Posted by Praveen K Paladugu 6 months, 2 weeks ago
Move guest interface management methods from qemu to hypervisor. These
methods will be shared by networking support in ch driver.

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
---
 po/POTFILES                       |   1 +
 src/hypervisor/domain_interface.c | 279 ++++++++++++++++++++++++++++++
 src/hypervisor/domain_interface.h |  38 ++++
 src/hypervisor/meson.build        |   1 +
 src/libvirt_private.syms          |   6 +
 src/qemu/qemu_command.c           |   7 +-
 src/qemu/qemu_hotplug.c           |   3 +-
 src/qemu/qemu_interface.c         | 246 +-------------------------
 src/qemu/qemu_interface.h         |   6 -
 src/qemu/qemu_process.c           |   3 +-
 10 files changed, 341 insertions(+), 249 deletions(-)
 create mode 100644 src/hypervisor/domain_interface.c
 create mode 100644 src/hypervisor/domain_interface.h

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..b01b6ee767
--- /dev/null
+++ b/src/hypervisor/domain_interface.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright Microsoft Corp. 2023
+ *
+ * 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 "virmacaddr.h"
+#include "virnetdevtap.h"
+#include "virconftypes.h"
+#include "domain_conf.h"
+#include "domain_interface.h"
+#include "domain_nwfilter.h"
+#include "domain_audit.h"
+#include "virebtables.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "viralloc.h"
+#include "virnetdevbridge.h"
+#include "network_conf.h"
+
+#define VIR_FROM_THIS VIR_FROM_INTERFACE
+
+VIR_LOG_INIT("interface.interface_connect");
+
+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
+ * @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
+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;
+        }
+    }
+    VIR_WARN("PPK: interfaceEthernetConnect Called\n");
+    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;
+}
+
+/**
+ * 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
+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;
+}
diff --git a/src/hypervisor/domain_interface.h b/src/hypervisor/domain_interface.h
new file mode 100644
index 0000000000..4e76b84990
--- /dev/null
+++ b/src/hypervisor/domain_interface.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright Microsoft Corp. 2023
+ *
+ * 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);
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 4e475d5b1a..cae0ecb857 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1630,6 +1630,12 @@ virDomainDriverNodeDeviceReset;
 virDomainDriverParseBlkioDeviceStr;
 virDomainDriverSetupPersistentDefBlkioParams;
 
+# hypervisor/domain_interface.h
+virDomainInterfaceEthernetConnect;
+virDomainInterfaceIsVnetCompatModel;
+virDomainInterfaceStartDevice;
+virDomainInterfaceStartDevices;
+
 
 # hypervisor/virclosecallbacks.h
 virCloseCallbacksDomainAdd;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8a7b80719f..eda5327293 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"
@@ -53,6 +54,7 @@
 #include "virmdev.h"
 #include "virutil.h"
 
+
 #include <sys/stat.h>
 #include <fcntl.h>
 
@@ -8523,7 +8525,10 @@ qemuBuildInterfaceConnect(virDomainObj *vm,
         break;
 
     case VIR_DOMAIN_NET_TYPE_ETHERNET:
-        if (qemuInterfaceEthernetConnect(vm->def, priv->driver, net,
+        if (virDomainInterfaceEthernetConnect(vm->def, net,
+                                        priv->driver->ebtables,
+                                        priv->driver->config->macFilter,
+                                        priv->driver->privileged,
                                          tapfd, tapfdSize) < 0)
             return -1;
         vhostfd = true;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 1f7f5bdd26..8e76cb8b38 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"
@@ -1269,7 +1270,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
     }
 
     /* Set device online immediately */
-    if (qemuInterfaceStartDevice(net) < 0)
+    if (virDomainInterfaceStartDevice(net) < 0)
         goto cleanup;
 
     qemuDomainInterfaceSetDefaultQDisc(driver, net);
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index 8856bb95a8..48e3422ae1 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,110 +42,9 @@
 
 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;
-}
 
 
 /**
@@ -166,7 +66,7 @@ qemuInterfaceStopDevice(virDomainNetDef *net)
         if (virDomainNetGetActualBridgeMACTableManager(net)
             == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
             /* remove the FDB entries that were added during
-             * qemuInterfaceStartDevices()
+             * virDomainInterfaceStartDevices()
              */
             if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
                                       VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
@@ -236,14 +136,7 @@ qemuInterfaceStopDevices(virDomainDef *def)
 }
 
 
-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);
-}
+
 
 
 /**
@@ -271,7 +164,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 +302,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 +344,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 +364,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 6eed3e6bd7..feb299dd6c 100644
--- a/src/qemu/qemu_interface.h
+++ b/src/qemu/qemu_interface.h
@@ -37,12 +37,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 ae0bb7bf80..8a87e7e685 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"
@@ -3121,7 +3122,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));
-- 
2.41.0
Re: [libvirt PATCH] hypervisor: Move interface mgmt methods to hypervisor
Posted by Laine Stump 6 months, 2 weeks ago
On 10/12/23 3:37 PM, Praveen K Paladugu wrote:
> Move guest interface management methods from qemu to hypervisor. These
> methods will be shared by networking support in ch driver.
> 
> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
> ---
>   po/POTFILES                       |   1 +
>   src/hypervisor/domain_interface.c | 279 ++++++++++++++++++++++++++++++
>   src/hypervisor/domain_interface.h |  38 ++++
>   src/hypervisor/meson.build        |   1 +
>   src/libvirt_private.syms          |   6 +
>   src/qemu/qemu_command.c           |   7 +-
>   src/qemu/qemu_hotplug.c           |   3 +-
>   src/qemu/qemu_interface.c         | 246 +-------------------------
>   src/qemu/qemu_interface.h         |   6 -
>   src/qemu/qemu_process.c           |   3 +-
>   10 files changed, 341 insertions(+), 249 deletions(-)
>   create mode 100644 src/hypervisor/domain_interface.c
>   create mode 100644 src/hypervisor/domain_interface.h
> 
> 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..b01b6ee767
> --- /dev/null
> +++ b/src/hypervisor/domain_interface.c
> @@ -0,0 +1,279 @@
> +/*
> + * Copyright Microsoft Corp. 2023

I haven't had time to look through the rest of this yet (although it 
seems pretty straightforward, and I think it might have been me who 
suggested it in the first place :-)), I did want to bring up this one 
topic now:


Best practices for the copyright notice in a new file have changed over 
the years (for example, we no longer list the "Author" of new files and 
even removed Author from existing files, since a more accurate and 
complete version of that info is all available from git), and I haven't 
paid close attention, but since this entire file is comprised of 
functions that were just moved from an existing file and renamed (rather 
than actual new code), I don't think it's appropriate for it to erase 
all trace of the original copyright holder and simply assign the 
copyright entirely to Microsoft.

What are others' opinions on this?


> + *
> + * 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 "virmacaddr.h"
> +#include "virnetdevtap.h"
> +#include "virconftypes.h"
> +#include "domain_conf.h"
> +#include "domain_interface.h"
> +#include "domain_nwfilter.h"
> +#include "domain_audit.h"
> +#include "virebtables.h"
> +#include "virlog.h"
> +#include "virfile.h"
> +#include "viralloc.h"
> +#include "virnetdevbridge.h"
> +#include "network_conf.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_INTERFACE
> +
> +VIR_LOG_INIT("interface.interface_connect");
> +
> +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
> + * @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
> +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;
> +        }
> +    }
> +    VIR_WARN("PPK: interfaceEthernetConnect Called\n");
> +    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;
> +}
> +
> +/**
> + * 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
> +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;
> +}
> diff --git a/src/hypervisor/domain_interface.h b/src/hypervisor/domain_interface.h
> new file mode 100644
> index 0000000000..4e76b84990
> --- /dev/null
> +++ b/src/hypervisor/domain_interface.h
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright Microsoft Corp. 2023
> + *
> + * 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);
> 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 4e475d5b1a..cae0ecb857 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1630,6 +1630,12 @@ virDomainDriverNodeDeviceReset;
>   virDomainDriverParseBlkioDeviceStr;
>   virDomainDriverSetupPersistentDefBlkioParams;
>   
> +# hypervisor/domain_interface.h
> +virDomainInterfaceEthernetConnect;
> +virDomainInterfaceIsVnetCompatModel;
> +virDomainInterfaceStartDevice;
> +virDomainInterfaceStartDevices;
> +
>   
>   # hypervisor/virclosecallbacks.h
>   virCloseCallbacksDomainAdd;
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 8a7b80719f..eda5327293 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"
> @@ -53,6 +54,7 @@
>   #include "virmdev.h"
>   #include "virutil.h"
>   
> +
>   #include <sys/stat.h>
>   #include <fcntl.h>
>   
> @@ -8523,7 +8525,10 @@ qemuBuildInterfaceConnect(virDomainObj *vm,
>           break;
>   
>       case VIR_DOMAIN_NET_TYPE_ETHERNET:
> -        if (qemuInterfaceEthernetConnect(vm->def, priv->driver, net,
> +        if (virDomainInterfaceEthernetConnect(vm->def, net,
> +                                        priv->driver->ebtables,
> +                                        priv->driver->config->macFilter,
> +                                        priv->driver->privileged,
>                                            tapfd, tapfdSize) < 0)
>               return -1;
>           vhostfd = true;
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 1f7f5bdd26..8e76cb8b38 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"
> @@ -1269,7 +1270,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
>       }
>   
>       /* Set device online immediately */
> -    if (qemuInterfaceStartDevice(net) < 0)
> +    if (virDomainInterfaceStartDevice(net) < 0)
>           goto cleanup;
>   
>       qemuDomainInterfaceSetDefaultQDisc(driver, net);
> diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
> index 8856bb95a8..48e3422ae1 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,110 +42,9 @@
>   
>   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;
> -}
>   
>   
>   /**
> @@ -166,7 +66,7 @@ qemuInterfaceStopDevice(virDomainNetDef *net)
>           if (virDomainNetGetActualBridgeMACTableManager(net)
>               == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
>               /* remove the FDB entries that were added during
> -             * qemuInterfaceStartDevices()
> +             * virDomainInterfaceStartDevices()
>                */
>               if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
>                                         VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
> @@ -236,14 +136,7 @@ qemuInterfaceStopDevices(virDomainDef *def)
>   }
>   
>   
> -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);
> -}
> +
>   
>   
>   /**
> @@ -271,7 +164,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 +302,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 +344,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 +364,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 6eed3e6bd7..feb299dd6c 100644
> --- a/src/qemu/qemu_interface.h
> +++ b/src/qemu/qemu_interface.h
> @@ -37,12 +37,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 ae0bb7bf80..8a87e7e685 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"
> @@ -3121,7 +3122,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));
Re: [libvirt PATCH] hypervisor: Move interface mgmt methods to hypervisor
Posted by Praveen Paladugu 6 months, 2 weeks ago
On Sun, Oct 15, 2023 at 03:03:40PM -0400, Laine Stump wrote:
> On 10/12/23 3:37 PM, Praveen K Paladugu wrote:
> >Move guest interface management methods from qemu to hypervisor. These
> >methods will be shared by networking support in ch driver.
> >
> >Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
> >---
> >  po/POTFILES                       |   1 +
> >  src/hypervisor/domain_interface.c | 279 ++++++++++++++++++++++++++++++
> >  src/hypervisor/domain_interface.h |  38 ++++
> >  src/hypervisor/meson.build        |   1 +
> >  src/libvirt_private.syms          |   6 +
> >  src/qemu/qemu_command.c           |   7 +-
> >  src/qemu/qemu_hotplug.c           |   3 +-
> >  src/qemu/qemu_interface.c         | 246 +-------------------------
> >  src/qemu/qemu_interface.h         |   6 -
> >  src/qemu/qemu_process.c           |   3 +-
> >  10 files changed, 341 insertions(+), 249 deletions(-)
> >  create mode 100644 src/hypervisor/domain_interface.c
> >  create mode 100644 src/hypervisor/domain_interface.h
> >
> >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..b01b6ee767
> >--- /dev/null
> >+++ b/src/hypervisor/domain_interface.c
> >@@ -0,0 +1,279 @@
> >+/*
> >+ * Copyright Microsoft Corp. 2023
> 
> I haven't had time to look through the rest of this yet (although it
> seems pretty straightforward, and I think it might have been me who
> suggested it in the first place :-)), I did want to bring up this
> one topic now:
> 
> 
> Best practices for the copyright notice in a new file have changed
> over the years (for example, we no longer list the "Author" of new
> files and even removed Author from existing files, since a more
> accurate and complete version of that info is all available from
> git), and I haven't paid close attention, but since this entire file
> is comprised of functions that were just moved from an existing file
> and renamed (rather than actual new code), I don't think it's
> appropriate for it to erase all trace of the original copyright
> holder and simply assign the copyright entirely to Microsoft.
> 
> What are others' opinions on this?
> 
> 
Thanks for the pointing this out. It was a miss on my part. I will send
an updated version with the original copyrights included.

- Praveen
> >+ *
> >+ * 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 "virmacaddr.h"
> >+#include "virnetdevtap.h"
> >+#include "virconftypes.h"
> >+#include "domain_conf.h"
> >+#include "domain_interface.h"
> >+#include "domain_nwfilter.h"
> >+#include "domain_audit.h"
> >+#include "virebtables.h"
> >+#include "virlog.h"
> >+#include "virfile.h"
> >+#include "viralloc.h"
> >+#include "virnetdevbridge.h"
> >+#include "network_conf.h"
> >+
> >+#define VIR_FROM_THIS VIR_FROM_INTERFACE
> >+
> >+VIR_LOG_INIT("interface.interface_connect");
> >+
> >+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
> >+ * @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
> >+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;
> >+        }
> >+    }
> >+    VIR_WARN("PPK: interfaceEthernetConnect Called\n");
> >+    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;
> >+}
> >+
> >+/**
> >+ * 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
> >+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;
> >+}
> >diff --git a/src/hypervisor/domain_interface.h b/src/hypervisor/domain_interface.h
> >new file mode 100644
> >index 0000000000..4e76b84990
> >--- /dev/null
> >+++ b/src/hypervisor/domain_interface.h
> >@@ -0,0 +1,38 @@
> >+/*
> >+ * Copyright Microsoft Corp. 2023
> >+ *
> >+ * 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);
> >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 4e475d5b1a..cae0ecb857 100644
> >--- a/src/libvirt_private.syms
> >+++ b/src/libvirt_private.syms
> >@@ -1630,6 +1630,12 @@ virDomainDriverNodeDeviceReset;
> >  virDomainDriverParseBlkioDeviceStr;
> >  virDomainDriverSetupPersistentDefBlkioParams;
> >+# hypervisor/domain_interface.h
> >+virDomainInterfaceEthernetConnect;
> >+virDomainInterfaceIsVnetCompatModel;
> >+virDomainInterfaceStartDevice;
> >+virDomainInterfaceStartDevices;
> >+
> >  # hypervisor/virclosecallbacks.h
> >  virCloseCallbacksDomainAdd;
> >diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> >index 8a7b80719f..eda5327293 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"
> >@@ -53,6 +54,7 @@
> >  #include "virmdev.h"
> >  #include "virutil.h"
> >+
> >  #include <sys/stat.h>
> >  #include <fcntl.h>
> >@@ -8523,7 +8525,10 @@ qemuBuildInterfaceConnect(virDomainObj *vm,
> >          break;
> >      case VIR_DOMAIN_NET_TYPE_ETHERNET:
> >-        if (qemuInterfaceEthernetConnect(vm->def, priv->driver, net,
> >+        if (virDomainInterfaceEthernetConnect(vm->def, net,
> >+                                        priv->driver->ebtables,
> >+                                        priv->driver->config->macFilter,
> >+                                        priv->driver->privileged,
> >                                           tapfd, tapfdSize) < 0)
> >              return -1;
> >          vhostfd = true;
> >diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> >index 1f7f5bdd26..8e76cb8b38 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"
> >@@ -1269,7 +1270,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
> >      }
> >      /* Set device online immediately */
> >-    if (qemuInterfaceStartDevice(net) < 0)
> >+    if (virDomainInterfaceStartDevice(net) < 0)
> >          goto cleanup;
> >      qemuDomainInterfaceSetDefaultQDisc(driver, net);
> >diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
> >index 8856bb95a8..48e3422ae1 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,110 +42,9 @@
> >  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;
> >-}
> >  /**
> >@@ -166,7 +66,7 @@ qemuInterfaceStopDevice(virDomainNetDef *net)
> >          if (virDomainNetGetActualBridgeMACTableManager(net)
> >              == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
> >              /* remove the FDB entries that were added during
> >-             * qemuInterfaceStartDevices()
> >+             * virDomainInterfaceStartDevices()
> >               */
> >              if (virNetDevBridgeFDBDel(&net->mac, net->ifname,
> >                                        VIR_NETDEVBRIDGE_FDB_FLAG_MASTER |
> >@@ -236,14 +136,7 @@ qemuInterfaceStopDevices(virDomainDef *def)
> >  }
> >-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);
> >-}
> >+
> >  /**
> >@@ -271,7 +164,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 +302,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 +344,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 +364,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 6eed3e6bd7..feb299dd6c 100644
> >--- a/src/qemu/qemu_interface.h
> >+++ b/src/qemu/qemu_interface.h
> >@@ -37,12 +37,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 ae0bb7bf80..8a87e7e685 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"
> >@@ -3121,7 +3122,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));
Re: [libvirt PATCH] hypervisor: Move interface mgmt methods to hypervisor
Posted by Daniel P. Berrangé 6 months, 2 weeks ago
On Sun, Oct 15, 2023 at 03:03:40PM -0400, Laine Stump wrote:
> On 10/12/23 3:37 PM, Praveen K Paladugu wrote:
> > Move guest interface management methods from qemu to hypervisor. These
> > methods will be shared by networking support in ch driver.
> > 
> > Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
> > ---
> >   po/POTFILES                       |   1 +
> >   src/hypervisor/domain_interface.c | 279 ++++++++++++++++++++++++++++++
> >   src/hypervisor/domain_interface.h |  38 ++++
> >   src/hypervisor/meson.build        |   1 +
> >   src/libvirt_private.syms          |   6 +
> >   src/qemu/qemu_command.c           |   7 +-
> >   src/qemu/qemu_hotplug.c           |   3 +-
> >   src/qemu/qemu_interface.c         | 246 +-------------------------
> >   src/qemu/qemu_interface.h         |   6 -
> >   src/qemu/qemu_process.c           |   3 +-
> >   10 files changed, 341 insertions(+), 249 deletions(-)
> >   create mode 100644 src/hypervisor/domain_interface.c
> >   create mode 100644 src/hypervisor/domain_interface.h
> > 
> > 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..b01b6ee767
> > --- /dev/null
> > +++ b/src/hypervisor/domain_interface.c
> > @@ -0,0 +1,279 @@
> > +/*
> > + * Copyright Microsoft Corp. 2023
> 
> I haven't had time to look through the rest of this yet (although it seems
> pretty straightforward, and I think it might have been me who suggested it
> in the first place :-)), I did want to bring up this one topic now:
> 
> 
> Best practices for the copyright notice in a new file have changed over the
> years (for example, we no longer list the "Author" of new files and even
> removed Author from existing files, since a more accurate and complete
> version of that info is all available from git), and I haven't paid close
> attention, but since this entire file is comprised of functions that were
> just moved from an existing file and renamed (rather than actual new code),
> I don't think it's appropriate for it to erase all trace of the original
> copyright holder and simply assign the copyright entirely to Microsoft.

If the original file that the code was copied from had any
Copyright lines, those must be preserved in the new file.
If the original file had no copyright lines, you're not
required to do any archeology to figure out copyrighth
holders, just leave the new file similarly devoid.

Simply moving code is also not a copyrightable enhancement,
so adding your own copyright on moved code is inappropriate.

Once you add new functionality to the newfile though, you
are free to add your own copyright statement at that point,
if desired.


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|