Enable libvirt send some events to the guest. This command currently only supports NMI and key events. Signed-off-by: Lai Jiangshan <laijs@xxxxxxxxxxxxxx> --- daemon/remote.c | 52 +++++++++++++++++++++ daemon/remote_dispatch_args.h | 2 daemon/remote_dispatch_prototypes.h | 16 ++++++ daemon/remote_dispatch_table.h | 10 ++++ include/libvirt/libvirt.h.in | 3 + src/driver.h | 7 ++ src/esx/esx_driver.c | 2 src/libvirt.c | 88 ++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 2 src/libxl/libxl_driver.c | 2 src/lxc/lxc_driver.c | 2 src/openvz/openvz_driver.c | 2 src/phyp/phyp_driver.c | 4 + src/qemu/qemu_driver.c | 86 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 27 +++++++++++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 68 +++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 + src/qemu/qemu_monitor_text.c | 56 ++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 2 src/remote/remote_driver.c | 50 ++++++++++++++++++++ src/remote/remote_protocol.c | 22 +++++++++ src/remote/remote_protocol.h | 19 +++++++ src/remote/remote_protocol.x | 14 +++++ src/test/test_driver.c | 2 src/uml/uml_driver.c | 2 src/vbox/vbox_tmpl.c | 2 src/vmware/vmware_driver.c | 2 src/xen/xen_driver.c | 2 src/xenapi/xenapi_driver.c | 2 tools/virsh.c | 56 ++++++++++++++++++++++ 31 files changed, 608 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 1700c2d..5f9e78a 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2836,6 +2836,58 @@ remoteDispatchDomainGetBlkioParameters(struct qemud_server *server } static int +remoteDispatchDomainSendEventNMI(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_send_event_nmi_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + + dom = get_nonnull_domain(conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainSendEventNMI(dom, args->vcpu) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + virDomainFree(dom); + return 0; +} + +static int +remoteDispatchDomainSendEventKey(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_send_event_key_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + + dom = get_nonnull_domain(conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainSendEventKey(dom, args->key) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + virDomainFree(dom); + return 0; +} + +static int remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client ATTRIBUTE_UNUSED, virConnectPtr conn, diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index f9537d7..289a42e 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -178,3 +178,5 @@ remote_domain_migrate_set_max_speed_args val_remote_domain_migrate_set_max_speed_args; remote_storage_vol_upload_args val_remote_storage_vol_upload_args; remote_storage_vol_download_args val_remote_storage_vol_download_args; + remote_domain_send_event_nmi_args val_remote_domain_send_event_nmi_args; + remote_domain_send_event_key_args val_remote_domain_send_event_key_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 18bf41d..f920193 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -1618,3 +1618,19 @@ static int remoteDispatchSupportsFeature( remote_error *err, remote_supports_feature_args *args, remote_supports_feature_ret *ret); +static int remoteDispatchDomainSendEventNMI( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_send_event_nmi_args *args, + void *ret); +static int remoteDispatchDomainSendEventKey( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_send_event_key_args *args, + void *ret); diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index b39f7c2..a706b19 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -1052,3 +1052,13 @@ .args_filter = (xdrproc_t) xdr_remote_storage_vol_download_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* DomainSendEventNmi => 210 */ + .fn = (dispatch_fn) remoteDispatchDomainSendEventNMI, + .args_filter = (xdrproc_t) xdr_remote_domain_send_event_nmi_args, + .ret_filter = (xdrproc_t) xdr_void, +}, +{ /* DomainSendEventKey => 211 */ + .fn = (dispatch_fn) remoteDispatchDomainSendEventKey, + .args_filter = (xdrproc_t) xdr_remote_domain_send_event_key_args, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index bd36015..adbe482 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2517,6 +2517,9 @@ int virDomainOpenConsole(virDomainPtr dom, virStreamPtr st, unsigned int flags); +int virDomainSendEventNMI(virDomainPtr domain, unsigned int vcpu); +int virDomainSendEventKey(virDomainPtr domain, const char *key); + #ifdef __cplusplus } #endif diff --git a/src/driver.h b/src/driver.h index e5f91ca..6caf13f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -515,6 +515,11 @@ typedef int virStreamPtr st, unsigned int flags); +typedef int + (*virDrvDomainSendEventNMI)(virDomainPtr dom, unsigned int vcpu); + +typedef int + (*virDrvDomainSendEventKey)(virDomainPtr dom, const char *key); /** * _virDriver: @@ -639,6 +644,8 @@ struct _virDriver { virDrvDomainSnapshotDelete domainSnapshotDelete; virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand; virDrvDomainOpenConsole domainOpenConsole; + virDrvDomainSendEventNMI domainSendEventNMI; + virDrvDomainSendEventKey domainSendEventKey; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index deda372..7167712 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4675,6 +4675,8 @@ static virDriver esxDriver = { esxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; diff --git a/src/libvirt.c b/src/libvirt.c index 9bdb4c8..245247f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -5245,6 +5245,94 @@ error: } /** + * virDomainSendEvnetNMI: + * @domain: pointer to domain object, or NULL for Domain0 + * @vcpu: the virtual CPU id to send NMI to + * + * Send NMI to a special vcpu of the guest + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int virDomainSendEventNMI(virDomainPtr domain, unsigned int vcpu) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "vcpu=%u", vcpu); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainSendEventNMI) { + int ret; + ret = conn->driver->domainSendEventNMI(domain, vcpu); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** + * virDomainSendEventKey: + * @domain: pointer to domain object, or NULL for Domain0 + * @key: the string of key or key sequence + * + * Send a special key or key sequence to the guest + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int virDomainSendEventKey(virDomainPtr domain, const char *key) +{ + virConnectPtr conn; + VIR_DOMAIN_DEBUG(domain, "key=%s", key); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainSendEventKey) { + int ret; + ret = conn->driver->domainSendEventKey(domain, key); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError (VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainSetVcpus: * @domain: pointer to domain object, or NULL for Domain0 * @nvcpus: the new number of virtual CPUs for this domain diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..cd0f474 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -434,6 +434,8 @@ LIBVIRT_0.9.0 { virEventRunDefaultImpl; virStorageVolDownload; virStorageVolUpload; + virDomainSendEventNMI; + virDomainSendEventKey; } LIBVIRT_0.8.8; # .... define new API here using predicted next version number .... diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index e996ff6..040fc16 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2353,6 +2353,8 @@ static virDriver libxlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; static virStateDriver libxlStateDriver = { diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e905302..1284ab1 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2906,6 +2906,8 @@ static virDriver lxcDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ lxcDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index fb30c37..26ba0a5 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1654,6 +1654,8 @@ static virDriver openvzDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 51f9ff6..d5d0ea6 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -4054,7 +4054,9 @@ static virDriver phypDriver = { NULL, /* domainRevertToSnapshot */ NULL, /* domainSnapshotDelete */ NULL, /* qemuMonitorCommand */ - NULL, /* domainOpenConsole */ + NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; static virStorageDriver phypStorageDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index dd12dc8..02af591 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1659,6 +1659,90 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) { return qemudDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_MEM_LIVE); } +static int qemuDomainSendEventNMI(virDomainPtr domain, unsigned int vcpu) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorSendEventNMI(priv->mon, vcpu); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + +static int qemuDomainSendEventKey(virDomainPtr domain, const char *key) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorSendEventKey(priv->mon, key); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { struct qemud_driver *driver = dom->conn->privateData; @@ -6923,6 +7007,8 @@ static virDriver qemuDriver = { qemuDomainSnapshotDelete, /* domainSnapshotDelete */ qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ qemuDomainOpenConsole, /* domainOpenConsole */ + qemuDomainSendEventNMI, /* domainSendEventNMI */ + qemuDomainSendEventKey, /* domainSendEventKey */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 2d28f8d..bc2e269 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2228,3 +2228,30 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); return ret; } + + +int qemuMonitorSendEventNMI(qemuMonitorPtr mon, unsigned int vcpu) +{ + int ret; + + VIR_DEBUG("mon=%p, vcpu=%u", mon, vcpu); + + if (mon->json) + ret = qemuMonitorJSONSendEventNMI(mon, vcpu); + else + ret = qemuMonitorTextSendEventNMI(mon, vcpu); + return ret; +} + +int qemuMonitorSendEventKey(qemuMonitorPtr mon, const char *key) +{ + int ret; + + VIR_DEBUG("mon=%p, key sequence=%s", mon, key); + + if (mon->json) + ret = qemuMonitorJSONSendEventKey(mon, key); + else + ret = qemuMonitorTextSendEventKey(mon, key); + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c90219b..fdc9859 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -423,6 +423,9 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, char **reply, bool hmp); +int qemuMonitorSendEventNMI(qemuMonitorPtr mon, unsigned int vcpu); +int qemuMonitorSendEventKey(qemuMonitorPtr mon, const char *key); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 20a78e1..5149d9e 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2513,3 +2513,71 @@ cleanup: return ret; } + +int qemuMonitorJSONSendEventNMI(qemuMonitorPtr mon, unsigned int vcpu) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + char *hmp_cmd; + + /* + * FIXME: qmp nmi is not supported until qemu-0.16.0, + * use human-monitor-command instead temporary. + */ + if (virAsprintf(&hmp_cmd, "nmi %u", vcpu) < 0) { + virReportOOMError(); + return -1; + } + + cmd = qemuMonitorJSONMakeCommand("human-monitor-command", + "s:command-line", hmp_cmd, + NULL); + if (!cmd) + goto out_free_hmp_cmd; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); +out_free_hmp_cmd: + VIR_FREE(hmp_cmd); + return ret; +} + +int qemuMonitorJSONSendEventKey(qemuMonitorPtr mon, const char *key_seq) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + char *hmp_cmd; + + /* + * FIXME: qmp sendkey is not supported until qemu-0.16.0, + * use human-monitor-command instead temporary. + */ + if (virAsprintf(&hmp_cmd, "sendkey %s", key_seq) < 0) { + virReportOOMError(); + return -1; + } + + cmd = qemuMonitorJSONMakeCommand("human-monitor-command", + "s:command-line", hmp_cmd, + NULL); + if (!cmd) + goto out_free_hmp_cmd; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); +out_free_hmp_cmd: + VIR_FREE(hmp_cmd); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 086f0e1..dc206df 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -204,4 +204,7 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, char **reply_str, bool hmp); +int qemuMonitorJSONSendEventNMI(qemuMonitorPtr mon, unsigned int vcpu); +int qemuMonitorJSONSendEventKey(qemuMonitorPtr mon, const char *key); + #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index e0e3292..d3416a8 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2627,3 +2627,59 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, return ret; } + +int qemuMonitorTextSendEventNMI(qemuMonitorPtr mon, unsigned int vcpu) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "nmi %u", vcpu) < 0) { + virReportOOMError(); + return -1; + } + if (qemuMonitorTextArbitraryCommand(mon, cmd, &reply)) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to send NMI using command '%s'"), + cmd); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} + +int qemuMonitorTextSendEventKey(qemuMonitorPtr mon, const char *key) +{ + char *cmd; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "sendkey %s", key) < 0) { + virReportOOMError(); + return -1; + } + if (qemuMonitorTextArbitraryCommand(mon, cmd, &reply)) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to send key using command '%s'"), + cmd); + goto cleanup; + } + + if (strstr(reply, "unknown key") != NULL) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("sent unknown key")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(cmd); + VIR_FREE(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 0838a2b..4a03c40 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -198,4 +198,6 @@ int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply); +int qemuMonitorTextSendEventNMI(qemuMonitorPtr mon, unsigned int vcpu); +int qemuMonitorTextSendEventKey(qemuMonitorPtr mon, const char *key); #endif /* QEMU_MONITOR_TEXT_H */ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index bf94e70..676f473 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2929,6 +2929,54 @@ done: } static int +remoteDomainSendEventNMI(virDomainPtr domain, unsigned int vcpu) +{ + int rv = -1; + remote_domain_send_event_nmi_args args; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + args.vcpu = vcpu; + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SEND_EVENT_NMI, + (xdrproc_t) xdr_remote_domain_send_event_nmi_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int +remoteDomainSendEventKey(virDomainPtr domain, const char *key) +{ + int rv = -1; + remote_domain_send_event_key_args args; + struct private_data *priv = domain->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + args.key = (char *)key; + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SEND_EVENT_KEY, + (xdrproc_t) xdr_remote_domain_send_event_key_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainSetVcpus (virDomainPtr domain, unsigned int nvcpus) { int rv = -1; @@ -11296,6 +11344,8 @@ static virDriver remote_driver = { remoteDomainSnapshotDelete, /* domainSnapshotDelete */ remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainOpenConsole, /* domainOpenConsole */ + remoteDomainSendEventNMI, /* domainSendEventNMI */ + remoteDomainSendEventKey, /* domainSendEventKey */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 5604371..a829219 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -1463,6 +1463,28 @@ xdr_remote_domain_undefine_args (XDR *xdrs, remote_domain_undefine_args *objp) } bool_t +xdr_remote_domain_send_event_nmi_args (XDR *xdrs, remote_domain_send_event_nmi_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vcpu)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_send_event_key_args (XDR *xdrs, remote_domain_send_event_key_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->key)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_domain_set_vcpus_args (XDR *xdrs, remote_domain_set_vcpus_args *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index d9bf151..027ef88 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -2200,6 +2200,19 @@ struct remote_storage_vol_download_args { u_int flags; }; typedef struct remote_storage_vol_download_args remote_storage_vol_download_args; + +struct remote_domain_send_event_nmi_args { + remote_nonnull_domain dom; + u_int vcpu; +}; +typedef struct remote_domain_send_event_nmi_args remote_domain_send_event_nmi_args; + +struct remote_domain_send_event_key_args { + remote_nonnull_domain dom; + remote_nonnull_string key; +}; +typedef struct remote_domain_send_event_key_args remote_domain_send_event_key_args; + #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -2413,6 +2426,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_SEND_EVENT_NMI = 210, + REMOTE_PROC_DOMAIN_SEND_EVENT_KEY = 211, }; typedef enum remote_procedure remote_procedure; @@ -2561,6 +2576,8 @@ extern bool_t xdr_remote_domain_create_with_flags_ret (XDR *, remote_domain_cre extern bool_t xdr_remote_domain_define_xml_args (XDR *, remote_domain_define_xml_args*); extern bool_t xdr_remote_domain_define_xml_ret (XDR *, remote_domain_define_xml_ret*); extern bool_t xdr_remote_domain_undefine_args (XDR *, remote_domain_undefine_args*); +extern bool_t xdr_remote_domain_send_event_nmi_args (XDR *, remote_domain_send_event_nmi_args*); +extern bool_t xdr_remote_domain_send_event_key_args (XDR *, remote_domain_send_event_key_args*); extern bool_t xdr_remote_domain_set_vcpus_args (XDR *, remote_domain_set_vcpus_args*); extern bool_t xdr_remote_domain_set_vcpus_flags_args (XDR *, remote_domain_set_vcpus_flags_args*); extern bool_t xdr_remote_domain_get_vcpus_flags_args (XDR *, remote_domain_get_vcpus_flags_args*); @@ -2918,6 +2935,8 @@ extern bool_t xdr_remote_domain_create_with_flags_ret (); extern bool_t xdr_remote_domain_define_xml_args (); extern bool_t xdr_remote_domain_define_xml_ret (); extern bool_t xdr_remote_domain_undefine_args (); +extern bool_t xdr_remote_domain_send_event_nmi_args (); +extern bool_t xdr_remote_domain_send_event_key_args (); extern bool_t xdr_remote_domain_set_vcpus_args (); extern bool_t xdr_remote_domain_set_vcpus_flags_args (); extern bool_t xdr_remote_domain_get_vcpus_flags_args (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 675eccd..34600d7 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -817,6 +817,16 @@ struct remote_domain_undefine_args { remote_nonnull_domain dom; }; +struct remote_domain_send_event_nmi_args { + remote_nonnull_domain dom; + unsigned int vcpu; +}; + +struct remote_domain_send_event_key_args { + remote_nonnull_domain dom; + remote_nonnull_string key; +}; + struct remote_domain_set_vcpus_args { remote_nonnull_domain dom; int nvcpus; @@ -2176,8 +2186,10 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_DOMAIN_SEND_EVENT_NMI = 210, + REMOTE_PROC_DOMAIN_SEND_EVENT_KEY = 211, /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more. diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 17f5ad9..2163850 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5447,6 +5447,8 @@ static virDriver testDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index e2bd5f2..756877d 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2249,6 +2249,8 @@ static virDriver umlDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ umlDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; static int diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 8bd27dd..73c5c87 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -8647,6 +8647,8 @@ virDriver NAME(Driver) = { vboxDomainSnapshotDelete, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index b5e416b..eb64087 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -1007,6 +1007,8 @@ static virDriver vmwareDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; int diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 9f47722..bd82001 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2141,6 +2141,8 @@ static virDriver xenUnifiedDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ xenUnifiedDomainOpenConsole, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; /** diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 27206a0..0f85ad8 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1885,6 +1885,8 @@ static virDriver xenapiDriver = { NULL, /* domainSnapshotDelete */ NULL, /* qemuDomainMonitorCommand */ NULL, /* domainOpenConsole */ + NULL, /* domainSendEventNMI */ + NULL, /* domainSendEventKey */ }; /** diff --git a/tools/virsh.c b/tools/virsh.c index faeaf47..0b78c6d 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2910,6 +2910,61 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) } /* + * "sendevent" command + */ +static const vshCmdInfo info_sendevent[] = { + {"help", N_("send events to the guest")}, + {"desc", N_("Send events (NMI or Keys) to the guest domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_sendevent[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"eventtype", VSH_OT_DATA, VSH_OFLAG_REQ, N_("the type of event (nmi or key)")}, + {"eventcontent", VSH_OT_DATA, VSH_OFLAG_REQ, N_("content for the event.")}, + {NULL, 0, 0, NULL} +}; + + +static int +cmdSendEvent(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *type; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + if (vshCommandOptString(cmd, "eventtype", &type) < 0) + return FALSE; + + if (STREQ(type, "nmi")) { + int cpu; + + if ((vshCommandOptInt(cmd, "eventcontent", &cpu) < 0) + || (virDomainSendEventNMI(dom, cpu) < 0)) + ret = FALSE; + } else if (STREQ(type, "key")) { + const char *key; + + if ((vshCommandOptString(cmd, "eventcontent", &key) < 0) + || (virDomainSendEventKey(dom, key) < 0)) + ret = FALSE; + } else { + virDomainFree(dom); + vshError(ctl, _("Invalid event type: %s, only \"nmi\" or \"key\" supported currently."), type); + return FALSE; + } + + virDomainFree(dom); + return ret; +} + +/* * "setmemory" command */ static const vshCmdInfo info_setmem[] = { @@ -10693,6 +10748,7 @@ static const vshCmdDef domManagementCmds[] = { {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, {"setmem", cmdSetmem, opts_setmem, info_setmem}, {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, + {"sendevent", cmdSendEvent, opts_sendevent, info_sendevent}, {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"start", cmdStart, opts_start, info_start}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list