[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