]> xenbits.xensource.com Git - libvirt.git/commitdiff
conf: add hypervisor agnostic, domain start-time, validation function for NetDef
authorLaine Stump <laine@redhat.com>
Fri, 18 Oct 2019 19:48:13 +0000 (15:48 -0400)
committerLaine Stump <laine@redhat.com>
Mon, 25 Nov 2019 20:30:05 +0000 (15:30 -0500)
<interface> devices (virDomainNetDef) are a bit different from other
types of devices in that their actual type may come from a network (in
the form of a port connection), and that doesn't happen until the
domain is started. This means that any validation of an <interface> at
parse time needs to be a bit liberal in what it accepts - when
type='network', you could think that something is/isn't allowed, but
once the domain is started and a port is created by the configured
network, the opposite might be true.

To solve this problem hypervisor drivers need to do an extra
validation step when the domain is being started. I recently (commit
3cff23f7, libvirt 5.7.0) added a function to peform such validation
for all interfaces to the QEMU driver -
qemuDomainValidateActualNetDef() - but while that function is a good
single point to call for the multiple places that need to "start" an
interface (domain startup, device hotplug, device update), it can't be
called by the other hypervisor drivers, since 1) it's in the QEMU
driver, and 2) it contains some checks specific to QEMU. For
validation that applies to network devices on *all* hypervisors, we
need yet another interface validation function that can be called by
any hypervisor driver (not just QEMU) right after its network port has
been created during domain startup or hotplug. This patch adds that
function - virDomainActualNetDefValidate(), in the conf directory,
and calls it in appropriate places in the QEMU, lxc, and libxl
drivers.

This new function is the place to put all network device validation
that 1) is hypervisor agnostic, and 2) can't be done until we know the
"actual type" of an interface.

There is no framework for validation at domain startup as there is for
post-parse validation, but I don't want to create a whole elaborate
system that will only be used by one type of device. For that reason,
I just made a single function that should be called directly from the
hypervisors, when they are initializing interfaces to start a domain,
right after conditionally allocating the network port (and regardless
of whether or not that was actually needed). In the case of the QEMU
driver, qemuDomainValidateActualNetDef() is already called in all the
appropriate places, so we can just call the new function from
there. In the case of the other hypervisors, we search for
virDomainNetAllocateActualDevice() (which is the hypervisor-agnostic
function that calls virNetworkPortCreateXML()), and add the call to our
new function right after that.

The new function itself could be plunked down into many places in the
code, but we already have 3 validation functions for network devices
in 2 different places (not counting any basic validation done in
virDomainNetDefParseXML() itself):

1) post-parse hypervisor-agnostic
   (virDomainNetDefValidate() - domain_conf.c:6145)
2) post-parse hypervisor-specific
   (qemuDomainDeviceDefValidateNetwork() - qemu_domain.c:5498)
3) domain-start hypervisor-specific
   (qemuDomainValidateActualNetDef() - qemu_domain.c:5390)

I placed (3) right next to (2) when I added it, specifically to avoid
spreading validation all over the code. For the same reason, I decided
to put this new function right next to (1) - this way if someone needs
to add validation specific to qemu, they go to one location, and if
they need to add validation applying to everyone, they go to the
other. It looks a bit strange to have a public function in between a
bunch of statics, but I think it's better than the alternative of
further fragmentation. (I'm open to other ideas though, of course.)

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Cole Robinson <crobinso@redhat.com>
src/conf/domain_conf.c
src/conf/domain_conf.h
src/libvirt_private.syms
src/libxl/libxl_domain.c
src/libxl/libxl_driver.c
src/lxc/lxc_driver.c
src/lxc/lxc_process.c
src/qemu/qemu_domain.c

index 6fb08fa4a8ced51b7dd2824598fe31b29f680c3b..1b59d04d34ddc47d83c6028f984da0f944f2ee39 100644 (file)
@@ -6134,6 +6134,28 @@ virDomainRedirdevDefValidate(const virDomainDef *def,
 }
 
 
+int
+virDomainActualNetDefValidate(const virDomainNetDef *net G_GNUC_UNUSED)
+{
+    /* Unlike virDomainNetDefValidate(), which is a static function
+     * called internally to this file, virDomainActualNetDefValidate()
+     * is a public function that can be called from a hypervisor after
+     * it has completely setup the NetDef for use by a domain,
+     * including possibly allocating a port from the network driver
+     * (which could change the effective/"actual" type of the NetDef,
+     * thus changing what should/shouldn't be allowed by validation).
+     *
+     * This function should contain validations not specific to a
+     * particular hypervisor (e.g. whether or not specifying bandwidth
+     * is allowed for a type of interface), but *not*
+     * hypervisor-specific things.
+     */
+
+    return 0;
+
+}
+
+
 static int
 virDomainNetDefValidate(const virDomainNetDef *net)
 {
index 31a791def38a4d1fac9bf44867562af5ca8ac058..49cb6970e631be5dae59c7e6ccaa31fec29c3ed5 100644 (file)
@@ -2803,6 +2803,9 @@ int virDomainDefValidate(virDomainDefPtr def,
                          unsigned int parseFlags,
                          virDomainXMLOptionPtr xmlopt);
 
+int
+virDomainActualNetDefValidate(const virDomainNetDef *net);
+
 static inline bool
 virDomainObjIsActive(virDomainObjPtr dom)
 {
index 44201cda145f8bae6bf0ba2181a2d6865813e806..8fe0bf936573a1ac7db554a98f2029c7b72296fe 100644 (file)
@@ -211,6 +211,7 @@ virDiskNameParse;
 virDiskNameToBusDeviceIndex;
 virDiskNameToIndex;
 virDomainActualNetDefFree;
+virDomainActualNetDefValidate;
 virDomainBlockedReasonTypeFromString;
 virDomainBlockedReasonTypeToString;
 virDomainBootTypeFromString;
index e71faee63d2f29f056db8a5d65ca48457f496d08..90ea2c9ece1bced313ca0924fd8ddfe9087fbe17 100644 (file)
@@ -1057,6 +1057,10 @@ libxlNetworkPrepareDevices(virDomainDefPtr def)
                 goto cleanup;
         }
 
+        /* final validation now that actual type is known */
+        if (virDomainActualNetDefValidate(net) < 0)
+            return -1;
+
         actualType = virDomainNetGetActualType(net);
         if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
             net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
index ec6a010030d44ab31bed9d58484e6073ddaa8e59..44a74e87792776f5d3d51ab07039725689a1fad7 100644 (file)
@@ -3412,6 +3412,10 @@ libxlDomainAttachNetDevice(libxlDriverPrivatePtr driver,
             goto cleanup;
     }
 
+    /* final validation now that actual type is known */
+    if (virDomainActualNetDefValidate(net) < 0)
+        return -1;
+
     actualType = virDomainNetGetActualType(net);
 
     if (virDomainHasNet(vm->def, net)) {
index dcf48c981c42b060f58107e8d35c2febf156dd71..826bf074e37871972a3bc722d379f3d5a6f4b473 100644 (file)
@@ -3843,6 +3843,10 @@ lxcDomainAttachDeviceNetLive(virConnectPtr conn,
         virObjectUnref(netconn);
     }
 
+    /* final validation now that actual type is known */
+    if (virDomainActualNetDefValidate(net) < 0)
+        return -1;
+
     actualType = virDomainNetGetActualType(net);
 
     switch (actualType) {
index cbcb3419311772b179a3f8b049783579c601f9bf..9b62a930964b7559311b6095821df2e3d16f7d8a 100644 (file)
@@ -563,6 +563,10 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
                 goto cleanup;
         }
 
+        /* final validation now that actual type is known */
+        if (virDomainActualNetDefValidate(net) < 0)
+            return -1;
+
         type = virDomainNetGetActualType(net);
         switch (type) {
         case VIR_DOMAIN_NET_TYPE_NETWORK:
index 1d2d6b3f55c482482dac73896528d1cbd04c9f72..c233a4ba9653584187c03757696c260b1d3d18fd 100644 (file)
@@ -5461,6 +5461,12 @@ qemuDomainValidateActualNetDef(const virDomainNetDef *net,
 
     virMacAddrFormat(&net->mac, macstr);
 
+    /* hypervisor-agnostic validation */
+    if (virDomainActualNetDefValidate(net) < 0)
+        return -1;
+
+    /* QEMU-specific validation */
+
     /* Only tap/macvtap devices support multiqueue. */
     if (net->driver.virtio.queues > 0) {