[libvirt PATCH v6 16/30] api: add virNodeDeviceDefineXML()

Jonathon Jongsma jjongsma at redhat.com
Fri Mar 26 16:48:12 UTC 2021


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 <jjongsma at 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)
+            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;
 } 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);
+    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");
+        return NULL;
+    }
+
+    def->caps->data.mdev.uuid = g_strdup(uuid);
+    mdevGenerateDeviceName(def);
+    device = nodeDeviceFindNewMediatedDevice(conn, uuid);
+
+    return device;
+}
+
+
 
 int
 nodeConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h
index b319990f0f..f626e9ac8a 100644
--- a/src/node_device/node_device_driver.h
+++ b/src/node_device/node_device_driver.h
@@ -102,6 +102,11 @@ nodeDeviceCreateXML(virConnectPtr conn,
 int
 nodeDeviceDestroy(virNodeDevicePtr dev);
 
+virNodeDevice*
+nodeDeviceDefineXML(virConnect *conn,
+                    const char *xmlDesc,
+                    unsigned int flags);
+
 int
 nodeConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
                                       virNodeDevicePtr dev,
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index 78144b7762..9de658cab5 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -2321,6 +2321,7 @@ static virNodeDeviceDriver udevNodeDeviceDriver = {
     .nodeDeviceListCaps = nodeDeviceListCaps, /* 0.7.3 */
     .nodeDeviceCreateXML = nodeDeviceCreateXML, /* 0.7.3 */
     .nodeDeviceDestroy = nodeDeviceDestroy, /* 0.7.3 */
+    .nodeDeviceDefineXML = nodeDeviceDefineXML, /* 7.2.0 */
 };
 
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 62ada08344..15c592b5b5 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8696,6 +8696,7 @@ static virNodeDeviceDriver node_device_driver = {
     .nodeDeviceNumOfCaps = remoteNodeDeviceNumOfCaps, /* 0.5.0 */
     .nodeDeviceListCaps = remoteNodeDeviceListCaps, /* 0.5.0 */
     .nodeDeviceCreateXML = remoteNodeDeviceCreateXML, /* 0.6.3 */
+    .nodeDeviceDefineXML = remoteNodeDeviceDefineXML, /* 7.2.0 */
     .nodeDeviceDestroy = remoteNodeDeviceDestroy /* 0.6.3 */
 };
 
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 7fdc65f029..a95ed65f12 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2145,6 +2145,15 @@ struct remote_node_device_destroy_args {
     remote_nonnull_string name;
 };
 
+struct remote_node_device_define_xml_args {
+    remote_nonnull_string xml_desc;
+    unsigned int flags;
+};
+
+struct remote_node_device_define_xml_ret {
+    remote_nonnull_node_device dev;
+};
+
 
 /*
  * Events Register/Deregister:
@@ -6745,5 +6754,11 @@ enum remote_procedure {
      * @generate: both
      * @acl: domain:read
      */
-    REMOTE_PROC_DOMAIN_START_DIRTY_RATE_CALC = 427
+    REMOTE_PROC_DOMAIN_START_DIRTY_RATE_CALC = 427,
+
+    /**
+     * @generate: both
+     * @acl: node_device:write
+     */
+    REMOTE_PROC_NODE_DEVICE_DEFINE_XML = 428
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index d13dc81a82..3488659da1 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1600,6 +1600,13 @@ struct remote_node_device_create_xml_ret {
 struct remote_node_device_destroy_args {
         remote_nonnull_string      name;
 };
+struct remote_node_device_define_xml_args {
+        remote_nonnull_string      xml_desc;
+        u_int                      flags;
+};
+struct remote_node_device_define_xml_ret {
+        remote_nonnull_node_device dev;
+};
 struct remote_connect_domain_event_register_ret {
         int                        cb_registered;
 };
@@ -3605,4 +3612,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET = 425,
         REMOTE_PROC_DOMAIN_GET_MESSAGES = 426,
         REMOTE_PROC_DOMAIN_START_DIRTY_RATE_CALC = 427,
+        REMOTE_PROC_NODE_DEVICE_DEFINE_XML = 428,
 };
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index 9dcd8c3e89..9f5bf0e316 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -567,6 +567,7 @@ elsif ($mode eq "server") {
             if ($argtype =~ m/^remote_node_device_/ and
                 !($argtype =~ m/^remote_node_device_lookup_by_name_/) and
                 !($argtype =~ m/^remote_node_device_create_xml_/) and
+                !($argtype =~ m/^remote_node_device_define_xml_/) and
                 !($argtype =~ m/^remote_node_device_lookup_scsi_host_by_wwn_/)) {
                 $has_node_device = 1;
                 push(@vars_list, "virNodeDevicePtr dev = NULL");
-- 
2.26.3




More information about the libvir-list mailing list