From 7a8a63380f6b88601fa4de71e5268b7c82b153b5 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 4 Aug 2006 10:41:05 +0000 Subject: [PATCH] * include/libvirt/libvirt.h include/libvirt/libvirt.h.in src/libvirt.c src/libvirt_sym.version src/xen_internal.c src/xen_internal.h src/xend_internal.c src/xend_internal.h: applied patch from Michel Ponceau and Philippe Berthault for virtual CPU and affinity support plus a bit of cleanup. Daniel --- ChangeLog | 8 ++ include/libvirt/libvirt.h | 101 +++++++++++++++++++++ include/libvirt/libvirt.h.in | 101 +++++++++++++++++++++ src/libvirt.c | 129 +++++++++++++++++++++++++++ src/libvirt_sym.version | 4 + src/xen_internal.c | 135 +++++++++++++++++++++++++++- src/xen_internal.h | 12 +++ src/xend_internal.c | 166 +++++++++++++++++++++++++++++++++-- src/xend_internal.h | 12 +++ 9 files changed, 662 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0dfb41d112..aa432be507 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Fri Aug 4 11:49:44 CEST 2006 Daniel Veillard + + * include/libvirt/libvirt.h include/libvirt/libvirt.h.in + src/libvirt.c src/libvirt_sym.version src/xen_internal.c + src/xen_internal.h src/xend_internal.c src/xend_internal.h: + applied patch from Michel Ponceau and Philippe Berthault for + virtual CPU and affinity support plus a bit of cleanup. + Tue Aug 1 16:22:52 CEST 2006 Daniel Veillard * libvirt.spec.in: xen is now built for ia64, c.f. RH#199685 diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 523bb73011..2db8beba03 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -290,6 +290,107 @@ int virConnectListDefinedDomains(virConnectPtr conn, int maxnames); int virDomainCreate (virDomainPtr domain); +/** + * virVcpuInfo: structure for information about a virtual CPU in a domain. + */ + +typedef enum { + VIR_VCPU_OFFLINE = 0, /* the virtual CPU is offline */ + VIR_VCPU_RUNNING = 1, /* the virtual CPU is running */ + VIR_VCPU_BLOCKED = 2, /* the virtual CPU is blocked on resource */ +} virVcpuState; + +typedef struct _virVcpuInfo virVcpuInfo; +struct _virVcpuInfo { + unsigned int number; /* virtual CPU number */ + int state; /* value from virVcpuState */ + unsigned long long cpuTime; /* CPU time used, in nanoseconds */ + int cpu; /* real CPU number, or -1 if offline */ +}; +typedef virVcpuInfo *virVcpuInfoPtr; + +int virDomainSetVcpus (virDomainPtr domain, + unsigned int nvcpus); + +int virDomainPinVcpu (virDomainPtr domain, + unsigned int vcpu, + unsigned char *cpumap, + int maplen); + +/** + * VIR_USE_CPU: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap. + */ + +#define VIR_USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8))) + +/** + * VIR_UNUSE_CPU: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap. + */ + +#define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) + +int virDomainGetVcpus (virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, + unsigned char *cpumaps, + int maplen); + +/** + * VIR_CPU_USABLE: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainGetVcpus() API. + * VIR_CPU_USABLE macro returns a non zero value (true) if the cpu + * is usable by the vcpu, and 0 otherwise. + */ + +#define VIR_CPU_USABLE(cpumaps,maplen,vcpu,cpu) \ + (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) + +/** + * VIR_COPY_CPUMAP: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * @cpumap: pointer to a cpumap (in 8-bit bytes) (OUT) + * This cpumap must be previously allocated by the caller + * (ie: malloc(maplen)) + * + * This macro is to be used in conjonction with virDomainGetVcpus() and + * virDomainPinVcpu() APIs. VIR_COPY_CPUMAP macro extract the cpumap of + * the specified vcpu from cpumaps array and copy it into cpumap to be used + * later by virDomainPinVcpu() API. + */ +#define VIR_COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \ + memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen)) + + +/** + * VIR_GET_CPUMAP: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * + * This macro is to be used in conjonction with virDomainGetVcpus() and + * virDomainPinVcpu() APIs. VIR_GET_CPUMAP macro returns a pointer to the + * cpumap of the specified vcpu from cpumaps array. + */ +#define VIR_GET_CPUMAP(cpumaps,maplen,vcpu) &(cpumaps[(vcpu)*(maplen)]) + + #ifdef __cplusplus } #endif diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 2668eaafcd..3f8a504ca7 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -290,6 +290,107 @@ int virConnectListDefinedDomains(virConnectPtr conn, int maxnames); int virDomainCreate (virDomainPtr domain); +/** + * virVcpuInfo: structure for information about a virtual CPU in a domain. + */ + +typedef enum { + VIR_VCPU_OFFLINE = 0, /* the virtual CPU is offline */ + VIR_VCPU_RUNNING = 1, /* the virtual CPU is running */ + VIR_VCPU_BLOCKED = 2, /* the virtual CPU is blocked on resource */ +} virVcpuState; + +typedef struct _virVcpuInfo virVcpuInfo; +struct _virVcpuInfo { + unsigned int number; /* virtual CPU number */ + int state; /* value from virVcpuState */ + unsigned long long cpuTime; /* CPU time used, in nanoseconds */ + int cpu; /* real CPU number, or -1 if offline */ +}; +typedef virVcpuInfo *virVcpuInfoPtr; + +int virDomainSetVcpus (virDomainPtr domain, + unsigned int nvcpus); + +int virDomainPinVcpu (virDomainPtr domain, + unsigned int vcpu, + unsigned char *cpumap, + int maplen); + +/** + * VIR_USE_CPU: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap. + */ + +#define VIR_USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8))) + +/** + * VIR_UNUSE_CPU: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap. + */ + +#define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) + +int virDomainGetVcpus (virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, + unsigned char *cpumaps, + int maplen); + +/** + * VIR_CPU_USABLE: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * @cpu: the physical CPU number + * + * This macro is to be used in conjonction with virDomainGetVcpus() API. + * VIR_CPU_USABLE macro returns a non zero value (true) if the cpu + * is usable by the vcpu, and 0 otherwise. + */ + +#define VIR_CPU_USABLE(cpumaps,maplen,vcpu,cpu) \ + (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) + +/** + * VIR_COPY_CPUMAP: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * @cpumap: pointer to a cpumap (in 8-bit bytes) (OUT) + * This cpumap must be previously allocated by the caller + * (ie: malloc(maplen)) + * + * This macro is to be used in conjonction with virDomainGetVcpus() and + * virDomainPinVcpu() APIs. VIR_COPY_CPUMAP macro extract the cpumap of + * the specified vcpu from cpumaps array and copy it into cpumap to be used + * later by virDomainPinVcpu() API. + */ +#define VIR_COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \ + memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen)) + + +/** + * VIR_GET_CPUMAP: + * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN) + * @maplen: the length (in bytes) of one cpumap + * @vcpu: the virtual CPU number + * + * This macro is to be used in conjonction with virDomainGetVcpus() and + * virDomainPinVcpu() APIs. VIR_GET_CPUMAP macro returns a pointer to the + * cpumap of the specified vcpu from cpumaps array. + */ +#define VIR_GET_CPUMAP(cpumaps,maplen,vcpu) &(cpumaps[(vcpu)*(maplen)]) + + #ifdef __cplusplus } #endif diff --git a/src/libvirt.c b/src/libvirt.c index f5734d2f78..70fcf0a7bc 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -1649,3 +1649,132 @@ virDomainCreate(virDomainPtr domain) { return(-1); } +/** + * virDomainSetVcpus: + * @domain: pointer to domain object, or NULL for Domain0 + * @nvcpus: the new number of virtual CPUs for this domain + * + * Dynamically change the number of virtual CPUs used by the domain. + * Note that this call may fail if the underlying virtualization hypervisor + * does not support it or if growing the number is arbitrary limited. + * This function requires priviledged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int +virDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) +{ + if (domain == NULL) { + TODO + return (-1); + } + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) + return (-1); + if (nvcpus < 1) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + /* TODO: access though the driver API not directly */ + +#if 0 + if (xenHypervisorSetVcpus(domain, nvcpus) == 0) + return 0; +#endif + return xenDaemonDomainSetVcpus(domain, nvcpus); +} + +/** + * virDomainPinVcpu: + * @domain: pointer to domain object, or NULL for Domain0 + * @vcpu: virtual CPU number + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN) + * Each bit set to 1 means that corresponding CPU is usable. + * Bytes are stored in little-endian order: CPU0-7, 8-15... + * In each byte, lowest CPU number is least significant bit. + * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in + * underlying virtualization system (Xen...). + * If maplen < size, missing bytes are set to zero. + * If maplen > size, failure code is returned. + * + * Dynamically change the real CPUs which can be allocated to a virtual CPU. + * This function requires priviledged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virDomainPinVcpu(virDomainPtr domain, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + if (domain == NULL) { + TODO + return (-1); + } + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + if (domain->conn->flags & VIR_CONNECT_RO) + return (-1); + if ((vcpu < 1) || (cpumap == NULL) || (maplen < 1)) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + /* TODO: access though the driver API not directly */ + if (xenHypervisorPinVcpu(domain, vcpu, cpumap, maplen) == 0) + return 0; + return (-1); //xenDaemonDomainPinVcpu(domain, vcpu, cpumap, maplen); +} + +/** + * virDomainGetVcpus: + * @domain: pointer to domain object, or NULL for Domain0 + * @info: pointer to an array of virVcpuInfo structures (OUT) + * @maxinfo: number of structures in info array + * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this + * domain (in 8-bit bytes) (OUT) + * If cpumaps is NULL, then no cupmap information is returned by the API. + * It's assumed there is cpumap in cpumaps array. + * The memory allocated to cpumaps must be (maxinfo * maplen) bytes + * (ie: calloc(maxinfo, maplen)). + * One cpumap inside cpumaps has the format described in + * virDomainPinVcpu() API. + * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in + * underlying virtualization system (Xen...). + * + * Extract information about virtual CPUs of domain, store it in info array + * and also in cpumaps if this pointer is'nt NULL. + * + * Returns the number of info filled in case of success, -1 in case of failure. + */ +int +virDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + int ret; + + if (domain == NULL) { + TODO + return (-1); + } + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return (-1); + } + if ((info == NULL) || (maxinfo < 1)) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + if (cpumaps != NULL && maplen < 1) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + /* TODO: access though the driver API not directly */ + ret = xenHypervisorGetVcpus(domain, info, maxinfo, cpumaps, maplen); + if (ret != -1) return ret; + return xenDaemonDomainGetVcpus(domain, info, maxinfo, cpumaps, maplen); +} diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index 0fe40693bc..e29ce78b9d 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -47,5 +47,9 @@ virConnResetLastError; virDefaultErrorFunc; virNodeGetInfo; + + virDomainSetVcpus; + virDomainPinVcpu; + virDomainGetVcpus; local: *; }; diff --git a/src/xen_internal.c b/src/xen_internal.c index d0ca433a94..8887abbe94 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -18,7 +18,7 @@ #include #include #include - +#include #include /* required for dom0_getdomaininfo_t */ @@ -845,3 +845,136 @@ xenHypervisorCheckID(virConnectPtr conn, int id) return (0); } +/** + * xenHypervisorSetVcpus: + * @domain: pointer to domain object + * @nvcpus: the new number of virtual CPUs for this domain + * + * Dynamically change the number of virtual CPUs used by the domain. + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int +xenHypervisorSetVcpus(virDomainPtr domain, unsigned int nvcpus) +{ + dom0_op_t op; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->conn->handle < 0) + || (nvcpus < 1)) + return (-1); + op.cmd = DOM0_MAX_VCPUS; + op.u.max_vcpus.domain = (domid_t) domain->handle; + op.u.max_vcpus.max = nvcpus; + if (xenHypervisorDoOp(domain->conn->handle, &op) < 0) + return (-1); + return 0; +} + +/** + * xenHypervisorPinVcpu: + * @domain: pointer to domain object + * @vcpu: virtual CPU number + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) + * @maplen: length of cpumap in bytes + * + * Dynamically change the real CPUs which can be allocated to a virtual CPU. + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int +xenHypervisorPinVcpu(virDomainPtr domain, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + dom0_op_t op; + uint64_t *pm = (uint64_t *)&op.u.setvcpuaffinity.cpumap; + int j; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->conn->handle < 0) + || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t)) + || (sizeof(cpumap_t) & 7)) + return (-1); + op.cmd = DOM0_SETVCPUAFFINITY; + op.u.setvcpuaffinity.domain = (domid_t) domain->handle; + op.u.setvcpuaffinity.vcpu = vcpu; + memset(pm, 0, sizeof(cpumap_t)); + for (j = 0; j < maplen; j++) + *(pm + (j / 8)) |= cpumap[j] << (8 * (j & 7)); + if (xenHypervisorDoOp(domain->conn->handle, &op) < 0) + return (-1); + return 0; +} + +/** + * virDomainGetVcpus: + * @domain: pointer to domain object, or NULL for Domain0 + * @info: pointer to an array of virVcpuInfo structures (OUT) + * @maxinfo: number of structures in info array + * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT) + * If cpumaps is NULL, then no cupmap information is returned by the API. + * It's assumed there is cpumap in cpumaps array. + * The memory allocated to cpumaps must be (maxinfo * maplen) bytes + * (ie: calloc(maxinfo, maplen)). + * One cpumap inside cpumaps has the format described in virDomainPinVcpu() API. + * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in + * underlying virtualization system (Xen...). + * + * Extract information about virtual CPUs of domain, store it in info array + * and also in cpumaps if this pointer is'nt NULL. + * + * Returns the number of info filled in case of success, -1 in case of failure. + */ +int +xenHypervisorGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + dom0_op_t op; + uint64_t *pm = (uint64_t *)&op.u.getvcpuinfo.cpumap; + virVcpuInfoPtr ipt; + int nbinfo, mapl, i; + unsigned char *cpumap; + int vcpu, cpu; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->conn->handle < 0) + || (info == NULL) || (maxinfo < 1) + || (sizeof(cpumap_t) & 7)) + return (-1); + if (cpumaps != NULL && maplen < 1) + return -1; + + /* first get the number of virtual CPUs in this domain */ + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t) domain->handle; + if (xenHypervisorDoOp(domain->conn->handle, &op) < 0) + return (-1); + nbinfo = (int)op.u.getdomaininfo.max_vcpu_id + 1; + if (nbinfo > maxinfo) nbinfo = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + op.cmd = DOM0_GETVCPUINFO; + for (i=0, ipt=info; i < nbinfo; i++, ipt++) { + vcpu = op.u.getvcpuinfo.vcpu = i; + if (xenHypervisorDoOp(domain->conn->handle, &op) < 0) + return (-1); + ipt->number = i; + if (op.u.getvcpuinfo.online) { + if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING; + if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED; + } + else ipt->state = VIR_VCPU_OFFLINE; + ipt->cpuTime = op.u.getvcpuinfo.cpu_time; + ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1; + if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) { + cpumap = (unsigned char *)VIR_GET_CPUMAP(cpumaps, maplen, vcpu); + mapl = (maplen > (int)sizeof(cpumap_t)) ? (int)sizeof(cpumap_t) : maplen; + for (cpu = 0; cpu < (mapl * CHAR_BIT); cpu++) { + if (*pm & ((uint64_t)1<%s\n", tmp); tmp = sexpr_node(node, "domain/image/hvm/boot"); if ((tmp != NULL) && (tmp[0] != 0)) { - // FIXME: - // Figure out how to map the 'a', 'b', 'c' nonsense to a - // device. + /* + * FIXME: + * Figure out how to map the 'a', 'b', 'c' nonsense to a + * device. + */ if (tmp[0] == 'a') virBufferAdd(buf, " \n", 25 ); else if (tmp[0] == 'c') - // Don't know what to put here. Say the vm has been given 3 - // disks - hda, hdb, hdc. How does one identify the boot disk? + /* + * Don't know what to put here. Say the vm has been given 3 + * disks - hda, hdb, hdc. How does one identify the boot disk? + */ virBufferAdd(buf, " \n", 22 ); else if (strcmp(tmp, "d") == 0) virBufferAdd(buf, " \n", 24 ); @@ -2434,6 +2438,158 @@ xenDaemonLookupByID(virConnectPtr conn, int id) { return (NULL); } +/** + * xenDaemonDomainSetVcpus: + * @domain: pointer to domain object + * @nvcpus: the new number of virtual CPUs for this domain + * + * Dynamically change the number of virtual CPUs used by the domain. + * + * Returns 0 for success; -1 (with errno) on error + */ +int +xenDaemonDomainSetVcpus(virDomainPtr domain, int vcpus) +{ + char buf[16]; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) + || (vcpus < 1)) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return (-1); + } + snprintf(buf, sizeof(buf), "%d", vcpus); + return(xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus", + buf, NULL)); +} + +/** + * xenDaemonDomainPinCpu: + * @domain: pointer to domain object + * @vcpu: virtual CPU number + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) + * @maplen: length of cpumap in bytes + * + * Dynamically change the real CPUs which can be allocated to a virtual CPU. + * + * Returns 0 for success; -1 (with errno) on error + */ +int +xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char buf[16], mapstr[sizeof(cpumap_t) * 64] = "["; + int i, j; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) + || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return (-1); + } + + /* from bit map, build character string of mapped CPU numbers */ + for (i = 0; i < maplen; i++) for (j = 0; j < 8; j++) + if (cpumap[i] & (1 << j)) { + sprintf(buf, "%d,", (8 * i) + j); + strcat(mapstr, buf); + } + mapstr[strlen(mapstr) - 1] = ']'; + snprintf(buf, sizeof(buf), "%d", vcpu); + return(xend_op(domain->conn, domain->name, "op", "pincpu", "vcpu", buf, + "cpumap", mapstr, NULL)); +} + +/** + * virDomainGetVcpus: + * @domain: pointer to domain object, or NULL for Domain0 + * @info: pointer to an array of virVcpuInfo structures (OUT) + * @maxinfo: number of structures in info array + * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT) + * If cpumaps is NULL, then no cupmap information is returned by the API. + * It's assumed there is cpumap in cpumaps array. + * The memory allocated to cpumaps must be (maxinfo * maplen) bytes + * (ie: calloc(maxinfo, maplen)). + * One cpumap inside cpumaps has the format described in virDomainPinVcpu() API. + * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in + * underlying virtualization system (Xen...). + * + * Extract information about virtual CPUs of domain, store it in info array + * and also in cpumaps if this pointer is'nt NULL. + * + * Returns the number of info filled in case of success, -1 in case of failure. + */ +int +xenDaemonDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + struct sexpr *root, *s, *t; + virVcpuInfoPtr ipt = info; + int nbinfo = 0, oln; + unsigned char *cpumap; + int vcpu, cpu; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) + || (info == NULL) || (maxinfo < 1)) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return (-1); + } + if (cpumaps != NULL && maplen < 1) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return (-1); + } + root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name); + if (root == NULL) + return (-1); + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */ + for (s = root; s->kind == SEXPR_CONS; s = s->cdr) + if ((s->car->kind == SEXPR_CONS) && + (s->car->car->kind == SEXPR_VALUE) && + !strcmp(s->car->car->value, "vcpu")) { + t = s->car; + vcpu = ipt->number = sexpr_int(t, "vcpu/number"); + if (oln = sexpr_int(t, "vcpu/online")) { + if (sexpr_int(t, "vcpu/running")) ipt->state = VIR_VCPU_RUNNING; + if (sexpr_int(t, "vcpu/blocked")) ipt->state = VIR_VCPU_BLOCKED; + } + else ipt->state = VIR_VCPU_OFFLINE; + ipt->cpuTime = sexpr_float(t, "vcpu/cpu_time") * 1000000000; + ipt->cpu = oln ? sexpr_int(t, "vcpu/cpu") : -1; + + if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) { + cpumap = (unsigned char *) VIR_GET_CPUMAP(cpumaps, maplen, vcpu); + /* + * get sexpr from "(cpumap (x y z...))" and convert values + * to bitmap + */ + for (t = t->cdr; t->kind == SEXPR_CONS; t = t->cdr) + if ((t->car->kind == SEXPR_CONS) && + (t->car->car->kind == SEXPR_VALUE) && + !strcmp(t->car->car->value, "cpumap") && + (t->car->cdr->kind == SEXPR_CONS)) { + for (t = t->car->cdr->car; t->kind == SEXPR_CONS; t = t->cdr) + if (t->car->kind == SEXPR_VALUE) { + cpu = strtol(t->car->value, NULL, 0); + if (cpu >= 0) + VIR_USE_CPU(cpumap, cpu); + } + break; + } + } + + if (++nbinfo == maxinfo) break; + ipt++; + } + sexpr_free(root); + return(nbinfo); +} + /** * xenDaemonLookupByUUID: * @conn: pointer to the hypervisor connection diff --git a/src/xend_internal.h b/src/xend_internal.h index 3806919a6c..336913bca5 100644 --- a/src/xend_internal.h +++ b/src/xend_internal.h @@ -631,6 +631,18 @@ virDomainPtr xenDaemonDomainLookupByName(virConnectPtr conn, const char *domname unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain); char **xenDaemonListDomainsOld(virConnectPtr xend); +int xenDaemonDomainSetVcpus (virDomainPtr domain, + int vcpus); +int xenDaemonDomainPinVcpu (virDomainPtr domain, + unsigned int vcpu, + unsigned char *cpumap, + int maplen); +int xenDaemonDomainGetVcpus (virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, + unsigned char *cpumaps, + int maplen); + #ifdef __cplusplus } #endif