[libvirt] [PATCH v3 06/20] nwfilter: export port binding concept in the public API

Daniel P. Berrangé berrange at redhat.com
Thu Jun 14 12:32:55 UTC 2018


When the daemons are split there will need to be a way for the virt
drivers and/or network driver to create and delete bindings between
network ports and network filters. This defines a set of public APIs
that are suitable for managing this facility.

Reviewed-by: John Ferlan <jferlan at redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
---
 include/libvirt/libvirt-nwfilter.h |  39 ++++
 include/libvirt/virterror.h        |   2 +
 src/datatypes.c                    |  67 +++++++
 src/datatypes.h                    |  31 +++
 src/driver-nwfilter.h              |  30 +++
 src/libvirt-nwfilter.c             | 305 +++++++++++++++++++++++++++++
 src/libvirt_private.syms           |   1 +
 src/libvirt_public.syms            |   9 +
 src/util/virerror.c                |  12 ++
 9 files changed, 496 insertions(+)

diff --git a/include/libvirt/libvirt-nwfilter.h b/include/libvirt/libvirt-nwfilter.h
index 9f01c175a9..20e6d1ff9a 100644
--- a/include/libvirt/libvirt-nwfilter.h
+++ b/include/libvirt/libvirt-nwfilter.h
@@ -43,6 +43,23 @@ typedef struct _virNWFilter virNWFilter;
  */
 typedef virNWFilter *virNWFilterPtr;
 
+/**
+ * virNWFilterBinding:
+ *
+ * a virNWFilterBinding is a private structure representing a network
+ * filter binding to a port
+ */
+typedef struct _virNWFilterBinding virNWFilterBinding;
+
+/**
+ * virNWFilterBindingPtr:
+ *
+ * a virNWFilterBindingPtr is pointer to a virNWFilterBinding private
+ * structure, this is the type used to reference a network filter
+ * port binding in the API.
+ */
+typedef virNWFilterBinding *virNWFilterBindingPtr;
+
 
 /*
  * List NWFilters
@@ -92,4 +109,26 @@ int                     virNWFilterGetUUIDString (virNWFilterPtr nwfilter,
 char *                  virNWFilterGetXMLDesc    (virNWFilterPtr nwfilter,
                                                   unsigned int flags);
 
+
+virNWFilterBindingPtr   virNWFilterBindingLookupByPortDev(virConnectPtr conn,
+                                                          const char *portdev);
+
+const char *            virNWFilterBindingGetPortDev(virNWFilterBindingPtr binding);
+const char *            virNWFilterBindingGetFilterName(virNWFilterBindingPtr binding);
+
+int                     virConnectListAllNWFilterBindings(virConnectPtr conn,
+                                                          virNWFilterBindingPtr **bindings,
+                                                          unsigned int flags);
+
+virNWFilterBindingPtr   virNWFilterBindingCreateXML(virConnectPtr conn,
+                                                    const char *xml,
+                                                    unsigned int flags);
+
+char *                  virNWFilterBindingGetXMLDesc(virNWFilterBindingPtr binding,
+                                                     unsigned int flags);
+
+int                     virNWFilterBindingDelete(virNWFilterBindingPtr binding);
+int                     virNWFilterBindingRef(virNWFilterBindingPtr binding);
+int                     virNWFilterBindingFree(virNWFilterBindingPtr binding);
+
 #endif /* __VIR_LIBVIRT_NWFILTER_H__ */
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 5e58b6a3f9..57aadb8d16 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -321,6 +321,8 @@ typedef enum {
                                            to guest-sync command (DEPRECATED)*/
     VIR_ERR_LIBSSH = 98,                /* error in libssh transport driver */
     VIR_ERR_DEVICE_MISSING = 99,        /* fail to find the desired device */
+    VIR_ERR_INVALID_NWFILTER_BINDING = 100,  /* invalid nwfilter binding */
+    VIR_ERR_NO_NWFILTER_BINDING = 101,  /* no nwfilter binding */
 } virErrorNumber;
 
 /**
diff --git a/src/datatypes.c b/src/datatypes.c
index 09b8eea5a2..878a1c5b5f 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -41,6 +41,7 @@ virClassPtr virInterfaceClass;
 virClassPtr virNetworkClass;
 virClassPtr virNodeDeviceClass;
 virClassPtr virNWFilterClass;
+virClassPtr virNWFilterBindingClass;
 virClassPtr virSecretClass;
 virClassPtr virStreamClass;
 virClassPtr virStorageVolClass;
@@ -54,6 +55,7 @@ static void virInterfaceDispose(void *obj);
 static void virNetworkDispose(void *obj);
 static void virNodeDeviceDispose(void *obj);
 static void virNWFilterDispose(void *obj);
+static void virNWFilterBindingDispose(void *obj);
 static void virSecretDispose(void *obj);
 static void virStreamDispose(void *obj);
 static void virStorageVolDispose(void *obj);
@@ -89,6 +91,7 @@ virDataTypesOnceInit(void)
     DECLARE_CLASS(virNetwork);
     DECLARE_CLASS(virNodeDevice);
     DECLARE_CLASS(virNWFilter);
+    DECLARE_CLASS(virNWFilterBinding);
     DECLARE_CLASS(virSecret);
     DECLARE_CLASS(virStream);
     DECLARE_CLASS(virStorageVol);
@@ -830,6 +833,70 @@ virNWFilterDispose(void *obj)
 }
 
 
+/**
+ * virGetNWFilterBinding:
+ * @conn: the hypervisor connection
+ * @portdev: pointer to the network filter port device name
+ * @filtername: name of the network filter
+ *
+ * Allocates a new network filter binding object. When the object is no longer
+ * needed, virObjectUnref() must be called in order to not leak data.
+ *
+ * Returns a pointer to the network filter binding object, or NULL on error.
+ */
+virNWFilterBindingPtr
+virGetNWFilterBinding(virConnectPtr conn, const char *portdev,
+                      const char *filtername)
+{
+    virNWFilterBindingPtr ret = NULL;
+
+    if (virDataTypesInitialize() < 0)
+        return NULL;
+
+    virCheckConnectGoto(conn, error);
+    virCheckNonNullArgGoto(portdev, error);
+
+    if (!(ret = virObjectNew(virNWFilterBindingClass)))
+        goto error;
+
+    if (VIR_STRDUP(ret->portdev, portdev) < 0)
+        goto error;
+
+    if (VIR_STRDUP(ret->filtername, filtername) < 0)
+        goto error;
+
+    ret->conn = virObjectRef(conn);
+
+    return ret;
+
+ error:
+    virObjectUnref(ret);
+    return NULL;
+}
+
+
+/**
+ * virNWFilterBindingDispose:
+ * @obj: the network filter binding to release
+ *
+ * Unconditionally release all memory associated with a nwfilter binding.
+ * The nwfilter binding object must not be used once this method returns.
+ *
+ * It will also unreference the associated connection object,
+ * which may also be released if its ref count hits zero.
+ */
+static void
+virNWFilterBindingDispose(void *obj)
+{
+    virNWFilterBindingPtr binding = obj;
+
+    VIR_DEBUG("release binding %p %s", binding, binding->portdev);
+
+    VIR_FREE(binding->portdev);
+    virObjectUnref(binding->conn);
+}
+
+
 /**
  * virGetDomainSnapshot:
  * @domain: the domain to snapshot
diff --git a/src/datatypes.h b/src/datatypes.h
index 192c86be80..e1b38706dc 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -36,6 +36,7 @@ extern virClassPtr virInterfaceClass;
 extern virClassPtr virNetworkClass;
 extern virClassPtr virNodeDeviceClass;
 extern virClassPtr virNWFilterClass;
+extern virClassPtr virNWFilterBindingClass;
 extern virClassPtr virSecretClass;
 extern virClassPtr virStreamClass;
 extern virClassPtr virStorageVolClass;
@@ -277,6 +278,20 @@ extern virClassPtr virAdmClientClass;
         } \
     } while (0)
 
+# define virCheckNWFilterBindingReturn(obj, retval) \
+    do { \
+        virNWFilterBindingPtr _nw = (obj); \
+        if (!virObjectIsClass(_nw, virNWFilterBindingClass) || \
+            !virObjectIsClass(_nw->conn, virConnectClass)) { \
+            virReportErrorHelper(VIR_FROM_NWFILTER, \
+                                 VIR_ERR_INVALID_NWFILTER_BINDING, \
+                                 __FILE__, __FUNCTION__, __LINE__, \
+                                 __FUNCTION__); \
+            virDispatchError(NULL); \
+            return retval; \
+        } \
+    } while (0)
+
 # define virCheckDomainSnapshotReturn(obj, retval) \
     do { \
         virDomainSnapshotPtr _snap = (obj); \
@@ -676,6 +691,19 @@ struct _virNWFilter {
 };
 
 
+/**
+* _virNWFilterBinding:
+*
+* Internal structure associated to a network filter port binding
+*/
+struct _virNWFilterBinding {
+    virObject parent;
+    virConnectPtr conn;                  /* pointer back to the connection */
+    char *portdev;                       /* the network filter port device name */
+    char *filtername;                    /* the network filter name */
+};
+
+
 /*
  * Helper APIs for allocating new object instances
  */
@@ -712,6 +740,9 @@ virStreamPtr virGetStream(virConnectPtr conn);
 virNWFilterPtr virGetNWFilter(virConnectPtr conn,
                               const char *name,
                               const unsigned char *uuid);
+virNWFilterBindingPtr virGetNWFilterBinding(virConnectPtr conn,
+                                            const char *portdev,
+                                            const char *filtername);
 virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain,
                                           const char *name);
 
diff --git a/src/driver-nwfilter.h b/src/driver-nwfilter.h
index cb49542f92..2c3e480a32 100644
--- a/src/driver-nwfilter.h
+++ b/src/driver-nwfilter.h
@@ -57,6 +57,31 @@ typedef char *
 (*virDrvNWFilterGetXMLDesc)(virNWFilterPtr nwfilter,
                             unsigned int flags);
 
+typedef virNWFilterBindingPtr
+(*virDrvNWFilterBindingLookupByPortDev)(virConnectPtr conn,
+                                        const char *portdev);
+
+typedef int
+(*virDrvConnectListAllNWFilterBindings)(virConnectPtr conn,
+                                        virNWFilterBindingPtr **bindings,
+                                        unsigned int flags);
+
+typedef virNWFilterBindingPtr
+(*virDrvNWFilterBindingCreateXML)(virConnectPtr conn,
+                                  const char *xml,
+                                  unsigned int flags);
+
+typedef char *
+(*virDrvNWFilterBindingGetXMLDesc)(virNWFilterBindingPtr binding,
+                                   unsigned int flags);
+
+typedef int
+(*virDrvNWFilterBindingDelete)(virNWFilterBindingPtr binding);
+typedef int
+(*virDrvNWFilterBindingRef)(virNWFilterBindingPtr binding);
+typedef int
+(*virDrvNWFilterBindingFree)(virNWFilterBindingPtr binding);
+
 
 typedef struct _virNWFilterDriver virNWFilterDriver;
 typedef virNWFilterDriver *virNWFilterDriverPtr;
@@ -77,6 +102,11 @@ struct _virNWFilterDriver {
     virDrvNWFilterDefineXML nwfilterDefineXML;
     virDrvNWFilterUndefine nwfilterUndefine;
     virDrvNWFilterGetXMLDesc nwfilterGetXMLDesc;
+    virDrvConnectListAllNWFilterBindings connectListAllNWFilterBindings;
+    virDrvNWFilterBindingLookupByPortDev nwfilterBindingLookupByPortDev;
+    virDrvNWFilterBindingCreateXML nwfilterBindingCreateXML;
+    virDrvNWFilterBindingDelete nwfilterBindingDelete;
+    virDrvNWFilterBindingGetXMLDesc nwfilterBindingGetXMLDesc;
 };
 
 
diff --git a/src/libvirt-nwfilter.c b/src/libvirt-nwfilter.c
index 948c30deef..e572d46c18 100644
--- a/src/libvirt-nwfilter.c
+++ b/src/libvirt-nwfilter.c
@@ -513,3 +513,308 @@ virNWFilterRef(virNWFilterPtr nwfilter)
     virObjectRef(nwfilter);
     return 0;
 }
+
+
+/**
+ * virConnectListAllNWFilterBindings:
+ * @conn: Pointer to the hypervisor connection.
+ * @bindings: Pointer to a variable to store the array containing the network
+ *            filter objects or NULL if the list is not required (just returns
+ *            number of network filters).
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Collect the list of network filters, and allocate an array to store those
+ * objects.
+ *
+ * Returns the number of network filters found or -1 and sets @filters to  NULL
+ * in case of error.  On success, the array stored into @filters is guaranteed to
+ * have an extra allocated element set to NULL but not included in the return count,
+ * to make iteration easier.  The caller is responsible for calling
+ * virNWFilterFree() on each array element, then calling free() on @filters.
+ */
+int
+virConnectListAllNWFilterBindings(virConnectPtr conn,
+                                  virNWFilterBindingPtr **bindings,
+                                  unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, bindings=%p, flags=0x%x", conn, bindings, flags);
+
+    virResetLastError();
+
+    if (bindings)
+        *bindings = NULL;
+
+    virCheckConnectReturn(conn, -1);
+
+    if (conn->nwfilterDriver &&
+        conn->nwfilterDriver->connectListAllNWFilterBindings) {
+        int ret;
+        ret = conn->nwfilterDriver->connectListAllNWFilterBindings(conn, bindings, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virNWFilterBindingLookupByPortDev:
+ * @conn: pointer to the hypervisor connection
+ * @portdev: name for the network port device
+ *
+ * Try to lookup a network filter binding on the given hypervisor based
+ * on network port device name.
+ *
+ * virNWFilterBindingFree should be used to free the resources after the
+ * binding object is no longer needed.
+ *
+ * Returns a new binding object or NULL in case of failure.  If the
+ * network filter cannot be found, then VIR_ERR_NO_NWFILTER_BINDING
+ * error is raised.
+ */
+virNWFilterBindingPtr
+virNWFilterBindingLookupByPortDev(virConnectPtr conn, const char *portdev)
+{
+    VIR_DEBUG("conn=%p, name=%s", conn, NULLSTR(portdev));
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(portdev, error);
+
+    if (conn->nwfilterDriver && conn->nwfilterDriver->nwfilterBindingLookupByPortDev) {
+        virNWFilterBindingPtr ret;
+        ret = conn->nwfilterDriver->nwfilterBindingLookupByPortDev(conn, portdev);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virNWFilterBindingFree:
+ * @binding: a binding object
+ *
+ * Free the binding object. The running instance is kept alive.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virNWFilterBindingFree(virNWFilterBindingPtr binding)
+{
+    VIR_DEBUG("binding=%p", binding);
+
+    virResetLastError();
+
+    virCheckNWFilterBindingReturn(binding, -1);
+
+    virObjectUnref(binding);
+    return 0;
+}
+
+
+/**
+ * virNWFilterBindingGetPortDev:
+ * @binding: a binding object
+ *
+ * Get the port dev name for the network filter binding
+ *
+ * Returns a pointer to the name or NULL, the string need not be deallocated
+ * its lifetime will be the same as the binding object.
+ */
+const char *
+virNWFilterBindingGetPortDev(virNWFilterBindingPtr binding)
+{
+    VIR_DEBUG("binding=%p", binding);
+
+    virResetLastError();
+
+    virCheckNWFilterBindingReturn(binding, NULL);
+
+    return binding->portdev;
+}
+
+
+/**
+ * virNWFilterBindingGetFilterName:
+ * @binding: a binding object
+ *
+ * Get the filter name for the network filter binding
+ *
+ * Returns a pointer to the name or NULL, the string need not be deallocated
+ * its lifetime will be the same as the binding object.
+ */
+const char *
+virNWFilterBindingGetFilterName(virNWFilterBindingPtr binding)
+{
+    VIR_DEBUG("binding=%p", binding);
+
+    virResetLastError();
+
+    virCheckNWFilterBindingReturn(binding, NULL);
+
+    return binding->filtername;
+}
+
+
+/**
+ * virNWFilterBindingCreateXML:
+ * @conn: pointer to the hypervisor connection
+ * @xml: an XML description of the binding
+ * @flags: currently unused, pass 0
+ *
+ * Define a new network filter, based on an XML description
+ * similar to the one returned by virNWFilterGetXMLDesc()
+ *
+ * virNWFilterFree should be used to free the resources after the
+ * binding object is no longer needed.
+ *
+ * Returns a new binding object or NULL in case of failure
+ */
+virNWFilterBindingPtr
+virNWFilterBindingCreateXML(virConnectPtr conn, const char *xml, unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, xml=%s", conn, NULLSTR(xml));
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(xml, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->nwfilterDriver && conn->nwfilterDriver->nwfilterBindingCreateXML) {
+        virNWFilterBindingPtr ret;
+        ret = conn->nwfilterDriver->nwfilterBindingCreateXML(conn, xml, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virNWFilterBindingDelete:
+ * @binding: a binding object
+ *
+ * Delete the binding object. This does not free the
+ * associated virNWFilterBindingPtr object.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virNWFilterBindingDelete(virNWFilterBindingPtr binding)
+{
+    virConnectPtr conn;
+    VIR_DEBUG("binding=%p", binding);
+
+    virResetLastError();
+
+    virCheckNWFilterBindingReturn(binding, -1);
+    conn = binding->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->nwfilterDriver && conn->nwfilterDriver->nwfilterBindingDelete) {
+        int ret;
+        ret = conn->nwfilterDriver->nwfilterBindingDelete(binding);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(binding->conn);
+    return -1;
+}
+
+
+/**
+ * virNWFilterBindingGetXMLDesc:
+ * @binding: a binding object
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Provide an XML description of the network filter. The description may be
+ * reused later to redefine the network filter with virNWFilterCreateXML().
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
+ *         the caller must free() the returned value.
+ */
+char *
+virNWFilterBindingGetXMLDesc(virNWFilterBindingPtr binding, unsigned int flags)
+{
+    virConnectPtr conn;
+    VIR_DEBUG("binding=%p, flags=0x%x", binding, flags);
+
+    virResetLastError();
+
+    virCheckNWFilterBindingReturn(binding, NULL);
+    conn = binding->conn;
+
+    if (conn->nwfilterDriver && conn->nwfilterDriver->nwfilterBindingGetXMLDesc) {
+        char *ret;
+        ret = conn->nwfilterDriver->nwfilterBindingGetXMLDesc(binding, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(binding->conn);
+    return NULL;
+}
+
+
+/**
+ * virNWFilterBindingRef:
+ * @binding: the binding to hold a reference on
+ *
+ * Increment the reference count on the binding. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virNWFilterFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using an binding would increment
+ * the reference count.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNWFilterBindingRef(virNWFilterBindingPtr binding)
+{
+    VIR_DEBUG("binding=%p refs=%d", binding,
+              binding ? binding->parent.u.s.refs : 0);
+
+    virResetLastError();
+
+    virCheckNWFilterBindingReturn(binding, -1);
+
+    virObjectRef(binding);
+    return 0;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7f364ec9a1..a323316607 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1200,6 +1200,7 @@ virGetInterface;
 virGetNetwork;
 virGetNodeDevice;
 virGetNWFilter;
+virGetNWFilterBinding;
 virGetSecret;
 virGetStoragePool;
 virGetStorageVol;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 3bf3c3f916..d4cdbd8b32 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -798,6 +798,15 @@ LIBVIRT_4.5.0 {
         virGetLastErrorDomain;
         virNodeGetSEVInfo;
         virDomainGetLaunchSecurityInfo;
+        virNWFilterBindingLookupByPortDev;
+        virConnectListAllNWFilterBindings;
+        virNWFilterBindingCreateXML;
+        virNWFilterBindingGetXMLDesc;
+        virNWFilterBindingDelete;
+        virNWFilterBindingRef;
+        virNWFilterBindingFree;
+        virNWFilterBindingGetPortDev;
+        virNWFilterBindingGetFilterName;
 } LIBVIRT_4.4.0;
 
 # .... define new API here using predicted next version number ....
diff --git a/src/util/virerror.c b/src/util/virerror.c
index 93632dbdf7..f198f27957 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -1494,6 +1494,18 @@ virErrorMsg(virErrorNumber error, const char *info)
             else
                 errmsg = _("device not found: %s");
             break;
+        case VIR_ERR_INVALID_NWFILTER_BINDING:
+            if (info == NULL)
+                errmsg = _("Invalid network filter binding");
+            else
+                errmsg = _("Invalid network filter binding: %s");
+            break;
+        case VIR_ERR_NO_NWFILTER_BINDING:
+            if (info == NULL)
+                errmsg = _("Network filter binding not found");
+            else
+                errmsg = _("Network filter binding not found: %s");
+            break;
     }
     return errmsg;
 }
-- 
2.17.0




More information about the libvir-list mailing list