--- include/libvirt/libvirt.h.in | 78 +++++++++++++++++++++++++ src/conf/object_event.c | 80 +++++++++++++++++++++++++- src/conf/object_event.h | 21 +++++-- src/driver.h | 14 +++++ src/libvirt.c | 133 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 7 +++ 7 files changed, 328 insertions(+), 6 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 25ab777..50fa3f7 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4966,6 +4966,7 @@ typedef enum { */ typedef enum { VIR_EVENT_NAMESPACE_DOMAIN = 0, /* 0 to keep value of virDomainEventId unchanged */ + VIR_EVENT_NAMESPACE_NETWORK = 1, } virEventNamespaceID; @@ -4980,6 +4981,83 @@ int virConnectDomainEventRegisterAny(virConnectPtr conn, int virConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID); +/** + * virNetworkEventLifecycleType: + * + * a virNetworkEventLifecycleType is emitted during network lifecycle events + */ +typedef enum { + VIR_NETWORK_EVENT_DEFINED = 0, + VIR_NETWORK_EVENT_UNDEFINED = 1, + VIR_NETWORK_EVENT_STARTED = 2, + VIR_NETWORK_EVENT_STOPPED = 3, + +#ifdef VIR_ENUM_SENTINELS + VIR_NETWORK_EVENT_LAST +#endif +} virNetworkEventLifecycleType; + +/** + * virConnectNetworkEventLifecycleCallback: + * @conn: connection object + * @net: network on which the event occurred + * @event: The specific virNetworkEventLifeCycleType which occurred + * @opaque: application specified data + * + * This callback occurs when the network is started or stopped. + * + * The callback signature to use when registering for an event of type + * VIR_NETWORK_EVENT_ID_LIFECYCLE with virConnectNetworkEventRegisterAny() + */ +typedef void (*virConnectNetworkEventLifecycleCallback)(virConnectPtr conn, + virNetworkPtr net, + int event, + void *opaque); + +/** + * VIR_NETWORK_EVENT_CALLBACK: + * + * Used to cast the event specific callback into the generic one + * for use for virNetworkEventRegister + */ +#define VIR_NETWORK_EVENT_CALLBACK(cb) ((virConnectNetworkEventGenericCallback)(cb)) + +typedef enum { + VIR_NETWORK_EVENT_ID_LIFECYCLE = 0, /* virConnectNetworkEventLifecycleCallback */ + +#ifdef VIR_ENUM_SENTINELS + VIR_NETWORK_EVENT_ID_LAST + /* + * NB: this enum value will increase over time as new events are + * added to the libvirt API. It reflects the last event ID supported + * by this version of the libvirt API. + */ +#endif +} virNetworkEventID; + +/* + * virConnectNetworkEventGenericCallback: + * @conn: the connection pointer + * @net: the network pointer + * @opaque: application specified data + * + * A generic network event callback handler. Specific events usually + * have a customization with extra parameters + */ +typedef void (*virConnectNetworkEventGenericCallback)(virConnectPtr conn, + virNetworkPtr net, + void *opaque); + +/* Use VIR_NETWORK_EVENT_CALLBACK() to cast the 'cb' parameter */ +int virConnectNetworkEventRegisterAny(virConnectPtr conn, + virNetworkPtr net, /* Optional, to filter */ + int eventID, + virConnectNetworkEventGenericCallback cb, + void *opaque, + virFreeCallback freecb); + +int virConnectNetworkEventDeregisterAny(virConnectPtr conn, + int callbackID); /** * virNWFilter: diff --git a/src/conf/object_event.c b/src/conf/object_event.c index c6538c0..2d5cf8c 100644 --- a/src/conf/object_event.c +++ b/src/conf/object_event.c @@ -542,6 +542,41 @@ typedef void (*virObjectEventDispatchFunc)(virConnectPtr conn, void *opaque); +static void +virNetworkEventDispatchDefaultFunc(virConnectPtr conn, + virObjectEventPtr event, + virConnectNetworkEventGenericCallback cb ATTRIBUTE_UNUSED, + void *cbopaque ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + virNetworkPtr net = virGetNetwork(conn, event->meta.name, event->meta.uuid); + if (!net) + return; + + switch ((virNetworkEventID) (event->eventID &0xFF) ) { + case VIR_NETWORK_EVENT_ID_LIFECYCLE: + { + virNetworkEventLifecyclePtr networkLifecycleEvent; + + networkLifecycleEvent = (virNetworkEventLifecyclePtr)event; + ((virConnectNetworkEventLifecycleCallback)cb)(conn, net, + networkLifecycleEvent->type, + cbopaque); + goto cleanup; + } + +#ifdef VIR_ENUM_SENTINELS + case VIR_NETWORK_EVENT_ID_LAST: + break; +#endif + } + VIR_WARN("Unexpected event ID %d", event->eventID); + +cleanup: + virNetworkFree(net); +} + + static int virObjectEventDispatchMatchCallback(virObjectEventPtr event, virObjectEventCallbackPtr cb) { @@ -650,6 +685,10 @@ virObjectEventStateDispatchFunc(virConnectPtr conn, virDomainEventDispatchDefaultFunc(conn, event, VIR_DOMAIN_EVENT_CALLBACK(cb), cbopaque, NULL); break; + case VIR_EVENT_NAMESPACE_NETWORK: + virNetworkEventDispatchDefaultFunc(conn, event, + VIR_NETWORK_EVENT_CALLBACK(cb), cbopaque, NULL); + break; } virObjectEventStateLock(state); } @@ -806,7 +845,44 @@ virObjectEventStateEventID(virConnectPtr conn, return ret; } -void *virNetworkEventLifecycleNew(int id, const char *name, + +/** + * virNetworkEventStateRegisterID: + * @conn: connection to associate with callback + * @state: object event state + * @net: network to filter on or NULL for all networks + * @eventID: ID of the event type to register for + * @cb: function to add to event + * @opaque: data blob to pass to callback + * @freecb: callback to free @opaque + * @callbackID: filled with callback ID + * + * Register the function @callbackID with connection @conn, + * from @state, for events of type @eventID. + * + * Returns: the number of callbacks now registered, or -1 on error + */ +int +virNetworkEventStateRegisterID(virConnectPtr conn, + virObjectEventStatePtr state, + virNetworkPtr net, + int eventID, + virConnectObjectEventGenericCallback cb, + void *opaque, + virFreeCallback freecb, + int *callbackID) +{ + if (net) + return virObjectEventStateRegisterID(conn, state, + net->uuid, net->name, 0, eventID, + cb, opaque, freecb, callbackID); + else + return virObjectEventStateRegisterID(conn, state, + NULL, NULL, 0, eventID, + cb, opaque, freecb, callbackID); +} + +void *virNetworkEventLifecycleNew(const char *name, const unsigned char *uuid, int type) { @@ -818,7 +894,7 @@ void *virNetworkEventLifecycleNew(int id, const char *name, if (!(event = virObjectEventNew(virNetworkEventLifecycleClass, eventId, - id, name, uuid))) + 0, name, uuid))) return NULL; event->type = type; diff --git a/src/conf/object_event.h b/src/conf/object_event.h index 3fdd8c5..181a798 100644 --- a/src/conf/object_event.h +++ b/src/conf/object_event.h @@ -93,8 +93,21 @@ virObjectEventStateEventID(virConnectPtr conn, int callbackID) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -void *virNetworkEventLifecycleNew(int id, - const char *name, - const unsigned char *uuid, - int type); +/* + * Network events + */ + +int +virNetworkEventStateRegisterID(virConnectPtr conn, + virObjectEventStatePtr state, + virNetworkPtr net, + int eventID, + virConnectObjectEventGenericCallback cb, + void *opaque, + virFreeCallback freecb, + int *callbackID); + +void *virNetworkEventLifecycleNew(const char *name, + const unsigned char *uuid, + int type); #endif diff --git a/src/driver.h b/src/driver.h index 8cd164a..3c7b536 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1366,6 +1366,18 @@ typedef int virNetworkPtr **nets, unsigned int flags); +typedef int +(*virDrvConnectNetworkEventRegisterAny)(virConnectPtr conn, + virNetworkPtr dom, + int eventID, + virConnectNetworkEventGenericCallback cb, + void *opaque, + virFreeCallback freecb); + +typedef int +(*virDrvConnectNetworkEventDeregisterAny)(virConnectPtr conn, + int callbackID); + typedef virNetworkPtr (*virDrvNetworkLookupByUUID)(virConnectPtr conn, const unsigned char *uuid); @@ -1444,6 +1456,8 @@ struct _virNetworkDriver { virDrvConnectNumOfDefinedNetworks connectNumOfDefinedNetworks; virDrvConnectListDefinedNetworks connectListDefinedNetworks; virDrvConnectListAllNetworks connectListAllNetworks; + virDrvConnectNetworkEventRegisterAny connectNetworkEventRegisterAny; + virDrvConnectNetworkEventDeregisterAny connectNetworkEventDeregisterAny; virDrvNetworkLookupByUUID networkLookupByUUID; virDrvNetworkLookupByName networkLookupByName; virDrvNetworkCreateXML networkCreateXML; diff --git a/src/libvirt.c b/src/libvirt.c index eff44eb..576ce96 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -19176,6 +19176,139 @@ error: } /** + * virConnectNetworkEventRegisterAny: + * @conn: pointer to the connection + * @net: pointer to the network + * @eventID: the event type to receive + * @cb: callback to the function handling network events + * @opaque: opaque data to pass on to the callback + * @freecb: optional function to deallocate opaque when not used anymore + * + * Adds a callback to receive notifications of arbitrary network events + * occurring on a network. + * + * If net is NULL, then events will be monitored for any network. If net + * is non-NULL, then only the specific network will be monitored + * + * Most types of event have a callback providing a custom set of parameters + * for the event. When registering an event, it is thus necessary to use + * the VIR_NETWORK_EVENT_CALLBACK() macro to cast the supplied function pointer + * to match the signature of this method. + * + * The virNetworkPtr object handle passed into the callback upon delivery + * of an event is only valid for the duration of execution of the callback. + * If the callback wishes to keep the network object after the callback + * returns, it shall take a reference to it, by calling virNetworkRef. + * The reference can be released once the object is no longer required + * by calling virNetworkFree. + * + * The return value from this method is a positive integer identifier + * for the callback. To unregister a callback, this callback ID should + * be passed to the virNetworkEventUnregisterAny method + * + * Returns a callback identifier on success, -1 on failure + */ +int +virConnectNetworkEventRegisterAny(virConnectPtr conn, + virNetworkPtr net, + int eventID, + virConnectNetworkEventGenericCallback cb, + void *opaque, + virFreeCallback freecb) +{ + VIR_DEBUG("conn=%p, eventID=%d, cb=%p, opaque=%p, freecb=%p", + conn, eventID, cb, opaque, freecb); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (net != NULL && + !(VIR_IS_CONNECTED_NETWORK(net) && net->conn == conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(conn); + return -1; + } + virCheckNonNullArgGoto(cb, error); + virCheckNonNegativeArgGoto(eventID, error); + if (((eventID & 0xFF00) >> 8) != VIR_EVENT_NAMESPACE_NETWORK) { + virReportInvalidArg(eventID, + _("eventID in %s must be have network namespace flags %d"), + __FUNCTION__, VIR_EVENT_NAMESPACE_NETWORK << 8); + goto error; + } + +#ifdef VIR_ENUM_SENTINELS + if ((eventID & 0xFF) >= VIR_NETWORK_EVENT_ID_LAST) { + virReportInvalidArg(eventID, + _("eventID in %s must be less than %d"), + __FUNCTION__, VIR_NETWORK_EVENT_ID_LAST); + goto error; + } +#endif + + if ((conn->networkDriver) && (conn->networkDriver->connectNetworkEventRegisterAny)) { + int ret; + ret = conn->networkDriver->connectNetworkEventRegisterAny(conn, net, + eventID, cb, + opaque, + freecb); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +} + +/** + * virConnectNetworkEventDeregisterAny: + * @conn: pointer to the connection + * @callbackID: the callback identifier + * + * Removes an event callback. The callbackID parameter should be the + * vaule obtained from a previous virNetworkEventRegisterAny method. + * + * Returns 0 on success, -1 on failure + */ +int +virConnectNetworkEventDeregisterAny(virConnectPtr conn, + int callbackID) +{ + VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + virCheckNonNegativeArgGoto(callbackID, error); + + if ((conn->networkDriver) && + (conn->networkDriver->connectNetworkEventDeregisterAny)) { + int ret; + ret = conn->networkDriver->connectNetworkEventDeregisterAny(conn, + callbackID); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +} + +/** * virDomainManagedSave: * @dom: pointer to the domain * @flags: bitwise-OR of virDomainSaveRestoreFlags diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6977324..22ec0ab 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -622,6 +622,7 @@ virNWFilterVarValueGetSimple; # conf/object_event.h virNetworkEventLifecycleNew; +virNetworkEventStateRegisterID; virObjectEventStateDeregisterID; virObjectEventStateEventID; virObjectEventStateFree; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index fe9b497..6ed6ce6 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -639,4 +639,11 @@ LIBVIRT_1.1.3 { virConnectGetCPUModelNames; } LIBVIRT_1.1.1; +LIBVIRT_1.2.1 { + global: + virConnectNetworkEventRegisterAny; + virConnectNetworkEventDeregisterAny; +} LIBVIRT_1.1.3; + + # .... define new API here using predicted next version number .... -- 1.8.4.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list