[Libvir] Add 'setvcpus', 'setmem', 'setmaxmem' to virsh
by Daniel P. Berrange
The attached patch adds three new commands to virsh:
setmem change memory allocation
setmaxmem change maximum memory limit
setvcpus change number of virtual CPUs
It also ensures then when using the 'test' hypervisor driver, it always
opens a read-write connection even as non-root. The test hypervisor does
not have any distinction between privileged / unprivileged users, so this
test for 'uuid == 0' was bogus.
Regards,
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
18 years, 3 months
[Libvir] Flags for CPU / system 'features'
by Daniel P. Berrange
In the XenD config there are various flags which allow CPU / system features
to be enabled / disabled for the guest domain. For example, HVM domains can
be created with, or without, PAE, ACPI, APIC. The XenD sexpr contains simple
boolean flags for these features within the (image (hvm ....)) block. IMHO,
although these 3 particular features may be only be relevant for HVM, it does
not make sense to restrict the expression of features to only HVM domains.
Thus I propose a top level '<features>' block within the '<domain>' XML doc.
This block would contain tags named after each feature to be enabled. Presence
of the named tag enables the feature, ommision disables it (thus all features
are disabled by default - matching current behaviour).
As an example, to enable ACPI, PAE & APIC:
<domain type='xen' id='55'>
<name>too</name>
<uuid>b5d70dd275cdaca517769660b059d8bc</uuid>
<os>
<type>hvm</type>
<loader>/usr/lib/xen/boot/hvmloader</loader>
<boot dev='hd'/>
</os>
<memory>409600</memory>
<vcpu>1</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<devices>
...snipped from example..
</devices>
</domain>
More flags could trivially be added over time. The attached patch implements
this proposal.
My only thought, is 'features' a good name for this ? Only other name I
came up with was 'capabilities' but this is harder to spell :-)
Regards,
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
18 years, 3 months
[Libvir] Fix handling of HVM boot parameters
by Daniel P. Berrange
Jeremy mentioned that it looked like libvirt wasn't able to create an
HVM domain configured to boot off cdrom, so I took a closer look at the
code and indeed the code dealing with <boot> section was both incomplete,
and just plain broken. Incomplete in so much as it never included details
of the ISO file backing the CDROM, and broken in so much as it was doing
string comparisons against the wrong variables. Digging further found
lots more work relating to creation of HVM domains so I've had a go at
writing a patch to resolve matters.
* Parsing of UUID from SEXPR assumed that the UUID fetched would always
have four '-' in the usual places. Well, when you run 'dumpxml' from
virsh the <uuid> element has the UUID encoded without any '-' chars.
If you feed this back into 'virsh create' and then once again run
'dumpxml' parsing will fail & libvirt throws errors. So this patch
allows for parsing of UUID's without '-'.
* The XML document size was limited to 1k - we just 'malloc(1000)'. While
this was enough for common cases, if someone creates lots of disk or
network devices this would overflow and libvirt return an error. So I
increased it to 4k which ought to be enough for forseeable future - in
any case my previous patch to fetch XML via the proxy is limited to 4k
in size too.
Now onto the fine details...
When converting SEXPR into XML current code is doing the following:
(boot a) -> <boot dev='/dev/fd0'/>
(boot c) -> <boot dev='hda'/>
(boot d) -> <boot dev='/dev/cdrom'/>
This is rather inconsistent - the 'hda' is intended to map to an entry
in <devices> block. The '/dev/fd0' and '/dev/cdrom' entries did not
map to anything.
Meanwhile, when converting from XML to SXEXPR it is doing the following
<boot dev='hda'/> -> (boot a)
<boot dev='hdd'/> -> (boot d)
<boot dev='*'/> -> (boot c)
Obviously this sucks because these processes should be matching each
other.
Secondly, the (image (hvm....)) SEXPR has three entries for defining
the ISO / disk image file backing the CDROM / Floppy devices. These
were just being ignored, rather than turned into <disk> entries within
the <devices> block. Similarly there was no way to express a <disk>
entry for CDROM/Floppy in the XML when creating a domain.
The upshot of all this is that although the last release of libvirt
included HVM support it was basically unusable for domain creation
unless you were using HD to boot. The XML returned was also incorrect.
Now the good news. Since it was sooo broken, we can fix without worrying
about XML compatability since there is no way any application could be
relying on it in its current state.
Now before I discuss the solution, one final point. The Xen IOMMU model
allows specifiying the boot device in terms of 'a', 'c', 'd' which has
the meaning:
a - first connected floppy device
c - first connected harddrive
d - first connected cdrom
In particular it does *not* allow for expressing boot device in terms
of an explicit disk device - you can't say boot off 'hdb' or 'hdc'. So
the current libvirt code which tries to fake such semantics is doomed
to failure. This isn't really too bad IMHO - VMware has these same
semantics, so does QEMU and so do normal bare metal BIOS
This in the patch I have attached I have implemented the following mapping:
(boot a) <-> <boot dev='fd'/>
(boot c) <-> <boot dev='hd'/>
(boot d) <-> <boot dev='cdrom'/>
The other part of the patch is to deal with definition of the floppy and
cdrom device backing files. For this I have done the following:
(image (hvm (fda /root/diskboot.img)))
<devices>
<disk type='file'>
<source file='/root/diskboot.img'/>
<target dev='fda'/>
</disk>
</devices>
And similar for 'fdb'. Then for cdroms:
(image (hvm (cdrom /root/image.iso)))
<devices>
<disk type='file'>
<source file='/root/image.iso'/>
<target dev='cdrom'/>
</disk>
</devices>
The patch has a little bit of logic such that when converting the
<devices> block backinto an SEXPR it filters out the disk entries
with a dev of 'fda', 'fdb' and 'cdrom' since they need to end up in
a different part of the SEXPR.
Finally, although PV guests automatically get a serial console created
for them (and i don't think you can turn it off), HVM guests need to have
a serial console explicitly requested. Since I recently added support in
the DumpXML method for including details of serial console like this:
<devices>
<console tty="/dev/pts/5"/>
</devices>
I decided to leverage this same structure when creating HVM domains. So
if you have:
<devices>
<console/>
</devices>
Then the SEXPR sent to XenD will include
(image (hvm (serial pty)))
Which enables allocation of PseudoTTY for the HVM's serial console.
I have tested that with this patch I can successfully create a HVM domain
which boots off a floppy, harddrive or cdrom. Furthermore if you then dump
the XML of this domain,the XML you get back will match the XML you fed in
(with the obvious exception of domain ID, and the Pseudo TTY path).
If you have been monitoring xen-devel mailing lists you'll be aware that
in 3.0.3 the way CDROM devices are configured is changing:
http://lists.xensource.com/archives/html/xen-devel/2006-08/msg00369.html
Although the patch attached does not support the config outlined in that
mail, I'm pretty confident that a small incremental patch will be able to
support it without breaking compatability with the changes I've outlined
in this mail. The only tricky bit will be that we need to detect whether
libvirt is running against a 3.0.2 or 3.0.3 version of XenD to decide how
to convert XML -> SEXPR & vica verca.
Regards,
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
18 years, 3 months
[Libvir] Guest Identification
by Juan Walker
Hi,
I'm trying to find a good way to correlate a domain to the machine it's
running on. Can I use libvir or some other method on a domU to get some
information that uniquely identifies it? Perhaps something that I can get
from the XML running on dom0? I'm thinking of using the MAC address because
I imagine that those things should be unique at least per hypervisor, but
I'm not sure if that would work across physical boxes.
The solution would be to use libvir to get the list of domains and then get
the xml which includes the mac address. Then every domain on my network
would hit a server and report its mac address, and then I could make a tree
that links the dom0's to the domU's. I'm wondering if there's a better way
to do this. Any suggestions would be greatly appreciated.
Thanks for your help.
18 years, 3 months
[Libvir] Patch to fix duplicate pause/destroy/shutdown calls
by Daniel P. Berrange
I spent a while chasing an issue where running 'virsh destroy foo' on an
HVM domain would result in an error being returned by the HV ioctl. What
I eventually discovered is that the code was doing a destroy op via XenD
and then also doing it via the hypervisor backend. It didn't typically
show as a problem for PV domains because it seems they took longer to
destroy - so were still around by the time the HV destroy was was called.
I tracked this issue down to the main dispatch methods in src/libvirt.c
which would indeed call both the XenD and HV driver backends for pause
destroy & shutdown methods. The patch attached simply returns as soon as
one of the driver methods returns a success return code.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
18 years, 3 months
[Libvir] Add port number to <graphics> tag
by Daniel P. Berrange
We recently added the '<graphics>' tag to the XML description for HVM
machines. Any apps using this info though would have to hardcode the
assumption that Xen's QEMU listens on Domain-ID + 5900. Hardcoding the
port numbers in the first place is already a really questionable decision,
so we should avoid that propagating out to application code.
Thus, the attached patch changes:
<graphics type="vnc"/>
So that it now looks like
<graphics type="vnc" port="5905"/>
The hardcoded 'Domain-ID + 5900' craziness is now at least isolated in
libvirt, so provided apps take the port number from the XML they will be
immune from changes in port numbering scheme.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
18 years, 3 months
[Libvir] Here the patch for virtual CPU functions.
by Philippe Berthault
The patch (vcpus.diff) is joined with this mail.
To apply the patch, untar the libvirt-0.1.3.tar.gz archive (if not
already done).
Then in libvirt-0.1.3 directory, do
./configure --prefix=/usr
if not already done, and after this:
patch -p1 < vcpus.diff
make
make install
From the initial patch of Michel Ponceau (not delivered), I've just
modify the virDomainGetVcpus function and added some useful macro for
bit manipulation in cpu bit maps.
TODO: These vcpus functions permits to dynamically change the vcpu/cpu
relation after the domain has been started but nothing has been done
regarding static cpus attribution in the XML configuration file of a domain.
Philippe Berthault.
--- libvirt-0.1.3/include/libvirt/libvirt.h 2006-07-11 18:05:07.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/include/libvirt/libvirt.h 2006-08-02 16:42:51.000000000 +0200
@@ -289,6 +289,106 @@
const char **names,
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);
+
+/**
+ * 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 USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8)))
+
+/**
+ * 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 UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8)))
+
+int virDomainGetVcpus (virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+ unsigned char *cpumaps,
+ int maplen);
+
+/**
+ * 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.
+ * CPU_USABLE macro returns a non zero value (true) if the cpu
+ * is usable by the vcpu, and 0 otherwise.
+ */
+
+#define CPU_USABLE(cpumaps,maplen,vcpu,cpu) \
+ (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8)))
+
+/**
+ * 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. 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 COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \
+ memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen))
+
+
+/**
+ * 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. GET_CPUMAP macro returns a pointer to the cpumap
+ * of the specified vcpu from cpumaps array.
+ */
+#define GET_CPUMAP(cpumaps,maplen,vcpu) &(cpumaps[(vcpu)*(maplen)])
+
#ifdef __cplusplus
}
--- libvirt-0.1.3/src/xen_internal.h 2006-07-03 17:09:24.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xen_internal.h 2006-08-02 16:53:42.000000000 +0200
@@ -44,6 +44,18 @@
unsigned long memory);
int xenHypervisorCheckID (virConnectPtr conn,
int id);
+int xenHypervisorSetVcpus (virDomainPtr domain,
+ unsigned int nvcpus);
+int xenHypervisorPinVcpu (virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+ int maplen);
+int xenHypervisorGetVcpus (virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+ unsigned char *cpumaps,
+ int maplen);
+
#ifdef __cplusplus
}
#endif
--- libvirt-0.1.3/src/xen_internal.c 2006-07-03 17:09:24.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xen_internal.c 2006-08-03 13:52:28.000000000 +0200
@@ -18,7 +18,7 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
-
+#include <limits.h>
#include <stdint.h>
/* required for dom0_getdomaininfo_t */
@@ -838,4 +838,138 @@
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 <maxinfo> 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 *)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<<cpu))
+ USE_CPU(cpumap, cpu);
+ }
+ }
+ }
+ return nbinfo;
+}
--- libvirt-0.1.3/src/libvirt.c 2006-07-03 17:09:24.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/libvirt.c 2006-08-02 15:30:29.000000000 +0200
@@ -1648,4 +1648,126 @@
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);
+ }
+// if (xenHypervisorSetVcpus(domain, nvcpus) == 0)
+// return 0;
+ 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);
+ }
+ 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 <maxinfo> 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);
+ }
+ ret = xenHypervisorGetVcpus(domain, info, maxinfo, cpumaps, maplen);
+ if (ret != -1) return ret;
+ return xenDaemonDomainGetVcpus(domain, info, maxinfo, cpumaps, maplen);
+}
--- libvirt-0.1.3/src/xend_internal.h 2006-07-10 12:24:05.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xend_internal.h 2006-08-02 16:54:27.000000000 +0200
@@ -631,6 +631,18 @@
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
--- libvirt-0.1.3/src/libvirt_sym.version 2006-05-29 18:19:30.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/libvirt_sym.version 2006-08-02 15:26:56.000000000 +0200
@@ -47,5 +47,9 @@
virConnResetLastError;
virDefaultErrorFunc;
virNodeGetInfo;
+
+ virDomainSetVcpus;
+ virDomainPinVcpu;
+ virDomainGetVcpus;
local: *;
};
--- libvirt-0.1.3/src/xend_internal.c 2006-07-10 16:41:54.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xend_internal.c 2006-08-02 16:48:24.000000000 +0200
@@ -2429,6 +2429,156 @@
free(name);
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 <maxinfo> 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 *)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)
+ USE_CPU(cpumap, cpu);
+ }
+ break;
+ }
+ }
+
+ if (++nbinfo == maxinfo) break;
+ ipt++;
+ }
+ sexpr_free(root);
+ return nbinfo;
+}
/**
* xenDaemonLookupByUUID:
18 years, 3 months
[Libvir] New (last ?) virtual cpu functions proposal
by Philippe Berthault
Here the new virtual cpu functions proposal.
What do you think about it ?
/**
* *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*;
/**
* *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);
/**
* *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).
* 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);
/* Macros for bit manipulation in cpumap */
#define *USE_CPU*(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8)))
#define *UNUSE_CPU*(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8)))
/**
* *virDomainGetVcpus*:
* @*domain*: pointer to domain object, or NULL for Domain0
* @*info*: pointer to an array of virVcpuInfo structures
* @*maxinfo*: number of structures in info array
* @*cpumaps*: pointer to a bit map of real CPUs for all vcpus of this
domain.
* If cpumaps is NULL, then no cpumap information is returned by
the API.
* It's assumed there is <maxinfo> cpumap in cpumaps.
* The memory allocated to cpumaps must be (maxinfo * maplen) bytes.
* One cpumap inside cupmaps have 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.
*
* 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, /* may be NULL */
int maplen);
/* Macros for bit testing in cpumaps */
#define *CPU_USABLE*(cpumaps,maplen,vcpu,cpu) \
(cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8)))
/*
* Macro for copying the cpumap of a vcpu from cupmaps inside a
standalone cpumap.
* This macro is useful in case of using virDomainPinVcpu() after
virDomainGetVcpus().
* cpumap must be previously allocated.
*/
#define *COPY_CPUMAP*(cpumaps,maplen,vcpu,cpumap) \
memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen))
18 years, 3 months
[Libvir] Newbie questions!
by Rodrigo Lord
Hello!
I`m trying o use libvirt (or libvir?) what`s the difference? (this is the
first question!)
So, I compiled libvirt and libvir on my ia64 system(debian sarge 3.1) and
download the code exemple of the website http://libvirt.org named info1.c
To compile I used: "gcc -o test_dom0 test_dom0.c -lvirt" and ok.
But when I try to run, shows the error below:
peso@debian-ia64:~/test_libvirt$ ./test_dom0
libvir: error : no support for hypervisor Xen
Failed to connect to hypervisor
I tryied too to compile using: "gcc -o test_dom0 test_dom0.c -lvir"
but doesn`t work too:
peso@debian-ia64:~/test_libvirt$ ./test_dom0
Failed to find Domain 0
Thanks!
18 years, 3 months
[Libvir] Re: Virtual CPU functions
by Philippe Berthault
I've tried to illustrate an exemple of virDomainGetVcpus API with a 2
dimensional cpumaps array.
If you are agree with this, I can modify the patch of Michel Ponceau in
this sense before the end of this week.
I've proposed the virDomainGetCpus API to be in accordance with the
virDomainPinVcpu which is per vpcu and not per domain as
virDomainGetVcpus API.
The virDomainPinVcpu API is'nt symmetrical with virDomainGetVcpus and
must be called N times to perform the CPU mapping of a domain which
isn't very satisfying.
Another complaint against the virDomainPinVcpu versus virDomainGetVcpus
API is that the cpumap parameter hasn't the same meaning in these two
APIs. This point requires to duplicate macro for bit manipulations on
these maps.
Philippe Berthault
______________________________________________________________________
virConnectPtr pConn;
virDomainPtr pDomain;
virNodeInfo nodeInfo;
virDomainInfo domInfo;
virVcpuInfoPtr pVcpuInfos;
int nbPhysCpus;
unsigned char *cpuMaps[]; /* 1st dimension = per virtual cpu, 2nd
dimension = per physical cpu */
int oneCpuMapLen;
int vcpu, cpu;
#define CPU_USABLE(maps,vcpu,cpu) (maps[vcpu][((cpu) / 8)] & (1 >>
((cpu) % 8)))
...
virNodeGetInfo(pConn, &nodeInfo);
nbPhysCpus = nodeInfo.cpus;
/* ? or ? */
nbPhysCpus = nodeInfo.nodes * nodeInfo.sockets * nodeInfo.cores *
nodeInfo.threads;
virDomainGetInfo(pDomain, &domInfo);
pVcpuInfos = malloc(sizeof(virVcpuInfo)*domInfo.nrVirtCpu);
oneCpuMapLen = (nbPhysCpus + 7) / 8;
cpuMaps = calloc(domInfo.nrVirtCpu, oneCpuMapLen);
virDomainGetVcpus(pDomain, pVcpuInfos, domInfo.nrVirtCpu, cpuMaps,
oneCpuMapLen);
for (vcpu = 0; vcpu < domInfo.nrVirtCpu; vcpu++) {
for (cpu = 0; cpu < nbPhysCpus; cpu++) {
int byteCpu = cpu / 8;
int bitCpu = cpu % 8;
int mask = 1 >> bitCpu; /* lowest CPU number is least
significant bit as M.Ponceau said */
int cpuUsable = cpuMaps[vcpu][byteCpu] & mask;
...
/* or */
int cpuUsable = CPU_USABLE(cpuMaps, vcpu, cpu);
...
if (cpuUsable) {
printf("The physical cpu #%d is usable by virtual cpu #%d of
domain #%s\n",
cpu, vcpu, virDomainGetName(pDomain));
}
}
}
______________________________________________________________________
18 years, 3 months