--- daemon/libvirtd.h | 1 + daemon/remote.c | 139 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 127 +++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 46 +++++++++++++- 4 files changed, 312 insertions(+), 1 deletion(-) diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index d0afdc8..47f2589 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -50,6 +50,7 @@ struct daemonClientPrivate { virMutex lock; int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST]; + int networkEventCallbackID[VIR_NETWORK_EVENT_ID_LAST]; # if WITH_SASL virNetSASLSessionPtr sasl; diff --git a/daemon/remote.c b/daemon/remote.c index f060006..bcd73d4 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -49,6 +49,7 @@ #include "qemu_protocol.h" #include "lxc_protocol.h" #include "virstring.h" +#include "object_event.h" #define VIR_FROM_THIS VIR_FROM_RPC @@ -653,6 +654,38 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); +static int remoteRelayNetworkEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED, + virNetworkPtr net, + int event, + int detail, + void *opaque) +{ + virNetServerClientPtr client = opaque; + remote_network_event_lifecycle_msg data; + + if (!client) + return -1; + + VIR_DEBUG("Relaying network lifecycle event %d, detail %d", event, detail); + + /* build return data */ + memset(&data, 0, sizeof(data)); + make_nonnull_network(&data.net, net); + data.event = event; + + remoteDispatchObjectEventSend(client, remoteProgram, + REMOTE_PROC_NETWORK_EVENT_LIFECYCLE, + (xdrproc_t)xdr_remote_network_event_lifecycle_msg, &data); + + return 0; +} + +static virConnectNetworkEventGenericCallback networkEventCallbacks[] = { + VIR_NETWORK_EVENT_CALLBACK(remoteRelayNetworkEventLifecycle), +}; + +verify(ARRAY_CARDINALITY(networkEventCallbacks) == VIR_NETWORK_EVENT_ID_LAST); + /* * You must hold lock for at least the client * We don't free stuff here, merely disconnect the client's @@ -680,6 +713,15 @@ void remoteClientFreeFunc(void *data) priv->domainEventCallbackID[i] = -1; } + for (i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i++) { + if (priv->networkEventCallbackID[i] != -1) { + VIR_DEBUG("Deregistering to relay remote events %zu", i); + virConnectNetworkEventDeregisterAny(priv->conn, + priv->networkEventCallbackID[i]); + } + priv->networkEventCallbackID[i] = -1; + } + virConnectClose(priv->conn); virIdentitySetCurrent(NULL); @@ -716,6 +758,9 @@ void *remoteClientInitHook(virNetServerClientPtr client, for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) priv->domainEventCallbackID[i] = -1; + for (i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i++) + priv->networkEventCallbackID[i] = -1; + virNetServerClientSetCloseHook(client, remoteClientCloseFunc); return priv; } @@ -5216,6 +5261,100 @@ cleanup: } +static int +remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, + remote_connect_network_event_register_any_args *args, + remote_connect_network_event_register_any_ret *ret ATTRIBUTE_UNUSED) +{ + int callbackID; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + virMutexLock(&priv->lock); + + if ((args->eventID & 0xFF) >= VIR_NETWORK_EVENT_ID_LAST) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported network event ID %d"), args->eventID); + goto cleanup; + } + + if (priv->networkEventCallbackID[args->eventID] != -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("network event %d already registered"), args->eventID); + goto cleanup; + } + + if ((callbackID = virConnectNetworkEventRegisterAny(priv->conn, + NULL, + args->eventID, + networkEventCallbacks[args->eventID], + client, NULL)) < 0) + goto cleanup; + + priv->networkEventCallbackID[args->eventID & 0xFF] = callbackID; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virMutexUnlock(&priv->lock); + return rv; +} + + +static int +remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, + remote_connect_network_event_deregister_any_args *args, + remote_connect_network_event_deregister_any_ret *ret ATTRIBUTE_UNUSED) +{ + int callbackID = -1; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + virMutexLock(&priv->lock); + + if ((args->eventID & 0xFF) >= VIR_NETWORK_EVENT_ID_LAST) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"), args->eventID); + goto cleanup; + } + + callbackID = priv->networkEventCallbackID[args->eventID]; + if (callbackID < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("network event %d not registered"), args->eventID); + goto cleanup; + } + + if (virConnectNetworkEventDeregisterAny(priv->conn, callbackID) < 0) + goto cleanup; + + priv->networkEventCallbackID[args->eventID] = -1; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virMutexUnlock(&priv->lock); + return rv; +} + /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 4a84a52..046f424 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -33,6 +33,7 @@ #include "virlog.h" #include "datatypes.h" #include "domain_event.h" +#include "network_event.h" #include "driver.h" #include "virbuffer.h" #include "remote_driver.h" @@ -273,6 +274,11 @@ remoteDomainBuildEventDeviceRemoved(virNetClientProgramPtr prog, virNetClientPtr client, void *evdata, void *opaque); +static void +remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque); + static virNetClientProgramEvent remoteDomainEvents[] = { { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE, remoteDomainBuildEventRTCChange, @@ -338,6 +344,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = { remoteDomainBuildEventDeviceRemoved, sizeof(remote_domain_event_device_removed_msg), (xdrproc_t)xdr_remote_domain_event_device_removed_msg }, + { REMOTE_PROC_NETWORK_EVENT_LIFECYCLE, + remoteNetworkBuildEventLifecycle, + sizeof(remote_network_event_lifecycle_msg), + (xdrproc_t)xdr_remote_network_event_lifecycle_msg }, }; enum virDrvOpenRemoteFlags { @@ -2902,6 +2912,99 @@ done: } static int +remoteConnectNetworkEventRegisterAny(virConnectPtr conn, + virNetworkPtr net, + int eventID, + virConnectNetworkEventGenericCallback callback, + void *opaque, + virFreeCallback freecb) +{ + int rv = -1; + struct private_data *priv = conn->privateData; + remote_connect_network_event_register_any_args args; + int callbackID; + int count; + + remoteDriverLock(priv); + + if ((count = virNetworkEventStateRegisterID(conn, + priv->domainEventState, + net, eventID, + VIR_OBJECT_EVENT_CALLBACK(callback), + opaque, freecb, + &callbackID)) < 0) { + virReportError(VIR_ERR_RPC, "%s", _("adding cb to list")); + goto done; + } + + /* If this is the first callback for this eventID, we need to enable + * events on the server */ + if (count == 1) { + args.eventID = eventID; + + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_NETWORK_EVENT_REGISTER_ANY, + (xdrproc_t) xdr_remote_connect_network_event_register_any_args, (char *) &args, + (xdrproc_t) xdr_void, (char *)NULL) == -1) { + virObjectEventStateDeregisterID(conn, + priv->domainEventState, + callbackID); + goto done; + } + } + + rv = callbackID; + +done: + remoteDriverUnlock(priv); + return rv; +} + + +static int +remoteConnectNetworkEventDeregisterAny(virConnectPtr conn, + int callbackID) +{ + struct private_data *priv = conn->privateData; + int rv = -1; + remote_connect_network_event_deregister_any_args args; + int eventID; + int count; + + remoteDriverLock(priv); + + if ((eventID = virObjectEventStateEventID(conn, + priv->domainEventState, + callbackID)) < 0) { + virReportError(VIR_ERR_RPC, _("unable to find callback ID %d"), callbackID); + goto done; + } + + if ((count = virObjectEventStateDeregisterID(conn, + priv->domainEventState, + callbackID)) < 0) { + virReportError(VIR_ERR_RPC, _("unable to find callback ID %d"), callbackID); + goto done; + } + + /* If that was the last callback for this eventID, we need to disable + * events on the server */ + if (count == 0) { + args.eventID = eventID; + + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_NETWORK_EVENT_DEREGISTER_ANY, + (xdrproc_t) xdr_remote_connect_network_event_deregister_any_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + } + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteConnectListAllInterfaces(virConnectPtr conn, virInterfacePtr **ifaces, unsigned int flags) @@ -4800,6 +4903,28 @@ remoteDomainBuildEventDeviceRemoved(virNetClientProgramPtr prog ATTRIBUTE_UNUSED } +static void +remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_network_event_lifecycle_msg *msg = evdata; + virNetworkPtr net; + virObjectEventPtr event = NULL; + + net = get_nonnull_network(conn, msg->net); + if (!net) + return; + + event = virNetworkEventLifecycleNew(net->name, net->uuid, msg->event); + virNetworkFree(net); + + remoteDomainEventQueue(priv, event); +} + + static virDrvOpenStatus ATTRIBUTE_NONNULL(1) remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags) @@ -7035,6 +7160,8 @@ static virNetworkDriver network_driver = { .connectNumOfDefinedNetworks = remoteConnectNumOfDefinedNetworks, /* 0.3.0 */ .connectListDefinedNetworks = remoteConnectListDefinedNetworks, /* 0.3.0 */ .connectListAllNetworks = remoteConnectListAllNetworks, /* 0.10.2 */ + .connectNetworkEventDeregisterAny = remoteConnectNetworkEventDeregisterAny, /* 1.2.1 */ + .connectNetworkEventRegisterAny = remoteConnectNetworkEventRegisterAny, /* 1.2.1 */ .networkLookupByUUID = remoteNetworkLookupByUUID, /* 0.3.0 */ .networkLookupByName = remoteNetworkLookupByName, /* 0.3.0 */ .networkCreateXML = remoteNetworkCreateXML, /* 0.3.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index f942670..c3d544f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2849,6 +2849,30 @@ struct remote_connect_get_cpu_model_names_ret { int ret; }; +struct remote_connect_network_event_register_any_args { + int eventID; +}; + +struct remote_connect_network_event_register_any_ret { + int cb_registered; +}; + +struct remote_connect_network_event_deregister_any_args { + int eventID; +}; + +struct remote_connect_network_event_deregister_any_ret { + int cb_registered; +}; + +struct remote_network_event_lifecycle_msg { + remote_nonnull_network net; + int event; + int detail; +}; + + + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -5018,5 +5042,25 @@ enum remote_procedure { * @generate: none * @acl: connect:read */ - REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES = 312 + REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES = 312, + + /** + * @generate: none + * @priority: high + * @acl: connect:read + */ + REMOTE_PROC_CONNECT_NETWORK_EVENT_REGISTER_ANY = 313, + + /** + * @generate: none + * @priority: high + * @acl: connect:read + */ + REMOTE_PROC_CONNECT_NETWORK_EVENT_DEREGISTER_ANY = 314, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_NETWORK_EVENT_LIFECYCLE = 315 }; -- 1.8.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list