[libvirt] [PATCH 1/3 V7] add nodeGetCPUmap() for getting available CPU IDs in a cpumap.

2012-03-01 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

Changelog:
 - fixed typos.
 - fixed string scan routine.

Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/libvirt_private.syms |1 +
 src/nodeinfo.c   |   66 ++
 src/nodeinfo.h   |3 ++
 3 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a104e70..0f4e64c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -793,6 +793,7 @@ virNodeDeviceObjUnlock;
 
 # nodeinfo.h
 nodeCapsInitNUMA;
+nodeGetCPUmap;
 nodeGetCPUStats;
 nodeGetCellsFreeMemory;
 nodeGetFreeMemory;
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index e0b66f7..2950306 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -31,6 +31,7 @@
 #include dirent.h
 #include sys/utsname.h
 #include sched.h
+#include conf/domain_conf.h
 
 #if HAVE_NUMACTL
 # define NUMA_VERSION1_COMPATIBILITY 1
@@ -569,6 +570,47 @@ int linuxNodeGetMemoryStats(FILE *meminfo,
 cleanup:
 return ret;
 }
+
+/*
+ * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set
+ * and max cpu is 7. The map file shows 0-4,6-7. This function parses
+ * it and returns cpumap.
+ */
+static const char *
+linuxParseCPUmap(int *max_cpuid, const char *path)
+{
+char *map = NULL;
+char *str = NULL;
+int max_id, i;
+
+if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, str)  0) {
+virReportOOMError();
+goto error;
+}
+
+if (VIR_ALLOC_N(map, VIR_DOMAIN_CPUMASK_LEN)  0) {
+virReportOOMError();
+goto error;
+}
+if (virDomainCpuSetParse(str, 0, map,
+ VIR_DOMAIN_CPUMASK_LEN)  0) {
+goto error;
+}
+
+for (i = 0; i  VIR_DOMAIN_CPUMASK_LEN; i++) {
+if (map[i]) {
+max_id = i;
+}
+}
+*max_cpuid = max_id;
+
+return map;
+
+error:
+VIR_FREE(str);
+VIR_FREE(map);
+return NULL;
+}
 #endif
 
 int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
@@ -712,6 +754,30 @@ int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
 #endif
 }
 
+const char *
+nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED,
+  int *max_id ATTRIBUTE_UNUSED,
+  const char *mapname ATTRIBUTE_UNUSED)
+{
+#ifdef __linux__
+char *path;
+const char *cpumap;
+
+if (virAsprintf(path, CPU_SYS_PATH /%s, mapname)  0) {
+virReportOOMError();
+return NULL;
+}
+
+cpumap = linuxParseCPUmap(max_id, path);
+VIR_FREE(path);
+return cpumap;
+#else
+ nodeReportError(VIR_ERR_NO_SUPPORT, %s,
+ _(node cpumap not implemented on this platform));
+ return NULL;
+#endif
+}
+
 #if HAVE_NUMACTL
 # if LIBNUMA_API_VERSION = 1
 #  define NUMA_MAX_N_CPUS 4096
diff --git a/src/nodeinfo.h b/src/nodeinfo.h
index 4766152..852e19d 100644
--- a/src/nodeinfo.h
+++ b/src/nodeinfo.h
@@ -46,4 +46,7 @@ int nodeGetCellsFreeMemory(virConnectPtr conn,
int maxCells);
 unsigned long long nodeGetFreeMemory(virConnectPtr conn);
 
+const char *nodeGetCPUmap(virConnectPtr conn,
+  int *max_id,
+  const char *mapname);
 #endif /* __VIR_NODEINFO_H__*/
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 3/3 V7] cpu-stats command shows cpu statistics information of a domain.

2012-03-01 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

Total:
cpu_time 14.312
CPU0:
cpu_time  3.253
CPU1:
cpu_time  1.923
CPU2:
cpu_time  7.424
CPU3:
cpu_time  1.712

Changed from V5:
  add --all, --start, --count option
Changed from V:
rebase

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |  154 +++
 tools/virsh.pod |8 +++
 2 files changed, 162 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index dc362dc..a431826 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -5537,6 +5537,159 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * cpu-stats command
+ */
+static const vshCmdInfo info_cpu_stats[] = {
+{help, N_(show domain cpu statistics)},
+{desc, N_(Display statistics about the domain's CPUs, including per-CPU 
statistics.)},
+{NULL, NULL},
+};
+
+static const vshCmdOptDef opts_cpu_stats[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{all, VSH_OT_BOOL, 0, N_(Show total statistics only)},
+{start, VSH_OT_INT, 0, N_(Show statistics from this CPU)},
+{count, VSH_OT_INT, 0, N_(Number of shown CPUs at most)},
+{NULL, 0, 0, NULL},
+};
+
+static bool
+cmdCPUStats(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+virTypedParameterPtr params = NULL;
+int i, j, pos, max_id, cpu = -1, show_count = -1, nparams;
+bool show_all = false, show_per_cpu = false;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+show_all = vshCommandOptBool(cmd, all);
+if (vshCommandOptInt(cmd, start, cpu)  0)
+show_per_cpu = true;
+if (vshCommandOptInt(cmd, count, show_count)  0)
+show_per_cpu = true;
+
+/* default show per_cpu and total */
+if (!show_all  !show_per_cpu) {
+show_all = true;
+show_per_cpu = true;
+}
+
+if (!show_all)
+goto do_show_per_cpu;
+
+/* get supported num of parameter for total statistics */
+if ((nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0))  0)
+goto failed_stats;
+if (VIR_ALLOC_N(params, nparams))
+goto failed_params;
+
+/* passing start_cpu == -1 gives us domain's total status */
+if ((nparams = virDomainGetCPUStats(dom, params, nparams, -1, 1, 0))  0)
+goto failed_stats;
+
+vshPrint(ctl, Total:\n);
+for (i = 0; i  nparams; i++) {
+vshPrint(ctl, \t%-10s , params[i].field);
+if (STREQ(params[i].field, VIR_DOMAIN_CPU_STATS_CPUTIME)) {
+if (params[i].type == VIR_TYPED_PARAM_ULLONG) {
+vshPrint(ctl, %12.3lf\n,
+ params[i].value.ul / 10.0);
+} else {
+const char *s = vshGetTypedParamValue(ctl, params[i]);
+vshPrint(ctl, _(%s(ABI changed? ullong is expected)\n), s);
+VIR_FREE(s);
+}
+} else {
+const char *s = vshGetTypedParamValue(ctl, params[i]);
+vshPrint(ctl, _(%s\n), s);
+VIR_FREE(s);
+}
+}
+virTypedParameterArrayClear(params, nparams);
+VIR_FREE(params);
+
+if (!show_per_cpu) /* show all stats only */
+goto cleanup;
+
+do_show_per_cpu:
+/* check cpu, show_count, and ignore wrong argument */
+if (cpu  0)
+cpu = 0;
+if (show_count  0)
+show_count = INT_MAX;
+
+/* get max cpu id on the node */
+if ((max_id = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0))  0)
+goto failed_stats;
+/* get percpu information */
+if ((nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0))  0)
+goto failed_stats;
+
+if (VIR_ALLOC_N(params, nparams * 128))
+goto failed_params;
+
+while (cpu = max_id) {
+int ncpus = 128;
+
+if (cpu + ncpus - 1  max_id) /* id starts from 0. */
+ncpus = max_id + 1 - cpu;
+
+if (virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0)  0)
+goto failed_stats;
+
+for (i = 0; i  ncpus; i++) {
+if (params[i * nparams].type == 0) /* this cpu is not in the map */
+continue;
+vshPrint(ctl, CPU%d:\n, cpu + i);
+
+for (j = 0; j  nparams; j++) {
+pos = i * nparams + j;
+vshPrint(ctl, \t%-10s , params[pos].field);
+if (STREQ(params[pos].field, VIR_DOMAIN_CPU_STATS_CPUTIME)) {
+if (params[j].type == VIR_TYPED_PARAM_ULLONG) {
+vshPrint(ctl, %12.3lf\n,
+ params[pos].value.ul / 10.0);
+} else {
+const char *s = vshGetTypedParamValue(ctl, 
params[pos]);
+vshPrint(ctl, _(%s(ABI changed? ullong

[libvirt] [PATCH 2/3 V7] qemu driver for virDomainGetCPUstats using cpuacct cgroup.

2012-03-01 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

* Now, only cpu_time is supported.
* cpuacct cgroup is used for providing percpu cputime information.

* include/libvirt/libvirt.h.in  - defines VIR_DOMAIN_CPU_STATS_CPUTIME
* src/qemu/qemu.conf - take care of cpuacct cgroup.
* src/qemu/qemu_conf.c   - take care of cpuacct cgroup.
* src/qemu/qemu_driver.c - added an interface
* src/util/cgroup.c/h- added interface for getting percpu cputime

Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu.conf |3 +-
 src/qemu/qemu_conf.c   |3 +-
 src/qemu/qemu_driver.c |  146 
 src/util/cgroup.c  |6 ++
 src/util/cgroup.h  |1 +
 5 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 95428c1..cb87728 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -166,6 +166,7 @@
 #  - 'memory' - use for memory tunables
 #  - 'blkio' - use for block devices I/O tunables
 #  - 'cpuset' - use for CPUs and memory nodes
+#  - 'cpuacct' - use for CPUs statistics.
 #
 # NB, even if configured here, they won't be used unless
 # the administrator has mounted cgroups, e.g.:
@@ -177,7 +178,7 @@
 # can be mounted in different locations. libvirt will detect
 # where they are located.
 #
-# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset ]
+# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset, 
cpuacct ]
 
 # This is the basic set of devices allowed / required by
 # all virtual machines.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index e95c7a5..a709cbf 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -318,7 +318,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 (1  VIR_CGROUP_CONTROLLER_DEVICES) |
 (1  VIR_CGROUP_CONTROLLER_MEMORY) |
 (1  VIR_CGROUP_CONTROLLER_BLKIO) |
-(1  VIR_CGROUP_CONTROLLER_CPUSET);
+(1  VIR_CGROUP_CONTROLLER_CPUSET) |
+(1  VIR_CGROUP_CONTROLLER_CPUACCT);
 }
 for (i = 0 ; i  VIR_CGROUP_CONTROLLER_LAST ; i++) {
 if (driver-cgroupControllers  (1  i)) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c6bdd29..d6b56ae 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12087,6 +12087,151 @@ cleanup:
 return ret;
 }
 
+/* qemuDomainGetCPUStats() with start_cpu == -1 */
+static int
+qemuDomainGetTotalcpuStats(virCgroupPtr group,
+  virTypedParameterPtr params,
+   int nparams)
+{
+unsigned long long cpu_time;
+int param_idx = 0;
+int ret;
+
+if (nparams == 0) /* return supported number of params */
+return 1;
+/* entry 0 is cputime */
+ret = virCgroupGetCpuacctUsage(group, cpu_time);
+if (ret  0) {
+virReportSystemError(-ret, %s, _(unable to get cpu account));
+return -1;
+}
+
+virTypedParameterAssign(params[param_idx], VIR_DOMAIN_CPU_STATS_CPUTIME,
+VIR_TYPED_PARAM_ULLONG, cpu_time);
+return 1;
+}
+
+static int qemuDomainGetPercpuStats(virDomainPtr domain,
+virCgroupPtr group,
+virTypedParameterPtr params,
+unsigned int nparams,
+int start_cpu,
+unsigned int ncpus)
+{
+const char *map = NULL;
+int rv = -1;
+int i, max_id;
+char *pos;
+char *buf = NULL;
+virTypedParameterPtr ent;
+int param_idx;
+
+/* return the number of supported params ? */
+if (nparams == 0  ncpus != 0)
+return 1; /* only cpu_time is supported */
+
+/* return percpu cputime in index 0 */
+param_idx = 0;
+/* to parse account file, we need present cpu map */
+map = nodeGetCPUmap(domain-conn, max_id, present);
+if (!map)
+return rv;
+
+if (ncpus == 0) { /* returns max cpu ID */
+rv = max_id;
+goto cleanup;
+}
+/* we get percpu cputime accounting info. */
+if (virCgroupGetCpuacctPercpuUsage(group, buf))
+goto cleanup;
+pos = buf;
+
+if (max_id  start_cpu + ncpus - 1)
+max_id = start_cpu + ncpus - 1;
+
+for (i = 0; i = max_id; i++) {
+unsigned long long cpu_time;
+
+if (!map[i])
+continue;
+if (virStrToLong_ull(pos, pos, 10, cpu_time)  0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(cpuacct parse error));
+goto cleanup;
+}
+if (i  start_cpu)
+continue;
+ent = params[ (i - start_cpu) * nparams + param_idx];
+virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
+VIR_TYPED_PARAM_ULLONG, cpu_time);
+}
+rv = param_idx + 1;
+cleanup

Re: [libvirt] [PATCH 1/3 V6] add nodeGetCPUmap() for getting available CPU IDs in a cpumap.

2012-02-22 Thread Lai Jiangshan
On 02/23/2012 08:10 AM, Eric Blake wrote:

 +if (virDomainCpuSetParse(str, 0, map,
 + VIR_DOMAIN_CPUMASK_LEN)  0) {
 +goto error;
 +}
 +
 +for (i = 0; i  VIR_DOMAIN_CPUMASK_LEN; i++) {
 +if (map[i]) {
 +max_id = i;
 
 That's off by a factor of 8 - map[i] means that you have visited i*8
 bits in cpumask.

@map is not bitmask, virDomainCpuSetParse() filled it a char per a cpu.
And the return of this function is also cpumap(byte per cpu).

I will rework the patches soon after you comments them.

Thank you very much.

--lai.

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 1/3 V6] add nodeGetCPUmap() for getting available CPU IDs in a cpumap.

2012-02-21 Thread Lai Jiangshan
Hi, Eric

Did you received these new patches?

Thanks,
Lai


On 02/16/2012 03:15 PM, Lai Jiangshan wrote:
 From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
 
 Changelog:
  - fixed typos.
  - fixed string scan routine.
 
 Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
 Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
 ---
  src/libvirt_private.syms |1 +
  src/nodeinfo.c   |   92 
 ++
  src/nodeinfo.h   |3 +
  3 files changed, 96 insertions(+), 0 deletions(-)
 
 diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
 index 0c22dec..6e99243 100644
 --- a/src/libvirt_private.syms
 +++ b/src/libvirt_private.syms
 @@ -792,6 +792,7 @@ virNodeDeviceObjUnlock;
  
  # nodeinfo.h
  nodeCapsInitNUMA;
 +nodeGetCPUmap;
  nodeGetCPUStats;
  nodeGetCellsFreeMemory;
  nodeGetFreeMemory;
 diff --git a/src/nodeinfo.c b/src/nodeinfo.c
 index e0b66f7..fc1aaea 100644
 --- a/src/nodeinfo.c
 +++ b/src/nodeinfo.c
 @@ -31,6 +31,7 @@
  #include dirent.h
  #include sys/utsname.h
  #include sched.h
 +#include conf/domain_conf.h
  
  #if HAVE_NUMACTL
  # define NUMA_VERSION1_COMPATIBILITY 1
 @@ -569,6 +570,73 @@ int linuxNodeGetMemoryStats(FILE *meminfo,
  cleanup:
  return ret;
  }
 +
 +/*
 + * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set
 + * and max cpu is 7. The map file shows 0-4,6-7. This function parses
 + * it and returns cpumap.
 + */
 +static const char *
 +linuxParseCPUmap(int *max_cpuid, const char *path)
 +{
 +FILE *fp;
 +char *map = NULL;
 +char *str = NULL;
 +size_t size = 128, pos = 0;
 +int max_id, i;
 +
 +fp = fopen(path, r);
 +if (!fp) {
 +virReportSystemError(errno,  _(cannot open %s), path);
 +goto error;
 +}
 +
 +if (VIR_ALLOC_N(str, size)  0) {
 +virReportOOMError();
 +goto error;
 +}
 +for (;;) {
 +pos += fread(str + pos, 1, size - pos, fp);
 +if (pos  size)
 +break;
 +
 +size = size  1;
 +if (VIR_REALLOC_N(str, size)  0) {
 +virReportOOMError();
 +goto error;
 +}
 +}
 +if (pos == 0) {
 +virReportSystemError(errno, _(cannot read from %s), path);
 +goto error;
 +}
 +str[pos - 1] = 0;
 +
 +if (VIR_ALLOC_N(map, VIR_DOMAIN_CPUMASK_LEN)  0) {
 +virReportOOMError();
 +goto error;
 +}
 +if (virDomainCpuSetParse(str, 0, map,
 + VIR_DOMAIN_CPUMASK_LEN)  0) {
 +goto error;
 +}
 +
 +for (i = 0; i  VIR_DOMAIN_CPUMASK_LEN; i++) {
 +if (map[i]) {
 +max_id = i;
 +}
 +}
 +*max_cpuid = max_id;
 +
 +VIR_FORCE_FCLOSE(fp);
 +return map;
 +
 +error:
 +VIR_FORCE_FCLOSE(fp);
 +VIR_FREE(str);
 +VIR_FREE(map);
 +return NULL;
 +}
  #endif
  
  int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr 
 nodeinfo) {
 @@ -712,6 +780,30 @@ int nodeGetMemoryStats(virConnectPtr conn 
 ATTRIBUTE_UNUSED,
  #endif
  }
  
 +const char *
 +nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED,
 +  int *max_id ATTRIBUTE_UNUSED,
 +  const char *mapname ATTRIBUTE_UNUSED)
 +{
 +#ifdef __linux__
 +char *path;
 +const char *cpumap;
 +
 +if (virAsprintf(path, CPU_SYS_PATH /%s, mapname)  0) {
 +virReportOOMError();
 +return NULL;
 +}
 +
 +cpumap = linuxParseCPUmap(max_id, path);
 +VIR_FREE(path);
 +return cpumap;
 +#else
 + nodeReportError(VIR_ERR_NO_SUPPORT, %s,
 + _(node cpumap not implemented on this platform));
 + return -1;
 +#endif
 +}
 +
  #if HAVE_NUMACTL
  # if LIBNUMA_API_VERSION = 1
  #  define NUMA_MAX_N_CPUS 4096
 diff --git a/src/nodeinfo.h b/src/nodeinfo.h
 index 4766152..852e19d 100644
 --- a/src/nodeinfo.h
 +++ b/src/nodeinfo.h
 @@ -46,4 +46,7 @@ int nodeGetCellsFreeMemory(virConnectPtr conn,
 int maxCells);
  unsigned long long nodeGetFreeMemory(virConnectPtr conn);
  
 +const char *nodeGetCPUmap(virConnectPtr conn,
 +  int *max_id,
 +  const char *mapname);
  #endif /* __VIR_NODEINFO_H__*/

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 1/3 V6] add nodeGetCPUmap() for getting available CPU IDs in a cpumap.

2012-02-15 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

Changelog:
 - fixed typos.
 - fixed string scan routine.

Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/libvirt_private.syms |1 +
 src/nodeinfo.c   |   92 ++
 src/nodeinfo.h   |3 +
 3 files changed, 96 insertions(+), 0 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0c22dec..6e99243 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -792,6 +792,7 @@ virNodeDeviceObjUnlock;
 
 # nodeinfo.h
 nodeCapsInitNUMA;
+nodeGetCPUmap;
 nodeGetCPUStats;
 nodeGetCellsFreeMemory;
 nodeGetFreeMemory;
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index e0b66f7..fc1aaea 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -31,6 +31,7 @@
 #include dirent.h
 #include sys/utsname.h
 #include sched.h
+#include conf/domain_conf.h
 
 #if HAVE_NUMACTL
 # define NUMA_VERSION1_COMPATIBILITY 1
@@ -569,6 +570,73 @@ int linuxNodeGetMemoryStats(FILE *meminfo,
 cleanup:
 return ret;
 }
+
+/*
+ * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set
+ * and max cpu is 7. The map file shows 0-4,6-7. This function parses
+ * it and returns cpumap.
+ */
+static const char *
+linuxParseCPUmap(int *max_cpuid, const char *path)
+{
+FILE *fp;
+char *map = NULL;
+char *str = NULL;
+size_t size = 128, pos = 0;
+int max_id, i;
+
+fp = fopen(path, r);
+if (!fp) {
+virReportSystemError(errno,  _(cannot open %s), path);
+goto error;
+}
+
+if (VIR_ALLOC_N(str, size)  0) {
+virReportOOMError();
+goto error;
+}
+for (;;) {
+pos += fread(str + pos, 1, size - pos, fp);
+if (pos  size)
+break;
+
+size = size  1;
+if (VIR_REALLOC_N(str, size)  0) {
+virReportOOMError();
+goto error;
+}
+}
+if (pos == 0) {
+virReportSystemError(errno, _(cannot read from %s), path);
+goto error;
+}
+str[pos - 1] = 0;
+
+if (VIR_ALLOC_N(map, VIR_DOMAIN_CPUMASK_LEN)  0) {
+virReportOOMError();
+goto error;
+}
+if (virDomainCpuSetParse(str, 0, map,
+ VIR_DOMAIN_CPUMASK_LEN)  0) {
+goto error;
+}
+
+for (i = 0; i  VIR_DOMAIN_CPUMASK_LEN; i++) {
+if (map[i]) {
+max_id = i;
+}
+}
+*max_cpuid = max_id;
+
+VIR_FORCE_FCLOSE(fp);
+return map;
+
+error:
+VIR_FORCE_FCLOSE(fp);
+VIR_FREE(str);
+VIR_FREE(map);
+return NULL;
+}
 #endif
 
 int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
@@ -712,6 +780,30 @@ int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
 #endif
 }
 
+const char *
+nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED,
+  int *max_id ATTRIBUTE_UNUSED,
+  const char *mapname ATTRIBUTE_UNUSED)
+{
+#ifdef __linux__
+char *path;
+const char *cpumap;
+
+if (virAsprintf(path, CPU_SYS_PATH /%s, mapname)  0) {
+virReportOOMError();
+return NULL;
+}
+
+cpumap = linuxParseCPUmap(max_id, path);
+VIR_FREE(path);
+return cpumap;
+#else
+ nodeReportError(VIR_ERR_NO_SUPPORT, %s,
+ _(node cpumap not implemented on this platform));
+ return -1;
+#endif
+}
+
 #if HAVE_NUMACTL
 # if LIBNUMA_API_VERSION = 1
 #  define NUMA_MAX_N_CPUS 4096
diff --git a/src/nodeinfo.h b/src/nodeinfo.h
index 4766152..852e19d 100644
--- a/src/nodeinfo.h
+++ b/src/nodeinfo.h
@@ -46,4 +46,7 @@ int nodeGetCellsFreeMemory(virConnectPtr conn,
int maxCells);
 unsigned long long nodeGetFreeMemory(virConnectPtr conn);
 
+const char *nodeGetCPUmap(virConnectPtr conn,
+  int *max_id,
+  const char *mapname);
 #endif /* __VIR_NODEINFO_H__*/
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/3 V6] qemu driver for virDomainGetCPUstats using cpuacct cgroup.

2012-02-15 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

* Now, only cpu_time is supported.
* cpuacct cgroup is used for providing percpu cputime information.

* include/libvirt/libvirt.h.in  - defines VIR_DOMAIN_CPU_STATS_CPUTIME
* src/qemu/qemu.conf - take care of cpuacct cgroup.
* src/qemu/qemu_conf.c   - take care of cpuacct cgroup.
* src/qemu/qemu_driver.c - added an interface
* src/util/cgroup.c/h- added interface for getting percpu cputime

Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu.conf |3 +-
 src/qemu/qemu_conf.c   |3 +-
 src/qemu/qemu_driver.c |  147 
 src/util/cgroup.c  |6 ++
 src/util/cgroup.h  |1 +
 5 files changed, 158 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 95428c1..cb87728 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -166,6 +166,7 @@
 #  - 'memory' - use for memory tunables
 #  - 'blkio' - use for block devices I/O tunables
 #  - 'cpuset' - use for CPUs and memory nodes
+#  - 'cpuacct' - use for CPUs statistics.
 #
 # NB, even if configured here, they won't be used unless
 # the administrator has mounted cgroups, e.g.:
@@ -177,7 +178,7 @@
 # can be mounted in different locations. libvirt will detect
 # where they are located.
 #
-# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset ]
+# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset, 
cpuacct ]
 
 # This is the basic set of devices allowed / required by
 # all virtual machines.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index e95c7a5..a709cbf 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -318,7 +318,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 (1  VIR_CGROUP_CONTROLLER_DEVICES) |
 (1  VIR_CGROUP_CONTROLLER_MEMORY) |
 (1  VIR_CGROUP_CONTROLLER_BLKIO) |
-(1  VIR_CGROUP_CONTROLLER_CPUSET);
+(1  VIR_CGROUP_CONTROLLER_CPUSET) |
+(1  VIR_CGROUP_CONTROLLER_CPUACCT);
 }
 for (i = 0 ; i  VIR_CGROUP_CONTROLLER_LAST ; i++) {
 if (driver-cgroupControllers  (1  i)) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index e2e73b7..e7871ab 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12078,6 +12078,152 @@ cleanup:
 return ret;
 }
 
+
+/* qemuDomainGetCPUStats() with start_cpu == -1 */
+static int
+qemuDomainGetTotalcpuStats(virCgroupPtr group,
+   virTypedParameterPtr params,
+   int nparams)
+{
+unsigned long long cpu_time;
+int param_idx = 0;
+int ret;
+
+if (nparams == 0) /* return supported number of params */
+return 1;
+/* entry 0 is cputime */
+ret = virCgroupGetCpuacctUsage(group, cpu_time);
+if (ret  0) {
+virReportSystemError(-ret, %s, _(unable to get cpu account));
+return -1;
+}
+
+virTypedParameterAssign(params[param_idx], VIR_DOMAIN_CPU_STATS_CPUTIME,
+VIR_TYPED_PARAM_ULLONG, cpu_time);
+return 1;
+}
+
+static int qemuDomainGetPercpuStats(virDomainPtr domain,
+virCgroupPtr group,
+virTypedParameterPtr params,
+unsigned int nparams,
+int start_cpu,
+unsigned int ncpus)
+{
+const char *map = NULL;
+int rv = -1;
+int i, max_id;
+char *pos;
+char *buf = NULL;
+virTypedParameterPtr ent;
+int param_idx;
+
+/* return the number of supported params ? */
+if (nparams == 0  ncpus != 0)
+return 1; /* only cpu_time is supported */
+
+/* return percpu cputime in index 0 */
+param_idx = 0;
+/* to parse account file, we need present cpu map */
+map = nodeGetCPUmap(domain-conn, max_id, present);
+if (!map)
+return rv;
+
+if (ncpus == 0) { /* returns max cpu ID */
+rv = max_id;
+goto cleanup;
+}
+/* we get percpu cputime accounting info. */
+if (virCgroupGetCpuacctPercpuUsage(group, buf))
+goto cleanup;
+pos = buf;
+
+if (max_id  start_cpu + ncpus - 1)
+max_id = start_cpu + ncpus - 1;
+
+for (i = 0; i = max_id; i++) {
+unsigned long long cpu_time;
+
+if (!map[i])
+continue;
+if (virStrToLong_ull(pos, pos, 10, cpu_time)  0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(cpuacct parse error));
+goto cleanup;
+}
+if (i  start_cpu)
+continue;
+ent = params[ (i - start_cpu) * nparams + param_idx];
+virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
+VIR_TYPED_PARAM_ULLONG, cpu_time);
+}
+rv = param_idx + 1;
+cleanup

Re: [libvirt] [PATCH 1/1 V4] virt-top: correct virt-top -1 command via cpuacct cgroup

2012-02-15 Thread Lai Jiangshan
Hi, Richard

virt-top and ocaml site patches can work and are completed weeks ago since
public API of libvirt is merged. Could you merged them?

virt-top and ocaml site patches only depend on the public API of libvirt.
but the testing of them may depend on the qemu-driver-site patch of libvirt,
which is sent today.

Thanks,
Lai

On 02/08/2012 04:59 PM, Lai Jiangshan wrote:
 
 
 Old virt-top -1 is not correct, its output is generated by guess:
 use average usage for pinned physical CPUs.
 
 example(old virt-top -1):
 
 PHYCPU %CPU rhel6  Windows
 
00.6  0.1=   0.5=
10.6  0.1=   0.5=#
20.6  0.1=   0.5=
30.6  0.1=#  0.5=
 
 The output almost makes no sense(all the value are just average, not real).
 
 This is new implement, it use cpuacct cgroup to gain *real* physical usages
 via cpuacct cgroup by virDomainGetCPUStats() API.
 
 new result:
 
 PHYCPU %CPU rhel6  Windows
01.3  0.3 1.0
12.3  0.3 2.0
22.2  0.5 1.7
32.5  0.4 2.1
 
 
 PHYCPU %CPU rhel6  Windows
01.7  0.4 1.3
13.6  1.0 2.7
21.6  0.4 1.2
34.8  3.1 1.7
 
 
 
 Note: average flag(=) is dropped, there is not average value in here.
 Note: running flag(#) is dropped, because if the value is not empty,
   it means the guest was once running in the physical CPU in this period
   between updates.
 
 Changed from V3:
   use new virDomainGetCPUStats() libvirt-API.
   add a new function find_usages_from_stats() to gain cpu usages.
 
 Acked-by: Richard W.M. Jones rjo...@redhat.com
 Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
 ---
  virt-top/virt_top.ml |   80 +++--
  1 files changed, 31 insertions(+), 49 deletions(-)
 
 diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml
 index ef5ac67..f7bd072 100644
 --- a/virt-top/virt_top.ml
 +++ b/virt-top/virt_top.ml
 @@ -446,14 +446,14 @@ let collect, clear_pcpu_display_data =
let last_info = Hashtbl.create 13 in
let last_time = ref (Unix.gettimeofday ()) in
  
 -  (* Save vcpuinfo structures across redraws too (only for pCPU display). *)
 -  let last_vcpu_info = Hashtbl.create 13 in
 +  (* Save pcpu_usages structures across redraws too (only for pCPU display). 
 *)
 +  let last_pcpu_usages = Hashtbl.create 13 in
  
let clear_pcpu_display_data () =
 -(* Clear out vcpu_info used by PCPUDisplay display_mode
 +(* Clear out pcpu_info used by PCPUDisplay display_mode
   * when we switch back to TaskDisplay mode.
   *)
 -Hashtbl.clear last_vcpu_info
 +Hashtbl.clear last_pcpu_usages
in
  
let collect (conn, _, _, _, _, node_info, _, _) =
 @@ -652,22 +652,28 @@ let collect, clear_pcpu_display_data =
 (try
let domid = rd.rd_domid in
let maplen = C.cpumaplen nr_pcpus in
 +  let cpu_stats = D.get_cpu_stats rd.rd_dom nr_pcpus in
 +  let rec find_usages_from_stats = (function
 +| (cpu_time, D.TypedFieldUInt64(usages)) :: _ - usages
 +| (_, _) :: params - find_usages_from_stats params
 +| [] - 0L) in
 +  let pcpu_usages = Array.map find_usages_from_stats cpu_stats in
let maxinfo = rd.rd_info.D.nr_virt_cpu in
let nr_vcpus, vcpu_infos, cpumaps =
  D.get_vcpus rd.rd_dom maxinfo maplen in
  
 -  (* Got previous vcpu_infos for this domain? *)
 -  let prev_vcpu_infos =
 -try Some (Hashtbl.find last_vcpu_info domid)
 +  (* Got previous pcpu_usages for this domain? *)
 +  let prev_pcpu_usages =
 +try Some (Hashtbl.find last_pcpu_usages domid)
  with Not_found - None in
 -  (* Update last_vcpu_info. *)
 -  Hashtbl.replace last_vcpu_info domid vcpu_infos;
 -
 -  (match prev_vcpu_infos with
 -   | Some prev_vcpu_infos
 -   when Array.length prev_vcpu_infos = Array.length 
 vcpu_infos -
 -   Some (domid, name, nr_vcpus, vcpu_infos, prev_vcpu_infos,
 - cpumaps, maplen)
 +  (* Update last_pcpu_usages. *)
 +  Hashtbl.replace last_pcpu_usages domid pcpu_usages;
 +
 +  (match prev_pcpu_usages with
 +   | Some prev_pcpu_usages
 +   when Array.length prev_pcpu_usages = Array.length 
 pcpu_usages -
 +   Some (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
 + prev_pcpu_usages, cpumaps, maplen)
 | _ - None (* ignore missing / unequal length 
 prev_vcpu_infos *)
);
  with
 @@ -680,37 +686,15 @@ let collect, clear_pcpu_display_data =
   (* Rearrange the data into a matrix.  Major axis (down) is
* pCPUs.  Minor axis

[libvirt] [PATCH 6/5 V5] GetCPUStats: fix overflow test

2012-02-09 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/libvirt.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/src/libvirt.c b/src/libvirt.c
index 8035add..a55d823 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -18541,7 +18541,7 @@ int virDomainGetCPUStats(virDomainPtr domain,
 (start_cpu == -1  ncpus != 1) ||
 ((params == NULL) != (nparams == 0)) ||
 (ncpus == 0  params != NULL) ||
-ncpus  UINT_MAX / nparams) {
+(nparams  ncpus  UINT_MAX / nparams)) {
 virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
 goto error;
 }
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/5 V5] qemu driver for virDomainGetCPUstats using cpuacct cgroup.

2012-02-09 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

* Now, only cpu_time is supported.
* cpuacct cgroup is used for providing percpu cputime information.

* include/libvirt/libvirt.h.in  - defines VIR_DOMAIN_CPU_STATS_CPUTIME
* src/qemu/qemu.conf - take care of cpuacct cgroup.
* src/qemu/qemu_conf.c   - take care of cpuacct cgroup.
* src/qemu/qemu_driver.c - added an interface
* src/util/cgroup.c/h- added interface for getting percpu cputime

Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu.conf |3 +-
 src/qemu/qemu_conf.c   |3 +-
 src/qemu/qemu_driver.c |  157 
 src/util/cgroup.c  |6 ++
 src/util/cgroup.h  |1 +
 5 files changed, 168 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 95428c1..db07b8a 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -166,6 +166,7 @@
 #  - 'memory' - use for memory tunables
 #  - 'blkio' - use for block devices I/O tunables
 #  - 'cpuset' - use for CPUs and memory nodes
+#  -  cpuacct - use for CPUs statistics.
 #
 # NB, even if configured here, they won't be used unless
 # the administrator has mounted cgroups, e.g.:
@@ -177,7 +178,7 @@
 # can be mounted in different locations. libvirt will detect
 # where they are located.
 #
-# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset ]
+# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset, 
cpuacct ]
 
 # This is the basic set of devices allowed / required by
 # all virtual machines.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index e95c7a5..a709cbf 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -318,7 +318,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 (1  VIR_CGROUP_CONTROLLER_DEVICES) |
 (1  VIR_CGROUP_CONTROLLER_MEMORY) |
 (1  VIR_CGROUP_CONTROLLER_BLKIO) |
-(1  VIR_CGROUP_CONTROLLER_CPUSET);
+(1  VIR_CGROUP_CONTROLLER_CPUSET) |
+(1  VIR_CGROUP_CONTROLLER_CPUACCT);
 }
 for (i = 0 ; i  VIR_CGROUP_CONTROLLER_LAST ; i++) {
 if (driver-cgroupControllers  (1  i)) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0cac6a5..7aa9d33 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12036,6 +12036,162 @@ cleanup:
 return ret;
 }
 
+
+/* qemuDomainGetCPUStats() with start_cpu == -1 */
+static int qemuDomainGetTotalcpuStats(virDomainPtr domain ATTRIBUTE_UNUSED,
+  virCgroupPtr group,
+  virTypedParameterPtr params,
+  int nparams,
+  unsigned int flags)
+{
+unsigned long long cpu_time;
+int param_idx = 0;
+int ret;
+
+virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+if (nparams == 0) /* return supprted number of params */
+return 1;
+/* entry 0 is cputime */
+ret = virCgroupGetCpuacctUsage(group, cpu_time);
+if (ret  0) {
+virReportSystemError(-ret, %s, _(unable to get cpu account));
+return -1;
+}
+
+virTypedParameterAssign(params[param_idx], VIR_DOMAIN_CPU_STATS_CPUTIME,
+VIR_TYPED_PARAM_ULLONG, cpu_time);
+return param_idx + 1;
+}
+
+static int qemuDomainGetPercpuStats(virDomainPtr domain,
+virCgroupPtr group,
+virTypedParameterPtr params,
+unsigned int nparams,
+int start_cpu,
+unsigned int ncpus,
+unsigned int flags)
+{
+virBitmapPtr map = NULL;
+int rv = -1;
+int i, max_id;
+char *pos;
+char *buf = NULL;
+virTypedParameterPtr ent;
+int param_idx;
+
+virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
+/* return the number of supported params ? */
+if (nparams == 0  ncpus != 0)
+return 1; /* only cpu_time is supported */
+
+/* return percpu cputime in index 0 */
+param_idx = 0;
+/* to parse account file, we need present cpu map */
+map = nodeGetCPUmap(domain-conn, max_id, present);
+if (!map)
+return rv;
+
+if (ncpus == 0) { /* returns max cpu ID */
+rv = max_id;
+goto cleanup;
+}
+/* we get percpu cputime accoutning info. */
+if (virCgroupGetCpuacctPercpuUsage(group, buf))
+goto cleanup;
+pos = buf;
+
+if (max_id  start_cpu + ncpus - 1)
+max_id = start_cpu + ncpus - 1;
+
+for (i = 0; i = max_id; i++) {
+bool exist;
+unsigned long long cpu_time;
+
+if (virBitmapGetBit(map, i, exist)  0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR, _(bitmap parse error));
+goto cleanup;
+}
+if (!exist

[libvirt] [PATCH 5/5 V5] cpu-accts command shows cpu accounting information of a domain.

2012-02-09 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

Total:
cpu_time15.8
CPU0:
cpu_time8.6
CPU1:
cpu_time3.5
CPU2:
cpu_time2.4
CPU3:
cpu_time1.3
---
 tools/virsh.c   |  116 +++
 tools/virsh.pod |5 ++
 2 files changed, 121 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 66ba61c..e9d2f86 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -5385,6 +5385,121 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * cputime command
+ */
+static const vshCmdInfo info_cpu_accts[] = {
+{help, N_(show domain cpu accounting information)},
+{desc, N_(Returns information about the domain's cpu accounting)},
+{NULL, NULL},
+};
+
+static const vshCmdOptDef opts_cpu_accts[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{NULL, 0, 0, NULL},
+};
+
+static bool
+cmdCPUAccts(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+virTypedParameterPtr params = NULL;
+bool ret = true;
+int i, j, pos, cpu, nparams;
+int max_id;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+/* get max cpu id on the node */
+max_id = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0);
+if (max_id  0) {
+vshPrint(ctl, max id %d\n, max_id);
+goto cleanup;
+}
+/* get supported num of parameter for total statistics */
+nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
+if (nparams  0)
+goto cleanup;
+
+if (VIR_ALLOC_N(params, nparams)) {
+virReportOOMError();
+goto cleanup;
+}
+/* passing start_cpu == -1 gives us domain's total status */
+nparams = virDomainGetCPUStats(dom, params, nparams, -1, 1, 0);
+if (nparams  0)
+goto cleanup;
+
+vshPrint(ctl, Total:\n);
+for (i = 0; i  nparams; i++) {
+vshPrint(ctl, \t%-15s , params[i].field);
+switch (params[i].type) {
+case VIR_TYPED_PARAM_ULLONG:
+/* Now all UULONG param is used for time accounting in ns */
+vshPrint(ctl, %.1lf\n,
+ params[i].value.ul / 10.0);
+break;
+default:
+vshError(ctl, %s, _(API mismatch?));
+goto cleanup;
+}
+}
+VIR_FREE(params);
+/* get percpu information */
+nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
+if (nparams  0)
+goto cleanup;
+
+cpu = 0;
+while (cpu = max_id) {
+int ncpus = 128;
+
+if (cpu + ncpus - 1  max_id) /* id starts from 0. */
+ncpus = max_id + 1 - cpu;
+
+if (VIR_ALLOC_N(params, nparams * ncpus)) {
+virReportOOMError();
+goto cleanup;
+}
+
+if (virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0)  0)
+goto cleanup;
+
+for (i = 0; i  ncpus; i++) {
+if (params[i * nparams].type == 0)
+continue;
+vshPrint(ctl, CPU%d:\n, cpu + i);
+
+for (j = 0; j  nparams; j++) {
+pos = i * nparams + j;
+if (params[pos].type == 0)
+continue;
+vshPrint(ctl, \t%-15s , params[pos].field);
+switch(params[j].type) {
+case VIR_TYPED_PARAM_ULLONG:
+vshPrint(ctl, %.1lf\n,
+params[pos].value.ul / 10.0);
+break;
+default:
+vshError(ctl, %s, _(API mismatch?));
+goto cleanup;
+}
+}
+}
+cpu += ncpus;
+/* Note: If we handle string type, it should be freed */
+VIR_FREE(params);
+}
+cleanup:
+VIR_FREE(params);
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * inject-nmi command
  */
 static const vshCmdInfo info_inject_nmi[] = {
@@ -16441,6 +16556,7 @@ static const vshCmdDef domManagementCmds[] = {
 #endif
 {cpu-baseline, cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0},
 {cpu-compare, cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0},
+{cpu-accts, cmdCPUAccts, opts_cpu_accts, info_cpu_accts, 0},
 {create, cmdCreate, opts_create, info_create, 0},
 {define, cmdDefine, opts_define, info_define, 0},
 {desc, cmdDesc, opts_desc, info_desc, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index bd79b4c..2b2f70b 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -762,6 +762,11 @@ Provide the maximum number of virtual CPUs supported for a 
guest VM on
 this connection.  If provided, the Itype parameter must be a valid
 type attribute for the domain element of XML.
 
+=item Bcpu-accts Idomain
+
+Provide cpu accounting information of a domain. The domain should
+be running.
+
 =item Bmigrate [I--live] 

[libvirt] [PATCH 3/5 V5] add nodeGetCPUmap() for getting available CPU IDs in a bitmap.

2012-02-09 Thread Lai Jiangshan
From: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com

 add virBitmapParseCommaSeparetedFormat() for parsing bitmap in
 comma separeted ascii format.
 This format of bitmap is used in Linux sysfs and cpuset.

Changelog:
 - fixed typos.
 - fixed string scan routine.

Signed-off-by: KAMEZAWA Hiroyuki kamezawa.hir...@jp.fujitsu.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/libvirt_private.syms |2 +
 src/nodeinfo.c   |   51 
 src/nodeinfo.h   |4 +++
 src/util/bitmap.c|   65 ++
 src/util/bitmap.h|6 +++-
 5 files changed, 127 insertions(+), 1 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6ad36c..14b144f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -17,6 +17,7 @@ virBitmapFree;
 virBitmapGetBit;
 virBitmapSetBit;
 virBitmapString;
+virBitmapParseCommaSeparatedFormat;
 
 
 # buf.h
@@ -797,6 +798,7 @@ nodeGetCellsFreeMemory;
 nodeGetFreeMemory;
 nodeGetInfo;
 nodeGetMemoryStats;
+nodeGetCPUmap;
 
 
 # nwfilter_conf.h
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index e0b66f7..b0ebb88 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -47,6 +47,7 @@
 #include count-one-bits.h
 #include intprops.h
 #include virfile.h
+#include bitmap.h
 
 
 #define VIR_FROM_THIS VIR_FROM_NONE
@@ -569,6 +570,33 @@ int linuxNodeGetMemoryStats(FILE *meminfo,
 cleanup:
 return ret;
 }
+
+/*
+ * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set
+ * and max cpu is 7. The map file shows 0-4,6-7. This functin parses
+ * it and returns bitmap.
+ */
+static virBitmapPtr linuxParseCPUmap(int *max_cpuid, const char *path)
+{
+char str[1024];
+FILE *fp;
+virBitmapPtr map = NULL;
+
+fp = fopen(path, r);
+if (!fp) {
+virReportSystemError(errno,  _(cannot open %s), path);
+goto cleanup;
+}
+if (fgets(str, sizeof(str), fp) == NULL) {
+virReportSystemError(errno, _(cannot read from %s), path);
+goto cleanup;
+}
+map = virBitmapParseCommaSeparatedFormat(str, max_cpuid);
+
+cleanup:
+VIR_FORCE_FCLOSE(fp);
+return map;
+}
 #endif
 
 int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
@@ -712,6 +740,29 @@ int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
 #endif
 }
 
+virBitmapPtr nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED,
+   int *max_id,
+   const char *mapname)
+{
+#ifdef __linux__
+char *path;
+virBitmapPtr map;
+
+if (virAsprintf(path, CPU_SYS_PATH /%s, mapname)  0) {
+virReportOOMError();
+return NULL;
+}
+
+map = linuxParseCPUmap(max_id, path);
+VIR_FREE(path);
+return map;
+#else
+ nodeReportError(VIR_ERR_NO_SUPPORT, %s,
+ _(node cpumap not implemented on this platform));
+ return -1;
+#endif
+}
+
 #if HAVE_NUMACTL
 # if LIBNUMA_API_VERSION = 1
 #  define NUMA_MAX_N_CPUS 4096
diff --git a/src/nodeinfo.h b/src/nodeinfo.h
index 4766152..7f26b77 100644
--- a/src/nodeinfo.h
+++ b/src/nodeinfo.h
@@ -26,6 +26,7 @@
 
 # include libvirt/libvirt.h
 # include capabilities.h
+# include bitmap.h
 
 int nodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo);
 int nodeCapsInitNUMA(virCapsPtr caps);
@@ -46,4 +47,7 @@ int nodeGetCellsFreeMemory(virConnectPtr conn,
int maxCells);
 unsigned long long nodeGetFreeMemory(virConnectPtr conn);
 
+virBitmapPtr nodeGetCPUmap(virConnectPtr conn,
+   int *max_id,
+   const char *mapname);
 #endif /* __VIR_NODEINFO_H__*/
diff --git a/src/util/bitmap.c b/src/util/bitmap.c
index 8c326c4..6dead3b 100644
--- a/src/util/bitmap.c
+++ b/src/util/bitmap.c
@@ -33,6 +33,11 @@
 #include bitmap.h
 #include memory.h
 #include buf.h
+#include c-ctype.h
+#include util.h
+#include virterror_internal.h
+
+#define VIR_FROM_THIS VIR_FROM_NONE
 
 
 struct _virBitmap {
@@ -180,3 +185,63 @@ char *virBitmapString(virBitmapPtr bitmap)
 
 return virBufferContentAndReset(buf);
 }
+
+/**
+ * virBitmapParseCommaSeparatedFormat:
+ *
+ * When bitmap is printed in ascii format, especially in Linux,
+ * comma-separated format is sometimes used. For example, a bitmap 1011 is
+ * represetned as 0-4,6-7. This function parses comma-separated format
+ * and returns virBitmap. Found max bit is returned, too.
+ *
+ * This functions stops if characters other than digits, ',', '-' are
+ * found. This function will be useful for parsing linux's bitmap.
+ */
+virBitmapPtr virBitmapParseCommaSeparatedFormat(char *buf, int *max_bit)
+{
+char *pos = buf;
+virBitmapPtr map = NULL;
+int val, x;
+
+/* at first, find the highest number */
+val = 0;
+while ((*pos != '\n')  (*pos != 0)) {
+if (c_isdigit(*pos)) {
+virStrToLong_i(pos, pos, 10, val);
+} else if ((*pos

[libvirt] [PATCH 1/1 V4] ocaml-libvirt: add D.get_cpu_stats() API to ocaml-libvirt

2012-02-08 Thread Lai Jiangshan
Changed from V3:
use new virDomainGetCPUStats() libvirt-API.
use C code to construct the typed_param list array

Acked-by: Richard W.M. Jones rjo...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 libvirt/libvirt.ml  |8 
 libvirt/libvirt.mli |   11 +
 libvirt/libvirt_c_oneoffs.c |   91 +++
 3 files changed, 110 insertions(+), 0 deletions(-)
diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml
index fc29264..08c501b 100644
--- a/libvirt/libvirt.ml
+++ b/libvirt/libvirt.ml
@@ -343,6 +343,13 @@ struct
 | SchedFieldInt64 of int64 | SchedFieldUInt64 of int64
 | SchedFieldFloat of float | SchedFieldBool of bool
 
+  type typed_param = string * typed_param_value
+  and typed_param_value =
+| TypedFieldInt32 of int32 | TypedFieldUInt32 of int32
+| TypedFieldInt64 of int64 | TypedFieldUInt64 of int64
+| TypedFieldFloat of float | TypedFieldBool of bool
+| TypedFieldString of string
+
   type migrate_flag = Live
 
   type memory_flag = Virtual
@@ -419,6 +426,7 @@ struct
   external set_vcpus : [`W] t - int - unit = 
ocaml_libvirt_domain_set_vcpus
   external pin_vcpu : [`W] t - int - string - unit = 
ocaml_libvirt_domain_pin_vcpu
   external get_vcpus : [`R] t - int - int - int * vcpu_info array * string 
= ocaml_libvirt_domain_get_vcpus
+  external get_cpu_stats : [`R] t - int - typed_param list array = 
ocaml_libvirt_domain_get_cpu_stats
   external get_max_vcpus : [`R] t - int = 
ocaml_libvirt_domain_get_max_vcpus
   external attach_device : [`W] t - xml - unit = 
ocaml_libvirt_domain_attach_device
   external detach_device : [`W] t - xml - unit = 
ocaml_libvirt_domain_detach_device
diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli
index 7bda889..31f2ca2 100644
--- a/libvirt/libvirt.mli
+++ b/libvirt/libvirt.mli
@@ -439,6 +439,13 @@ sig
 | SchedFieldInt64 of int64 | SchedFieldUInt64 of int64
 | SchedFieldFloat of float | SchedFieldBool of bool
 
+  type typed_param = string * typed_param_value
+  and typed_param_value =
+| TypedFieldInt32 of int32 | TypedFieldUInt32 of int32
+| TypedFieldInt64 of int64 | TypedFieldUInt64 of int64
+| TypedFieldFloat of float | TypedFieldBool of bool
+| TypedFieldString of string
+
   type migrate_flag = Live
 
   type memory_flag = Virtual
@@ -586,6 +593,10 @@ sig
for a domain.  See the libvirt documentation for details
of the array and bitmap returned from this function.
 *)
+  val get_cpu_stats : [`R] t - int - typed_param list array
+(** [get_pcpu_stats dom nr_pcpu] returns the physic CPU stats
+   for a domain.  See the libvirt documentation for details.
+*)
   val get_max_vcpus : [`R] t - int
 (** Returns the maximum number of vCPUs supported for this domain. *)
   val attach_device : [`W] t - xml - unit
diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c
index d87dd21..a0c74be 100644
--- a/libvirt/libvirt_c_oneoffs.c
+++ b/libvirt/libvirt_c_oneoffs.c
@@ -604,6 +604,97 @@ ocaml_libvirt_domain_get_vcpus (value domv, value 
maxinfov, value maplenv)
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv)
+{
+  CAMLparam2 (domv, nr_pcpusv);
+  CAMLlocal5 (cpustats, param_head, param_node, typed_param, 
typed_param_value);
+  virDomainPtr dom = Domain_val (domv);
+  virConnectPtr conn = Connect_domv (domv);
+  int nr_pcpus = Int_val (nr_pcpusv);
+  virTypedParameterPtr params;
+  int r, cpu, ncpus, nparams, i, j, pos;
+
+  /* get percpu information */
+  NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0));
+  CHECK_ERROR (nparams  0, conn, virDomainGetCPUStats);
+
+  if ((params = malloc(sizeof(*params) * nparams * 128)) == NULL)
+caml_failwith ((char *)__FUNCTION__);
+
+  cpustats = caml_alloc (nr_pcpus, 0); /* cpustats: array of params(list of 
typed_param) */
+  cpu = 0;
+  while (cpu  nr_pcpus) {
+ncpus = nr_pcpus - cpu  128 ? 128 : nr_pcpus - cpu;
+
+NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 
0));
+CHECK_ERROR (r  0, conn, virDomainGetCPUStats);
+
+for (i = 0; i  ncpus; i++) {
+  /* list of typed_param: single linked list of param_nodes */
+  param_head = Val_emptylist; /* param_head: the head param_node of list 
of typed_param */
+
+  if (params[i * nparams].type == 0) {
+Store_field(cpustats, cpu + i, param_head);
+continue;
+  }
+
+  for (j = nparams - 1; j = 0; j--) {
+pos = i * nparams + j;
+  if (params[pos].type == 0)
+continue;
+
+param_node = caml_alloc(2, 0); /* param_node: typed_param, next 
param_node */
+Store_field(param_node, 1, param_head);
+param_head = param_node;
+
+typed_param = caml_alloc(2, 0); /* typed_param: field name(string), 
typed_param_value */
+Store_field(param_node, 0, typed_param);
+Store_field(typed_param, 0

[libvirt] [PATCH 1/1 V4] virt-top: correct virt-top -1 command via cpuacct cgroup

2012-02-08 Thread Lai Jiangshan


Old virt-top -1 is not correct, its output is generated by guess:
use average usage for pinned physical CPUs.

example(old virt-top -1):

PHYCPU %CPU rhel6  Windows  
  
   00.6  0.1=   0.5=
   10.6  0.1=   0.5=#
   20.6  0.1=   0.5=
   30.6  0.1=#  0.5=

The output almost makes no sense(all the value are just average, not real).

This is new implement, it use cpuacct cgroup to gain *real* physical usages
via cpuacct cgroup by virDomainGetCPUStats() API.

new result:

PHYCPU %CPU rhel6  Windows
   01.3  0.3 1.0
   12.3  0.3 2.0
   22.2  0.5 1.7
   32.5  0.4 2.1


PHYCPU %CPU rhel6  Windows
   01.7  0.4 1.3
   13.6  1.0 2.7
   21.6  0.4 1.2
   34.8  3.1 1.7



Note: average flag(=) is dropped, there is not average value in here.
Note: running flag(#) is dropped, because if the value is not empty,
  it means the guest was once running in the physical CPU in this period
  between updates.

Changed from V3:
use new virDomainGetCPUStats() libvirt-API.
add a new function find_usages_from_stats() to gain cpu usages.

Acked-by: Richard W.M. Jones rjo...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 virt-top/virt_top.ml |   80 +++--
 1 files changed, 31 insertions(+), 49 deletions(-)

diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml
index ef5ac67..f7bd072 100644
--- a/virt-top/virt_top.ml
+++ b/virt-top/virt_top.ml
@@ -446,14 +446,14 @@ let collect, clear_pcpu_display_data =
   let last_info = Hashtbl.create 13 in
   let last_time = ref (Unix.gettimeofday ()) in
 
-  (* Save vcpuinfo structures across redraws too (only for pCPU display). *)
-  let last_vcpu_info = Hashtbl.create 13 in
+  (* Save pcpu_usages structures across redraws too (only for pCPU display). *)
+  let last_pcpu_usages = Hashtbl.create 13 in
 
   let clear_pcpu_display_data () =
-(* Clear out vcpu_info used by PCPUDisplay display_mode
+(* Clear out pcpu_info used by PCPUDisplay display_mode
  * when we switch back to TaskDisplay mode.
  *)
-Hashtbl.clear last_vcpu_info
+Hashtbl.clear last_pcpu_usages
   in
 
   let collect (conn, _, _, _, _, node_info, _, _) =
@@ -652,22 +652,28 @@ let collect, clear_pcpu_display_data =
  (try
 let domid = rd.rd_domid in
 let maplen = C.cpumaplen nr_pcpus in
+let cpu_stats = D.get_cpu_stats rd.rd_dom nr_pcpus in
+let rec find_usages_from_stats = (function
+  | (cpu_time, D.TypedFieldUInt64(usages)) :: _ - usages
+  | (_, _) :: params - find_usages_from_stats params
+  | [] - 0L) in
+let pcpu_usages = Array.map find_usages_from_stats cpu_stats in
 let maxinfo = rd.rd_info.D.nr_virt_cpu in
 let nr_vcpus, vcpu_infos, cpumaps =
   D.get_vcpus rd.rd_dom maxinfo maplen in
 
-(* Got previous vcpu_infos for this domain? *)
-let prev_vcpu_infos =
-  try Some (Hashtbl.find last_vcpu_info domid)
+(* Got previous pcpu_usages for this domain? *)
+let prev_pcpu_usages =
+  try Some (Hashtbl.find last_pcpu_usages domid)
   with Not_found - None in
-(* Update last_vcpu_info. *)
-Hashtbl.replace last_vcpu_info domid vcpu_infos;
-
-(match prev_vcpu_infos with
- | Some prev_vcpu_infos
- when Array.length prev_vcpu_infos = Array.length 
vcpu_infos -
- Some (domid, name, nr_vcpus, vcpu_infos, prev_vcpu_infos,
-   cpumaps, maplen)
+(* Update last_pcpu_usages. *)
+Hashtbl.replace last_pcpu_usages domid pcpu_usages;
+
+(match prev_pcpu_usages with
+ | Some prev_pcpu_usages
+ when Array.length prev_pcpu_usages = Array.length 
pcpu_usages -
+ Some (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
+   prev_pcpu_usages, cpumaps, maplen)
  | _ - None (* ignore missing / unequal length 
prev_vcpu_infos *)
 );
   with
@@ -680,37 +686,15 @@ let collect, clear_pcpu_display_data =
(* Rearrange the data into a matrix.  Major axis (down) is
 * pCPUs.  Minor axis (right) is domains.  At each node we store:
 *  cpu_time (on this pCPU only, nanosecs),
-*  average? (if set, then cpu_time is an average because the
-* vCPU is pinned to more than one pCPU)
-*  running? (if set, we were instantaneously running on this pCPU)
 *)
-   let empty_node = (0L, false, false) in
-   let pcpus = Array.make_matrix nr_pcpus nr_doms empty_node

Re: [libvirt] [PATCH V4 1/5] Add new public API virDomainGetCPUStats()

2012-02-08 Thread Lai Jiangshan
Hi, Eric

Are any problem/suggestion with 3/5 4/5 5/5 of V4 patchset?
If not, I will rebase them and resend them with tiny fixes applied.

Thanks,
Lai

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/5 V3] virsh: Enable the pcpuinfo command in virsh

2012-01-17 Thread Lai Jiangshan
This command gets information about the physical CPUs.
Example:

# virsh pcpuinfo rhel6
CPU:0
Curr VCPU:  -
Usage:  47.3

CPU:1
Curr VCPU:  1
Usage:  46.8

CPU:2
Curr VCPU:  0
Usage:  52.7

CPU:3
Curr VCPU:  -
Usage:  44.1

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |   93 +++
 tools/virsh.pod |5 +++
 2 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index c511e2a..e8b9221 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -4702,6 +4702,98 @@ cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * pcpuinfo command
+ */
+static const vshCmdInfo info_pcpuinfo[] = {
+{help, N_(detailed domain pcpu information)},
+{desc, N_(Returns basic information about the domain's physical 
CPUs.)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_pcpuinfo[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{NULL, 0, 0, NULL}
+};
+
+static bool
+cmdPcpuinfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainInfo info;
+virDomainPtr dom;
+virNodeInfo nodeinfo;
+virVcpuInfoPtr cpuinfo;
+unsigned char *cpumaps;
+int ncpus, maxcpu;
+size_t cpumaplen;
+bool ret = true;
+int n, m;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (virNodeGetInfo(ctl-conn, nodeinfo) != 0) {
+virDomainFree(dom);
+return false;
+}
+
+if (virDomainGetInfo(dom, info) != 0) {
+virDomainFree(dom);
+return false;
+}
+
+cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
+maxcpu = VIR_NODEINFO_MAXCPUS(nodeinfo);
+cpumaplen = VIR_CPU_MAPLEN(maxcpu);
+cpumaps = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
+
+if ((ncpus = virDomainGetVcpus(dom,
+   cpuinfo, info.nrVirtCpu,
+   cpumaps, cpumaplen)) = 0) {
+unsigned long long *usages;
+int nr_usages = maxcpu;
+
+if (VIR_ALLOC_N(usages, nr_usages)  0) {
+virReportOOMError();
+goto fail;
+}
+
+if (virDomainGetPcpusUsage(dom, usages, nr_usages, 0)  0) {
+VIR_FREE(usages);
+goto fail;
+}
+
+for (n = 0; n  MIN(maxcpu, nr_usages); n++) {
+vshPrint(ctl, %-15s %d\n, _(CPU:), n);
+for (m = 0; m  ncpus; m++) {
+if (cpuinfo[m].cpu == n) {
+vshPrint(ctl, %-15s %d\n, _(Curr VCPU:), m);
+break;
+}
+}
+if (m == ncpus) {
+vshPrint(ctl, %-15s %s\n, _(Curr VCPU:), _(-));
+}
+vshPrint(ctl, %-15s %.1lf\n\n, _(Usage:),
+ usages[n] / 10.0);
+}
+VIR_FREE(usages);
+goto cleanup;
+}
+
+fail:
+ret = false;
+
+cleanup:
+VIR_FREE(cpumaps);
+VIR_FREE(cpuinfo);
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * vcpupin command
  */
 static const vshCmdInfo info_vcpupin[] = {
@@ -15952,6 +16044,7 @@ static const vshCmdDef domManagementCmds[] = {
 {migrate-getspeed, cmdMigrateGetMaxSpeed,
  opts_migrate_getspeed, info_migrate_getspeed, 0},
 {numatune, cmdNumatune, opts_numatune, info_numatune, 0},
+{pcpuinfo, cmdPcpuinfo, opts_pcpuinfo, info_pcpuinfo, 0},
 {reboot, cmdReboot, opts_reboot, info_reboot, 0},
 {reset, cmdReset, opts_reset, info_reset, 0},
 {restore, cmdRestore, opts_restore, info_restore, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index c88395b..8d9cceb 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1296,6 +1296,11 @@ Thus, this command always takes exactly zero or two 
flags.
 Returns basic information about the domain virtual CPUs, like the number of
 vCPUs, the running time, the affinity to physical processors.
 
+=item Bpcpuinfo Idomain-id
+
+Returns information about the physical CPUs of the domain, like the usage of
+CPUs, the current attached vCPUs.
+
 =item Bvcpupin Idomain-id [Ivcpu] [Icpulist] [[I--live]
 [I--config] | [I--current]]
 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 1/1 V3] virt-top: correct virt-top -1 command via cpuacct cgroup

2012-01-17 Thread Lai Jiangshan
Old virt-top -1 is not correct, its output is generated by guess:
use average usage for pinned physical CPUs.

example(old virt-top -1):

PHYCPU %CPU rhel6  Windows  
  
   00.6  0.1=   0.5=
   10.6  0.1=   0.5=#
   20.6  0.1=   0.5=
   30.6  0.1=#  0.5=

The output almost makes no sense(all the value are just average, not real).

This is new implement, it use cpuacct cgroup to gain *real* physical usages
via cpuacct cgroup by virDomainGetPcpusUsage() API.

new result:

PHYCPU %CPU rhel6  Windows  

   03.3  2.90.3
   11.7  1.10.6
   23.5  1.81.6
   33.4  1.61.8

PHYCPU %CPU rhel6  Windows  

   01.2  0.80.4
   11.6 1.6
   22.2  1.70.5
   33.0  2.50.5


Note: average flag(=) is dropped, there is not average value in here.
Note: running flag(#) is dropped, because if the value is not empty,
  it means the guest was once running in the physical CPU in this period
  between updates.

Acked-by: Richard W.M. Jones rjo...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 virt-top/virt_top.ml |   75 +
 1 files changed, 26 insertions(+), 49 deletions(-)

diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml
index ef5ac67..2556b77 100644
--- a/virt-top/virt_top.ml
+++ b/virt-top/virt_top.ml
@@ -446,14 +446,14 @@ let collect, clear_pcpu_display_data =
   let last_info = Hashtbl.create 13 in
   let last_time = ref (Unix.gettimeofday ()) in
 
-  (* Save vcpuinfo structures across redraws too (only for pCPU display). *)
-  let last_vcpu_info = Hashtbl.create 13 in
+  (* Save pcpu_usages structures across redraws too (only for pCPU display). *)
+  let last_pcpu_usages = Hashtbl.create 13 in
 
   let clear_pcpu_display_data () =
-(* Clear out vcpu_info used by PCPUDisplay display_mode
+(* Clear out pcpu_info used by PCPUDisplay display_mode
  * when we switch back to TaskDisplay mode.
  *)
-Hashtbl.clear last_vcpu_info
+Hashtbl.clear last_pcpu_usages
   in
 
   let collect (conn, _, _, _, _, node_info, _, _) =
@@ -652,22 +652,23 @@ let collect, clear_pcpu_display_data =
  (try
 let domid = rd.rd_domid in
 let maplen = C.cpumaplen nr_pcpus in
+let pcpu_usages = D.get_pcpu_usages rd.rd_dom nr_pcpus in
 let maxinfo = rd.rd_info.D.nr_virt_cpu in
 let nr_vcpus, vcpu_infos, cpumaps =
   D.get_vcpus rd.rd_dom maxinfo maplen in
 
-(* Got previous vcpu_infos for this domain? *)
-let prev_vcpu_infos =
-  try Some (Hashtbl.find last_vcpu_info domid)
+(* Got previous pcpu_usages for this domain? *)
+let prev_pcpu_usages =
+  try Some (Hashtbl.find last_pcpu_usages domid)
   with Not_found - None in
-(* Update last_vcpu_info. *)
-Hashtbl.replace last_vcpu_info domid vcpu_infos;
-
-(match prev_vcpu_infos with
- | Some prev_vcpu_infos
- when Array.length prev_vcpu_infos = Array.length 
vcpu_infos -
- Some (domid, name, nr_vcpus, vcpu_infos, prev_vcpu_infos,
-   cpumaps, maplen)
+(* Update last_pcpu_usages. *)
+Hashtbl.replace last_pcpu_usages domid pcpu_usages;
+
+(match prev_pcpu_usages with
+ | Some prev_pcpu_usages
+ when Array.length prev_pcpu_usages = Array.length 
pcpu_usages -
+ Some (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
+   prev_pcpu_usages, cpumaps, maplen)
  | _ - None (* ignore missing / unequal length 
prev_vcpu_infos *)
 );
   with
@@ -680,37 +681,15 @@ let collect, clear_pcpu_display_data =
(* Rearrange the data into a matrix.  Major axis (down) is
 * pCPUs.  Minor axis (right) is domains.  At each node we store:
 *  cpu_time (on this pCPU only, nanosecs),
-*  average? (if set, then cpu_time is an average because the
-* vCPU is pinned to more than one pCPU)
-*  running? (if set, we were instantaneously running on this pCPU)
 *)
-   let empty_node = (0L, false, false) in
-   let pcpus = Array.make_matrix nr_pcpus nr_doms empty_node in
+   let pcpus = Array.make_matrix nr_pcpus nr_doms 0L in
 
List.iteri (
- fun di (domid, name, nr_vcpus, vcpu_infos, prev_vcpu_infos,
- cpumaps, maplen) -
+ fun di (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
+ prev_pcpu_usages, cpumaps, maplen

[libvirt] [PATCH 1/5 V3] libvirt: Add new public API virDomainGetPcpusUsage

2012-01-17 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in |5 
 python/generator.py  |1 +
 src/driver.h |7 +
 src/libvirt.c|   51 ++
 src/libvirt_public.syms  |5 
 5 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index e436f3c..167e89f 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3606,6 +3606,11 @@ int virConnectSetKeepAlive(virConnectPtr conn,
int interval,
unsigned int count);
 
+int virDomainGetPcpusUsage(virDomainPtr dom,
+   unsigned long long *usages,
+   int *nr_usages,
+   unsigned int flags);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/python/generator.py b/python/generator.py
index 6fee3a4..0311004 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -421,6 +421,7 @@ skip_impl = (
 'virDomainGetBlockIoTune',
 'virDomainSetInterfaceParameters',
 'virDomainGetInterfaceParameters',
+'virDomainGetPcpusUsage', # not implemented yet
 )
 
 qemu_skip_impl = (
diff --git a/src/driver.h b/src/driver.h
index 24636a4..2a3c46d 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -794,6 +794,12 @@ typedef int
   int *nparams,
   unsigned int flags);
 
+typedef int
+(*virDrvDomainGetPcpusUsage)(virDomainPtr dom,
+ unsigned long long *usages,
+ int *nr_usages,
+ unsigned int flags);
+
 /**
  * _virDriver:
  *
@@ -962,6 +968,7 @@ struct _virDriver {
 virDrvNodeSuspendForDuration nodeSuspendForDuration;
 virDrvDomainSetBlockIoTune domainSetBlockIoTune;
 virDrvDomainGetBlockIoTune domainGetBlockIoTune;
+virDrvDomainGetPcpusUsage domainGetPcpusUsage;
 };
 
 typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index a540424..bd19bf5 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -17882,3 +17882,54 @@ error:
 virDispatchError(dom-conn);
 return -1;
 }
+
+/**
+ * virDomainGetPcpusUsage:
+ * @dom: pointer to domain object
+ * @usages: returned physical cpu usages
+ * @nr_usages: length of @usages
+ * @flags: flags to control the operation
+ *
+ * Get the cpu usages for every physical cpu since the domain started (in 
nanoseconds).
+ *
+ * Returns 0 if success, -1 on error
+ */
+int virDomainGetPcpusUsage(virDomainPtr dom,
+   unsigned long long *usages,
+   int *nr_usages,
+   unsigned int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(dom, usages=%p, nr_usages=%d, flags=%x,
+ usages, (nr_usages) ? *nr_usages : -1, flags);
+
+virResetLastError();
+
+if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+virDispatchError(NULL);
+return -1;
+}
+
+if (nr_usages == NULL  *nr_usages != 0) {
+virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+goto error;
+}
+
+conn = dom-conn;
+
+if (conn-driver-domainGetPcpusUsage) {
+int ret;
+ret = conn-driver-domainGetPcpusUsage(dom, usages, nr_usages, flags);
+if (ret  0)
+goto error;
+return ret;
+}
+
+virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+virDispatchError(dom-conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 4ca7216..15d944c 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -516,4 +516,9 @@ LIBVIRT_0.9.9 {
 virDomainSetNumaParameters;
 } LIBVIRT_0.9.8;
 
+LIBVIRT_0.9.10 {
+global:
+virDomainGetPcpusUsage;
+} LIBVIRT_0.9.9;
+
 #  define new API here using predicted next version number 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 0/5 0/1 0/1 V3] Add new public API virDomainGetPcpusUsage() and pcpuinfo command in virsh

2012-01-17 Thread Lai Jiangshan
virt-top -1 can call virDomainGetPcpusUsage() periodically and get
the CPU activities per CPU. (See the last patch in this series).

virsh is also added a pcpuinfo command which calls virDomainGetPcpusUsage(),
it gets information about the physical CPUs, such as the usage of
CPUs, the current attached vCPUs.

# virsh pcpuinfo rhel6
CPU:0
Curr VCPU:  -
Usage:  47.3

CPU:1
Curr VCPU:  1
Usage:  46.8

CPU:2
Curr VCPU:  0
Usage:  52.7

CPU:3
Curr VCPU:  -
Usage:  44.1

Changed from V2:
Simple cleanup
Add python implementation of virDomainGetPcpusUsage()

Acked-by: Richard W.M. Jones rjo...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com


Patch for libvirt(5 patches):

 daemon/remote.c |   68 
 include/libvirt/libvirt.h.in|5 ++
 python/generator.py |1 +
 python/libvirt-override-api.xml |6 +++
 python/libvirt-override.c   |   33 ++
 src/driver.h|7 +++
 src/libvirt.c   |   51 +
 src/libvirt_public.syms |5 ++
 src/qemu/qemu.conf  |5 +-
 src/qemu/qemu_conf.c|3 +-
 src/qemu/qemu_driver.c  |   74 +++
 src/remote/remote_driver.c  |   51 +
 src/remote/remote_protocol.x|   17 +++-
 src/remote_protocol-structs |   13 +
 src/util/cgroup.c   |7 +++
 src/util/cgroup.h   |1 +
 tools/virsh.c   |   93 +++
 tools/virsh.pod |5 ++
 18 files changed, 441 insertions(+), 4 deletions(-)


Patch for ocaml-libvirt (1 patch):

 libvirt/libvirt.ml  |1 +
 libvirt/libvirt.mli |4 
 libvirt/libvirt_c_oneoffs.c |   25 +
 3 files changed, 30 insertions(+), 0 deletions(-)

Patch for virt-top (1 patch):

 virt-top/virt_top.ml |   75 +
 1 files changed, 26 insertions(+), 49 deletions(-)

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 1/1 V3] ocaml-libvirt: and virDomainGetPcpusUsage() API to ocaml-libvirt

2012-01-17 Thread Lai Jiangshan
Acked-by: Richard W.M. Jones rjo...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 libvirt/libvirt.ml  |1 +
 libvirt/libvirt.mli |4 
 libvirt/libvirt_c_oneoffs.c |   25 +
 3 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml
index fc29264..a8720a9 100644
--- a/libvirt/libvirt.ml
+++ b/libvirt/libvirt.ml
@@ -419,6 +419,7 @@ struct
   external set_vcpus : [`W] t - int - unit = 
ocaml_libvirt_domain_set_vcpus
   external pin_vcpu : [`W] t - int - string - unit = 
ocaml_libvirt_domain_pin_vcpu
   external get_vcpus : [`R] t - int - int - int * vcpu_info array * string 
= ocaml_libvirt_domain_get_vcpus
+  external get_pcpu_usages : [`R] t - int - int64 array = 
ocaml_libvirt_domain_get_pcpu_usages
   external get_max_vcpus : [`R] t - int = 
ocaml_libvirt_domain_get_max_vcpus
   external attach_device : [`W] t - xml - unit = 
ocaml_libvirt_domain_attach_device
   external detach_device : [`W] t - xml - unit = 
ocaml_libvirt_domain_detach_device
diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli
index 7bda889..63bf830 100644
--- a/libvirt/libvirt.mli
+++ b/libvirt/libvirt.mli
@@ -586,6 +586,10 @@ sig
for a domain.  See the libvirt documentation for details
of the array and bitmap returned from this function.
 *)
+  val get_pcpu_usages : [`R] t - int - int64 array
+(** [get_pcpu_usages dom nr_pcpu] returns the physical CPU usages
+   for a domain.  See the libvirt documentation for details.
+*)
   val get_max_vcpus : [`R] t - int
 (** Returns the maximum number of vCPUs supported for this domain. *)
   val attach_device : [`W] t - xml - unit
diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c
index d87dd21..68d5ecc 100644
--- a/libvirt/libvirt_c_oneoffs.c
+++ b/libvirt/libvirt_c_oneoffs.c
@@ -604,6 +604,31 @@ ocaml_libvirt_domain_get_vcpus (value domv, value 
maxinfov, value maplenv)
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_libvirt_domain_get_pcpu_usages (value domv, value nr_pcpusv)
+{
+  CAMLparam2 (domv, nr_pcpusv);
+  CAMLlocal1 (usagev);
+  virDomainPtr dom = Domain_val (domv);
+  virConnectPtr conn = Connect_domv (domv);
+  int nr_pcpus = Int_val (nr_pcpusv);
+  unsigned long long pcpu_usages[nr_pcpus];
+  int r, i;
+
+  memset (pcpu_usages, 0, sizeof(pcpu_usages[0]) * nr_pcpus);
+
+  NONBLOCKING (r = virDomainGetPcpusUsage (dom, pcpu_usages, nr_pcpus, 0));
+  CHECK_ERROR (r == -1, conn, virDomainGetPcpusUsage);
+
+  /* Copy the pcpu_usages. */
+  usagev = caml_alloc (nr_pcpus, 0);
+  for (i = 0; i  nr_pcpus; ++i) {
+Store_field (usagev, i, caml_copy_int64 ((int64_t)pcpu_usages[i]));
+  }
+
+  CAMLreturn (usagev);
+}
+
 #ifdef HAVE_WEAK_SYMBOLS
 #ifdef HAVE_VIRDOMAINMIGRATE
 extern virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 5/5 V3] python: implement virDomainGetPcpusUsage

2012-01-17 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 python/generator.py |2 +-
 python/libvirt-override-api.xml |6 ++
 python/libvirt-override.c   |   33 +
 3 files changed, 40 insertions(+), 1 deletions(-)

diff --git a/python/generator.py b/python/generator.py
index 0311004..cf75c44 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -421,7 +421,7 @@ skip_impl = (
 'virDomainGetBlockIoTune',
 'virDomainSetInterfaceParameters',
 'virDomainGetInterfaceParameters',
-'virDomainGetPcpusUsage', # not implemented yet
+'virDomainGetPcpusUsage',
 )
 
 qemu_skip_impl = (
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index 704fee9..69bb159 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -421,5 +421,11 @@
   arg name='flags' type='unsigned int' info='an ORapos;ed set of 
virDomainMemoryFlags'/
   return type='char *' info='the returned buffer or None in case of 
error'/
 /function
+function name='virDomainGetPcpusUsage' file='python'
+  infoGet the cpu usages for every physical cpu since the domain started 
(in nanoseconds)./info
+  arg name='dom' type='virDomainPtr' info='pointer to the domain'/
+  arg name='flags' type='unsigned int' info='an ORapos;ed set of 
virDomainMemoryFlags'/
+  return type='unsigned long long *' info='the tuple of the cpu usages'/
+/function
   /symbols
 /api
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index d2aad0f..ad4646d 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -5108,6 +5108,38 @@ cleanup:
 return py_retval;
 }
 
+static PyObject *
+libvirt_virDomainGetPcpusUsage(PyObject *self ATTRIBUTE_UNUSED,
+   PyObject *args) {
+PyObject *py_retval = NULL;
+int c_retval;
+virDomainPtr domain;
+PyObject *pyobj_domain;
+unsigned long long usages[32];
+int i, nr_usages = sizeof(usages) / sizeof(usages[0]);
+unsigned int flags;
+
+if (!PyArg_ParseTuple(args, (char *)Oi:virDomainGetPcpusUsage, 
pyobj_domain,
+  flags))
+return NULL;
+
+domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+LIBVIRT_BEGIN_ALLOW_THREADS;
+c_retval = virDomainGetPcpusUsage(domain, usages, nr_usages, flags);
+LIBVIRT_END_ALLOW_THREADS;
+
+if (c_retval  0)
+return VIR_PY_NONE;
+
+if ((py_retval = PyTuple_New(nr_usages)) == NULL)
+return VIR_PY_NONE;
+for (i = 0; i  nr_usages; i++)
+PyTuple_SetItem(py_retval, i, PyLong_FromLongLong(usages[i]));
+
+return py_retval;
+}
+
 /
  * *
  * The registration stuff  *
@@ -5206,6 +5238,7 @@ static PyMethodDef libvirtMethods[] = {
 {(char *) virDomainMigrateGetMaxSpeed, 
libvirt_virDomainMigrateGetMaxSpeed, METH_VARARGS, NULL},
 {(char *) virDomainBlockPeek, libvirt_virDomainBlockPeek, METH_VARARGS, 
NULL},
 {(char *) virDomainMemoryPeek, libvirt_virDomainMemoryPeek, 
METH_VARARGS, NULL},
+{(char *) virDomainGetPcpusUsage, libvirt_virDomainGetPcpusUsage, 
METH_VARARGS, NULL},
 {NULL, NULL, 0, NULL}
 };
 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/5 V3] remote: mplement new API virDomainGetPcpusUsage for remote driver

2012-01-17 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 daemon/remote.c  |   68 ++
 src/remote/remote_driver.c   |   51 +++
 src/remote/remote_protocol.x |   17 ++-
 src/remote_protocol-structs  |   13 
 4 files changed, 148 insertions(+), 1 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index a28a754..9b0206f 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -2084,6 +2084,74 @@ cleanup:
 return rv;
 }
 
+static int
+remoteDispatchDomainGetPcpusUsage(virNetServerPtr server ATTRIBUTE_UNUSED,
+  virNetServerClientPtr client 
ATTRIBUTE_UNUSED,
+  virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+  virNetMessageErrorPtr rerr,
+  remote_domain_get_pcpus_usage_args *args,
+  remote_domain_get_pcpus_usage_ret *ret)
+{
+int i;
+virDomainPtr dom = NULL;
+int rv = -1;
+unsigned long long *usages;
+int nr_usages = args-nr_usages;
+struct daemonClientPrivate *priv =
+virNetServerClientGetPrivateData(client);
+
+if (!priv-conn) {
+virNetError(VIR_ERR_INTERNAL_ERROR, %s, _(connection not open));
+goto cleanup;
+}
+
+if (nr_usages  REMOTE_DOMAIN_PCPUS_USAGE_PARAMETERS_MAX) {
+virNetError(VIR_ERR_INTERNAL_ERROR, %s, _(nr_usages too large));
+goto cleanup;
+}
+
+if (VIR_ALLOC_N(usages, nr_usages)  0) {
+virReportOOMError();
+goto cleanup;
+}
+
+if (!(dom = get_nonnull_domain(priv-conn, args-dom)))
+goto cleanup;
+
+if (virDomainGetPcpusUsage(dom, usages, nr_usages, args-flags)  0)
+goto cleanup;
+
+ret-nr_usages = nr_usages;
+
+/*
+ * In this case, we need to send back the number of parameters
+ * supported
+ */
+if (args-nr_usages == 0) {
+goto success;
+}
+
+ret-usages.usages_len = MIN(args-nr_usages, nr_usages);
+if (VIR_ALLOC_N(ret-usages.usages_val, ret-usages.usages_len)  0) {
+virReportOOMError();
+goto cleanup;
+}
+
+for (i = 0; i  ret-usages.usages_len; i++) {
+ret-usages.usages_val[i] = usages[i];
+}
+
+success:
+rv = 0;
+
+cleanup:
+if (rv  0)
+virNetMessageSaveError(rerr);
+VIR_FREE(usages);
+if (dom)
+virDomainFree(dom);
+return rv;
+}
 
 #ifdef HAVE_SASL
 /*
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e28840b..9e2f931 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2305,6 +2305,56 @@ done:
 return rv;
 }
 
+static int remoteDomainGetPcpusUsage(virDomainPtr domain,
+ unsigned long long *usages,
+ int *nr_usages,
+ unsigned int flags)
+{
+int i;
+int rv = -1;
+remote_domain_get_pcpus_usage_args args;
+remote_domain_get_pcpus_usage_ret ret;
+struct private_data *priv = domain-conn-privateData;
+
+remoteDriverLock(priv);
+
+make_nonnull_domain(args.dom, domain);
+args.nr_usages = *nr_usages;
+args.flags = flags;
+
+memset(ret, 0, sizeof(ret));
+
+if (call(domain-conn, priv, 0, REMOTE_PROC_DOMAIN_GET_PCPUS_USAGE,
+ (xdrproc_t) xdr_remote_domain_get_pcpus_usage_args,
+   (char *) args,
+ (xdrproc_t) xdr_remote_domain_get_pcpus_usage_ret,
+   (char *) ret) == -1) {
+goto done;
+}
+
+/* Handle the case when the caller does not know the number of parameters
+ * and is asking for the number of parameters supported
+ */
+if (*nr_usages == 0) {
+*nr_usages = ret.nr_usages;
+goto cleanup;
+}
+
+for (i = 0; i  MIN(*nr_usages, ret.usages.usages_len); i++) {
+usages[i] = ret.usages.usages_val[i];
+}
+*nr_usages = ret.nr_usages;
+
+rv = 0;
+
+cleanup:
+xdr_free ((xdrproc_t) xdr_remote_domain_get_pcpus_usage_ret,
+  (char *) ret);
+done:
+remoteDriverUnlock(priv);
+return rv;
+}
+
 /*--*/
 
 static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
@@ -4750,6 +4800,7 @@ static virDriver remote_driver = {
 .domainGetBlockIoTune = remoteDomainGetBlockIoTune, /* 0.9.8 */
 .domainSetNumaParameters = remoteDomainSetNumaParameters, /* 0.9.9 */
 .domainGetNumaParameters = remoteDomainGetNumaParameters, /* 0.9.9 */
+.domainGetPcpusUsage = remoteDomainGetPcpusUsage, /* 0.9.10 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index ca739ff..3c1ab41 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -131,6 +131,9 @@ const REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX = 16;
 /* Upper limit on list of numa

[libvirt] [PATCH 3/5 V3] qemu: implement new API virDomainGetPcpusUsage for qemu driver

2012-01-17 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu.conf |5 ++-
 src/qemu/qemu_conf.c   |3 +-
 src/qemu/qemu_driver.c |   74 
 src/util/cgroup.c  |7 
 src/util/cgroup.h  |1 +
 5 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 4ec5e6c..5f75b3e 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -158,18 +158,19 @@
 #  - 'memory' - use for memory tunables
 #  - 'blkio' - use for block devices I/O tunables
 #  - 'cpuset' - use for CPUs and memory nodes
+#  - 'cpuacct' - use for CPUs' account
 #
 # NB, even if configured here, they won't be used unless
 # the administrator has mounted cgroups, e.g.:
 #
 #  mkdir /dev/cgroup
-#  mount -t cgroup -o devices,cpu,memory,blkio,cpuset none /dev/cgroup
+#  mount -t cgroup -o devices,cpu,memory,blkio,cpuset,cpuacct none /dev/cgroup
 #
 # They can be mounted anywhere, and different controllers
 # can be mounted in different locations. libvirt will detect
 # where they are located.
 #
-# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset ]
+# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset, 
cpuacct ]
 
 # This is the basic set of devices allowed / required by
 # all virtual machines.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index bc0a646..4775638 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -307,7 +307,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 (1  VIR_CGROUP_CONTROLLER_DEVICES) |
 (1  VIR_CGROUP_CONTROLLER_MEMORY) |
 (1  VIR_CGROUP_CONTROLLER_BLKIO) |
-(1  VIR_CGROUP_CONTROLLER_CPUSET);
+(1  VIR_CGROUP_CONTROLLER_CPUSET) |
+(1  VIR_CGROUP_CONTROLLER_CPUACCT);
 }
 for (i = 0 ; i  VIR_CGROUP_CONTROLLER_LAST ; i++) {
 if (driver-cgroupControllers  (1  i)) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 712f1fc..e90e185 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11180,6 +11180,79 @@ cleanup:
 return ret;
 }
 
+static int
+qemuGetPcpusUsage(virDomainPtr dom,
+  unsigned long long *usages,
+  int *nr_usages,
+  unsigned int flags)
+{
+struct qemud_driver *driver = dom-conn-privateData;
+virCgroupPtr group = NULL;
+virDomainObjPtr vm = NULL;
+char *pos, *raw;
+unsigned long long val;
+int nr_cpus = 0;
+int ret = -1;
+int rc;
+bool isActive;
+
+virCheckFlags(0, -1);
+
+qemuDriverLock(driver);
+
+vm = virDomainFindByUUID(driver-domains, dom-uuid);
+
+if (vm == NULL) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(No such domain %s), dom-uuid);
+goto cleanup;
+}
+
+isActive = virDomainObjIsActive(vm);
+
+if (!isActive) {
+qemuReportError(VIR_ERR_OPERATION_INVALID, %s,
+_(domain is not running));
+goto cleanup;
+}
+
+if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID,
+%s, _(cgroup CPUACCT controller is not mounted));
+goto cleanup;
+}
+
+if (virCgroupForDomain(driver-cgroup, vm-def-name, group, 0) != 0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(cannot find cgroup for domain %s), vm-def-name);
+goto cleanup;
+}
+
+rc = virCgroupGetCpuacctPcpusUsage(group, raw);
+if (rc != 0) {
+virReportSystemError(-rc, %s, _(unable to get cpu account));
+goto cleanup;
+}
+
+pos = raw;
+while (virStrToLong_ull(pos, pos, 10, val) = 0) {
+if (nr_cpus  *nr_usages) {
+usages[nr_cpus] = val;
+}
+nr_cpus++;
+}
+
+VIR_FREE(raw);
+*nr_usages = nr_cpus;
+ret = 0;
+
+cleanup:
+virCgroupFree(group);
+if (vm)
+virDomainObjUnlock(vm);
+qemuDriverUnlock(driver);
+return ret;
+}
 
 static virDomainPtr qemuDomainAttach(virConnectPtr conn,
  unsigned int pid,
@@ -11983,6 +12056,7 @@ static virDriver qemuDriver = {
 .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
 .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 
*/
 .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 
*/
+.domainGetPcpusUsage = qemuGetPcpusUsage, /* 0.9.10 */
 };
 
 
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index 25f2691..114eeb5 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -1554,6 +1554,13 @@ int virCgroupGetCpuacctUsage(virCgroupPtr group, 
unsigned long long *usage)
 cpuacct.usage, usage);
 }
 
+int virCgroupGetCpuacctPcpusUsage(virCgroupPtr group, char **usage)
+{
+return virCgroupGetValueStr(group

Re: [libvirt] [PATCH 0/4 0/1 0/1 V2] Add new public API virDomainGetPcpusUsage() and pcpuinfo command in virsh

2012-01-09 Thread Lai Jiangshan
On 01/05/2012 12:55 AM, Eric Blake wrote:
 On 01/03/2012 09:09 PM, Lai Jiangshan wrote:
 virt-top -1 can call virDomainGetPcpusUsage() periodically and get
 the CPU activities per CPU. (See the last patch in this series).

 virsh is also added a pcpuinfo command which calls virDomainGetPcpusUsage(),
 it gets information about the physic CPUs, such as the usage of
 CPUs, the current attached vCPUs.
 
 I think this is invasive enough that we should defer it until after the
 0.9.9 release, but it's definitely on my list of things to review and
 not forgotten.
 

Ping.

I'm glad to see your comments.

Thanks,
Lai

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 1/4 V2] libvirt: Add new public API virDomainGetPcpusUsage

2012-01-06 Thread Lai Jiangshan
On 01/05/2012 10:23 PM, Richard W.M. Jones wrote:
 On Wed, Jan 04, 2012 at 12:09:18PM +0800, Lai Jiangshan wrote:
 +int virDomainGetPcpusUsage(virDomainPtr dom,
 +   unsigned long long *usages,
 +   int *nr_usages,
 +   unsigned int flags);
 
 It'd be useful to get feedback from libvirt folk about whether this
 API is reasonable.
 
 +/**
 + * virDomainGetPcpusUsage:
 + * @dom: pointer to domain object
 + * @usages: returned physic cpu usages
 
 'physical'
 
 + * @nr_usages: length of @usages
 + * @flags: flags to control the operation
 + *
 + * Get the cpu usages per every physic cpu
 
 'physical'
 
 I think this needs to describe what exactly is returned.  Nanoseconds
 since the domain started, I assume?

Yes.

I will apply your comments in next version which will be deferred
until 0.9.9 released as Eric suggested.

Thank you very much.

Lai

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 1/4 V2] libvirt: Add new public API virDomainGetPcpusUsage

2012-01-03 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in |5 
 python/generator.py  |1 +
 src/driver.h |7 +
 src/libvirt.c|   51 ++
 src/libvirt_public.syms  |5 
 5 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index ad6fcce..fc92143 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3600,6 +3600,11 @@ int virConnectSetKeepAlive(virConnectPtr conn,
int interval,
unsigned int count);
 
+int virDomainGetPcpusUsage(virDomainPtr dom,
+   unsigned long long *usages,
+   int *nr_usages,
+   unsigned int flags);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/python/generator.py b/python/generator.py
index 6fee3a4..0311004 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -421,6 +421,7 @@ skip_impl = (
 'virDomainGetBlockIoTune',
 'virDomainSetInterfaceParameters',
 'virDomainGetInterfaceParameters',
+'virDomainGetPcpusUsage', # not implemented yet
 )
 
 qemu_skip_impl = (
diff --git a/src/driver.h b/src/driver.h
index ec4abf3..2cf408a 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -793,6 +793,12 @@ typedef int
   int *nparams,
   unsigned int flags);
 
+typedef int
+(*virDrvDomainGetPcpusUsage)(virDomainPtr dom,
+ unsigned long long *usages,
+ int *nr_usages,
+ unsigned int flags);
+
 /**
  * _virDriver:
  *
@@ -961,6 +967,7 @@ struct _virDriver {
 virDrvNodeSuspendForDuration nodeSuspendForDuration;
 virDrvDomainSetBlockIoTune domainSetBlockIoTune;
 virDrvDomainGetBlockIoTune domainGetBlockIoTune;
+virDrvDomainGetPcpusUsage domainGetPcpusUsage;
 };
 
 typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index feb3ca6..79ff2df 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -17867,3 +17867,54 @@ error:
 virDispatchError(dom-conn);
 return -1;
 }
+
+/**
+ * virDomainGetPcpusUsage:
+ * @dom: pointer to domain object
+ * @usages: returned physic cpu usages
+ * @nr_usages: length of @usages
+ * @flags: flags to control the operation
+ *
+ * Get the cpu usages per every physic cpu
+ *
+ * Returns 0 if success, -1 on error
+ */
+int virDomainGetPcpusUsage(virDomainPtr dom,
+   unsigned long long *usages,
+   int *nr_usages,
+   unsigned int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(dom, usages=%p, nr_usages=%d, flags=%x,
+ usages, (nr_usages) ? *nr_usages : -1, flags);
+
+virResetLastError();
+
+if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+virDispatchError(NULL);
+return -1;
+}
+
+if (nr_usages == NULL  *nr_usages != 0) {
+virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+goto error;
+}
+
+conn = dom-conn;
+
+if (conn-driver-domainGetPcpusUsage) {
+int ret;
+ret = conn-driver-domainGetPcpusUsage(dom, usages, nr_usages, flags);
+if (ret  0)
+goto error;
+return ret;
+}
+
+virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+virDispatchError(dom-conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 4ca7216..15d944c 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -516,4 +516,9 @@ LIBVIRT_0.9.9 {
 virDomainSetNumaParameters;
 } LIBVIRT_0.9.8;
 
+LIBVIRT_0.9.10 {
+global:
+virDomainGetPcpusUsage;
+} LIBVIRT_0.9.9;
+
 #  define new API here using predicted next version number 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/4 V2] virsh: Enable the pcpuinfo command in virsh

2012-01-03 Thread Lai Jiangshan
This command gets information about the physic CPUs.
Example:

# virsh pcpuinfo rhel6
CPU:0
Curr VCPU:  -
Usage:  47.3

CPU:1
Curr VCPU:  1
Usage:  46.8

CPU:2
Curr VCPU:  0
Usage:  52.7

CPU:3
Curr VCPU:  -
Usage:  44.1


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |   93 +++
 tools/virsh.pod |5 +++
 2 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 0bc0519..f6fac24 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -4578,6 +4578,98 @@ cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * pcpuinfo command
+ */
+static const vshCmdInfo info_pcpuinfo[] = {
+{help, N_(detailed domain pcpu information)},
+{desc, N_(Returns basic information about the domain physic CPUs.)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_pcpuinfo[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{NULL, 0, 0, NULL}
+};
+
+static bool
+cmdPcpuinfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainInfo info;
+virDomainPtr dom;
+virNodeInfo nodeinfo;
+virVcpuInfoPtr cpuinfo;
+unsigned char *cpumaps;
+int ncpus, maxcpu;
+size_t cpumaplen;
+bool ret = true;
+int n, m;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (virNodeGetInfo(ctl-conn, nodeinfo) != 0) {
+virDomainFree(dom);
+return false;
+}
+
+if (virDomainGetInfo(dom, info) != 0) {
+virDomainFree(dom);
+return false;
+}
+
+cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
+maxcpu = VIR_NODEINFO_MAXCPUS(nodeinfo);
+cpumaplen = VIR_CPU_MAPLEN(maxcpu);
+cpumaps = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
+
+if ((ncpus = virDomainGetVcpus(dom,
+   cpuinfo, info.nrVirtCpu,
+   cpumaps, cpumaplen)) = 0) {
+unsigned long long *usages;
+int nr_usages = maxcpu;
+
+if (VIR_ALLOC_N(usages, nr_usages)  0) {
+virReportOOMError();
+goto fail;
+}
+
+if (virDomainGetPcpusUsage(dom, usages, nr_usages, 0)  0) {
+VIR_FREE(usages);
+goto fail;
+}
+
+for (n = 0; n  MIN(maxcpu, nr_usages); n++) {
+vshPrint(ctl, %-15s %d\n, _(CPU:), n);
+for (m = 0; m  ncpus; m++) {
+if (cpuinfo[m].cpu == n) {
+vshPrint(ctl, %-15s %d\n, _(Curr VCPU:), m);
+break;
+}
+}
+if (m == ncpus) {
+vshPrint(ctl, %-15s %s\n, _(Curr VCPU:), _(-));
+}
+vshPrint(ctl, %-15s %.1lf\n\n, _(Usage:),
+ usages[n] / 10.0);
+}
+VIR_FREE(usages);
+goto cleanup;
+}
+
+fail:
+ret = false;
+
+cleanup:
+VIR_FREE(cpumaps);
+VIR_FREE(cpuinfo);
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * vcpupin command
  */
 static const vshCmdInfo info_vcpupin[] = {
@@ -15813,6 +15905,7 @@ static const vshCmdDef domManagementCmds[] = {
 {migrate-getspeed, cmdMigrateGetMaxSpeed,
  opts_migrate_getspeed, info_migrate_getspeed, 0},
 {numatune, cmdNumatune, opts_numatune, info_numatune, 0},
+{pcpuinfo, cmdPcpuinfo, opts_pcpuinfo, info_pcpuinfo, 0},
 {reboot, cmdReboot, opts_reboot, info_reboot, 0},
 {reset, cmdReset, opts_reset, info_reset, 0},
 {restore, cmdRestore, opts_restore, info_restore, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 138f886..5a8b2e6 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1286,6 +1286,11 @@ Thus, this command always takes exactly zero or two 
flags.
 Returns basic information about the domain virtual CPUs, like the number of
 vCPUs, the running time, the affinity to physical processors.
 
+=item Bpcpuinfo Idomain-id
+
+Returns information about the physic CPUs of the domain, like the usage of
+CPUs, the current attached vCPUs.
+
 =item Bvcpupin Idomain-id [Ivcpu] [Icpulist] [[I--live]
 [I--config] | [I--current]]
 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/4 V2] remote: mplement new API virDomainGetPcpusUsage for remote driver

2012-01-03 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 daemon/remote.c  |   68 ++
 src/remote/remote_driver.c   |   51 +++
 src/remote/remote_protocol.x |   17 ++-
 src/remote_protocol-structs  |   13 
 4 files changed, 148 insertions(+), 1 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index a28a754..9b0206f 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -2084,6 +2084,74 @@ cleanup:
 return rv;
 }
 
+static int
+remoteDispatchDomainGetPcpusUsage(virNetServerPtr server ATTRIBUTE_UNUSED,
+  virNetServerClientPtr client 
ATTRIBUTE_UNUSED,
+  virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+  virNetMessageErrorPtr rerr,
+  remote_domain_get_pcpus_usage_args *args,
+  remote_domain_get_pcpus_usage_ret *ret)
+{
+int i;
+virDomainPtr dom = NULL;
+int rv = -1;
+unsigned long long *usages;
+int nr_usages = args-nr_usages;
+struct daemonClientPrivate *priv =
+virNetServerClientGetPrivateData(client);
+
+if (!priv-conn) {
+virNetError(VIR_ERR_INTERNAL_ERROR, %s, _(connection not open));
+goto cleanup;
+}
+
+if (nr_usages  REMOTE_DOMAIN_PCPUS_USAGE_PARAMETERS_MAX) {
+virNetError(VIR_ERR_INTERNAL_ERROR, %s, _(nr_usages too large));
+goto cleanup;
+}
+
+if (VIR_ALLOC_N(usages, nr_usages)  0) {
+virReportOOMError();
+goto cleanup;
+}
+
+if (!(dom = get_nonnull_domain(priv-conn, args-dom)))
+goto cleanup;
+
+if (virDomainGetPcpusUsage(dom, usages, nr_usages, args-flags)  0)
+goto cleanup;
+
+ret-nr_usages = nr_usages;
+
+/*
+ * In this case, we need to send back the number of parameters
+ * supported
+ */
+if (args-nr_usages == 0) {
+goto success;
+}
+
+ret-usages.usages_len = MIN(args-nr_usages, nr_usages);
+if (VIR_ALLOC_N(ret-usages.usages_val, ret-usages.usages_len)  0) {
+virReportOOMError();
+goto cleanup;
+}
+
+for (i = 0; i  ret-usages.usages_len; i++) {
+ret-usages.usages_val[i] = usages[i];
+}
+
+success:
+rv = 0;
+
+cleanup:
+if (rv  0)
+virNetMessageSaveError(rerr);
+VIR_FREE(usages);
+if (dom)
+virDomainFree(dom);
+return rv;
+}
 
 #ifdef HAVE_SASL
 /*
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 7580477..7dd3876 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2305,6 +2305,56 @@ done:
 return rv;
 }
 
+static int remoteDomainGetPcpusUsage(virDomainPtr domain,
+ unsigned long long *usages,
+ int *nr_usages,
+ unsigned int flags)
+{
+int i;
+int rv = -1;
+remote_domain_get_pcpus_usage_args args;
+remote_domain_get_pcpus_usage_ret ret;
+struct private_data *priv = domain-conn-privateData;
+
+remoteDriverLock(priv);
+
+make_nonnull_domain(args.dom, domain);
+args.nr_usages = *nr_usages;
+args.flags = flags;
+
+memset(ret, 0, sizeof(ret));
+
+if (call(domain-conn, priv, 0, REMOTE_PROC_DOMAIN_GET_PCPUS_USAGE,
+ (xdrproc_t) xdr_remote_domain_get_pcpus_usage_args,
+   (char *) args,
+ (xdrproc_t) xdr_remote_domain_get_pcpus_usage_ret,
+   (char *) ret) == -1) {
+goto done;
+}
+
+/* Handle the case when the caller does not know the number of parameters
+ * and is asking for the number of parameters supported
+ */
+if (*nr_usages == 0) {
+*nr_usages = ret.nr_usages;
+goto cleanup;
+}
+
+for (i = 0; i  MIN(*nr_usages, ret.usages.usages_len); i++) {
+usages[i] = ret.usages.usages_val[i];
+}
+*nr_usages = ret.nr_usages;
+
+rv = 0;
+
+cleanup:
+xdr_free ((xdrproc_t) xdr_remote_domain_get_pcpus_usage_ret,
+  (char *) ret);
+done:
+remoteDriverUnlock(priv);
+return rv;
+}
+
 /*--*/
 
 static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
@@ -4739,6 +4789,7 @@ static virDriver remote_driver = {
 .domainGetBlockIoTune = remoteDomainGetBlockIoTune, /* 0.9.8 */
 .domainSetNumaParameters = remoteDomainSetNumaParameters, /* 0.9.9 */
 .domainGetNumaParameters = remoteDomainGetNumaParameters, /* 0.9.9 */
+.domainGetPcpusUsage = remoteDomainGetPcpusUsage, /* 0.9.10 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index ca739ff..d38206d 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -131,6 +131,9 @@ const REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX = 16;
 /* Upper limit on list of numa

[libvirt] [PATCH 1/1 V2] ocaml-libvirt: and virDomainGetPcpusUsage() API to ocaml-libvirt

2012-01-03 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 libvirt/libvirt.ml  |1 +
 libvirt/libvirt.mli |4 
 libvirt/libvirt_c_oneoffs.c |   25 +
 3 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml
index fc29264..a8720a9 100644
--- a/libvirt/libvirt.ml
+++ b/libvirt/libvirt.ml
@@ -419,6 +419,7 @@ struct
   external set_vcpus : [`W] t - int - unit = 
ocaml_libvirt_domain_set_vcpus
   external pin_vcpu : [`W] t - int - string - unit = 
ocaml_libvirt_domain_pin_vcpu
   external get_vcpus : [`R] t - int - int - int * vcpu_info array * string 
= ocaml_libvirt_domain_get_vcpus
+  external get_pcpu_usages : [`R] t - int - int64 array = 
ocaml_libvirt_domain_get_pcpu_usages
   external get_max_vcpus : [`R] t - int = 
ocaml_libvirt_domain_get_max_vcpus
   external attach_device : [`W] t - xml - unit = 
ocaml_libvirt_domain_attach_device
   external detach_device : [`W] t - xml - unit = 
ocaml_libvirt_domain_detach_device
diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli
index 7bda889..63bf830 100644
--- a/libvirt/libvirt.mli
+++ b/libvirt/libvirt.mli
@@ -586,6 +586,10 @@ sig
for a domain.  See the libvirt documentation for details
of the array and bitmap returned from this function.
 *)
+  val get_pcpu_usages : [`R] t - int - int64 array
+(** [get_pcpu_usages dom nr_pcpu] returns the physic CPU usages
+   for a domain.  See the libvirt documentation for details.
+*)
   val get_max_vcpus : [`R] t - int
 (** Returns the maximum number of vCPUs supported for this domain. *)
   val attach_device : [`W] t - xml - unit
diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c
index d87dd21..68d5ecc 100644
--- a/libvirt/libvirt_c_oneoffs.c
+++ b/libvirt/libvirt_c_oneoffs.c
@@ -604,6 +604,31 @@ ocaml_libvirt_domain_get_vcpus (value domv, value 
maxinfov, value maplenv)
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_libvirt_domain_get_pcpu_usages (value domv, value nr_pcpusv)
+{
+  CAMLparam2 (domv, nr_pcpusv);
+  CAMLlocal1 (usagev);
+  virDomainPtr dom = Domain_val (domv);
+  virConnectPtr conn = Connect_domv (domv);
+  int nr_pcpus = Int_val (nr_pcpusv);
+  unsigned long long pcpu_usages[nr_pcpus];
+  int r, i;
+
+  memset (pcpu_usages, 0, sizeof(pcpu_usages[0]) * nr_pcpus);
+
+  NONBLOCKING (r = virDomainGetPcpusUsage (dom, pcpu_usages, nr_pcpus, 0));
+  CHECK_ERROR (r == -1, conn, virDomainGetPcpusUsage);
+
+  /* Copy the pcpu_usages. */
+  usagev = caml_alloc (nr_pcpus, 0);
+  for (i = 0; i  nr_pcpus; ++i) {
+Store_field (usagev, i, caml_copy_int64 ((int64_t)pcpu_usages[i]));
+  }
+
+  CAMLreturn (usagev);
+}
+
 #ifdef HAVE_WEAK_SYMBOLS
 #ifdef HAVE_VIRDOMAINMIGRATE
 extern virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 0/4 0/1 0/1 V2] Add new public API virDomainGetPcpusUsage() and pcpuinfo command in virsh

2012-01-03 Thread Lai Jiangshan
virt-top -1 can call virDomainGetPcpusUsage() periodically and get
the CPU activities per CPU. (See the last patch in this series).

virsh is also added a pcpuinfo command which calls virDomainGetPcpusUsage(),
it gets information about the physic CPUs, such as the usage of
CPUs, the current attached vCPUs.

# virsh pcpuinfo rhel6
CPU:0
Curr VCPU:  -
Usage:  47.3

CPU:1
Curr VCPU:  1
Usage:  46.8

CPU:2
Curr VCPU:  0
Usage:  52.7

CPU:3
Curr VCPU:  -
Usage:  44.1



Patch for libvirt(4 patches):

 daemon/remote.c  |   68 ++
 include/libvirt/libvirt.h.in |5 ++
 python/generator.py  |1 +
 src/driver.h |7 +++
 src/libvirt.c|   51 +++
 src/libvirt_public.syms  |5 ++
 src/qemu/qemu.conf   |5 +-
 src/qemu/qemu_conf.c |3 +-
 src/qemu/qemu_driver.c   |   74 +
 src/remote/remote_driver.c   |   51 +++
 src/remote/remote_protocol.x |   17 +++-
 src/remote_protocol-structs  |   13 ++
 src/util/cgroup.c|7 +++
 src/util/cgroup.h|1 +
 tools/virsh.c|   93 ++
 tools/virsh.pod  |5 ++
 16 files changed, 402 insertions(+), 4 deletions(-)

Patch for ocaml-libvirt (1 patch):

 libvirt/libvirt.ml  |1 +
 libvirt/libvirt.mli |4 
 libvirt/libvirt_c_oneoffs.c |   25 +
 3 files changed, 30 insertions(+), 0 deletions(-)

Patch for virt-top (1 patch):

 virt-top/virt_top.ml |   75 +
 1 files changed, 26 insertions(+), 49 deletions(-)

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 3/4 V2] qemu: implement new API virDomainGetPcpusUsage for qemu driver

2012-01-03 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu.conf |5 ++-
 src/qemu/qemu_conf.c   |3 +-
 src/qemu/qemu_driver.c |   74 
 src/util/cgroup.c  |7 
 src/util/cgroup.h  |1 +
 5 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 4ec5e6c..5f75b3e 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -158,18 +158,19 @@
 #  - 'memory' - use for memory tunables
 #  - 'blkio' - use for block devices I/O tunables
 #  - 'cpuset' - use for CPUs and memory nodes
+#  - 'cpuacct' - use for CPUs' account
 #
 # NB, even if configured here, they won't be used unless
 # the administrator has mounted cgroups, e.g.:
 #
 #  mkdir /dev/cgroup
-#  mount -t cgroup -o devices,cpu,memory,blkio,cpuset none /dev/cgroup
+#  mount -t cgroup -o devices,cpu,memory,blkio,cpuset,cpuacct none /dev/cgroup
 #
 # They can be mounted anywhere, and different controllers
 # can be mounted in different locations. libvirt will detect
 # where they are located.
 #
-# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset ]
+# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset, 
cpuacct ]
 
 # This is the basic set of devices allowed / required by
 # all virtual machines.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index bc0a646..4775638 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -307,7 +307,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 (1  VIR_CGROUP_CONTROLLER_DEVICES) |
 (1  VIR_CGROUP_CONTROLLER_MEMORY) |
 (1  VIR_CGROUP_CONTROLLER_BLKIO) |
-(1  VIR_CGROUP_CONTROLLER_CPUSET);
+(1  VIR_CGROUP_CONTROLLER_CPUSET) |
+(1  VIR_CGROUP_CONTROLLER_CPUACCT);
 }
 for (i = 0 ; i  VIR_CGROUP_CONTROLLER_LAST ; i++) {
 if (driver-cgroupControllers  (1  i)) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 82bab67..3d023eb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11194,6 +11194,79 @@ cleanup:
 return ret;
 }
 
+static int
+qemuGetPcpusUsage(virDomainPtr dom,
+  unsigned long long *usages,
+  int *nr_usages,
+  unsigned int flags)
+{
+struct qemud_driver *driver = dom-conn-privateData;
+virCgroupPtr group = NULL;
+virDomainObjPtr vm = NULL;
+char *pos, *raw;
+unsigned long long val;
+int nr_cpus = 0;
+int ret = -1;
+int rc;
+bool isActive;
+
+virCheckFlags(0, -1);
+
+qemuDriverLock(driver);
+
+vm = virDomainFindByUUID(driver-domains, dom-uuid);
+
+if (vm == NULL) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(No such domain %s), dom-uuid);
+goto cleanup;
+}
+
+isActive = virDomainObjIsActive(vm);
+
+if (!isActive) {
+qemuReportError(VIR_ERR_OPERATION_INVALID, %s,
+_(domain is not running));
+goto cleanup;
+}
+
+if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID,
+%s, _(cgroup CPUACCT controller is not mounted));
+goto cleanup;
+}
+
+if (virCgroupForDomain(driver-cgroup, vm-def-name, group, 0) != 0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(cannot find cgroup for domain %s), vm-def-name);
+goto cleanup;
+}
+
+rc = virCgroupGetCpuacctPcpusUsage(group, raw);
+if (rc != 0) {
+virReportSystemError(-rc, %s, _(unable to get cpu account));
+goto cleanup;
+}
+
+pos = raw;
+while (virStrToLong_ull(pos, pos, 10, val) = 0) {
+if (nr_cpus  *nr_usages) {
+usages[nr_cpus] = val;
+}
+nr_cpus++;
+}
+
+VIR_FREE(raw);
+*nr_usages = nr_cpus;
+ret = 0;
+
+cleanup:
+virCgroupFree(group);
+if (vm)
+virDomainObjUnlock(vm);
+qemuDriverUnlock(driver);
+return ret;
+}
 
 static virDomainPtr qemuDomainAttach(virConnectPtr conn,
  unsigned int pid,
@@ -11997,6 +12070,7 @@ static virDriver qemuDriver = {
 .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
 .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 
*/
 .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 
*/
+.domainGetPcpusUsage = qemuGetPcpusUsage, /* 0.9.10 */
 };
 
 
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index 25f2691..114eeb5 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -1554,6 +1554,13 @@ int virCgroupGetCpuacctUsage(virCgroupPtr group, 
unsigned long long *usage)
 cpuacct.usage, usage);
 }
 
+int virCgroupGetCpuacctPcpusUsage(virCgroupPtr group, char **usage)
+{
+return virCgroupGetValueStr(group

[libvirt] [PATCH 1/1 V2] virt-top: correct virt-top -1 command via cpuacct cgroup

2012-01-03 Thread Lai Jiangshan
Old virt-top -1 is not correct, its output is generated by guess:
use average usage for pinned physic CPUs.

example(old virt-top -1):

PHYCPU %CPU rhel6  Windows  
  
   00.6  0.1=   0.5=
   10.6  0.1=   0.5=#
   20.6  0.1=   0.5=
   30.6  0.1=#  0.5=

The output almost makes no sense(all the value are just average, not real).

This is new implement, it use cpuacct cgroup to gain *real* physic usages
via cpuacct cgroup by virDomainGetPcpusUsage() API.

new result:

PHYCPU %CPU rhel6  Windows  

   03.3  2.90.3
   11.7  1.10.6
   23.5  1.81.6
   33.4  1.61.8

PHYCPU %CPU rhel6  Windows  

   01.2  0.80.4
   11.6 1.6
   22.2  1.70.5
   33.0  2.50.5


Note: average flag(=) is dropped, there is not average value in here.
Note: running flag(#) is dropped, because if the value is not empty,
  it means the guest was once running in the physic CPU in this period
  between updates.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 virt-top/virt_top.ml |   75 +
 1 files changed, 26 insertions(+), 49 deletions(-)

diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml
index ef5ac67..2556b77 100644
--- a/virt-top/virt_top.ml
+++ b/virt-top/virt_top.ml
@@ -446,14 +446,14 @@ let collect, clear_pcpu_display_data =
   let last_info = Hashtbl.create 13 in
   let last_time = ref (Unix.gettimeofday ()) in
 
-  (* Save vcpuinfo structures across redraws too (only for pCPU display). *)
-  let last_vcpu_info = Hashtbl.create 13 in
+  (* Save pcpu_usages structures across redraws too (only for pCPU display). *)
+  let last_pcpu_usages = Hashtbl.create 13 in
 
   let clear_pcpu_display_data () =
-(* Clear out vcpu_info used by PCPUDisplay display_mode
+(* Clear out pcpu_info used by PCPUDisplay display_mode
  * when we switch back to TaskDisplay mode.
  *)
-Hashtbl.clear last_vcpu_info
+Hashtbl.clear last_pcpu_usages
   in
 
   let collect (conn, _, _, _, _, node_info, _, _) =
@@ -652,22 +652,23 @@ let collect, clear_pcpu_display_data =
  (try
 let domid = rd.rd_domid in
 let maplen = C.cpumaplen nr_pcpus in
+let pcpu_usages = D.get_pcpu_usages rd.rd_dom nr_pcpus in
 let maxinfo = rd.rd_info.D.nr_virt_cpu in
 let nr_vcpus, vcpu_infos, cpumaps =
   D.get_vcpus rd.rd_dom maxinfo maplen in
 
-(* Got previous vcpu_infos for this domain? *)
-let prev_vcpu_infos =
-  try Some (Hashtbl.find last_vcpu_info domid)
+(* Got previous pcpu_usages for this domain? *)
+let prev_pcpu_usages =
+  try Some (Hashtbl.find last_pcpu_usages domid)
   with Not_found - None in
-(* Update last_vcpu_info. *)
-Hashtbl.replace last_vcpu_info domid vcpu_infos;
-
-(match prev_vcpu_infos with
- | Some prev_vcpu_infos
- when Array.length prev_vcpu_infos = Array.length 
vcpu_infos -
- Some (domid, name, nr_vcpus, vcpu_infos, prev_vcpu_infos,
-   cpumaps, maplen)
+(* Update last_pcpu_usages. *)
+Hashtbl.replace last_pcpu_usages domid pcpu_usages;
+
+(match prev_pcpu_usages with
+ | Some prev_pcpu_usages
+ when Array.length prev_pcpu_usages = Array.length 
pcpu_usages -
+ Some (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
+   prev_pcpu_usages, cpumaps, maplen)
  | _ - None (* ignore missing / unequal length 
prev_vcpu_infos *)
 );
   with
@@ -680,37 +681,15 @@ let collect, clear_pcpu_display_data =
(* Rearrange the data into a matrix.  Major axis (down) is
 * pCPUs.  Minor axis (right) is domains.  At each node we store:
 *  cpu_time (on this pCPU only, nanosecs),
-*  average? (if set, then cpu_time is an average because the
-* vCPU is pinned to more than one pCPU)
-*  running? (if set, we were instantaneously running on this pCPU)
 *)
-   let empty_node = (0L, false, false) in
-   let pcpus = Array.make_matrix nr_pcpus nr_doms empty_node in
+   let pcpus = Array.make_matrix nr_pcpus nr_doms 0L in
 
List.iteri (
- fun di (domid, name, nr_vcpus, vcpu_infos, prev_vcpu_infos,
- cpumaps, maplen) -
+ fun di (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
+ prev_pcpu_usages, cpumaps, maplen) -
(* Which pCPUs can this dom run

[libvirt] [PATCH] virsh: move version command to virsh group

2011-12-27 Thread Lai Jiangshan
Trivial patch, move version command to virsh commands group.

It has no any related with any domain.

It may connect to the daemon, so the flag is 0 but not VSH_CMD_FLAG_NOCONNECT.

---
diff --git a/tools/virsh.c b/tools/virsh.c
index 02f2e0d..0166bc6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -15641,7 +15641,6 @@ static const vshCmdDef domManagementCmds[] = {
 {vcpucount, cmdVcpucount, opts_vcpucount, info_vcpucount, 0},
 {vcpuinfo, cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0},
 {vcpupin, cmdVcpuPin, opts_vcpupin, info_vcpupin, 0},
-{version, cmdVersion, opts_version, info_version, 0},
 {vncdisplay, cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0},
 {NULL, NULL, NULL, NULL, 0}
 };
@@ -15810,6 +15809,7 @@ static const vshCmdDef secretCmds[] = {
 };
 
 static const vshCmdDef virshCmds[] = {
+{version, cmdVersion, opts_version, info_version, 0},
 {cd, cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT},
 {echo, cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT},
 {exit, cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT},

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 0/4] Add new public API virDomainGetPcpusUsage and pcpuinfo command in virsh

2011-12-15 Thread Lai Jiangshan
Hi, Eric

On 12/08/2011 11:44 AM, Eric Blake wrote:
 On 12/07/2011 08:40 PM, Lai Jiangshan wrote:
 virt-top -1 can call virDomainGetPcpusUsage() periodically and get
 the CPU activities per CPU. (still require virt-top site patch).

 virsh is also added a pcpuinfo command which calls virDomainGetPcpusUsage(),
 it gets information about the physic CPUs, such as the usage of
 CPUs, the current attached vCPUs.
 
 Meta-question - is this the time taken _by just the guest in question_
 on the host's physical CPU, or is it the cumulative CPU time taken by
 all process on the physical CPU, in which case this would be better
 named as virNodeGetCpusUsage()?  


It's per-domain usage.


 And if it is per-domain, then what's
 the difference between physical cpu usage and virtual cpu usage 

the API tell us how many cpu utilization the whole guest occupies for
every physic CPUs. I don't know what is virtual cpu usage means.

 (that
 is, can we even tell the overhead of the hypervisor, and should we be
 exposing that overhead to the user)?
 

it is not exposed to the normal user.

the administrator can use virt-top -1 or virsh pcpuinfo to get cpus
usage, to find out which physic cpu is busy, to change the cpu bound of (new) 
guests,
to find a proper physic cpu and offline it, or to do nothing, just to observe 
the stat of the guests.

I/(I will) very appreciate for your reply.

Thanks,
Lai

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 0/4] Add new public API virDomainGetPcpusUsage and pcpuinfo command in virsh

2011-12-08 Thread Lai Jiangshan
On 12/08/2011 11:44 AM, Eric Blake wrote:
 On 12/07/2011 08:40 PM, Lai Jiangshan wrote:
 virt-top -1 can call virDomainGetPcpusUsage() periodically and get
 the CPU activities per CPU. (still require virt-top site patch).

 virsh is also added a pcpuinfo command which calls virDomainGetPcpusUsage(),
 it gets information about the physic CPUs, such as the usage of
 CPUs, the current attached vCPUs.
 
 Meta-question - is this the time taken _by just the guest in question_
 on the host's physical CPU, or is it the cumulative CPU time taken by

The time is used by the guest in question on the host's physical CPUs.
per-domain and per physical CPU

 all process on the physical CPU, in which case this would be better
 named as virNodeGetCpusUsage()?  And if it is per-domain, then what's
 the difference between physical cpu usage and virtual cpu usage (that
 is, can we even tell the overhead of the hypervisor, and should we be
 exposing that overhead to the user)?
 

I did not catch your mean, could you explain more?

Thanks,
Lai

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/4] remote: implement new API virDomainGetPcpusUsage for remote driver

2011-12-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 daemon/remote.c  |   68 ++
 src/remote/remote_driver.c   |   51 +++
 src/remote/remote_protocol.x |   17 ++-
 src/remote_protocol-structs  |   13 
 4 files changed, 148 insertions(+), 1 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index e1d208c..c154892 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -2022,6 +2022,74 @@ cleanup:
 return rv;
 }
 
+static int
+remoteDispatchDomainGetPcpusUsage(virNetServerPtr server ATTRIBUTE_UNUSED,
+  virNetServerClientPtr client 
ATTRIBUTE_UNUSED,
+  virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+  virNetMessageErrorPtr rerr,
+  remote_domain_get_pcpus_usage_args *args,
+  remote_domain_get_pcpus_usage_ret *ret)
+{
+int i;
+virDomainPtr dom = NULL;
+int rv = -1;
+unsigned long long *usages;
+int nr_usages = args-nr_usages;
+struct daemonClientPrivate *priv =
+virNetServerClientGetPrivateData(client);
+
+if (!priv-conn) {
+virNetError(VIR_ERR_INTERNAL_ERROR, %s, _(connection not open));
+goto cleanup;
+}
+
+if (nr_usages  REMOTE_DOMAIN_PCPUS_USAGE_PARAMETERS_MAX) {
+virNetError(VIR_ERR_INTERNAL_ERROR, %s, _(nr_usages too large));
+goto cleanup;
+}
+
+if (VIR_ALLOC_N(usages, nr_usages)  0) {
+virReportOOMError();
+goto cleanup;
+}
+
+if (!(dom = get_nonnull_domain(priv-conn, args-dom)))
+goto cleanup;
+
+if (virDomainGetPcpusUsage(dom, usages, nr_usages, args-flags)  0)
+goto cleanup;
+
+ret-nr_usages = nr_usages;
+
+/*
+ * In this case, we need to send back the number of parameters
+ * supported
+ */
+if (args-nr_usages == 0) {
+goto success;
+}
+
+ret-usages.usages_len = MIN(args-nr_usages, nr_usages);
+if (VIR_ALLOC_N(ret-usages.usages_val, ret-usages.usages_len)  0) {
+virReportOOMError();
+goto cleanup;
+}
+
+for (i = 0; i  ret-usages.usages_len; i++) {
+ret-usages.usages_val[i] = usages[i];
+}
+
+success:
+rv = 0;
+
+cleanup:
+if (rv  0)
+virNetMessageSaveError(rerr);
+VIR_FREE(usages);
+if (dom)
+virDomainFree(dom);
+return rv;
+}
 
 #ifdef HAVE_SASL
 /*
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 556c90c..1a4c129 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2255,6 +2255,56 @@ done:
 return rv;
 }
 
+static int remoteDomainGetPcpusUsage(virDomainPtr domain,
+ unsigned long long *usages,
+ int *nr_usages,
+ unsigned int flags)
+{
+int i;
+int rv = -1;
+remote_domain_get_pcpus_usage_args args;
+remote_domain_get_pcpus_usage_ret ret;
+struct private_data *priv = domain-conn-privateData;
+
+remoteDriverLock(priv);
+
+make_nonnull_domain(args.dom, domain);
+args.nr_usages = *nr_usages;
+args.flags = flags;
+
+memset(ret, 0, sizeof(ret));
+
+if (call(domain-conn, priv, 0, REMOTE_PROC_DOMAIN_GET_PCPUS_USAGE,
+ (xdrproc_t) xdr_remote_domain_get_pcpus_usage_args,
+   (char *) args,
+ (xdrproc_t) xdr_remote_domain_get_pcpus_usage_ret,
+   (char *) ret) == -1) {
+goto done;
+}
+
+/* Handle the case when the caller does not know the number of parameters
+ * and is asking for the number of parameters supported
+ */
+if (*nr_usages == 0) {
+*nr_usages = ret.nr_usages;
+goto cleanup;
+}
+
+for (i = 0; i  MIN(*nr_usages, ret.usages.usages_len); i++) {
+usages[i] = ret.usages.usages_val[i];
+}
+*nr_usages = ret.nr_usages;
+
+rv = 0;
+
+cleanup:
+xdr_free ((xdrproc_t) xdr_remote_domain_get_pcpus_usage_ret,
+  (char *) ret);
+done:
+remoteDriverUnlock(priv);
+return rv;
+}
+
 /*--*/
 
 static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
@@ -4677,6 +4727,7 @@ static virDriver remote_driver = {
 .nodeSuspendForDuration = remoteNodeSuspendForDuration, /* 0.9.8 */
 .domainSetBlockIoTune = remoteDomainSetBlockIoTune, /* 0.9.8 */
 .domainGetBlockIoTune = remoteDomainGetBlockIoTune, /* 0.9.8 */
+.domainGetPcpusUsage = remoteDomainGetPcpusUsage, /* 0.9.9 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 509a20b..e6b38ac 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -128,6 +128,9 @@ const REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX = 16;
 /* Upper limit on list of blockio tuning parameters

[libvirt] [PATCH 0/4] Add new public API virDomainGetPcpusUsage and pcpuinfo command in virsh

2011-12-07 Thread Lai Jiangshan
virt-top -1 can call virDomainGetPcpusUsage() periodically and get
the CPU activities per CPU. (still require virt-top site patch).

virsh is also added a pcpuinfo command which calls virDomainGetPcpusUsage(),
it gets information about the physic CPUs, such as the usage of
CPUs, the current attached vCPUs.

# virsh pcpuinfo rhel6
CPU:0
Curr VCPU:  -
Usage:  47.3

CPU:1
Curr VCPU:  1
Usage:  46.8

CPU:2
Curr VCPU:  0
Usage:  52.7

CPU:3
Curr VCPU:  -
Usage:  44.1

Lai Jiangshan (4):
  Add new public API virDomainGetPcpusUsage
  remote: support new API virDomainGetPcpusUsage for remote driver
  qemu: implemnt new API virDomainGetPcpusUsage for qemu driver
  Enable the pcpuinfo command in virsh

 daemon/remote.c  |   68 ++
 include/libvirt/libvirt.h.in |5 ++
 python/generator.py  |1 +
 src/driver.h |7 +++
 src/libvirt.c|   51 +++
 src/libvirt_public.syms  |5 ++
 src/qemu/qemu.conf   |5 +-
 src/qemu/qemu_conf.c |3 +-
 src/qemu/qemu_driver.c   |   74 +
 src/remote/remote_driver.c   |   51 +++
 src/remote/remote_protocol.x |   17 +++-
 src/remote_protocol-structs  |   13 ++
 src/util/cgroup.c|7 +++
 src/util/cgroup.h|1 +
 tools/virsh.c|   93 ++
 tools/virsh.pod  |5 ++
 16 files changed, 402 insertions(+), 4 deletions(-)

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 3/4] qemu: implement new API virDomainGetPcpusUsage for qemu driver

2011-12-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu.conf |5 ++-
 src/qemu/qemu_conf.c   |3 +-
 src/qemu/qemu_driver.c |   74 
 src/util/cgroup.c  |7 
 src/util/cgroup.h  |1 +
 5 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index c3f264f..beb0123 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -158,18 +158,19 @@
 #  - 'memory' - use for memory tunables
 #  - 'blkio' - use for block devices I/O tunables
 #  - 'cpuset' - use for CPUs and memory nodes
+#  - 'cpuacct' - use for CPUs' account
 #
 # NB, even if configured here, they won't be used unless
 # the administrator has mounted cgroups, e.g.:
 #
 #  mkdir /dev/cgroup
-#  mount -t cgroup -o devices,cpu,memory,blkio,cpuset none /dev/cgroup
+#  mount -t cgroup -o devices,cpu,memory,blkio,cpuset,cpuacct none /dev/cgroup
 #
 # They can be mounted anywhere, and different controllers
 # can be mounted in different locations. libvirt will detect
 # where they are located.
 #
-# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset ]
+# cgroup_controllers = [ cpu, devices, memory, blkio, cpuset, 
cpuacct ]
 
 # This is the basic set of devices allowed / required by
 # all virtual machines.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 3766119..bf8d77a 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -307,7 +307,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 (1  VIR_CGROUP_CONTROLLER_DEVICES) |
 (1  VIR_CGROUP_CONTROLLER_MEMORY) |
 (1  VIR_CGROUP_CONTROLLER_BLKIO) |
-(1  VIR_CGROUP_CONTROLLER_CPUSET);
+(1  VIR_CGROUP_CONTROLLER_CPUSET) |
+(1  VIR_CGROUP_CONTROLLER_CPUACCT);
 }
 for (i = 0 ; i  VIR_CGROUP_CONTROLLER_LAST ; i++) {
 if (driver-cgroupControllers  (1  i)) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ed90c66..648910e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10748,6 +10748,79 @@ cleanup:
 return ret;
 }
 
+static int
+qemuGetPcpusUsage(virDomainPtr dom,
+  unsigned long long *usages,
+  int *nr_usages,
+  unsigned int flags)
+{
+struct qemud_driver *driver = dom-conn-privateData;
+virCgroupPtr group = NULL;
+virDomainObjPtr vm = NULL;
+char *pos, *raw;
+unsigned long long val;
+int nr_cpus = 0;
+int ret = -1;
+int rc;
+bool isActive;
+
+virCheckFlags(0, -1);
+
+qemuDriverLock(driver);
+
+vm = virDomainFindByUUID(driver-domains, dom-uuid);
+
+if (vm == NULL) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(No such domain %s), dom-uuid);
+goto cleanup;
+}
+
+isActive = virDomainObjIsActive(vm);
+
+if (!isActive) {
+qemuReportError(VIR_ERR_OPERATION_INVALID, %s,
+_(domain is not running));
+goto cleanup;
+}
+
+if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID,
+%s, _(cgroup CPUACCT controller is not mounted));
+goto cleanup;
+}
+
+if (virCgroupForDomain(driver-cgroup, vm-def-name, group, 0) != 0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+_(cannot find cgroup for domain %s), vm-def-name);
+goto cleanup;
+}
+
+rc = virCgroupGetCpuacctPcpusUsage(group, raw);
+if (rc != 0) {
+virReportSystemError(-rc, %s, _(unable to get cpu account));
+goto cleanup;
+}
+
+pos = raw;
+while (virStrToLong_ull(pos, pos, 10, val) = 0) {
+if (nr_cpus  *nr_usages) {
+usages[nr_cpus] = val;
+}
+nr_cpus++;
+}
+
+VIR_FREE(raw);
+*nr_usages = nr_cpus;
+ret = 0;
+
+cleanup:
+virCgroupFree(group);
+if (vm)
+virDomainObjUnlock(vm);
+qemuDriverUnlock(driver);
+return ret;
+}
 
 static virDomainPtr qemuDomainAttach(virConnectPtr conn,
  unsigned int pid,
@@ -11589,6 +11662,7 @@ static virDriver qemuDriver = {
 .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
 .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
 .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
+.domainGetPcpusUsage = qemuGetPcpusUsage, /* 0.9.9 */
 };
 
 
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index b4d3d8b..3d281f9 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -1522,6 +1522,13 @@ int virCgroupGetCpuacctUsage(virCgroupPtr group, 
unsigned long long *usage)
 cpuacct.usage, usage);
 }
 
+int virCgroupGetCpuacctPcpusUsage(virCgroupPtr group, char **usage)
+{
+return virCgroupGetValueStr(group,
+VIR_CGROUP_CONTROLLER_CPUACCT

[libvirt] [PATCH 4/4] Enable the pcpuinfo command in virsh

2011-12-07 Thread Lai Jiangshan
This command gets information about the physic CPUs.
Example:

# virsh pcpuinfo rhel6
CPU:0
Curr VCPU:  -
Usage:  47.3

CPU:1
Curr VCPU:  1
Usage:  46.8

CPU:2
Curr VCPU:  0
Usage:  52.7

CPU:3
Curr VCPU:  -
Usage:  44.1


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |   93 +++
 tools/virsh.pod |5 +++
 2 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 0fccf88..4a3833c 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -4012,6 +4012,98 @@ cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * pcpuinfo command
+ */
+static const vshCmdInfo info_pcpuinfo[] = {
+{help, N_(detailed domain pcpu information)},
+{desc, N_(Returns basic information about the domain physic CPUs.)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_pcpuinfo[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{NULL, 0, 0, NULL}
+};
+
+static bool
+cmdPcpuinfo(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainInfo info;
+virDomainPtr dom;
+virNodeInfo nodeinfo;
+virVcpuInfoPtr cpuinfo;
+unsigned char *cpumaps;
+int ncpus, maxcpu;
+size_t cpumaplen;
+bool ret = true;
+int n, m;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (virNodeGetInfo(ctl-conn, nodeinfo) != 0) {
+virDomainFree(dom);
+return false;
+}
+
+if (virDomainGetInfo(dom, info) != 0) {
+virDomainFree(dom);
+return false;
+}
+
+cpuinfo = vshMalloc(ctl, sizeof(virVcpuInfo)*info.nrVirtCpu);
+maxcpu = VIR_NODEINFO_MAXCPUS(nodeinfo);
+cpumaplen = VIR_CPU_MAPLEN(maxcpu);
+cpumaps = vshMalloc(ctl, info.nrVirtCpu * cpumaplen);
+
+if ((ncpus = virDomainGetVcpus(dom,
+   cpuinfo, info.nrVirtCpu,
+   cpumaps, cpumaplen)) = 0) {
+unsigned long long *usages;
+int nr_usages = maxcpu;
+
+if (VIR_ALLOC_N(usages, nr_usages)  0) {
+virReportOOMError();
+goto fail;
+}
+
+if (virDomainGetPcpusUsage(dom, usages, nr_usages, 0)  0) {
+VIR_FREE(usages);
+goto fail;
+}
+
+for (n = 0; n  MIN(maxcpu, nr_usages); n++) {
+vshPrint(ctl, %-15s %d\n, _(CPU:), n);
+for (m = 0; m  ncpus; m++) {
+if (cpuinfo[m].cpu == n) {
+vshPrint(ctl, %-15s %d\n, _(Curr VCPU:), m);
+break;
+}
+}
+if (m == ncpus) {
+vshPrint(ctl, %-15s %s\n, _(Curr VCPU:), _(-));
+}
+vshPrint(ctl, %-15s %.1lf\n\n, _(Usage:),
+ usages[n] / 10.0);
+}
+VIR_FREE(usages);
+goto cleanup;
+}
+
+fail:
+ret = false;
+
+cleanup:
+VIR_FREE(cpumaps);
+VIR_FREE(cpuinfo);
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * vcpupin command
  */
 static const vshCmdInfo info_vcpupin[] = {
@@ -15130,6 +15222,7 @@ static const vshCmdDef domManagementCmds[] = {
  opts_migrate_setspeed, info_migrate_setspeed, 0},
 {migrate-getspeed, cmdMigrateGetMaxSpeed,
  opts_migrate_getspeed, info_migrate_getspeed, 0},
+{pcpuinfo, cmdPcpuinfo, opts_pcpuinfo, info_pcpuinfo, 0},
 {reboot, cmdReboot, opts_reboot, info_reboot, 0},
 {reset, cmdReset, opts_reset, info_reset, 0},
 {restore, cmdRestore, opts_restore, info_restore, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 5131ade..241e0dc 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1217,6 +1217,11 @@ Thus, this command always takes exactly zero or two 
flags.
 Returns basic information about the domain virtual CPUs, like the number of
 vCPUs, the running time, the affinity to physical processors.
 
+=item Bpcpuinfo Idomain-id
+
+Returns information about the physic CPUs of the domain, like the usage of
+CPUs, the current attached vCPUs.
+
 =item Bvcpupin Idomain-id [Ivcpu] [Icpulist] [[I--live]
 [I--config] | [I--current]]
 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 1/4] Add new public API virDomainGetPcpusUsage

2011-12-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in |5 
 python/generator.py  |1 +
 src/driver.h |7 +
 src/libvirt.c|   51 ++
 src/libvirt_public.syms  |5 
 5 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index d01d1bc..2ec6b6b 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3487,6 +3487,11 @@ int virConnectSetKeepAlive(virConnectPtr conn,
int interval,
unsigned int count);
 
+int virDomainGetPcpusUsage(virDomainPtr dom,
+   unsigned long long *usages,
+   int *nr_usages,
+   unsigned int flags);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/python/generator.py b/python/generator.py
index 88c52b9..a39244f 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -416,6 +416,7 @@ skip_impl = (
 'virDomainBlockStatsFlags',
 'virDomainSetBlockIoTune',
 'virDomainGetBlockIoTune',
+'virDomainGetPcpusUsage', # not implemented yet
 )
 
 qemu_skip_impl = (
diff --git a/src/driver.h b/src/driver.h
index 941ff51..3d54370 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -770,6 +770,12 @@ typedef int
   int *nparams,
   unsigned int flags);
 
+typedef int
+(*virDrvDomainGetPcpusUsage)(virDomainPtr dom,
+ unsigned long long *usages,
+ int *nr_usages,
+ unsigned int flags);
+
 /**
  * _virDriver:
  *
@@ -934,6 +940,7 @@ struct _virDriver {
 virDrvNodeSuspendForDuration nodeSuspendForDuration;
 virDrvDomainSetBlockIoTune domainSetBlockIoTune;
 virDrvDomainGetBlockIoTune domainGetBlockIoTune;
+virDrvDomainGetPcpusUsage domainGetPcpusUsage;
 };
 
 typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index 68074e7..06a019c 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -17599,3 +17599,54 @@ error:
 virDispatchError(dom-conn);
 return -1;
 }
+
+/**
+ * virDomainGetPcpusUsage:
+ * @dom: pointer to domain object
+ * @usages: returned physic cpu usages
+ * @nr_usages: length of @usages
+ * @flags: flags to control the operation
+ *
+ * Get the cpu usages per every physic cpu
+ *
+ * Returns 0 if success, -1 on error
+ */
+int virDomainGetPcpusUsage(virDomainPtr dom,
+   unsigned long long *usages,
+   int *nr_usages,
+   unsigned int flags)
+{
+virConnectPtr conn;
+
+VIR_DOMAIN_DEBUG(dom, usages=%p, nr_usages=%d, flags=%x,
+ usages, (nr_usages) ? *nr_usages : -1, flags);
+
+virResetLastError();
+
+if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+virDispatchError(NULL);
+return -1;
+}
+
+if (nr_usages == NULL  *nr_usages != 0) {
+virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+goto error;
+}
+
+conn = dom-conn;
+
+if (conn-driver-domainGetPcpusUsage) {
+int ret;
+ret = conn-driver-domainGetPcpusUsage(dom, usages, nr_usages, flags);
+if (ret  0)
+goto error;
+return ret;
+}
+
+virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+virDispatchError(dom-conn);
+return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 164039a..05f8d9e 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -508,4 +508,9 @@ LIBVIRT_0.9.8 {
 virNodeSuspendForDuration;
 } LIBVIRT_0.9.7;
 
+LIBVIRT_0.9.9 {
+global:
+virDomainGetPcpusUsage;
+} LIBVIRT_0.9.8;
+
 #  define new API here using predicted next version number 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] problem of escaped scancodes

2011-08-23 Thread Lai Jiangshan

Hi, Daniel P. Berrange,

Our user found that some keycode can not be handled well when
they try to map other keycode to xt_kbd keycode, when xt_kbd keycode
is an escaped scancode.

The xt_kbd keycode http://git.gnome.org/browse/gtk-vnc/plain/src/keymaps.csv
are come from x86_keycodes[] of linux/drivers/char/keyboard.c.
And x86_keycodes[] are:

static const unsigned short x86_keycodes[256] =
{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };


There is no keycode in range [128, 256] in this table, which means
all escaped scancode e0 ?? are encoded as 0x100 | ?? in this table.
Example, LeftCtrl is 0x1d, and RightCtrl is escaped: e0 1d,
RightCtrl is encoded as 0x100 | 0x1d(=0x11d=285) in this table.
The code also tell me the same information:

code = x86_keycodes[keycode];
if (!code)
return -1;

if (code  0x100)
put_queue(vc, 0xe0);
put_queue(vc, (code  0x7f) | up_flag);



But some other place, escaped scancode e0 ?? are encoded as 0x80 | ??,
this encoding is more commonly used, and qemu uses this encoding,
RightCtrl is encoded as 0x80 | 0x1d(=0x9d=157) in qemu:

{ 0x9d, ctrl_r },

keycode = keycodes[i];
if (keycode  0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode  0x7f);


The problem:
keymaps.csv uses the first encoding while qemu uses the second one, it
causes virsh send-key command can't work when it sends escaped scancodes.

Example:
When do virsh send-key domain KEY_RIGHTCTRL, qemu will receive keycode=285
which is not expected.

So I suggest to change keymaps.csv.
Covert the old
KEY_RIGHTCTRL,97,RightControl,0x3e,,,88,,285,228,VK_RCONTROL,0xa3,0x65,0x65
to new
KEY_RIGHTCTRL,97,RightControl,0x3e,,,88,,157,228,VK_RCONTROL,0xa3,0x65,0x65
(ditto for other escaped scancodes)

Or just add the new line to keymaps.csv followed by the old line, and make
285 and 157 can work at the same time.

Thought?

Thanks,
Lai.

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH ] send-key: Implement Python API

2011-07-25 Thread Lai Jiangshan
ping.

On 07/21/2011 05:21 PM, Lai Jiangshan wrote:
 
 Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
 ---
 diff --git a/python/libvirt-override.c b/python/libvirt-override.c
 index b713b6a..1ef5bfa 100644
 --- a/python/libvirt-override.c
 +++ b/python/libvirt-override.c
 @@ -3789,6 +3789,53 @@ libvirt_virStreamSend(PyObject *self ATTRIBUTE_UNUSED,
  return py_retval;
  }
  
 +static PyObject *
 +libvirt_virDomainSendKey(PyObject *self ATTRIBUTE_UNUSED,
 + PyObject *args)
 +{
 +PyObject *py_retval;
 +virDomainPtr domain;
 +PyObject *pyobj_domain;
 +PyObject *pyobj_list;
 +int codeset;
 +int holdtime;
 +unsigned int flags;
 +int ret;
 +int i;
 +unsigned int keycodes[VIR_DOMAIN_SEND_KEY_MAX_KEYS];
 +unsigned int nkeycodes;
 +
 +if (!PyArg_ParseTuple(args, (char *)OiiOii:virDomainSendKey,
 +  pyobj_domain, codeset, holdtime, pyobj_list,
 +  nkeycodes, flags)) {
 +DEBUG(%s failed to parse tuple\n, __FUNCTION__);
 +return VIR_PY_INT_FAIL;
 +}
 +domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
 +
 +if (!PyList_Check(pyobj_list)) {
 +return VIR_PY_INT_FAIL;
 +}
 +
 +if (nkeycodes != PyList_Size(pyobj_list) ||
 +nkeycodes  VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
 +return VIR_PY_INT_FAIL;
 +}
 +
 +for (i = 0; i  nkeycodes; i++) {
 +keycodes[i] = (int)PyInt_AsLong(PyList_GetItem(pyobj_list, i));
 +}
 +
 +LIBVIRT_BEGIN_ALLOW_THREADS;
 +ret = virDomainSendKey(domain, codeset, holdtime, keycodes, nkeycodes, 
 flags);
 +LIBVIRT_END_ALLOW_THREADS;
 +
 +DEBUG(virDomainSendKey ret=%d\n, ret);
 +
 +py_retval = libvirt_intWrap(ret);
 +return py_retval;
 +}
 +
  /
   *   *
   *   The registration stuff  *
 @@ -3872,6 +3919,7 @@ static PyMethodDef libvirtMethods[] = {
  {(char *) virDomainGetJobInfo, libvirt_virDomainGetJobInfo, 
 METH_VARARGS, NULL},
  {(char *) virDomainSnapshotListNames, 
 libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
  {(char *) virDomainRevertToSnapshot, 
 libvirt_virDomainRevertToSnapshot, METH_VARARGS, NULL},
 +{(char *) virDomainSendKey, libvirt_virDomainSendKey, METH_VARARGS, 
 NULL},
  {NULL, NULL, 0, NULL}
  };
  
 

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH ] send-key: Implement Python API

2011-07-21 Thread Lai Jiangshan

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index b713b6a..1ef5bfa 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -3789,6 +3789,53 @@ libvirt_virStreamSend(PyObject *self ATTRIBUTE_UNUSED,
 return py_retval;
 }
 
+static PyObject *
+libvirt_virDomainSendKey(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+PyObject *py_retval;
+virDomainPtr domain;
+PyObject *pyobj_domain;
+PyObject *pyobj_list;
+int codeset;
+int holdtime;
+unsigned int flags;
+int ret;
+int i;
+unsigned int keycodes[VIR_DOMAIN_SEND_KEY_MAX_KEYS];
+unsigned int nkeycodes;
+
+if (!PyArg_ParseTuple(args, (char *)OiiOii:virDomainSendKey,
+  pyobj_domain, codeset, holdtime, pyobj_list,
+  nkeycodes, flags)) {
+DEBUG(%s failed to parse tuple\n, __FUNCTION__);
+return VIR_PY_INT_FAIL;
+}
+domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+if (!PyList_Check(pyobj_list)) {
+return VIR_PY_INT_FAIL;
+}
+
+if (nkeycodes != PyList_Size(pyobj_list) ||
+nkeycodes  VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
+return VIR_PY_INT_FAIL;
+}
+
+for (i = 0; i  nkeycodes; i++) {
+keycodes[i] = (int)PyInt_AsLong(PyList_GetItem(pyobj_list, i));
+}
+
+LIBVIRT_BEGIN_ALLOW_THREADS;
+ret = virDomainSendKey(domain, codeset, holdtime, keycodes, nkeycodes, 
flags);
+LIBVIRT_END_ALLOW_THREADS;
+
+DEBUG(virDomainSendKey ret=%d\n, ret);
+
+py_retval = libvirt_intWrap(ret);
+return py_retval;
+}
+
 /
  * *
  * The registration stuff  *
@@ -3872,6 +3919,7 @@ static PyMethodDef libvirtMethods[] = {
 {(char *) virDomainGetJobInfo, libvirt_virDomainGetJobInfo, 
METH_VARARGS, NULL},
 {(char *) virDomainSnapshotListNames, 
libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
 {(char *) virDomainRevertToSnapshot, libvirt_virDomainRevertToSnapshot, 
METH_VARARGS, NULL},
+{(char *) virDomainSendKey, libvirt_virDomainSendKey, METH_VARARGS, 
NULL},
 {NULL, NULL, 0, NULL}
 };
 

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH] virsh: add custom readline generator

2011-07-20 Thread Lai Jiangshan
On 06/28/2011 05:29 PM, Michal Privoznik wrote:
 On 27.06.2011 21:39, Eric Blake wrote:
 On 06/27/2011 12:06 PM, Michal Privoznik wrote:
 That is, if you have command-based custom generators, then each command
 has to repeat parsing functionality, then call back to common list
 generators; whereas if you have option-based custom generators, then you
 have fewer callbacks because all the smarts are tied to well-typed
 options, and after all, it is the type of each option that determines
 which list to generate, more than the type of the command that includes
 the option.

 I was thinking about same feature and started to work on it during this
 weekend. But I ran into a problem. Basically, what I intended to
 implement, is:

 1.) expand struct vshCmdDef for a char *(*callback) (const char *text,
 int state). But for real benefit, we need connection object, so we could
 e.g. list only inactive networks for 'net-start' command. And this is
 the problem, because we would have to make this object global (since
 readline functions does not allow passing any opaque value).

 As gross as it is, a global object isn't entirely bad - virsh is
 single-threaded.  And even if we want to make virsh threaded at some
 point, I still think we can get away with adding a thread-local access
 scheme.


 2.) expand each command definition with its own completer. So e.g. for
 start commands we could only list inactive domains, networks, pools,
 whatever. For destroy only active objects. And so on.

 So maybe we want both - an option-based completer that generates the
 initial list, and a command-based completer that can then prune out
 irrelevant options?

 
 Well, I would say that is the highest goal to be achieved. Although that
 implies parsing during options generation.
 
 But I don't think I get it. Option-based completer generates list for
 given option, command-based completer generates list for given command
 (entries from this list are options). Take detach-interface for
 instance. This have some options:
 --mac: here we want option-based completer to list mac addresses of a
 NICs of a domain specified by
 --domain: since this could be left out we want here command-base
 completer to either list all domains, or list only those domains which
 have a NIC.
 
 So then we get:
 
 # detach-interface TABTAB
 --mac --persistent domain1 domain2
 
 # detach-interface domain1 --mac TABTAB
 00:11:22:33:44:55 01:23:45:67:89
 
 My point is - I can't see any pruning here. But maybe I've chosen wrong
 example. However, this example shows we need both types of completer.
 
 Michal
 

Hi, All

Are their any progress now?

Thanks,
Lai

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/4 V5] util: add virtkey

2011-07-20 Thread Lai Jiangshan
Add virtkey lib for usage-improvment and keycode translating.
Add 4 internal API for the aim

const char *virKeycodeSetTypeToString(int codeset);
int virKeycodeSetTypeFromString(const char *name);
int virKeycodeValueFromString(virKeycodeSet codeset, const char *keyname);
int virKeycodeValueTranslate(virKeycodeSet from_codeset,
 virKeycodeSet to_offset,
 int key_value);

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in  |6 ++
 src/Makefile.am   |   12 +++-
 src/libvirt_private.syms  |5 ++
 src/util/virkey.c |  145 +
 src/util/virkeycode-mapgen.py |   45 +
 src/util/virkeycode.h |   35 ++
 6 files changed, 247 insertions(+), 1 deletions(-)
 create mode 100644 src/util/virkey.c
 create mode 100644 src/util/virkeycode-mapgen.py
 create mode 100644 src/util/virkeycode.h

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 40ce0fc..6afd591 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1788,6 +1788,12 @@ typedef enum {
 VIR_KEYCODE_SET_ATSET1 = 2,
 VIR_KEYCODE_SET_ATSET2 = 3,
 VIR_KEYCODE_SET_ATSET3 = 4,
+VIR_KEYCODE_SET_OSX= 5,
+VIR_KEYCODE_SET_XT_KBD = 6,
+VIR_KEYCODE_SET_USB= 7,
+VIR_KEYCODE_SET_WIN32  = 8,
+
+VIR_KEYCODE_SET_LAST,
 } virKeycodeSet;
 
 /**
diff --git a/src/Makefile.am b/src/Makefile.am
index 2a6b0e4..87117de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -81,7 +81,17 @@ UTIL_SOURCES =   
\
util/util.c util/util.h \
util/viraudit.c util/viraudit.h \
util/xml.c util/xml.h   \
-   util/virterror.c util/virterror_internal.h
+   util/virterror.c util/virterror_internal.h  \
+   util/virkey.c util/virkeycode.h util/virkeymaps.h
+
+EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \
+   $(srcdir)/util/virkeycode-mapgen.py
+
+$(srcdir)/util/virkeymaps.h: $(srcdir)/util/keymaps.csv\
+   $(srcdir)/util/virkeycode-mapgen.py
+   python $(srcdir)/util/virkeycode-mapgen.py $(srcdir)/util/keymaps.csv 
$@
+
+$(srcdir)/util/virkey.c: $(srcdir)/util/virkeycode.h 
$(srcdir)/util/virkeymaps.h
 
 EXTRA_DIST += util/threads-pthread.c util/threads-win32.c
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3e3b1dd..e9ae018 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1097,6 +1097,11 @@ virSetError;
 virSetErrorLogPriorityFunc;
 virStrerror;
 
+# virkeycode.h
+virKeycodeSetTypeToString;
+virKeycodeSetTypeFromString;
+virKeycodeValueFromString;
+virKeycodeValueTranslate;
 
 # xml.h
 virXMLParseFileHelper;
diff --git a/src/util/virkey.c b/src/util/virkey.c
new file mode 100644
index 000..e94768a
--- /dev/null
+++ b/src/util/virkey.c
@@ -0,0 +1,145 @@
+
+/*
+ * Copyright (c) 2011 Lai Jiangshan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include config.h
+#include virkeycode.h
+#include string.h
+#include stddef.h
+
+#define getfield(object, field_type, field_offset) \
+(*(typeof(field_type) *)((char *)(object) + field_offset))
+
+struct keycode {
+const char *linux_name;
+const char *os_x_name;
+const char *win32_name;
+unsigned short linux_keycode;
+unsigned short os_x;
+unsigned short atset1;
+unsigned short atset2;
+unsigned short atset3;
+unsigned short xt;
+unsigned short xt_kbd;
+unsigned short usb;
+unsigned short win32;
+};
+
+#define VIRT_KEY_INTERNAL
+#include virkeymaps.h
+
+static unsigned int codeOffset[] = {
+[VIR_KEYCODE_SET_LINUX] =
+offsetof(struct keycode, linux_keycode),
+[VIR_KEYCODE_SET_XT] =
+offsetof(struct keycode, xt),
+[VIR_KEYCODE_SET_ATSET1] =
+offsetof(struct keycode, atset1),
+[VIR_KEYCODE_SET_ATSET2] =
+offsetof(struct keycode, atset2),
+[VIR_KEYCODE_SET_ATSET3] =
+offsetof(struct keycode, atset3

[libvirt] [PATCH 0/4 V5] Add support for send keys to guest

2011-07-20 Thread Lai Jiangshan
Add virtkey lib for usage-improvment and keycode translating.
Expose send-key in virsh
Implement send-key function for the qemu driver

Daniel P. Berrange (1):
  util: Add keymaps.csv

Lai Jiangshan (3):
  util: add virtkey
  send-key: Expose the new API in virsh
  qemu:send-key: Implement the driver methods

 include/libvirt/libvirt.h.in  |6 +
 src/Makefile.am   |   14 +-
 src/libvirt_private.syms  |5 +
 src/qemu/qemu_driver.c|   71 +++
 src/qemu/qemu_monitor.c   |   17 ++
 src/qemu/qemu_monitor.h   |5 +
 src/qemu/qemu_monitor_json.c  |   15 ++
 src/qemu/qemu_monitor_json.h  |5 +
 src/qemu/qemu_monitor_text.c  |   49 +
 src/qemu/qemu_monitor_text.h  |5 +
 src/util/keymaps.csv  |  463 +
 src/util/virkey.c |  145 +
 src/util/virkeycode-mapgen.py |   45 
 src/util/virkeycode.h |   35 +++
 tools/virsh.c |   94 +
 tools/virsh.pod   |4 +
 16 files changed, 976 insertions(+), 2 deletions(-)
 create mode 100644 src/util/keymaps.csv
 create mode 100644 src/util/virkey.c
 create mode 100644 src/util/virkeycode-mapgen.py
 create mode 100644 src/util/virkeycode.h

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/4 V5] qemu:send-key: Implement the driver methods

2011-07-20 Thread Lai Jiangshan
qemu driver just accept xt_kbd codeset's keycode, so the lib virtkey
is used for translating keycodes from other codesets.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu_driver.c   |   71 ++
 src/qemu/qemu_monitor.c  |   17 ++
 src/qemu/qemu_monitor.h  |5 +++
 src/qemu/qemu_monitor_json.c |   15 +
 src/qemu/qemu_monitor_json.h |5 +++
 src/qemu/qemu_monitor_text.c |   49 +
 src/qemu/qemu_monitor_text.h |5 +++
 7 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index cd65bce..f1ecebf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -87,6 +87,7 @@
 #include configmake.h
 #include threadpool.h
 #include locking/lock_manager.h
+#include virkeycode.h
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -1849,6 +1850,75 @@ cleanup:
 return ret;
 }
 
+static int qemuDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int *keycodes,
+ int nkeycodes,
+ unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+/* translate the keycode to XT_KBD for qemu driver */
+if (codeset != VIR_KEYCODE_SET_XT_KBD) {
+int i;
+int keycode;
+
+for (i = 0; i  nkeycodes; i++) {
+keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_XT_KBD,
+   keycodes[i]);
+if (keycode  0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR, can not translate 
+keycode %u of %s codeset to xt_kbd codeset 
+keycode, keycodes[i],
+virKeycodeSetTypeToString(codeset));
+return -1;
+}
+keycodes[i] = keycode;
+}
+}
+
+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;
+}
+
+priv = vm-privateData;
+
+if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY)  0)
+goto cleanup;
+
+if (!virDomainObjIsActive(vm)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID,
+%s, _(domain is not running));
+goto cleanup;
+}
+
+ignore_value(qemuDomainObjEnterMonitorWithDriver(driver, vm));
+ret = qemuMonitorSendKey(priv-mon, holdtime, keycodes, nkeycodes);
+qemuDomainObjExitMonitorWithDriver(driver, vm);
+if (qemuDomainObjEndJob(driver, vm) == 0) {
+vm = NULL;
+goto cleanup;
+}
+
+cleanup:
+if (vm)
+virDomainObjUnlock(vm);
+qemuDriverUnlock(driver);
+return ret;
+}
+
 static int qemudDomainGetInfo(virDomainPtr dom,
   virDomainInfoPtr info)
 {
@@ -8653,6 +8723,7 @@ static virDriver qemuDriver = {
 .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */
 .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
+.domainSendKey = qemuDomainSendKey, /* 0.9.4 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 3a30a15..016f8f0 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2408,6 +2408,23 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
 return ret;
 }
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int holdtime,
+   unsigned int *keycodes,
+   unsigned int nkeycodes)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, holdtime=%u, nkeycodes=%u,
+  mon, holdtime, nkeycodes);
+
+if (mon-json)
+ret = qemuMonitorJSONSendKey(mon, holdtime, keycodes, nkeycodes);
+else
+ret = qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes);
+return ret;
+}
+
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index f246d21..0419147 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -447,6 +447,11 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon);
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file);
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int holdtime,
+   unsigned int *keycodes,
+   unsigned int

[libvirt] [PATCH 1/4 V5] util: Add keymaps.csv

2011-07-20 Thread Lai Jiangshan
From: Daniel P. Berrange berra...@redhat.com

Should keep it as the same as:
http://git.gnome.org/browse/gtk-vnc/commit/src/keymaps.csv

All master  keymaps are defined in a CSV file. THis covers
Linux keycodes, OSX keycodes, AT set1, 2  3, XT keycodes,
the XT encoding used by the Linux KBD driver, USB keycodes,
Win32 keycodes, the XT encoding used by Xorg on Cygwin,
the XT encoding used by Xorg on Linux with kbd driver.

Signed-off-by: Daniel P. Berrange berra...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/Makefile.am  |2 +-
 src/util/keymaps.csv |  463 ++
 2 files changed, 464 insertions(+), 1 deletions(-)
 create mode 100644 src/util/keymaps.csv

diff --git a/src/Makefile.am b/src/Makefile.am
index f4ff489..2a6b0e4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@ AM_CFLAGS =   $(DRIVER_MODULE_CFLAGS) 
\
$(COVERAGE_CFLAGS)
 AM_LDFLAGS = $(COVERAGE_LDFLAGS)
 
-EXTRA_DIST = $(conf_DATA)
+EXTRA_DIST = $(conf_DATA) util/keymaps.csv
 
 BUILT_SOURCES =
 
diff --git a/src/util/keymaps.csv b/src/util/keymaps.csv
new file mode 100644
index 000..c447f46
--- /dev/null
+++ b/src/util/keymaps.csv
@@ -0,0 +1,463 @@
+Linux Name,Linux Keycode,OS-X Name,OS-X Keycode,AT set1 keycode,AT 
set2 keycode,AT set3 keycode,XT,XT KBD,USB Keycodes,Win32 Name,Win32 
Keycode,Xwin XT,Xfree86 KBD XT
+KEY_RESERVED,0
+KEY_ESC,1,Escape,0x35,1,118,8,1,1,41,VK_ESCAPE,0x1b,1,1
+KEY_1,2,ANSI_1,0x12,2,22,22,2,2,30,VK_1,0x31,2,2
+KEY_2,3,ANSI_2,0x13,3,30,30,3,3,31,VK_2,0x32,3,3
+KEY_3,4,ANSI_3,0x14,4,38,38,4,4,32,VK_3,0x33,4,4
+KEY_4,5,ANSI_4,0x15,5,37,37,5,5,33,VK_4,0x34,5,5
+KEY_5,6,ANSI_5,0x17,6,46,46,6,6,34,VK_5,0x35,6,6
+KEY_6,7,ANSI_6,0x16,7,54,54,7,7,35,VK_6,0x36,7,7
+KEY_7,8,ANSI_7,0x1a,8,61,61,8,8,36,VK_7,0x37,8,8
+KEY_8,9,ANSI_8,0x1c,9,62,62,9,9,37,VK_8,0x38,9,9
+KEY_9,10,ANSI_9,0x19,10,70,70,10,10,38,VK_9,0x39,10,10
+KEY_0,11,ANSI_0,0x1d,11,69,69,11,11,39,VK_0,0x30,11,11
+KEY_MINUS,12,ANSI_Minus,0x1b,12,78,78,12,12,45,VK_OEM_MINUS,0xbd,12,12
+KEY_EQUAL,13,ANSI_Equal,0x18,13,85,85,13,13,46,VK_OEM_PLUS,0xbb,13,13
+KEY_BACKSPACE,14,Delete,0x33,14,102,102,14,14,42,VK_BACK,0x08,14,14
+KEY_TAB,15,Tab,0x30,15,13,13,15,15,43,VK_TAB,0x09,15,15
+KEY_Q,16,ANSI_Q,0xc,16,21,21,16,16,20,VK_Q,0x51,16,16
+KEY_W,17,ANSI_W,0xd,17,29,29,17,17,26,VK_W,0x57,17,17
+KEY_E,18,ANSI_E,0xe,18,36,36,18,18,8,VK_E,0x45,18,18
+KEY_R,19,ANSI_R,0xf,19,45,45,19,19,21,VK_R,0x52,19,19
+KEY_T,20,ANSI_T,0x11,20,44,44,20,20,23,VK_T,0x54,20,20
+KEY_Y,21,ANSI_Y,0x10,21,53,53,21,21,28,VK_Y,0x59,21,21
+KEY_U,22,ANSI_U,0x20,22,60,60,22,22,24,VK_U,0x55,22,22
+KEY_I,23,ANSI_I,0x22,23,67,67,23,23,12,VK_I,0x49,23,23
+KEY_O,24,ANSI_O,0x1f,24,68,68,24,24,18,VK_O,0x4f,24,24
+KEY_P,25,ANSI_P,0x23,25,77,77,25,25,19,VK_P,0x50,25,25
+KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,26,84,84,26,26,47,VK_OEM_4,0xdb,26,26
+KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,27,91,91,27,27,48,VK_OEM_6,0xdd,27,27
+KEY_ENTER,28,Return,0x24,28,90,90,28,28,40,VK_RETURN,0x0d,28,28
+KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_LCONTROL,0xa2,29,29
+KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_CONTROL,0x11,29,29
+KEY_A,30,ANSI_A,0x0,30,28,28,30,30,4,VK_A,0x41,30,30
+KEY_S,31,ANSI_S,0x1,31,27,27,31,31,22,VK_S,0x53,31,31
+KEY_D,32,ANSI_D,0x2,32,35,35,32,32,7,VK_D,0x44,32,32
+KEY_F,33,ANSI_F,0x3,33,43,43,33,33,9,VK_F,0x46,33,33
+KEY_G,34,ANSI_G,0x5,34,52,52,34,34,10,VK_G,0x47,34,34
+KEY_H,35,ANSI_H,0x4,35,51,51,35,35,11,VK_H,0x48,35,35
+KEY_J,36,ANSI_J,0x26,36,59,59,36,36,13,VK_J,0x4a,36,36
+KEY_K,37,ANSI_K,0x28,37,66,66,37,37,14,VK_K,0x4b,37,37
+KEY_L,38,ANSI_L,0x25,38,75,75,38,38,15,VK_L,0x4c,38,38
+KEY_SEMICOLON,39,ANSI_Semicolon,0x29,39,76,76,39,39,51,VK_OEM_1,0xba,39,39
+KEY_APOSTROPHE,40,ANSI_Quote,0x27,40,82,82,40,40,52,VK_OEM_2,0xbf,40,40
+KEY_GRAVE,41,ANSI_Grave,0x32,41,14,14,41,41,53,VK_OEM_3,0xc0,41,41
+KEY_LEFTSHIFT,42,Shift,0x38,42,18,18,42,42,225,VK_LSHIFT,0xa0,42,42
+KEY_BACKSLASH,43,ANSI_Backslash,0x2a,43,93,93,43,43,50,VK_OEM_5,0xdc,43,43
+KEY_Z,44,ANSI_Z,0x6,44,26,26,44,44,29,VK_Z,0x5a,44,44
+KEY_X,45,ANSI_X,0x7,45,34,34,45,45,27,VK_X,0x58,45,45
+KEY_C,46,ANSI_C,0x8,46,33,33,46,46,6,VK_C,0x43,46,46
+KEY_V,47,ANSI_V,0x9,47,42,42,47,47,25,VK_V,0x56,47,47
+KEY_B,48,ANSI_B,0xb,48,50,50,48,48,5,VK_B,0x42,48,48
+KEY_N,49,ANSI_N,0x2d,49,49,49,49,49,17,VK_N,0x4e,49,49
+KEY_M,50,ANSI_M,0x2e,50,58,58,50,50,16,VK_M,0x4d,50,50
+KEY_COMMA,51,ANSI_Comma,0x2b,51,65,65,51,51,54,VK_OEM_COMMA,0xbc,51,51
+KEY_DOT,52,ANSI_Period,0x2f,52,73,73,52,52,55,VK_OEM_PERIOD,0xbe,52,52
+KEY_SLASH,53,ANSI_Slash,0x2c,53,74,74,53,53,56,VK_OEM_2,0xbf,53,53
+KEY_RIGHTSHIFT,54,RightShift,0x3c,54,89,89,54,54,229,VK_RSHIFT,0xa1,54,54
+KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,55,124,126,55,55,85,VK_MULTIPLY,0x6a,55,55
+KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_LMENU,0xa4,56,56
+KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_MENU,0x12,56,56
+KEY_SPACE,57,Space

[libvirt] [PATCH 3/4 V5] send-key: Expose the new API in virsh

2011-07-20 Thread Lai Jiangshan
Also support string names for the linux keycode(auto detect).

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
Acked-by: Daniel P. Berrange berra...@redhat.com
---
 tools/virsh.c   |   94 +++
 tools/virsh.pod |4 ++
 2 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index ca92f0c..e9294f8 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -58,6 +58,7 @@
 #include threads.h
 #include command.h
 #include count-one-bits.h
+#include virkeycode.h
 
 static char *progname;
 
@@ -3447,6 +3448,98 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * send-key command
+ */
+static const vshCmdInfo info_send_key[] = {
+{help, N_(Send keycodes to the guest)},
+{desc, N_(Send keycodes to the guest, the keycodes must be integers\n
+Examples:\n\n
+virsh # send-key domain 37 18 21\n
+virsh # send-key domain KEY_RIGHTCTRL KEY_C\n
+virsh # send-key domain --codeset xt 37 18 21\n
+virsh # send-key domain --holdtime 1000 0x15 18 
0xf\n
+)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_send_key[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{codeset, VSH_OT_STRING, VSH_OFLAG_REQ_OPT, N_(the codeset of keycodes, 
default:linux)},
+{holdtime, VSH_OT_INT, VSH_OFLAG_REQ_OPT,
+ N_(the time (in millsecond) how long the keys will be 
held)},
+{keycode, VSH_OT_ARGV, VSH_OFLAG_REQ, N_(the key code)},
+{NULL, 0, 0, NULL}
+};
+
+static int get_integer_keycode(const char *key_name)
+{
+long val;
+char *endptr;
+
+val = strtol(key_name, endptr, 0);
+if (*endptr != '\0' || val  0x || val = 0)
+ return -1;
+
+return val;
+}
+
+static bool
+cmdSendKey(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = false;
+const char *codeset_option;
+int codeset;
+int holdtime;
+int count = 0;
+const vshCmdOpt *opt = NULL;
+int keycode;
+unsigned int keycodes[VIR_DOMAIN_SEND_KEY_MAX_KEYS];
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (vshCommandOptString(cmd, codeset, codeset_option) = 0)
+codeset_option = linux;
+
+if (vshCommandOptInt(cmd, holdtime, holdtime) = 0)
+holdtime = 0;
+
+codeset = virKeycodeSetTypeFromString(codeset_option);
+if ((int)codeset  0) {
+vshError(ctl, _(unknown codeset: '%s'), codeset_option);
+goto cleanup;
+}
+
+while ((opt = vshCommandOptArgv(cmd, opt))) {
+if (count == VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
+vshError(ctl, _(too many keycodes));
+goto cleanup;
+}
+
+if ((keycode = get_integer_keycode(opt-data)) = 0) {
+if ((keycode = virKeycodeValueFromString(codeset, opt-data)) = 
0) {
+vshError(ctl, _(invalid keycode: '%s'), opt-data);
+goto cleanup;
+}
+}
+
+keycodes[count] = keycode;
+count++;
+}
+
+if (!(virDomainSendKey(dom, codeset, holdtime, keycodes, count, 0)  0))
+ret = true;
+
+cleanup:
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * setmemory command
  */
 static const vshCmdInfo info_setmem[] = {
@@ -12005,6 +12098,7 @@ static const vshCmdDef domManagementCmds[] = {
 {dumpxml, cmdDumpXML, opts_dumpxml, info_dumpxml, 0},
 {edit, cmdEdit, opts_edit, info_edit, 0},
 {inject-nmi, cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0},
+{send-key, cmdSendKey, opts_send_key, info_send_key},
 {managedsave, cmdManagedSave, opts_managedsave, info_managedsave, 0},
 {managedsave-remove, cmdManagedSaveRemove, opts_managedsaveremove,
  info_managedsaveremove, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 9cd2853..60ae8ff 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -309,6 +309,10 @@ running Bvirsh suspend.  When in a paused state the 
domain will still
 consume allocated resources like memory, but will not be eligible for
 scheduling by the hypervisor.
 
+=item Bsend-key Idomain-id optional I--codeset Bcodeset optional 
I--holdtime Bholdtime Bkeycode...
+
+Send keys to the guest
+
 =item Bshutdown
 
 The domain is in the process of shutting down, i.e. the guest operating system
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 0/4 V4] Add support for send keys to guest

2011-07-13 Thread Lai Jiangshan
Add virtkey lib for usage-improvment and keycode translating.
Expose send-key in virsh
Implement send-key function for the qemu driver

Daniel P. Berrange (1):
  util: Add keymaps.csv

Lai Jiangshan (3):
  util: add virtkey
  send-key: Expose the new API in virsh
  qemu:send-key: Implement the driver methods

 include/libvirt/libvirt.h.in |8 +
 src/Makefile.am  |   11 +-
 src/libvirt_private.syms |5 +
 src/qemu/qemu_driver.c   |   71 +++
 src/qemu/qemu_monitor.c  |   17 ++
 src/qemu/qemu_monitor.h  |5 +
 src/qemu/qemu_monitor_json.c |   15 ++
 src/qemu/qemu_monitor_json.h |5 +
 src/qemu/qemu_monitor_text.c |   49 +
 src/qemu/qemu_monitor_text.h |5 +
 src/util/keymaps.csv |  463 ++
 src/util/virtkey.c   |  117 +++
 src/util/virtkey.h   |   41 
 src/util/virtkeymap-gen.py   |   47 +
 tools/virsh.c|   94 +
 tools/virsh.pod  |4 +
 16 files changed, 956 insertions(+), 1 deletions(-)
 create mode 100644 src/util/keymaps.csv
 create mode 100644 src/util/virtkey.c
 create mode 100644 src/util/virtkey.h
 create mode 100644 src/util/virtkeymap-gen.py

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/4 V4] util: add virtkey

2011-07-13 Thread Lai Jiangshan
Add virtkey lib for usage-improvment and keycode translating.
Add 4 internal API for the aim

const char *virKeycodeSetTypeToString(int codeset);
int virKeycodeSetTypeFromString(const char *name);
int virParseKeyName(virKeycodeSet codeset, const char *keyname);
int virTranslateKeyCode(virKeycodeSet from_codeset,
virKeycodeSet to_offset,
int key_value);

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in |8 +++
 src/Makefile.am  |   11 -
 src/libvirt_private.syms |5 ++
 src/util/virtkey.c   |  117 ++
 src/util/virtkey.h   |   41 +++
 src/util/virtkeymap-gen.py   |   47 +
 6 files changed, 228 insertions(+), 1 deletions(-)
 create mode 100644 src/util/virtkey.c
 create mode 100644 src/util/virtkey.h
 create mode 100644 src/util/virtkeymap-gen.py

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index d5a7105..acfe9d9 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1778,6 +1778,14 @@ typedef enum {
 VIR_KEYCODE_SET_ATSET1 = 2,
 VIR_KEYCODE_SET_ATSET2 = 3,
 VIR_KEYCODE_SET_ATSET3 = 4,
+VIR_KEYCODE_SET_OSX= 5,
+VIR_KEYCODE_SET_XT_KBD = 6,
+VIR_KEYCODE_SET_USB= 7,
+VIR_KEYCODE_SET_WIN32  = 8,
+VIR_KEYCODE_SET_XWIN_XT= 9,
+VIR_KEYCODE_SET_XFREE86_KBD_XT = 10,
+
+VIR_KEYCODE_SET_LAST,
 } virKeycodeSet;
 
 /**
diff --git a/src/Makefile.am b/src/Makefile.am
index 39f0cf8..90b0743 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -81,7 +81,16 @@ UTIL_SOURCES =   
\
util/util.c util/util.h \
util/viraudit.c util/viraudit.h \
util/xml.c util/xml.h   \
-   util/virterror.c util/virterror_internal.h
+   util/virterror.c util/virterror_internal.h  \
+   util/virtkey.c util/virtkey.h   \
+   util/virtkeymaps.c
+
+EXTRA_DIST += $(srcdir)/util/virtkeymaps.c $(srcdir)/util/keymaps.csv \
+   $(srcdir)/util/virtkeymap-gen.py
+
+$(srcdir)/util/virtkeymaps.c: $(srcdir)/util/keymaps.csv   \
+   $(srcdir)/util/virtkeymap-gen.py
+   python $(srcdir)/util/virtkeymap-gen.py $(srcdir)/util/keymaps.csv $@
 
 EXTRA_DIST += util/threads-pthread.c util/threads-win32.c
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3237d18..6611471 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1094,6 +1094,11 @@ virSetError;
 virSetErrorLogPriorityFunc;
 virStrerror;
 
+# virtkey.h
+virKeycodeSetTypeToString;
+virKeycodeSetTypeFromString;
+virParseKeyName;
+virTranslateKeyCode;
 
 # xml.h
 virXMLParseFileHelper;
diff --git a/src/util/virtkey.c b/src/util/virtkey.c
new file mode 100644
index 000..1eb3c62
--- /dev/null
+++ b/src/util/virtkey.c
@@ -0,0 +1,117 @@
+
+/*
+ * Copyright (c) 2011 Lai Jiangshan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include virtkey.h
+#include string.h
+#include stddef.h
+
+#define getfield(object, field_type, field_offset) \
+(*(typeof(field_type) *)((char *)(object) + field_offset))
+
+static unsigned int codeOffset[] = {
+[VIR_KEYCODE_SET_LINUX] =
+offsetof(struct keycode, linux_keycode),
+[VIR_KEYCODE_SET_XT] =
+offsetof(struct keycode, xt),
+[VIR_KEYCODE_SET_ATSET1] =
+offsetof(struct keycode, atset1),
+[VIR_KEYCODE_SET_ATSET2] =
+offsetof(struct keycode, atset2),
+[VIR_KEYCODE_SET_ATSET3] =
+offsetof(struct keycode, atset3),
+[VIR_KEYCODE_SET_OSX] =
+offsetof(struct keycode, os_x),
+[VIR_KEYCODE_SET_XT_KBD] =
+offsetof(struct keycode, xt_kbd),
+[VIR_KEYCODE_SET_USB] =
+offsetof(struct keycode, usb),
+[VIR_KEYCODE_SET_WIN32] =
+offsetof(struct keycode, win32),
+[VIR_KEYCODE_SET_XWIN_XT] =
+offsetof(struct keycode, xwin_xt),
+[VIR_KEYCODE_SET_XFREE86_KBD_XT] =
+offsetof(struct keycode, xfree86_kbd_xt),
+};
+
+VIR_ENUM_IMPL(virKeycodeSet, VIR_KEYCODE_SET_LAST,
+linux,
+xt,
+atset1,
+atset2,
+atset3,
+os_x,
+xt_kbd,
+usb,
+win32,
+xwin_xt,
+xfree86_kbd_xt);
+
+static int virParseKeyNameOffset(unsigned int name_offset,
+ unsigned int code_offset,
+ const char *keyname)
+{
+int i;
+
+for (i = 0; i  virtKeycodesSize; i++) {
+const char *name = getfield(virtKeycodes + i, const char *, 
name_offset);
+
+if (name  !strcmp(name, keyname

[libvirt] [PATCH 1/4 V4] util: Add keymaps.csv

2011-07-13 Thread Lai Jiangshan
From: Daniel P. Berrange berra...@redhat.com

Should keep it as the same as:
http://git.gnome.org/browse/gtk-vnc/commit/src/keymaps.csv

All master  keymaps are defined in a CSV file. THis covers
Linux keycodes, OSX keycodes, AT set1, 2  3, XT keycodes,
the XT encoding used by the Linux KBD driver, USB keycodes,
Win32 keycodes, the XT encoding used by Xorg on Cygwin,
the XT encoding used by Xorg on Linux with kbd driver.

Signed-off-by: Daniel P. Berrange berra...@redhat.com
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/util/keymaps.csv |  463 ++
 1 files changed, 463 insertions(+), 0 deletions(-)
 create mode 100644 src/util/keymaps.csv

diff --git a/src/util/keymaps.csv b/src/util/keymaps.csv
new file mode 100644
index 000..c447f46
--- /dev/null
+++ b/src/util/keymaps.csv
@@ -0,0 +1,463 @@
+Linux Name,Linux Keycode,OS-X Name,OS-X Keycode,AT set1 keycode,AT 
set2 keycode,AT set3 keycode,XT,XT KBD,USB Keycodes,Win32 Name,Win32 
Keycode,Xwin XT,Xfree86 KBD XT
+KEY_RESERVED,0
+KEY_ESC,1,Escape,0x35,1,118,8,1,1,41,VK_ESCAPE,0x1b,1,1
+KEY_1,2,ANSI_1,0x12,2,22,22,2,2,30,VK_1,0x31,2,2
+KEY_2,3,ANSI_2,0x13,3,30,30,3,3,31,VK_2,0x32,3,3
+KEY_3,4,ANSI_3,0x14,4,38,38,4,4,32,VK_3,0x33,4,4
+KEY_4,5,ANSI_4,0x15,5,37,37,5,5,33,VK_4,0x34,5,5
+KEY_5,6,ANSI_5,0x17,6,46,46,6,6,34,VK_5,0x35,6,6
+KEY_6,7,ANSI_6,0x16,7,54,54,7,7,35,VK_6,0x36,7,7
+KEY_7,8,ANSI_7,0x1a,8,61,61,8,8,36,VK_7,0x37,8,8
+KEY_8,9,ANSI_8,0x1c,9,62,62,9,9,37,VK_8,0x38,9,9
+KEY_9,10,ANSI_9,0x19,10,70,70,10,10,38,VK_9,0x39,10,10
+KEY_0,11,ANSI_0,0x1d,11,69,69,11,11,39,VK_0,0x30,11,11
+KEY_MINUS,12,ANSI_Minus,0x1b,12,78,78,12,12,45,VK_OEM_MINUS,0xbd,12,12
+KEY_EQUAL,13,ANSI_Equal,0x18,13,85,85,13,13,46,VK_OEM_PLUS,0xbb,13,13
+KEY_BACKSPACE,14,Delete,0x33,14,102,102,14,14,42,VK_BACK,0x08,14,14
+KEY_TAB,15,Tab,0x30,15,13,13,15,15,43,VK_TAB,0x09,15,15
+KEY_Q,16,ANSI_Q,0xc,16,21,21,16,16,20,VK_Q,0x51,16,16
+KEY_W,17,ANSI_W,0xd,17,29,29,17,17,26,VK_W,0x57,17,17
+KEY_E,18,ANSI_E,0xe,18,36,36,18,18,8,VK_E,0x45,18,18
+KEY_R,19,ANSI_R,0xf,19,45,45,19,19,21,VK_R,0x52,19,19
+KEY_T,20,ANSI_T,0x11,20,44,44,20,20,23,VK_T,0x54,20,20
+KEY_Y,21,ANSI_Y,0x10,21,53,53,21,21,28,VK_Y,0x59,21,21
+KEY_U,22,ANSI_U,0x20,22,60,60,22,22,24,VK_U,0x55,22,22
+KEY_I,23,ANSI_I,0x22,23,67,67,23,23,12,VK_I,0x49,23,23
+KEY_O,24,ANSI_O,0x1f,24,68,68,24,24,18,VK_O,0x4f,24,24
+KEY_P,25,ANSI_P,0x23,25,77,77,25,25,19,VK_P,0x50,25,25
+KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,26,84,84,26,26,47,VK_OEM_4,0xdb,26,26
+KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,27,91,91,27,27,48,VK_OEM_6,0xdd,27,27
+KEY_ENTER,28,Return,0x24,28,90,90,28,28,40,VK_RETURN,0x0d,28,28
+KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_LCONTROL,0xa2,29,29
+KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_CONTROL,0x11,29,29
+KEY_A,30,ANSI_A,0x0,30,28,28,30,30,4,VK_A,0x41,30,30
+KEY_S,31,ANSI_S,0x1,31,27,27,31,31,22,VK_S,0x53,31,31
+KEY_D,32,ANSI_D,0x2,32,35,35,32,32,7,VK_D,0x44,32,32
+KEY_F,33,ANSI_F,0x3,33,43,43,33,33,9,VK_F,0x46,33,33
+KEY_G,34,ANSI_G,0x5,34,52,52,34,34,10,VK_G,0x47,34,34
+KEY_H,35,ANSI_H,0x4,35,51,51,35,35,11,VK_H,0x48,35,35
+KEY_J,36,ANSI_J,0x26,36,59,59,36,36,13,VK_J,0x4a,36,36
+KEY_K,37,ANSI_K,0x28,37,66,66,37,37,14,VK_K,0x4b,37,37
+KEY_L,38,ANSI_L,0x25,38,75,75,38,38,15,VK_L,0x4c,38,38
+KEY_SEMICOLON,39,ANSI_Semicolon,0x29,39,76,76,39,39,51,VK_OEM_1,0xba,39,39
+KEY_APOSTROPHE,40,ANSI_Quote,0x27,40,82,82,40,40,52,VK_OEM_2,0xbf,40,40
+KEY_GRAVE,41,ANSI_Grave,0x32,41,14,14,41,41,53,VK_OEM_3,0xc0,41,41
+KEY_LEFTSHIFT,42,Shift,0x38,42,18,18,42,42,225,VK_LSHIFT,0xa0,42,42
+KEY_BACKSLASH,43,ANSI_Backslash,0x2a,43,93,93,43,43,50,VK_OEM_5,0xdc,43,43
+KEY_Z,44,ANSI_Z,0x6,44,26,26,44,44,29,VK_Z,0x5a,44,44
+KEY_X,45,ANSI_X,0x7,45,34,34,45,45,27,VK_X,0x58,45,45
+KEY_C,46,ANSI_C,0x8,46,33,33,46,46,6,VK_C,0x43,46,46
+KEY_V,47,ANSI_V,0x9,47,42,42,47,47,25,VK_V,0x56,47,47
+KEY_B,48,ANSI_B,0xb,48,50,50,48,48,5,VK_B,0x42,48,48
+KEY_N,49,ANSI_N,0x2d,49,49,49,49,49,17,VK_N,0x4e,49,49
+KEY_M,50,ANSI_M,0x2e,50,58,58,50,50,16,VK_M,0x4d,50,50
+KEY_COMMA,51,ANSI_Comma,0x2b,51,65,65,51,51,54,VK_OEM_COMMA,0xbc,51,51
+KEY_DOT,52,ANSI_Period,0x2f,52,73,73,52,52,55,VK_OEM_PERIOD,0xbe,52,52
+KEY_SLASH,53,ANSI_Slash,0x2c,53,74,74,53,53,56,VK_OEM_2,0xbf,53,53
+KEY_RIGHTSHIFT,54,RightShift,0x3c,54,89,89,54,54,229,VK_RSHIFT,0xa1,54,54
+KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,55,124,126,55,55,85,VK_MULTIPLY,0x6a,55,55
+KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_LMENU,0xa4,56,56
+KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_MENU,0x12,56,56
+KEY_SPACE,57,Space,0x31,57,41,41,57,57,44,VK_SPACE,0x20,57,57
+KEY_CAPSLOCK,58,CapsLock,0x39,58,88,20,58,58,57,VK_CAPITAL,0x14,58,58
+KEY_F1,59,F1,0x7a,59,5,7,59,59,58,VK_F1,0x70,59,59
+KEY_F2,60,F2,0x78,60,6,15,60,60,59,VK_F2,0x71,60,60
+KEY_F3,61,F3,0x63,61,4,23,61,61,60,VK_F3,0x72,61,61
+KEY_F4,62,F4,0x76,62,12,31,62,62,61,VK_F4,0x73,62,62
+KEY_F5,63,F5,0x60,63,3,39,63,63,62,VK_F5,0x74,63,63
+KEY_F6,64

[libvirt] [PATCH 4/4 V4] qemu:send-key: Implement the driver methods

2011-07-13 Thread Lai Jiangshan
qemu driver just accept xt_kbd codeset's keycode, so the lib virtkey
is used for translating keycodes from other codesets.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu_driver.c   |   71 ++
 src/qemu/qemu_monitor.c  |   17 ++
 src/qemu/qemu_monitor.h  |5 +++
 src/qemu/qemu_monitor_json.c |   15 +
 src/qemu/qemu_monitor_json.h |5 +++
 src/qemu/qemu_monitor_text.c |   49 +
 src/qemu/qemu_monitor_text.h |5 +++
 7 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0ea182d..c93885b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -87,6 +87,7 @@
 #include configmake.h
 #include threadpool.h
 #include locking/lock_manager.h
+#include virtkey.h
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -1843,6 +1844,75 @@ cleanup:
 return ret;
 }
 
+static int qemuDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int *keycodes,
+ int nkeycodes,
+ unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+/* translate the keycode to XT_KBD for qemu driver */
+if (codeset != VIR_KEYCODE_SET_XT_KBD) {
+int i;
+int keycode;
+
+for (i = 0; i  nkeycodes; i++) {
+keycode = virTranslateKeyCode(codeset, VIR_KEYCODE_SET_XT_KBD,
+  keycodes[i]);
+if (keycode  0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR, can not translate 
+keycode %u of %s codeset to xt_kbd codeset 
+keycode, keycodes[i],
+virKeycodeSetTypeToString(codeset));
+return -1;
+}
+keycodes[i] = keycode;
+}
+}
+
+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;
+}
+
+priv = vm-privateData;
+
+if (qemuDomainObjBeginJobWithDriver(driver, vm)  0)
+goto cleanup;
+
+if (!virDomainObjIsActive(vm)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID,
+%s, _(domain is not running));
+goto cleanup;
+}
+
+qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ret = qemuMonitorSendKey(priv-mon, holdtime, keycodes, nkeycodes);
+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)
 {
@@ -8646,6 +8716,7 @@ static virDriver qemuDriver = {
 .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */
 .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
+.domainSendKey = qemuDomainSendKey, /* 0.9.3 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index e593642..35fb999 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2398,6 +2398,23 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
 return ret;
 }
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int holdtime,
+   unsigned int *keycodes,
+   unsigned int nkeycodes)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, holdtime=%u, nkeycodes=%u,
+  mon, holdtime, nkeycodes);
+
+if (mon-json)
+ret = qemuMonitorJSONSendKey(mon, holdtime, keycodes, nkeycodes);
+else
+ret = qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes);
+return ret;
+}
+
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 893f3e9..73a95f1 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -444,6 +444,11 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon);
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file);
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int holdtime,
+   unsigned int *keycodes,
+   unsigned int nkeycodes);
+
 /**
  * When running two dd process

Re: [libvirt] [PATCH 1/3 V3] lib: add virtkey

2011-06-27 Thread Lai Jiangshan
On 06/24/2011 09:18 PM, Daniel P. Berrange wrote:
 On Fri, Jun 24, 2011 at 02:33:29PM +0800, Lai Jiangshan wrote:
 Add virtkey lib for usage-improvment and keycode translating.
 Add 4 internal API for the aim

 const char *virKeycodeSetName(virKeycodeSet codeset);
 virKeycodeSet virParseKeycodeSet(const char *name);
 
 These should just be done using the standard VIR_ENUM_DECL/IMPL macros.
 
 diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
 index 3f634e6..2f2efe7 100644
 --- a/include/libvirt/libvirt.h.in
 +++ b/include/libvirt/libvirt.h.in
 @@ -1815,6 +1815,12 @@ typedef enum {
  VIR_KEYCODE_SET_ATSET1 = 2,
  VIR_KEYCODE_SET_ATSET2 = 3,
  VIR_KEYCODE_SET_ATSET3 = 4,
 +VIR_KEYCODE_SET_OSX= 5,
 +VIR_KEYCODE_SET_XT_KBD = 6,
 +VIR_KEYCODE_SET_USB= 7,
 +VIR_KEYCODE_SET_WIN32  = 8,
 +VIR_KEYCODE_SET_XWIN_XT= 9,
 +VIR_KEYCODE_SET_XFREE86_KBD_XT = 10,
  } virKeycodeSet;
 
 IMHO, we don't really need to include the XT_KBD, XWIN_XT or
 XFREE86_KBD_XT codesets, since these are all special purpose
 sets which are just derived from the based XT set. Lets just
 stick to the core interesting sets. So add OSX, USB and WIN32
 only.

I found qemu monitor just accept XT_KBD, not XT, maybe I'm wrong.

 
 diff --git a/src/util/virtkey.c b/src/util/virtkey.c
 new file mode 100644
 index 000..48fbfcc
 --- /dev/null
 +++ b/src/util/virtkey.c
 @@ -0,0 +1,633 @@
 +
 +/*
 + * Copyright (c) 2011 Lai Jiangshan
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms of the GNU General Public License version 2 as published 
 by
 + * the Free Software Foundation.
 + */
 +
 +#include config.h
 +#include string.h
 +#include stddef.h
 +#include libvirt/libvirt.h
 +#include virtkey.h
 +
 +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
 +#define getfield(object, field_type, field_offset) \
 +(*(typeof(field_type) *)((char *)(object) + field_offset))
 +
 +struct keycode {
 +const char *linux_name;
 +const char *os_x_name;
 +const char *win32_name;
 +unsigned short linux_keycode;
 +unsigned short xt;
 +unsigned short atset1;
 +unsigned short atset2;
 +unsigned short atset3;
 +unsigned short os_x;
 +unsigned short xt_kbd;
 +unsigned short usb;
 +unsigned short win32;
 +unsigned short xwin_xt;
 +unsigned short xfree86_kbd_xt;
 +};
 +
 +/*
 + * generated from http://git.gnome.org/browse/gtk-vnc/plain/src/keymaps.csv
 + * script:
 + *
 + * #!/bin/python
 + * import sys
 + * import re
 + *
 + * for line in sys.stdin.xreadlines():
 + * a = re.match(([^,]*), * 13 + ([^,]*)$, line[0:-1]).groups()
 + * b = 
 + * for i in (0,2,10,1,7,4,5,6,3,8,9,11,12,13):
 + * if i in (0, 2, 10):
 + * b = b + (a[i] and ('' + a[i] + '') or 'NULL') + ','
 + * else:
 + * b = b + (a[i] or '0') + ','
 + * print {  + b + },
 + */
 
 One of the goals of having the keymap data in the CSV file was that
 it makes it trivially updatable across apps using it, without making
 code changes. In fact my goal is to actually put 'keymaps.csv' and
 'keymaps.pl' into a separate shared package at some point. So rather
 than hardcoding this giant array in libvirt, just include the GTK-VNC
 keymaps.csv and keymaps.pl file as-is, and run them to generate the
 mapping tables for combinations we need.
 
 NB, keymaps.pl will need to be updated to be able to output a
 table for doing string-keycode mapping since it doesn't
 do that yet. For the plain  keycode-keycode mappings though
 just use its currently functionality.

I didn't find separate git repository for  keymaps.csv.
Should I copy keymaps.csv to libvirt?

keymaps.pl need to be run O(N*N) times and it will generate O(N*N) tables
for different translating, I think that 1 table is the best, even the
table are bigger.


 
 +const char *virKeycodeSetName(virKeycodeSet codeset)
 +{
 +int i = (int)codeset;
 +
 +if (i  0 || i = ARRAY_SIZE(codesetInfo))
 +return UNKNOWN;
 +
 +return codesetInfo[i].name;
 +}
 +
 +virKeycodeSet virParseKeycodeSet(const char *name)
 +{
 +int i;
 +
 +for (i = 0; i  ARRAY_SIZE(codesetInfo); i++) {
 +if (!strcmp(codesetInfo[i].name, name))
 +return (virKeycodeSet)i;
 +}
 +
 +return (virKeycodeSet)-1;
 +}
 
 These just get replaced by VIR_ENUM_IMPL

Will do, thanks,

 
 +static int virParseKeyNameOffset(unsigned int name_offset,
 + unsigned int code_offset,
 + const char *keyname)
 +{
 +int i;
 +
 +for (i = 0; i  ARRAY_SIZE(keycodes); i++) {
 +const char *name = getfield(keycodes + i, const char *, 
 name_offset);
 +
 +if (name  !strcmp(name, keyname))
 +return getfield(keycodes + i, unsigned short, code_offset);
 +}
 +
 +return -1

[libvirt] [PATCH 0/3 V3] Add support for send keys to guest

2011-06-24 Thread Lai Jiangshan
Add virtkey lib for usage-improvment and keycode translating.
Expose send-key in virsh
Implement send-key function for the qemu driver

Lai Jiangshan (3):
  lib: add virtkey
  send-key: Expose the new API in virsh
  qemu:send-key: Implement the driver methods

 include/libvirt/libvirt.h.in |6 +
 src/Makefile.am  |3 +-
 src/libvirt_private.syms |5 +
 src/qemu/qemu_driver.c   |   51 
 src/qemu/qemu_monitor.c  |   37 +++
 src/qemu/qemu_monitor.h  |6 +
 src/qemu/qemu_monitor_json.c |   15 +
 src/qemu/qemu_monitor_json.h |5 +
 src/qemu/qemu_monitor_text.c |   49 
 src/qemu/qemu_monitor_text.h |5 +
 src/util/virtkey.c   |  633 ++
 src/util/virtkey.h   |   21 ++
 tools/virsh.c|   94 +++
 tools/virsh.pod  |4 +
 14 files changed, 933 insertions(+), 1 deletions(-)
 create mode 100644 src/util/virtkey.c
 create mode 100644 src/util/virtkey.h

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/3 V3] send-key: Expose the new API in virsh

2011-06-24 Thread Lai Jiangshan
Also support string names for the linux keycode(auto detect).

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |   93 +++
 tools/virsh.pod |4 ++
 2 files changed, 97 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index a1e2f83..d7fb8a6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -3263,6 +3263,98 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * send-key command
+ */
+static const vshCmdInfo info_send_key[] = {
+{help, N_(Send keycodes to the guest)},
+{desc, N_(Send keycodes to the guest, the keycodes must be integers\n
+Examples:\n\n
+virsh # send-key domain 37 18 21\n
+virsh # send-key domain KEY_RIGHTCTRL KEY_C\n
+virsh # send-key domain --codeset xt 37 18 21\n
+virsh # send-key domain --holdtime 1000 0x15 18 
0xf\n
+)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_send_key[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{codeset, VSH_OT_STRING, VSH_OFLAG_REQ_OPT, N_(the codeset of keycodes, 
default:linux)},
+{holdtime, VSH_OT_INT, VSH_OFLAG_REQ_OPT,
+ N_(the time (in millsecond) how long the keys will be 
held)},
+{keycode, VSH_OT_ARGV, VSH_OFLAG_REQ, N_(the key code)},
+{NULL, 0, 0, NULL}
+};
+
+static int get_integer_keycode(const char *key_name)
+{
+long val;
+char *endptr;
+
+val = strtol(key_name, endptr, 0);
+if (*endptr != '\0' || val  0x || val = 0)
+ return -1;
+
+return val;
+}
+
+static bool
+cmdSendKey(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = false;
+const char *codeset_option;
+int codeset;
+int holdtime;
+int count = 0;
+const vshCmdOpt *opt = NULL;
+int keycode;
+unsigned int keycodes[VIR_DOMAIN_SEND_KEY_MAX_KEYS];
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (vshCommandOptString(cmd, codeset, codeset_option) = 0)
+codeset_option = linux;
+
+if (vshCommandOptInt(cmd, holdtime, holdtime) = 0)
+holdtime = 0;
+
+codeset = virParseKeycodeSet(codeset_option);
+if ((int)codeset  0) {
+vshError(ctl, _(unknown codeset: '%s'), codeset_option);
+goto cleanup;
+}
+
+while ((opt = vshCommandOptArgv(cmd, opt))) {
+if (count == VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
+vshError(ctl, _(too many keycodes));
+goto cleanup;
+}
+
+if ((keycode = get_integer_keycode(opt-data)) = 0) {
+if ((keycode = virParseKeyName(codeset, opt-data)) = 0) {
+vshError(ctl, _(invalid keycode: '%s'), opt-data);
+goto cleanup;
+}
+}
+
+keycodes[count] = keycode;
+count++;
+}
+
+if (!(virDomainSendKey(dom, codeset, holdtime, keycodes, count, 0)  0))
+ret = true;
+
+cleanup:
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * setmemory command
  */
 static const vshCmdInfo info_setmem[] = {
@@ -11672,6 +11764,7 @@ static const vshCmdDef domManagementCmds[] = {
 {dumpxml, cmdDumpXML, opts_dumpxml, info_dumpxml, 0},
 {edit, cmdEdit, opts_edit, info_edit, 0},
 {inject-nmi, cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0},
+{send-key, cmdSendKey, opts_send_key, info_send_key},
 {managedsave, cmdManagedSave, opts_managedsave, info_managedsave, 0},
 {managedsave-remove, cmdManagedSaveRemove, opts_managedsaveremove,
  info_managedsaveremove, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 023ab42..50c4800 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -308,6 +308,10 @@ scheduling by the hypervisor.
 
 Inject NMI to the guest
 
+=item Bsend-key Idomain-id optional I--codeset Bcodeset optional 
I--holdtime Bholdtime Bkeycode...
+
+Send keys to the guest
+
 =item Bshutdown
 
 The domain is in the process of shutting down, i.e. the guest operating system
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 3/3 V3] qemu:send-key: Implement the driver methods

2011-06-24 Thread Lai Jiangshan
qemu driver just accept xt_kbd codeset's keycode, so the lib virtkey
is used for translating keycodes from other codesets.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu_driver.c   |   51 ++
 src/qemu/qemu_monitor.c  |   37 ++
 src/qemu/qemu_monitor.h  |6 +
 src/qemu/qemu_monitor_json.c |   15 
 src/qemu/qemu_monitor_json.h |5 
 src/qemu/qemu_monitor_text.c |   49 
 src/qemu/qemu_monitor_text.h |5 
 7 files changed, 168 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 01587e8..994d7bd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1761,6 +1761,56 @@ cleanup:
 return ret;
 }
 
+static int qemuDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int *keycodes,
+ int nkeycodes,
+ unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+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;
+}
+
+priv = vm-privateData;
+
+if (qemuDomainObjBeginJobWithDriver(driver, vm)  0)
+goto cleanup;
+
+if (!virDomainObjIsActive(vm)) {
+qemuReportError(VIR_ERR_OPERATION_INVALID,
+%s, _(domain is not running));
+goto cleanup;
+}
+
+qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ret = qemuMonitorSendKey(priv-mon, codeset, holdtime, keycodes, 
nkeycodes);
+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)
 {
@@ -8436,6 +8486,7 @@ static virDriver qemuDriver = {
 .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */
 .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
+.domainSendKey = qemuDomainSendKey, /* 0.9.3 */
 .domainBlockPull = qemuDomainBlockPull, /* 0.9.3 */
 .domainBlockPullAll = qemuDomainBlockPullAll, /* 0.9.3 */
 .domainBlockPullAbort = qemuDomainBlockPullAbort, /* 0.9.3 */
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 89a3f64..e14703b 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -36,6 +36,7 @@
 #include memory.h
 #include logging.h
 #include files.h
+#include virtkey.h
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -2369,6 +2370,42 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
 return ret;
 }
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int *keycodes,
+   unsigned int nkeycodes)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, codeset=%s(%u), holdtime=%u, nkeycodes=%u,
+  mon, virKeycodeSetName(codeset), codeset, holdtime, nkeycodes);
+
+if (codeset != VIR_KEYCODE_SET_XT_KBD) {
+int i;
+int keycode;
+
+for (i = 0; i  nkeycodes; i++) {
+keycode = virTranslateKeyCode(codeset, VIR_KEYCODE_SET_XT_KBD,
+  keycodes[i]);
+if (keycode  0) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR, can not translate 
+keycode %u of %s codeset to xt_kbd codeset 
+keycode, keycodes[i],
+virKeycodeSetName(codeset));
+return -1;
+}
+keycodes[i] = keycode;
+}
+}
+
+if (mon-json)
+ret = qemuMonitorJSONSendKey(mon, holdtime, keycodes, nkeycodes);
+else
+ret = qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes);
+return ret;
+}
+
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 3bb0269..ed80c4b 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -462,6 +462,12 @@ int qemuMonitorBlockPull(qemuMonitorPtr mon,
  virDomainBlockPullInfoPtr info,
  int

[libvirt] [PATCH 1/3 V3] lib: add virtkey

2011-06-24 Thread Lai Jiangshan
Add virtkey lib for usage-improvment and keycode translating.
Add 4 internal API for the aim

const char *virKeycodeSetName(virKeycodeSet codeset);
virKeycodeSet virParseKeycodeSet(const char *name);
int virParseKeyName(virKeycodeSet codeset, const char *keyname);
int virTranslateKeyCode(virKeycodeSet from_codeset,
virKeycodeSet to_offset,
int key_value);

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in |6 +
 src/Makefile.am  |3 +-
 src/libvirt_private.syms |5 +
 src/util/virtkey.c   |  633 ++
 src/util/virtkey.h   |   21 ++
 tools/virsh.c|1 +
 6 files changed, 668 insertions(+), 1 deletions(-)
 create mode 100644 src/util/virtkey.c
 create mode 100644 src/util/virtkey.h

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 3f634e6..2f2efe7 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1815,6 +1815,12 @@ typedef enum {
 VIR_KEYCODE_SET_ATSET1 = 2,
 VIR_KEYCODE_SET_ATSET2 = 3,
 VIR_KEYCODE_SET_ATSET3 = 4,
+VIR_KEYCODE_SET_OSX= 5,
+VIR_KEYCODE_SET_XT_KBD = 6,
+VIR_KEYCODE_SET_USB= 7,
+VIR_KEYCODE_SET_WIN32  = 8,
+VIR_KEYCODE_SET_XWIN_XT= 9,
+VIR_KEYCODE_SET_XFREE86_KBD_XT = 10,
 } virKeycodeSet;
 
 /**
diff --git a/src/Makefile.am b/src/Makefile.am
index 4f9bfc9..e34ea74 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -81,7 +81,8 @@ UTIL_SOURCES =
\
util/util.c util/util.h \
util/xml.c util/xml.h   \
util/virtaudit.c util/virtaudit.h   \
-   util/virterror.c util/virterror_internal.h
+   util/virterror.c util/virterror_internal.hi \
+   util/virtkey.c util/virtkey.h
 
 EXTRA_DIST += util/threads-pthread.c util/threads-win32.c
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 09b0159..151e256 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1059,6 +1059,11 @@ virSetError;
 virSetErrorLogPriorityFunc;
 virStrerror;
 
+# virtkey.h
+virKeycodeSetName;
+virParseKeycodeSet;
+virParseKeyName;
+virTranslateKeyCode;
 
 # xml.h
 virXMLParseFileHelper;
diff --git a/src/util/virtkey.c b/src/util/virtkey.c
new file mode 100644
index 000..48fbfcc
--- /dev/null
+++ b/src/util/virtkey.c
@@ -0,0 +1,633 @@
+
+/*
+ * Copyright (c) 2011 Lai Jiangshan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include config.h
+#include string.h
+#include stddef.h
+#include libvirt/libvirt.h
+#include virtkey.h
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
+#define getfield(object, field_type, field_offset) \
+(*(typeof(field_type) *)((char *)(object) + field_offset))
+
+struct keycode {
+const char *linux_name;
+const char *os_x_name;
+const char *win32_name;
+unsigned short linux_keycode;
+unsigned short xt;
+unsigned short atset1;
+unsigned short atset2;
+unsigned short atset3;
+unsigned short os_x;
+unsigned short xt_kbd;
+unsigned short usb;
+unsigned short win32;
+unsigned short xwin_xt;
+unsigned short xfree86_kbd_xt;
+};
+
+/*
+ * generated from http://git.gnome.org/browse/gtk-vnc/plain/src/keymaps.csv
+ * script:
+ *
+ * #!/bin/python
+ * import sys
+ * import re
+ *
+ * for line in sys.stdin.xreadlines():
+ * a = re.match(([^,]*), * 13 + ([^,]*)$, line[0:-1]).groups()
+ * b = 
+ * for i in (0,2,10,1,7,4,5,6,3,8,9,11,12,13):
+ * if i in (0, 2, 10):
+ * b = b + (a[i] and ('' + a[i] + '') or 'NULL') + ','
+ * else:
+ * b = b + (a[i] or '0') + ','
+ * print {  + b + },
+ */
+static struct keycode keycodes[] = {
+{ KEY_RESERVED,NULL,NULL,0,0,0,0,0,0,0,0,0,0,0,},
+{ KEY_ESC,Escape,VK_ESCAPE,1,1,1,118,8,0x35,1,41,0x1b,1,1,},
+{ KEY_1,ANSI_1,VK_1,2,2,2,22,22,0x12,2,30,0x31,2,2,},
+{ KEY_2,ANSI_2,VK_2,3,3,3,30,30,0x13,3,31,0x32,3,3,},
+{ KEY_3,ANSI_3,VK_3,4,4,4,38,38,0x14,4,32,0x33,4,4,},
+{ KEY_4,ANSI_4,VK_4,5,5,5,37,37,0x15,5,33,0x34,5,5,},
+{ KEY_5,ANSI_5,VK_5,6,6,6,46,46,0x17,6,34,0x35,6,6,},
+{ KEY_6,ANSI_6,VK_6,7,7,7,54,54,0x16,7,35,0x36,7,7,},
+{ KEY_7,ANSI_7,VK_7,8,8,8,61,61,0x1a,8,36,0x37,8,8,},
+{ KEY_8,ANSI_8,VK_8,9,9,9,62,62,0x1c,9,37,0x38,9,9,},
+{ KEY_9,ANSI_9,VK_9,10,10,10,70,70,0x19,10,38,0x39,10,10,},
+{ KEY_0,ANSI_0,VK_0,11,11,11,69,69,0x1d,11,39,0x30,11,11,},
+{ 
KEY_MINUS,ANSI_Minus,VK_OEM_MINUS,12,12,12,78,78,0x1b,12,45,0xbd,12,12,},
+{ 
KEY_EQUAL,ANSI_Equal,VK_OEM_PLUS

[libvirt] [PATCH] virsh: add custom readline generator

2011-06-24 Thread Lai Jiangshan
Custom readline generator will help for some usecase.

Also add a custom readline generator for the help command.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
diff --git a/tools/virsh.c b/tools/virsh.c
index fcd254d..51e43c1 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -13575,7 +13575,7 @@ vshCloseLogFile(vshControl *ctl)
  * (i.e. STATE == 0), then we start at the top of the list.
  */
 static char *
-vshReadlineCommandGenerator(const char *text, int state)
+vshReadlineCmdAndGrpGenerator(const char *text, int state, int grpname)
 {
 static int grp_list_index, cmd_list_index, len;
 const char *name;
@@ -13604,8 +13604,13 @@ vshReadlineCommandGenerator(const char *text, int 
state)
 return vshStrdup(NULL, name);
 }
 } else {
+name = grp[grp_list_index].keyword;
 cmd_list_index = 0;
 grp_list_index++;
+
+if (grpname  STREQLEN(name, text, len))
+return vshStrdup(NULL, name);
+
 }
 }
 
@@ -13614,10 +13619,45 @@ vshReadlineCommandGenerator(const char *text, int 
state)
 }
 
 static char *
+vshReadlineCommandGenerator(const char *text, int state)
+{
+   return vshReadlineCmdAndGrpGenerator(text, state, 0);
+}
+
+static char *
+vshReadlineHelpOptionGenerator(const char *text, int state)
+{
+   return vshReadlineCmdAndGrpGenerator(text, state, 1);
+}
+
+struct vshCustomReadLine {
+   const char *name;
+   char *(*CustomReadLineOptionGenerator)(const char *text, int state);
+};
+
+struct vshCustomReadLine customeReadLine[] = {
+   { help, vshReadlineHelpOptionGenerator },
+   { NULL, NULL }
+};
+
+static struct vshCustomReadLine *vshCustomReadLineSearch(const char *name)
+{
+struct vshCustomReadLine *ret = customeReadLine;
+
+for (ret = customeReadLine; ret-name; ret++) {
+if (STREQ(ret-name, name))
+return ret;
+}
+
+return NULL;
+}
+
+static char *
 vshReadlineOptionsGenerator(const char *text, int state)
 {
 static int list_index, len;
 static const vshCmdDef *cmd = NULL;
+static const struct vshCustomReadLine *rl = NULL;
 const char *name;
 
 if (!state) {
@@ -13632,6 +13672,7 @@ vshReadlineOptionsGenerator(const char *text, int state)
 memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
 
 cmd = vshCmddefSearch(cmdname);
+rl = vshCustomReadLineSearch(cmdname);
 list_index = 0;
 len = strlen(text);
 VIR_FREE(cmdname);
@@ -13640,6 +13681,9 @@ vshReadlineOptionsGenerator(const char *text, int state)
 if (!cmd)
 return NULL;
 
+if (rl)
+return rl-CustomReadLineOptionGenerator(text, state);
+
 if (!cmd-opts)
 return NULL;
 

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 05/10 V2] [PATCH 05/13] send-key: Defining the public API

2011-06-07 Thread Lai Jiangshan
Add public virDomainSendKey() and enum libvirt_keycode_set
for the @codeset.

Python version of virDomainSendKey() has not been implemented yet,
it will be done soon.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 include/libvirt/libvirt.h.in |7 +++
 include/libvirt/virtkeys.h   |   22 ++
 python/generator.py  |1 +
 src/libvirt_public.syms  |5 +
 4 files changed, 35 insertions(+), 0 deletions(-)
 create mode 100644 include/libvirt/virtkeys.h

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index df213f1..94da205 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2673,6 +2673,13 @@ typedef struct _virTypedParameter virMemoryParameter;
  */
 typedef virMemoryParameter *virMemoryParameterPtr;
 
+int virDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int *keycodes,
+ unsigned int nkeycodes,
+ unsigned int flags);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/libvirt/virtkeys.h b/include/libvirt/virtkeys.h
new file mode 100644
index 000..854594a
--- /dev/null
+++ b/include/libvirt/virtkeys.h
@@ -0,0 +1,22 @@
+#ifndef _LIBVIRT_VIRTKEYS_H
+#define _LIBVIRT_VIRTKEYS_H
+
+/*
+ * Copyright (c) 2011 Lai Jiangshan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+enum libvirt_keycode_set {
+LIBVIRT_KEYCODE_LINUX  = 0,
+LIBVIRT_KEYCODE_XT = 1,
+LIBVIRT_KEYCODE_ATSET1 = 2,
+LIBVIRT_KEYCODE_ATSET2 = 3,
+LIBVIRT_KEYCODE_ATSET3 = 4,
+};
+
+#define MAX_SEND_KEY  16
+
+#endif
diff --git a/python/generator.py b/python/generator.py
index 7c38fdd..57373f0 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -356,6 +356,7 @@ skip_impl = (
 'virNodeDeviceListCaps',
 'virConnectBaselineCPU',
 'virDomainRevertToSnapshot',
+'virDomainSendKey',
 )
 
 
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 4d4299a..ddfed44 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -450,4 +450,9 @@ LIBVIRT_0.9.2 {
 virInterfaceChangeRollback;
 } LIBVIRT_0.9.0;
 
+LIBVIRT_0.9.3 {
+global:
+virDomainSendKey;
+} LIBVIRT_0.9.2;
+
 #  define new API here using predicted next version number 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 02/10 V2] improve the iteration of VSH_OT_ARGV options

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c |   47 ---
 1 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 61eb11e..638029c 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -280,7 +280,27 @@ static int vshCommandOptULongLong(const vshCmd *cmd, const 
char *name,
   unsigned long long *value)
 ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
 static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
-static char *vshCommandOptArgv(const vshCmd *cmd, int count);
+
+/*
+ * Iterate all the argv arguments.
+ *
+ * Requires that a VSH_OT_ARGV option  be last in the
+ * list of supported options in CMD-def-opts.
+ */
+static inline const vshCmdOpt *__variable_arg(const vshCmdOpt *opt)
+{
+while (opt) {
+ if (opt-def  opt-def-type == VSH_OT_ARGV)
+ break;
+ opt = opt-next;
+}
+
+return opt;
+}
+
+#define for_each_variable_arg(cmd, opt)   \
+for (opt = __variable_arg(cmd-opts); opt; opt = __variable_arg(opt-next))
+
 
 #define VSH_BYID (1  1)
 #define VSH_BYUUID   (1  2)
@@ -10341,6 +10361,7 @@ cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd 
*cmd)
 bool shell = false;
 bool xml = false;
 int count = 0;
+const vshCmdOpt *opt;
 char *arg;
 virBuffer buf = VIR_BUFFER_INITIALIZER;
 
@@ -10349,10 +10370,11 @@ cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const 
vshCmd *cmd)
 if (vshCommandOptBool(cmd, xml))
 xml = true;
 
-while ((arg = vshCommandOptArgv(cmd, count)) != NULL) {
+for_each_variable_arg(cmd, opt) {
 bool close_quote = false;
 char *q;
 
+arg = opt-data;
 if (count)
 virBufferAddChar(buf, ' ');
 /* Add outer '' only if arg included shell metacharacters.  */
@@ -11803,27 +11825,6 @@ vshCommandOptBool(const vshCmd *cmd, const char *name)
 return vshCommandOpt(cmd, name) != NULL;
 }
 
-/*
- * Returns the COUNT argv argument, or NULL after last argument.
- *
- * Requires that a VSH_OT_ARGV option with the name  be last in the
- * list of supported options in CMD-def-opts.
- */
-static char *
-vshCommandOptArgv(const vshCmd *cmd, int count)
-{
-vshCmdOpt *opt = cmd-opts;
-
-while (opt) {
-if (opt-def  opt-def-type == VSH_OT_ARGV) {
-if (count-- == 0)
-return opt-data;
-}
-opt = opt-next;
-}
-return NULL;
-}
-
 /* Determine whether CMD-opts includes an option with name OPTNAME.
If not, give a diagnostic and return false.
If so, return true.  */
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 00/10 V2] Add support for send keys to guest

2011-06-07 Thread Lai Jiangshan
Add API virDomainSendKey() and virsh send-key command.

PATCH 01~04 prepare
PATCH 05~10 Add support for send keys to guest

Python version of virDomainSendKey() has not been implemented yet,
it will be done soon.

Some usage-improvment patches will be sent later(after these 10 are applied)
these usage-improvment patches does not touch any APIs
nor change the behaviors:
   support KEY_XXX names for the linux keycode for virsh command(auto detect),
   translate keycodes between different codesets,
   ...etc.


Lai Jiangshan (10):
  allow name for VSH_OT_ARGV options
  improve the iteration of VSH_OT_ARGV options
  add VSH_OFLAG_REQ_OPT options
  remote generator: Handle (unsigned) int arrays
  send-key: Defining the public API
  send-key: Defining the internal API
  send-key: Implementing the public API
  send-key: Implementing the remote protocol
  send-key: Expose the new API in virsh
  qemu:send-key: Implement the driver methods

 daemon/remote_generator.pl   |   17 
 include/libvirt/libvirt.h.in |7 ++
 include/libvirt/virtkeys.h   |   22 +
 python/generator.py  |1 +
 src/driver.h |8 ++
 src/libvirt.c|   63 +++
 src/libvirt_public.syms  |5 +
 src/qemu/qemu_driver.c   |   50 
 src/qemu/qemu_monitor.c  |   27 +++
 src/qemu/qemu_monitor.h  |6 ++
 src/qemu/qemu_monitor_json.c |   15 
 src/qemu/qemu_monitor_json.h |5 +
 src/qemu/qemu_monitor_text.c |   47 +++
 src/qemu/qemu_monitor_text.h |5 +
 src/remote/remote_driver.c   |1 +
 src/remote/remote_protocol.x |   16 -
 src/remote_protocol-structs  |   11 +++
 tools/virsh.c|  175 +++---
 tools/virsh.pod  |4 +
 19 files changed, 455 insertions(+), 30 deletions(-)
 create mode 100644 include/libvirt/virtkeys.h

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 04/10 V2] remote generator: Handle (unsigned) int arrays

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 daemon/remote_generator.pl |   17 +
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl
index 632972c..532fe63 100755
--- a/daemon/remote_generator.pl
+++ b/daemon/remote_generator.pl
@@ -407,6 +407,13 @@ elsif ($opt_b) {
 }
 
 push(@args_list, args-$2.$2_len);
+} elsif ($args_member =~ m/^(?:unsigned )?int (\S+)\S+;/) {
+if (! @args_list) {
+push(@args_list, conn);
+}
+
+push(@args_list, args-$1.$1_val);
+push(@args_list, args-$1.$1_len);
 } elsif ($args_member =~ m/^remote_typed_param (\S+)(\S+);/) 
{
 push(@vars_list, virTypedParameterPtr $1 = NULL);
 push(@vars_list, int n$1);
@@ -985,6 +992,16 @@ elsif ($opt_k) {
 push(@setters_list, args.$arg_name.${arg_name}_val = 
(char *)$arg_name;);
 push(@setters_list, args.$arg_name.${arg_name}_len = 
${arg_name}len;);
 push(@args_check_list, { name = \$arg_name\, arg = 
${arg_name}len, limit = $limit });
+} elsif ($args_member =~ m/^((?:unsigned )?int) 
(\S+)(\S+);/) {
+my $type_name = $1;
+my $arg_name = $2;
+my $limit = $3;
+
+push(@args_list, ${type_name} *$arg_name);
+push(@args_list, unsigned int ${arg_name}len);
+push(@setters_list, args.$arg_name.${arg_name}_val = 
$arg_name;);
+push(@setters_list, args.$arg_name.${arg_name}_len = 
${arg_name}len;);
+push(@args_check_list, { name = \$arg_name\, arg = 
${arg_name}len, limit = $limit });
 } elsif ($args_member =~ m/^remote_typed_param (\S+)(\S+);/) 
{
 push(@args_list, virTypedParameterPtr $1);
 push(@args_list, int n$1);
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 09/10 V2] send-key: Expose the new API in virsh

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |  102 +++
 tools/virsh.pod |4 ++
 2 files changed, 106 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index d13c12b..7b5847f 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -33,6 +33,8 @@
 #include signal.h
 #include poll.h
 
+#include libvirt/virtkeys.h
+
 #include libxml/parser.h
 #include libxml/tree.h
 #include libxml/xpath.h
@@ -3182,6 +3184,105 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * send-key command
+ */
+static const vshCmdInfo info_send_key[] = {
+{help, N_(Send keycodes to the guest)},
+{desc, N_(Send keycodes to the guest, the keycodes must be integers\n
+Examples:\n\n
+virsh # send-key domain 37 18 21\n
+virsh # send-key domain --holdtime 1000 0x15 18 
0xf\n
+)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_send_key[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{codeset, VSH_OT_STRING, VSH_OFLAG_REQ_OPT, N_(the codeset of keycodes, 
default:linux)},
+{holdtime, VSH_OT_INT, VSH_OFLAG_REQ_OPT,
+ N_(the time (in millsecond) how long the keys will be 
held)},
+{keycode, VSH_OT_ARGV, VSH_OFLAG_REQ, N_(the key code)},
+{NULL, 0, 0, NULL}
+};
+
+static int get_integer_keycode(const char *key_name)
+{
+long val;
+char *endptr;
+
+val = strtol(key_name, endptr, 0);
+if (*endptr != '\0' || val  255 || val = 0)
+ return -1;
+
+return val;
+}
+
+static bool
+cmdSendKey(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = false;
+const char *codeset_option;
+int codeset;
+int holdtime;
+int count = 0;
+const vshCmdOpt *opt;
+int keycode;
+unsigned int keycodes[MAX_SEND_KEY];
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (vshCommandOptString(cmd, codeset, codeset_option) = 0)
+codeset_option = default;
+
+if (vshCommandOptInt(cmd, holdtime, holdtime) = 0)
+holdtime = 0;
+
+if (STREQ(codeset_option, default) || STREQ(codeset_option, linux)) {
+codeset = LIBVIRT_KEYCODE_LINUX;
+} else if (STREQ(codeset_option, xt)) {
+codeset = LIBVIRT_KEYCODE_XT;
+} else if (STREQ(codeset_option, atset1)) {
+codeset = LIBVIRT_KEYCODE_ATSET1;
+} else if (STREQ(codeset_option, atset2)) {
+codeset = LIBVIRT_KEYCODE_ATSET2;
+} else if (STREQ(codeset_option, atset3)) {
+codeset = LIBVIRT_KEYCODE_ATSET3;
+} else {
+vshError(ctl, _(unknown codeset: '%s'), codeset_option);
+goto free_domain;
+}
+
+for_each_variable_arg(cmd, opt) {
+if (count == MAX_SEND_KEY) {
+vshError(ctl, _(too many keycode));
+goto free_domain;
+}
+
+if ((keycode = get_integer_keycode(opt-data))  0)
+goto get_keycode;
+
+vshError(ctl, _(invalid keycode: '%s'), opt-data);
+goto free_domain;
+
+get_keycode:
+keycodes[count] = keycode;
+count++;
+}
+
+if (!(virDomainSendKey(dom, codeset, holdtime, keycodes, count, 0)  0))
+ret = true;
+
+free_domain:
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * setmemory command
  */
 static const vshCmdInfo info_setmem[] = {
@@ -11095,6 +11196,7 @@ static const vshCmdDef domManagementCmds[] = {
 {dumpxml, cmdDumpXML, opts_dumpxml, info_dumpxml, 0},
 {edit, cmdEdit, opts_edit, info_edit, 0},
 {inject-nmi, cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0},
+{send-key, cmdSendKey, opts_send_key, info_send_key},
 {managedsave, cmdManagedSave, opts_managedsave, info_managedsave, 0},
 {managedsave-remove, cmdManagedSaveRemove, opts_managedsaveremove,
  info_managedsaveremove, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 7ed3003..03b1418 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -296,6 +296,10 @@ scheduling by the hypervisor.
 
 Inject NMI to the guest
 
+=item Bsend-key Idomain-id I--codeset Bcodeset I--holdtime 
Bholdtime Bkeycode...
+
+Send keys to the guest
+
 =item Bshutdown
 
 The domain is in the process of shutting down, i.e. the guest operating system
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 06/10 V2] send-key: Defining the internal API

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/driver.h |8 
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/src/driver.h b/src/driver.h
index 5df798a..2e335a1 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -542,6 +542,13 @@ typedef int
 typedef int
 (*virDrvDomainInjectNMI)(virDomainPtr dom, unsigned int flags);
 
+typedef int
+(*virDrvDomainSendKey)(virDomainPtr dom, unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int *keycodes,
+   unsigned int nkeycodes,
+   unsigned int flags);
+
 typedef char *
 (*virDrvDomainMigrateBegin3)
 (virDomainPtr domain,
@@ -749,6 +756,7 @@ struct _virDriver {
 virDrvDomainMigratePerform3domainMigratePerform3;
 virDrvDomainMigrateFinish3 domainMigrateFinish3;
 virDrvDomainMigrateConfirm3domainMigrateConfirm3;
+virDrvDomainSendKey domainSendKey;
 };
 
 typedef int
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 01/10 V2] allow name for VSH_OT_ARGV options

2011-06-07 Thread Lai Jiangshan
A name will improve the usege, example

# virsh help echo
  NAME
echo - echo arguments

  SYNOPSIS
echo [--shell] [--xml] [string]...

  DESCRIPTION
Echo back arguments, possibly with quoting.

  OPTIONS
--shell  escape for shell use
--xmlescape for XML use
string arguments to echo

[string]... is added to SYNOPSIS.
string arguments to echo is added to OPTIONS.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c |   19 +--
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index d98be1c..61eb11e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -126,7 +126,7 @@ typedef enum {
 VSH_OT_STRING,   /* optional string option */
 VSH_OT_INT,  /* optional or mandatory int option */
 VSH_OT_DATA, /* string data (as non-option) */
-VSH_OT_ARGV  /* remaining arguments, opt-name should be  */
+VSH_OT_ARGV  /* remaining arguments */
 } vshCmdOptType;
 
 /*
@@ -10328,7 +10328,7 @@ static const vshCmdInfo info_echo[] = {
 static const vshCmdOptDef opts_echo[] = {
 {shell, VSH_OT_BOOL, 0, N_(escape for shell use)},
 {xml, VSH_OT_BOOL, 0, N_(escape for XML use)},
-{, VSH_OT_ARGV, 0, N_(arguments to echo)},
+{string, VSH_OT_ARGV, 0, N_(arguments to echo)},
 {NULL, 0, 0, NULL}
 };
 
@@ -11379,6 +11379,11 @@ vshCmddefGetOption(vshControl *ctl, const vshCmdDef 
*cmd, const char *name,
 vshError(ctl, _(option --%s already seen), name);
 return NULL;
 }
+if (opt-type == VSH_OT_ARGV) {
+vshError(ctl, _(variable argument %s 
+ should not be used with --%s), name, name);
+return NULL;
+}
 *opts_seen |= 1  i;
 return opt;
 }
@@ -11427,7 +11432,7 @@ vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd, 
uint32_t opts_required,
 const vshCmdOptDef *opt = def-opts[i];
 
 vshError(ctl,
- opt-type == VSH_OT_DATA ?
+ opt-type == VSH_OT_DATA || opt-type == VSH_OT_ARGV ?
  _(command '%s' requires %s option) :
  _(command '%s' requires --%s option),
  def-name, opt-name);
@@ -11535,7 +11540,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
 break;
 case VSH_OT_ARGV:
 /* xgettext:c-format */
-fmt = _([string]...);
+fmt = (opt-flag  VSH_OFLAG_REQ) ? _(%s...)
+   : _([%s]...);
 break;
 default:
 assert(0);
@@ -11575,7 +11581,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
 break;
 case VSH_OT_ARGV:
 /* Not really an option. */
-continue;
+snprintf(buf, sizeof(buf), _(%s), opt-name);
+break;
 default:
 assert(0);
 }
@@ -13012,7 +13019,7 @@ vshReadlineOptionsGenerator(const char *text, int state)
 
 list_index++;
 
-if (opt-type == VSH_OT_DATA)
+if (opt-type == VSH_OT_DATA || opt-type == VSH_OT_ARGV)
 /* ignore non --option */
 continue;
 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 07/10] send-key: Implementing the public API

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/libvirt.c |   63 +
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/src/libvirt.c b/src/libvirt.c
index cbe1926..112f690 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -26,6 +26,8 @@
 #include libxml/uri.h
 #include getpass.h
 
+#include libvirt/virtkeys.h
+
 #ifdef HAVE_WINSOCK2_H
 # include winsock2.h
 #endif
@@ -6511,6 +6513,67 @@ error:
 }
 
 /**
+ * virDomainSendKey:
+ * @domain:pointer to domain object, or NULL for Domain0
+ * @codeset:   the code set of keycodes
+ * @holdtime:  the time (in millsecond) how long the keys will be held
+ * @nkeycodes: number of keycodes
+ * @keycodes:  array of keycodes
+ * @flags: the flags for controlling behavior, pass 0 for now
+ *
+ * Send key to the guest
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int virDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int *keycodes,
+ unsigned int nkeycodes,
+ unsigned int flags)
+{
+virConnectPtr conn;
+VIR_DOMAIN_DEBUG(domain, codeset=%u,holdtime=%u,nkeycodes=%u,flags=%u,
+ codeset, holdtime, nkeycodes, flags);
+
+virResetLastError();
+
+if (nkeycodes == 0 || nkeycodes  MAX_SEND_KEY) {
+virLibDomainError(VIR_ERR_OPERATION_INVALID, __FUNCTION__);
+virDispatchError(NULL);
+return -1;
+}
+
+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-domainSendKey) {
+int ret;
+ret = conn-driver-domainSendKey(domain, codeset, holdtime,
+  keycodes, nkeycodes, flags);
+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
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 08/10 V2] send-key: Implementing the remote protocol

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/remote/remote_driver.c   |1 +
 src/remote/remote_protocol.x |   16 +++-
 src/remote_protocol-structs  |   11 +++
 3 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 8335a1a..f08a609 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -6337,6 +6337,7 @@ static virDriver remote_driver = {
 .domainMigratePerform3 = remoteDomainMigratePerform3, /* 0.9.2 */
 .domainMigrateFinish3 = remoteDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = remoteDomainMigrateConfirm3, /* 0.9.2 */
+.domainSendKey = remoteDomainSendKey, /* 0.9.3 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index c9b8cff..2126325 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -191,6 +191,11 @@ const REMOTE_SECRET_UUID_LIST_MAX = 16384;
  */
 const REMOTE_CPU_BASELINE_MAX = 256;
 
+/*
+ * Max number of sending keycodes.
+ */
+const REMOTE_SEND_KEY_MAX = 16;
+
 /* UUID.  VIR_UUID_BUFLEN definition comes from libvirt.h */
 typedef opaque remote_uuid[VIR_UUID_BUFLEN];
 
@@ -811,6 +816,14 @@ struct remote_domain_inject_nmi_args {
 unsigned int flags;
 };
 
+struct remote_domain_send_key_args {
+remote_nonnull_domain dom;
+unsigned int codeset;
+unsigned int holdtime;
+unsigned int keycodesREMOTE_SEND_KEY_MAX;
+unsigned int flags;
+};
+
 struct remote_domain_set_vcpus_args {
 remote_nonnull_domain dom;
 unsigned int nvcpus;
@@ -2297,7 +2310,8 @@ enum remote_procedure {
 REMOTE_PROC_INTERFACE_CHANGE_COMMIT = 221, /* autogen autogen */
 REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK = 222, /* autogen autogen */
 REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS = 223, /* skipgen 
autogen */
-REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224 /* skipgen skipgen */
+REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224, /* skipgen skipgen */
+REMOTE_PROC_DOMAIN_SEND_KEY = 225 /* autogen autogen */
 
 /*
  * Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 1d90dd5..dd70c24 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1550,3 +1550,14 @@ struct remote_message_header {
 u_int  serial;
 remote_message_status  status;
 };
+
+struct remote_domain_send_key_args {
+remote_nonnull_domain dom;
+unsigned int codeset;
+unsigned int holdtime;
+struct {
+unsigned int keycodes_len;
+unsigned int * keycodes_val;
+} keycodes;
+unsigned int flags;
+};
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 10/10 V2] qemu:send-key: Implement the driver methods

2011-06-07 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu_driver.c   |   50 ++
 src/qemu/qemu_monitor.c  |   27 ++
 src/qemu/qemu_monitor.h  |6 +
 src/qemu/qemu_monitor_json.c |   15 
 src/qemu/qemu_monitor_json.h |5 
 src/qemu/qemu_monitor_text.c |   47 +++
 src/qemu/qemu_monitor_text.h |5 
 7 files changed, 155 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 2957467..1678deb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1764,6 +1764,55 @@ cleanup:
 return ret;
 }
 
+static int qemuDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int *keycodes,
+ unsigned int nkeycodes,
+ unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+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 = qemuMonitorSendKey(priv-mon, codeset, holdtime, nkeycodes, 
keycodes);
+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)
 {
@@ -8092,6 +8141,7 @@ static virDriver qemuDriver = {
 .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */
 .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
+.domainSendKey = qemuDomainSendKey, /* 0.9.2 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 26bb814..faab819 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -38,6 +38,8 @@
 #include logging.h
 #include files.h
 
+#include libvirt/virtkeys.h
+
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
 #define DEBUG_IO 0
@@ -2357,6 +2359,31 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
 return ret;
 }
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int nkeycodes,
+   unsigned int *keycodes)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, codeset=%u, holdtime=%u, nkeycodes=%u,
+  mon, codeset, holdtime, nkeycodes);
+
+if (codeset != LIBVIRT_KEYCODE_XT) {
+qemuReportError(VIR_ERR_NO_SUPPORT,
+qemu monitor can not support the codeset: %d,
+codeset);
+return -1;
+}
+
+if (mon-json)
+ret = qemuMonitorJSONSendKey(mon, holdtime, nkeycodes, keycodes);
+else
+ret = qemuMonitorTextSendKey(mon, holdtime, nkeycodes, keycodes);
+return ret;
+}
+
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 910865b..64a6320 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -441,6 +441,12 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon);
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file);
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int nkeycodes,
+   unsigned int *keycodes);
+
 /**
  * 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 75adf66..538e98f 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2619,6 +2619,21 @@ cleanup:
 return ret;
 }
 
+int qemuMonitorJSONSendKey(qemuMonitorPtr mon,
+   unsigned int holdtime,
+   unsigned int nkeycodes

[libvirt] [PATCH 03/10 V2] add VSH_OFLAG_REQ_OPT options

2011-06-07 Thread Lai Jiangshan
A VSH_OFLAG_REQ_OPT option means --optionname is required when used.
It will kill any ambiguity even !VSH_OFLAG_REQ option listed before
VSH_OFLAG_REQ option if the !VSH_OFLAG_REQ option is a VSH_OFLAG_REQ_OPT option.

It will help us use optional arguement with VSH_OT_ARGV argument.

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c |7 +++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 638029c..d13c12b 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -152,6 +152,7 @@ enum {
 VSH_OFLAG_NONE = 0,/* without flags */
 VSH_OFLAG_REQ  = (1  0), /* option required */
 VSH_OFLAG_EMPTY_OK = (1  1), /* empty string option allowed */
+VSH_OFLAG_REQ_OPT  = (1  2), /* --optionname required */
 };
 
 /* dummy */
@@ -11375,6 +11376,12 @@ vshCmddefOptParse(const vshCmdDef *cmd, uint32_t* 
opts_need_arg,
 return -1; /* bool options can't be mandatory */
 continue;
 }
+if (opt-flag  VSH_OFLAG_REQ_OPT) {
+if (opt-flag  VSH_OFLAG_REQ)
+*opts_required |= 1  i;
+continue;
+}
+
 *opts_need_arg |= 1  i;
 if (opt-flag  VSH_OFLAG_REQ) {
 if (optional)
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 00/13] Add support for send keys to guest

2011-05-26 Thread Lai Jiangshan
On 05/26/2011 12:36 AM, Daniel P. Berrange wrote:
 On Wed, May 25, 2011 at 05:37:42PM +0800, Lai Jiangshan wrote:
 Add API virDomainSendKey() and virsh send-key command.

 # virsh help send-key
   NAME
 send-key - Send keycodes to the guest

   SYNOPSIS
 send-key domain [--codeset string] [--holdtime number] keycode...

   DESCRIPTION
 Send keycodes to the guest, the keycodes must be integers
 or the qemu-style key strings for the xt:keystring codeset
 or the KEY_* strings listed below for the linux codeset.

 Available codeset:
 linux  the keycodes specified in 
 /usr/include/linux/input.h(default)
 defaultlinux codeset will be used
 driver_default the hypervisor default codeset will be used
 xt XT(set1) scancode of standard AT keyboards and PS/2 
 keyboards
 atset1 set1 scancode of standard AT keyboards and PS/2 
 keyboards
 atset2 set2 scancode of standard AT keyboards and PS/2 
 keyboards
 atset3 set3 scancode of standard AT keyboards and PS/2 
 keyboards
 xt:keystring   XT scancode, but keycode... must be the qemu-style 
 key strings
 
 I was thinking we'd just use the Linux keycode set in the API, but I guess
 if the client app already has things in XT codeset, it isn't too nice to
 force them to convert to Linux keycodes, only for libvirt to convert them
 straight back for QEMU. So I think it was a good idea to add different
 codesets.
 
 I don't think that 'driver_default' makes sense though. For that to be
 usable, the person invoking the API must somehow know what the driver
 default codeset is. If they know that, then they can trivially just
 specify that already, so 'driver_default' doesn't seem to add any
 benefit.

OK, it will be removed.

 
 
 As for 'xt:keystring', if you think it is worth being able to use
 key strings, then perhaps we should have 2 apis. One API that takes
 a list of keycodes as ints, and one API that takes a list of keycodes
 as strings.

I don't think it is a good idea to add a second API, virDomainSendKey()
is not used directly by human, integer is enough. 2 apis will make the user of
the lib confused.

virsh send-key command is a human interface,
I think it is good if it accepts strings, so I allow KEY_XXX strings.

And this command should wrap all things(convert strings to integers).

If you deny 'xt:keystring', I can remove the patch, but KEY_XXX strings will
still stay.

 
 This would avoid the need for every client application to maintain
 a mapping table of strings - ints. eg, all the mapping tables
 would be contained within libvirt.

qemu monitor don't require ints--names conversions, it just needs
very trivial conversions ints--0xNN, this conversion will not need
when qmp send-key is implemented.

I don't know other hypervisors, but I think virDomainSendKey() taking
a list of keycode as ints is the best api for all hypervisors.

 

 Examples:

 virsh # send-key domain 37 18 21
 virsh # send-key domain --holdtime 1000 0x15 18 0xf
 virsh # send-key domain KEY_LEFTCTRL KEY_LEFTALT KEY_F1
 virsh # send-key domain --codeset xt:keystring alt-sysrq h

 KEY_XXX strings for the linux codeset:
 
 For virsh, perhaps it should default to always using the strings
 for the keys, and only use integers if given a special flag. I
 think most admins using virsh would just be using strings. The
 integer keycodes are mostly useful for apps using the API directly.
 
 eg, perhaps
 
  virsh # send-key domain KEY_LEFTCTRL KEY_LEFTALT KEY_F1
  virsh # send-key domain --codeset linux KEY_LEFTCTRL KEY_LEFTALT 
 KEY_F1
  virsh # send-key domain --codeset xt alt-sysrq h
  virsh # send-key domain --num 37 18 21
  virsh # send-key domain --num --holdtime 1000 0x15 18 0xf
  virsh # send-key domain --num --codeset linux --holdtime 1000 0x15 
 18 0xf

It is good for me, but I may want to wrap the strings-ints conversions in virsh
instead of in hypervisors.

 
 .
 .
 .
   OPTIONS
 [--domain] string  domain name, id or uuid
 --codeset string   the codeset of keycodes, default:linux
   --numthe keys are specified as integer values,
 --holdtime number  the time (in millsecond) how long the keys will be 
 held
 keycodethe key string (or value if --num is set)
 
 
 Daniel

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 05/13] send-key: Defining the public API

2011-05-26 Thread Lai Jiangshan
On 05/26/2011 12:43 AM, Daniel P. Berrange wrote:
 On Wed, May 25, 2011 at 05:37:47PM +0800, Lai Jiangshan wrote:
 Add public virDomainSendKey() and enum libvirt_keycode_set
 for the @codeset.

 Python version of virDomainSendKey() has not been implemented yet,
 it will be done soon.

 Signed-off-by: Lai Jiangshan la...@fujitsu.com
 ---
  include/libvirt/libvirt.h.in |7 +++
  include/libvirt/virtkeys.h   |   23 +++
  python/generator.py  |1 +
  src/libvirt_public.syms  |1 +
  4 files changed, 32 insertions(+), 0 deletions(-)

 diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
 index 7cd6e13..9167dbc 100644
 --- a/include/libvirt/libvirt.h.in
 +++ b/include/libvirt/libvirt.h.in
 @@ -2617,6 +2617,13 @@ int virDomainOpenConsole(virDomainPtr dom,
  
  int virDomainInjectNMI(virDomainPtr domain, unsigned int flags);
  
 +int virDomainSendKey(virDomainPtr domain,
 + unsigned int codeset,
 + unsigned int holdtime,
 + unsigned int nkeycodes,
 + unsigned int *keycodes,
 + unsigned int flags);
 +
 
 This looks fine. As mentioned earlier we might like to *also*
 have a variant which takes strings, to make life easier for
 virsh, or similar use cases
 
  +int virDomainSendKeyStr(virDomainPtr domain,
  +   unsigned int codeset,
  +   unsigned int holdtime,
  +   unsigned int nkeycodes,
  +   unsigned char **keycodestrs,
  +   unsigned int flags);
  +
 
 
  #ifdef __cplusplus
  }
  #endif
 diff --git a/include/libvirt/virtkeys.h b/include/libvirt/virtkeys.h
 new file mode 100644
 index 000..eb07129
 --- /dev/null
 +++ b/include/libvirt/virtkeys.h
 @@ -0,0 +1,23 @@
 +#ifndef _LIBVIRT_VIRTKEYS_H
 +#define _LIBVIRT_VIRTKEYS_H
 +
 +/*
 + * Copyright (c) 2011 Lai Jiangshan
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms of the GNU General Public License version 2 as published 
 by
 + * the Free Software Foundation.
 + */
 +
 +enum libvirt_keycode_set {
 +LIBVIRT_KEYCODE_LINUX  = 0,
 +LIBVIRT_KEYCODE_DRIVER_DEFAULT = 1,
 +LIBVIRT_KEYCODE_XT = 2,
 +LIBVIRT_KEYCODE_ATSET1 = LIBVIRT_KEYCODE_XT,
 +LIBVIRT_KEYCODE_ATSET2 = 3,
 +LIBVIRT_KEYCODE_ATSET3 = 4,
 +};
 
 If we're going to have constants for XT and ATSET1 then we
 probably want to have them separate values. If not then
 we should just kill one of them. As mentioned in the initial
 message, I think 'driver default' isn't useful, so I'd go
 with:
 
  +enum libvirt_keycode_set {
  +LIBVIRT_KEYCODE_LINUX  = 0,
  +LIBVIRT_KEYCODE_XT = 1,
  +LIBVIRT_KEYCODE_ATSET1 = 2
  +LIBVIRT_KEYCODE_ATSET2 = 3,
  +LIBVIRT_KEYCODE_ATSET3 = 4,
  +};
 


Sorry, That's my fault, I thought xt and atset1 are the same codeset.
Thank you for correcting me.

Thanks,
Lai.

 
 +
 +#define MAX_SEND_KEY  16
 +
 +#endif
 diff --git a/python/generator.py b/python/generator.py
 index 1741bba..3d57bf9 100755
 --- a/python/generator.py
 +++ b/python/generator.py
 @@ -355,6 +355,7 @@ skip_impl = (
  'virNodeDeviceListCaps',
  'virConnectBaselineCPU',
  'virDomainRevertToSnapshot',
 +'virDomainSendKey',
  )
  
  
 diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
 index 0590535..9e8a37c 100644
 --- a/src/libvirt_public.syms
 +++ b/src/libvirt_public.syms
 @@ -442,6 +442,7 @@ LIBVIRT_0.9.2 {
  virDomainInjectNMI;
  virDomainScreenshot;
  virDomainSetSchedulerParametersFlags;
 +virDomainSendKey;
  } LIBVIRT_0.9.0;
  
  #  define new API here using predicted next version number 
 
 Daniel

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 08/13] send-key: Implementing the remote protocol

2011-05-25 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 src/remote/remote_driver.c   |1 +
 src/remote/remote_protocol.x |   19 ++-
 src/remote_protocol-structs  |   11 +++
 3 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 1691dab..6614250 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -6868,6 +6868,7 @@ static virDriver remote_driver = {
 .domainMigrateFinish3 = remoteDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = remoteDomainMigrateConfirm3, /* 0.9.2 */
 .domainSetSchedulerParametersFlags = 
remoteDomainSetSchedulerParametersFlags, /* 0.9.2 */
+.domainSendKey = remoteDomainSendKey, /* 0.9.2 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index f0da95d..61504c4 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -191,6 +191,14 @@ const REMOTE_SECRET_UUID_LIST_MAX = 16384;
  */
 const REMOTE_CPU_BASELINE_MAX = 256;
 
+/*
+ * Max number of sending keycodes.
+ */
+const REMOTE_SEND_KEY_MAX = 16;
+
+/* define dynamic array's base type for unsigned int */
+typedef unsigned int u_int_DABT;
+
 /* UUID.  VIR_UUID_BUFLEN definition comes from libvirt.h */
 typedef opaque remote_uuid[VIR_UUID_BUFLEN];
 
@@ -838,6 +846,14 @@ struct remote_domain_inject_nmi_args {
 unsigned int flags;
 };
 
+struct remote_domain_send_key_args {
+remote_nonnull_domain dom;
+unsigned int codeset;
+unsigned int holdtime;
+u_int_DABT keycodesREMOTE_SEND_KEY_MAX;
+unsigned int flags;
+};
+
 struct remote_domain_set_vcpus_args {
 remote_nonnull_domain dom;
 int nvcpus;
@@ -2291,7 +2307,8 @@ enum remote_procedure {
 REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3 = 216, /* skipgen skipgen */
 REMOTE_PROC_DOMAIN_MIGRATE_FINISH3 = 217, /* skipgen skipgen */
 REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3 = 218, /* skipgen skipgen */
-REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS_FLAGS = 219 /* skipgen skipgen 
*/
+REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS_FLAGS = 219, /* skipgen 
skipgen */
+REMOTE_PROC_DOMAIN_SEND_KEY = 220 /* autogen autogen */
 
 /*
  * Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 414b4d5..814821a 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1553,3 +1553,14 @@ struct remote_message_header {
 u_int  serial;
 remote_message_status  status;
 };
+
+struct remote_domain_send_key_args {
+remote_nonnull_domain dom;
+unsigned int codeset;
+unsigned int holdtime;
+struct {
+unsigned int keycodes_len;
+unsigned int * keycodes_val;
+} keycodes;
+unsigned int flags;
+};
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 09/13] send-key: Expose the new API in virsh

2011-05-25 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 tools/virsh.c   |  103 +++
 tools/virsh.pod |4 ++
 2 files changed, 107 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 80cffac..505a821 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -33,6 +33,8 @@
 #include signal.h
 #include poll.h
 
+#include libvirt/virtkeys.h
+
 #include libxml/parser.h
 #include libxml/tree.h
 #include libxml/xpath.h
@@ -3010,6 +3012,106 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * send-key command
+ */
+static const vshCmdInfo info_send_key[] = {
+{help, N_(Send keycodes to the guest)},
+{desc, N_(Send keycodes to the guest, the keycodes must be integers\n
+Examples:\n\n
+virsh # send-key domain 37 18 21\n
+virsh # send-key domain --holdtime 1000 0x15 18 
0xf\n
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_send_key[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{codeset, VSH_OT_STRING, VSH_OFLAG_REQ_OPT, N_(the codeset of keycodes, 
default:linux)},
+{holdtime, VSH_OT_INT, VSH_OFLAG_REQ_OPT,
+ N_(the time (in millsecond) how long the keys will be 
held)},
+{keycode, VSH_OT_ARGV, VSH_OFLAG_REQ, N_(the key code)},
+{NULL, 0, 0, NULL}
+};
+
+static int get_integer_keycode(const char *key_name)
+{
+long val;
+char *endptr;
+
+val = strtol(key_name, endptr, 0);
+if (*endptr != '\0' || val  255 || val = 0)
+ return -1;
+
+return val;
+}
+
+static bool
+cmdSendKey(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = false;
+const char *codeset_option;
+int codeset;
+int holdtime;
+int count = 0;
+const vshCmdOpt *opt;
+int keycode;
+unsigned int keycodes[MAX_SEND_KEY];
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (vshCommandOptString(cmd, codeset, codeset_option) = 0)
+codeset_option = default;
+
+if (vshCommandOptInt(cmd, holdtime, holdtime) = 0)
+holdtime = 0;
+
+if (STREQ(codeset_option, default) || STREQ(codeset_option, linux)) {
+codeset = LIBVIRT_KEYCODE_LINUX;
+} else if (STREQ(codeset_option, diriver_default)) {
+codeset = LIBVIRT_KEYCODE_DRIVER_DEFAULT;
+} else if (STREQ(codeset_option, xt)) {
+codeset = LIBVIRT_KEYCODE_XT;
+} else if (STREQ(codeset_option, atset1)) {
+codeset = LIBVIRT_KEYCODE_ATSET1;
+} else if (STREQ(codeset_option, atset2)) {
+codeset = LIBVIRT_KEYCODE_ATSET2;
+} else if (STREQ(codeset_option, atset3)) {
+codeset = LIBVIRT_KEYCODE_ATSET3;
+} else {
+vshError(ctl, _(unknown codeset: '%s'), codeset_option);
+goto free_domain;
+}
+
+for_each_variable_arg(cmd, opt) {
+if (count == MAX_SEND_KEY) {
+vshError(ctl, _(too many keycode));
+goto free_domain;
+}
+
+if ((keycode = get_integer_keycode(opt-data))  0)
+goto get_keycode;
+
+vshError(ctl, _(invalid keycode: '%s'), opt-data);
+goto free_domain;
+
+get_keycode:
+keycodes[count] = keycode;
+count++;
+}
+
+if (!(virDomainSendKey(dom, codeset, holdtime, count, keycodes, 0)  0))
+ret = true;
+
+free_domain:
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * setmemory command
  */
 static const vshCmdInfo info_setmem[] = {
@@ -10807,6 +10909,7 @@ static const vshCmdDef domManagementCmds[] = {
 {dumpxml, cmdDumpXML, opts_dumpxml, info_dumpxml, 0},
 {edit, cmdEdit, opts_edit, info_edit, 0},
 {inject-nmi, cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0},
+{send-key, cmdSendKey, opts_send_key, info_send_key},
 {managedsave, cmdManagedSave, opts_managedsave, info_managedsave, 0},
 {managedsave-remove, cmdManagedSaveRemove, opts_managedsaveremove,
  info_managedsaveremove, 0},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index ef01f41..beef608 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -294,6 +294,10 @@ scheduling by the hypervisor.
 
 Inject NMI to the guest
 
+=item Bsend-key Idomain-id I--codeset Bcodeset I--holdtime 
Bholdtime Bkeycode...
+
+Send keys to the guest
+
 =item Bshutdown
 
 The domain is in the process of shutting down, i.e. the guest operating system
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 04/13] remote_generator: support general dynamic array

2011-05-25 Thread Lai Jiangshan
It will allow us use dynamic_array_basic_type member_nameMAX
for remote protocol and avoid so many manual coding.

For avoiding ambiguity, dynamic_array_basic_type must have a _DABT suffix.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 daemon/remote_generator.pl |   18 ++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl
index d21f959..6905ff3 100755
--- a/daemon/remote_generator.pl
+++ b/daemon/remote_generator.pl
@@ -343,6 +343,12 @@ elsif ($opt_b) {
 }
 
 push(@args_list, args-$2.$2_len);
+} elsif ($args_member =~ m/^(\S+_DABT) (\S+)\S+;/) { # 
normal dynamic array
+if (! @args_list) {
+push(@args_list, conn);
+}
+push(@args_list, args-$2.$2_len);
+push(@args_list, ($1 *)args-$2.$2_val);
 } elsif ($args_member =~ m/\S+;/ or $args_member =~ 
m/\[\S+\];/) {
 # just make all other array types fail
 die unhandled type for argument value: $args_member;
@@ -838,6 +844,18 @@ elsif ($opt_k) {
 push(@setters_list, args.$arg_name.${arg_name}_val = 
(char *)$arg_name;);
 push(@setters_list, args.$arg_name.${arg_name}_len = 
${arg_name}len;);
 push(@args_check_list, { name = \$arg_name\, arg = 
${arg_name}len, limit = $limit });
+} elsif ($args_member =~ m/^(\S+_DABT) (\S+)(\S+);/) { # 
normal dynamic array
+my $type_name = $1;
+my $arg_name = $2;
+my $limit = $3;
+
+push(@args_list, unsigned int n${arg_name});
+push(@args_list, ${type_name} *$arg_name);
+
+push(@setters_list, args.$arg_name.${arg_name}_len = 
n${arg_name};);
+push(@setters_list, args.$arg_name.${arg_name}_val = 
(${type_name} *)$arg_name;);
+
+push(@args_check_list, { name = \$arg_name\, arg = 
n${arg_name}, limit = $limit });
 } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) {
 my $type_name;
 my $arg_name = $3;
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 11/13] send-key: support KEY_XXX names for the linux keycode

2011-05-25 Thread Lai Jiangshan
It make send-key command more friendly for user.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 include/libvirt/virtkeys.h |  253 
 tools/virsh.c  |   21 
 2 files changed, 274 insertions(+), 0 deletions(-)

diff --git a/include/libvirt/virtkeys.h b/include/libvirt/virtkeys.h
index eb07129..7893450 100644
--- a/include/libvirt/virtkeys.h
+++ b/include/libvirt/virtkeys.h
@@ -20,4 +20,257 @@ enum libvirt_keycode_set {
 
 #define MAX_SEND_KEY  16
 
+#define ITEM_KEYCODE(KEY_XXX) VIRT##KEY_XXX
+#define KEYCODES() \
+keycode(KEY_ESC, 1)\
+keycode(KEY_1,   2)\
+keycode(KEY_2,   3)\
+keycode(KEY_3,   4)\
+keycode(KEY_4,   5)\
+keycode(KEY_5,   6)\
+keycode(KEY_6,   7)\
+keycode(KEY_7,   8)\
+keycode(KEY_8,   9)\
+keycode(KEY_9,   10)\
+keycode(KEY_0,   11)\
+keycode(KEY_MINUS,   12)\
+keycode(KEY_EQUAL,   13)\
+keycode(KEY_BACKSPACE,   14)\
+keycode(KEY_TAB, 15)\
+keycode(KEY_Q,   16)\
+keycode(KEY_W,   17)\
+keycode(KEY_E,   18)\
+keycode(KEY_R,   19)\
+keycode(KEY_T,   20)\
+keycode(KEY_Y,   21)\
+keycode(KEY_U,   22)\
+keycode(KEY_I,   23)\
+keycode(KEY_O,   24)\
+keycode(KEY_P,   25)\
+keycode(KEY_LEFTBRACE,   26)\
+keycode(KEY_RIGHTBRACE,  27)\
+keycode(KEY_ENTER,   28)\
+keycode(KEY_LEFTCTRL,29)\
+keycode(KEY_A,   30)\
+keycode(KEY_S,   31)\
+keycode(KEY_D,   32)\
+keycode(KEY_F,   33)\
+keycode(KEY_G,   34)\
+keycode(KEY_H,   35)\
+keycode(KEY_J,   36)\
+keycode(KEY_K,   37)\
+keycode(KEY_L,   38)\
+keycode(KEY_SEMICOLON,   39)\
+keycode(KEY_APOSTROPHE,  40)\
+keycode(KEY_GRAVE,   41)\
+keycode(KEY_LEFTSHIFT,   42)\
+keycode(KEY_BACKSLASH,   43)\
+keycode(KEY_Z,   44)\
+keycode(KEY_X,   45)\
+keycode(KEY_C,   46)\
+keycode(KEY_V,   47)\
+keycode(KEY_B,   48)\
+keycode(KEY_N,   49)\
+keycode(KEY_M,   50)\
+keycode(KEY_COMMA,   51)\
+keycode(KEY_DOT, 52)\
+keycode(KEY_SLASH,   53)\
+keycode(KEY_RIGHTSHIFT,  54)\
+keycode(KEY_KPASTERISK,  55)\
+keycode(KEY_LEFTALT, 56)\
+keycode(KEY_SPACE,   57)\
+keycode(KEY_CAPSLOCK,58)\
+keycode(KEY_F1,  59)\
+keycode(KEY_F2,  60)\
+keycode(KEY_F3,  61)\
+keycode(KEY_F4,  62)\
+keycode(KEY_F5,  63)\
+keycode(KEY_F6,  64)\
+keycode(KEY_F7,  65)\
+keycode(KEY_F8,  66)\
+keycode(KEY_F9,  67)\
+keycode(KEY_F10, 68)\
+keycode(KEY_NUMLOCK, 69)\
+keycode(KEY_SCROLLLOCK,  70)\
+keycode(KEY_KP7, 71)\
+keycode(KEY_KP8, 72)\
+keycode(KEY_KP9, 73)\
+keycode(KEY_KPMINUS, 74)\
+keycode(KEY_KP4, 75)\
+keycode(KEY_KP5, 76)\
+keycode(KEY_KP6, 77)\
+keycode(KEY_KPPLUS,  78)\
+keycode(KEY_KP1, 79)\
+keycode(KEY_KP2, 80)\
+keycode(KEY_KP3, 81)\
+keycode(KEY_KP0, 82)\
+keycode(KEY_KPDOT,   83)\
+keycode(KEY_ZENKAKUHANKAKU,  85)\
+keycode(KEY_102ND,   86)\
+keycode(KEY_F11, 87)\
+keycode(KEY_F12, 88)\
+keycode(KEY_RO,  89)\
+keycode(KEY_KATAKANA,90)\
+keycode(KEY_HIRAGANA,91)\
+keycode(KEY_HENKAN,  92)\
+keycode(KEY_KATAKANAHIRAGANA,93)\
+keycode(KEY_MUHENKAN,94)\
+keycode(KEY_KPJPCOMMA,   95)\
+keycode(KEY_KPENTER, 96)\
+keycode(KEY_RIGHTCTRL,   97)\
+keycode(KEY_KPSLASH, 98)\
+keycode(KEY_SYSRQ,   99)\
+keycode(KEY_RIGHTALT,100)\
+keycode(KEY_LINEFEED,101)\
+keycode(KEY_HOME,102)\
+keycode(KEY_UP,  103)\
+keycode

[libvirt] [PATCH 03/13] add VSH_OFLAG_REQ_OPT options

2011-05-25 Thread Lai Jiangshan
A VSH_OFLAG_REQ_OPT option means --optionname is required when used.
It will kill any ambiguity even !VSH_OFLAG_REQ option listed before
VSH_OFLAG_REQ option if the !VSH_OFLAG_REQ option is a VSH_OFLAG_REQ_OPT option.

It will help us use optional arguement with VSH_OT_ARGV argument.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 tools/virsh.c |7 +++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 2e27535..80cffac 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -152,6 +152,7 @@ enum {
 VSH_OFLAG_NONE = 0,/* without flags */
 VSH_OFLAG_REQ  = (1  0), /* option required */
 VSH_OFLAG_EMPTY_OK = (1  1), /* empty string option allowed */
+VSH_OFLAG_REQ_OPT  = (1  2), /* --optionname required */
 };
 
 /* dummy */
@@ -11080,6 +11081,12 @@ vshCmddefOptParse(const vshCmdDef *cmd, uint32_t* 
opts_need_arg,
 return -1; /* bool options can't be mandatory */
 continue;
 }
+if (opt-flag  VSH_OFLAG_REQ_OPT) {
+if (opt-flag  VSH_OFLAG_REQ)
+*opts_required |= 1  i;
+continue;
+}
+
 *opts_need_arg |= 1  i;
 if (opt-flag  VSH_OFLAG_REQ) {
 if (optional)
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 01/13] allow name for VSH_OT_ARGV options

2011-05-25 Thread Lai Jiangshan
A name will improve the usege, example

# virsh help echo
  NAME
echo - echo arguments

  SYNOPSIS
echo [--shell] [--xml] [string]...

  DESCRIPTION
Echo back arguments, possibly with quoting.

  OPTIONS
--shell  escape for shell use
--xmlescape for XML use
string arguments to echo

[string]... is added to SYNOPSIS.
string arguments to echo is added to OPTIONS.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 tools/virsh.c |   19 +--
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index de49489..c358580 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -126,7 +126,7 @@ typedef enum {
 VSH_OT_STRING,   /* optional string option */
 VSH_OT_INT,  /* optional or mandatory int option */
 VSH_OT_DATA, /* string data (as non-option) */
-VSH_OT_ARGV  /* remaining arguments, opt-name should be  */
+VSH_OT_ARGV  /* remaining arguments */
 } vshCmdOptType;
 
 /*
@@ -10046,7 +10046,7 @@ static const vshCmdInfo info_echo[] = {
 static const vshCmdOptDef opts_echo[] = {
 {shell, VSH_OT_BOOL, 0, N_(escape for shell use)},
 {xml, VSH_OT_BOOL, 0, N_(escape for XML use)},
-{, VSH_OT_ARGV, 0, N_(arguments to echo)},
+{string, VSH_OT_ARGV, 0, N_(arguments to echo)},
 {NULL, 0, 0, NULL}
 };
 
@@ -11084,6 +11084,11 @@ vshCmddefGetOption(vshControl *ctl, const vshCmdDef 
*cmd, const char *name,
 vshError(ctl, _(option --%s already seen), name);
 return NULL;
 }
+if (opt-type == VSH_OT_ARGV) {
+vshError(ctl, _(variable argument %s 
+ should not be used with --%s), name, name);
+return NULL;
+}
 *opts_seen |= 1  i;
 return opt;
 }
@@ -11132,7 +11137,7 @@ vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd, 
uint32_t opts_required,
 const vshCmdOptDef *opt = def-opts[i];
 
 vshError(ctl,
- opt-type == VSH_OT_DATA ?
+ opt-type == VSH_OT_DATA || opt-type == VSH_OT_ARGV ?
  _(command '%s' requires %s option) :
  _(command '%s' requires --%s option),
  def-name, opt-name);
@@ -11240,7 +11245,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
 break;
 case VSH_OT_ARGV:
 /* xgettext:c-format */
-fmt = _([string]...);
+fmt = (opt-flag  VSH_OFLAG_REQ) ? _(%s...)
+   : _([%s]...);
 break;
 default:
 assert(0);
@@ -11280,7 +11286,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
 break;
 case VSH_OT_ARGV:
 /* Not really an option. */
-continue;
+snprintf(buf, sizeof(buf), _(%s), opt-name);
+break;
 default:
 assert(0);
 }
@@ -12693,7 +12700,7 @@ vshReadlineOptionsGenerator(const char *text, int state)
 
 list_index++;
 
-if (opt-type == VSH_OT_DATA)
+if (opt-type == VSH_OT_DATA || opt-type == VSH_OT_ARGV)
 /* ignore non --option */
 continue;
 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 06/13] send-key: Defining the internal API

2011-05-25 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 src/driver.h |8 
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/src/driver.h b/src/driver.h
index 450dd53..70a30d9 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -535,6 +535,13 @@ typedef int
 typedef int
 (*virDrvDomainInjectNMI)(virDomainPtr dom, unsigned int flags);
 
+typedef int
+(*virDrvDomainSendKey)(virDomainPtr dom, unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int nkeycodes,
+   unsigned int *keycodes,
+   unsigned int flags);
+
 typedef char *
 (*virDrvDomainMigrateBegin3)
 (virDomainPtr domain,
@@ -738,6 +745,7 @@ struct _virDriver {
 virDrvDomainMigratePerform3domainMigratePerform3;
 virDrvDomainMigrateFinish3 domainMigrateFinish3;
 virDrvDomainMigrateConfirm3domainMigrateConfirm3;
+virDrvDomainSendKey domainSendKey;
 };
 
 typedef int
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 10/13] qemu:send-key: Implement the driver methods

2011-05-25 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 src/qemu/qemu_driver.c   |   50 ++
 src/qemu/qemu_monitor.c  |   28 +++
 src/qemu/qemu_monitor.h  |6 +
 src/qemu/qemu_monitor_json.c |   15 
 src/qemu/qemu_monitor_json.h |5 
 src/qemu/qemu_monitor_text.c |   48 
 src/qemu/qemu_monitor_text.h |5 
 7 files changed, 157 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 691965d..f7e21bf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1753,6 +1753,55 @@ cleanup:
 return ret;
 }
 
+static int qemuDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes,
+ unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+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 = qemuMonitorSendKey(priv-mon, codeset, holdtime, nkeycodes, 
keycodes);
+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)
 {
@@ -7746,6 +7795,7 @@ static virDriver qemuDriver = {
 .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
 .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
 .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 
0.9.2 */
+.domainSendKey = qemuDomainSendKey, /* 0.9.2 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5186f99..c0688fd 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -38,6 +38,8 @@
 #include logging.h
 #include files.h
 
+#include libvirt/virtkeys.h
+
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
 #define DEBUG_IO 0
@@ -2294,6 +2296,32 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
 return ret;
 }
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int nkeycodes,
+   unsigned int *keycodes)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, codeset=%u, holdtime=%u, nkeycodes=%u,
+  mon, codeset, holdtime, nkeycodes);
+
+if (!(codeset == LIBVIRT_KEYCODE_DRIVER_DEFAULT
+|| codeset == LIBVIRT_KEYCODE_XT)) {
+qemuReportError(VIR_ERR_NO_SUPPORT,
+qemu monitor can not support the codeset: %d,
+codeset);
+return -1;
+}
+
+if (mon-json)
+ret = qemuMonitorJSONSendKey(mon, holdtime, nkeycodes, keycodes);
+else
+ret = qemuMonitorTextSendKey(mon, holdtime, nkeycodes, keycodes);
+return ret;
+}
+
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 05c3359..76a849a 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -435,6 +435,12 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon);
 int qemuMonitorScreendump(qemuMonitorPtr mon,
   const char *file);
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+   unsigned int codeset,
+   unsigned int holdtime,
+   unsigned int nkeycodes,
+   unsigned int *keycodes);
+
 /**
  * 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 2d8a390..a547f1d 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2615,6 +2615,21 @@ cleanup:
 return ret;
 }
 
+int qemuMonitorJSONSendKey(qemuMonitorPtr mon

[libvirt] [PATCH 00/13] Add support for send keys to guest

2011-05-25 Thread Lai Jiangshan
Add API virDomainSendKey() and virsh send-key command.

# virsh help send-key
  NAME
send-key - Send keycodes to the guest

  SYNOPSIS
send-key domain [--codeset string] [--holdtime number] keycode...

  DESCRIPTION
Send keycodes to the guest, the keycodes must be integers
or the qemu-style key strings for the xt:keystring codeset
or the KEY_* strings listed below for the linux codeset.

Available codeset:
linux  the keycodes specified in 
/usr/include/linux/input.h(default)
defaultlinux codeset will be used
driver_default the hypervisor default codeset will be used
xt XT(set1) scancode of standard AT keyboards and PS/2 
keyboards
atset1 set1 scancode of standard AT keyboards and PS/2 keyboards
atset2 set2 scancode of standard AT keyboards and PS/2 keyboards
atset3 set3 scancode of standard AT keyboards and PS/2 keyboards
xt:keystring   XT scancode, but keycode... must be the qemu-style key 
strings

Examples:

virsh # send-key domain 37 18 21
virsh # send-key domain --holdtime 1000 0x15 18 0xf
virsh # send-key domain KEY_LEFTCTRL KEY_LEFTALT KEY_F1
virsh # send-key domain --codeset xt:keystring alt-sysrq h

KEY_XXX strings for the linux codeset:
.
.
.
  OPTIONS
[--domain] string  domain name, id or uuid
--codeset string  the codeset of keycodes, default:linux
--holdtime number  the time (in millsecond) how long the keys will be held
keycodethe key code


PATCH 01~04 prepare
PATCH 05~10 Add support for send keys to guest
PATCH 11~13 improve usage of send keys.

Python version of virDomainSendKey() has not been implemented yet,
it will be done soon.

Lai Jiangshan (13):
  allow name for VSH_OT_ARGV options
  improve the iteration of VSH_OT_ARGV options
  add VSH_OFLAG_REQ_OPT options
  remote_generator: support general dynamic array
  send-key: Defining the public API
  send-key: Defining the internal API
  send-key: Implementing the public API
  send-key: Implementing the remote protocol
  send-key: Expose the new API in virsh
  qemu:send-key: Implement the driver methods
  send-key: support KEY_XXX names for the linux keycode
  qemu,send-key: map linux keycode to xt keycode
  virsh,send-key: add --codeset xt:keystring support

 daemon/remote_generator.pl   |   18 ++
 include/libvirt/libvirt.h.in |7 +
 include/libvirt/virtkeys.h   |  276 
 python/generator.py  |1 +
 src/driver.h |8 +
 src/libvirt.c|   54 ++
 src/libvirt_public.syms  |1 +
 src/qemu/qemu_driver.c   |   50 +
 src/qemu/qemu_monitor.c  |   75 
 src/qemu/qemu_monitor.h  |6 +
 src/qemu/qemu_monitor_json.c |   15 ++
 src/qemu/qemu_monitor_json.h |5 +
 src/qemu/qemu_monitor_text.c |   48 +
 src/qemu/qemu_monitor_text.h |5 +
 src/remote/remote_driver.c   |1 +
 src/remote/remote_protocol.x |   19 ++-
 src/remote_protocol-structs  |   11 +
 tools/virsh.c|  415 +++---
 tools/virsh.pod  |4 +
 19 files changed, 989 insertions(+), 30 deletions(-)
 create mode 100644 include/libvirt/virtkeys.h

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 13/13] virsh, send-key: add --codeset xt:keystring support

2011-05-25 Thread Lai Jiangshan
It make send-key command more friendly for user.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 tools/virsh.c |  224 -
 1 files changed, 221 insertions(+), 3 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 3bccc08..18ef4bb 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -3017,11 +3017,24 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
 static const vshCmdInfo info_send_key[] = {
 {help, N_(Send keycodes to the guest)},
 {desc, N_(Send keycodes to the guest, the keycodes must be integers\n
+or the qemu-style key strings for the \xt:keystring\ 
codeset\n
 or the KEY_* strings listed below for the \linux\ 
codeset.\n\n
+Available codeset:\n
+linux  the keycodes specified in \n
+/usr/include/linux/input.h(default)\n
+defaultlinux codeset will be used\n
+driver_default the hypervisor default codeset will be 
used\n
+xt XT(set1) scancode of standard AT 
keyboards and PS/2 keyboards\n
+atset1 set1 scancode of standard AT keyboards 
and PS/2 keyboards\n
+atset2 set2 scancode of standard AT keyboards 
and PS/2 keyboards\n
+atset3 set3 scancode of standard AT keyboards 
and PS/2 keyboards\n
+xt:keystring   XT scancode, but keycode... must be 
the qemu-style key strings\n
+\n
 Examples:\n\n
 virsh # send-key domain 37 18 21\n
 virsh # send-key domain --holdtime 1000 0x15 18 
0xf\n
-virsh # send-eky domain KEY_LEFTCTRL KEY_LEFTALT 
KEY_F1\n
+virsh # send-key domain KEY_LEFTCTRL KEY_LEFTALT 
KEY_F1\n
+virsh # send-key domain --codeset xt:keystring 
alt-sysrq h\n
 \n
 KEY_XXX strings for the \linux\ codeset:\n
 #define keycode(var, value)   #var  =  #value \n
@@ -3062,6 +3075,178 @@ static int get_integer_keycode(const char *key_name)
 return val;
 }
 
+
+typedef struct {
+int keycode;
+const char *name;
+} KeyDef;
+
+static const KeyDef key_defs[] = {
+{ 0x2a, shift },
+{ 0x36, shift_r },
+
+{ 0x38, alt },
+{ 0xb8, alt_r },
+{ 0x64, altgr },
+{ 0xe4, altgr_r },
+{ 0x1d, ctrl },
+{ 0x9d, ctrl_r },
+
+{ 0xdd, menu },
+
+{ 0x01, esc },
+
+{ 0x02, 1 },
+{ 0x03, 2 },
+{ 0x04, 3 },
+{ 0x05, 4 },
+{ 0x06, 5 },
+{ 0x07, 6 },
+{ 0x08, 7 },
+{ 0x09, 8 },
+{ 0x0a, 9 },
+{ 0x0b, 0 },
+{ 0x0c, minus },
+{ 0x0d, equal },
+{ 0x0e, backspace },
+
+{ 0x0f, tab },
+{ 0x10, q },
+{ 0x11, w },
+{ 0x12, e },
+{ 0x13, r },
+{ 0x14, t },
+{ 0x15, y },
+{ 0x16, u },
+{ 0x17, i },
+{ 0x18, o },
+{ 0x19, p },
+{ 0x1a, bracket_left },
+{ 0x1b, bracket_right },
+{ 0x1c, ret },
+
+{ 0x1e, a },
+{ 0x1f, s },
+{ 0x20, d },
+{ 0x21, f },
+{ 0x22, g },
+{ 0x23, h },
+{ 0x24, j },
+{ 0x25, k },
+{ 0x26, l },
+{ 0x27, semicolon },
+{ 0x28, apostrophe },
+{ 0x29, grave_accent },
+
+{ 0x2b, backslash },
+{ 0x2c, z },
+{ 0x2d, x },
+{ 0x2e, c },
+{ 0x2f, v },
+{ 0x30, b },
+{ 0x31, n },
+{ 0x32, m },
+{ 0x33, comma },
+{ 0x34, dot },
+{ 0x35, slash },
+
+{ 0x37, asterisk },
+
+{ 0x39, spc },
+{ 0x3a, caps_lock },
+{ 0x3b, f1 },
+{ 0x3c, f2 },
+{ 0x3d, f3 },
+{ 0x3e, f4 },
+{ 0x3f, f5 },
+{ 0x40, f6 },
+{ 0x41, f7 },
+{ 0x42, f8 },
+{ 0x43, f9 },
+{ 0x44, f10 },
+{ 0x45, num_lock },
+{ 0x46, scroll_lock },
+
+{ 0xb5, kp_divide },
+{ 0x37, kp_multiply },
+{ 0x4a, kp_subtract },
+{ 0x4e, kp_add },
+{ 0x9c, kp_enter },
+{ 0x53, kp_decimal },
+{ 0x54, sysrq },
+
+{ 0x52, kp_0 },
+{ 0x4f, kp_1 },
+{ 0x50, kp_2 },
+{ 0x51, kp_3 },
+{ 0x4b, kp_4 },
+{ 0x4c, kp_5 },
+{ 0x4d, kp_6 },
+{ 0x47, kp_7 },
+{ 0x48, kp_8 },
+{ 0x49, kp_9 },
+
+{ 0x56,  },
+
+{ 0x57, f11 },
+{ 0x58, f12 },
+
+{ 0xb7, print },
+
+{ 0xc7, home },
+{ 0xc9, pgup },
+{ 0xd1, pgdn },
+{ 0xcf, end },
+
+{ 0xcb, left },
+{ 0xc8, up },
+{ 0xd0, down },
+{ 0xcd, right },
+
+{ 0xd2, insert },
+{ 0xd3, delete },
+
+{ 0xf0, stop },
+{ 0xf1, again },
+{ 0xf2, props },
+{ 0xf3, undo },
+{ 0xf4, front },
+{ 0xf5, copy },
+{ 0xf6, open },
+{ 0xf7, paste },
+{ 0xf8, find },
+{ 0xf9, cut },
+{ 0xfa, lf },
+{ 0xfb, help },
+{ 0xfc, meta_l },
+{ 0xfd, meta_r },
+{ 0xfe, compose },
+
+{ 0, NULL

[libvirt] [PATCH 05/13] send-key: Defining the public API

2011-05-25 Thread Lai Jiangshan
Add public virDomainSendKey() and enum libvirt_keycode_set
for the @codeset.

Python version of virDomainSendKey() has not been implemented yet,
it will be done soon.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 include/libvirt/libvirt.h.in |7 +++
 include/libvirt/virtkeys.h   |   23 +++
 python/generator.py  |1 +
 src/libvirt_public.syms  |1 +
 4 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 7cd6e13..9167dbc 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2617,6 +2617,13 @@ int virDomainOpenConsole(virDomainPtr dom,
 
 int virDomainInjectNMI(virDomainPtr domain, unsigned int flags);
 
+int virDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes,
+ unsigned int flags);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/libvirt/virtkeys.h b/include/libvirt/virtkeys.h
new file mode 100644
index 000..eb07129
--- /dev/null
+++ b/include/libvirt/virtkeys.h
@@ -0,0 +1,23 @@
+#ifndef _LIBVIRT_VIRTKEYS_H
+#define _LIBVIRT_VIRTKEYS_H
+
+/*
+ * Copyright (c) 2011 Lai Jiangshan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+enum libvirt_keycode_set {
+LIBVIRT_KEYCODE_LINUX  = 0,
+LIBVIRT_KEYCODE_DRIVER_DEFAULT = 1,
+LIBVIRT_KEYCODE_XT = 2,
+LIBVIRT_KEYCODE_ATSET1 = LIBVIRT_KEYCODE_XT,
+LIBVIRT_KEYCODE_ATSET2 = 3,
+LIBVIRT_KEYCODE_ATSET3 = 4,
+};
+
+#define MAX_SEND_KEY  16
+
+#endif
diff --git a/python/generator.py b/python/generator.py
index 1741bba..3d57bf9 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -355,6 +355,7 @@ skip_impl = (
 'virNodeDeviceListCaps',
 'virConnectBaselineCPU',
 'virDomainRevertToSnapshot',
+'virDomainSendKey',
 )
 
 
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 0590535..9e8a37c 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -442,6 +442,7 @@ LIBVIRT_0.9.2 {
 virDomainInjectNMI;
 virDomainScreenshot;
 virDomainSetSchedulerParametersFlags;
+virDomainSendKey;
 } LIBVIRT_0.9.0;
 
 #  define new API here using predicted next version number 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 02/13] improve the iteration of VSH_OT_ARGV options

2011-05-25 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 tools/virsh.c |   47 ---
 1 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index c358580..2e27535 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -277,7 +277,27 @@ static int vshCommandOptULongLong(const vshCmd *cmd, const 
char *name,
   unsigned long long *value)
 ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
 static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
-static char *vshCommandOptArgv(const vshCmd *cmd, int count);
+
+/*
+ * Iterate all the argv arguments.
+ *
+ * Requires that a VSH_OT_ARGV option  be last in the
+ * list of supported options in CMD-def-opts.
+ */
+static inline const vshCmdOpt *__variable_arg(const vshCmdOpt *opt)
+{
+while (opt) {
+ if (opt-def  opt-def-type == VSH_OT_ARGV)
+ break;
+ opt = opt-next;
+}
+
+return opt;
+}
+
+#define for_each_variable_arg(cmd, opt)   \
+for (opt = __variable_arg(cmd-opts); opt; opt = __variable_arg(opt-next))
+
 
 #define VSH_BYID (1  1)
 #define VSH_BYUUID   (1  2)
@@ -10059,6 +10079,7 @@ cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd 
*cmd)
 bool shell = false;
 bool xml = false;
 int count = 0;
+const vshCmdOpt *opt;
 char *arg;
 virBuffer buf = VIR_BUFFER_INITIALIZER;
 
@@ -10067,10 +10088,11 @@ cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const 
vshCmd *cmd)
 if (vshCommandOptBool(cmd, xml))
 xml = true;
 
-while ((arg = vshCommandOptArgv(cmd, count)) != NULL) {
+for_each_variable_arg(cmd, opt) {
 bool close_quote = false;
 char *q;
 
+arg = opt-data;
 if (count)
 virBufferAddChar(buf, ' ');
 /* Add outer '' only if arg included shell metacharacters.  */
@@ -11484,27 +11506,6 @@ vshCommandOptBool(const vshCmd *cmd, const char *name)
 return vshCommandOpt(cmd, name) != NULL;
 }
 
-/*
- * Returns the COUNT argv argument, or NULL after last argument.
- *
- * Requires that a VSH_OT_ARGV option with the name  be last in the
- * list of supported options in CMD-def-opts.
- */
-static char *
-vshCommandOptArgv(const vshCmd *cmd, int count)
-{
-vshCmdOpt *opt = cmd-opts;
-
-while (opt) {
-if (opt-def  opt-def-type == VSH_OT_ARGV) {
-if (count-- == 0)
-return opt-data;
-}
-opt = opt-next;
-}
-return NULL;
-}
-
 /* Determine whether CMD-opts includes an option with name OPTNAME.
If not, give a diagnostic and return false.
If so, return true.  */
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 07/13] send-key: Implementing the public API

2011-05-25 Thread Lai Jiangshan
Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 src/libvirt.c |   54 ++
 1 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/src/libvirt.c b/src/libvirt.c
index ff16c48..8246975 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -6080,6 +6080,60 @@ error:
 }
 
 /**
+ * virDomainSendKey:
+ * @domain:pointer to domain object, or NULL for Domain0
+ * @codeset:   the code set of keycodes
+ * @holdtime:  the time (in millsecond) how long the keys will be held
+ * @nkeycodes: number of keycodes
+ * @keycodes:  array of keycodes
+ * @flags: the flags for controlling behavior, pass 0 for now
+ *
+ * Send key to the guest
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int virDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes,
+ unsigned int flags)
+{
+virConnectPtr conn;
+VIR_DOMAIN_DEBUG(domain, flags=%u, flags);
+
+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-domainSendKey) {
+int ret;
+ret = conn-driver-domainSendKey(domain, codeset, holdtime,
+  nkeycodes, keycodes, flags);
+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
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 12/13] qemu, send-key: map linux keycode to xt keycode

2011-05-25 Thread Lai Jiangshan
It allows us use linux keycode for qemu driver.

Signed-off-by: Lai Jiangshan la...@fujitsu.com
---
 src/qemu/qemu_monitor.c |   49 ++-
 1 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index c0688fd..f6cdff1 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2296,6 +2296,41 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
 return ret;
 }
 
+unsigned int linux2xt_keycode[256] = {
+/* 00: */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+/* 08: */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+/* 10: */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+/* 18: */ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+/* 20: */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+/* 28: */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+/* 30: */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 38: */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+/* 40: */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 48: */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f,
+/* 50: */ 0x50, 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x57,
+/* 58: */ 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60: */ 0x00, 0x9d, 0xb5, 0x54, 0xb8, 0x00, 0xc7, 0xc8,
+/* 68: */ 0xc9, 0xcb, 0xcd, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3,
+/* 70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 80: */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+/* 88: */ 0xf8, 0xf9, 0xfb, 0xdd, 0x00, 0x00, 0x00, 0x00,
+/* 90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* d0: */ 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
 int qemuMonitorSendKey(qemuMonitorPtr mon,
unsigned int codeset,
unsigned int holdtime,
@@ -2307,7 +2342,19 @@ int qemuMonitorSendKey(qemuMonitorPtr mon,
 VIR_DEBUG(mon=%p, codeset=%u, holdtime=%u, nkeycodes=%u,
   mon, codeset, holdtime, nkeycodes);
 
-if (!(codeset == LIBVIRT_KEYCODE_DRIVER_DEFAULT
+if (codeset == LIBVIRT_KEYCODE_LINUX) {
+int i;
+
+for (i = 0; i  nkeycodes; i++) {
+if (keycodes[i] = 256 || !linux2xt_keycode[keycodes[i]]) {
+qemuReportError(VIR_ERR_INTERNAL_ERROR,
+can not map the linux keycode:%d to XT 
keycode,
+keycodes[i]);
+return -1;
+}
+keycodes[i] = linux2xt_keycode[keycodes[i]];
+}
+} else if (!(codeset == LIBVIRT_KEYCODE_DRIVER_DEFAULT
 || codeset == LIBVIRT_KEYCODE_XT)) {
 qemuReportError(VIR_ERR_NO_SUPPORT,
 qemu monitor can not support the codeset: %d,
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 0/6 V4] Add support for injecting NMI to guest

2011-05-10 Thread Lai Jiangshan
This patch series implements a feature of injecting NMI to guest,
which is accessible via new virDomainInjectNMI API and
'inject-nmi' command in virsh.

Lai Jiangshan (6):
  inject-nmi: Defining the public API
  inject-nmi: Defining the internal API
  inject-nmi: Implementing the public API
  inject-nmi: Implementing the remote protocol
  inject-nmi: Expose the new API in virsh
  qemu,inject-nmi: Implement the driver methods

 daemon/remote_generator.pl   |2 +-
 include/libvirt/libvirt.h.in |2 +
 src/driver.h |4 +++
 src/esx/esx_driver.c |1 +
 src/libvirt.c|   44 +
 src/libvirt_public.syms  |5 
 src/libxl/libxl_driver.c |1 +
 src/lxc/lxc_driver.c |1 +
 src/openvz/openvz_driver.c   |1 +
 src/phyp/phyp_driver.c   |3 +-
 src/qemu/qemu_driver.c   |   45 ++
 src/qemu/qemu_monitor.c  |   14 +
 src/qemu/qemu_monitor.h  |2 +
 src/qemu/qemu_monitor_json.c |   27 +
 src/qemu/qemu_monitor_json.h |1 +
 src/qemu/qemu_monitor_text.c |   28 ++
 src/qemu/qemu_monitor_text.h |1 +
 src/remote/remote_driver.c   |1 +
 src/remote/remote_protocol.x |8 ++-
 src/remote_protocol-structs  |4 +++
 src/test/test_driver.c   |1 +
 src/uml/uml_driver.c |1 +
 src/vbox/vbox_tmpl.c |1 +
 src/vmware/vmware_driver.c   |1 +
 src/xen/xen_driver.c |1 +
 src/xen/xen_driver.h |1 +
 src/xen/xen_hypervisor.c |1 +
 src/xen/xen_inotify.c|1 +
 src/xen/xend_internal.c  |1 +
 src/xen/xm_internal.c|1 +
 src/xen/xs_internal.c|1 +
 src/xenapi/xenapi_driver.c   |1 +
 tools/virsh.c|   35 
 tools/virsh.pod  |4 +++
 34 files changed, 243 insertions(+), 3 deletions(-)

-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 3/6 V4] inject-nmi: Implementing the public API

2011-05-10 Thread Lai Jiangshan
---
 src/libvirt.c |   44 
 1 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/src/libvirt.c b/src/libvirt.c
index abacf85..f468b61 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -5217,6 +5217,50 @@ error:
 }
 
 /**
+ * virDomainInjectNMI:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @flags:  the flags for controlling behaviours
+ *
+ * Send NMI to the guest
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int virDomainInjectNMI(virDomainPtr domain, unsigned int flags)
+{
+virConnectPtr conn;
+VIR_DOMAIN_DEBUG(domain, flags=%u, flags);
+
+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-domainInjectNMI) {
+int ret;
+ret = conn-driver-domainInjectNMI(domain, flags);
+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
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 6/6 V4] qemu, inject-nmi: Implement the driver methods

2011-05-10 Thread Lai Jiangshan
---
 src/qemu/qemu_driver.c   |   46 +-
 src/qemu/qemu_monitor.c  |   14 
 src/qemu/qemu_monitor.h  |2 +
 src/qemu/qemu_monitor_json.c |   27 
 src/qemu/qemu_monitor_json.h |1 +
 src/qemu/qemu_monitor_text.c |   28 +
 src/qemu/qemu_monitor_text.h |1 +
 7 files changed, 118 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index fa4a2bd..bec0e35 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1705,6 +1705,50 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, 
unsigned long memory)
 return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
 }
 
+static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+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 = qemuMonitorInjectNMI(priv-mon);
+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)
 {
@@ -7192,7 +7236,7 @@ static virDriver qemuDriver = {
 qemuDomainSnapshotDelete, /* domainSnapshotDelete */
 qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
 qemuDomainOpenConsole, /* domainOpenConsole */
-NULL, /* domainInjectNMI */
+qemuDomainInjectNMI, /* domainInjectNMI */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f89038e..9f0f20d 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2228,3 +2228,17 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
 ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply);
 return ret;
 }
+
+
+int qemuMonitorInjectNMI(qemuMonitorPtr mon)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, mon);
+
+if (mon-json)
+ret = qemuMonitorJSONInjectNMI(mon);
+else
+ret = qemuMonitorTextInjectNMI(mon);
+return ret;
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c90219b..b84e230 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -423,6 +423,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
 char **reply,
 bool hmp);
 
+int qemuMonitorInjectNMI(qemuMonitorPtr mon);
+
 /**
  * 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..04ef077 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2513,3 +2513,30 @@ cleanup:
 
 return ret;
 }
+
+int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon)
+{
+int ret;
+virJSONValuePtr cmd;
+virJSONValuePtr reply = NULL;
+
+cmd = qemuMonitorJSONMakeCommand(inject-nmi, NULL);
+if (!cmd)
+return -1;
+
+if ((ret = qemuMonitorJSONCommand(mon, cmd, reply))  0)
+goto cleanup;
+
+if (qemuMonitorJSONHasError(reply, CommandNotFound) 
+qemuMonitorCheckHMP(mon, inject-nmi)) {
+VIR_DEBUG0(inject-nmi command not found, trying HMP);
+ret = qemuMonitorTextInjectNMI(mon);
+} else {
+ret = qemuMonitorJSONCheckError(cmd, reply);
+}
+
+cleanup:
+virJSONValueFree(cmd);
+virJSONValueFree(reply);
+return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 086f0e1..f2dc4d2 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -204,4 +204,5 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
 char **reply_str,
 bool hmp);
 
+int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon);
 #endif /* QEMU_MONITOR_JSON_H */
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 53781c8..1a15d49 100644
--- a/src/qemu/qemu_monitor_text.c
+++ 

[libvirt] [PATCH 1/6 V4] inject-nmi: Defining the public API

2011-05-10 Thread Lai Jiangshan
---
 include/libvirt/libvirt.h.in |2 ++
 src/libvirt_public.syms  |5 +
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 5783303..0e1e27a 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2519,6 +2519,8 @@ int virDomainOpenConsole(virDomainPtr dom,
  virStreamPtr st,
  unsigned int flags);
 
+int virDomainInjectNMI(virDomainPtr domain, unsigned int flags);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index b4aed41..ababf39 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -436,4 +436,9 @@ LIBVIRT_0.9.0 {
 virStorageVolUpload;
 } LIBVIRT_0.8.8;
 
+LIBVIRT_0.9.2 {
+global:
+virDomainInjectNMI;
+} LIBVIRT_0.9.0;
+
 #  define new API here using predicted next version number 
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 5/6 V4] inject-nmi: Expose the new API in virsh

2011-05-10 Thread Lai Jiangshan
---
 tools/virsh.c   |   35 +++
 tools/virsh.pod |4 
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 2b16714..c2dabd7 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2912,6 +2912,40 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * inject-nmi command
+ */
+static const vshCmdInfo info_inject_nmi[] = {
+{help, N_(Inject NMI to the guest)},
+{desc, N_(Inject NMI to the guest domain.)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_inject_nmi[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{NULL, 0, 0, NULL}
+};
+
+
+static bool
+cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = true;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (virDomainInjectNMI(dom, 0)  0)
+ret = false;
+
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * setmemory command
  */
 static const vshCmdInfo info_setmem[] = {
@@ -10720,6 +10754,7 @@ static const vshCmdDef domManagementCmds[] = {
 {setmaxmem, cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
 {setmem, cmdSetmem, opts_setmem, info_setmem},
 {setvcpus, cmdSetvcpus, opts_setvcpus, info_setvcpus},
+{inject-nmi, cmdInjectNMI, opts_inject_nmi, info_inject_nmi},
 {shutdown, cmdShutdown, opts_shutdown, info_shutdown},
 {start, cmdStart, opts_start, info_start},
 {suspend, cmdSuspend, opts_suspend, info_suspend},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 2a708f6..f317c57 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -290,6 +290,10 @@ running Bvirsh suspend.  When in a paused state the 
domain will still
 consume allocated resources like memory, but will not be eligible for
 scheduling by the hypervisor.
 
+=item Binject-nmi Idomain-id
+
+Inject NMI to the guest
+
 =item Bshutdown
 
 The domain is in the process of shutting down, i.e. the guest operating system
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/6 V4] inject-nmi: Implementing the remote protocol

2011-05-10 Thread Lai Jiangshan
---
 daemon/remote_generator.pl   |2 +-
 src/remote/remote_driver.c   |2 +-
 src/remote/remote_protocol.x |8 +++-
 src/remote_protocol-structs  |4 
 4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl
index 062ccc1..74fa769 100755
--- a/daemon/remote_generator.pl
+++ b/daemon/remote_generator.pl
@@ -35,7 +35,7 @@ sub name_to_ProcName {
 @elems = map { $_ =~ s/Nwfilter/NWFilter/; $_ =~ s/Xml/XML/;
$_ =~ s/Uri/URI/; $_ =~ s/Uuid/UUID/; $_ =~ s/Id/ID/;
$_ =~ s/Mac/MAC/; $_ =~ s/Cpu/CPU/; $_ =~ s/Os/OS/;
-   $_ } @elems;
+   $_ =~ s/Nmi/NMI/; $_ } @elems;
 join , @elems
 }
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index c6beb3d..0a1afde 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -6493,7 +6493,7 @@ static virDriver remote_driver = {
 remoteDomainSnapshotDelete, /* domainSnapshotDelete */
 remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
 remoteDomainOpenConsole, /* domainOpenConsole */
-NULL, /* domainInjectNMI */
+remoteDomainInjectNMI, /* domainInjectNMI */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index c706c36..cdb8369 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -817,6 +817,11 @@ struct remote_domain_undefine_args {
 remote_nonnull_domain dom;
 };
 
+struct remote_domain_inject_nmi_args {
+remote_nonnull_domain dom;
+unsigned int flags;
+};
+
 struct remote_domain_set_vcpus_args {
 remote_nonnull_domain dom;
 int nvcpus;
@@ -2176,7 +2181,8 @@ 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_INJECT_NMI = 210
 
 /*
  * Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index f904c4d..8a5ade0 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1435,3 +1435,7 @@ struct remote_message_header {
 u_int  serial;
 remote_message_status  status;
 };
+struct remote_domain_inject_nmi_args {
+remote_nonnull_domain  dom;
+unsigned int   flags;
+};
-- 
1.7.4.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH] libvirt, logging: cleanup VIR_DEBUG0() VIR_INFO0() VIR_WARN0() VIR_ERROR0()

2011-05-10 Thread Lai Jiangshan
Is this OK?  fmt...

#define high_level_api(fmt...) low_level_api(fmt)

On 05/10/2011 11:29 PM, Eric Blake wrote:
 On 05/10/2011 08:52 AM, Eric Blake wrote:
 On 05/09/2011 03:24 AM, Lai Jiangshan wrote:
 These VIR_0 APIs make us confused, use the non-0-suffix APIs instead.

 How these coversions works? The magic is using ##.
 #define high_levle_api(fmt, ...) low_levle_api(fmt, ##__VA_ARGS__)
 When __VA_ARGS__ is empty, ## will swallow the , in fmt, to avoid 
 compile error.

 ##__VA_ARGS__ is a GNU extension; it does not work on all C99 compilers.

 I'm worried that this is not portable.
 
 But, we CAN do:
 
 #ifdef __GNUC__
 # define high_level(fmt, ...) low_level(fmt, ##__VA_ARGS__)
 #else
 # define PP_NARG(...) \
  PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
 # define PP_NARG_(...) \
  PP_ARG_N(__VA_ARGS__)
 # define PP_ARG_N( \
   _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
  _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
  _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
  _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
  _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
  _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
  _61,_62,_63,N,...) N
 # define PP_RSEQ_N() \
  63,62,61,60,   \
  59,58,57,56,55,54,53,52,51,50, \
  49,48,47,46,45,44,43,42,41,40, \
  39,38,37,36,35,34,33,32,31,30, \
  29,28,27,26,25,24,23,22,21,20, \
  19,18,17,16,15,14,13,12,11,10, \
  9,8,7,6,5,4,3,2,1,0
 # define VIR_DEBUG(...) VIR_DEBUG ## PP_NARG(__VA_ARGS__) (__VA_ARGS__)
 # define VIR_DEBUG1(xxx) xxx
 # define VIR_DEBUG2(xxx, xxx) xxx
 ...
 # define VIR_DEBUG63(xxx, ..., xxx) xxx
 #endif
 
 suitably expanded (and we can also place a cap on the maximum number of
 arguments we ever expect to see in VIR_DEBUG, rather than going all the
 way to the C99 limit of 63).
 
 Thanks to:
 https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5
 for the idea.
 
 Yeah, it's gross, but we limit the grossness to one header, and the rest
 of the code is more maintainable as a result.
 

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 0/6 V3] Add support for injecting NMI to guest

2011-05-05 Thread Lai Jiangshan
On 04/21/2011 02:42 PM, Lai Jiangshan wrote:
 
 
 This patch series implements a feature of injecting NMI to guest,
 which is accessible via new virDomainInjectNMI API and
 'inject-nmi' command in virsh.
 
 Lai Jiangshan (6):
   inject-nmi: Defining the public API
   inject-nmi: Defining the internal API
   inject-nmi: Implementing the public API
   inject-nmi: Implementing the remote protocol
   inject-nmi: Expose the new API in virsh
   qemu,inject-nmi: Implement the driver methods
 

Hi, Eric and Daniel:

In qemu community, Luiz have accepted the inject-nmi patches,
could you accept these patches for libvirt?

Thanks,
Lai.
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 2/6 V3] inject-nmi: Defining the internal API

2011-04-21 Thread Lai Jiangshan


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/driver.h   |4 
 src/esx/esx_driver.c   |1 +
 src/libxl/libxl_driver.c   |1 +
 src/lxc/lxc_driver.c   |1 +
 src/openvz/openvz_driver.c |1 +
 src/phyp/phyp_driver.c |3 ++-
 src/qemu/qemu_driver.c |1 +
 src/remote/remote_driver.c |1 +
 src/test/test_driver.c |1 +
 src/uml/uml_driver.c   |1 +
 src/vbox/vbox_tmpl.c   |1 +
 src/vmware/vmware_driver.c |1 +
 src/xen/xen_driver.c   |1 +
 src/xen/xen_driver.h   |1 +
 src/xen/xen_hypervisor.c   |1 +
 src/xen/xen_inotify.c  |1 +
 src/xen/xend_internal.c|1 +
 src/xen/xm_internal.c  |1 +
 src/xen/xs_internal.c  |1 +
 src/xenapi/xenapi_driver.c |1 +
 20 files changed, 24 insertions(+), 1 deletions(-)

diff --git a/src/driver.h b/src/driver.h
index a8b79e6..94cc37d 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -515,6 +515,9 @@ typedef int
virStreamPtr st,
unsigned int flags);
 
+typedef int
+(*virDrvDomainInjectNMI)(virDomainPtr dom, unsigned int flags);
+
 
 /**
  * _virDriver:
@@ -639,6 +642,7 @@ struct _virDriver {
 virDrvDomainSnapshotDelete domainSnapshotDelete;
 virDrvQemuDomainMonitorCommand qemuDomainMonitorCommand;
 virDrvDomainOpenConsole domainOpenConsole;
+virDrvDomainInjectNMI domainInjectNMI;
 };
 
 typedef int
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 50c631b..5b9edea 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -4672,6 +4672,7 @@ static virDriver esxDriver = {
 esxDomainSnapshotDelete, /* domainSnapshotDelete */
 NULL,/* qemuDomainMonitorCommand */
 NULL,/* domainOpenConsole */
+NULL,/* domainInjectNMI */
 };
 
 
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 247d78e..bc6d0d9 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -2748,6 +2748,7 @@ static virDriver libxlDriver = {
 NULL,   /* domainSnapshotDelete */
 NULL,   /* qemuDomainMonitorCommand */
 NULL,   /* domainOpenConsole */
+NULL,   /* domainInjectNMI */
 };
 
 static virStateDriver libxlStateDriver = {
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index e905302..fbbe803 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -2906,6 +2906,7 @@ static virDriver lxcDriver = {
 NULL, /* domainSnapshotDelete */
 NULL, /* qemuDomainMonitorCommand */
 lxcDomainOpenConsole, /* domainOpenConsole */
+NULL, /* domainInjectNMI */
 };
 
 static virStateDriver lxcStateDriver = {
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 4af28e9..96f82bb 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -1667,6 +1667,7 @@ static virDriver openvzDriver = {
 NULL, /* domainSnapshotDelete */
 NULL, /* qemuDomainMonitorCommand */
 NULL, /* domainOpenConsole */
+NULL, /* domainInjectNMI */
 };
 
 int openvzRegister(void) {
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index bb0e0ac..33848ff 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -3794,7 +3794,8 @@ static virDriver phypDriver = {
 NULL,   /* domainRevertToSnapshot */
 NULL,   /* domainSnapshotDelete */
 NULL,   /* qemuMonitorCommand */
-NULL, /* domainOpenConsole */
+NULL,   /* domainOpenConsole */
+NULL,   /* domainInjectNMI */
 };
 
 static virStorageDriver phypStorageDriver = {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f6e503a..ac1adbb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7031,6 +7031,7 @@ static virDriver qemuDriver = {
 qemuDomainSnapshotDelete, /* domainSnapshotDelete */
 qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
 qemuDomainOpenConsole, /* domainOpenConsole */
+NULL, /* domainInjectNMI */
 };
 
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e30780c..4655338 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -11298,6 +11298,7 @@ static virDriver remote_driver = {
 remoteDomainSnapshotDelete, /* domainSnapshotDelete */
 remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
 remoteDomainOpenConsole, /* domainOpenConsole */
+NULL, /* domainInjectNMI */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 0978214..f3df6a5 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -5447,6 +5447,7 @@ static virDriver testDriver = {
 NULL, /* domainSnapshotDelete */
 NULL

[libvirt] [PATCH 0/6 V3] Add support for injecting NMI to guest

2011-04-21 Thread Lai Jiangshan


This patch series implements a feature of injecting NMI to guest,
which is accessible via new virDomainInjectNMI API and
'inject-nmi' command in virsh.

Lai Jiangshan (6):
  inject-nmi: Defining the public API
  inject-nmi: Defining the internal API
  inject-nmi: Implementing the public API
  inject-nmi: Implementing the remote protocol
  inject-nmi: Expose the new API in virsh
  qemu,inject-nmi: Implement the driver methods

 daemon/remote.c |   28 +
 daemon/remote_dispatch_args.h   |1 +
 daemon/remote_dispatch_prototypes.h |8 ++
 daemon/remote_dispatch_table.h  |5 
 include/libvirt/libvirt.h.in|2 +
 src/driver.h|4 +++
 src/esx/esx_driver.c|1 +
 src/libvirt.c   |   44 ++
 src/libvirt_public.syms |5 
 src/libxl/libxl_driver.c|1 +
 src/lxc/lxc_driver.c|1 +
 src/openvz/openvz_driver.c  |1 +
 src/phyp/phyp_driver.c  |3 +-
 src/qemu/qemu_driver.c  |   45 +++
 src/qemu/qemu_monitor.c |   14 +++
 src/qemu/qemu_monitor.h |2 +
 src/qemu/qemu_monitor_json.c|   27 +
 src/qemu/qemu_monitor_json.h|1 +
 src/qemu/qemu_monitor_text.c|   20 +++
 src/qemu/qemu_monitor_text.h|1 +
 src/remote/remote_driver.c  |   25 +++
 src/remote/remote_protocol.c|   11 
 src/remote/remote_protocol.h|   10 +++
 src/remote/remote_protocol.x|8 +-
 src/remote_protocol-structs |4 +++
 src/test/test_driver.c  |1 +
 src/uml/uml_driver.c|1 +
 src/vbox/vbox_tmpl.c|1 +
 src/vmware/vmware_driver.c  |1 +
 src/xen/xen_driver.c|1 +
 src/xen/xen_driver.h|1 +
 src/xen/xen_hypervisor.c|1 +
 src/xen/xen_inotify.c   |1 +
 src/xen/xend_internal.c |1 +
 src/xen/xm_internal.c   |1 +
 src/xen/xs_internal.c   |1 +
 src/xenapi/xenapi_driver.c  |1 +
 tools/virsh.c   |   35 +++
 tools/virsh.pod |4 +++
 39 files changed, 321 insertions(+), 2 deletions(-)

-- 
1.7.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 3/6 V3] inject-nmi: Implementing the public API

2011-04-21 Thread Lai Jiangshan


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/libvirt.c |   44 
 1 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/src/libvirt.c b/src/libvirt.c
index 9e6784b..32446d1 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -5214,6 +5214,50 @@ error:
 }
 
 /**
+ * virDomainInjectNMI:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @flags:  the flags for controlling behaviours
+ *
+ * Send NMI to the guest
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int virDomainInjectNMI(virDomainPtr domain, unsigned int flags)
+{
+virConnectPtr conn;
+VIR_DOMAIN_DEBUG(domain, flags=%u, flags);
+
+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-domainInjectNMI) {
+int ret;
+ret = conn-driver-domainInjectNMI(domain, flags);
+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
-- 
1.7.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 4/6 V3] inject-nmi: Implementing the remote protocol

2011-04-21 Thread Lai Jiangshan


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 daemon/remote.c |   28 
 daemon/remote_dispatch_args.h   |1 +
 daemon/remote_dispatch_prototypes.h |8 
 daemon/remote_dispatch_table.h  |5 +
 src/remote/remote_driver.c  |   26 +-
 src/remote/remote_protocol.c|   11 +++
 src/remote/remote_protocol.h|   10 ++
 src/remote/remote_protocol.x|8 +++-
 src/remote_protocol-structs |4 
 9 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 54fef64..9ae232e 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -3288,6 +3288,34 @@ no_memory:
 }
 
 static int
+remoteDispatchDomainInjectNmi(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_inject_nmi_args *args,
+  void *ret ATTRIBUTE_UNUSED)
+{
+virDomainPtr dom;
+int rv = -1;
+
+if (!(dom = get_nonnull_domain(conn, args-dom)))
+goto cleanup;
+
+if (virDomainInjectNMI(dom, args-flags) == -1)
+goto cleanup;
+
+rv = 0;
+
+cleanup:
+if (rv  0)
+remoteDispatchError(rerr);
+if (dom)
+virDomainFree(dom);
+return rv;
+}
+
+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..4887d7c 100644
--- a/daemon/remote_dispatch_args.h
+++ b/daemon/remote_dispatch_args.h
@@ -178,3 +178,4 @@
 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_inject_nmi_args val_remote_domain_inject_nmi_args;
diff --git a/daemon/remote_dispatch_prototypes.h 
b/daemon/remote_dispatch_prototypes.h
index 18bf41d..3de6046 100644
--- a/daemon/remote_dispatch_prototypes.h
+++ b/daemon/remote_dispatch_prototypes.h
@@ -338,6 +338,14 @@ static int remoteDispatchDomainHasManagedSaveImage(
 remote_error *err,
 remote_domain_has_managed_save_image_args *args,
 remote_domain_has_managed_save_image_ret *ret);
+static int remoteDispatchDomainInjectNmi(
+struct qemud_server *server,
+struct qemud_client *client,
+virConnectPtr conn,
+remote_message_header *hdr,
+remote_error *err,
+remote_domain_inject_nmi_args *args,
+void *ret);
 static int remoteDispatchDomainInterfaceStats(
 struct qemud_server *server,
 struct qemud_client *client,
diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h
index b39f7c2..dacafdb 100644
--- a/daemon/remote_dispatch_table.h
+++ b/daemon/remote_dispatch_table.h
@@ -1052,3 +1052,8 @@
 .args_filter = (xdrproc_t) xdr_remote_storage_vol_download_args,
 .ret_filter = (xdrproc_t) xdr_void,
 },
+{   /* DomainInjectNmi = 210 */
+.fn = (dispatch_fn) remoteDispatchDomainInjectNmi,
+.args_filter = (xdrproc_t) xdr_remote_domain_inject_nmi_args,
+.ret_filter = (xdrproc_t) xdr_void,
+},
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 4655338..58eb682 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2933,6 +2933,30 @@ done:
 }
 
 static int
+remoteDomainInjectNMI(virDomainPtr domain, unsigned int flags)
+{
+int rv = -1;
+remote_domain_inject_nmi_args args;
+struct private_data *priv = domain-conn-privateData;
+
+remoteDriverLock(priv);
+
+make_nonnull_domain (args.dom, domain);
+args.flags = flags;
+
+if (call (domain-conn, priv, 0, REMOTE_PROC_DOMAIN_INJECT_NMI,
+  (xdrproc_t) xdr_remote_domain_inject_nmi_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;
@@ -11298,7 +11322,7 @@ static virDriver remote_driver = {
 remoteDomainSnapshotDelete, /* domainSnapshotDelete */
 remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
 remoteDomainOpenConsole, /* domainOpenConsole */
-NULL, /* domainInjectNMI */
+remoteDomainInjectNMI, /* domainInjectNMI */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c
index 5604371..3ff0b1f 100644
--- a/src/remote

[libvirt] [PATCH 5/6 V3] inject-nmi: Expose the new API in virsh

2011-04-21 Thread Lai Jiangshan


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 tools/virsh.c   |   35 +++
 tools/virsh.pod |4 
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 9ac27b3..54fd6bf 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2912,6 +2912,40 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * inject-nmi command
+ */
+static const vshCmdInfo info_inject_nmi[] = {
+{help, N_(Inject NMI to the guest)},
+{desc, N_(Inject NMI to the guest domain.)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_inject_nmi[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{NULL, 0, 0, NULL}
+};
+
+
+static bool
+cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = true;
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return false;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return false;
+
+if (virDomainInjectNMI(dom, 0)  0)
+ret = false;
+
+virDomainFree(dom);
+return ret;
+}
+
+/*
  * setmemory command
  */
 static const vshCmdInfo info_setmem[] = {
@@ -10730,6 +10764,7 @@ static const vshCmdDef domManagementCmds[] = {
 {setmaxmem, cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
 {setmem, cmdSetmem, opts_setmem, info_setmem},
 {setvcpus, cmdSetvcpus, opts_setvcpus, info_setvcpus},
+{inject-nmi, cmdInjectNMI, opts_inject_nmi, info_inject_nmi},
 {shutdown, cmdShutdown, opts_shutdown, info_shutdown},
 {start, cmdStart, opts_start, info_start},
 {suspend, cmdSuspend, opts_suspend, info_suspend},
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 2a708f6..f317c57 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -290,6 +290,10 @@ running Bvirsh suspend.  When in a paused state the 
domain will still
 consume allocated resources like memory, but will not be eligible for
 scheduling by the hypervisor.
 
+=item Binject-nmi Idomain-id
+
+Inject NMI to the guest
+
 =item Bshutdown
 
 The domain is in the process of shutting down, i.e. the guest operating system
-- 
1.7.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH 6/6 V3] qemu, inject-nmi: Implement the driver methods

2011-04-21 Thread Lai Jiangshan


Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 src/qemu/qemu_driver.c   |   46 +-
 src/qemu/qemu_monitor.c  |   14 
 src/qemu/qemu_monitor.h  |2 +
 src/qemu/qemu_monitor_json.c |   27 
 src/qemu/qemu_monitor_json.h |1 +
 src/qemu/qemu_monitor_text.c |   20 ++
 src/qemu/qemu_monitor_text.h |1 +
 7 files changed, 110 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ac1adbb..548e657 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1702,6 +1702,50 @@ static int qemudDomainSetMaxMemory(virDomainPtr dom, 
unsigned long memory)
 return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
 }
 
+static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
+{
+struct qemud_driver *driver = domain-conn-privateData;
+virDomainObjPtr vm = NULL;
+int ret = -1;
+qemuDomainObjPrivatePtr priv;
+
+virCheckFlags(0, -1);
+
+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 = qemuMonitorInjectNMI(priv-mon);
+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)
 {
@@ -7031,7 +7075,7 @@ static virDriver qemuDriver = {
 qemuDomainSnapshotDelete, /* domainSnapshotDelete */
 qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
 qemuDomainOpenConsole, /* domainOpenConsole */
-NULL, /* domainInjectNMI */
+qemuDomainInjectNMI, /* domainInjectNMI */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 2d28f8d..5ed41e1 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2228,3 +2228,17 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
 ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply);
 return ret;
 }
+
+
+int qemuMonitorInjectNMI(qemuMonitorPtr mon)
+{
+int ret;
+
+VIR_DEBUG(mon=%p, mon);
+
+if (mon-json)
+ret = qemuMonitorJSONInjectNMI(mon);
+else
+ret = qemuMonitorTextInjectNMI(mon);
+return ret;
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c90219b..b84e230 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -423,6 +423,8 @@ int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
 char **reply,
 bool hmp);
 
+int qemuMonitorInjectNMI(qemuMonitorPtr mon);
+
 /**
  * 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..04ef077 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2513,3 +2513,30 @@ cleanup:
 
 return ret;
 }
+
+int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon)
+{
+int ret;
+virJSONValuePtr cmd;
+virJSONValuePtr reply = NULL;
+
+cmd = qemuMonitorJSONMakeCommand(inject-nmi, NULL);
+if (!cmd)
+return -1;
+
+if ((ret = qemuMonitorJSONCommand(mon, cmd, reply))  0)
+goto cleanup;
+
+if (qemuMonitorJSONHasError(reply, CommandNotFound) 
+qemuMonitorCheckHMP(mon, inject-nmi)) {
+VIR_DEBUG0(inject-nmi command not found, trying HMP);
+ret = qemuMonitorTextInjectNMI(mon);
+} else {
+ret = qemuMonitorJSONCheckError(cmd, reply);
+}
+
+cleanup:
+virJSONValueFree(cmd);
+virJSONValueFree(reply);
+return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 086f0e1..f2dc4d2 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -204,4 +204,5 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
 char **reply_str,
 bool hmp);
 
+int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon);
 #endif /* QEMU_MONITOR_JSON_H */
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 53781c8..2ce871c 100644
--- a/src

  1   2   >