<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, May 8, 2021 at 2:43 PM Zheng Yan <<a href="mailto:yanzheng759@huawei.com">yanzheng759@huawei.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The new virDomainReloadTlsCertificates API is used to notify domain reload<br>
its certificates without restart, and avoid service interruption.<br>
<br>
Currently, only QEMU VNC TLS certificates are supported, but parameters and<br>
flags are also reserved for subsequent scenarios.<br>
<br>
Take reload QEMU VNC TLS certificates as an example, we can call:<br>
<br>
  virDomainReloadTlsCertificates(domain,<br>
                                 VIR_DOMAIN_TLS_CERT_GRAPHICS_VNC,<br>
                                 NULL, 0, 0);<br>
<br>
Then the specified QMP message would be send to QEMU:<br>
{"execute": "display-reload", "arguments":{"type": "vnc", "tls-certs": true}}<br>
<br>
Refers:<br>
<a href="https://gitlab.com/qemu-project/qemu/-/commit/9cc07651655ee86eca41059f5ead8c4e5607c734" rel="noreferrer" target="_blank">https://gitlab.com/qemu-project/qemu/-/commit/9cc07651655ee86eca41059f5ead8c4e5607c734</a></blockquote><div>The qmp is introduced in QEMU 6.0. A qemu compatibility flag should be added to check if target qemu supports</div><div>this qmp. See a former example: <a href="https://libvirt.org/git/?p=libvirt.git;a=commitdiff;h=adb9f7123a">https://libvirt.org/git/?p=libvirt.git;a=commitdiff;h=adb9f7123a</a></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
---<br>
 include/libvirt/libvirt-domain.h | 20 +++++++++++<br>
 src/driver-hypervisor.h          |  8 +++++<br>
 src/libvirt-domain.c             | 58 ++++++++++++++++++++++++++++++++<br>
 src/libvirt_public.syms          |  5 +++<br>
 src/qemu/qemu_driver.c           | 40 ++++++++++++++++++++++<br>
 src/qemu/qemu_hotplug.c          | 17 ++++++++++<br>
 src/qemu/qemu_hotplug.h          |  4 +++<br>
 src/qemu/qemu_monitor.c          | 27 +++++++++++++++<br>
 src/qemu/qemu_monitor.h          |  3 ++<br>
 src/qemu/qemu_monitor_json.c     | 27 +++++++++++++++<br>
 src/qemu/qemu_monitor_json.h     |  4 +++<br>
 src/remote/remote_driver.c       |  1 +<br>
 src/remote/remote_protocol.x     | 15 ++++++++-<br>
 src/remote_protocol-structs      | 10 ++++++<br>
 14 files changed, 238 insertions(+), 1 deletion(-)<br></blockquote><div>Please add a virsh sub-command for this new API.<br></div><div> </div><div>It's better to split the big patch info pieces, for example:</div><div>- A patch for qemu compatibilities</div><div>- A patch for qemu driver internal</div><div>- A patch for remote driver</div><div>- A patch for libvirt pub API</div><div>- A patch for virsh</div><div>At last, a patch for news after these above are merged.<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h<br>
index e99bfb7654..357d3598a6 100644<br>
--- a/include/libvirt/libvirt-domain.h<br>
+++ b/include/libvirt/libvirt-domain.h<br>
@@ -5152,4 +5152,24 @@ int virDomainStartDirtyRateCalc(virDomainPtr domain,<br>
                                 int seconds,<br>
                                 unsigned int flags);<br>
<br>
+/**<br>
+ * virDomainTlsCertificateType:<br>
+ * the used scene of TLS certificates for doamin<br>
+ */<br>
+typedef enum {<br>
+    VIR_DOMAIN_TLS_CERT_GRAPHICS_VNC      = 0,<br>
+    VIR_DOMAIN_TLS_CERT_GRAPHICS_SPICE    = 1,<br>
+<br>
+# ifdef VIR_ENUM_SENTINELS<br>
+    VIR_DOMAIN_TLS_CERT_LAST<br>
+# endif<br>
+} virDomainTlsCertificateType;<br>
+<br>
+int<br>
+virDomainReloadTlsCertificates(virDomainPtr domain,<br>
+                               unsigned int type,<br>
+                               virTypedParameterPtr params,<br>
+                               int nparams,<br>
+                               unsigned int flags);<br>
+<br>
 #endif /* LIBVIRT_DOMAIN_H */<br>
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h<br>
index d642af8a37..d0d4976441 100644<br>
--- a/src/driver-hypervisor.h<br>
+++ b/src/driver-hypervisor.h<br>
@@ -1410,6 +1410,13 @@ typedef int<br>
                                   int seconds,<br>
                                   unsigned int flags);<br>
<br>
+typedef int<br>
+(*virDrvDomainReloadTlsCertificates)(virDomainPtr domain,<br>
+                                     unsigned int type,<br>
+                                     virTypedParameterPtr params,<br>
+                                     int nparams,<br>
+                                     unsigned int flags);<br>
+<br>
 typedef struct _virHypervisorDriver virHypervisorDriver;<br>
<br>
 /**<br>
@@ -1676,4 +1683,5 @@ struct _virHypervisorDriver {<br>
     virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet;<br>
     virDrvDomainGetMessages domainGetMessages;<br>
     virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc;<br>
+    virDrvDomainReloadTlsCertificates domainReloadTlsCertificates;<br>
 };<br>
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c<br>
index 42c75f6cc5..1b6889ab49 100644<br>
--- a/src/libvirt-domain.c<br>
+++ b/src/libvirt-domain.c<br>
@@ -13218,3 +13218,61 @@ virDomainStartDirtyRateCalc(virDomainPtr domain,<br>
     virDispatchError(conn);<br>
     return -1;<br>
 }<br>
+<br>
+/**<br>
+ * virDomainReloadTlsCertificates:<br>
+ * @domain: a domain object.<br>
+ * @type: a value of virDomainTlsCertificateType<br>
+ * @params: pointer to TLS Certs parameter objects, must be NULL if not used<br>
+ * @nparams: number of TLS Certs parameter objects, must be 0 if not used<br>
+ * @flags: extra flags; not used yet, so callers should always pass 0<br>
+ *<br>
+ * Notify domain reload its certificates with specified 'type'<br>
+ *<br>
+ * Returns 0 in case of success, -1 otherwise.<br>
+ */<br>
+int<br>
+virDomainReloadTlsCertificates(virDomainPtr domain,<br>
+                               unsigned int type,<br>
+                               virTypedParameterPtr params,<br>
+                               int nparams,<br>
+                               unsigned int flags)<br>
+{<br>
+    virConnectPtr conn;<br>
+<br>
+    VIR_DOMAIN_DEBUG(domain, "certificate type=%u, params=%p, nparams=%d, flags=%x",<br>
+                     type, params, nparams, flags);<br>
+<br>
+    virResetLastError();<br>
+<br>
+    virCheckDomainReturn(domain, -1);<br>
+    conn = domain->conn;<br>
+<br>
+    virCheckReadOnlyGoto(conn->flags, error);<br>
+    virCheckNonNegativeArgGoto(nparams, error);<br>
+<br>
+    if (type >= VIR_DOMAIN_TLS_CERT_LAST) {<br>
+        virReportInvalidArg(type,<br>
+                            _("type must be less than %d"),<br>
+                            VIR_DOMAIN_TLS_CERT_LAST);<br>
+        goto error;<br>
+    }<br>
+<br>
+    if (conn->driver->domainReloadTlsCertificates) {<br>
+        int ret;<br>
+        ret = conn->driver->domainReloadTlsCertificates(domain,<br>
+                                                        type,<br>
+                                                        params,<br>
+                                                        nparams,<br>
+                                                        flags);<br>
+        if (ret < 0)<br>
+            goto error;<br>
+        return ret;<br>
+    }<br>
+<br>
+    virReportUnsupportedError();<br>
+<br>
+ error:<br>
+    virDispatchError(domain->conn);<br>
+    return -1;<br>
+}<br>
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms<br>
index 5678a13cda..30ff012958 100644<br>
--- a/src/libvirt_public.syms<br>
+++ b/src/libvirt_public.syms<br>
@@ -896,4 +896,9 @@ LIBVIRT_7.3.0 {<br>
         virNodeDeviceCreate;<br>
 } LIBVIRT_7.2.0;<br>
<br>
+LIBVIRT_7.4.0 {<br>
+    global:<br>
+        virDomainReloadTlsCertificates;<br>
+} LIBVIRT_7.3.0;<br>
+<br>
 # .... define new API here using predicted next version number ....<br>
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c<br>
index c90d52edc0..422a350c65 100644<br>
--- a/src/qemu/qemu_driver.c<br>
+++ b/src/qemu/qemu_driver.c<br>
@@ -20449,6 +20449,45 @@ qemuDomainStartDirtyRateCalc(virDomainPtr dom,<br>
     return ret;<br>
 }<br>
<br>
+static int<br>
+qemuDomainReloadTlsCertificates(virDomainPtr domain,<br>
+                                unsigned int type,<br>
+                                virTypedParameterPtr params,<br>
+                                int nparams,<br>
+                                unsigned int flags)<br>
+{<br>
+    int ret = -1;<br>
+    virQEMUDriver *driver = domain->conn->privateData;<br>
+    virDomainObj *vm = qemuDomObjFromDomain(domain);<br>
+<br>
+    if (!vm)<br>
+        goto cleanup;<br>
+<br>
+    virCheckNonNullArgGoto(params, cleanup);<br>
+    if (nparams != 0) {<br>
+        virReportInvalidZeroArg(nparams);<br>
+        goto cleanup;<br>
+    }<br>
+    virCheckFlagsGoto(0, cleanup);<br>
+<br>
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)<br>
+        goto cleanup;<br>
+<br>
+     if (!virDomainObjIsActive(vm)) {<br>
+        virReportError(VIR_ERR_OPERATION_INVALID,<br>
+                       "%s", _("domain is not running"));<br>
+        goto endjob;<br>
+    }<br>
+<br>
+    ret = qemuDomainReloadTLSCerts(driver, vm, type);<br>
+<br>
+ endjob:<br>
+    qemuDomainObjEndJob(driver, vm);<br>
+<br>
+ cleanup:<br>
+    virDomainObjEndAPI(&vm);<br>
+    return ret;<br>
+}<br>
<br>
 static virHypervisorDriver qemuHypervisorDriver = {<br>
     .name = QEMU_DRIVER_NAME,<br>
@@ -20693,6 +20732,7 @@ static virHypervisorDriver qemuHypervisorDriver = {<br>
     .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */<br>
     .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */<br>
     .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */<br>
+    .domainReloadTlsCertificates = qemuDomainReloadTlsCertificates, /* 7.4.0 */<br>
 };<br>
<br>
<br>
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c<br>
index a64cddb9e7..34dc035d73 100644<br>
--- a/src/qemu/qemu_hotplug.c<br>
+++ b/src/qemu/qemu_hotplug.c<br>
@@ -6704,3 +6704,20 @@ qemuDomainSetVcpuInternal(virQEMUDriver *driver,<br>
     virBitmapFree(livevcpus);<br>
     return ret;<br>
 }<br>
+<br>
+int qemuDomainReloadTLSCerts(virQEMUDriverPtr driver,<br>
+                             virDomainObjPtr vm,<br>
+                             unsigned int type)<br>
+{<br>
+    int ret = -1;<br>
+    qemuDomainObjPrivate *priv = vm->privateData;<br>
+<br>
+    qemuDomainObjEnterMonitor(driver, vm);<br>
+<br>
+    ret = qemuMonitorDisplayReloadTLSCerts(priv->mon, type);<br>
+<br>
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)<br>
+        ret = -1;<br>
+<br>
+    return ret;<br>
+}<br>
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h<br>
index df8f76f8d6..411741a688 100644<br>
--- a/src/qemu/qemu_hotplug.h<br>
+++ b/src/qemu/qemu_hotplug.h<br>
@@ -160,3 +160,7 @@ int qemuHotplugAttachDBusVMState(virQEMUDriver *driver,<br>
 int qemuHotplugRemoveDBusVMState(virQEMUDriver *driver,<br>
                                  virDomainObj *vm,<br>
                                  qemuDomainAsyncJob asyncJob);<br>
+<br>
+int qemuDomainReloadTLSCerts(virQEMUDriverPtr driver,<br>
+                             virDomainObjPtr vm,<br>
+                             unsigned int type);<br>
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c<br>
index 1e6f892e08..11f8cc8670 100644<br>
--- a/src/qemu/qemu_monitor.c<br>
+++ b/src/qemu/qemu_monitor.c<br>
@@ -4746,3 +4746,30 @@ qemuMonitorQueryDirtyRate(qemuMonitor *mon,<br>
<br>
     return qemuMonitorJSONQueryDirtyRate(mon, info);<br>
 }<br>
+<br>
+static const char *<br>
+qemuMonitorTLSCertificateTypeToString(unsigned int type)<br>
+{<br>
+    switch (type) {<br>
+    /* for now, only VNC is supported */<br>
+    case VIR_DOMAIN_TLS_CERT_GRAPHICS_VNC:<br>
+        return "vnc";<br>
+    default:<br>
+        virReportError(VIR_ERR_INVALID_ARG,<br>
+                       _("unsupported qemu certificate type %u"),<br>
+                       type);<br>
+        return NULL;<br>
+    }<br>
+}<br>
+<br>
+int<br>
+qemuMonitorDisplayReloadTLSCerts(qemuMonitorPtr mon, unsigned int type)<br>
+{<br>
+    const char *certType = qemuMonitorTLSCertificateTypeToString(type);<br>
+    if (!certType)<br>
+        return -1;<br>
+<br>
+    QEMU_CHECK_MONITOR(mon);<br>
+<br>
+    return qemuMonitorJSONDisplayReload(mon, certType, true);<br>
+}<br>
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h<br>
index 6a25def78b..f26f92fb51 100644<br>
--- a/src/qemu/qemu_monitor.h<br>
+++ b/src/qemu/qemu_monitor.h<br>
@@ -1496,3 +1496,6 @@ struct _qemuMonitorDirtyRateInfo {<br>
 int<br>
 qemuMonitorQueryDirtyRate(qemuMonitor *mon,<br>
                           qemuMonitorDirtyRateInfo *info);<br>
+<br>
+int qemuMonitorDisplayReloadTLSCerts(qemuMonitorPtr mon,<br>
+                                     unsigned int type);<br>
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c<br>
index 46aa3330a8..9934613cc2 100644<br>
--- a/src/qemu/qemu_monitor_json.c<br>
+++ b/src/qemu/qemu_monitor_json.c<br>
@@ -9446,3 +9446,30 @@ qemuMonitorJSONQueryDirtyRate(qemuMonitor *mon,<br>
<br>
     return qemuMonitorJSONExtractDirtyRateInfo(data, info);<br>
 }<br>
+<br>
+int qemuMonitorJSONDisplayReload(qemuMonitorPtr mon,<br>
+                                 const char *type,<br>
+                                 bool tlsCerts)<br>
+{<br>
+    int ret = -1;<br>
+    virJSONValuePtr reply = NULL;<br>
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("display-reload",<br>
+                                                     "s:type", type,<br>
+                                                     "b:tls-certs", tlsCerts,<br>
+                                                     NULL);<br>
+    if (!cmd)<br>
+        return -1;<br>
+<br>
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)<br>
+        goto cleanup;<br>
+<br>
+    if (qemuMonitorJSONCheckError(cmd, reply) < 0)<br>
+        goto cleanup;<br>
+<br>
+    ret = 0;<br>
+<br>
+ cleanup:<br>
+    virJSONValueFree(cmd);<br>
+    virJSONValueFree(reply);<br>
+    return ret;<br>
+}<br>
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h<br>
index 01a3ba25f1..73761d54f8 100644<br>
--- a/src/qemu/qemu_monitor_json.h<br>
+++ b/src/qemu/qemu_monitor_json.h<br>
@@ -706,3 +706,7 @@ qemuMonitorJSONStartDirtyRateCalc(qemuMonitor *mon,<br>
 int<br>
 qemuMonitorJSONQueryDirtyRate(qemuMonitor *mon,<br>
                               qemuMonitorDirtyRateInfo *info);<br>
+<br>
+int qemuMonitorJSONDisplayReload(qemuMonitorPtr mon,<br>
+                                 const char *type,<br>
+                                 bool tlsCerts);<br>
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c<br>
index 0c72d69933..0e6e4e3007 100644<br>
--- a/src/remote/remote_driver.c<br>
+++ b/src/remote/remote_driver.c<br>
@@ -8566,6 +8566,7 @@ static virHypervisorDriver hypervisor_driver = {<br>
     .domainAuthorizedSSHKeysSet = remoteDomainAuthorizedSSHKeysSet, /* 6.10.0 */<br>
     .domainGetMessages = remoteDomainGetMessages, /* 7.1.0 */<br>
     .domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 7.2.0 */<br>
+    .domainReloadTlsCertificates = remoteDomainReloadTlsCertificates, /* 7.4.0 */<br>
 };<br>
<br>
 static virNetworkDriver network_driver = {<br>
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x<br>
index de69704b68..c13b3e1f5c 100644<br>
--- a/src/remote/remote_protocol.x<br>
+++ b/src/remote/remote_protocol.x<br>
@@ -286,6 +286,8 @@ const REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX = 2048;<br>
 /* Upper limit on number of messages */<br>
 const REMOTE_DOMAIN_MESSAGES_MAX = 2048;<br>
<br>
+/* Upper limit on list of TLS certificate parameters */<br>
+const REMOTE_DOMAIN_RELOAD_TLS_CERT_PARAMETERS_MAX = 16;<br>
<br>
 /* UUID.  VIR_UUID_BUFLEN definition comes from libvirt.h */<br>
 typedef opaque remote_uuid[VIR_UUID_BUFLEN];<br>
@@ -3836,6 +3838,12 @@ struct remote_domain_start_dirty_rate_calc_args {<br>
     unsigned int flags;<br>
 };<br>
<br>
+struct remote_domain_reload_tls_certificates_args {<br>
+    remote_nonnull_domain dom;<br>
+    unsigned int type;<br>
+    remote_typed_param params<REMOTE_DOMAIN_RELOAD_TLS_CERT_PARAMETERS_MAX>;<br>
+    unsigned int flags;<br>
+};<br>
<br>
 /*----- Protocol. -----*/<br>
<br>
@@ -6784,6 +6792,11 @@ enum remote_procedure {<br>
      * @priority: high<br>
      * @acl: node_device:start<br>
      */<br>
-    REMOTE_PROC_NODE_DEVICE_CREATE = 430<br>
+    REMOTE_PROC_NODE_DEVICE_CREATE = 430,<br>
<br>
+        /**<br>
+     * @generate: both<br>
+     * @acl: domain:write<br>
+     */<br>
+    REMOTE_PROC_DOMAIN_RELOAD_TLS_CERTIFICATES = 431<br>
 };<br>
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs<br>
index 6b46328adc..799a8596ea 100644<br>
--- a/src/remote_protocol-structs<br>
+++ b/src/remote_protocol-structs<br>
@@ -3192,6 +3192,15 @@ struct remote_domain_start_dirty_rate_calc_args {<br>
         int                        seconds;<br>
         u_int                      flags;<br>
 };<br>
+struct remote_domain_reload_tls_certificates_args {<br>
+        remote_nonnull_domain      dom;<br>
+        u_int                      type;<br>
+        struct {<br>
+                u_int              params_len;<br>
+                remote_typed_param * params_val;<br>
+        } params;<br>
+        u_int                      flags;<br>
+};<br>
 enum remote_procedure {<br>
         REMOTE_PROC_CONNECT_OPEN = 1,<br>
         REMOTE_PROC_CONNECT_CLOSE = 2,<br>
@@ -3623,4 +3632,5 @@ enum remote_procedure {<br>
         REMOTE_PROC_NODE_DEVICE_DEFINE_XML = 428,<br>
         REMOTE_PROC_NODE_DEVICE_UNDEFINE = 429,<br>
         REMOTE_PROC_NODE_DEVICE_CREATE = 430,<br>
+        REMOTE_PROC_DOMAIN_RELOAD_TLS_CERTIFICATES = 431,<br>
 };<br>
-- <br>
2.25.1<br>
<br>
</blockquote></div></div>