[libvirt] [PATCH 0/3] support sysrq in xen/libxl driver

xm/xend and libxl already support sending sysrq key. Adding the equivalant to libvirt. Chunyan Liu (3): virkeycode: add virKeynameFromKeycode function xen: add .domainSendKey libxl: add .domainSendKey src/libvirt_private.syms | 1 + src/libxl/libxl_driver.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virkeycode.c | 17 +++++++++ src/util/virkeycode.h | 1 + src/xen/xen_driver.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ src/xen/xend_internal.c | 21 ++++++++++++ src/xen/xend_internal.h | 1 + 7 files changed, 215 insertions(+) -- 1.8.4.5

Add virKeynameFromKeycode for later xen/libxl sendkey usage. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 1 + src/util/virkeycode.c | 17 +++++++++++++++++ src/util/virkeycode.h | 1 + 3 files changed, 19 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6df2784..087b75f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1540,6 +1540,7 @@ virKeycodeSetTypeFromString; virKeycodeSetTypeToString; virKeycodeValueFromString; virKeycodeValueTranslate; +virKeynameFromKeycode; # util/virkeyfile.h diff --git a/src/util/virkeycode.c b/src/util/virkeycode.c index 7880a0a..c6b3b36 100644 --- a/src/util/virkeycode.c +++ b/src/util/virkeycode.c @@ -124,3 +124,20 @@ int virKeycodeValueTranslate(virKeycodeSet from_codeset, return -1; } + +const char * +virKeynameFromKeycode(virKeycodeSet codeset, int keycode) +{ + size_t i; + + for (i = 0; i < VIR_KEYMAP_ENTRY_MAX; i++) { + if (!virKeymapNames[codeset] || + !virKeymapValues[codeset]) + continue; + + if (virKeymapValues[codeset][i] == keycode) + return virKeymapNames[codeset][i]; + } + + return NULL; +} diff --git a/src/util/virkeycode.h b/src/util/virkeycode.h index 6947cfe..aefb1c9 100644 --- a/src/util/virkeycode.h +++ b/src/util/virkeycode.h @@ -29,5 +29,6 @@ int virKeycodeValueFromString(virKeycodeSet codeset, const char *keyname); int virKeycodeValueTranslate(virKeycodeSet from_codeset, virKeycodeSet to_offset, int key_value); +const char *virKeynameFromKeycode(virKeycodeSet codeset, int keycode); #endif -- 1.8.4.5

xm/xend supports sysrq command. Add .domainSendKey function to support sending sysrq key. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/xen/xen_driver.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ src/xen/xend_internal.c | 21 ++++++++++++ src/xen/xend_internal.h | 1 + 3 files changed, 107 insertions(+) diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index c9f4159..434236e 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -67,6 +67,7 @@ #include "configmake.h" #include "virstring.h" #include "viraccessapicheck.h" +#include "virkeycode.h" #define VIR_FROM_THIS VIR_FROM_XEN @@ -2738,6 +2739,89 @@ xenUnifiedNodeSuspendForDuration(virConnectPtr conn, return nodeSuspendForDuration(target, duration, flags); } +typedef struct keyname_to_letter { + const char *keyname; + const char *letter; +} keyname_to_letter; + +static const keyname_to_letter sysrq_keymap[] = { + {"KEY_0", "0"}, {"KEY_1", "1"}, {"KEY_2", "2"}, {"KEY_3", "3"}, + {"KEY_4", "4"}, {"KEY_5", "5"}, {"KEY_6", "6"}, {"KEY_7", "7"}, + {"KEY_8", "8"}, {"KEY_9", "9"}, {"KEY_A", "a"}, {"KEY_B", "b"}, + {"KEY_C", "c"}, {"KEY_D", "d"}, {"KEY_E", "e"}, {"KEY_F", "f"}, + {"KEY_G", "g"}, {"KEY_H", "h"}, {"KEY_I", "i"}, {"KEY_J", "j"}, + {"KEY_K", "k"}, {"KEY_L", "l"}, {"KEY_M", "m"}, {"KEY_N", "n"}, + {"KEY_O", "o"}, {"KEY_P", "p"}, {"KEY_Q", "q"}, {"KEY_R", "r"}, + {"KEY_S", "s"}, {"KEY_T", "t"}, {"KEY_U", "u"}, {"KEY_V", "v"}, + {"KEY_W", "w"}, {"KEY_X", "x"}, {"KEY_Y", "y"}, {"KEY_Z", "z"}, + {NULL, NULL} +}; + +static int +xenUnifiedDomainSendKey(virDomainPtr dom, + unsigned int codeset, + unsigned int holdtime ATTRIBUTE_UNUSED, + unsigned int *keycodes, + int nkeycodes, + unsigned int flags) +{ + int ret = -1; + virDomainDefPtr def; + const char *keyname0, *keyname1; + + virCheckFlags(0, -1); + + if (!(def = xenGetDomainDefForDom(dom))) + goto cleanup; + + if (virDomainSendKeyEnsureACL(dom->conn, def) < 0) + goto cleanup; + + /* check key, only support sending magic sysrq. Like: + * #virsh send-key guest1 KEY_LEFTALT KEY_SYSRQ KEY_H + */ + if (nkeycodes < 3) + goto non_sysrq; + + keyname0 = virKeynameFromKeycode(codeset, keycodes[0]); + keyname1 = virKeynameFromKeycode(codeset, keycodes[1]); + if (!keyname0 || !keyname1) + goto non_sysrq; + + if ((STREQ(keyname0, "KEY_LEFTALT") && STREQ(keyname1, "KEY_SYSRQ")) || + (STREQ(keyname1, "KEY_LEFTALT") && STREQ(keyname0, "KEY_SYSRQ"))) { + const keyname_to_letter *item = sysrq_keymap; + char *key = NULL; + const char *keyname = virKeynameFromKeycode(codeset, keycodes[2]); + + while (item && item->keyname) { + if (keyname && STREQ(item->keyname, keyname)) { + if (VIR_STRDUP(key, item->letter) < 0) + goto cleanup; + break; + } + item++; + } + + if (!key) + goto non_sysrq; + + ret = xenDaemonDomainSysrq(dom->conn, def, key); + VIR_FREE(key); + goto cleanup; + + } else { + goto non_sysrq; + } + + non_sysrq: + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + "%s", _("Sending non-sysrq keys is not supported")); + + cleanup: + virDomainDefFree(def); + return ret; +} /*----- Register with libvirt.c, and initialize Xen drivers. -----*/ @@ -2836,6 +2920,7 @@ static virHypervisorDriver xenUnifiedDriver = { .nodeSuspendForDuration = xenUnifiedNodeSuspendForDuration, /* 0.9.8 */ .nodeGetMemoryParameters = xenUnifiedNodeGetMemoryParameters, /* 0.10.2 */ .nodeSetMemoryParameters = xenUnifiedNodeSetMemoryParameters, /* 0.10.2 */ + .domainSendKey = xenUnifiedDomainSendKey, /* 1.2.11 */ }; /** diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index b233b6b..eabb6ed 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -1349,6 +1349,27 @@ xenDaemonDomainReboot(virConnectPtr conn, virDomainDefPtr def) } /** + * xenDaemonDomainSysrq: + * @conn: the connection object + * @def: the domain to destroy + * + * Send a sysrq to a domain. + * + * Returns 0 in case of success, -1 (with errno) in case of error. + */ +int +xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char *key) +{ + if (def->id < 0) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("Domain %s isn't running."), def->name); + return -1; + } + + return xend_op(conn, def->name, "op", "sysrq", "key", key, NULL); +} + +/** * xenDaemonDomainDestroy: * @conn: the connection object * @def: the domain to destroy diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 814330d..6706394 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -213,5 +213,6 @@ int xenDaemonSetSchedulerParameters(virConnectPtr conn, virDomainDefPtr def, virTypedParameterPtr params, int nparams); +int xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char *key); #endif /* __XEND_INTERNAL_H_ */ -- 1.8.4.5

libxl supports sysrq. Add .domainSendKey function to support sending sysrq key. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libxl/libxl_driver.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 53c87ce..6cc5fe6 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -56,6 +56,7 @@ #include "viratomic.h" #include "virhostdev.h" #include "network/bridge_driver.h" +#include "virkeycode.h" #define VIR_FROM_THIS VIR_FROM_LIBXL @@ -4729,6 +4730,93 @@ libxlDomainMigrateConfirm3Params(virDomainPtr domain, return libxlDomainMigrationConfirm(driver, vm, flags, cancelled); } +typedef struct keyname_to_letter { + const char *keyname; + const char *letter; +} keyname_to_letter; + +static const keyname_to_letter sysrq_keymap[] = { + {"KEY_0", "0"}, {"KEY_1", "1"}, {"KEY_2", "2"}, {"KEY_3", "3"}, + {"KEY_4", "4"}, {"KEY_5", "5"}, {"KEY_6", "6"}, {"KEY_7", "7"}, + {"KEY_8", "8"}, {"KEY_9", "9"}, {"KEY_A", "a"}, {"KEY_B", "b"}, + {"KEY_C", "c"}, {"KEY_D", "d"}, {"KEY_E", "e"}, {"KEY_F", "f"}, + {"KEY_G", "g"}, {"KEY_H", "h"}, {"KEY_I", "i"}, {"KEY_J", "j"}, + {"KEY_K", "k"}, {"KEY_L", "l"}, {"KEY_M", "m"}, {"KEY_N", "n"}, + {"KEY_O", "o"}, {"KEY_P", "p"}, {"KEY_Q", "q"}, {"KEY_R", "r"}, + {"KEY_S", "s"}, {"KEY_T", "t"}, {"KEY_U", "u"}, {"KEY_V", "v"}, + {"KEY_W", "w"}, {"KEY_X", "x"}, {"KEY_Y", "y"}, {"KEY_Z", "z"}, + {NULL, NULL} +}; + +static int +libxlDomainSendKey(virDomainPtr dom, + unsigned int codeset, + unsigned int holdtime ATTRIBUTE_UNUSED, + unsigned int *keycodes, + int nkeycodes, + unsigned int flags) +{ + virDomainObjPtr vm; + libxlDomainObjPrivatePtr priv; + const char *keyname0, *keyname1; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = libxlDomObjFromDomain(dom))) + goto cleanup; + + priv = vm->privateData; + + if (virDomainSendKeyEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + /* check key, only support sending magic sysrq. Like: + * #virsh send-key guest1 KEY_LEFTALT KEY_SYSRQ KEY_H + */ + if (nkeycodes < 3) + goto non_sysrq; + + keyname0 = virKeynameFromKeycode(codeset, keycodes[0]); + keyname1 = virKeynameFromKeycode(codeset, keycodes[1]); + if (!keyname0 || !keyname1) + goto non_sysrq; + + if ((STREQ(keyname0, "KEY_LEFTALT") && STREQ(keyname1, "KEY_SYSRQ")) || + (STREQ(keyname1, "KEY_LEFTALT") && STREQ(keyname0, "KEY_SYSRQ"))) { + const keyname_to_letter *item = sysrq_keymap; + char *key = NULL; + const char *keyname = virKeynameFromKeycode(codeset, keycodes[2]); + + while (item && item->keyname) { + if (keyname && STREQ(item->keyname, keyname)) { + if (VIR_STRDUP(key, item->letter) < 0) + goto cleanup; + break; + } + item++; + } + + if (!key) + goto non_sysrq; + + ret = libxl_send_sysrq(priv->ctx, vm->def->id, key[0]); + VIR_FREE(key); + goto cleanup; + + } else { + goto non_sysrq; + } + + non_sysrq: + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + "%s", _("Sending non-sysrq keys is not supported")); + + cleanup: + if (vm) + virObjectUnlock(vm); + return ret; +} static virHypervisorDriver libxlDriver = { .no = VIR_DRV_LIBXL, @@ -4824,6 +4912,7 @@ static virHypervisorDriver libxlDriver = { .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */ .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */ .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */ + .domainSendKey = libxlDomainSendKey, /* 1.2.11 */ }; static virStateDriver libxlStateDriver = { -- 1.8.4.5

On Tue, Dec 09, 2014 at 11:27:46AM +0800, Chunyan Liu wrote:
libxl supports sysrq. Add .domainSendKey function to support sending sysrq key.
I think this is really bending the semantics of the virDomainSendKey API too much. This API is documented to inject *any* scancodes into the guest operating system. Implementing it in such a way that you can only send sysrq key sequences to the guest kernel is not what applications will expect when they try to use this API. So NACK to this patch I'm open to the idea of adding an explicit API for triggering the sysrq sequence though. eg virDomainSendSysRequest or something like that, if you really want access to sysrq via the API. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 12/9/2014 at 05:44 PM, in message <20141209094444.GB29167@redhat.com>, "Daniel P. Berrange" <berrange@redhat.com> wrote: On Tue, Dec 09, 2014 at 11:27:46AM +0800, Chunyan Liu wrote: libxl supports sysrq. Add .domainSendKey function to support sending sysrq key.
I think this is really bending the semantics of the virDomainSendKey API too much. This API is documented to inject *any* scancodes into the guest operating system. Implementing it in such a way that you can only send sysrq key sequences to the guest kernel is not what applications will expect when they try to use this API. So NACK to this patch
I'm open to the idea of adding an explicit API for triggering the sysrq sequence though. eg virDomainSendSysRequest or something like that, if you really want access to sysrq via the API.
Libxl now has no ability to send any key sequence to guest kernel but supports sending sysrq key. We just want a way to send sysrq key, so adding new virDomainSendSysRequest API is OK to me. Meanwhile, that means: Adding .domainSendSysRequest to virHypervisorDriver? And in virsh, add a new 'virsh sysrq' command or update code of cmdSendKey to handle sysrq key sequence? (like if .domainSendKey is not supported by driver, check if it is sysrq key sequence, if yes, try virDomainSysRequest if driver supports that.) Thanks, Chunyan
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Dec 09, 2014 at 11:19:22PM -0700, Chun Yan Liu wrote:
On 12/9/2014 at 05:44 PM, in message <20141209094444.GB29167@redhat.com>, "Daniel P. Berrange" <berrange@redhat.com> wrote: On Tue, Dec 09, 2014 at 11:27:46AM +0800, Chunyan Liu wrote: libxl supports sysrq. Add .domainSendKey function to support sending sysrq key.
I think this is really bending the semantics of the virDomainSendKey API too much. This API is documented to inject *any* scancodes into the guest operating system. Implementing it in such a way that you can only send sysrq key sequences to the guest kernel is not what applications will expect when they try to use this API. So NACK to this patch
I'm open to the idea of adding an explicit API for triggering the sysrq sequence though. eg virDomainSendSysRequest or something like that, if you really want access to sysrq via the API.
Libxl now has no ability to send any key sequence to guest kernel but supports sending sysrq key. We just want a way to send sysrq key, so adding new virDomainSendSysRequest API is OK to me.
Meanwhile, that means: Adding .domainSendSysRequest to virHypervisorDriver? And in virsh, add a new 'virsh sysrq' command or update code of cmdSendKey to handle sysrq key sequence? (like if .domainSendKey is not supported by driver, check if it is sysrq key sequence, if yes, try virDomainSysRequest if driver supports that.)
Yes pretty much, but I wouldn't do anything with domainSendKey. Apps can choose to try to use domainSendKey if domainSysRequest isn't supported. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 12/10/2014 at 05:21 PM, in message <20141210092125.GB6450@redhat.com>, "Daniel P. Berrange" <berrange@redhat.com> wrote: On Tue, Dec 09, 2014 at 11:19:22PM -0700, Chun Yan Liu wrote:
On 12/9/2014 at 05:44 PM, in message <20141209094444.GB29167@redhat.com>, "Daniel P. Berrange" <berrange@redhat.com> wrote: On Tue, Dec 09, 2014 at 11:27:46AM +0800, Chunyan Liu wrote: libxl supports sysrq. Add .domainSendKey function to support sending sysrq key.
I think this is really bending the semantics of the virDomainSendKey API too much. This API is documented to inject *any* scancodes into the guest operating system. Implementing it in such a way that you can only send sysrq key sequences to the guest kernel is not what applications will expect when they try to use this API. So NACK to this patch
I'm open to the idea of adding an explicit API for triggering the sysrq sequence though. eg virDomainSendSysRequest or something like that, if you really want access to sysrq via the API.
Libxl now has no ability to send any key sequence to guest kernel but supports sending sysrq key. We just want a way to send sysrq key, so adding new virDomainSendSysRequest API is OK to me.
Meanwhile, that means: Adding .domainSendSysRequest to virHypervisorDriver? And in virsh, add a new 'virsh sysrq' command or update code of cmdSendKey to handle sysrq key sequence? (like if .domainSendKey is not supported by driver, check if it is sysrq key sequence, if yes, try virDomainSysRequest if driver supports that.)
Yes pretty much, but I wouldn't do anything with domainSendKey. Apps can choose to try to use domainSendKey if domainSysRequest isn't supported.
OK. I'll update.
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Chun Yan Liu
-
Chunyan Liu
-
Daniel P. Berrange