On Fri, Mar 26, 2021 at 11:48:12AM -0500, Jonathon Jongsma wrote:
> With mediated devices, we can now define persistent node devices that
> can be started and stopped. In order to take advantage of this, we need
> an API to define new node devices.
> 
> Signed-off-by: Jonathon Jongsma <jjong...@redhat.com>
> ---
>  include/libvirt/libvirt-nodedev.h    |  4 ++
>  src/driver-nodedev.h                 |  6 +++
>  src/libvirt-nodedev.c                | 42 ++++++++++++++++
>  src/libvirt_public.syms              |  1 +
>  src/node_device/node_device_driver.c | 71 ++++++++++++++++++++++++++++
>  src/node_device/node_device_driver.h |  5 ++
>  src/node_device/node_device_udev.c   |  1 +
>  src/remote/remote_driver.c           |  1 +
>  src/remote/remote_protocol.x         | 17 ++++++-
>  src/remote_protocol-structs          |  8 ++++
>  src/rpc/gendispatch.pl               |  1 +
>  11 files changed, 156 insertions(+), 1 deletion(-)
> 
> diff --git a/include/libvirt/libvirt-nodedev.h 
> b/include/libvirt/libvirt-nodedev.h
> index 77d814935e..33eb46b3cd 100644
> --- a/include/libvirt/libvirt-nodedev.h
> +++ b/include/libvirt/libvirt-nodedev.h
> @@ -131,6 +131,10 @@ virNodeDevicePtr        virNodeDeviceCreateXML  
> (virConnectPtr conn,
>  
>  int                     virNodeDeviceDestroy    (virNodeDevicePtr dev);
>  
> +virNodeDevicePtr virNodeDeviceDefineXML(virConnectPtr conn,
> +                                        const char *xmlDesc,
> +                                        unsigned int flags);
> +
>  /**
>   * VIR_NODE_DEVICE_EVENT_CALLBACK:
>   *
> diff --git a/src/driver-nodedev.h b/src/driver-nodedev.h
> index d0fc7f19cf..64a0a7c473 100644
> --- a/src/driver-nodedev.h
> +++ b/src/driver-nodedev.h
> @@ -74,6 +74,11 @@ typedef virNodeDevicePtr
>  typedef int
>  (*virDrvNodeDeviceDestroy)(virNodeDevicePtr dev);
>  
> +typedef virNodeDevice*
> +(*virDrvNodeDeviceDefineXML)(virConnect *conn,
> +                             const char *xmlDesc,
> +                             unsigned int flags);
> +
>  typedef int
>  (*virDrvConnectNodeDeviceEventRegisterAny)(virConnectPtr conn,
>                                             virNodeDevicePtr dev,
> @@ -113,4 +118,5 @@ struct _virNodeDeviceDriver {
>      virDrvNodeDeviceListCaps nodeDeviceListCaps;
>      virDrvNodeDeviceCreateXML nodeDeviceCreateXML;
>      virDrvNodeDeviceDestroy nodeDeviceDestroy;
> +    virDrvNodeDeviceDefineXML nodeDeviceDefineXML;
>  };
> diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c
> index fb707b570f..cfc0c9de5b 100644
> --- a/src/libvirt-nodedev.c
> +++ b/src/libvirt-nodedev.c
> @@ -737,6 +737,48 @@ virNodeDeviceDestroy(virNodeDevicePtr dev)
>  }
>  
>  
> +/**
> + * virNodeDeviceDefineXML:
> + * @conn: pointer to the hypervisor connection
> + * @xmlDesc: string containing an XML description of the device to be defined
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Define a new device on the VM host machine, for example, a mediated device
> + *
> + * virNodeDeviceFree should be used to free the resources after the
> + * node device object is no longer needed.
> + *
> + * Returns a node device object if successful, NULL in case of failure
> + */
> +virNodeDevice*
> +virNodeDeviceDefineXML(virConnect *conn,
> +                       const char *xmlDesc,
> +                       unsigned int flags)
> +{
> +    VIR_DEBUG("conn=%p, xmlDesc=%s, flags=0x%x", conn, NULLSTR(xmlDesc), 
> flags);
> +
> +    virResetLastError();
> +
> +    virCheckConnectReturn(conn, NULL);
> +    virCheckReadOnlyGoto(conn->flags, error);
> +    virCheckNonNullArgGoto(xmlDesc, error);
> +
> +    if (conn->nodeDeviceDriver &&
> +        conn->nodeDeviceDriver->nodeDeviceDefineXML) {
> +        virNodeDevice *dev = 
> conn->nodeDeviceDriver->nodeDeviceDefineXML(conn, xmlDesc, flags);
> +        if (dev == NULL)

    if (!dev)
        goto error;

> +            goto error;
> +        return dev;
> +    }
> +
> +    virReportUnsupportedError();
> +
> + error:
> +    virDispatchError(conn);
> +    return NULL;
> +}
> +
> +
>  /**
>   * virConnectNodeDeviceEventRegisterAny:
>   * @conn: pointer to the connection
> diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
> index 51a3d7265a..3d8176351c 100644
> --- a/src/libvirt_public.syms
> +++ b/src/libvirt_public.syms
> @@ -887,6 +887,7 @@ LIBVIRT_7.1.0 {
>  LIBVIRT_7.2.0 {
>      global:
>          virDomainStartDirtyRateCalc;
> +        virNodeDeviceDefineXML;

Obvious note: this will have to be bumped 1 last time :).

>  } LIBVIRT_7.1.0;
>  
>  # .... define new API here using predicted next version number ....
> diff --git a/src/node_device/node_device_driver.c 
> b/src/node_device/node_device_driver.c
> index abd45a6eab..418faa9fb9 100644
> --- a/src/node_device/node_device_driver.c
> +++ b/src/node_device/node_device_driver.c
> @@ -776,6 +776,26 @@ virMdevctlStart(virNodeDeviceDefPtr def, char **uuid, 
> char **errmsg)
>  }
>  
>  
> +static int
> +virMdevctlDefine(virNodeDeviceDefPtr def, char **uuid, char **errmsg)
> +{
> +    int status;
> +    g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlDefineCommand(def, uuid, 
> errmsg);

newline here^

> +    if (!cmd)
> +        return -1;
> +
> +    /* an auto-generated uuid is returned via stdout if no uuid is specified 
> in
> +     * the mdevctl args */
> +    if (virCommandRun(cmd, &status) < 0 || status != 0)
> +        return -1;
> +
> +    /* remove newline */
> +    *uuid = g_strstrip(*uuid);
> +
> +    return 0;
> +}
> +
> +
>  static virNodeDevicePtr
>  nodeDeviceCreateXMLMdev(virConnectPtr conn,
>                          virNodeDeviceDefPtr def)
> @@ -1112,6 +1132,57 @@ nodeDeviceDestroy(virNodeDevicePtr device)
>      return ret;
>  }
>  
> +virNodeDevice*
> +nodeDeviceDefineXML(virConnect *conn,
> +                    const char *xmlDesc,
> +                    unsigned int flags)
> +{
> +    g_autoptr(virNodeDeviceDef) def = NULL;
> +    virNodeDevice *device = NULL;
> +    const char *virt_type = NULL;
> +    g_autofree char *uuid = NULL;
> +    g_autofree char *errmsg = NULL;
> +
> +    virCheckFlags(0, NULL);
> +
> +    if (nodeDeviceWaitInit() < 0)
> +        return NULL;
> +
> +    virt_type  = virConnectGetType(conn);
> +
> +    if (!(def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, 
> virt_type)))
> +        return NULL;
> +
> +    if (virNodeDeviceDefineXMLEnsureACL(conn, def) < 0)
> +        return NULL;
> +
> +    if (!nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("Unsupported device type"));
> +        return NULL;
> +    }
> +
> +    if (!def->parent) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("cannot define a mediated device without a 
> parent"));
> +        return NULL;
> +    }
> +
> +    if (virMdevctlDefine(def, &uuid, &errmsg) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to define mediated device: %s"),
> +                       errmsg && errmsg[0] ? errmsg : "Unknown Error");

    My comment from 1/30 would apply ^here too.

Reviewed-by: Erik Skultety <eskul...@redhat.com>

Reply via email to