From b57a9aecaf3be956c531035cbe0d3afbbcf28d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 9 May 2018 12:21:25 +0100 Subject: [PATCH] nwfilter: export port binding concept in the public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Daniel P. Berrangé --- 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 4983db5175..b5b8266709 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1199,6 +1199,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; }