[libvirt] [PATCH 5/6] qemu: setup infrastructure to handle NIC_RX_FILTER_CHANGED event
Tony Krowiak
akrowiak at linux.vnet.ibm.com
Tue Sep 30 15:54:12 UTC 2014
On 09/24/2014 05:50 AM, Laine Stump wrote:
> NIC_RX_FILTER_CHANGED is sent by qemu any time a NIC driver in the
> guest modified the NIC's RX Filter (for example, if the MAC address of
> the NIC is changed by the guest).
>
> This patch doesn't do anything useful with that event; it just sets up
> all the plumbing to get news of the event into a worker thread with
> all proper locking/reference counting, and provide an easy place to
> add in desired functionality.
>
> For easy reference the next time a handler for a qemu event is
> written, here is the sequence:
I assume you mean qemu_monitor_json.c
> The handler in qemu_json_monitor.c calls
>
> qemu_json_monitor.c:qemuMonitorJSONHandleNicRxFilterChanged()
>
> which calls
>
> qemu_monitor.c:qemuMonitorEmitNicRxFilterChanged()
>
> which uses QEMU_MONITOR_CALLBACK() to call
> mon->cb->domainNicRxFilterChanged(), ie:
>
> qemuProcessHandleNicRxFilterChanged()
>
> which will queue an event QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED for
> a worker thread to handle.
>
> When the worker thread gets the event, it calls
>
> qemuProcessEventHandler()
>
> which calls
>
> processNicRxFilterChangedEvent()
>
> and *that* is where the actual work will be done (and any
> event-specific memory allocated during qemuProcessHandleXXX() will be
> freed) - it is the middle of this function where functionality behind
> the event will be added in the next patch; for now there is just a
> VIR_DEBUG() to log the event.
> ---
> src/qemu/qemu_domain.h | 1 +
> src/qemu/qemu_driver.c | 55 ++++++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_monitor.c | 13 +++++++++++
> src/qemu/qemu_monitor.h | 7 ++++++
> src/qemu/qemu_monitor_json.c | 17 ++++++++++++++
> src/qemu/qemu_process.c | 42 +++++++++++++++++++++++++++++++++
> 6 files changed, 135 insertions(+)
>
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 845d3c7..ad45a66 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -195,6 +195,7 @@ typedef enum {
> QEMU_PROCESS_EVENT_WATCHDOG = 0,
> QEMU_PROCESS_EVENT_GUESTPANIC,
> QEMU_PROCESS_EVENT_DEVICE_DELETED,
> + QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED,
>
> QEMU_PROCESS_EVENT_LAST
> } qemuProcessEventType;
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 543de79..64f1d45 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -4140,6 +4140,58 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
> }
>
>
> +static void
> +processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + char *devAlias)
> +{
> + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> + virDomainDeviceDef dev;
> + virDomainNetDefPtr def;
> +
> + VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s "
> + "from domain %p %s",
> + devAlias, vm, vm->def->name);
> +
> + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
> + goto cleanup;
> +
> + if (!virDomainObjIsActive(vm)) {
> + VIR_DEBUG("Domain is not running");
> + goto endjob;
> + }
> +
> + if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0) {
> + VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
> + "non-existent device %s in domain %s",
> + devAlias, vm->def->name);
> + goto endjob;
> + }
> + if (dev.type != VIR_DOMAIN_DEVICE_NET) {
> + VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
> + "non-network device %s in domain %s",
> + devAlias, vm->def->name);
> + goto endjob;
> + }
I understand the need to check the device type, but is it necessary to
log a warning message? I wonder if it may not cause unnecessary concern
for someone viewing the logs. Is it possible to receive a
NIC_RX_FILTER_CHANGED event for something other than a network device?
> + def = dev.data.net;
> +
> + /* handle the event - send query-rx-filter and respond to it. */
> +
> + VIR_DEBUG("process NIC_RX_FILTER_CHANGED event for network "
> + "device %s in domain %s", def->info.alias, vm->def->name);
> +
> + endjob:
> + /* We had an extra reference to vm before starting a new job so ending the
> + * job is guaranteed not to remove the last reference.
> + */
> + ignore_value(qemuDomainObjEndJob(driver, vm));
> +
> + cleanup:
> + VIR_FREE(devAlias);
> + virObjectUnref(cfg);
> +}
> +
> +
> static void qemuProcessEventHandler(void *data, void *opaque)
> {
> struct qemuProcessEvent *processEvent = data;
> @@ -4160,6 +4212,9 @@ static void qemuProcessEventHandler(void *data, void *opaque)
> case QEMU_PROCESS_EVENT_DEVICE_DELETED:
> processDeviceDeletedEvent(driver, vm, processEvent->data);
> break;
> + case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED:
> + processNicRxFilterChangedEvent(driver, vm, processEvent->data);
> + break;
> case QEMU_PROCESS_EVENT_LAST:
> break;
> }
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 48cbe3e..a4661f8 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -1387,6 +1387,19 @@ qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
> }
>
>
> +int
> +qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
> + const char *devAlias)
> +{
> + int ret = -1;
> + VIR_DEBUG("mon=%p", mon);
> +
> + QEMU_MONITOR_CALLBACK(mon, ret, domainNicRxFilterChanged, mon->vm, devAlias);
> +
> + return ret;
> +}
> +
> +
> int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
> {
> int ret;
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index c37e36f..e841505 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -171,6 +171,10 @@ typedef int (*qemuMonitorDomainDeviceDeletedCallback)(qemuMonitorPtr mon,
> virDomainObjPtr vm,
> const char *devAlias,
> void *opaque);
> +typedef int (*qemuMonitorDomainNicRxFilterChangedCallback)(qemuMonitorPtr mon,
> + virDomainObjPtr vm,
> + const char *devAlias,
> + void *opaque);
>
> typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
> typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
> @@ -197,6 +201,7 @@ struct _qemuMonitorCallbacks {
> qemuMonitorDomainPMSuspendDiskCallback domainPMSuspendDisk;
> qemuMonitorDomainGuestPanicCallback domainGuestPanic;
> qemuMonitorDomainDeviceDeletedCallback domainDeviceDeleted;
> + qemuMonitorDomainNicRxFilterChangedCallback domainNicRxFilterChanged;
> };
>
> char *qemuMonitorEscapeArg(const char *in);
> @@ -285,6 +290,8 @@ int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
> int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon);
> int qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
> const char *devAlias);
> +int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
> + const char *devAlias);
>
> int qemuMonitorStartCPUs(qemuMonitorPtr mon,
> virConnectPtr conn);
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 58007e6..640d96e 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -81,6 +81,7 @@ static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValueP
> static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
> static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
> static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
> +static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
>
> typedef struct {
> const char *type;
> @@ -96,6 +97,7 @@ static qemuEventHandler eventHandlers[] = {
> { "DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted, },
> { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
> { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
> + { "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, },
> { "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
> { "RESET", qemuMonitorJSONHandleReset, },
> { "RESUME", qemuMonitorJSONHandleResume, },
> @@ -1041,6 +1043,21 @@ qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data)
> qemuMonitorEmitDeviceDeleted(mon, device);
> }
>
> +
> +static void
> +qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data)
> +{
> + const char *name;
> +
> + if (!(name = virJSONValueObjectGetString(data, "name"))) {
> + VIR_WARN("missing device in NIC_RX_FILTER_CHANGED event");
> + return;
> + }
The device path is also sent with the event. It may be that data
element is useless with regard to subsequent NIC_RX_FILTER_CHANGED event
handling but, for my edification, I am curious as to why you ignored it.
> +
> + qemuMonitorEmitNicRxFilterChanged(mon, name);
> +}
> +
> +
> int
> qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
> const char *cmd_str,
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index dddca35..07f1f38 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -1489,6 +1489,47 @@ qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> }
>
>
> +static int
> +qemuProcessHandleNicRxFilterChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> + virDomainObjPtr vm,
> + const char *devAlias,
> + void *opaque)
> +{
> + virQEMUDriverPtr driver = opaque;
> + struct qemuProcessEvent *processEvent = NULL;
> + char *data;
> +
> + virObjectLock(vm);
> +
> + VIR_DEBUG("Device %s RX Filter changed in domain %p %s",
> + devAlias, vm, vm->def->name);
> +
> + if (VIR_ALLOC(processEvent) < 0)
> + goto error;
> +
> + processEvent->eventType = QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED;
> + if (VIR_STRDUP(data, devAlias) < 0)
> + goto error;
> + processEvent->data = data;
> + processEvent->vm = vm;
> +
> + virObjectRef(vm);
> + if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
> + ignore_value(virObjectUnref(vm));
> + goto error;
> + }
> +
> + cleanup:
> + virObjectUnlock(vm);
> + return 0;
> + error:
> + if (processEvent)
> + VIR_FREE(processEvent->data);
> + VIR_FREE(processEvent);
> + goto cleanup;
> +}
> +
> +
> static qemuMonitorCallbacks monitorCallbacks = {
> .eofNotify = qemuProcessHandleMonitorEOF,
> .errorNotify = qemuProcessHandleMonitorError,
> @@ -1510,6 +1551,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
> .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk,
> .domainGuestPanic = qemuProcessHandleGuestPanic,
> .domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
> + .domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
> };
>
> static int
More information about the libvir-list
mailing list