[Libvir] [PATCH] Add bus attribute to disk target definition
by Soren Hansen
Hi!
I'd like to propose that the following patch gets applied against
libvirt. It adds the option of putting a bus attribute on a disk target.
To acommodate this, it also changes the way drives are defined for kvm
from the old "-hda /path/to/file -boot c" style to the new "-drive
file=/path/to/file,if=ide,boot=on". This makes it possible to specify
virtio, scsi, and ide disks.
=== modified file 'src/qemu_conf.c'
--- src/qemu_conf.c 2008-04-28 15:14:59 +0000
+++ src/qemu_conf.c 2008-04-29 07:43:11 +0000
@@ -568,6 +568,7 @@
xmlChar *source = NULL;
xmlChar *target = NULL;
xmlChar *type = NULL;
+ xmlChar *bus = NULL;
int typ = 0;
type = xmlGetProp(node, BAD_CAST "type");
@@ -598,6 +599,7 @@
} else if ((target == NULL) &&
(xmlStrEqual(cur->name, BAD_CAST "target"))) {
target = xmlGetProp(cur, BAD_CAST "dev");
+ bus = xmlGetProp(cur, BAD_CAST "bus");
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
disk->readonly = 1;
}
@@ -646,7 +648,9 @@
strcmp((const char *)target, "hda") &&
strcmp((const char *)target, "hdb") &&
strcmp((const char *)target, "hdc") &&
- strcmp((const char *)target, "hdd")) {
+ strcmp((const char *)target, "hdd") &&
+ strcmp((const char *)target, "hdd") &&
+ strncmp((const char *)target, "vd", 2)) {
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Invalid harddisk device name: %s"), target);
goto error;
@@ -673,6 +677,20 @@
goto error;
}
+ if (!bus)
+ disk->bus = QEMUD_DISK_BUS_IDE;
+ else if (!strcmp((const char *)bus, "ide"))
+ disk->bus = QEMUD_DISK_BUS_IDE;
+ else if (!strcmp((const char *)bus, "scsi"))
+ disk->bus = QEMUD_DISK_BUS_SCSI;
+ else if (!strcmp((const char *)bus, "virtio"))
+ disk->bus = QEMUD_DISK_BUS_VIRTIO;
+ else {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Invalid bus type: %s", bus);
+ goto error;
+ }
+
+ xmlFree(bus);
xmlFree(device);
xmlFree(target);
xmlFree(source);
@@ -688,6 +706,8 @@
xmlFree(source);
if (device)
xmlFree(device);
+ if (bus)
+ xmlFree(bus);
return -1;
}
@@ -1350,6 +1370,68 @@
return -1;
}
+static int qemudDiskCompare(const void *aptr, const void *bptr) {
+ struct qemud_vm_disk_def *a = (struct qemud_vm_disk_def *) aptr;
+ struct qemud_vm_disk_def *b = (struct qemud_vm_disk_def *) bptr;
+ if (a->device == b->device)
+ return virDiskNameToIndex(a->dst) - virDiskNameToIndex(b->dst);
+ else
+ return a->device - b->device;
+}
+
+static const char *qemudBusIdToName(int busId) {
+ const char *busnames[] = { "ide",
+ "scsi",
+ "virtio" };
+
+ if (busId >= 0 && busId < 3)
+ return busnames[busId];
+ else
+ return 0;
+}
+
+static char *qemudDriveOpt(struct qemud_vm_disk_def *disk, int boot)
+{
+ char opt[PATH_MAX];
+
+ switch (disk->device) {
+ case QEMUD_DISK_CDROM:
+ snprintf(opt, PATH_MAX, "file=%s,if=ide,media=cdrom%s",
+ disk->src, boot ? ",boot=on" : "");
+ break;
+ case QEMUD_DISK_FLOPPY:
+ snprintf(opt, PATH_MAX, "file=%s,if=floppy%s",
+ disk->src, boot ? ",boot=on" : "");
+ break;
+ case QEMUD_DISK_DISK:
+ snprintf(opt, PATH_MAX, "file=%s,if=%s%s",
+ disk->src, qemudBusIdToName(disk->bus), boot ? ",boot=on" : "");
+ break;
+ default:
+ return 0;
+ }
+ return strdup(opt);
+}
+
+static char *qemudAddBootDrive(virConnectPtr conn,
+ struct qemud_vm_def *def,
+ char *handledDisks,
+ int type) {
+ int j = 0;
+ struct qemud_vm_disk_def *disk = def->disks;
+
+ while (disk) {
+ if (!handledDisks[j] && disk->device == type) {
+ handledDisks[j] = 1;
+ return qemudDriveOpt(disk, 1);
+ }
+ j++;
+ disk = disk->next;
+ }
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ "Requested boot device type %d, but no such device defined.", type);
+ return 0;
+}
/*
* Parses a libvirt XML definition of a guest, and populates the
@@ -1739,7 +1821,6 @@
obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
- struct qemud_vm_disk_def *prev = NULL;
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
struct qemud_vm_disk_def *disk = calloc(1, sizeof(*disk));
if (!disk) {
@@ -1752,13 +1833,20 @@
goto error;
}
def->ndisks++;
- disk->next = NULL;
if (i == 0) {
+ disk->next = NULL;
def->disks = disk;
} else {
- prev->next = disk;
+ struct qemud_vm_disk_def *ptr = def->disks;
+ while (ptr) {
+ if (!ptr->next || qemudDiskCompare(ptr->next, disk) < 0) {
+ disk->next = ptr->next;
+ ptr->next = disk;
+ break;
+ }
+ ptr = ptr->next;
+ }
}
- prev = disk;
}
}
xmlXPathFreeObject(obj);
@@ -2207,30 +2295,32 @@
goto no_memory;
}
- for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
- switch (vm->def->os.bootDevs[i]) {
- case QEMUD_BOOT_CDROM:
- boot[i] = 'd';
- break;
- case QEMUD_BOOT_FLOPPY:
- boot[i] = 'a';
- break;
- case QEMUD_BOOT_DISK:
- boot[i] = 'c';
- break;
- case QEMUD_BOOT_NET:
- boot[i] = 'n';
- break;
- default:
- boot[i] = 'c';
- break;
+ if (vm->def->virtType != QEMUD_VIRT_KVM) {
+ for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
+ switch (vm->def->os.bootDevs[i]) {
+ case QEMUD_BOOT_CDROM:
+ boot[i] = 'd';
+ break;
+ case QEMUD_BOOT_FLOPPY:
+ boot[i] = 'a';
+ break;
+ case QEMUD_BOOT_DISK:
+ boot[i] = 'c';
+ break;
+ case QEMUD_BOOT_NET:
+ boot[i] = 'n';
+ break;
+ default:
+ boot[i] = 'c';
+ break;
+ }
}
+ boot[vm->def->os.nBootDevs] = '\0';
+ if (!((*argv)[++n] = strdup("-boot")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(boot)))
+ goto no_memory;
}
- boot[vm->def->os.nBootDevs] = '\0';
- if (!((*argv)[++n] = strdup("-boot")))
- goto no_memory;
- if (!((*argv)[++n] = strdup(boot)))
- goto no_memory;
if (vm->def->os.kernel[0]) {
if (!((*argv)[++n] = strdup("-kernel")))
@@ -2251,28 +2341,74 @@
goto no_memory;
}
- while (disk) {
- char dev[NAME_MAX];
- char file[PATH_MAX];
- if (!strcmp(disk->dst, "hdc") &&
- disk->device == QEMUD_DISK_CDROM) {
- if (disk->src[0])
- snprintf(dev, NAME_MAX, "-%s", "cdrom");
- else {
- /* Don't put anything on the cmdline for an empty cdrom*/
- disk = disk->next;
- continue;
- }
- } else
- snprintf(dev, NAME_MAX, "-%s", disk->dst);
- snprintf(file, PATH_MAX, "%s", disk->src);
-
- if (!((*argv)[++n] = strdup(dev)))
- goto no_memory;
- if (!((*argv)[++n] = strdup(file)))
- goto no_memory;
-
- disk = disk->next;
+ if (vm->def->virtType == QEMUD_VIRT_KVM) {
+ char *handledDisks = NULL;
+ int j;
+
+ handledDisks = calloc(sizeof(*handledDisks), vm->def->ndisks);
+
+ if (!handledDisks)
+ goto no_memory;
+
+ /* When using -drive notation, we need to provide the devices in boot
+ * preference order. */
+ for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
+ if (!((*argv)[++n] = strdup("-drive")))
+ goto no_memory;
+
+ switch (vm->def->os.bootDevs[i]) {
+ case QEMUD_BOOT_CDROM:
+ if (!((*argv)[++n] = qemudAddBootDrive(conn, vm->def, handledDisks, QEMUD_DISK_CDROM)))
+ goto error;
+ break;
+ case QEMUD_BOOT_FLOPPY:
+ if (!((*argv)[++n] = qemudAddBootDrive(conn, vm->def, handledDisks, QEMUD_DISK_FLOPPY)))
+ goto error;
+ break;
+ case QEMUD_BOOT_DISK:
+ if (!((*argv)[++n] = qemudAddBootDrive(conn, vm->def, handledDisks, QEMUD_DISK_DISK)))
+ goto error;
+ break;
+ }
+ }
+
+ /* Pick up the rest of the devices */
+ j=0;
+ while (disk) {
+ if (!handledDisks[j]) {
+ handledDisks[j] = 1;
+ if (!((*argv)[++n] = strdup("-drive")))
+ goto no_memory;
+ if (!((*argv)[++n] = qemudDriveOpt(disk, 0)))
+ goto no_memory;
+ }
+ disk = disk->next;
+ j++;
+ }
+ } else {
+ while (disk) {
+ char dev[NAME_MAX];
+ char file[PATH_MAX];
+
+ if (!strcmp(disk->dst, "hdc") &&
+ disk->device == QEMUD_DISK_CDROM)
+ if (disk->src[0])
+ snprintf(dev, NAME_MAX, "-%s", "cdrom");
+ else {
+ disk = disk->next;
+ continue;
+ }
+ else
+ snprintf(dev, NAME_MAX, "-%s", disk->dst);
+ snprintf(file, PATH_MAX, "%s", disk->src);
+
+ if (!((*argv)[++n] = strdup(dev)))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(file)))
+ goto no_memory;
+
+ disk = disk->next;
+ }
}
if (!net) {
@@ -3565,6 +3701,7 @@
virBufferVSprintf(&buf, " <source %s='%s'/>\n",
typeAttrs[disk->type], disk->src);
+ virBufferVSprintf(&buf, " <target dev='%s' bus='%s'/>\n", disk->dst, qemudBusIdToName(disk->bus));
virBufferVSprintf(&buf, " <target dev='%s'/>\n", disk->dst);
if (disk->readonly)
=== modified file 'src/qemu_conf.h'
--- src/qemu_conf.h 2008-04-25 20:46:13 +0000
+++ src/qemu_conf.h 2008-04-29 07:13:16 +0000
@@ -56,10 +56,17 @@
QEMUD_DISK_FLOPPY,
};
+enum qemud_vm_disk_bus {
+ QEMUD_DISK_BUS_IDE,
+ QEMUD_DISK_BUS_SCSI,
+ QEMUD_DISK_BUS_VIRTIO
+};
+
/* Stores the virtual disk configuration */
struct qemud_vm_disk_def {
int type;
int device;
+ int bus;
char src[PATH_MAX];
char dst[NAME_MAX];
int readonly;
=== modified file 'src/util.c'
--- src/util.c 2008-04-25 14:53:05 +0000
+++ src/util.c 2008-04-29 06:59:49 +0000
@@ -771,3 +771,43 @@
return -1;
}
+
+/* Translates a device name of the form (regex) "[fhv]d[a-z]+" into
+ * the corresponding index (e.g. sda => 1, hdz => 26, vdaa => 27)
+ * @param name The name of the device
+ * @return name's index, or 0 on failure
+ */
+int virDiskNameToIndex(const char *name) {
+ const char *ptr = NULL;
+ int idx = 0;
+
+ if (strlen(name) < 3)
+ return 0;
+
+ switch (*name) {
+ case 'f':
+ case 'h':
+ case 'v':
+ break;
+ default:
+ return 0;
+ }
+
+ if (*(name + 1) != 'd')
+ return 0;
+
+ ptr = name+2;
+
+ while (*ptr) {
+ idx = idx * 26;
+
+ if ('a' > *ptr || 'z' < *ptr)
+ return 0;
+
+ idx += *ptr - 'a' + 1;
+ ptr++;
+ }
+
+ return idx;
+}
+
=== modified file 'src/util.h'
--- src/util.h 2008-04-25 14:53:05 +0000
+++ src/util.h 2008-04-29 06:59:57 +0000
@@ -92,4 +92,6 @@
int virParseMacAddr(const char* str, unsigned char *addr);
+int virDiskNameToIndex(const char* str);
+
#endif /* __VIR_UTIL_H__ */
--
Soren Hansen |
Virtualisation specialist | Ubuntu Server Team
Canonical Ltd. | http://www.ubuntu.com/
16 years, 5 months
[Libvir] Re: libvirt on mingw
by Richard W.M. Jones
Brecht Sanders wrote:
> Hi,
> I saw on the following link:
> http://www.mail-archive.com/libvir-list@redhat.com/msg04103.html
> that you are also trying to compile libvirt on win32.
> I'm also attempting to do this, and I guess I got stuck at the same
> point your post was about.
> Have you in the mean time found an XDR implementation that compiles on
> MinGW and that implements xdr_u_quad_t?
> If you did, can you please tell me where to find it?
You'll find the answer to this question and more if you look through the
libvir-list archives for the current month:
https://www.redhat.com/archives/libvir-list/2008-January/thread.html
Rich.
--
Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/
Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in
England and Wales under Company Registration No. 03798903
16 years, 5 months
[Libvir] [PATCH] Fix USB device name mis-conversion from S-Expr to XML
by Hiroyuki Kaguchi
"tablet" and "mouse" are set as a value of the
/local/domain/<domid>/image/hvm/usbdevice,
but libvirt expects "usbdevice" and "usbmouse" as a value.
This causes the following.
If a USB device is attached by virt-manager,
the USB device is not seen from virt-manager.
This patch fixes expected value of libvirt
Thanks,
Hiroyuki Kaguchi
Index: xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.162
diff -u -r1.162 xend_internal.c
--- xend_internal.c 21 Jan 2008 16:29:10 -0000 1.162
+++ xend_internal.c 23 Jan 2008 00:37:02 -0000
@@ -1743,11 +1743,9 @@
node = cur->u.s.car;
if (sexpr_lookup(node, "usbdevice")) {
tmp = sexpr_node(node, "usbdevice");
- if (tmp && *tmp) {
- if (!strcmp(tmp, "usbtablet"))
- virBufferAdd(&buf, " <input type='tablet'
bus='usb'/>\n", 37);
- else if (!strcmp(tmp, "usbmouse"))
- virBufferAdd(&buf, " <input type='mouse'
bus='usb'/>\n", 36);
+ if (!strcmp(tmp, "tablet") ||
+ !strcmp(tmp, "mouse")) {
+ virBufferVSprintf(&buf, " <input type='%s'
bus='usb'/>\n", tmp);
}
}
}
16 years, 6 months
[Libvir] Reopening the old discussion about virDomainBlockPeek
by Richard W.M. Jones
Virt-df[1] has now gained the ability to fully parse LVM2 partitions,
thus:
# virt-df -c qemu:///system -h
Filesystem Size Used Available Type
rhel51x32kvm:hda1 96.8 MiB 14.6 MiB 82.2 MiB Linux ext2/3
rhel51x32kvm:VolGroup00/LogVol00 6.4 GiB 3.6 GiB 2.8 GiB Linux ext2/3
rhel51x32kvm:VolGroup00/LogVol01 992.0 MiB Linux swap
However it still has to do it by opening the local partitions / files,
which means it isn't using a "proper" part of libvirt and more
importantly it cannot run remotely.
I'd like to find out whether the time has come for us to look again at
a virDomainBlockPeek call for libvirt. Here is the original thread
plus patch from 7 months ago:
http://www.redhat.com/archives/libvir-list/2007-October/thread.html#00089
(I've attached an updated patch against current CVS).
I appreciate that some cases might not be simple (iSCSI?), but the
same argument applies to block device statistics too, and we make
those available where possible. I think a best-effort call allowing
callers to peek into the block devices of guests would be very useful.
Rich.
[1] http://hg.et.redhat.com/applications/virt/applications/virt-df--devel
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
16 years, 6 months
[Libvir] KVM migration
by Richard W.M. Jones
It turns out that the general migration strategy I defined[1] in
reference to Xen, ie. the 3 steps of Prepare/Perform/Finish, isn't
sufficient to support KVM migration.
The problem is that the destination needs to start qemu-kvm with
pretty much the exact same configuration / command line parameters as
were used at the source[2]. eg. If the source qemu-kvm has 512 MB of
RAM, then the destination had better have exactly 512 MB of RAM also.
(This is not the same as Xen where the migration protocol itself
carries this information between the two xend daemons).
We can modify the Prepare step to pass this information -- I'm
suggesting that we just pass the domain XML of the source domain.
Thus the Prepare step would change from:
static int
qemudDomainMigratePrepare (virConnectPtr dconn,
char **cookie,
int *cookielen,
const char *uri_in,
char **uri_out,
unsigned long flags,
const char *dname,
unsigned long resource)
to:
static int
qemudDomainMigratePreparev2 (virConnectPtr dconn,
char **cookie,
int *cookielen,
const char *uri_in,
char **uri_out,
+ const char *dom_xml,
unsigned long flags,
const char *dname,
unsigned long resource)
As hinted there, we also need a new version of the migration protocol,
and a new remote call (Preparev2).
So questions:
(a) Does anyone have any objections?
(b) Does anyone see a simpler way to do this?
(c) Since we're adding a second version of the protocol, does anyone
want anything else added?
(d) Will the domain XML alone be sufficient to recreate the exact
qemu command line? (Seems to be the case, and in fact KVM suspend/
restore support seems to implicitly rely on this too).
Rich.
Notes:
[1] https://www.redhat.com/archives/libvir-list/2007-July/msg00357.html
and https://www.redhat.com/archives/libvir-list/2007-July/msg00304.html
[2] http://kvm.qumranet.com/kvmwiki/Migration#head-71900dbcf45d8ac81649fe4f03...
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
16 years, 7 months
[Libvir] How to get the memory used by a guest domin
by Pranay Prasoon
Hi,
It appears to be no API available to provide the memory used by a guest
domin.
I looked at the availble libvirt api called "virNodeGetCellsFreeMemory"
using which it is possible to get the free mem. But looking further I found
that this is free memory of the "whole box" rather than based upon the guest
domain.
How can I get the memory used by a guest domin.
Thanks n Regards,
-Pranay.
16 years, 7 months
[Libvir] [PATCH] sound support for qemu and xen
by Cole Robinson
The patch below adds xml support for the soundhw option to qemu
and xen. The new xml element takes the form:
<sound driver='drivername'/>
Where driver name can be pcspk, sb16, es1370, or all.
Everything seems to be in working order but I have a few
implementation questions:
1) Should multiple drivers be able to be specified? qemu
accommodates this, allowing '-soundhw sb16,pcspk' for example.
If this should be allowed, what should the xml format be?
2) Should acceptable driver options be hardcoded? The other option
is to just pass the input straight to qemu. This patch has the
options hardcoded.
Also I realize this will probably need to be rediff'd around
Dan's serial + parallel device patch, but I figured I would just
get this out there.
Thanks,
Cole
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index d9b82b2..bfd9ba4 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -1011,6 +1011,41 @@ static int qemudParseInputXML(virConnectPtr conn,
return -1;
}
+/* Sound device helper functions */
+static int qemudSoundDriverFromString(virConnectPtr conn,
+ const char *driver) {
+ if (STREQ(driver, "all")) {
+ return QEMU_SOUND_ALL;
+ } else if (STREQ(driver, "sb16")) {
+ return QEMU_SOUND_SB16;
+ } else if (STREQ(driver, "es1370")) {
+ return QEMU_SOUND_ES1370;
+ } else if (STREQ(driver, "pcspk")) {
+ return QEMU_SOUND_PCSPK;
+ }
+
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+ _("invalid sound driver '%s'"), driver);
+ return -1;
+}
+
+static const char *qemudSoundDriverToString(virConnectPtr conn,
+ const int driver) {
+
+ if (driver == QEMU_SOUND_ALL) {
+ return "all";
+ } else if (driver == QEMU_SOUND_SB16) {
+ return "sb16";
+ } else if (driver == QEMU_SOUND_ES1370) {
+ return "es1370";
+ } else if (driver == QEMU_SOUND_PCSPK) {
+ return "pcspk";
+ }
+
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("invalid sound driver '%d'"), driver);
+ return NULL;
+}
/*
* Parses a libvirt XML definition of a guest, and populates the
@@ -1486,6 +1521,25 @@ static struct qemud_vm_def *qemudParseXML(virConnectPtr conn,
}
}
xmlXPathFreeObject(obj);
+
+ /* Parse sound driver xml */
+ obj = xmlXPathEval(BAD_CAST "/domain/devices/sound", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+ (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
+ def->soundDriver = QEMU_SOUND_NONE;
+ } else if ((prop = xmlGetProp(obj->nodesetval->nodeTab[0],
+ BAD_CAST "driver"))) {
+
+ if ((def->soundDriver = qemudSoundDriverFromString(conn,
+ (char *) prop)) < 0)
+ goto error;
+
+ xmlFree(prop);
+ prop = NULL;
+ } else {
+ def->soundDriver = QEMU_SOUND_NONE;
+ }
+ xmlXPathFreeObject(obj);
obj = NULL;
/* If graphics are enabled, there's an implicit PS2 mouse */
@@ -1694,6 +1748,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
(vm->def->os.cmdline[0] ? 2 : 0) + /* cmdline */
(vm->def->graphicsType == QEMUD_GRAPHICS_VNC ? 2 :
(vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */
+ (vm->def->soundDriver == QEMU_SOUND_NONE ? 0 : 2) + /* sound */
(vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */
snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024);
@@ -1970,6 +2025,14 @@ int qemudBuildCommandLine(virConnectPtr conn,
/* SDL is the default. no args needed */
}
+ /* Add sound hardware */
+ if (vm->def->soundDriver != QEMU_SOUND_NONE) {
+ if (!((*argv)[++n] = strdup("-soundhw")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup((char *) qemudSoundDriverToString(conn, vm->def->soundDriver))))
+ goto no_memory;
+ }
+
if (vm->migrateFrom[0]) {
if (!((*argv)[++n] = strdup("-S")))
goto no_memory;
@@ -3125,7 +3188,11 @@ char *qemudGenerateXML(virConnectPtr conn,
break;
}
- if (def->graphicsType == QEMUD_GRAPHICS_VNC) {
+ if (def->soundDriver != QEMU_SOUND_NONE) {
+ if (virBufferVSprintf(buf, " <sound driver='%s'/>\n",
+ qemudSoundDriverToString(conn,
+ def->soundDriver)) < 0)
+ goto no_memory;
}
if (virBufferAddLit(buf, " </devices>\n") < 0)
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index c59b1fa..1383c10 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -136,6 +136,14 @@ struct qemud_vm_input_def {
struct qemud_vm_input_def *next;
};
+enum qemu_vm_sound_driver {
+ QEMU_SOUND_NONE,
+ QEMU_SOUND_ALL,
+ QEMU_SOUND_SB16,
+ QEMU_SOUND_ES1370,
+ QEMU_SOUND_PCSPK,
+};
+
/* Flags for the 'type' field in next struct */
enum qemud_vm_device_type {
QEMUD_DEVICE_DISK,
@@ -214,6 +222,7 @@ struct qemud_vm_def {
int vncActivePort;
char vncListen[BR_INET_ADDR_MAXLEN];
char *keymap;
+ int soundDriver;
int ndisks;
struct qemud_vm_disk_def *disks;
diff --git a/src/xend_internal.c b/src/xend_internal.c
index 6ba4571..b470731 100644
--- a/src/xend_internal.c
+++ b/src/xend_internal.c
@@ -1783,6 +1783,18 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root,
}
}
}
+
+ if (sexpr_node(root, "domain/image/hvm/soundhw")) {
+ tmp = sexpr_node(root, "domain/image/hvm/soundhw");
+ if (tmp && *tmp) {
+ if (STREQ(tmp, "all") ||
+ STREQ(tmp, "pcspk") ||
+ STREQ(tmp, "sb16") ||
+ STREQ(tmp, "es1370")) {
+ virBufferVSprintf(&buf, " <sound driver='%s'/>\n", tmp);
+ }
+ }
+ }
}
/* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */
diff --git a/src/xm_internal.c b/src/xm_internal.c
index 3d845dc..91c7cf1 100644
--- a/src/xm_internal.c
+++ b/src/xm_internal.c
@@ -934,6 +934,15 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) {
/* Ignore else branch - probably some other non-input device we don't
support in libvirt yet */
}
+
+ if ((xenXMConfigGetString(conf, "soundhw", &str) == 0) && str) {
+ if (STREQ(str, "all") ||
+ STREQ(str, "pcspk") ||
+ STREQ(str, "sb16") ||
+ STREQ(str, "es1370")) {
+ virBufferVSprintf(buf, " <sound driver='%s'/>\n", str);
+ }
+ }
}
/* HVM guests, or old PV guests use this config format */
@@ -2081,6 +2090,11 @@ virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml) {
if (xenXMConfigSetStringFromXPath(conn, conf, ctxt, "usbdevice", "string(/domain/devices/input[@bus='usb' or (not(@bus) and @type='tablet')]/@type)", 1,
"cannot set the usbdevice parameter") < 0)
goto error;
+
+ if (xenXMConfigSetStringFromXPath(conn, conf, ctxt, "soundhw",
+ "string(/domain/devices/sound[@driver]",
+ 1, "cannot set soundhw parameter") < 0)
+ goto error;
}
if (hvm || priv->xendConfigVersion < 3) {
diff --git a/src/xml.c b/src/xml.c
index 8e95103..f4bfb29 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -877,6 +877,14 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node,
nodes = NULL;
}
+ cur = virXPathNode("/domain/devices/sound", ctxt);
+ if (cur) {
+ xmlChar *driver = NULL;
+ driver = xmlGetProp(cur, (xmlChar *) "driver");
+ if (driver)
+ virBufferVSprintf(buf, "(soundhw '%s')", driver);
+ xmlFree(driver);
+ }
res = virXPathBoolean("count(domain/devices/console) > 0", ctxt);
if (res < 0) {
16 years, 7 months
[Libvir] [PATCH][RFC] libvirt ldoms support
by Ryan Scott
Note: I haven't tried building this on Linux yet, so we may have some
#ifdef or Makefile changes on non-Solaris platforms.
Please Cc: Eunice.Moon(a)Sun.COM on any response.
Thanks,
Ryan
LDoms Support
This patch adds the Logical Domains (LDoms) support for the SPARC
platforms. LDoms software is Sun Microsystem's virtualization technology
to subdivide a supported system's resources (CPUs, memory, I/O, and
storage) creating partitions called logical domains. The Logical Domains
Manager is used to create and manage logical domains and maps logical
domains to physical resources. The LDoms Manager provides a command-line
interface and also exports an XML-based control interface. The Libvirt
for LDoms uses this XML interface to communicate with the LDoms Manager
to retrieve the LDoms data for:
- Listing domains
- Requesting CPU and memory resource updates
- Performing life-cycle actions for logical domains
This libvirt patch supports LDoms 1.0.1 and 1.0.2.
This patch will modify the following existing files:
src/libvirt.c
src/virsh.c
src/virterror.c
src/driver.h
src/Makefile.am
include/libvirt/libvirt.h.in
include/libvirt/virterror.h
configure.in
and add the following new files:
src/ldoms_common.h
src/ldoms_internal.h
src/ldoms_internal.c
src/ldoms_intfc.h
src/ldoms_intfc.c
src/ldoms_xml_parse.h
src/ldoms_xml_parse.c
Signed-off-by: Eunice Moon <eunice.moon(a)sun.com>
diff --git a/src/libvirt.c b/src/libvirt.c
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -48,6 +48,9 @@
#ifdef WITH_LXC
#include "lxc_driver.h"
#endif
+#ifdef WITH_LDOMS
+extern int ldomsRegister(void);
+#endif
/*
* TODO:
@@ -267,6 +270,11 @@ virInitialize(void)
* Note that the order is important: the first ones have a higher
* priority when calling virConnectOpen.
*/
+#ifdef WITH_LDOMS
+ if (ldomsRegister() == -1) return -1;
+ /* Don't want to run any other HV with LDoms */
+ return (0);
+#endif
#ifdef WITH_TEST
if (testRegister() == -1) return -1;
#endif
@@ -1794,11 +1802,17 @@ virDomainGetUUID(virDomainPtr domain, un
return (-1);
}
+#ifndef WITH_LDOMS
if (domain->id == 0) {
memset(uuid, 0, VIR_UUID_BUFLEN);
} else {
memcpy(uuid, &domain->uuid[0], VIR_UUID_BUFLEN);
}
+#endif
+
+#ifdef WITH_LDOMS
+ memcpy(uuid, &domain->uuid[0], VIR_UUID_BUFLEN);
+#endif
return (0);
}
@@ -5025,6 +5039,42 @@ virStorageVolGetPath(virStorageVolPtr vo
return NULL;
}
+#ifdef WITH_LDOMS
+/**
+ * virLDomConsole:
+ * @domain: the domain if available
+ *
+ * Opens a terminal window to the console for a domain
+ *
+ * Returns -1 in case of error, LDom console port number in case of success
+ */
+int
+virLDomConsole(virDomainPtr domain)
+{
+ virConnectPtr conn;
+ DEBUG("Starting domain %p", domain);
+
+ if (domain == NULL) {
+ TODO
+ return (-1);
+ }
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return (-1);
+ }
+ conn = domain->conn;
+ if (conn->flags & VIR_CONNECT_RO) {
+ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ return (-1);
+ }
+
+ if (conn->driver->ldomConsole)
+ return conn->driver->ldomConsole (domain);
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+#endif
/*
* vim: set tabstop=4:
diff --git a/src/virsh.c b/src/virsh.c
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -494,6 +494,11 @@ cmdConsole(vshControl * ctl, vshCmd * cm
virDomainPtr dom;
int ret = FALSE;
char *doc;
+#ifdef WITH_LDOMS
+ int port;
+ char command[80];
+#endif
+
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
@@ -501,6 +506,19 @@ cmdConsole(vshControl * ctl, vshCmd * cm
if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL)))
return FALSE;
+#ifdef WITH_LDOMS
+ port = virLDomConsole(dom);
+ if (port > 0) {
+ sprintf(command, "%s %d &",
+ "/usr/X/bin/xterm -sb -sl 1000 -e telnet localhost ", port);
+ system(command);
+ return TRUE;
+ }
+
+ vshError(ctl, FALSE, _("Failed to start console"));
+ return FALSE;
+#endif
+
doc = virDomainGetXMLDesc(dom, 0);
if (!doc)
goto cleanup;
@@ -1003,13 +1021,21 @@ cmdUndefine(vshControl * ctl, vshCmd * c
*/
static vshCmdInfo info_start[] = {
{"syntax", "start <domain>"},
+#ifdef WITH_LDOMS
+ {"help", gettext_noop("start an inactive or bound domain")},
+#else
{"help", gettext_noop("start a (previously defined) inactive domain")},
+#endif
{"desc", gettext_noop("Start a domain.")},
{NULL, NULL}
};
static vshCmdOptDef opts_start[] = {
+#ifdef WITH_LDOMS
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive or bound domain")},
+#else
{"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")},
+#endif
{NULL, 0, 0, NULL}
};
@@ -1019,17 +1045,26 @@ cmdStart(vshControl * ctl, vshCmd * cmd)
virDomainPtr dom;
int ret = TRUE;
+#ifdef WITH_LDOMS
+ /* Need to send in the 'domain' option name instead of 'name' */
+ if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, VSH_BYNAME)))
+ return FALSE;
+#else
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
+#endif
if (!(dom = vshCommandOptDomainBy(ctl, cmd, "name", NULL, VSH_BYNAME)))
return FALSE;
+ /* Allow LDoms domain state to be inactive or bound */
+#ifndef WITH_LDOMS
if (virDomainGetID(dom) != (unsigned int)-1) {
vshError(ctl, FALSE, "%s", _("Domain is already active"));
virDomainFree(dom);
return FALSE;
}
+#endif
if (virDomainCreate(dom) == 0) {
vshPrint(ctl, _("Domain %s started\n"),
@@ -1660,11 +1695,13 @@ cmdVcpuinfo(vshControl * ctl, vshCmd * c
vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
}
+#ifndef WITH_LDOMS
vshPrint(ctl, "%-15s ", _("CPU Affinity:"));
for (m = 0 ; m < VIR_NODEINFO_MAXCPUS(nodeinfo) ; m++) {
vshPrint(ctl, "%c", VIR_CPU_USABLE(cpumap, cpumaplen, n, m) ? 'y' : '-');
}
vshPrint(ctl, "\n");
+#endif
if (n < (ncpus - 1)) {
vshPrint(ctl, "\n");
}
@@ -5087,19 +5124,23 @@ cmdQuit(vshControl * ctl, vshCmd * cmd A
*/
static vshCmdDef commands[] = {
{"help", cmdHelp, opts_help, info_help},
+#ifndef WITH_LDOMS
{"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device},
{"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
{"attach-interface", cmdAttachInterface, opts_attach_interface, info_attach_interface},
{"autostart", cmdAutostart, opts_autostart, info_autostart},
{"capabilities", cmdCapabilities, NULL, info_capabilities},
{"connect", cmdConnect, opts_connect, info_connect},
+#endif /* WITH_LDOMS */
{"console", cmdConsole, opts_console, info_console},
{"create", cmdCreate, opts_create, info_create},
{"start", cmdStart, opts_start, info_start},
{"destroy", cmdDestroy, opts_destroy, info_destroy},
+#ifndef WITH_LDOMS
{"detach-device", cmdDetachDevice, opts_detach_device, info_detach_device},
{"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk},
{"detach-interface", cmdDetachInterface, opts_detach_interface, info_detach_interface},
+#endif /* WITH_LDOMS */
{"define", cmdDefine, opts_define, info_define},
{"domid", cmdDomid, opts_domid, info_domid},
{"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
@@ -5112,7 +5153,9 @@ static vshCmdDef commands[] = {
{"freecell", cmdFreecell, opts_freecell, info_freecell},
{"hostname", cmdHostname, NULL, info_hostname},
{"list", cmdList, opts_list, info_list},
+#ifndef WITH_LDOMS
{"migrate", cmdMigrate, opts_migrate, info_migrate},
+#endif /* WITH_LDOMS */
{"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
{"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
@@ -5144,20 +5187,28 @@ static vshCmdDef commands[] = {
{"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
{"quit", cmdQuit, NULL, info_quit},
+#ifndef WITH_LDOMS
{"reboot", cmdReboot, opts_reboot, info_reboot},
{"restore", cmdRestore, opts_restore, info_restore},
{"resume", cmdResume, opts_resume, info_resume},
{"save", cmdSave, opts_save, info_save},
{"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
{"dump", cmdDump, opts_dump, info_dump},
+#endif /* WITH_LDOMS */
{"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
{"setmem", cmdSetmem, opts_setmem, info_setmem},
+#ifndef WITH_LDOMS
{"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
+#endif /* WITH_LDOMS */
{"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
+#ifndef WITH_LDOMS
{"suspend", cmdSuspend, opts_suspend, info_suspend},
{"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
+#endif /* WITH_LDOMS */
{"undefine", cmdUndefine, opts_undefine, info_undefine},
+#ifndef WITH_LDOMS
{"uri", cmdURI, NULL, info_uri},
+#endif /* WITH_LDOMS */
{"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
{"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
@@ -5170,9 +5221,13 @@ static vshCmdDef commands[] = {
{"vol-key", cmdVolKey, opts_vol_key, info_vol_key},
{"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
+#ifndef WITH_LDOMS
{"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
+#endif /* WITH_LDOMS */
{"version", cmdVersion, NULL, info_version},
+#ifndef WITH_LDOMS
{"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
+#endif /* WITH_LDOMS */
{NULL, NULL, NULL, NULL}
};
@@ -5905,6 +5960,10 @@ vshDomainVcpuStateToString(int state)
return gettext_noop("blocked");
case VIR_VCPU_RUNNING:
return gettext_noop("running");
+#ifdef WITH_LDOMS
+ case VIR_VCPU_UNKNOWN:
+ return gettext_noop("unknown");
+#endif
default:
;/*FALLTHROUGH*/
}
diff --git a/src/virterror.c b/src/virterror.c
--- a/src/virterror.c
+++ b/src/virterror.c
@@ -304,7 +304,11 @@ virDefaultErrorFunc(virErrorPtr err)
case VIR_FROM_STORAGE:
dom = "Storage ";
break;
-
+#ifdef WITH_LDOMS
+ case VIR_FROM_LDOMS:
+ dom = "LDoms ";
+ break;
+#endif
}
if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
domain = err->dom->name;
@@ -713,6 +717,14 @@ __virErrorMsg(virErrorNumber error, cons
else
errmsg = _("Failed to find a storage driver: %s");
break;
+#ifdef WITH_LDOMS
+ case VIR_ERR_INVALID_OPTION:
+ if (info == NULL)
+ errmsg = _("invalid option");
+ else
+ errmsg = _("invalid option: %s");
+ break;
+#endif
}
return (errmsg);
}
diff --git a/src/driver.h b/src/driver.h
--- a/src/driver.h
+++ b/src/driver.h
@@ -24,7 +24,10 @@ typedef enum {
VIR_DRV_QEMU = 3,
VIR_DRV_REMOTE = 4,
VIR_DRV_OPENVZ = 5,
- VIR_DRV_LXC = 6
+ VIR_DRV_LXC = 6,
+#ifdef WITH_LDOMS
+ VIR_DRV_LDOMS = 7
+#endif
} virDrvNo;
@@ -253,6 +256,11 @@ typedef virDomainPtr
const char *uri,
unsigned long flags);
+#ifdef WITH_LDOMS
+typedef int
+ (*virDrvLDomConsole) (virDomainPtr domain);
+#endif
+
typedef struct _virDriver virDriver;
typedef virDriver *virDriverPtr;
@@ -337,6 +345,9 @@ struct _virDriver {
virDrvDomainInterfaceStats domainInterfaceStats;
virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
virDrvNodeGetFreeMemory getFreeMemory;
+#ifdef WITH_LDOMS
+ virDrvLDomConsole ldomConsole;
+#endif
};
typedef int
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -549,6 +549,9 @@ 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 */
+#ifdef WITH_LDOMS
+ VIR_VCPU_UNKNOWN = 3, /* the virtual CPU state is unknown */
+#endif
} virVcpuState;
typedef struct _virVcpuInfo virVcpuInfo;
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -56,6 +56,9 @@ typedef enum {
VIR_FROM_STATS_LINUX, /* Error in the Linux Stats code */
VIR_FROM_LXC, /* Error from Linux Container driver */
VIR_FROM_STORAGE, /* Error from storage driver */
+#ifdef WITH_LDOMS
+ VIR_FROM_LDOMS, /* Error from LDoms driver */
+#endif
} virErrorDomain;
@@ -139,6 +142,9 @@ typedef enum {
VIR_WAR_NO_STORAGE, /* failed to start storage */
VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */
VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */
+#ifdef WITH_LDOMS
+ VIR_ERR_INVALID_OPTION, /* invalid command line option */
+#endif
} virErrorNumber;
/**
diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -89,7 +89,17 @@ else
EXTRA_DIST += storage_backend_disk.h storage_backend_disk.c
endif
-
+if WITH_LDOMS
+CLIENT_SOURCES += ldoms_common.h \
+ ldoms_internal.h ldoms_internal.c \
+ ldoms_intfc.h ldoms_intfc.h \
+ ldoms_xml_parse.h ldoms_xml_parse.c \
+else
+EXTRA_DIST += ldoms_common.h \
+ ldoms_internal.h ldoms_internal.c \
+ ldoms_intfc.h ldoms_intfc.h \
+ ldoms_xml_parse.h ldoms_xml_parse.c \
+endif
libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES)
diff --git a/configure.in b/configure.in
--- a/configure.in
+++ b/configure.in
@@ -246,6 +246,10 @@ if test "$with_remote" = "yes" ; then
LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_REMOTE"
fi
+if test "$with_ldoms" = "yes" ; then
+ LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_LDOMS"
+fi
+
if test "$with_xen" = "yes" ; then
dnl search for the Xen store library
AC_SEARCH_LIBS(xs_read, [xenstore],
diff --git a/src/ldoms_common.h b/src/ldoms_common.h
new file mode 100644
--- /dev/null
+++ b/src/ldoms_common.h
@@ -0,0 +1,80 @@
+/*
+ * ldoms_common.h: LDoms common definitions
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifndef __VIR_LDOMS_COMMON_H__
+#define __VIR_LDOMS_COMMON_H__
+
+#ifdef WITH_LDOMS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDOMS_VERSION_NUMBER 1000001 /* 1.0.1 */
+#define NAME_SIZE 256
+
+/* LDOM memory unit */
+#define LDOMMEMUNIT_BYTES 1
+#define LDOMMEMUNIT_KILOBYTES 2
+#define LDOMMEMUNIT_MEGABYTES 3
+#define LDOMMEMUNIT_GIGABYTES 4
+
+/* LDOM lifecycle actions */
+#define LDOM_START 1
+#define LDOM_STOP 2
+#define LDOM_BIND 3
+#define LDOM_UNBIND 4
+#define LDOM_DELETE 5
+
+/* LDOM States */
+/* binding is to bind (attach) configured resource to a logical domain
+ * unbinding is to release resources bound to configured logical domains
+ */
+#define LDOM_STATE_ACTIVE 1
+#define LDOM_STATE_STOPPING 2
+#define LDOM_STATE_INACTIVE 3
+#define LDOM_STATE_BINDING 4
+#define LDOM_STATE_UNBINDING 5
+#define LDOM_STATE_BOUND 6
+#define LDOM_STATE_STARTING 7
+
+/* resource pool supported */
+#define CPU_RP 1
+#define MEM_RP 2
+#define CRYPTO_RP 3
+#define IOBUS_RP 4
+
+/* capacity or reserved resource */
+#define RP_CAPACITY 1
+#define RP_RESERVED 2
+
+/* Global vars */
+extern unsigned long ldomsFreeMem;
+extern unsigned long ldomsUsedMem;
+extern int ldomsFreeCpu;
+extern int ldomsUsedCpu;
+
+/* Structures */
+
+struct cpuBindings_s {
+ unsigned int virt;
+ int real;
+ struct cpuBindings_s *next;
+};
+typedef struct cpuBindings_s cpuBindings_t;
+
+/* Debug print */
+extern void dprt(const char *template, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WITH_LDOMS */
+#endif /* __VIR_LDOMS_COMMON_H__ */
diff --git a/src/ldoms_internal.h b/src/ldoms_internal.h
new file mode 100644
--- /dev/null
+++ b/src/ldoms_internal.h
@@ -0,0 +1,29 @@
+/*
+ * ldoms_internal.h: internal definitions just used by LDoms driver
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifndef __VIR_LDOMS_INTERNAL_H__
+#define __VIR_LDOMS_INTERNAL_H__
+
+#ifdef WITH_LDOMS
+
+#include <libvirt/virterror.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ldomsRegister(void);
+void ldomsError(virConnectPtr, virDomainPtr, virErrorNumber, const char*, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WITH_LDOMS */
+#endif /* __VIR_LDOMS_INTERNAL_H__ */
diff --git a/src/ldoms_internal.c b/src/ldoms_internal.c
new file mode 100644
--- /dev/null
+++ b/src/ldoms_internal.c
@@ -0,0 +1,2254 @@
+/*
+ * ldoms_internal.c: access to LDoms hypervisor via LDoms Manager (LDM)
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifdef WITH_LDOMS
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/processor.h>
+#include <pwd.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <values.h>
+#include <limits.h>
+#include <pthread.h>
+
+#include "buf.h"
+#include "internal.h"
+#include "xml.h"
+#include "ldoms_common.h"
+#include "ldoms_internal.h"
+#include "ldoms_intfc.h"
+#include "ldoms_xml_parse.h"
+
+/* Local function prototypes */
+static void refresh_ldom_data();
+static int ldomsNodeGetInfo(virConnectPtr , virNodeInfoPtr );
+static long long getCpuUpTime();
+static long getHypervisorVersion();
+static unsigned long getLDMVersion();
+
+/* Domain state info
+ * LDom State enumerations
+ * 1 = active LDOM_STATE_ACTIVE
+ * 2 = stopping LDOM_STATE_STOPPING
+ * 3 = inactive LDOM_STATE_INACTIVE
+ * 4 = binding LDOM_STATE_BINDING
+ * 5 = unbinding LDOM_STATE_UNBINDING
+ * 6 = bound LDOM_STATE_BOUND
+ * 7 = starting LDOM_STATE_STARTING
+ *
+ * libvirt LDom State enums
+ * typedef enum {
+ * VIR_DOMAIN_NOSTATE = 0, no state
+ * VIR_DOMAIN_RUNNING = 1, the domain is running
+ * VIR_DOMAIN_BLOCKED = 2, the domain is blocked on resource
+ * VIR_DOMAIN_PAUSED = 3, the domain is paused by user
+ * VIR_DOMAIN_SHUTDOWN= 4, the domain is being shut down
+ * VIR_DOMAIN_SHUTOFF = 5, the domain is shut off
+ * VIR_DOMAIN_CRASHED = 6 the domain is crashed
+ * } virDomainState;
+ */
+
+ldominfo_t **ldominfo_list = NULL;
+int ldom_cnt = 0;
+const unsigned char Uuid[] = "" ;
+static long last_ldom_refresh = 0;
+static pthread_rwlock_t update_lock;
+static unsigned long LDMVersion = 1000001;
+
+/* Mem and CPU Free/Used */
+unsigned long ldomsFreeMem;
+unsigned long ldomsUsedMem;
+int ldomsFreeCpu;
+int ldomsUsedCpu;
+
+/* Global vars for debug statement */
+int ldoms_debug = 0;
+int ldoms_detailed_debug = 0;
+
+/* Prototype Structures */
+struct domains {
+ short valid; /* Flag to indicate this Domain is valid */
+ short active; /* Flag to indicate this Domain is valid */
+ char name[30]; /* Domain Name; primary, ldg1, etc */
+ int id; /* ID for the Domain; Used alot by other code to find a Domain */
+ virDomainInfo info; /* Domain name, state */
+ unsigned char uuid[VIR_UUID_BUFLEN]; /* 32 char unique ID */
+};
+
+/* This is global. Need to fill on first call from virsh or VMM */
+virNodeInfo nodeInfo;
+short nodeInfoFilled = 0;
+
+int maxDomID = 0;
+
+/*
+ * General error logging function. This is the exact same
+ * as used by Qemu and Test.
+ */
+void
+ldomsError(virConnectPtr con,
+ virDomainPtr dom,
+ virErrorNumber error,
+ const char *info,
+ int level)
+{
+ const char *errmsg;
+
+ if (error == VIR_ERR_OK) {
+ errmsg = info;
+ /* return; */
+ } else
+ errmsg = __virErrorMsg(error, info);
+
+ __virRaiseError(con, dom, NULL, VIR_FROM_LDOMS, error, level,
+ errmsg, info, NULL, 0, 0, errmsg, info, 0);
+}
+
+/*
+ * getDomainIndex
+ *
+ * What: Get the index for the input Domain for a given connection.
+ * Note: libivrt does not associated an Index with an inactive
+ * Domain. For LDoms, we assign an Index to all Domains.
+ *
+ * Input: domain - A ptr to a virDomain
+ * Output: The Domain ID. -1 if for no ID.
+ */
+static int
+getDomainIndex(virDomainPtr domain)
+{
+ int i, domID;
+
+ /* get the current ldom data from LDM (LDoms Manager) */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getDomainIndex(ENTER) domName=%s, domID=%d, ldom_cnt=%d\n",domain->name,domain->id,ldom_cnt);
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ ldomsError((domain ? domain->conn : NULL), domain, VIR_ERR_INVALID_ARG,
+ __FUNCTION__, VIR_ERR_ERROR);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getDomainIndex(EXIT ERROR) domain input not valid\n");
+ return (-1);
+ }
+
+ domID = domain->id;
+ for (i = 0 ; i < ldom_cnt ; i++) {
+ if (domID >= 0) {
+ if (domID == i) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getDomainIndex(EXIT) From ID: domidx=%d\n",i);
+ return (i);
+ }
+ } else {
+ if (!strcmp(domain->name, ldominfo_list[i]->ldomName)) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getDomainIndex(EXIT) From Name:domidx=%d\n",i);
+ return (i);
+ }
+ }
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getDomainIndex(EXIT ERROR) domID=-1\n");
+ return (-1);
+} /* getDomainIndex() */
+
+/*
+ * ldomsOpen
+ *
+ * Open a connection to the LDoms Manager and handshake to
+ * verify the a connection can be made for future XML requests.
+ *
+ * Input: All inputs are ignored at this time.
+ * Output: 0 -> Success, <0 -> Failure
+ */
+static virDrvOpenStatus
+ldomsOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags)
+{
+ struct timeval tv;
+ int u, ret, connid;
+ int socketFD;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsOpen(ENTER) \n");
+
+ if (!uri)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (!uri->scheme || strcmp(uri->scheme, "ldoms") != 0)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (!uri->scheme || strcmp(uri->scheme, "ldoms")) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsOpen(FAIL): uri scheme NOT correct\n");
+ ldomsError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("URI is not valid for LDoms"), VIR_ERR_ERROR);
+ return (-1);
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsOpen(): scheme=%s, path=%s\n",
+ (uri->scheme==0) ? "NULL" : uri->scheme,
+ (uri->path==0) ? "NULL" : uri->path);
+
+ /* Verify the LDM (LDoms Manager) can be talked to. Open an socket
+ connection, Handshake, then close the socket. */
+ if ((socketFD = open_ldm_connection()) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsOpen(): Cannot talk with LDoms Manager\n");
+ ldomsError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Cannot open socket to LDMD"), VIR_ERR_ERROR);
+ return(-1);
+ }
+ close_ldm_connection(socketFD);
+
+
+ return(0);
+} /* ldomsOpen() */
+
+static int
+ldomsClose(virConnectPtr conn)
+{
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsClose(ENTER/EXIT)\n");
+ /* Nothing to do */
+ return(0);
+}
+
+/*
+ * ldomsGetMaxVcpus
+ *
+ * What: Just get the total number of free CPUs in the system.
+ * Call get_ldom_total_cpu(), so it will set, as a side effect,
+ * the number of free CPUs and free Memory in the system.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * memory - Size in KiloBytes
+ * Output: function return - Number of Max CPUs supported, or -1 for error
+ */
+int
+ldomsGetMaxVcpus(virConnectPtr conn, const char *type)
+{
+ virNodeInfo nodeInfo;
+ int rc;
+ int totalVcpus;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsGetMaxVcpus(ENTER) \n");
+
+ if (get_ldom_total_cpu(&totalVcpus) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsGetMaxVcpus() get_ldom_total_cpu() failed\n");
+ return (0);
+ }
+
+ /* Success */
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsGetMaxVcpus() Free Vcpus = %d\n",ldomsFreeCpu);
+ return (ldomsFreeCpu);
+} /* ldomsGetMaxVcpus() */
+
+/*
+ * ldomsNodeGetInfo
+ *
+ * What: Get the info for a Node, which is the physical
+ * hardware system.
+ *
+ * Input: conn - Pointer to a virConnect struct (Not used)
+ * info - Poiner to a virNodeInfo struct to update
+ * Output: Indirect virNodeInfo struct updated with Node info
+ */
+static int
+ldomsNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
+{
+ int total_cpu;
+ unsigned long total_memory;
+
+ /* to get the CPU frequency and fill the nodeInfo.mhz field
+ *
+ * NOTE:
+ * Since processor_info provides info for the domain on which it
+ * is being called (control domain), the virtual processor id 0 is used
+ * to retrieve the processor speed assuming that the cpu speed
+ * is the same for all Cpus on the system. That is a safe
+ * assumption for single-chip platforms like Ontario and Huron,
+ * but it might not work for multi-chip platforms based on VF or ROCK
+ * chips.
+ */
+ processor_info_t cpu_info;
+ int pid = 0; /* physical processor ID */
+ int p_clock = 1600; /* default processor clock speed in MHz */
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNodeGetInfo(ENTER)\n");
+
+ /*
+ * NOTE: We get the Node info values (number of CPUs and memory)
+ * from the LDM (LDoms Manager) by adding up the total number of CPUs and Memory for all domains.
+ */
+
+ /* if the nodeInfo variable hasn't been filled yet, try to get the
+ * total number of CPUs and memory from the LDM (LDoms Manager).
+ */
+
+
+ if (nodeInfoFilled == 0) {
+
+ strcpy(nodeInfo.model, "SPARC");
+
+ /*
+ * Fill the total amount of memory by sending the LDM list-devices
+ * and list-bindings XML requests and adding up free and bound
+ * memory amounts for all domains. If it fails to retrieve the total
+ * amount of memory from LDM, 64GB (expressed in KB) will be
+ * used as default value.
+ */
+
+ if (get_ldom_total_memory(&total_memory) < 0) {
+ if (ldoms_debug)
+ dprt("LDOMS_DEBUG: ldomsNodeGetInfo() get_ldom_total_memory() failed\n");
+ nodeInfo.memory = 0;
+ } else {
+ if (ldoms_detailed_debug)
+ dprt("LDOMS_DETAILED_DEBUG: ldomsNodeGetInfo() Total Node Memory=%lu\n", total_memory);
+ nodeInfo.memory = total_memory;
+ }
+
+ /*
+ * Fill the total number of CPUs by sending the LDM list-devices
+ * and list-bindings XML requests and adding up free and bound
+ * CPUs for all domains. If it fails to retrieve the total
+ * number of CPUs from LDM, 0 will be used as default value.
+ */
+
+ if (get_ldom_total_cpu(&total_cpu) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNodeGetInfo() get_ldom_total_cpu() failed\n");
+ nodeInfo.cpus = 0;
+ } else {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNodeGetInfo() Total Node CPUs=%d\n", total_cpu);
+ nodeInfo.cpus = total_cpu;
+ }
+
+ /* get the processor clock speed in MHz */
+ while ((pid < 64) && (processor_info(pid++, &cpu_info) != 0) );
+
+ /* Found a pid on the primary domain */
+ if (pid <= 64) {
+ if (ldoms_detailed_debug)
+ dprt("LDOMS_DETAILED_DEBUG: ldomsNodeGetInfo(). processor_info with pid=%d clock=%d\n",
+ pid, cpu_info.pi_clock);
+ p_clock = cpu_info.pi_clock;
+ }
+
+ nodeInfo.mhz = p_clock;
+ nodeInfo.nodes = 1; /* Only 1 node in LDoms */
+ nodeInfo.sockets = 1;
+ nodeInfo.cores = 8; /* 8 cores on N1 and N2. 4 threads on N1 core, 8 on N2 */
+
+ /* If there are more than 32 CPUs, then 8 Threads/Core, else 4 Threads/Core */
+ if (nodeInfo.cpus > 32)
+ nodeInfo.threads = 8; /* This is Threads per Core, not total Threads */
+ else
+ nodeInfo.threads = 4; /* This is Threads per Core, not total Threads */
+
+ /* nodeInfo has been filled */
+ nodeInfoFilled = 1;
+ }
+
+ memcpy(info, &nodeInfo, sizeof(virNodeInfo));
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNodeGetInfo(EXIT)\n");
+ return (0);
+} /* ldomsNodeGetInfo() */
+
+/* Don't really know what to return for this */
+static const char *
+ldomsGetType(virConnectPtr conn)
+{
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsGetType(ENTER)\n");
+ return(strdup("LDoms"));
+}
+
+/* This returns the HV version. Make it the same as the LDoms version */
+static int
+ldomsGetVersion(virConnectPtr conn, unsigned long *hvVer)
+{
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsGetVersion(ENTER/EXIT)\n");
+ *hvVer = getHypervisorVersion();
+ return(0);
+}
+
+static char *
+ldomsGetHostname(virConnectPtr conn)
+{
+
+ int rc;
+ char hostname [MAXHOSTNAMELEN+1];
+ char *host;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsGetHostname(ENTER)\n");
+
+ rc = gethostname (hostname, MAXHOSTNAMELEN);
+ if (rc == -1) {
+ ldomsError (conn, NULL, VIR_ERR_SYSTEM_ERROR, strerror (errno), VIR_ERR_ERROR);
+ return NULL;
+ }
+
+ host = strdup (hostname);
+ if (host == NULL) {
+ ldomsError (conn, NULL, VIR_ERR_SYSTEM_ERROR, strerror (errno), VIR_ERR_ERROR);
+ return NULL;
+ }
+ return host;
+}
+
+/*
+ * ldomsListDomains
+ *
+ * What: Return the array of Domain ID's for all the active Domains.
+ * Send an XML request to LDM (LDoms Manager) for a list of all Domains.
+ *
+ * Yes, this functions does pretty much the same as ldomsNumOfDomains() with
+ * the addition of returning the ID numbers for the valid Domains.
+ *
+ * Input: conn - The Connection structure
+ * maxids - The total number of Domains to look at to
+ * determine what Domain IDs to return.
+ * Output: ids - An array of integers to hold the IDs of the
+ * Domains whose state is other than 'inactive' -
+ * VIR_DOMAIN_SHUTOFF
+ */
+static int
+ldomsListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ int i,n;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsListDomains(ENTER), Max # of non inactive domains=%d\n",maxids);
+
+ /* Send an LDM request 'list-domains' */
+ if (get_ldom_names(&ldom_cnt, &ldominfo_list) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsListDomains() get_ldom_names() failed\n");
+ return (-1);
+ };
+
+ /* The Domain ID will be the index into the ldominfo_list array */
+ for (i=0, n=0; i<ldom_cnt && n<maxids; i++) {
+ if (ldominfo_list[i]->ldomState != LDOM_STATE_INACTIVE) {
+ ids[n++] = i;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsListDomains(), Active Domain ID=%d\n",i);
+ }
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsListDomains(EXIT), # of non inactive domains=%d\n",n);
+ return(n);
+} /* ldomsListDomains() */
+
+/*
+ * ldomsNumOfDomains
+ *
+ * What: Return the total number of active Domains (not VIR_SHUT_OFF)
+ *
+ * Input: conn - Pointer to a connection structure
+ * Output: function return - # of active Domains
+ */
+static int
+ldomsNumOfDomains(virConnectPtr conn)
+{
+ int rc, i, numActive=0;
+ /* int ldom_cnt; */
+ /* ldominfo_t **ldominfo_list = NULL; */
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNumOfDomains(ENTER) \n");
+ /*
+ * Call LDM with a list-domains cmd to get the total
+ * # of Domains and the basic information of each one.
+ */
+
+ if (get_ldom_names(&ldom_cnt, &ldominfo_list) < 0) {
+ /* Any ldominfo_t memory was freed in get_ldom_names() */
+ free(ldominfo_list);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNumOfDomains() get_ldom_names() failed\n");
+ return (0);
+ };
+
+ /* Get the number of non inactive domains */
+ for (i=0; i<ldom_cnt; i++) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNumOfDomains() name=%s\n",ldominfo_list[i]->ldomName);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNumOfDomains() state=%d\n",ldominfo_list[i]->ldomState);
+ if (ldominfo_list[i]->ldomState != LDOM_STATE_INACTIVE) numActive++;
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNumOfDomains(EXIT) non inactive ldom_cnt=%d\n",numActive);
+ return (numActive);
+
+} /* ldomsNumOfDomains() */
+
+/*
+ * ldomsDomainCreateXML
+ *
+ * What: Create a domain from an XML file so that it is left in the
+ * inactive state. Just call the DefineXML function. The XML input
+ * has to be a complete and valid XML requeset for the LDM. No
+ * modification is done to this file.
+ *
+ * Input: xml - The xml file
+ * Output: function return - A ptr to a virDomain or NULL
+ */
+virDomainPtr
+ldomsDomainCreateXML(virConnectPtr conn, const char *xml, unsigned int flags)
+{
+ virDomainPtr domPtr = NULL;
+ char *domainName = NULL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainCreateXML(ENTER) \n");
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainCreateXML(ENTER) xmldoc=\n%s\n",xml);
+
+ /* Send the XML file along with the lifecycle action */
+ domainName = send_ldom_create_domain((char *)xml, XML_ADD_DOMAIN);
+
+ /*
+ * If the create/bind domain was successful, then we have to create a DomainInfo
+ * structure to pass back to the caller. We need the Domain name that was
+ * created, and the only way to get that is from parsing the input xml
+ * document. This is done in send_ldom_create_domain() and passed back as the return.
+ * Also we create the uuid for the domain name.
+ */
+ if (domainName != NULL) {
+
+ /*
+ * The UUID is not important, cuz only the Domain name is printed
+ * out in the virsh. So just use the default UUID.
+ */
+ domPtr = virGetDomain(conn, domainName, Uuid);
+ free(domainName);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainCreateXML(EXIT) \n");
+
+ return (domPtr);
+} /* ldomsDomainCreateXML() */
+
+
+/*
+ * ldomsDomainLookupByID
+ *
+ * What: Given a Domain ID, either malloc or return the existing
+ * virDomain structure for the Domain associated with the ID.
+ *
+ * Input: conn - A connection structure
+ * id - ID of the Domain you want to find
+ * Output: Pointer to a virDomain of the Domain identified by the ID
+ */
+static virDomainPtr
+ldomsDomainLookupByID(virConnectPtr conn, int id)
+{
+
+ virDomainPtr domPtr;
+ int i, idx=-1;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainLookupByID(ENTER) id=%d\n",id);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+ /* Find the Domain that matches the ID. The index of the ldominfo_list
+ * array is the Domain ID */
+ for (i=0; i<ldom_cnt; i++) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainLookupByID() id=%d, Dom id=%d\n",id,i);
+ if (i == id) {
+ idx = i;
+ break;
+ }
+ }
+
+ /*
+ * If Domain is inactive, then libvirt does not assocaite an ID with an
+ * inactive domain. So check the LDoms domain state and if inactive, log
+ * and return an error.
+ */
+ if ((idx < 0) || (ldominfo_list[idx]->ldomState == LDOM_STATE_INACTIVE)) {
+ ldomsError(conn, NULL, VIR_ERR_NO_DOMAIN, _("no ID match"), VIR_ERR_ERROR);
+ return(NULL);
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainLookupByID() found id=%d, Dom id=%d\n",id,idx);
+
+ domPtr = virGetDomain(conn, ldominfo_list[id]->ldomName, ldominfo_list[id]->uuid);
+ if (domPtr == NULL) {
+ ldomsError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"), VIR_ERR_ERROR);
+ return(NULL);
+ }
+
+ domPtr->id = id;
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainLookupByID(EXIT) \n");
+ return (domPtr);
+} /* ldomsDomainLookupByID() */
+
+/*
+ * ldomsDomainLookupByUUID
+ *
+ * What: Given a Domain UUID, either malloc or return the existing
+ * virDomain structure for the Domain associated with the UUID.
+ *
+ * Input: conn - A connection structure
+ * id - ID of the Domain you want to find
+ * Output: Pointer to a virDomain of the Domain identified by the UUID
+ */
+static virDomainPtr
+ldomsDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+
+ virDomainPtr domPtr;
+ int i, idx=-1;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainLookupByUUID(ENTER) \n");
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /* Find the Domain that matches the UUID. */
+ for (i=0; i<ldom_cnt; i++) {
+ if (memcmp(uuid, ldominfo_list[i]->uuid, VIR_UUID_BUFLEN) == 0) {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx < 0) {
+ ldomsError(conn, NULL, VIR_ERR_NO_DOMAIN, _("no UUID match"), VIR_ERR_ERROR);
+ return(NULL);
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainLookupByUUID() found id=%d\n",idx);
+
+ domPtr = virGetDomain(conn, ldominfo_list[idx]->ldomName, ldominfo_list[idx]->uuid);
+ if (domPtr == NULL) {
+ ldomsError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"), VIR_ERR_ERROR);
+ return(NULL);
+ }
+
+ /* If the Domain state is inactive, then the ID must be set to -1 */
+ if (ldominfo_list[idx]->ldomState == LDOM_STATE_INACTIVE) {
+ idx = -1;
+ }
+ domPtr->id = idx;
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainLookupByUUID(EXIT) \n");
+ return (domPtr);
+} /* ldomsDomainLookupByID() */
+
+/*
+ * ldomsDomainLookupByName
+ *
+ * What: Given a Domain Name, either malloc or return the existing
+ * virDomain structure for the Domain associated with the name.
+ * The virDomain will contain the ID and UUID for the domain.
+ * If a Domain is in the inactive state, then we don't set a
+ * ID for it. libvirt considers inactive Domains to have an
+ * ID of -1 until they are moved out of the inactive state.
+ *
+ *
+ * Input: conn - A connection structure
+ * name - Pointer to the Domain name
+ * Output: Pointer to a virDomain of the Domain identified by the name
+ */
+virDomainPtr
+ldomsDomainLookupByName(virConnectPtr conn, const char *name)
+{
+ virDomainPtr domPtr = NULL;
+ int i, uuidIdx, idx = -99;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainLookupByName(ENTER) name=%s\n",name);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /* Find the index of our internal ldominfo_list[] that has the Domain data */
+ for (i=0; i<ldom_cnt; i++) {
+ if (strcmp(ldominfo_list[i]->ldomName,name) == 0) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainLookupByName(), Found Domain: ID=%d\n",i);
+
+ /* If the Domain is inactive, then set the index to -1 */
+ if (ldominfo_list[i]->ldomState == LDOM_STATE_INACTIVE) {
+ idx = -1;
+ uuidIdx = i;
+ }
+ else
+ idx = i;
+ break;
+ }
+ }
+
+
+ /* A non-inactive domain was found */
+ if (idx >= 0) {
+ domPtr = virGetDomain(conn, name, ldominfo_list[idx]->uuid);
+ if (domPtr == NULL) {
+ ldomsError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating domain"), VIR_ERR_ERROR);
+ return(NULL);
+ }
+ domPtr->id = idx;
+ }
+
+ /* An inactive domain was found, or worst case, LDM does not know
+ * about the input domain name!! This latter case should not happen
+ */
+ else if (idx == -1) {
+ domPtr = virGetDomain(conn, name, ldominfo_list[uuidIdx]->uuid);
+ if (domPtr == NULL) {
+ ldomsError(conn, NULL, VIR_ERR_NO_MEMORY, _("allocating inactive domain"), VIR_ERR_ERROR);
+ return(NULL);
+ }
+ domPtr->id = idx;
+ }
+
+ /* No domain name match was made */
+ else {
+ ldomsError(conn, NULL, VIR_ERR_NO_DOMAIN, _("no domain name match"), VIR_ERR_ERROR);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainLookupByName(EXIT) ID=%d\n",idx);
+ return (domPtr);
+} /* ldomsDomainLookupByName() */
+
+/*
+ * ldomsDomainSuspend
+ *
+ * What: Given a Domain pointer, suspend/stop/pause the domain.
+ * These 3 actions are equivalent: suspend/stop/pause.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainSuspend(virDomainPtr domain)
+{
+ int rc;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSuspend(ENTER) name=%s\n",domain->name);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /*
+ * If the domain state is not active (1), then we can't perform
+ * this action.
+ */
+
+ if (ldominfo_list[domain->id]->ldomState != LDOM_STATE_ACTIVE) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSuspend() Domain state not 'active', aborting request. domain=%s, state=%d\n",domain->name, ldominfo_list[domain->id]->ldomState);
+ return (-1);
+ }
+
+ /* Request LDM to change the state of the LDom */
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_STOP);
+
+ /*
+ * If successful, the domain state changed from active to bound,
+ * so update the status.
+ */
+ if (rc == 0) {
+ ldominfo_list[domain->id]->ldomState = LDOM_STATE_BOUND;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainSuspend() Domain state changed to 'bound'. domain=%s\n",
+ domain->name);
+ return (0);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSuspend(EXIT) Domain state change failed. domain=%s\n",domain->name);
+ return (-1);
+} /* ldomsDomainSuspend() */
+
+/*
+ * ldomsDomainResume
+ *
+ * What: Given a Domain pointer, resume/start the domain.
+ * These 2 states are equivalent: resume/start.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainResume(virDomainPtr domain)
+{
+ int rc;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainResume(ENTER) name=%s\n",domain->name);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /*
+ * If the domain state is not bound (6), then we can't perform
+ * this action.
+ */
+
+ if (ldominfo_list[domain->id]->ldomState != LDOM_STATE_BOUND) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainResume() Domain state not 'bound', aborting request. domain=%s, state=%d\n",domain->name, ldominfo_list[domain->id]->ldomState);
+ return (0);
+ }
+
+ /* Request LDM to change the state of the LDom */
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_START);
+
+ /*
+ * If successful, the domain state changed from bound to active,
+ * so update the status.
+ */
+ if (rc == 0) {
+ ldominfo_list[domain->id]->ldomState = LDOM_STATE_ACTIVE;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainResume() Domain state changed to 'active'. domain=%s\n",
+ domain->name);
+ return (0);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainResume(EXIT) Domain state change failed. domain=%s\n",domain->name);
+ return (-1);
+} /* ldomsDomainResume() */
+
+/*
+ * ldomsDomainShutdown
+ *
+ * What: Given a Domain pointer, shutdown/bind the domain.
+ * The domain can only be in the active state to begin,
+ * and will be put into the bound state.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainShutdown(virDomainPtr domain)
+{
+ int rc = -1;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainShutdown(ENTER) domName=%s, domID=%d\n",
+ domain->name,domain->id);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /* If the domain is inactive, then log an error and return */
+ if (domain->id == -1) {
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, _("Domain is inactive"), VIR_ERR_WARNING );
+ return (-1);
+ }
+
+ /* If the domain is already bound, then log an error and return */
+ if (ldominfo_list[domain->id]->ldomState == LDOM_STATE_BOUND) {
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, _("Domain is already bound"), VIR_ERR_WARNING );
+ return (-1);
+ }
+
+
+ /* If the domain state is active, then stop the domain */
+ if (ldominfo_list[domain->id]->ldomState == LDOM_STATE_ACTIVE) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainShutdown() Domain state is 'active', stopping...\n");
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_STOP);
+ }
+
+ /*
+ * If successful, the domain state changed from active to bound,
+ * so update the status.
+ */
+ if (rc == 0) {
+ ldominfo_list[domain->id]->ldomState = LDOM_STATE_BOUND;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainShutdown() Domain state changed to 'bound'. domain=%s\n",
+ domain->name);
+ return (0);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainShutdown(EXIT) Domain state change failed. domain=%s\n",domain->name);
+
+ return (-1);
+} /* ldomsDomainShutdown() */
+
+
+/*
+ * ldomsDomainDestroy
+ *
+ * What: Given a Domain pointer, destroy/unbind the domain.
+ * The domain can be in the active or bound state to begin
+ * and will be put into the inactive state.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainDestroy(virDomainPtr domain)
+{
+ int rc = -1;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDestroy(ENTER) domName=%s, domID=%d\n",
+ domain->name,domain->id);
+
+ /* If the domain is already inactive, then log an error and return */
+ if (domain->id == -1) {
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, _("Domain is already inactive"), VIR_ERR_WARNING );
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDestroy() Domain is already inactive.\n");
+ return (-1);
+ }
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /* If the domain state is active, then stop the domain */
+ if (ldominfo_list[domain->id]->ldomState == LDOM_STATE_ACTIVE) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDestroy() Domain state is 'active', stopping...\n");
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_STOP);
+
+ /* Need to tell the next piece of code that a 'stop' was done and
+ * was successful, because the ldom info has not been updated.
+ */
+ if (rc == 0) rc = 1;
+ }
+
+ /* If the domain state is bound (6), then unbind the domain */
+ if ((rc == 1) || (ldominfo_list[domain->id]->ldomState == LDOM_STATE_BOUND)) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDestroy() Domain state is 'bound' rc=%d, unbinding...\n",rc);
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_UNBIND);
+ }
+
+ /*
+ * If successful, the domain state changed to inactive,
+ * so update the status.
+ */
+ if (rc == 0) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDestroy() Domain state changed to 'inactive'. domain=%s\n",
+ domain->name);
+ return (0);
+ }
+
+ /*
+ * In case the input domain info is not correct and the domain is really
+ * inactive, log a warning.
+ */
+ if (rc == -1) {
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, _("Domain is already inactive"), VIR_ERR_WARNING );
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDestroy() Domain state/ID not indicating inactive, ID=%d\n", domain->id);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDestroy(EXIT) Domain state change failed. domain=%s\n",domain->name);
+
+ return (-1);
+} /* ldomsDomainDestroy() */
+
+/*
+ * ldomsDomainGetOSType
+ *
+ * What: The the OS type for an LDoms domain
+ *
+ * Input: domain - A pointer to the virDomain structure * NOT USED *
+ * Output: String representing the OS type
+ */
+char *
+ldomsDomainGetOSType(virDomainPtr domain)
+{
+ return strdup("Solaris");
+} /* ldomsDomainGetOSType() */
+
+
+/*
+ * ldomsDomainGetMaxMemory
+ *
+ * What:
+ * For LDoms, GetMaxMemory will just get the current memory
+ * allocated to the Domain. There is no concept of Max memory
+ * for a Domain in LDoms.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - The amount of memory in Kilobytes
+ *
+ */
+unsigned long
+ldomsDomainGetMaxMemory(virDomainPtr domain)
+{
+ int domidx;
+ unsigned long memory;
+
+ if ((domidx = getDomainIndex(domain)) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetMaxMemory(EXIT) getDomainIndex() failed\n");
+ return (-1);
+ }
+ memory = ldominfo_list[domidx]->ldomMemSize;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetMaxMemory() MaxMemory=%dKB\n",memory);
+ return (memory);
+} /* ldomsDomainGetMaxMemory() */
+
+/*
+ * ldomsDomainSetMemory
+ *
+ * What: Given a Domain pointer, send an XML request to change
+ * the amount of memory for the domain.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * memory - Size in KiloBytes
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainSetMemory(virDomainPtr domain, unsigned long memory)
+{
+ int rc;
+ int domidx;
+ virDomainInfo domInfo;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetMemory(ENTER) memory=%d\n",memory);
+
+ if ((domidx = getDomainIndex(domain)) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetMemory(EXIT) getDomainIndex() failed\n");
+ return (-1);
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainSetMemory: domain=%s, domidx=%d\n",domain->name,domidx);
+
+ /* Send request to LDM to set the memory */
+ rc = send_ldom_set_memory(domain->name, memory);
+
+ if (rc == 0) {
+ ldominfo_list[domidx]->ldomMemSize = memory;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainSetMemory() memory changed to %dKB\n",memory);
+ }
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetMemory(EXIT) memory change failed\n");
+ return (-1);
+ }
+
+ /* Success */
+ return (0);
+} /* ldomsDomainSetMemory() */
+
+/*
+ * ldomsDomainSetMaxMemory
+ *
+ * What:
+ * For LDoms, you cannot set the Maximum memory that a domain can use.
+ * If a domain asks for X memory and it is available, then the domain
+ * will get it when it is bound. Max memory is already calculated for
+ * all domains, just to be able to work with virsh, so this function will
+ * merely return Success to appease virsh.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * memory - Size in KiloBytes
+ * Output: function return - 0 - success
+ *
+ */
+int
+ldomsDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
+{
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetMaxMemory(ENTER/EXIT) memory=%d\n",memory);
+ return (0);
+} /* ldomsDomainSetMaxMemory() */
+
+/*
+ * ldomsDomainGetInfo
+ *
+ * What: Given a virDomain, get the info for that Domain and return it.
+ * Note: The info.maxMem variable is set to the maximum memory allowed.
+ * We try to get the maximum memory allowed by LDM, by calling
+ * list-devices to get the free memory and by
+ * adding up the total used memory from all domains.
+ * If this fails,
+ * the info.maxMem variable will be set to the maximum value for
+ * a signed long. This is because LDoms does not have a
+ * concept for Max memory for a Domain. However the VMM and
+ * virsh shell do have a Max mem concept and won't let you
+ * change the memory for a Domain if the new amount is
+ * greater than the Maximum. So this is why we set the Max
+ * to the value for a signed long, even though the info.maxMem
+ * data type is an unsigned long.
+ *
+ * Input: domain - Pointer to a virDomain struct
+ * info - Poiner to a virDomainInfo struct to update
+ * Output: Indirect virDomainInfo struct updated with input domain info
+ */
+int
+ldomsDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info)
+{
+ char state;
+ int domidx;
+ struct timeval tv;
+ virDomainInfo domInfo;
+
+ unsigned long maxmem;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetInfo(ENTER) \n");
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ ldomsError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("getting time of day"), VIR_ERR_WARNING);
+ return (-1);
+ }
+
+ if ((domidx = getDomainIndex(domain)) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetInfo(EXIT) getDomainIndex() failed\n");
+ return (-1);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetInfo() domain=%s, domidx=%d\n",domain->name,domidx);
+
+/* Convert between LDom Domain state and libvirt Domain state
+ * LDoms
+ * 1 = active
+ * 2 = stopping
+ * 3 = inactive
+ * 4 = binding
+ * 5 = unbinding
+ * 6 = bound
+ * 7 = starting
+ *
+ * libvirt
+ *
+ * VIR_DOMAIN_NOSTATE = 0, no state
+ * VIR_DOMAIN_RUNNING = 1, /* the domain is running
+ * VIR_DOMAIN_BLOCKED = 2, /* the domain is blocked on resource
+ * VIR_DOMAIN_PAUSED = 3, /* the domain is paused by user
+ * VIR_DOMAIN_SHUTDOWN= 4, /* the domain is being shut down
+ * VIR_DOMAIN_SHUTOFF = 5, /* the domain is shut off
+ * VIR_DOMAIN_CRASHED = 6 /* the domain is crashed
+ */
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetInfo() ldomName=%s\n",ldominfo_list[domidx]->ldomName);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetInfo() ldomState=%d\n",ldominfo_list[domidx]->ldomState);
+
+ switch (ldominfo_list[domidx]->ldomState) {
+ case LDOM_STATE_ACTIVE: state = VIR_DOMAIN_RUNNING; break;
+ case LDOM_STATE_STOPPING: state = VIR_DOMAIN_SHUTDOWN; break;
+ case LDOM_STATE_INACTIVE: state = VIR_DOMAIN_SHUTOFF; break;
+ case LDOM_STATE_BINDING: state = VIR_DOMAIN_SHUTDOWN; break;
+ case LDOM_STATE_UNBINDING: state = VIR_DOMAIN_SHUTOFF; break;
+ case LDOM_STATE_BOUND: state = VIR_DOMAIN_SHUTDOWN; break;
+ case LDOM_STATE_STARTING: state = VIR_DOMAIN_RUNNING; break;
+ default: state= VIR_DOMAIN_NOSTATE; break;
+ }
+
+ /* Only name and state are obtained from a list-domain */
+ domInfo.state = state;
+
+ /*
+ * Get the maximum memory that can be allocated for this domain.
+ * For a domain that is bound or active, then it already has that
+ * memory allocated to it. The amount the it can add is only the
+ * amount free in the system, so just add Free + Bound memory.
+ *
+ * For a domain that is inactive, it can request any amount of
+ * memory, even more than what is physically present. Thus we
+ * have to put an upper limit on the Maximum, so again, we just
+ * add the amount of Free system memory to the requested memory.
+ *
+ * Set the dominfo.maxMem to the maximum value for a signed long
+ * if it fails to get the maximum memory allowed from LDM
+ */
+ if (get_free_memory(&maxmem) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetInfo() get_free_memory() failed\n");
+ domInfo.maxMem = MAXLONG;
+ } else
+ domInfo.maxMem = maxmem + ldominfo_list[domidx]->ldomMemSize;
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetInfo() MaxMemory=%d\n", maxmem);
+
+ domInfo.memory = ldominfo_list[domidx]->ldomMemSize;
+ domInfo.nrVirtCpu = (unsigned short)ldominfo_list[domidx]->ldomNumVCpu;
+ /* LDM XML does not give the uptime for a Domain, so just set this to 0 */
+ domInfo.cpuTime = 0; /* ((tv.tv_sec * 1000ll * 1000ll * 1000ll * (domidx+1)) + (tv.tv_usec + 100011)); */
+ memcpy(info, &domInfo, sizeof(virDomainInfo));
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetInfo() ldomMemory=%d\n",ldominfo_list[domidx]->ldomMemSize);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetInfo() ldomVcpu=%d\n",ldominfo_list[domidx]->ldomNumVCpu);
+
+
+ return (0);
+} /* ldomsDomainGetInfo() */
+
+/*
+ * ldomsDomainSetVcpus
+ *
+ * What: Given a Domain pointer, send an XML request to change
+ * the number of cpus for the domain.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
+{
+ int rc;
+ int domidx;
+ virDomainInfo domInfo;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetVcpus(ENTER) vcpus=%d\n",nvcpus);
+
+ if ((domidx = getDomainIndex(domain) < 0)) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetVcpus(EXIT) getDomainIndex() failed\n");
+ return (-1);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainSetVcpus: domain=%s, domidx=%d\n",domain->name,domidx);
+ rc = send_ldom_set_vcpu(domain->name, nvcpus);
+
+ if (rc == 0) {
+ ldominfo_list[domidx]->ldomNumVCpu = nvcpus;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainSetVcpus() vcpus changed to %d\n",nvcpus);
+ }
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainSetVcpus() vcpu change failed\n");
+ return (-1);
+ }
+ return(0);
+
+} /* ldomsDomainSetVcpus() */
+
+/*
+ * ldomsDomainGetVcpus
+ *
+ * What: Given a Domain pointer, send an XML request to get
+ * the CPU bindings for the domain. Then fill in the
+ * input cpuInfo structure with detailed info for each
+ * CPU: virt->phys mapping, State, Uptime. The Affinity
+ * is only Xen specific at this time.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+ unsigned char *cpumaps, int maplen)
+{
+ int i,rc;
+ int domidx;
+ int numCpu;
+ long long upTime;
+ char cpuBits;
+ cpuBindings_t *cpuBindings;
+ processor_info_t pinfo;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetVcpus(ENTER) domName=%s, maxinfo=%d, maplen=%d\n",domain->name, maxinfo, maplen);
+
+ /* Get the Domain index */
+ if ((domidx = getDomainIndex(domain) < 0)) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetVcpus(EXIT) getDomainIndex() failed\n");
+ return (-1);
+ }
+
+ /* The domain must be in the Bound or Active state */
+ if ( (ldominfo_list[domidx]->ldomState == LDOM_STATE_BOUND) ||
+ (ldominfo_list[domidx]->ldomState == LDOM_STATE_ACTIVE) )
+ {
+ if ((numCpu = get_ldom_cpu_bindings(domain->name, &cpuBindings)) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetVcpus(EXIT) numCpu=%d failed\n",numCpu);
+ return (-1);
+ }
+ }
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetVcpus(EXIT) Domain in wrong state %s\n",ldominfo_list[domidx]->ldomState);
+ return (-1);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainGetVcpus() numCpu=%d, cpuBindings=%d \n",numCpu,cpuBindings);
+
+ /* Walk the linked list of CPU bindings and fill in the cpuInfoPtr return structure */
+
+ upTime = getCpuUpTime();
+ while (cpuBindings != NULL) {
+
+ /* Get the CPU state from processor_info(). This will only work for
+ * CPUs in the Control Domain. All other CPUs are in the Guest Domains,
+ * so we set their state to Unknown and Uptime to 0.
+ * TODO unless we can get the State and Uptime from the PRI??
+ */
+
+ if (processor_info(cpuBindings->real, &pinfo) == 0) {
+ switch (pinfo.pi_state) {
+ case 1: info->state = VIR_VCPU_OFFLINE; break;
+ case 2: info->state = VIR_VCPU_RUNNING; break;
+ case 3: info->state = VIR_VCPU_BLOCKED; break;
+ case 4: info->state = VIR_VCPU_OFFLINE; break;
+ case 5: info->state = VIR_VCPU_OFFLINE; break;
+ case 6: info->state = VIR_VCPU_RUNNING; break;
+ case 7: info->state = VIR_VCPU_OFFLINE; break;
+ default: info->state = VIR_VCPU_OFFLINE; break;
+ }
+ info->cpuTime = upTime;
+ } else {
+ info->state = VIR_VCPU_UNKNOWN;
+ info->cpuTime = 0;
+ }
+
+ info->number = cpuBindings->virt;
+ info->cpu = cpuBindings->real;
+
+ /* Got this from libvirt/libvirt.h VIR_CPU_USABLE */
+ /* cpumaps[(info->number) + (info->cpu)/8] = (1<<((info->cpu)%8)); */
+ info++;
+
+ cpuBindings = cpuBindings->next;
+ }
+
+ return (numCpu);
+
+} /* ldomsDomainSetVcpus() */
+
+/*
+ * ldomsDomainGetMaxVcpus
+ *
+ * What: If the domain is inactive, then you can set the cpu constraint
+ * to any number you want, because the CPUs are not reserved until
+ * the domain is bound. Return MAXINT for inactive domains.
+ *
+ * For non-inactive domains, call existing fuctions to get the amount
+ * of Free and Used CPUs in the system. Now since a request is being
+ * made for a domain that already has Vcpus allocated to it, we have
+ * to add that amount of the Free amount, and then return that value.
+ *
+ * Example. Total Vcpus=32; Free Vcpus=10; Domains X has 15.
+ * Now, we want to increase Domain X Vcpus to 17.
+ * Now, if we return the # for Free Vcpus, virsh will not call the
+ * SetVcpu routine, and will report an error instead, because the
+ * request of 17 is greater than the Free amount.
+ * So we add the Free (10) and the current allocated (15) and return
+ * that as the Max # of Vcpus.
+ *
+ *
+ * Input: domain - A pointer to the virDomain structure UNUSED
+ * Output: function return - >=0 # of Free CPUs. <0 error.
+ */
+int
+ldomsDomainGetMaxVcpus(virDomainPtr domain)
+{
+ int freeVcpus;
+ int domainVcpus;
+
+ /* inactive domains can request any amount of vcpus */
+ if (domain->id < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetMaxVcpus(ENTER) inactive domain=%s, MaxVcpus=%d\n",domain->name,MAXINT);
+ return (MAXINT);
+ }
+
+ /*
+ * For bound and active domains, sum the # of Free Vcpus and the # currently
+ * currently used by the Domain. This is the Max # that can be requested.
+ */
+ freeVcpus = ldomsGetMaxVcpus(NULL, NULL);
+ domainVcpus = ldominfo_list[domain->id]->ldomNumVCpu;
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainGetMaxVcpus() Domain Vcpus=%d, Free Vcpus=%d\n",ldominfo_list[domain->id]->ldomNumVCpu,freeVcpus);
+
+ return (freeVcpus + domainVcpus);
+
+
+} /* ldomsDomainSetVcpus() */
+
+/*
+ * ldomsDomainDumpXML
+ *
+ * What: Send a list-constraints request to LDM for the domain specified
+ * by the input virDomain.
+ *
+ * Input: domain - Pointer to a virDomain structure
+ * Output: function return - char ptr to the XML data
+ */
+char *
+ldomsDomainDumpXML(virDomainPtr domain, int flags)
+{
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDumpXML(ENTER) domain=%s\n",domain->name);
+
+ xmlDocPtr xml_to_send;
+ xmlDocPtr xml_received;
+ unsigned char *xml;
+ int xmlSize;
+ int domidx;
+
+ if ((domidx = getDomainIndex(domain)) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDumpXML(EXIT) getDomainIndex() failed\n");
+ return (NULL);
+ }
+
+ /* Create XML list-constraints request */
+ xml_to_send = create_xml_file_4_ldom_action(domain->name, XML_LIST_CONST);
+ if (xml_to_send == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDumpXML() can not create list-constraints xml file\n");
+ ldomsError(NULL, domain, VIR_ERR_INTERNAL_ERROR, "Could not create XML file", VIR_ERR_ERROR);
+ return (NULL);
+ }
+
+ /* Send request to LDM and receive response */
+ xml_received = send_xml_file_to_ldm(xml_to_send);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDumpXML() failed to send xml file to ldm and receive xml response\n");
+ ldomsError(NULL, domain, VIR_ERR_OPERATION_FAILED, "Could not create XML file", VIR_ERR_ERROR);
+ xmlFreeDoc(xml_to_send);
+ return (NULL);
+ }
+
+ /* Dump the response to memory */
+ xml = malloc(sizeof(char) * 10000);
+ xmlKeepBlanksDefault(0);
+ xmlDocDumpFormatMemory(xml_received, &xml, &xmlSize, 1);
+ if ( xmlSize > 0 ) {
+ xmlFree(xml_received);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDumpXML() xml doc size is %d:\n%s\n",xmlSize,xml);
+ return ((char *)xml);
+ }
+
+ return (NULL);
+
+} /* ldomsDomainDumpXML() */
+
+/*
+ * ldomsListDefinedDomains
+ *
+ * What: Return the names of all inactive Domains
+ *
+ * Input: conn - Pointer to a connection structure
+ * names - An array of pointers to chars (Domain names)
+ * maxnames - Total number of inactive Domains
+ * Output: function return - # of inactive Domains found
+ * names - Updated pointers to strdup'd inactive Domain names
+ */
+int ldomsListDefinedDomains(virConnectPtr conn,
+ char **const names,
+ int maxnames)
+{
+
+/* virsh command 'define' creates a domain but leaves it in the bound state.
+ * This routine is finding all inactive domains, but the name of the routine is
+ * ListDefinedDomains. We are just following what test.c does, which is count
+ * the number of Domains in libvirt state SHUTOFF, which is LDoms state inactive.
+ */
+ int n = 0, i;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsListDefinedDomains(ENTER) maxnames=%d\n",maxnames);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /* TODO NOTE: We did not call get_ldom_names() here since the thought
+ * is that ldomsNumOfDefinedDomains() will always be called right
+ * before this is. This may not be the case, but for now we will
+ * leave until we find out otherwise.
+ */
+ for (i = 0, n = 0 ; i < ldom_cnt && n < maxnames ; i++) {
+ if (ldominfo_list[i]->ldomState == LDOM_STATE_INACTIVE) {
+ names[n++] = strdup(ldominfo_list[i]->ldomName);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsListDefinedDomains() inactive domain=%s\n",
+ ldominfo_list[i]->ldomName);
+ }
+ }
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsListDefinedDomains(EXIT) # of inactive domains=%d\n",n);
+ return (n);
+} /* ldomsListDefinedDomains() */
+
+/*
+ * ldomsNumOfDefinedDomains
+ *
+ * What: Return the total number of inactive Domains (VIR_SHUT_OFF)
+ *
+ * Input: conn - Pointer to a connection structure
+ * Output: function return - # of inactive Domains
+ */
+int
+ldomsNumOfDefinedDomains (virConnectPtr conn)
+{
+ int numInactive = 0, i;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNumOfDefinedDomains(ENTER) \n");
+
+ /* Send an LDM request 'list-domains' */
+ if (get_ldom_names(&ldom_cnt, &ldominfo_list) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNumOfDefinedDomains() get_ldom_names() failed\n");
+ return (-1);
+ };
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNumOfDefinedDomains() get_ldom_names(return) ldom_cnt=%d\n",ldom_cnt);
+
+
+ /* The Domain ID will be the index into the ldominfo_list array */
+ for (i=0; i<ldom_cnt; i++) {
+ if (ldominfo_list[i] == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNumOfDefinedDomains() ldominfo_list[%d] is NULL\n",i);
+ }
+ else if (ldominfo_list[i]->ldomState == LDOM_STATE_INACTIVE) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNumOfDefinedDomains() inactive Domain ID=%d \n",i);
+ numInactive++;
+ }
+ }
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsNumOfDefinedDomains(EXIT) # of inactive domains=%d \n",numInactive);
+ return (numInactive);
+} /* ldomsNumOfDefinedDomains() */
+
+/*
+ * ldomsDomainStart
+ *
+ * What: Start a previously defined inactive domain.
+ * The domain can be in the inactive or bound state to begin
+ * and will be put into the active state.
+ *
+ * Input: domain - A pointer to a virDomain structure (unused)
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainStart(virDomainPtr domain)
+{
+ int rc = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainStart(ENTER) domName=%s, domID=%d\n",
+ domain->name,domain->id);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+
+ /* If the domain ID is -1, this means the domain state is 'inactive.
+ * If the domain state is inactive (3), then bind the domain */
+ if ((domain->id == -1) ||
+ (ldominfo_list[domain->id]->ldomState == LDOM_STATE_INACTIVE)) {
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainStart() Domain state is 'inactive', binding...\n");
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_BIND);
+
+ /* Need to tell the next piece of code that a 'bind' was done and
+ * was successful, because the ldom info has not been updated.
+ */
+ if (rc == 0) rc = 1;
+ }
+
+ /* If the domain was inactive and failed to bind, or if the domain was already
+ * active, then we fall into this case.
+ */
+ if (rc < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainStart(EXIT) Domain state change failed. domain=%s\n",domain->name);
+ return (-1);
+ }
+
+ /* If the domain state is bound (6), then start the domain */
+ if ((rc == 1) || (ldominfo_list[domain->id]->ldomState == LDOM_STATE_BOUND)) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainStart() Domain state is 'bound' rc=%d, starting...\n",rc);
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_START);
+ if (rc == 0) rc = 2;
+ }
+
+ /* If successful, the domain state changed to active */
+ if (rc == 2) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainStart() Domain state changed to 'active'. domain=%s\n",
+ domain->name);
+ return (0);
+ }
+
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, _("Domain is active"), VIR_ERR_WARNING );
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainStart(EXIT) Domain state change failed. domain=%s\n",domain->name);
+ return (-1);
+
+
+} /* ldomsDomainStart() */
+
+/*
+ * ldomsDomainDefineXML
+ *
+ * What: Create a domain from an XML file so that it is left in the
+ * bound state. The XML input must be of the form from the
+ * output of 'ldm list-constraints -x <ldom>'. Any of the
+ * XML can be changed, but the <action> tag will be added by
+ * this code.
+ *
+ * Input: xml - The xml file in a char buffer
+ * Output: function return - A ptr to a virDomain or NULL
+ */
+virDomainPtr
+ldomsDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ virDomainPtr domPtr = NULL;
+ char *domainName = NULL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDefineXML(ENTER) \n");
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainDefineXML(ENTER) xmldoc=\n%s\n",xml);
+
+ /* Send the XML file along with the lifecycle action */
+ domainName = send_ldom_create_domain((char *)xml, XML_BIND_DOMAIN);
+
+ /*
+ * If the create domain was successful, then we have to create a DomainInfo
+ * structure to pass back to the caller. We need the Domain name that was
+ * created, and the only way to get that is from parsing the input xml
+ * document. This is done in send_ldom_create_domain() and passed back as the return.
+ * Also we create the uuid for the domain name.
+ */
+ if (domainName != NULL) {
+
+ /*
+ * The UUID is not important, cuz only the Domain name is printed
+ * out in the virsh. So just use the default UUID.
+ */
+ domPtr = virGetDomain(conn, domainName, Uuid);
+ free(domainName);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainDefine(EXIT) \n");
+
+ return (domPtr);
+} /* ldomsDomainDefineXML() */
+
+/*
+ * ldomsDomainUndefine
+ *
+ * What: Given a Domain pointer, undefine/delete the domain.
+ * The domain can only be in the inactive state to begin,
+ * and will be deleted to not exist.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - >=0 is success
+ */
+int
+ldomsDomainUndefine(virDomainPtr domain)
+{
+ int rc = -1;
+ int domidx;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainUndefine(ENTER) domName=%s, domID=%d\n",
+ domain->name,domain->id);
+
+ /* If the Domain is inactive, the ID in the input domain will be a -1.
+ * Get the domain index from our ldominfo_list to verify it is indeed inactive
+ * before we try to delete it.
+ */
+ if ((domidx = getDomainIndex(domain)) < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainUndefine(EXIT) getDomainIndex() failed\n");
+ return (-1);
+ }
+
+ /* If the domain state is inactive, then delete the domain */
+ if ( (ldominfo_list[domidx]->ldomState == LDOM_STATE_INACTIVE) &&
+ (domain->id == -1) )
+ {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainUndefine() Domain state is 'inactive', deleting...\n");
+ rc = send_ldom_lifecycle_action(domain->name, LDOM_DELETE);
+ } else {
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, _("Domain is not inactive"), VIR_ERR_WARNING );
+ return (-1);
+ }
+
+ /* If successful, the domain has been deleted */
+ if (rc == 0) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsDomainUndefine() Domain deleted\n");
+ return (0);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainUndefine(EXIT) Domain undefine failed\n");
+
+ return (-1);
+} /* ldomsDomainUndefine() */
+
+/*
+ * ldomsDomainConsole
+ *
+ * What: Given a Domain pointer, get the console port number
+ * for the domain.
+ *
+ * Input: domain - A pointer to the virDomain structure
+ * Output: function return - <0 is failure, >0 is the domain console port number
+ */
+int
+ldomsDomainConsole(virDomainPtr domain)
+{
+ int rc = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainConsole(ENTER) domName=%s, domID=%d\n",
+ domain->name,domain->id);
+
+ /* get the current ldom data from LDM */
+ (void) pthread_rwlock_wrlock(&update_lock);
+ refresh_ldom_data();
+ (void) pthread_rwlock_unlock(&update_lock);
+
+ /*
+ * If the domain ID is -1, this means the domain state is 'inactive.
+ * If the domain state is inactive (3), then we don't return a port #
+ * Log an error because an inactive domain has no active console port.
+ */
+ if ((domain->id == -1) ||
+ (ldominfo_list[domain->id]->ldomState == LDOM_STATE_INACTIVE)) {
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DEBUG: ldomsDomainConsole(EXIT) Domain state is 'inactive'\n");
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, "Domain is inactive", VIR_ERR_WARNING );
+ return (-1);
+ }
+
+ /*
+ * If the domain is the primary domain, then its console has to be accessed
+ * via the SC and not thru this utility. There is no port number associated
+ * with the primary domain console.
+ */
+ if (strcmp(domain->name, "primary") == 0) {
+ ldomsError(NULL, domain, VIR_ERR_INVALID_OPTION, "Must connect to primary console via the SC", VIR_ERR_WARNING );
+ return (-1);
+ }
+
+ /* Else, the console port # is in the ldominfo_list[] for that domain */
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsDomainConsole(EXIT) console=%d\n",
+ ldominfo_list[domain->id]->ldomConsole);
+ return (ldominfo_list[domain->id]->ldomConsole);
+}
+
+void dprt(const char *template, ...)
+{
+ va_list ap;
+ char buf[10240];
+ static int do_open = 1;
+ static FILE * fp;
+
+ va_start(ap, template);
+ (void) vsprintf(buf, template, ap);
+ va_end(ap);
+
+ if (do_open) {
+ do_open = 0;
+
+ fp = fopen("/var/log/libvirt_ldoms.dbg", "w");
+ }
+ fputs(buf, fp);
+ fflush(fp);
+} /* dprt */
+
+/*
+ * refresh_ldom_data
+ *
+ * Send an XML request to LDM for a list of all Domains
+ * and get the basic information of each Domain.
+ *
+ * This function will be called for each commands to
+ * guarantee that we have the current LDom info for any
+ * virsh CLI command.
+ *
+ * Input:
+ * Output:
+ */
+static void
+refresh_ldom_data()
+{
+ struct timeval tv;
+ long delta;
+
+ /* Try and throttle calling the LDM to update the list of
+ * LDoms. If the calls are 2 secs or less apart, then we just
+ * use the current LDoms info. This is because each
+ * command from virsh can turn into several calls into
+ * function in this file, which all call this function
+ * to refresh the LDom data.
+ */
+ if (gettimeofday(&tv, NULL) >= 0) {
+ /* See if the time since the last call to this functions
+ * is less than 3 seconds. If so, just return.
+ */
+ if ((delta=tv.tv_sec - last_ldom_refresh) < 3) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: refresh_ldom_data(NO Refresh) delta=%d\n",
+ delta);
+ return;
+ }
+ last_ldom_refresh = tv.tv_sec;
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: refresh_ldom_data(Refresh) delta=%d\n",delta);
+
+ /*
+ * Call LDM with a list-domains cmd to get the total
+ * # of Domains and the basic information of each one.
+ */
+
+ if (get_ldom_names(&ldom_cnt, &ldominfo_list) < 0) {
+ /* Any ldominfo_t memory was freed in get_ldom_names() */
+ free(ldominfo_list);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: refresh_ldom_data() get_ldom_names() failed\n");
+ }
+
+} /* refresh_ldom_data() */
+
+/*
+ * getHypervisorVersion()
+ *
+ * Gets the LDoms hypervisor version by parsing the output of
+ * the command 'ldm -V'.
+ *
+ * The output is:
+ * Logical Domain Manager (v 1.0.1)
+ * Hypervisor control protocol v 1.0
+
+ * System PROM:
+ * Hypervisor v. 1.5.1 @(#)Hypervisor 1.5.1 2007/09/14 16:11\015
+ *
+ * OpenBoot v. 4.27.1 @(#)OBP 4.27.1 2007/09/14 15:17
+ *
+ * Output: long representing the value of the hypervisor version in the format
+ * needed by virsh.
+ */
+
+static long
+getHypervisorVersion()
+{
+ FILE *fp = popen("/opt/SUNWldm/bin/ldm -V", "r");
+ char buf[256];
+ char major[8], minor[8], rel[8];
+ char *chp,*chp1;
+ long long hyperVersion;
+ int done = 0;
+ int PROM_line_found = 0;
+ long maj,min,release;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion(ENTER)\n");
+
+ /* check the popen for failure */
+ if (fp == NULL)
+ return(0);
+
+ /* Read the input until we find and process the Hypervisor version */
+ while (! done) {
+ chp = fgets(buf,sizeof(buf),fp);
+ if (chp == NULL)
+ return(0);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getHypervisorVersion() line=%s\n",buf);
+
+ if ( (chp1=strstr(buf,"PROM")) != NULL ) {
+ PROM_line_found = 1;
+ continue;
+ }
+
+ if (((chp1=strstr(buf,"Hypervisor")) != NULL ) && (PROM_line_found)) {
+
+ /*
+ * There are more than 1 lines with 'Hypervisor' in them. Wait until
+ * we find the line with 'System PROM'. The next line with 'Hypervisor'
+ * will be the one we want.
+ */
+
+ /* Step thru to the '.' */
+ while (*chp1 != '.') chp1++;
+ chp1++;
+
+ /* Step to the 1st digit of the version */
+ while ((*chp1 == ' ') || (*chp1 == '\t')) chp1++;
+
+ /* Pointing to 1st digit of version. */
+ if (isdigit(*chp1)) {
+ major[0] = *chp1++;
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion() Major '%c' is not a digit\n",*chp1);
+ return(0);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getHypervisorVersion() major=%c:%d \n",major[0],major[0]);
+
+ /* *chp1 should be a '.' */
+ if (*chp1++ != '.' ) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion() No . after major? ch=%c\n",*(--chp1));
+ return(0);
+ }
+ /* Should be pointing to minor version digit */
+ if (isdigit(*chp1)) {
+ minor[0] = *chp1++;
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion() Minor '%c' is not a digit\n",*chp1);
+ return(0);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getHypervisorVersion() minor=%c:%d \n",minor[0],minor[0]);
+
+ /* If we are not pointing to a '.', then there is no rel */
+ if (*chp1++ != '.' ) {
+ rel[0] = '0';
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion() Not pointing to a '.' before the release digit. ch=%c\n",*(--chp1));
+ } else {
+ if (isdigit(*chp1)) {
+ rel[0] = *chp1++;
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion() Release '%c' is not a digit\n",*chp1);
+ rel[0] = '0';
+ }
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getHypervisorVersion() rel=%c:%d \n",rel[0],rel[0]);
+
+ break; /* out of while */
+ }
+ } /* while */
+
+ /* Now construct the long long that virsh needs to convert to a version number */
+ major[1] = '\0';
+ minor[1] = '\0';
+ rel[1] = '\0';
+
+ maj = atol(major) * 1000000;
+ min = atol(minor) * 1000;
+ release = atol(rel);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getHypervisorVersion(EXIT) maj=%d, min=%d, rel=%d, version=%d\n",
+ maj,min,release,maj+min+release);
+
+ return (maj + min + release);
+
+} /* getHypervisorVersion() */
+
+
+/*
+ * getLDMVersion()
+ *
+ * Gets the LDoms Manager version by parsing the output of
+ * the command 'ldm -V'.
+ *
+ * The output is:
+ * Logical Domain Manager (v 1.0.1)
+ * ..
+ * Output: long representing the value of the LDoms Manager version in the format
+ * needed by virsh.
+ */
+
+static unsigned long
+getLDMVersion()
+{
+ FILE *fp = popen("/opt/SUNWldm/bin/ldm -V", "r");
+ char buf[256];
+ char major[8], minor[8], rel[8];
+ char *chp,*chp1;
+ int done = 0;
+ int LDM_line_found = 0;
+ unsigned long maj,min,release;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion(ENTER)\n");
+
+ /* check the popen for failure */
+ if (fp == NULL)
+ return(0);
+
+ /* Read the input until we find and process the LDoms Manager version */
+ while (! done) {
+ chp = fgets(buf,sizeof(buf),fp);
+ if (chp == NULL)
+ return(0);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getLDMVersion() line=%s\n",buf);
+
+
+ if ( (chp1=strstr(buf,"Logical Domain Manager")) != NULL ) {
+ LDM_line_found = 1;
+ }
+
+ if (LDM_line_found) {
+
+ /* Step thru to the 'v' */
+ while (*chp1 != 'v') chp1++;
+ chp1++;
+
+ /* Step to the 1st digit of the version */
+ while ((*chp1 == ' ') || (*chp1 == '\t')) chp1++;
+
+ /* Pointing to 1st digit of version. */
+ if (isdigit(*chp1)) {
+ major[0] = *chp1++;
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion() Major '%c' is not a digit\n",*chp1);
+ return(0);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getLDMVersion() major=%c:%d \n",major[0],major[0]);
+
+ /* *chp1 should be a '.' */
+ if (*chp1++ != '.' ) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion() No . after major? ch=%c\n",*(--chp1));
+ return(0);
+ }
+ /* Should be pointing to minor version digit */
+ if (isdigit(*chp1)) {
+ minor[0] = *chp1++;
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion() Minor '%c' is not a digit\n",*chp1);
+ return(0);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getLDMVersion() minor=%c:%d \n",minor[0],minor[0]);
+
+ /* If we are not pointing to a '.', then there is no rel */
+ if (*chp1++ != '.' ) {
+ rel[0] = '0';
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion() Not pointing to a '.' before the release digit. ch=%c\n",*(--chp1));
+ } else {
+ if (isdigit(*chp1)) {
+ rel[0] = *chp1++;
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion() Release '%c' is not a digit\n",*chp1);
+ rel[0] = '0';
+ }
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getLDMVersion() rel=%c:%d \n",rel[0],rel[0]);
+
+ break; /* out of while */
+ }
+ } /* while */
+
+ /* Now construct the long long that virsh needs to convert to a version number */
+ major[1] = '\0';
+ minor[1] = '\0';
+ rel[1] = '\0';
+
+ maj = atol(major) * 1000000;
+ min = atol(minor) * 1000;
+ release = atol(rel);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: getLDMVersion(EXIT) maj=%d, min=%d, rel=%d, version=%d\n",
+ maj,min,release,maj+min+release);
+
+ return (maj + min + release);
+
+} /* getLDMVersion() */
+
+/*
+ * getCpuUpTime()
+ *
+ * Gets the CPU uptime by parsing the output of the command 'uptime'.
+ *
+ * Output: long representing the value of the cpu up time in nanosecs
+ */
+long long
+getCpuUpTime()
+{
+ FILE *fp = popen("/bin/uptime", "r");
+ char buf[256];
+ char output[256];
+ char day[5];
+ char hour[5];
+ char min[5];
+ char *chp1,*chp2;
+ int d=0,h=0,m=0;
+ long long uptime;
+ long long duptime;
+ long long huptime;
+ long long muptime;
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getCpuUpTime(ENTER) \n");
+
+ /* check the popen for failure */
+ if (fp == NULL)
+ return(0);
+
+ fgets(buf,sizeof(buf),fp);
+ pclose(fp);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getCpuUpTime() buf=%s \n",buf);
+ /* Find 'up', then advance to the day */
+ /* 6:56am up 6 day(s), 14:46, 10 users, load average: 0.06, 0.14, 0.12 */
+ chp1 = strstr(buf, "up");
+ if (chp1 == NULL)
+ return(0);
+
+ while (*chp1 != ' ') chp1++;
+ chp1++;
+
+ /* Get the day number */
+ /* chp2 is point at the 6 */
+ chp2=chp1;
+ while (*chp2 != ' ') {
+ day[d++] = *chp2;
+ chp2++;
+ }
+ day[d] = '\0';
+ chp2++;
+
+ /* Advance to the 1st digit of the hour */
+ /* chp2 is pointing at the 'd' */
+ while (*chp2 != ' ') chp2++;
+ chp2++;
+
+ /* Get the hour number */
+ /* chp2 is pointing at the '1' */
+ while (*chp2 != ':') { hour[h++] = *chp2; chp2++; }
+ hour[h] = '\0';
+ chp2++;
+
+ /* Get the minute number */
+ /* chp2 is pointing at the '4' after : */
+ while (*chp2 != ',') { min[m++] = *chp2; chp2++; }
+ min[m] = '\0';
+ chp2++;
+
+ strncpy(output, chp1, (chp2 - chp1));
+ output[chp2-chp1] = '\0';
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getCpuUpTime(): Uptime = %s\n",output);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getCpuUpTime(): day=%s, hour=%s, min=%s\n",day,hour,min);
+
+ duptime = atoll(day);
+ duptime = duptime * 60 * 60 * 24;
+ huptime = atoll(hour);
+ huptime = huptime * 60 * 60;
+ muptime = atoll(min);
+ muptime = muptime * 60;
+ uptime = duptime + huptime + muptime;
+ uptime *= 1000000000;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: getCpuUpTime(): Uptime = %lld nanosecs\n",uptime);
+
+ return (uptime);
+
+} /* getCpuUpTime() */
+
+/*
+ * Callback functions for Network actions. These are defined at the end
+ * so we don't have to declare function prototypes at the beginning of
+ * this file.
+ */
+static virNetworkDriver ldomsNtwkDriver = {
+ "LDoms",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Callback functions for Domain actions. These are defined at the end
+ * so we don't have to declare function prototypes at the beginning of
+ * this file.
+ */
+static virDriver ldomsDriver = {
+ VIR_DRV_LDOMS, /* Driver number */
+ "LDoms", /* Name of the driver */
+ LDOMS_VERSION_NUMBER, /* Version of LDoms API */
+ ldomsOpen, /* open */
+ ldomsClose, /* close */
+ NULL, /* virDrvSupportsFeature supports_feature; NOT LDOMS SUPPORTED */
+ ldomsGetType, /* type */
+ ldomsGetVersion, /* getVersion */
+ ldomsGetHostname, /* getHostname */
+ NULL, /* virDrvGetURI getURI; NOT LDOMS SUPPORTED */
+ ldomsGetMaxVcpus, /* virDrvGetMaxVcpus TODO need support */
+ ldomsNodeGetInfo, /* nodeGetInfo */
+ NULL, /* virDrvGetCapabilities getCapabilities; NOT LDOMS SUPPORTED */
+ ldomsListDomains, /* listDomains */
+ ldomsNumOfDomains, /* numOfDomains */
+ ldomsDomainCreateXML, /* domainCreateLinux; Create an inactive domain from XML */
+ ldomsDomainLookupByID, /* domainLookupByID */
+ ldomsDomainLookupByUUID, /* domainLookupByUUID */
+ ldomsDomainLookupByName, /* domainLookupByName */
+ ldomsDomainSuspend, /* virDrvDomainSuspend domainSuspend; TODO NOT LDOMS SUPPORTED */
+ ldomsDomainResume, /* virDrvDomainResume domainResume; TODO NOT LDOMS SUPPORTED */
+ ldomsDomainShutdown, /* domainShutdown */
+ NULL, /* virDrvDomainReboot domainReboot; NOT LDOMS SUPPORTED */
+ ldomsDomainDestroy, /* domainDestroy */
+ ldomsDomainGetOSType, /* domainGetOSType */
+ ldomsDomainGetMaxMemory, /* domainGetMaxMemory */
+ ldomsDomainSetMaxMemory, /* domainSetMaxMemory */
+ ldomsDomainSetMemory, /* domainSetMemory */
+ ldomsDomainGetInfo, /* domainGetInfo */
+ NULL, /* virDrvDomainSave domainSave; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainRestore domainRestore; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainCoreDump domainCoreDump; NOT LDOMS SUPPORTED */
+ ldomsDomainSetVcpus, /* domainSetVcpus */
+ NULL, /* virDrvDomainPinVcpu domainPinVcpu; NOT LDOMS SUPPORTED */
+ ldomsDomainGetVcpus, /* domainGetVcpus */
+ ldomsDomainGetMaxVcpus, /* domainGetMaxVcpus; */
+ ldomsDomainDumpXML, /* domainDumpXML */
+ ldomsListDefinedDomains, /* listDefinedDomains */
+ ldomsNumOfDefinedDomains, /* numOfDefinedDomains */
+ ldomsDomainStart, /* domainCreate - Really start an inactive domain */
+ ldomsDomainDefineXML, /* domainDefineXML */
+ ldomsDomainUndefine, /* domainUndefine */
+ NULL, /* virDrvDomainAttachDevice domainAttachDevice; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainDetachDevice domainDetachDevice; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainGetAutostart domainGetAutostart; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainSetAutostart domainSetAutostart; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainGetSchedulerType domainGetSchedulerType; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainMigratePrepare domainMigratePrepare; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainMigratePerform domainMigratePerform; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainMigrateFinish domainMigrateFinish; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainBlockStats domainBlockStats; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvDomainInterfaceStats domainInterfaceStats; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory; NOT LDOMS SUPPORTED */
+ NULL, /* virDrvNodeGetFreeMemory getFreeMemory; NOT LDOMS SUPPORTED */
+ ldomsDomainConsole, /* ldomConsole */
+};
+
+/*
+ * ldomsRegister:
+ *
+ * Registers LDoms in libvirt driver system. This functions goes at the
+ * end so we don't have to declare ldomsDriver or ldomsNtwkDriver ahead of time.
+ */
+int ldomsRegister(void) {
+
+ /* for debug statements */
+#ifdef LDOMS_DEBUG
+ ldoms_debug = 1;
+ dprt("LDOMS_DEBUG on\n");
+#endif
+#ifdef LDOMS_DETAILED_DEBUG
+ ldoms_detailed_debug = 1;
+ dprt("LDOMS_DETAILED_DEBUG on\n");
+#endif
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsRegister(ENTER)\n");
+
+ /* Only root can execute libvirt LDoms */
+ if (geteuid() != 0) return -1;
+
+ /* initialize for a rw-lock to make the code more multithread-safe */
+ (void) pthread_rwlock_init(&update_lock, NULL);
+
+ /* Get the LDoms Manager version number */
+ LDMVersion = getLDMVersion();
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: ldomsRegister.. LDoms version used = %u\n", LDMVersion);
+
+ return (virRegisterDriver(&ldomsDriver));
+
+
+}
+
+
+#endif /* WITH_LDOMS */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
diff --git a/src/ldoms_intfc.h b/src/ldoms_intfc.h
new file mode 100644
--- /dev/null
+++ b/src/ldoms_intfc.h
@@ -0,0 +1,336 @@
+/*
+ * ldoms_intfc.h: LDoms definitions used for interfaces with the LDoms Manager (LDM)
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifndef __VIR_LDOMS_INTFC_H__
+#define __VIR_LDOMS_INTFC_H__
+
+#ifdef WITH_LDOMS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/byteorder.h>
+#include <inttypes.h>
+#include <libxml/tree.h>
+
+#include "ldoms_xml_parse.h"
+#include "ldoms_common.h"
+
+#define DEFAULT_PORT 5311
+#define LDOM_INTERFACE_VERSION ((xmlChar *)"1.0")
+#define LDOM_DATA_VERSION ((xmlChar *)"2.0")
+#define VERSION_ATTR ((xmlChar *)"version")
+
+#define XML_VERSION ((xmlChar *)"1.0") /* version of XML used */
+
+#define XML_ADD_DOMAIN ((xmlChar *)"add-domain")
+#define XML_DELETE ((xmlChar *)"remove-domain")
+#define XML_STOP ((xmlChar *)"stop-domain")
+#define XML_START_DOMAIN ((xmlChar *)"start-domain")
+#define XML_BIND_DOMAIN ((xmlChar *)"bind-domain")
+#define XML_UNBIND ((xmlChar *)"unbind-domain")
+#define XML_LIST_CONST ((xmlChar *)"list-constraints")
+#define XML_LIST_BIND ((xmlChar *)"list-bindings")
+#define XML_LIST ((xmlChar *)"list-domain")
+#define XML_LIST_DEVICES ((xmlChar *)"list-devices")
+#define XML_LIST_SERVICES ((xmlChar *)"list-services")
+#define XML_LIST_SETS ((xmlChar *)"list-spconfig")
+#define XML_LIST_VARS ((xmlChar *)"list-variable")
+#define XML_ADD_VCPU ((xmlChar *)"add-vcpu")
+#define XML_ADD_MAU ((xmlChar *)"add-mau")
+#define XML_ADD_MEM ((xmlChar *)"add-memory")
+#define XML_ADD_IO ((xmlChar *)"add-io")
+#define XML_ADD_VAR ((xmlChar *)"add-variable")
+#define XML_ADD_VCONSCON ((xmlChar *)"add-vconscon")
+#define XML_ADD_VDISK ((xmlChar *)"add-vdisk")
+#define XML_ADD_VDS ((xmlChar *)"add-vdiskserver")
+#define XML_ADD_VDSDEV ((xmlChar *)"add-vdiskserverdevice")
+#define XML_ADD_VNET ((xmlChar *)"add-vnet")
+#define XML_ADD_VSW ((xmlChar *)"add-vswitch")
+#define XML_ADD_SPCONFIG ((xmlChar *)"add-spconfig")
+#define XML_ADD_VDPCS ((xmlChar *)"add-vdpcs")
+#define XML_ADD_VDPCC ((xmlChar *)"add-vdpcc")
+#define XML_SET_VCPU ((xmlChar *)"set-vcpu")
+#define XML_SET_MAU ((xmlChar *)"set-mau")
+#define XML_SET_MEM ((xmlChar *)"set-memory")
+#define XML_SET_VAR ((xmlChar *)"set-variable")
+#define XML_SET_VCONSCON ((xmlChar *)"set-vconscon")
+#define XML_SET_VNET ((xmlChar *)"set-vnet")
+#define XML_SET_VSW ((xmlChar *)"set-vswitch")
+#define XML_SET_SPCONFIG ((xmlChar *)"set-spconfig")
+#define XML_SET_VCONSOLE ((xmlChar *)"set-vconsole")
+#define XML_REMOVE_VCPU ((xmlChar *)"remove-vcpu")
+#define XML_REMOVE_MAU ((xmlChar *)"remove-mau")
+#define XML_REMOVE_MEM ((xmlChar *)"remove-memory")
+#define XML_REMOVE_IO ((xmlChar *)"remove-io")
+#define XML_REMOVE_VAR ((xmlChar *)"remove-variable")
+#define XML_REMOVE_VCONSCON ((xmlChar *)"remove-vconscon")
+#define XML_REMOVE_VDISK ((xmlChar *)"remove-vdisk")
+#define XML_REMOVE_VDS ((xmlChar *)"remove-vdiskserver")
+#define XML_REMOVE_VDSDEV ((xmlChar *)"remove-vdiskserverdevice")
+#define XML_REMOVE_VNET ((xmlChar *)"remove-vnet")
+#define XML_REMOVE_VSW ((xmlChar *)"remove-vswitch")
+#define XML_REMOVE_SPCONFIG ((xmlChar *)"remove-spconfig")
+#define XML_REMOVE_RECONF ((xmlChar *)"remove-reconf")
+#define XML_REMOVE_VDPCS ((xmlChar *)"remove-vdpcs")
+#define XML_REMOVE_VDPCC ((xmlChar *)"remove-vdpcc")
+
+#define XML_LDM_INTERFACE ((xmlChar *)"LDM_interface")
+#define XML_ACTION ((xmlChar *)"action")
+#define XML_DATA ((xmlChar *)"data")
+#define XML_SNMP_USER ((xmlChar *)"snmp_user")
+#define XML_CMD ((xmlChar *)"cmd")
+#define XML_LDM_INFO ((xmlChar *)"ldom_info")
+#define XML_LDM_NAME ((xmlChar *)"ldom_name")
+#define XML_RESPONSE ((xmlChar *)"response")
+#define XML_STATUS ((xmlChar *)"status")
+#define XML_RESP_MSG ((xmlChar *)"resp_msg")
+#define XML_BINDING ((xmlChar *)"binding")
+#define XML_FREE ((xmlChar *)"free")
+#define XML_PID ((xmlChar *)"pid")
+#define XML_VID ((xmlChar *)"vid")
+#define XML_STRAND_PERCENT ((xmlChar *)"strand_percent")
+#define XML_REAL_ADDR ((xmlChar *)"real_addr")
+#define XML_PHYS_ADDR ((xmlChar *)"phys_addr")
+#define XML_MODE ((xmlChar *)"mode")
+#define XML_CPUSET ((xmlChar *)"cpuset")
+#define XML_DEV_TYPE ((xmlChar *)"device_type")
+#define XML_PORT ((xmlChar *)"port")
+#define XML_SPCONFIG ((xmlChar *)"spconfig")
+#define XML_SPCONFIG_NAME ((xmlChar *)"spconfig_name")
+#define XML_SPCONFIG_STATUS ((xmlChar *)"spconfig_status")
+#define XML_SERVICE_DOMAIN ((xmlChar *)"service_domain")
+#define XML_PHYSIO_DEVICE ((xmlChar *)"physio_device")
+
+#define XML_CURRENT_STATUS ((xmlChar *)"current")
+#define XML_NEXT_STATUS ((xmlChar *)"next")
+
+#define XML_SUCCESS "success"
+#define XML_FAILURE "failure"
+
+/*
+ * XML node and attribute names
+ */
+#define CONSOLE_INSTANCE_NODE ((xmlChar *)"console_instance")
+#define CONSOLE_NODE ((xmlChar *)"console")
+#define CPU_NODE ((xmlChar *)"cpu")
+#define MAU_NODE ((xmlChar *)"mau")
+#define DEV_PATH_NODE ((xmlChar *)"dev_path")
+#define GROUP_NODE ((xmlChar *)"group")
+#define VCONS_PORT_NODE ((xmlChar *)"port")
+#define INSTANCE_NODE ((xmlChar *)"instance")
+#define LDOM_DATABASE_NODE ((xmlChar *)"ldom_database")
+#define LDOM_NAME_NODE ((xmlChar *)"ldom_name")
+#define LDOM_NODE ((xmlChar *)"ldom")
+#define MAC_ADDRESS_NODE ((xmlChar *)"mac_address")
+#define MAX_PORT_NODE ((xmlChar *)"max_port")
+#define MEMORY_NODE ((xmlChar *)"memory")
+#define MIN_PORT_NODE ((xmlChar *)"min_port")
+#define MTU_NODE ((xmlChar *)"mtu")
+#define NAME_NODE ((xmlChar *)"name")
+#define NUMBER_NODE ((xmlChar *)"number")
+#define PHYSIO_MINOR_NODE ((xmlChar *)"minor")
+#define VOLUME_NAME_NODE ((xmlChar *)"vol_name")
+#define VOLUME_OPTS_NODE ((xmlChar *)"vol_opts")
+#define BLOCKDEV_NODE ((xmlChar *)"block_dev")
+#define PHYSIO_NODE ((xmlChar *)"physio")
+#define SERVICE_NAME_NODE ((xmlChar *)"service_name")
+#define SERVER_INSTANCE_NODE ((xmlChar *)"server_instance")
+#define SERVER_NODE ((xmlChar *)"server")
+#define SHARING_NODE ((xmlChar *)"sharing")
+#define SIZE_NODE ((xmlChar *)"size")
+#define STATE_NODE ((xmlChar *)"state")
+#define VALUE_NODE ((xmlChar *)"value")
+#define VARIABLES_NODE ((xmlChar *)"variables")
+#define VAR_NODE ((xmlChar *)"var")
+#define VCC_INSTANCE_NODE ((xmlChar *)"vcc_instance")
+#define VCC_NODE ((xmlChar *)"vcc")
+#define DISK_INSTANCE_NODE ((xmlChar *)"disk_instance")
+#define DISK_NODE ((xmlChar *)"disk")
+#define VDISK_NAME_NODE ((xmlChar *)"vdisk_name")
+#define VDS_VOLUME_NODE ((xmlChar *)"vds_volume")
+#define VDS_VOLUMES_NODE ((xmlChar *)"vds_volumes")
+#define VDS_INSTANCE_NODE ((xmlChar *)"vds_instance")
+#define VDS_NODE ((xmlChar *)"vds")
+#define VNET_INSTANCE_NODE ((xmlChar *)"network_instance")
+#define VNET_NODE ((xmlChar *)"network")
+#define VNET_NAME_NODE ((xmlChar *)"vnet_name")
+#define VSW_INSTANCE_NODE ((xmlChar *)"vsw_instance")
+#define VSW_POLICIES_NODE ((xmlChar *)"policies")
+#define VSW_NODE ((xmlChar *)"vsw")
+#define IO_INSTANCE_NODE ((xmlChar *)"io_instance")
+#define IO_NODE ((xmlChar *)"io")
+#define IO_NAME_NODE ((xmlChar *)"iodevice")
+#define IO_BYPASS_NODE ((xmlChar *)"bypass_mode")
+#define VLDCC_NODE ((xmlChar *)"vldcc")
+#define TIMEOUT_NODE ((xmlChar *)"timeout")
+
+/*
+ * Protocol version supported.
+ */
+#define LDM_MAJOR_VER 1
+#define LDM_MINOR_VER 0
+
+/* per class version numbers */
+#define LDM_CLI_MAJOR_VER 2
+#define LDM_CLI_MINOR_VER 0
+
+#define LDM_CONTROL_MAJOR_VER 1
+#define LDM_CONTROL_MINOR_VER 0
+
+#define LDM_SUNMC_MAJOR_VER 1
+#define LDM_SUNMC_MINOR_VER 0
+
+enum {
+ LDM_INIT_REQ = 0x0,
+ LDM_INIT_ACK = 0x1,
+ LDM_INIT_NACK = 0x2,
+ LDM_ERROR = 0x3,
+ LDM_OP_REQ = 0x4,
+ LDM_OP_REPLY = 0x5
+};
+
+typedef struct {
+ uint32_t msg_type;
+ uint32_t payload_len;
+} ldm_hdr_t;
+
+enum {
+ LDM_CLASS_CLI = 0x1,
+ LDM_CLASS_CONTROL = 0x2,
+ LDM_CLASS_SUNMC = 0x3
+};
+
+typedef struct {
+ uint32_t client_class;
+ uint16_t major_vers;
+ uint16_t minor_vers;
+} ldm_init_req_t;
+
+typedef struct {
+ uint16_t minor_vers;
+} ldm_init_ack_t;
+
+typedef struct {
+ uint16_t major_vers;
+} ldm_init_nack_t;
+
+enum {
+ LDM_ERROR_UNKNOWN = 0x1,
+ LDM_ERROR_UNEXPECTED = 0x2,
+ LDM_ERROR_INVALID = 0x3
+};
+
+typedef struct {
+ uint32_t error_code;
+} ldm_error_t;
+
+typedef struct {
+ uint32_t rq_len;
+ uint32_t rq_id;
+ uint8_t rq_data[];
+} ldm_op_req_t;
+
+typedef struct {
+ uint32_t rp_len;
+ uint32_t rp_reqid;
+ uint8_t rp_data[];
+} ldm_op_reply_t;
+
+/*
+ * 0-3 are used by the ldm_protocol's initialization calls.
+ */
+enum {
+ LDM_CNTRL_PRI_REQ = 0x4,
+ LDM_CNTRL_PRI_REPLY = 0x5,
+ LDM_CNTRL_XML_REQ = 0x6,
+ LDM_CNTRL_XML_RESP = 0x7
+};
+
+/* used by malloc to allocate memory for an entire msg */
+typedef struct ldm_handshake_msg_s {
+ ldm_hdr_t hdr_msg;
+ ldm_init_req_t msg;
+} ldm_handshake_msg;
+
+typedef struct {
+ int len;
+ char data[];
+} xml_msg_t;
+
+#if defined(_BIG_ENDIAN)
+#define hton8(_x) ((uint8_t)(_x))
+#define hton16(_x) ((uint16_t)(_x))
+#define hton32(_x) ((uint32_t)(_x))
+#define hton64(_x) ((uint64_t)(_x))
+#define ntoh8(_x) ((uint8_t)(_x))
+#define ntoh16(_x) ((uint16_t)(_x))
+#define ntoh32(_x) ((uint32_t)(_x))
+#define ntoh64(_x) ((uint64_t)(_x))
+#else
+#define hton8(_x) ((uint8_t)(_x))
+#define hton16(_x) BSWAP_16((uint16_t)(_x))
+#define hton32(_x) BSWAP_32((uint32_t)(_x))
+#define hton64(_x) BSWAP_64((uint64_t)(_x))
+#define ntoh8(_x) ((uint8_t)(_x))
+#define ntoh16(_x) BSWAP_16((uint16_t)(_x))
+#define ntoh32(_x) BSWAP_32((uint32_t)(_x))
+#define ntoh64(_x) BSWAP_64((uint64_t)(_x))
+#endif
+
+xmlDocPtr send_xml_file_to_ldm(xmlDoc *xml_output);
+xmlDocPtr handle_resp(char *resp_buf);
+
+void close_ldm_connection(int sock);
+int get_free_memory(unsigned long *);
+int get_ldom_names(int *, ldominfo_t ***);
+int get_ldom_cpu_bindings(char *, cpuBindings_t **);
+int get_ldom_total_cpu(int *);
+int get_ldom_total_memory(unsigned long *);
+int ldm_create_pkt_buf(char **pkt_buf, char *xml_buf, int xml_buf_len);
+int open_ldm_connection(void);
+int send_ldom_active_mgmt(char *snmp_user, char *ldom_name, int ldom_state);
+char * send_ldom_create_domain(char *, xmlChar *);
+int send_ldom_lifecycle_action(char *, int);
+int send_ldom_set_memory(char *, unsigned long);
+int send_ldom_set_vcpu(char *, int);
+
+int get_all_ldominfo(char *snmp_user, int *all_ldom_cnt, ldominfo_t ***all_ldominfo_list);
+int get_crypto(char *snmp_user, char *ldom_name, int *crypto_cnt, crypto_t ***crypto_list);
+int get_envvars(char *snmp_user, char *ldom_name, int *envvars_cnt, envvars_t ***envvars_list);
+int get_iobus(char *snmp_user, char *ldom_name, int *iobus_cnt, iobus_t ***iobus_list);
+int get_ldominfo(char *ldom_name, int *num_cpu, int *mem_size, int *mem_unit, int *num_crypto, int *num_iobus, int * console, int state);
+int get_response(int sock, char **resp_buf);
+int get_rp(char *snmp_user, int resource, int rp_type, ulong_t *rp_qty, int *unit);
+int get_vcc(char *snmp_user, char *ldom_name, int *vcc_cnt, vcc_t ***vcc_list);
+int get_vcons(char *snmp_user, char *ldom_name, int *vcons_cnt, vcons_t ***vcons_list);
+int get_vconsvccrel(char *snmp_user, char *ldom_name, int *vconsvccrel_cnt, vconsvccrel_t ***vconsvccrel_list);
+int get_vcpu(char *snmp_user, char *ldom_name, int *vcpu_cnt, vcpu_t ***vcpu_list);
+int get_vdisk(char *snmp_user, char *ldom_name, int *vdisk_cnt, vdisk_t ***vdisk_list);
+int get_vds(char *snmp_user, char *ldom_name, int *vds_cnt, vds_t ***vds_list);
+int get_vdsdev(char *snmp_user, char *ldom_name, int *vdsdev_cnt, vdsdev_t ***vdsdev_list);
+int get_vmem(char *snmp_user, char *ldom_name, int *vmem_cnt, vmem_data_t ***vmem_list);
+int get_vmem_physbind(char *snmp_user, char *ldom_name, int *vmem_physbind_cnt, vmem_physbind_t ***vmem_physbind_list);
+int get_vnet(char *snmp_user, char *ldom_name, int *vnet_cnt, vnet_t ***vnet_list);
+int get_vsw(char *snmp_user, char *ldom_name, int *vsw_cnt, vsw_t ***vsw_list);
+
+xmlNodePtr xml_get_next_ele_node(xmlNodePtr node);
+xmlNodePtr xml_find_subnode(xmlNodePtr node, const xmlChar *name);
+int create_pkt_buf(char **pkt_buf, char *xml_buf, int xml_buf_len,
+ int msg_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WITH_LDOMS */
+#endif /* __VIR_LDOMS_INTFC_H__ */
diff --git a/src/ldoms_intfc.c b/src/ldoms_intfc.c
new file mode 100644
--- /dev/null
+++ b/src/ldoms_intfc.c
@@ -0,0 +1,1825 @@
+/*
+ * ldoms_intfc.c: Interface code to the LDoms Manager (LDM)
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifdef WITH_LDOMS
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <libintl.h>
+#include <time.h>
+
+
+#include "libvirt/libvirt.h"
+#include "internal.h"
+#include "ldoms_internal.h"
+#include "ldoms_common.h"
+#include "ldoms_xml_parse.h"
+#include "ldoms_intfc.h"
+#include "xml.h"
+
+
+/* Domain state info
+ * LDom State enumerations
+ * 1 = active LDOM_STATE_ACTIVE
+ * 2 = stopping LDOM_STATE_STOPPING
+ * 3 = inactive LDOM_STATE_INACTIVE
+ * 4 = binding LDOM_STATE_BINDING
+ * 5 = unbinding LDOM_STATE_UNBINDING
+ * 6 = bound LDOM_STATE_BOUND
+ * 7 = starting LDOM_STATE_STARTING
+ *
+ * libvirt LDom State enums
+ * typedef enum {
+ * VIR_DOMAIN_NOSTATE = 0, no state
+ * VIR_DOMAIN_RUNNING = 1, the domain is running
+ * VIR_DOMAIN_BLOCKED = 2, the domain is blocked on resource
+ * VIR_DOMAIN_PAUSED = 3, the domain is paused by user
+ * VIR_DOMAIN_SHUTDOWN= 4, the domain is being shut down
+ * VIR_DOMAIN_SHUTOFF = 5, the domain is shut off
+ * VIR_DOMAIN_CRASHED = 6 the domain is crashed
+ * } virDomainState;
+ */
+
+/* Global vars for debug statement */
+extern int ldoms_debug;
+extern int ldoms_detailed_debug;
+
+/*
+ * open_ldm_connection
+ *
+ * This is the function that opens a client socket connection to the LDOM Manager and
+ * performs the initial handshake protocol with the LDOM Manager.
+ *
+ * Returns:
+ * socket descriptor if the operation is successful
+ * -1 if it fails
+ *
+ * NOTE: This routine was copied from the example code provided by the LDOM Manager developer.
+ * The LDOM Manager handshake protocol is defined in the ldm_protocol.h file
+ * in the LDOM Manager source code. Also see the create_connection() routine in ldm.c
+ * from the LDOM Manager source code.
+ */
+int
+open_ldm_connection(void)
+{
+ struct sockaddr_in myaddr;
+ struct stat statbuf;
+ ldm_hdr_t *hdr, hdr_buf;
+ ldm_init_req_t *init_req;
+ ldm_handshake_msg *buf;
+ int error, sock;
+ uint16_t port;
+
+ int client_class = LDM_CLASS_CONTROL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection(ENTER)\n");
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..can not create socket\n");
+ return (-1);
+ }
+
+ port = DEFAULT_PORT;
+
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ myaddr.sin_port = htons(port);
+ error = connect(sock, (struct sockaddr *)(&myaddr), sizeof (struct sockaddr_in));
+
+ if (error == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..socket connect failed: port=%d\n",port);
+ return (-1);
+ }
+
+ if ((buf = malloc(sizeof(ldm_handshake_msg))) == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..malloc ldm_handshake_msg failed\n");
+ return(-1);
+ }
+
+ /* Header msg is always required to LDM */
+ hdr = (ldm_hdr_t *)buf;
+ hdr->msg_type = hton32(LDM_INIT_REQ);
+ hdr->payload_len = sizeof (ldm_init_req_t);
+
+ /* Specific request to LDM */
+ init_req = &buf->msg;
+ init_req->client_class = hton32(client_class);
+ init_req->major_vers = hton16(LDM_CONTROL_MAJOR_VER);
+ init_req->minor_vers = hton16(LDM_CONTROL_MINOR_VER);
+
+ /* Send the request to the LDM */
+ error = send(sock, buf, sizeof(ldm_handshake_msg), 0);
+ if (error == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..socket send with LDM_INIT_REQ failed\n");
+ return(-1);
+ }
+
+ free(buf);
+
+ /*
+ * Get the header part of the response from the LDM. This
+ * will let us know how big the message part is.
+ */
+ error = recv(sock, &hdr_buf, sizeof (ldm_hdr_t), MSG_WAITALL);
+ if (error == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..socket recv failed\n");
+ return(-1);
+ }
+
+ hdr_buf.msg_type = ntoh32(hdr_buf.msg_type);
+ hdr_buf.payload_len = ntoh32(hdr_buf.payload_len);
+
+ /* See what the LDM responded with for the handshake request */
+ switch (hdr_buf.msg_type) {
+ case LDM_INIT_ACK: {
+ ldm_init_ack_t ack;
+
+ /* Get the rest of the response */
+ error = recv(sock, &ack, sizeof (ack), MSG_WAITALL);
+ if (error == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..LDM_INIT_ACK recv failed\n");
+ return(-1);
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: open_ldm_connection..LDM_INIT_ACK received, Minor sent=%d, Minor rcvd=%d\n",LDM_CONTROL_MINOR_VER,ack.minor_vers);
+ break;
+ }
+
+ case LDM_INIT_NACK: {
+ ldm_init_nack_t nack;
+
+ error = recv(sock, &nack, sizeof (nack), MSG_WAITALL);
+ if (error == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..LDM_INIT_NACK recv failed\n");
+ return(-1);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..LDM_INIT_NACK received, Major Version mismatch. Mjr sent=%d, Mjr rcvd=%d\n",LDM_CONTROL_MAJOR_VER,nack.major_vers);
+ return(-1);
+ }
+
+ case LDM_ERROR: {
+ ldm_error_t err;
+
+ error = recv(sock, &err, sizeof (err), MSG_WAITALL);
+ if (error == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..LDM_ERROR recv failed\n");
+ return(-1);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection..LDM_ERROR: Protocol error=%d\n",err.error_code);
+
+ return(-1);
+ break;
+ }
+
+ default:
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection: Unknown response type=%d\n",hdr_buf.msg_type);
+ return(-1);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: open_ldm_connection(ENTER)\n");
+
+ return (sock);
+}
+
+/*
+ * close_ldm_connection
+ *
+ * This function will close the socket connection to the LDM
+ *
+ * Input:
+ * sock - a socket descriptor to close
+ */
+void
+close_ldm_connection(int sock)
+{
+ if (ldoms_debug) dprt("LDOMS_DEBUG: close_ldm_connection(ENTER)..trying to close LDM socket=%d\n", sock);
+ (void)close(sock);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: close_ldm_connection(EXIT)\n");
+}
+
+
+/*
+ * get_response
+ *
+ * This function receives messages from the LDM socket connection and puts them
+ * into the message buffer.
+ *
+ * Input:
+ * sock - socket descriptor to receive messages
+ *
+ * Output:
+ * resp_buf - pointer to the response buffer that contains the messages
+ * from the socket connection. This memory must be freed by the caller.
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * NOTE: This routine was copied from the example code provided by the LDOM Manager developer.
+ */
+int
+get_response(int sock, char **resp_buf)
+{
+ ldm_hdr_t hdr;
+ char *buf;
+ int status, resp_len, text_len, cc;
+ int i;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_response(ENTER)\n");
+
+ /* Receive the Header of the response */
+ status = recv(sock, &hdr, sizeof (ldm_hdr_t), MSG_WAITALL);
+ if (status <= 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_response..recv failed for rsp header\n");
+ /* error or LDom manager exited */
+ return(-1);
+ }
+
+ hdr.msg_type = ntoh32(hdr.msg_type);
+
+ if (hdr.msg_type != LDM_CNTRL_XML_RESP) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_response..Unexpected response message type=%d\n",hdr.msg_type);
+ return(-1);
+ }
+
+ hdr.payload_len = ntoh32(hdr.payload_len);
+
+ *resp_buf = malloc(hdr.payload_len);
+
+ if (*resp_buf == NULL)
+ return(-1);
+
+ /* receive the actual response body from LDM */
+ status = recv(sock, *resp_buf, hdr.payload_len, MSG_WAITALL);
+ if (status == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_response..recv failed for rsp body\n");
+ free(resp_buf);
+ return(-1);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_response(EXIT)..received %d bytes for rsp body\n", status);
+
+ return (0);
+} /* get_response() */
+
+/*
+ * handle_resp
+ *
+ * This function converts the message buffer (received from the socket connection)
+ * into an xml document.
+ *
+ * Input:
+ * resp_buf - pointer to the message buffer received from the socket connection
+ *
+ * Returns:
+ * xml doc pointer if the operation is successful
+ * NULL if the operation fails
+ *
+ * NOTE: This routine was copied from the example code provided by the LDOM Manager developer.
+ */
+xmlDocPtr
+handle_resp(char *resp_buf)
+{
+ xmlDocPtr xml_output;
+ ldm_op_req_t *req;
+ xml_msg_t *xml_msg;
+ char * dptr;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: handle_resp(ENTER)\n");
+
+ req = (ldm_op_req_t *)resp_buf;
+ xml_msg = (xml_msg_t *)req->rq_data;
+
+
+ xml_output = xmlParseMemory((const char *)req->rq_data, req->rq_len);
+
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: handle_resp.. xml output is NULL\n");
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: handle_resp(EXIT)\n");
+
+ return (xml_output);
+}
+
+/*
+ * send_xml_file_to_ldm
+ *
+ * This function sends an XML request to LDM and then receives the XML
+ * response. It packages the XML response into an XML document so other
+ * code can search through it.
+ *
+ * Input:
+ * doc - xml doc to send to the LDOM Manager
+ *
+ * Returns:
+ * xml doc pointer of the response xml file received from the LDOM Manager
+ * if the operation is successful.
+ * NULL if the operation fails
+ *
+ */
+xmlDocPtr
+send_xml_file_to_ldm(xmlDoc *doc)
+{
+ char *pkt_buf;
+ char *resp_buf;
+ char *xml_buf;
+ int status;
+ int pkt_buf_len;
+ int xml_buf_len;
+ int ret;
+ int sock;
+ xmlDoc *doc_from_ldm;
+
+ /* connect to the ldom manager */
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_xml_file_to_ldm(ENTER)\n");
+ sock = open_ldm_connection();
+
+ if (sock == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_xml_file_to_ldm.. error in opening socket connection\n");
+ return(NULL);
+ }
+
+ (void) xmlDocDumpMemory(doc, (xmlChar **)&xml_buf, &xml_buf_len);
+
+ pkt_buf_len = ldm_create_pkt_buf(&pkt_buf, xml_buf, xml_buf_len);
+
+ status = send(sock, pkt_buf, pkt_buf_len, 0);
+ if (status == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_xml_file_to_ldm.. error in send\n");
+ close_ldm_connection(sock);
+ return(NULL);
+ }
+
+ free(xml_buf);
+ free(pkt_buf);
+
+ if (get_response(sock, &resp_buf) == 0)
+ doc_from_ldm = handle_resp(resp_buf);
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_xml_file_to_ldm.. error in get_response\n");
+ close_ldm_connection(sock);
+ return(NULL);
+ }
+
+ free(resp_buf);
+
+ /* close the socket connection */
+ close_ldm_connection(sock);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_xml_file_to_ldm(EXIT)\n");
+
+ return (doc_from_ldm);
+} /* send_xml_file_to_ldm() */
+
+/*
+ * ldm_create_pkt_buf
+ *
+ * This function creates a ldom operation request message buffer with an XML
+ * character buffer array. This functions sets the appropriate protocol headers
+ * for the protocol handshake with the LDOM Manager.
+ *
+ * Input:
+ * xml_buf - pointer to the xml character buffer
+ * xml_buf_len - length of the xml character buffer
+ *
+ * Output:
+ * pkt_buf - pointer to the message buffer to send to the socket connection
+ *
+ * Returns:
+ * buffer length for the message buffer
+ *
+ * NOTE: This routine was copied from the example code provided by the LDOM Manager developer.
+ * Also see the create_pkt_buf() routine in xml_common.c from the LDOM Manager source code.
+ */
+int
+ldm_create_pkt_buf(char **pkt_buf, char *xml_buf, int xml_buf_len)
+{
+ char *temp_buf;
+ int i;
+ int pkt_buf_len;
+ ldm_hdr_t *hdr;
+ ldm_op_req_t *req;
+ xml_msg_t *xml_msg;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_pkt_buf(ENTER)\n");
+
+ pkt_buf_len = sizeof (ldm_hdr_t) + sizeof (ldm_op_req_t) + xml_buf_len;
+
+ *pkt_buf = malloc(pkt_buf_len);
+
+ /* set LDM protocol headers */
+ hdr = (ldm_hdr_t *)*pkt_buf;
+ hdr->msg_type = hton32(LDM_CNTRL_XML_REQ);
+ hdr->payload_len = hton32(sizeof (ldm_op_req_t) + xml_buf_len);
+
+ req = (ldm_op_req_t *)(*pkt_buf + sizeof (ldm_hdr_t));
+ req->rq_len = hton32(xml_buf_len);
+ req->rq_id = 1;
+
+ memcpy(req->rq_data, xml_buf, xml_buf_len);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_pkt_buf(EXIT)\n");
+
+ return (pkt_buf_len);
+
+} /* ldm_create_pkt_buf() */
+
+
+/*
+ * get_ldominfo
+ *
+ * This function gets the ldom info such as the number of virtial cpu, memory and
+ * its unit, crypto, iobus and console port for the given ldom by invoking routines
+ * to create and send the "list-constraints" and "list-bindings" XML request to the
+ * LDOM Manager and parse the response.
+ *
+ * XML output from the LDOM Manager.
+ *
+ * Input:
+ * ldom_name - name of the ldom to retrieve the ldom info
+ * state - State of the ldom
+ *
+ * Output (pointers are used to pass information from this function to the caller):
+ * num_cpu - pointer to the number of virtual cpu
+ * mem_size - pointer to the virtual memory size
+ * mem_unit - pointer to the virtual memory unit
+ * num_crypto - pointer to the number of crypto unit
+ * num_iobus - pointer to the number of io bus
+ * console - pointer to the console port
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+get_ldominfo(char *ldom_name, int *num_cpu, int *mem_size, int *mem_unit,
+ int *num_crypto, int *num_iobus, int *console, int state)
+{
+ xmlDocPtr xml_output;
+ xmlDocPtr xml_received;
+ xmlChar *action = XML_LIST_CONST;
+ xmlChar *bindAction = XML_LIST_BIND;
+ int ret;
+
+ int num_cpu_from_xml = 0;
+ int mem_size_from_xml = 0;
+ int mem_unit_from_xml = 0;
+ int num_crypto_from_xml = 0;
+ int num_iobus_from_xml = 0;
+ int console_from_xml = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo(ENTER) ldom_name=%s\n", ldom_name);
+
+ *num_cpu = 0;
+ *mem_size = 0;
+ *mem_unit = 0;
+ *num_crypto = 0;
+ *num_iobus = 0;
+ *console = 0;
+
+ /*
+ * The following "list-constraints" XML request will be created and sent to the LDOM Manager
+ * NOTE: list-constraints will not get the Console port. We have to
+ * use list-bindings for that.
+ *
+ * if the input ldom name is 'primary':
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-constraints</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * </ldom>
+ * </data>
+ * </cmd>
+ * </LDM_interface>
+ */
+ xml_output = create_xml_file_4_ldom_action(ldom_name, action);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo.. failed to create xml file for ldom_name=%s action=%s\n",
+ ldom_name, action);
+ return (-1);
+ }
+
+ /* send XML file to the ldom manager */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo.. failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ /*
+ * Example of the xml file received from the LDOM Manager:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-constraints</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <cpu>
+ * <number>4</number>
+ * </cpu>
+ * <mau>
+ * <number>1</number>
+ * </mau>
+ * <memory>
+ * <size>1G</size>
+ * </memory>
+ * .....
+ */
+ /* parse the received XML file to get the ldom info */
+
+ /*
+ * <response><status> will be failure if the ldom is not active or bound.
+ * then, use zero for num of cpu and mem size
+ */
+ ret = parse_xml_get_ldominfo(xml_received, &num_cpu_from_xml, &mem_size_from_xml,
+ &mem_unit_from_xml, &num_crypto_from_xml, &num_iobus_from_xml);
+ if (ret == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo.. failed to parse xml file\n");
+ return (-1);
+ }
+
+ /* Update the return parms */
+ *num_cpu = num_cpu_from_xml;
+ *mem_size = mem_size_from_xml;
+ *mem_unit = mem_unit_from_xml;
+ *num_crypto = num_crypto_from_xml;
+ *num_iobus = num_iobus_from_xml;
+
+ /*
+ * Now we have to get the console port for each LDom. This is done by
+ * sending a 'list-bindings' XML command. So this means we can only
+ * send this request for domains that are bound or active. You cannot
+ * do a list-bindings on an inactive domain. If the domain is inactive,
+ * then the console port is set to 0.
+ *
+ * Example:
+ * If the input ldom name is 'primary', the XML request is:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-bindings</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * </ldom>
+ * </data>
+ * </cmd>
+ * </LDM_interface>
+ */
+
+ /* Domain state is inactive (3), so list-bindings is invalid */
+ if (state == LDOM_STATE_INACTIVE)
+ return (0);
+
+ xml_output = create_xml_file_4_ldom_action(ldom_name, bindAction);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo.. failed to create xml file for ldom_name=%s action=%s\n",
+ ldom_name, action);
+ return (-1);
+ }
+
+ /* send XML file to the ldom manager */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo.. failed to send xml file to ldm and receive xml back for Ldom %s, action %s\n", ldom_name, action);
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ /*
+ * Example of the xml file received from the LDOM Manager:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-constraints</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>ldom-126</ldom_name>
+ * <mac_address>00:14:4f:f9:1a:7d</mac_address>
+ * </ldom_info>
+ * .....
+ * <console>
+ * <service_name>primary-vcc0</service_name>
+ * <port>5005</port>
+ * </console>
+ * .....
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </cmd>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </LDM_interface>
+ */
+
+ /* parse the received XML file to get the ldom info */
+
+ ret = parse_xml_get_console(xml_received, &console_from_xml);
+ if (ret == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo() failed to parse xml file for action %s\n", bindAction);
+ return (-1);
+ }
+ /* Update the return parms */
+ *console = console_from_xml;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldominfo(EXIT)\n");
+
+ return(0);
+}
+
+/*
+* get_ldom_names
+*
+* This function creates a list of all ldoms with the ldom name and state data
+* by invoking routines to create and send the "list-domain" XML request
+* to the LDOM Manager and parse the response XML output from the LDOM Manager.
+*
+* For each LDom returned from the list-domain action, get_ldominfo() is called
+* to get the specific LDom info.
+*
+* Input:
+*
+* Output (pointers are used to pass information from this function to the caller):
+* ldom_cnt - pointer to the number of ldoms in the ldom info list
+* ldominfo_list - pointer to the list of pointers to the ldom info array
+*
+* Returns:
+* 0 if the operation is successful
+* -1 if the operation fails
+*
+* NOTE: The following pictorial description explains the data structure used in
+* this function to pass the ldom count and the list of pointers to the ldom info array.
+* The definition of the data structures is implemented in the ldm_xml_parse.h file.
+* Most get_<data> routines in this file is using the similar data structures
+* to pass the data.
+*
+* +-------------+
+* | num_ldoms | <--- *ldom_cnt = pointer to the integer that has the value of
+* +-------------+ the number of ldoms
+*
+* +-------------+
+* | ldom_list + <--- ***ldominfo_list = pointer to the list of pointers to
+* +-------------+ the ldom info array of type ldominfo_t
+* of which is defined in ldm_xml_parse.h file
+* ldom_list[0]
+* |
+* | type ldominfo_t
+* | +-------------+---------------+------------+
+* |---> | ldom name | ldom state | ...... |
+* +------------------------------------------+
+*
+* ldom_list[1]
+* |
+* | type ldominfo_t
+* | +-------------+---------------+------------+
+* |---> | ldom name | ldom state | ...... |
+* +------------------------------------------+
+*
+*/
+int
+get_ldom_names(int *ldom_cnt, ldominfo_t ***ldominfolist)
+{
+ ldominfo_t **ldom_list = NULL;
+ xmlDocPtr xml_to_send;
+ xmlDocPtr xml_received;
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr name_node = NULL;
+ xmlNodePtr subnode = NULL;
+ xmlChar *ldom_name = NULL;
+ xmlChar *action = XML_LIST;
+
+ int num_ldoms = 0;
+ int i = 0, idx = 0;
+ int nameLen;
+ int ldomCpus, ldomMem, memUnit, ldomCrypto, ldomIO, ldomConsole;
+ char ldomName[NAME_SIZE];
+ char multChr;
+
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names(ENTER) i=%d\n",i);
+
+ /*
+ * This function can be called many times for a single Virt Mgr
+ * operation. In order to not have to devise a grand scheme to
+ * determine when certain LDom info is valid or not, we will
+ * always free the existing structure and then generate new
+ * ones with current data from LDM. This also allows us to
+ * have the latest data from LDM.
+ */
+ if (*ldominfolist != NULL ) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names.. freeing ldominfolist\n");
+ for (i=0; i < *ldom_cnt; i++) {
+ free((*ldominfolist)[i]);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names.. freed *ldominfolist[%d]\n",i);
+ }
+ free(*ldominfolist);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names.. freed *ldominfolist\n");
+ }
+
+ /* Initialize return parameters */
+ *ldom_cnt = 0;
+ *ldominfolist = NULL;
+
+ /*
+ * The following "list-domain" XML request will be created and sent to the LDOM Manager:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-domain</action>
+ * <data version="2.0">
+ * </data>
+ * </cmd>
+ * </LDM_interface>
+ */
+ xml_to_send = create_xml_file_4_ldom_action(NULL, action);
+ if (xml_to_send == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. can not create list xml file\n");
+ return (-1);
+ }
+
+ xml_received = send_xml_file_to_ldm(xml_to_send);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. failed to send xml file to ldm and receive xml response\n");
+ xmlFreeDoc(xml_to_send);
+ return (-1);
+ }
+
+ /*
+ * Example of the xml file received from the LDOM Manager:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-domain</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * <state>active</state>
+ * </ldom_info>
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </cmd>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </LDM_interface>
+ */
+
+ /* Get the total # of LDoms first */
+ if (parse_xml_get_ldom_cnt(xml_received, &num_ldoms) == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. failed to parse xml file for ldom cnt=%s\n", xml_received);
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+ return (-1);
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names.. number of ldoms=%d \n", num_ldoms);
+
+ /* Allocate the memory to hold the info for each LDom */
+ if (num_ldoms > 0)
+ ldom_list = calloc(num_ldoms, sizeof(ldominfo_t *));
+
+ if (ldom_list == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. can't alloc memory for ldom_list\n");
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+ return (-1);
+ }
+
+ /* Make sure mandantory XML tags are present before getting LDom data */
+ root_node = xmlDocGetRootElement(xml_received);
+ if (root_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. XML file does not have root node\n");
+ free(ldom_list);
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+ return (-1);
+ }
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. XML file does not have <cmd> tag\n");
+ free(ldom_list);
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+ return (-1);
+ }
+
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+ if (data_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. XML file does not have <data> tag\n");
+ free(ldom_list);
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+ return (-1);
+ }
+
+ /*
+ * The response XML has data for all LDoms and their state. As we step thru
+ * the response for each LDom, we have to get more detailed info for the LDom,
+ * thus will send other XML requests for this data.
+ */
+ while (1) {
+
+ /* get the ldom node within the <data> tag */
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+
+
+ /* Need a <ldom> tag */
+ if (ldom_node != NULL) {
+ subnode = ldom_node->xmlChildrenNode;
+
+ while (subnode != NULL) {
+ /* Skip tags that are not element tags (tags with no data) */
+ if (subnode->type != XML_ELEMENT_NODE) {
+ subnode = subnode->next;
+ continue;
+ }
+
+ /* Look for <ldom_info> tag */
+ if (xmlStrcmp(subnode->name, (const xmlChar *)XML_LDM_INFO) == 0) {
+ /* Need a <ldom_name> tag */
+ name_node = xml_find_subnode(subnode, XML_LDM_NAME);
+
+ /* We did not find a <ldom_name> tag. No work can be done without this */
+ if (name_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names.. XML file does not have <ldom_name> tag\n");
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+ /* Should free the ldominto_t and ldominfo_list memory also, but this should NEVER happen */
+ return (-1);
+ }
+
+ /* Error checking needed here on ldom_name and ldom_list[idx] */
+ if ((ldom_name = xmlNodeGetContent(name_node)) == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names..xmlNodeGetContent() is NULL\n");
+ subnode = subnode->next;
+ continue;
+ }
+
+ if ((ldom_list[idx] = malloc(sizeof(ldominfo_t))) == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names..malloc() failed for ldom_list[idx]\n");
+ subnode = subnode->next;
+ xmlFree(ldom_name);
+ continue;
+ }
+
+ /* Save the LDom name and state */
+ strlcpy(ldom_list[idx]->ldomName, (char *)ldom_name, sizeof (ldom_list[idx]->ldomName));
+ ldom_list[idx]->ldomState = parse_xml_get_ldom_state(subnode);
+ xmlFree(ldom_name);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names..ldom name:state=%s:%d; ldom_list[%d]=%u\n",
+ ldom_list[idx]->ldomName, ldom_list[idx]->ldomState,idx,ldom_list[idx]);
+
+ /* Now we need to get some specific data about the domain */
+ if (get_ldominfo(ldom_list[idx]->ldomName, &ldomCpus,
+ &ldomMem, &memUnit, &ldomCrypto, &ldomIO,
+ &ldomConsole, ldom_list[idx]->ldomState) >= 0)
+ {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names..get_ldominfo() cpus=%d, mem=%d, unit=%d, mau=%d, io=%d, console=%d\n",
+ ldomCpus, ldomMem, memUnit, ldomCrypto, ldomIO, ldomConsole);
+
+ /* The VMM GUI displays the memory in KB, so we need to convert to KB */
+ switch (memUnit) {
+ case LDOMMEMUNIT_KILOBYTES: break; /* KB already */
+ case LDOMMEMUNIT_MEGABYTES: ldomMem *= 1024; break; /* MB */
+ case LDOMMEMUNIT_GIGABYTES: ldomMem *= (1024 * 1024); break;/* GB */
+ case LDOMMEMUNIT_BYTES: ldomMem /= 1024; break; /* Bytes */
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names..get_ldominfo() mem=%d\n",ldomMem);
+
+ /* Now put the LDom into into the current list */
+ ldom_list[idx]->ldomNumVCpu = ldomCpus;
+ ldom_list[idx]->ldomMemSize = ldomMem;
+ ldom_list[idx]->ldomMemUnit = memUnit;
+ ldom_list[idx]->ldomNumCrypto = ldomCrypto;
+ ldom_list[idx]->ldomNumIOBus = ldomIO;
+ ldom_list[idx]->ldomConsole = ldomConsole;
+
+ /* Create the UUID for this domain/index. We want to keep the
+ * UUID constant, no matter how many domains are addeded or
+ * or deleted, so we will use the integer values for each
+ * char in the domain name in the calculation.
+ */
+ strcpy(ldomName, ldom_list[idx]->ldomName);
+ nameLen = strlen(ldom_list[idx]->ldomName);
+ for (i = 0 ; i < VIR_UUID_BUFLEN ; i++) {
+ if (i < nameLen)
+ multChr = ldomName[i];
+
+ ldom_list[idx]->uuid[i] = ((i+1) * (76 + multChr))%255;
+ }
+ }
+ else {
+ /* Now put the LDom into into the current list */
+ ldom_list[idx]->ldomNumVCpu = 0;;
+ ldom_list[idx]->ldomMemSize = 0;
+ ldom_list[idx]->ldomMemUnit = 4;
+ ldom_list[idx]->ldomNumCrypto = 0;
+ ldom_list[idx]->ldomNumIOBus = 0;
+ ldom_list[idx]->ldomConsole = 0;
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names() get_ldominfo() failed\n");
+ strcpy(ldomName, ldom_list[idx]->ldomName);
+ nameLen = strlen(ldom_list[idx]->ldomName);
+ for (i = 0 ; i < VIR_UUID_BUFLEN ; i++) {
+ if (i < nameLen)
+ multChr = ldomName[i];
+
+ ldom_list[idx]->uuid[i] = ((i+1) * (76 + multChr))%255;
+ }
+ }
+
+ idx++;
+ subnode = subnode->next;
+ continue;
+ }
+ subnode = subnode->next;
+ }
+ }
+
+ /*
+ * xml response for list-domain has <data> tags for each ldom info
+ * so, get the next data section
+ */
+ data_node = xml_get_next_ele_node(data_node);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names..looking for next <data> node\n");
+
+ if (data_node == NULL)
+ break;
+ }
+
+ *ldom_cnt = num_ldoms;
+ *ldominfolist = ldom_list;
+ for (i=0; i<*ldom_cnt; i++)
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names: ldom_list[%d]=%d\n",i,ldom_list[i]);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names: ldominfolist=%u\n",ldominfolist);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names: *ldominfolist=%u\n",*ldominfolist);
+ for (i=0; i<*ldom_cnt; i++)
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_names: (*ldominfolist)[%d]=%u\n",i,(*ldominfolist)[i]);
+
+ xmlFreeDoc(xml_to_send);
+ xmlFreeDoc(xml_received);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_names(EXIT) ldom_cnt=%d\n",*ldom_cnt);
+
+ return (0);
+} /* get_ldom_names() */
+
+/*
+ * send_ldom_set_vcpu
+ *
+ * This function sends an LDom XML xxxxxx request to the LDM to change the
+ * number of virtual cpus for the input domain.
+ *
+ * Input:
+ * ldom_name - name of the ldom to start or stop
+ * nvcpus - The new number of virtual cpus for the domain
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+send_ldom_set_vcpu(char *ldom_name, int nvcpus)
+{
+ xmlDocPtr xml_output;
+ xmlDocPtr xml_received;
+ xmlChar *action;
+ int ret;
+ xmlNodePtr root_node = NULL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_vcpu(ENTER): ldom_name=%s, nvcpus=%d\n", ldom_name, nvcpus);
+
+ /* create XML file to send request to the ldom manager */
+ xml_output = create_xml_file_4_set_vcpu(ldom_name, nvcpus);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_vcpu.. failed to create xml file for set vcpus\n");
+ return (-1);
+ }
+
+ /* send XML file to the LDM */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_vcpu.. failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ /* check the response status */
+ root_node = xmlDocGetRootElement(xml_received);
+ if (root_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_vcpu.. XML file does not have root node\n");
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+ return(-1);
+ }
+
+ if (parse_xml_get_response_status(root_node) == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_vcpu.. failure response from received xml\n");
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+ return(-1);
+ }
+
+ /* cleanup */
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_vcpu(EXIT)\n");
+ return(0);
+}
+
+/*
+ * send_ldom_set_memory
+ *
+ * This function sends an LDom XML set-memory request to the LDM to change the
+ * virtual memory for the input domain. The value of memory is in KB.
+ *
+ * Input:
+ * ldom_name - name of the ldom to change the memory
+ * memory - The new memory for the domain
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+send_ldom_set_memory(char *ldom_name, unsigned long memory)
+{
+ xmlDocPtr xml_output;
+ xmlDocPtr xml_received;
+ xmlChar *action;
+ int ret;
+ xmlNodePtr root_node = NULL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_memory(ENTER): ldom_name=%s, memory=%lu\n", ldom_name, memory);
+
+ /* create XML file to send request to the ldom manager */
+ xml_output = create_xml_file_4_set_memory(ldom_name, memory);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_memory.. failed to create xml file for set memory\n");
+ return (-1);
+ }
+
+ /* send XML file to the LDM */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_memory.. failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ /* check the response status */
+ root_node = xmlDocGetRootElement(xml_received);
+ if (root_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_memory.. XML file does not have root node\n");
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+ return(-1);
+ }
+
+ if (parse_xml_get_response_status(root_node) == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_memory.. failure response from received xml\n");
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+ return(-1);
+ }
+
+ /* cleanup */
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_set_memory(EXIT)\n");
+ return(0);
+}
+
+/*
+ * send_ldom_create_domain
+ *
+ * This function sends an LDom lifecycle action to the LDM to create a
+ * domain. The new domain will be left in either the inactive or bound
+ * state. The domain is created from the definition of an input XML file.
+ * The structure of the XML file is that of 'ldm list-constraints -x <ldom>'
+ *
+ * Input:
+ * xml - A char buffer of the input xml file (This is not an xmlDocPtr yet)
+ * action - The Lifecycle action to perform after domain creation
+ *
+ * Returns:
+ * Ptr to the Domain name if the operation is successful
+ * NULL - if the operation fails
+ *
+ */
+char *
+send_ldom_create_domain(char *xml, xmlChar *action)
+{
+ xmlDocPtr xml_request;
+ xmlDocPtr xml_response;
+ xmlNodePtr root_node = NULL;
+ int ret;
+ char *ldomName;
+ char *filerc;
+ char fname[64];
+ char xmlBuf[256];
+ char tags[64];
+ char *newXml,*modXml;
+ time_t timesecs;
+ FILE *fptr;
+ size_t fwrc;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain(ENTER)\n");
+
+ /*
+ * The input XML char buffer should be the output of list-constrtains -x
+ * It can be modified for the constraints, but will not have the
+ * <cmd> or <action> tags. These tags have to be added to that XML
+ * file before sending it to LDM.
+ *
+ * The input XML char buffer is written to a file, then that file is read
+ * one line at a time so we can determine when to insert the new tags.
+ * The lines read in are accumulated in memory in a char buffer, that
+ * will get converted into an XmlDoc.
+ */
+
+ /* Create a unique file name for the temp file */
+ timesecs = time(NULL);
+ sprintf(fname,"/tmp/xmlfile-%d",timesecs);
+
+ /* Write the XML char buffer to the file */
+ fptr = fopen(fname, "w");
+ if (fptr == NULL) {
+ ldomsError(NULL, NULL, VIR_ERR_OPEN_FAILED, fname, VIR_ERR_ERROR);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain() fopen(%s) for write failed\n", fname);
+ return(NULL);
+ }
+ fwrc = fwrite(xml, strlen(xml), 1, fptr);
+ fclose(fptr);
+
+ /* Read in the XML file and insert the <cmd> and <action> tags */
+ fptr = fopen(fname, "r");
+ if (fptr == NULL) {
+ ldomsError(NULL, NULL, VIR_ERR_READ_FAILED, fname, VIR_ERR_ERROR);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain() fopen(%s) for read failed\n", fname);
+ return(NULL);
+ }
+
+ /* Can't malloc the space for the XML doc + new tags */
+ if (!(modXml = malloc(strlen(xml) + 128))) {
+ ldomsError(NULL, NULL, VIR_ERR_NO_MEMORY, (char*)action, VIR_ERR_ERROR);
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain() malloc failed\n", fname);
+ fclose(fptr);
+ remove(fname);
+ return(NULL);
+ }
+ /* Save the poiner to the beginning of the in memory XML doc */
+ bzero(modXml, strlen(xml) + 128);
+ newXml = modXml;
+
+ /* Get the 1st line of the XML file */
+ filerc = fgets(xmlBuf, sizeof(xmlBuf), fptr);
+
+ /* Read in the XML file, appending to the in memory XML */
+ while (filerc != NULL) {
+ memcpy(modXml, xmlBuf, strlen(xmlBuf));
+ modXml = modXml + strlen(xmlBuf);
+
+ /* The 1st set of tags, <cmd><action>, go after <LDM_interface> */
+ if (strstr(xmlBuf, (char*)XML_LDM_INTERFACE) != NULL) {
+ sprintf(tags, "<%s><%s>%s</%s>",
+ XML_CMD, XML_ACTION, action, XML_ACTION);
+ memcpy(modXml, tags, strlen(tags));
+ modXml = modXml + strlen(tags);
+
+ filerc = fgets(xmlBuf, sizeof(xmlBuf), fptr);
+ /* Go to another while loop to find the end tags */
+ break;
+ }
+ filerc = fgets(xmlBuf, sizeof(xmlBuf), fptr);
+ }
+
+ /* Finish reading and appending until the end tag is found so we can add </cmd> */
+ while (filerc != NULL) {
+ /* </cmd> goes before </LDM_interface> */
+ if (strstr(xmlBuf, (char*)XML_LDM_INTERFACE) != NULL) {
+ sprintf(tags, "</%s>", XML_CMD);
+ memcpy(modXml, tags, strlen(tags));
+ modXml = modXml + strlen(tags);
+ }
+ memcpy(modXml, xmlBuf, strlen(xmlBuf));
+ modXml = modXml + strlen(xmlBuf);
+ filerc = fgets(xmlBuf, sizeof(xmlBuf), fptr);
+ }
+ fclose(fptr);
+ modXml++; *modXml = '\0';
+
+ /* create XML file to send request to the ldom manager */
+ xml_request = xmlReadDoc((const xmlChar *) newXml, NULL, NULL, 0);
+
+ if (xml_request == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain(EXIT) Failed to create xml file \n");
+ remove(fname);
+ return (NULL);
+ }
+
+ /* send XML file to the LDM */
+ xml_response = send_xml_file_to_ldm(xml_request);
+ if (xml_response == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain(EXIT) Failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_request);
+ remove(fname);
+ return (NULL);
+ }
+
+ /* Check the response status to make the the request was successful.
+ * An invalid request can return an XML document.
+ */
+ root_node = xmlDocGetRootElement(xml_response);
+ if (root_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain.. XML file does not have root node\n");
+ xmlFreeDoc(xml_request);
+ xmlFreeDoc(xml_response);
+ remove(fname);
+ return(NULL);
+ }
+
+ if (parse_xml_get_response_status(root_node) == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain(EXIT) Failure response from received xml\n");
+ xmlFreeDoc(xml_request);
+ xmlFreeDoc(xml_response);
+ remove(fname);
+ return(NULL);
+ }
+
+ /* Get the Domain name from the request */
+ ldomName = parse_xml_get_ldom_name(xmlDocGetRootElement(xml_request));
+
+ /* cleanup */
+ xmlFreeDoc(xml_request);
+ xmlFreeDoc(xml_response);
+ remove(fname);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_create_domain(EXIT)\n");
+
+ return(ldomName);
+}
+
+/*
+ * send_ldom_lifecycle_action
+ *
+ * This function sends an LDom lifecycle action to the LDM to change the state
+ * of an LDom. Valid actions are: start-domain, stop-domain, bind-domain,
+ * unbind-domain, destroy-domain.
+ *
+ * Input:
+ * ldom_name - name of the ldom to start or stop
+ * ldom_action - Life cycle action. See ldoms_common.h
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+send_ldom_lifecycle_action(char *ldom_name, int ldom_action)
+{
+ xmlDocPtr xml_output;
+ xmlDocPtr xml_received;
+ xmlChar *action;
+ int ret;
+ xmlNodePtr root_node = NULL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_lifecycle_action(ENTER): ldom_name=%s, action=%d\n", ldom_name, ldom_action);
+
+ if (ldom_action == LDOM_START)
+ action = XML_START_DOMAIN;
+ else if (ldom_action == LDOM_STOP)
+ action = XML_STOP;
+ else if (ldom_action == LDOM_BIND)
+ action = XML_BIND_DOMAIN;
+ else if (ldom_action == LDOM_UNBIND)
+ action = XML_UNBIND;
+ else if (ldom_action == LDOM_DELETE)
+ action = XML_DELETE;
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_lifecycle_action(EXIT): unsupported lifecycle action %d\n",ldom_action);
+ return(-1);
+ }
+
+ /* create XML file to send request to the ldom manager */
+ xml_output = create_xml_file_4_ldom_action(ldom_name, action);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_active_mgmt.. failed to create xml file for ldom_name=%s action=%s\n",
+ ldom_name, action);
+ return (-1);
+ }
+
+ /* send XML file to the LDM */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_active_mgmt.. failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ /* check the response status */
+ root_node = xmlDocGetRootElement(xml_received);
+ if (root_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_active_mgmt.. XML file does not have root node\n");
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+ return(-1);
+ }
+
+ if (parse_xml_get_response_status(root_node) == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_active_mgmt.. failure response from received xml\n");
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+ return(-1);
+ }
+
+ /* cleanup */
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: send_ldom_lifecycle_action(EXIT)\n");
+
+ return(0);
+}
+
+
+/*
+ * get_ldom_rsc_pool
+ *
+ * This function gets the resource pool info such as the CPU and memory
+ * capacity or reserved data by invoking routines to create and send
+ * the "list-devices" (for capacity data) or "list-bindings" (for reserved data)
+ * XML requests to the LDOM Manager and parse the response XML output from the LDOM Manager.
+ *
+ * Input:
+ * resource - indicates which resource to retrieve the resource pool data
+ * CPU_RP=CPU resource pool
+ * MEM_RP = memory resource pool
+ * rp_type - indicates either capacity or reserved
+ * RP_CAPACITY = capacity resource
+ * RP_RESERVED = reserved resource
+ *
+ * Output (pointers are used to pass information from this function to the caller):
+ * rp_qty - pointer to the integer for the resource pool quantity
+ * unit - pointer to the allocation unit for CPU or memory resources
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+get_ldom_rsc_pool(int resource, int rp_type, ulong_t *rp_qty, int *unit)
+{
+ xmlDocPtr xml_output;
+ xmlDocPtr xml_received;
+ xmlChar *action;
+ int ret;
+
+ ulong_t rp_qty_from_xml = 0;
+ int unit_from_xml = 1;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_rsc_pool (ENTER)\n");
+
+ *rp_qty = 0;
+ *unit = 0;
+
+ /* use list-devices for capacity and list-bindings for reserved resources */
+ if (rp_type == RP_CAPACITY)
+ action = XML_LIST_DEVICES;
+ else
+ action = XML_LIST_BIND;
+
+ /* create XML file to send request to the ldom manager */
+ xml_output = create_xml_file_4_ldom_action(NULL, action);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_rsc_pool.. failed to create xml file for action=%s\n",
+ action);
+ return (-1);
+ }
+
+ /* send XML file to the ldom manager */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_rsc_pool.. failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ switch (resource) {
+ case CPU_RP:
+ /* parse the received XML file to get the cpu resource rp_qty info */
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool.. trying to parse for cpu resource\n");
+ if (rp_type == RP_CAPACITY) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool.. trying to parse for capacity value\n");
+ ret = parse_xml_get_cpu_rp(xml_received, rp_type, &rp_qty_from_xml, &unit_from_xml);
+ }
+ else {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool.. trying to parse for reserved value\n");
+ ret = parse_xml_get_cpu_rp(xml_received, rp_type, &rp_qty_from_xml, &unit_from_xml);
+ }
+ break;
+ case MEM_RP:
+ /* parse the received XML file to get the memory resource rp_qty info */
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool.. trying to parse for memory resource\n");
+ if (rp_type == RP_CAPACITY) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool.. trying to parse for capacity value\n");
+ ret = parse_xml_get_mem_rp(xml_received, rp_type, &rp_qty_from_xml, &unit_from_xml);
+ }
+ else {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool.. trying to parse for reserved value\n");
+ ret = parse_xml_get_mem_rp(xml_received, rp_type, &rp_qty_from_xml, &unit_from_xml);
+ }
+ break;
+ default:
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_rsc_pool.. unsupported resource\n");
+ }
+
+ if (ret == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_rsc_pool.. failed to parse xml file\n");
+ return (-1);
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_rsc_pool. rp_qty=%d unit=%d\n", rp_qty_from_xml, unit_from_xml);
+
+ *rp_qty = rp_qty_from_xml;
+ *unit = unit_from_xml;
+
+ /* cleanup */
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_rsc_pool (EXIT)\n");
+
+ return(0);
+} /* get_ldom_rsc_pool */
+
+/*
+ * get_ldom_cpu_bindings
+ *
+ * This function gets the cpu bindings for the input domain.
+ * The CPU binding info is put into the input cpuBinding structure.
+ * The processing of this data is handeled by the calling routine.
+
+ * Input:
+ * domain - The domain name
+ * cpuBindings - Pointer to a structure to place CPU binding info
+ *
+ * Output:
+ * cpuBindings - Updated structure content with CPU binding info
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+get_ldom_cpu_bindings(char *domain, cpuBindings_t **cpuBindings)
+{
+ xmlDocPtr xml_output;
+ xmlDocPtr xml_received;
+ xmlChar *action;
+ int ret;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_cpu_bindings (ENTER)\n");
+
+ action = XML_LIST_BIND;
+
+ /* create XML file to send request to the ldom manager */
+ xml_output = create_xml_file_4_ldom_action(domain, action);
+ if (xml_output == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_cpu_bindings.. failed to create xml file for action=%s\n",action);
+ return (-1);
+ }
+
+ /* send XML file to the ldom manager */
+ xml_received = send_xml_file_to_ldm(xml_output);
+ if (xml_received == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_cpu_bindings.... failed to send xml file to ldm and receive xml back\n");
+ xmlFreeDoc(xml_output);
+ return (-1);
+ }
+
+ ret = parse_xml_get_cpu_bindings(xml_received, cpuBindings);
+
+ if (ret < 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_cpu_bindings...... failed to parse xml file\n");
+ return (ret);
+ }
+
+ /* cleanup */
+ xmlFreeDoc(xml_output);
+ xmlFreeDoc(xml_received);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_cpu_bindings(EXIT)\n");
+
+ return(ret);
+} /* get_ldom_cpu_bindings */
+
+/*
+ * get_free_memory
+ *
+ * This function gets the amount of unused (free) memory in the LDoms system, by
+ * invoking get_ldom_rsc_pool() routine that sends the "list-devices" XML request
+ * to the ldom manager.
+ * The memory amount is converted to KBytes.
+ *
+ * Input:
+ *
+ * Output (pointer is used to pass information from this function to the caller):
+ * maxmem - pointer to the maximum amount of memory allowed (in KB)
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+get_free_memory(unsigned long *maxmem)
+{
+ int ret;
+ ulong_t capacity = 0;
+ int memunit = LDOMMEMUNIT_KILOBYTES;
+
+ unsigned long mem;
+
+ int resource = MEM_RP;
+ int rp_type = RP_CAPACITY;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_free_memory(ENTER) \n");
+
+ *maxmem = 0;
+
+ ret = get_ldom_rsc_pool(resource, rp_type, &capacity, &memunit);
+
+ if (ret == -1)
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_free_memory... get_ldom_rsc_pool failed\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_free_memory.. capacity=%d memunit=%d\n", capacity, memunit);
+
+ /* convert the memory value to KBytes */
+ switch (memunit) {
+ case LDOMMEMUNIT_KILOBYTES: break; /* KB already */
+ case LDOMMEMUNIT_MEGABYTES: capacity *= 1024; break; /* MB */
+ case LDOMMEMUNIT_GIGABYTES: capacity *= (1024 * 1024); break; /* GB */
+ case LDOMMEMUNIT_BYTES: capacity /= 1024; break; /* Bytes */
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_free_memory.. Free memory = %dKB\n", capacity);
+
+ mem = capacity;
+
+ *maxmem = mem;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_free_memory(EXIT).. Maximum Free memory = %dKB\n", mem);
+
+ return(ret);
+
+} /* get_free_memory */
+
+
+/*
+ * get_ldom_total_memory
+ *
+ * This function retrieves the total amount of memory on the system from LDM by
+ * invoking get_ldom_rsc_pool() calls to send the "list-devices" (for free
+ * resource) and "list-bindings" (for bound resource) to the ldom manager
+ * and adds up the free and bound memory amount for all domains.
+ * This function converts the memory to KBytes.
+ *
+ * Input:
+ *
+ * Output (pointer is used to pass information from this function to the caller):
+ * total_mem - pointer to the total amount of memory (in KB)
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+get_ldom_total_memory(unsigned long *total_mem)
+{
+ int ret;
+ ulong_t capacity = 0;
+ ulong_t reserved = 0;
+ int memunit = LDOMMEMUNIT_KILOBYTES;
+
+ unsigned long mem;
+
+ int resource = MEM_RP;
+ int rp_type = RP_CAPACITY;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_memory(ENTER) \n");
+
+ *total_mem = 0;
+
+ /* first, get the amount of free memory by using the RP_CAPACITY type
+ * that sends the list-devices request */
+ ret = get_ldom_rsc_pool(resource, rp_type, &capacity, &memunit);
+
+ if (ret == -1)
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_memory... get_ldom_rsc_pool failed with RP_CAPACITY\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_total_memory.. capacity=%d memunit=%d\n", capacity, memunit);
+
+ /* convert the memory value to KBytes */
+ switch (memunit) {
+ case LDOMMEMUNIT_KILOBYTES: break; /* KB already */
+ case LDOMMEMUNIT_MEGABYTES: capacity *= 1024; break; /* MB */
+ case LDOMMEMUNIT_GIGABYTES: capacity *= (1024 * 1024); break; /* GB */
+ case LDOMMEMUNIT_BYTES: capacity /= 1024; break; /* Bytes */
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_total_memory.. Free memory = %dKB\n", capacity);
+
+ mem = capacity;
+
+ /* Set the global var for the Free memory in KB */
+ ldomsFreeMem = mem;
+
+ /* now, get the amount of bound memory by using the RP_RESERVED type
+ * that send the list-bindings request */
+ rp_type = RP_RESERVED;
+ ret = get_ldom_rsc_pool(resource, rp_type, &reserved, &memunit);
+
+ if (ret == -1)
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_memory... get_ldom_rsc_pool failed with RP_RESERVED\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_total_memory.. reserved=%d memunit=%d\n", reserved, memunit);
+
+ /* convert the memory value to KBytes */
+ switch (memunit) {
+ case LDOMMEMUNIT_KILOBYTES: break; /* KB already */
+ case LDOMMEMUNIT_MEGABYTES: reserved *= 1024; break; /* MB */
+ case LDOMMEMUNIT_GIGABYTES: reserved *= (1024 * 1024); break; /* GB */
+ case LDOMMEMUNIT_BYTES: reserved /= 1024; break; /* Bytes */
+ }
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_total_memory.. Used memory = %dKB\n", reserved);
+
+ /* add up the amount of bound memory to the free memory */
+ mem += reserved;
+
+ /* Set the global var for the Used memory in KB */
+ ldomsUsedMem = reserved;
+
+ *total_mem = mem;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_memory(EXIT): total memory in KB=%d\n", mem);
+
+ return(ret);
+
+} /* get_ldom_total_memory */
+
+
+/*
+ * get_ldom_total_cpu
+ *
+ * This function retrieves the total number of CPUs on the system from LDM by
+ * invoking get_ldom_rsc_pool() calls to send the "list-devices" (for free
+ * resource) and "list-bindings" (for bound resource) to the ldom manager
+ * and adds up the free and bound CPUs for all domains.
+ *
+ * Input:
+ *
+ * Output (pointer is used to pass information from this function to the caller):
+ * total_cpu - pointer to the total number of CPUs
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ */
+int
+get_ldom_total_cpu(int *total_cpu)
+{
+ int ret;
+ ulong_t capacity = 0;
+ ulong_t reserved = 0;
+ int unit = 1;
+
+ int tcpu;
+
+ int resource = CPU_RP;
+ int rp_type = RP_CAPACITY;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_cpu(ENTER) \n");
+
+ *total_cpu = 0;
+
+ /* first, get the number of free CPUs by using the RP_CAPACITY type
+ * that sends the list-devices request */
+ ret = get_ldom_rsc_pool(resource, rp_type, &capacity, &unit);
+
+ if (ret == -1)
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_cpu... get_ldom_rsc_pool failed with RP_CAPACITY\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_total_cpu.. capacity(free CPUs)=%d \n", capacity);
+
+ tcpu = capacity;
+
+ /* Set the global var for the Free CPUs */
+ ldomsFreeCpu = capacity;
+
+ /* now, get the number of bound CPUs by using the RP_RESERVED type
+ * that send the list-bindings request */
+ rp_type = RP_RESERVED;
+ ret = get_ldom_rsc_pool(resource, rp_type, &reserved, &unit);
+
+ if (ret == -1)
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_cpu... get_ldom_rsc_pool failed with RP_RESERVED\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: get_ldom_total_cpu.. reserved(bound CPUs)=%d\n", reserved);
+
+ /* add up the amount of bound memory to the free memory */
+ tcpu += reserved;
+
+ /* Set the global var for the Used CPUs */
+ ldomsUsedCpu = reserved;
+
+ *total_cpu = tcpu;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: get_ldom_total_cpu(EXIT): total_cpu=%d\n", tcpu);
+
+ return(ret);
+
+} /* get_ldom_total_cpu */
+
+#endif /* WITH_LDOMS */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
diff --git a/src/ldoms_xml_parse.h b/src/ldoms_xml_parse.h
new file mode 100644
--- /dev/null
+++ b/src/ldoms_xml_parse.h
@@ -0,0 +1,212 @@
+/*
+ * ldoms_xml_parse.h: data structure to be used in the LDoms XML parsing.
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifndef __VIR_LDOMS_XML_PARSE_H__
+#define __VIR_LDOMS_XML_PARSE_H__
+
+#ifdef WITH_LDOMS
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include "libvirt/libvirt.h"
+#include "ldoms_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* data structures that parsing code will populate */
+typedef struct ldominfo {
+ ulong_t index;
+ char ldomName[NAME_SIZE]; /* ldom name */
+ uint_t ldomState; /* admin state */
+ ulong_t ldomNumVCpu; /* number of VCpu */
+ ulong_t ldomMemSize; /* virtual memory size */
+ uint_t ldomMemUnit; /* unit of memory */
+ ulong_t ldomNumCrypto; /* number of crypto */
+ ulong_t ldomNumIOBus; /* number of IO bus */
+ int ldomConsole; /* console port */
+ unsigned char uuid[VIR_UUID_BUFLEN];
+} ldominfo_t;
+
+typedef struct vcpu_s {
+ ulong_t index;
+ ulong_t vcpuLdomIndex; /* index to ldom table */
+ char vcpuDeviceID[NAME_SIZE]; /* virtual CPU Device ID */
+ uint_t vcpuOperationalStatus; /* vcpu status */
+ char vcpuPhysBind[NAME_SIZE]; /* physical binding */
+ ulong_t vcpuPhysBindUsage; /* physical bind usage */
+} vcpu_t;
+
+typedef struct vmem_data_s {
+ ulong_t index;
+ ulong_t vmemLdomIndex; /* index to ldom table */
+ ulong_t vmemNumberOfBlocks; /* number of vmem blocks */
+} vmem_data_t;
+
+typedef struct vmem_physbind_s {
+ ulong_t index;
+ ulong_t vmemLdomIndex; /* index to ldom table */
+ char vmemPhysBind[NAME_SIZE]; /* memory block binding */
+} vmem_physbind_t;
+
+typedef struct vsw_s {
+ ulong_t index;
+ ulong_t vswLdomIndex; /* index to ldom table */
+ char vswServiceName[NAME_SIZE]; /* vsw service name */
+ char vswMacAddress[NAME_SIZE]; /* vsw mac address */
+ char vswPhysDevPath[NAME_SIZE]; /* vsw physical dev path */
+ uint_t vswMode; /* vsw mode */
+ char vswLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vsw_t;
+
+typedef struct vsw_name_s {
+ char ServiceName[NAME_SIZE]; /* vsw service name */
+} vsw_name_t;
+
+typedef struct vnet_s {
+ ulong_t index;
+ ulong_t vnetLdomIndex; /* index to ldom table */
+ ulong_t vnetVswIndex; /* index to vsw table */
+ char vnetDevName[NAME_SIZE]; /* vnet dev name */
+ char vnetDevMacAddress[NAME_SIZE]; /* vnet dev mac address */
+ char vnetServiceName[NAME_SIZE]; /* vsw service name - used to index to vsw table */
+ char vnetLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vnet_t;
+
+typedef struct vds_s {
+ ulong_t index;
+ ulong_t vdsLdomIndex; /* index to ldom table */
+ char vdsServiceName[NAME_SIZE]; /* vds service name */
+ ulong_t vdsNumofAvailVolume; /* number of available logical volume */
+ ulong_t vdsNumofUsedVolume; /* number of used logical volume */
+ char vdsLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vds_t;
+
+typedef struct vds_name_s {
+ char ServiceName[NAME_SIZE]; /* vds service name */
+} vds_name_t;
+
+typedef struct vdsdev_s {
+ ulong_t index;
+ ulong_t vdsdevVdsIndex; /* index to vds table */
+ char vdsdevVolumeName[NAME_SIZE]; /* volume name */
+ char vdsdevDevPath[NAME_SIZE]; /* block dev */
+ char vdsdevServiceName[NAME_SIZE]; /* vds service name - used to index to vds table */
+} vdsdev_t;
+
+typedef struct vdsdev_name_s {
+ char VolumeName[NAME_SIZE]; /* vdsdev name */
+ char ServiceName[NAME_SIZE]; /* vds name */
+} vdsdev_name_t;
+
+typedef struct vdisk_s {
+ ulong_t index;
+ ulong_t vdiskLdomIndex; /* index to ldom table */
+ ulong_t vdiskVdsdevIndex; /* index to vdsdev table */
+ char vdiskName[NAME_SIZE]; /* vdisk name */
+ char vdiskServiceName[NAME_SIZE]; /* vds name - used to index to vdsdev table */
+ char vdiskVolumeName[NAME_SIZE]; /* vdsdev name - used to index to vdsdev table */
+ char vdiskLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vdisk_t;
+
+typedef struct vcc_s {
+ ulong_t index;
+ ulong_t vccLdomIndex; /* index to ldom table */
+ char vccName[NAME_SIZE]; /* vcc service name */
+ uint_t vccPortRangeLow; /* vcc min port */
+ uint_t vccPortRangeHigh; /* vcc max port */
+ char vccLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vcc_t;
+
+typedef struct vcc_name_s {
+ char ServiceName[NAME_SIZE]; /* vcc name */
+} vcc_name_t;
+
+typedef struct vcons_s {
+ ulong_t index;
+ char vconsGroupName[NAME_SIZE]; /* vcons group name */
+ uint_t vconsPortNumber; /* vcons port */
+ char vconsLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vcons_t;
+
+typedef struct vconsvccrel_s {
+ ulong_t index;
+ uint_t vconsvccrelVconsIndex; /* index to vcons table */
+ uint_t vconsvccrelLdomIndex; /* index to ldom table */
+ uint_t vconsvccrelVccIndex; /* index to vcc table */
+ char vconsvccrelServiceName[NAME_SIZE]; /* vcc service name - used to index to vcc table */
+ char vconsvccrelLdomName[NAME_SIZE]; /* ldom name - used to index to ldom table */
+} vconsvccrel_t;
+
+typedef struct envvars_s {
+ ulong_t index;
+ ulong_t envvarsLdomIndex; /* index to ldom table */
+ char envvarsName[NAME_SIZE]; /* env var name */
+ char envvarsValue[NAME_SIZE]; /* env var value */
+} envvars_t;
+
+typedef struct crypto_s {
+ ulong_t index;
+ ulong_t cryptoLdomIndex; /* index to ldom table */
+ char cryptoCpuSet[NAME_SIZE]; /* crypto cpuset */
+} crypto_t;
+
+typedef struct iobus_s {
+ ulong_t index;
+ ulong_t iobusLdomIndex; /* index to ldom table */
+ char iobusDevName[NAME_SIZE]; /* iobus device name */
+ char iobusDevPath[NAME_SIZE]; /* iobus device path */
+} iobus_t;
+
+xmlDocPtr create_xml_file(char *snmp_user, char *ldom_name, const xmlChar *action);
+xmlDocPtr create_xml_file_4_ldom_action(char *, const xmlChar *);
+xmlDocPtr create_xml_file_4_set_vcpu(char *, int );
+xmlDocPtr create_xml_file_4_set_memory(char *, unsigned long );
+
+int parse_xml_get_response_status(xmlNodePtr node);
+int parse_xml_get_ldom_state(xmlNodePtr node);
+
+int parse_xml_get_ldom_cnt(xmlDoc *doc, int *ldom_cnt);
+int parse_xml_get_ldominfo(xmlDoc *doc, int *num_cpu, int *mem_size, int *mem_unit, int *num_crypto, int *num_iobus);
+char* parse_xml_get_ldom_name(xmlNodePtr node);
+
+int parse_xml_get_subnode_cnt(xmlNodePtr node, xmlChar *subnode);
+int parse_xml_get_vds_volume(xmlNodePtr node, char *service_name);
+int parse_xml_get_vds_volume_bind(xmlDoc *doc, char *service_name);
+char* parse_xml_get_mac_addr(xmlNodePtr node);
+
+int parse_xml_get_cpu_bindings(xmlDocPtr, cpuBindings_t **);
+int parse_xml_get_console(xmlDoc *, int *);
+int parse_xml_get_vcpu(xmlDoc *doc, int *vcpu_cnt, vcpu_t ***vcpu);
+int parse_xml_get_vmem(xmlDoc *doc, int *vmem_cnt, vmem_data_t ***vmem);
+int parse_xml_get_vmem_physbind(xmlDoc *doc, int *vmem_cnt, vmem_physbind_t ***vmem);
+int parse_xml_get_vsw(xmlDoc *doc, int *vsw_cnt, vsw_t ***vsw);
+int parse_xml_get_vnet(xmlDoc *doc, int *vnet_cnt, vnet_t ***vnet);
+int parse_xml_get_vds(xmlDoc *doc, int *vds_cnt, vds_t ***vds);
+int parse_xml_get_vdsdev(xmlDoc *doc, int *vdsdev_cnt, vdsdev_t ***vdsdev);
+int parse_xml_get_vdisk(xmlDoc *doc, int *vdisk_cnt, vdisk_t ***vdisk);
+int parse_xml_get_vcc(xmlDoc *doc, int *vcc_cnt, vcc_t ***vcc);
+int parse_xml_get_vcons(xmlDoc *doc, int *vcons_cnt, vcons_t ***vcons);
+int parse_xml_get_vconsvccrel(xmlDoc *doc, int *vconsvccrel_cnt, vconsvccrel_t ***vconsvccrel);
+int parse_xml_get_envvars(xmlDoc *doc, int *envvars_cnt, envvars_t ***envvars);
+int parse_xml_get_crypto(xmlDoc *doc, int *crypto_cnt, crypto_t ***crypto);
+int parse_xml_get_iobus(xmlDoc *doc, int *iobus_cnt, iobus_t ***iobus);
+
+int parse_xml_get_cpu_rp(xmlDoc *doc, int rp_type, ulong_t *reserved, int *unit);
+int parse_xml_get_mem_rp(xmlDoc *doc, int rp_type, ulong_t *reserved, int *unit);
+int parse_xml_get_crypto_rp(xmlDoc *doc, int rp_type, ulong_t *reserved, int *unit);
+int parse_xml_get_iobus_rp(xmlDoc *doc, int rp_type, ulong_t *reserved, int *unit);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WITH_LDOMS*/
+#endif /* __VIR_LDOMS_XML_PARSE_H__ */
diff --git a/src/ldoms_xml_parse.c b/src/ldoms_xml_parse.c
new file mode 100644
--- /dev/null
+++ b/src/ldoms_xml_parse.c
@@ -0,0 +1,1832 @@
+/*
+ * ldoms_xml_parse.c: LDoms XML parsing routines using the LDoms XML Schema V2
+ * to interface with the LDoms Manager (LDM)
+ *
+ * Copyright 2008 Sun Microsystems, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ */
+
+#ifdef WITH_LDOMS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/processor.h>
+#include <fcntl.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+
+#include "internal.h"
+#include "xml.h"
+#include "ldoms_internal.h"
+#include "ldoms_intfc.h"
+
+/* Domain state info
+ * LDom State enumerations
+ * 1 = active
+ * 2 = stopping
+ * 3 = inactive
+ * 4 = binding
+ * 5 = unbinding
+ * 6 = bound
+ * 7 = starting
+ *
+ * libvirt LDom State enums
+ * typedef enum {
+ * VIR_DOMAIN_NOSTATE = 0, no state
+ * VIR_DOMAIN_RUNNING = 1, the domain is running
+ * VIR_DOMAIN_BLOCKED = 2, the domain is blocked on resource
+ * VIR_DOMAIN_PAUSED = 3, the domain is paused by user
+ * VIR_DOMAIN_SHUTDOWN= 4, the domain is being shut down
+ * VIR_DOMAIN_SHUTOFF = 5, the domain is shut off
+ * VIR_DOMAIN_CRASHED = 6 the domain is crashed
+ * } virDomainState;
+ */
+
+/*
+ * when adding up the memory (capacity/reserved) for the memory resource pool,
+ * the memory unit will be converted to take the smallest unit in use.
+ */
+#define MEM_GB_BYTES (1024*1024*1024) /* 1 GB in bytes */
+#define MEM_MB_BYTES (1024*1024) /* 1 MB in bytes */
+#define MEM_KB_BYTES (1024) /* 1 KB in bytes */
+
+/* Global vars for debug statement */
+extern int ldoms_debug;
+extern int ldoms_detailed_debug;
+
+/*
+ * Returns the next elemental sibling node of the node you pass in. If there
+ * are no more nodes it returns NULL.
+ */
+xmlNodePtr
+xml_get_next_ele_node(xmlNodePtr node)
+{
+ xmlNodePtr sib_node;
+
+ sib_node = node->next;
+
+ while (sib_node != NULL) {
+ if (sib_node->type != XML_ELEMENT_NODE)
+ sib_node = sib_node->next;
+ else
+ break;
+ }
+
+ return (sib_node);
+} /* xml_get_next_ele_node() */
+
+/*
+ * Find and return the first-level subnode (if any) of 'node' which has name
+ * 'name'.
+ */
+xmlNodePtr
+xml_find_subnode(xmlNodePtr node, const xmlChar *name)
+{
+ xmlNodePtr subnode;
+
+ subnode = node->xmlChildrenNode;
+ while (subnode != NULL) {
+ if (xmlStrcmp(subnode->name, name) == 0)
+ break;
+ subnode = subnode->next;
+ }
+
+ return (subnode);
+} /* xml_find_subnode */
+
+
+/*
+ * create_xml_file_4_set_vcpu
+ *
+ * This function creates the XML request file for changing the number
+ * or virtual cpus for an LDom
+ *
+ * Input:
+ * ldom_name - name of the ldom to be included in the XML file with
+ * the <ldom_name> tag.
+ * nvcpus - The new number of vcpus for this LDom
+ *
+ * Returns:
+ * pointer to the created xml doc if the operation is successful
+ * NULL if the operation fails
+ *
+ * Example: The following XML file will be created for LDom ldom1
+ * and a new vcpu value of 4
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>set-vcpu</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>ldom1</ldom_name>
+ * </ldom_info>
+ * <cpu>
+ * <number>4</number>
+ * </cpu>
+ * </ldom>
+ * </data>
+ * </cmd>
+ * </LDM_interface>
+ */
+
+xmlDocPtr
+create_xml_file_4_set_vcpu(char *ldom_name, int nvcpus)
+{
+ xmlDocPtr xml_output;
+ xmlNodePtr root, cmd, data, ldom, info_node, cpu;
+ char vcpu[10]; /* ascii version of input int nvcpus */
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_xml_file_4_set_vcpu(ENTER): ldom=%s, vcpus=%d\n",
+ (ldom_name==NULL? "NULL" : ldom_name), nvcpus);
+
+ xml_output = xmlNewDoc(XML_VERSION);
+
+ /* <LDM_interface> tag with version attribute */
+ root = xmlNewDocNode(xml_output, NULL, XML_LDM_INTERFACE, NULL);
+ xmlDocSetRootElement(xml_output, root);
+ xmlNewProp(root, VERSION_ATTR, LDOM_INTERFACE_VERSION);
+
+ /* <cmd> tag */
+ cmd = xmlNewChild(root, NULL, XML_CMD, NULL);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() cmd tag\n");
+
+ /* <action> tag */
+ xmlNewChild(cmd, NULL, XML_ACTION, XML_SET_VCPU);
+
+ /* <data> tag with version attribute */
+ data = xmlNewChild(cmd, NULL, XML_DATA, NULL);
+ xmlNewProp(data, VERSION_ATTR, LDOM_DATA_VERSION);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() data tag\n");
+
+ /* <ldom> tag */
+ ldom = xmlNewChild(data, NULL, LDOM_NODE, NULL);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() ldom tag\n");
+
+ /* <ldom_info> tag with child <ldom_name> tag */
+ info_node = xmlNewChild(ldom, NULL, XML_LDM_INFO, NULL);
+ xmlNewChild(info_node, NULL, XML_LDM_NAME, (xmlChar *)ldom_name);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() ldom_info tag\n");
+
+ /* <cpu> tag with child <number> tag */
+ cpu = xmlNewChild(ldom, NULL, CPU_NODE, NULL);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() cpu tag\n");
+ sprintf(vcpu, "%d", nvcpus);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() vcpu=%s\n",vcpu);
+ xmlNewChild(cpu, NULL, NUMBER_NODE, (xmlChar *)vcpu);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_vcpu() number tag\n");
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_xml_file_4_set_vcpu(EXIT)\n");
+
+ return(xml_output);
+} /* create_xml_file_4_set_vpcu() */
+
+/*
+ * create_xml_file_4_set_memory
+ *
+ * This function creates the XML request file for changing the memory
+ * for an LDom
+ *
+ * Input:
+ * ldom_name - name of the ldom to be included in the XML file with
+ * the <ldom_name> tag.
+ * memory - The new memory size for this LDom.
+ * The memory size is in Kilobytes.
+ * NOTE: The VMM and virsh displays the memory in KB.
+ *
+ * Returns:
+ * pointer to the created xml doc if the operation is successful
+ * NULL if the operation fails
+ *
+ * Example: The following XML file will be created for LDom ldom1
+ * and a new memory value of 256 Kilobytes.
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>set-memory</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>ldom1</ldom_name>
+ * </ldom_info>
+ * <memory>
+ * <size>256K</size>
+ * </memory>
+ * </ldom>
+ * </data>
+ * </cmd>
+ * </LDM_interface>
+ */
+
+xmlDocPtr
+create_xml_file_4_set_memory(char *ldom_name, unsigned long memory)
+{
+ xmlDocPtr xml_output;
+ xmlNodePtr root, cmd, data, ldom, info_node, mem;
+ char mem_str[10]; /* ascii version of input int memory */
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_xml_file_4_set_memory(ENTER): ldom=%s, memory=%lu\n",
+ (ldom_name==NULL? "NULL" : ldom_name), memory);
+
+ xml_output = xmlNewDoc(XML_VERSION);
+
+ /* <LDM_interface> tag with version sttribute */
+ root = xmlNewDocNode(xml_output, NULL, XML_LDM_INTERFACE, NULL);
+ xmlDocSetRootElement(xml_output, root);
+ xmlNewProp(root, VERSION_ATTR, LDOM_INTERFACE_VERSION);
+
+ /* <cmd> tag */
+ cmd = xmlNewChild(root, NULL, XML_CMD, NULL);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() cmd tag\n");
+
+ /* <action> tag */
+ xmlNewChild(cmd, NULL, XML_ACTION, XML_SET_MEM);
+
+ /* <data> tag with version attribute */
+ data = xmlNewChild(cmd, NULL, XML_DATA, NULL);
+ xmlNewProp(data, VERSION_ATTR, LDOM_DATA_VERSION);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() data tag\n");
+
+ /* <ldom> tag */
+ ldom = xmlNewChild(data, NULL, LDOM_NODE, NULL);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() ldom tag\n");
+
+ /* <ldom_info> tag with child <ldom_name> tag */
+ info_node = xmlNewChild(ldom, NULL, XML_LDM_INFO, NULL);
+ xmlNewChild(info_node, NULL, XML_LDM_NAME, (xmlChar *)ldom_name);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() ldom_info tag\n");
+
+ /* add memory unit K (for Kilobytes) to the memory size string */
+ sprintf(mem_str, "%d", memory);
+ strlcat(mem_str, "K", sizeof (mem_str));
+
+ /* <memory> tag with child <size> tag */
+ mem = xmlNewChild(ldom, NULL, MEMORY_NODE, NULL);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() memory tag\n");
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() memory=%s\n", mem_str);
+ xmlNewChild(mem, NULL, SIZE_NODE, (xmlChar *)mem_str);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: create_xml_file_4_set_memory() size tag\n");
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_xml_file_4_set_memory(EXIT)\n");
+
+ return(xml_output);
+} /* create_xml_file_4_set_memory() */
+
+/*
+ * create_xml_file_4_ldom_action
+ *
+ * This function creates the XML request file for the given ldom and action.
+ *
+ * Input:
+ * ldom_name - name of the ldom to be included in the XML file with
+ * the <ldom_name> tag. if ldom_name is NULL, the XML request for
+ * all ldoms will be created
+ * action - action (such as list-bindings or list-constraints..etc) to be
+ * included in the XML file with the <action> tag
+ *
+ * Returns:
+ * pointer to the created xml doc if the operation is successful
+ * NULL if the operation fails
+ *
+ * Example: The following XML file will be created if the
+ * name of the ldom is 'ldg3', and the action is 'list-bindings'.
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-bindings</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>ldg3</ldom_name>
+ * </ldom_info>
+ * </ldom>
+ * </data>
+ * </cmd>
+ * </LDM_interface>
+ */
+xmlDocPtr
+create_xml_file_4_ldom_action(char *ldom_name, const xmlChar *action)
+{
+ xmlDocPtr xml_output;
+ xmlNodePtr root, cmd, data, ldom, info_node;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_xml_file_4_ldom_action(ENTER): ldom=%s, action=%s\n",
+ (ldom_name==NULL? "NULL" : ldom_name), action);
+
+ xml_output = xmlNewDoc(XML_VERSION);
+ root = xmlNewDocNode(xml_output, NULL, XML_LDM_INTERFACE, NULL);
+ xmlDocSetRootElement(xml_output, root);
+ xmlNewProp(root, VERSION_ATTR, LDOM_INTERFACE_VERSION);
+
+ cmd = xmlNewChild(root, NULL, XML_CMD, NULL);
+
+ xmlNewChild(cmd, NULL, XML_ACTION, action);
+
+ data = xmlNewChild(cmd, NULL, XML_DATA, NULL);
+ xmlNewProp(data, VERSION_ATTR, LDOM_DATA_VERSION);
+
+ /*
+ * If the ldom_name is NULL, the LDM will return info for
+ * all existing LDoms, independent of their state. Otherwise,
+ * we get the info for only the LDom specified.
+ */
+ if (ldom_name != NULL) {
+ ldom = xmlNewChild(data, NULL, LDOM_NODE, NULL);
+ info_node = xmlNewChild(ldom, NULL, XML_LDM_INFO, NULL);
+ xmlNewChild(info_node, NULL, XML_LDM_NAME, (xmlChar *)ldom_name);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: create_xml_file_4_ldom_action(EXIT)\n");
+
+ return(xml_output);
+} /* create_xml_file_4_ldom_action() */
+
+
+/*
+ * parse_xml_get_subnode_cnt
+ *
+ * This function counts the specific subnodes starting from the given xml node.
+ *
+ * Input:
+ * node - pointer to the xml node to start looking for the subnode
+ * subnode_to_find - subnode to look for and count the numbers
+ *
+ * Returns:
+ * number of subnodes if the operation is successful
+ * 0 if no subnode is found
+ */
+int
+parse_xml_get_subnode_cnt(xmlNodePtr node, xmlChar *subnode_to_find)
+{
+ xmlNodePtr subnode;
+ int i = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_subnode_cnt(ENTER)\n");
+
+ subnode = node->xmlChildrenNode;
+ while (subnode != NULL) {
+ if (subnode->type != XML_ELEMENT_NODE) {
+ subnode = subnode->next;
+ continue;
+ }
+
+
+ if (xmlStrcmp(subnode->name, (const xmlChar *)subnode_to_find) == 0) {
+ i++;
+ subnode = subnode->next;
+ continue;
+ }
+
+ subnode = subnode->next;
+ }
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_subnode_cnt(EXIT) cnt=%d\n",i);
+
+
+ return(i);
+}
+
+/*
+ * parse_xml_get_console
+ *
+ * This function gets the console port number for an LDom.
+ *
+ * Input:
+ * xml doc - XML document to read (this will be an XML document for one ldom)
+ *
+ * Output (pointers are used to pass information from this function to the caller):
+ * console - pointer to the console port number
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * NOTE: Example XML document that this function will parse to get the ldom info:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-bindings</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <console>
+ * <service_name>primary-vcc0</service_name>
+ * <port>5004</port>
+ * </console>
+ *...
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </cmd>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </LDM_interface>
+ */
+int
+parse_xml_get_console(xmlDoc *doc, int *console)
+{
+ int ret = 0;
+ int console_xml;
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr console_node = NULL;
+ char *ldm_name = NULL;
+ xmlChar *content = NULL;
+
+ xmlNodePtr subnode;
+
+ uint64_t size = 0;
+
+ *console = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console(ENTER) \n");
+
+ root_node = xmlDocGetRootElement(doc);
+
+ /* Check for an XML failure */
+ if (parse_xml_get_response_status(root_node) == -1)
+ return(-1);
+
+ /* Get the <cmd> tag */
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. XML file does not have <cmd> tag\n");
+ return (-1);
+ }
+
+ /* Get the <data> tag */
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+ if (data_node != NULL)
+ /* Get the <ldom> tag */
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. XML file does not have <data> tag\n");
+ return (-1);
+ }
+
+ if (ldom_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. XML file does not have <ldom> tag\n");
+ return (-1);
+ }
+
+ /* Get the <console> tag */
+ console_node = xml_find_subnode(ldom_node, CONSOLE_NODE);
+ if (console_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. XML file does not have <console> tag\n");
+ console_xml = 0;
+ } else {
+ /* Get the <port> tag */
+ subnode = xml_find_subnode(console_node, XML_PORT);
+ if (subnode == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. XML file does not have <port> tag within <console> tag\n");
+ console_xml = 0;
+ } else {
+ /* Contents of the <port> tag */
+ content = xmlNodeGetContent(subnode);
+
+ console_xml = atoi((const char *)content);
+ if (console_xml <= 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. Invalid <port> num: %s\n", content);
+ }
+ xmlFree(content);
+ }
+ }
+
+ *console = console_xml;
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console(EXIT) console=%d\n", console_xml);
+
+ return (ret);
+}
+
+/*
+ * parse_xml_get_ldominfo
+ *
+ * This function gets the ldom info such as the number of virtial cpu, memory and
+ * its unit, crypto, and iobus by parsing the XML output from the LDOM Manager.
+ *
+ * Input:
+ * xml doc - XML document to read (this will be an XML document for one ldom)
+ *
+ * Output (pointers are used to pass information from this function to the caller):
+ * num_cpu - pointer to the number of virtual cpu
+ * mem_size - pointer to the virtual memory size
+ * mem_unit - pointer to the virtual memory unit
+ * num_crypto - pointer to the number of crypto unit
+ * num_iobus - pointer to the number of io bus
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * NOTE: Example XML document that this function will parse to get the ldom info:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-constraints</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <cpu>
+ * <number>4</number>
+ * </cpu>
+ * <mau>
+ * <number>1</number>
+ * </mau>
+ * <memory>
+ * <size>1G</size>
+ * </memory>
+ * <physio_device>
+ * <name>pci@780</name>
+ * </physio_device>
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </cmd>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </LDM_interface>
+ */
+int
+parse_xml_get_ldominfo(xmlDoc *doc, int *num_cpu, int *mem_size, int *mem_unit, int *num_crypto, int *num_iobus)
+{
+ int ret = 0;
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr cpu_node = NULL;
+ xmlNodePtr memory_node = NULL;
+ xmlNodePtr mau_node = NULL;
+ char *ldm_name = NULL;
+ xmlChar *content = NULL;
+
+ xmlNodePtr subnode;
+
+ long long num_cpu_xml = 0;
+ long long num_crypto_xml = 0;
+ long long num_iobus_xml = 0;
+
+ char *endp;
+ uint64_t size = 0;
+
+ *num_cpu = 0;
+ *mem_size = 0;
+ *num_crypto = 0;
+ *num_iobus = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo(ENTER) \n");
+
+ root_node = xmlDocGetRootElement(doc);
+
+ if (parse_xml_get_response_status(root_node) == -1)
+ return(-1);
+
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <cmd> tag\n");
+ return (-1);
+ }
+
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+ if (data_node != NULL)
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <data> tag\n");
+ return (ret);
+ }
+
+ if (ldom_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <ldom> tag\n");
+ return (ret);
+ }
+
+ /* get number of cpu */
+ cpu_node = xml_find_subnode(ldom_node, CPU_NODE);
+ if (cpu_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <cpu> tag\n");
+ num_cpu_xml = 0;
+ } else {
+ subnode = xml_find_subnode(cpu_node, NUMBER_NODE);
+ if (subnode == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <number> tag within <cpu> tag\n");
+ num_cpu_xml = 0;
+ } else {
+
+ content = xmlNodeGetContent(subnode);
+
+ num_cpu_xml = strtoll((char *)content, NULL, 0);
+ if (num_cpu_xml <= 0) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. Invalid cpu num specified: %s\n", content);
+ }
+ xmlFree(content);
+ }
+ }
+
+
+ /* get memory size */
+ memory_node = xml_find_subnode(ldom_node, MEMORY_NODE);
+ if (memory_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <memory> tag\n");
+ size = 0;
+ } else {
+ subnode = xml_find_subnode(memory_node, SIZE_NODE);
+ if (subnode == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have <size> tag within <memory> tag\n");
+ size = 0;
+ } else {
+
+ content = xmlNodeGetContent(subnode);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldominfo.. mem_size = %s\n", content);
+
+ /* extract the number and unit from the content */
+ size = strtoull((char *)content, &endp, 0);
+ if (size > 0) {
+
+ /* get the memory unit */
+ /* Ldoms Manager CLI is using "bytes" as the default memory unit. */
+ *mem_unit = LDOMMEMUNIT_BYTES; /* use bytes as default */
+ switch (strlen(endp)) {
+ case 0: break;
+ default:
+ switch (endp[strlen(endp)-1]) {
+ case 'G':
+ case 'g':
+ *mem_unit = LDOMMEMUNIT_GIGABYTES;
+ break;
+ case 'M':
+ case 'm':
+ *mem_unit = LDOMMEMUNIT_MEGABYTES;
+ break;
+ case 'K':
+ case 'k':
+ *mem_unit = LDOMMEMUNIT_KILOBYTES;
+ break;
+ default:
+ *mem_unit = LDOMMEMUNIT_BYTES;
+ }
+ break;
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldominfo.. mem size unit = %s\n", endp);
+ } else {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. Invalid mem size specified: %s\n", content);
+ }
+ xmlFree(content);
+ }
+
+ }
+
+ /* get number of crypto */
+ mau_node = xml_find_subnode(ldom_node, MAU_NODE);
+ if (mau_node == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldominfo.. XML file does not have <mau> tag\n");
+ num_crypto_xml = 0;
+ } else {
+ subnode = xml_find_subnode(mau_node, NUMBER_NODE);
+ if (subnode == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldominfo.. XML file does not have <number> tag within <mau> tag\n");
+ num_crypto_xml = 0;
+ } else {
+
+ content = xmlNodeGetContent(subnode);
+ num_crypto_xml = strtoll((char *)content, NULL, 0);
+ if (num_crypto_xml <= 0) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldominfo.. Invalid crypto num specified: %s\n", content);
+ }
+ xmlFree(content);
+ }
+ }
+
+ /* get number of io bus */
+ num_iobus_xml = parse_xml_get_subnode_cnt(ldom_node, XML_PHYSIO_DEVICE);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldominfo.. number of <physio_device> tags =%d\n", num_iobus_xml);
+
+ *num_cpu = (int)num_cpu_xml;
+ *mem_size = (int)size;
+ *num_crypto = (int)num_crypto_xml;
+ *num_iobus = (int)num_iobus_xml;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo(EXIT)\n");
+
+ return (ret);
+}
+
+xmlNodePtr
+xmlFindSubnode(xmlNodePtr node, const xmlChar *name)
+{
+ xmlNodePtr subnode;
+
+ subnode = node->xmlChildrenNode;
+ while (subnode != NULL) {
+ if (xmlStrcmp(subnode->name, name) == 0)
+ break;
+ subnode = subnode->next;
+ }
+
+ return (subnode);
+}
+
+/*
+ * parse_xml_get_ldom_name
+ *
+ * This function find the <ldom_name> tag within the input xml document
+ * and return the LDom name in that tag, or NULL if the tag does not exist.
+ *
+ * Input:
+ * node - An xmlNodePtr to the xml data root node
+ *
+ * Output:
+ * A ptr to the LDom name (caller must free memory when done)
+ * NULL if no <ldom_name> tag or content is found
+ */
+char *
+parse_xml_get_ldom_name(xmlNodePtr node)
+{
+ char *ldomName = NULL;
+ xmlChar *content = NULL;
+ xmlNodePtr subnode;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_name(ENTER) \n");
+ if (ldoms_debug) dprt(" DBG: ENTER: nodeName=%s, nodeType=%d\n",node->name,node->type);
+
+ /* Find the <ldom_name> tag and get its content, which is the LDom name */
+ subnode = xmlFindSubnode(node, XML_CMD);
+ if (subnode != NULL) {
+ subnode = xmlFindSubnode(subnode, XML_DATA);
+ if (subnode != NULL) {
+ subnode = xmlFindSubnode(subnode, LDOM_NODE);
+ if (subnode != NULL) {
+ subnode = xmlFindSubnode(subnode, XML_LDM_INFO);
+ if (subnode != NULL) {
+ subnode = xmlFindSubnode(subnode, XML_LDM_NAME);
+ if (subnode != NULL) {
+ content = xmlNodeGetContent(subnode);
+ ldomName = strdup((const char *)content);
+ }
+ }
+ }
+ }
+ }
+
+
+ if (ldomName == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_name() XML file does not have <ldom_name> tag\n");
+ return(NULL);
+ }
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_name(EXIT) LDom Name = %s\n",ldomName);
+
+ return (ldomName);
+} /* parse_xml_get_ldom_name */
+
+/*
+ * parse_xml_get_ldom_state
+ *
+ * This function converts the ldom state to the enum value.
+ *
+ * Input:
+ * node - pointer to the xml node that contains the ldom state data
+ *
+ * Returns:
+ * following ldom state enum value if the operation is successful
+ * 1 = active LDOM_STATE_ACTIVE
+ * 2 = stopping LDOM_STATE_STOPPING
+ * 3 = inactive LDOM_STATE_INACTIVE
+ * 4 = binding LDOM_STATE_BINDING
+ * 5 = unbinding LDOM_STATE_UNBINDING
+ * 6 = bound LDOM_STATE_BOUND
+ * 7 = starting LDOM_STATE_STARTING
+ *
+ * -1 if the operation fails
+ *
+ */
+int
+parse_xml_get_ldom_state(xmlNodePtr node)
+{
+ xmlNodePtr state_node = NULL;
+ xmlChar *content = NULL;
+ int ldom_state = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_state(ENTER)\n");
+ state_node = xml_find_subnode(node, STATE_NODE);
+ if (state_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_state.. XML file does not have <state> tag\n");
+ return (-1);
+ }
+
+ content = xmlNodeGetContent(state_node);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldom_state.. state=%s\n", content);
+
+ if (strcmp((char *)content, "active") == 0)
+ ldom_state = LDOM_STATE_ACTIVE;
+ else if (strcmp((char *)content, "stopping") == 0)
+ ldom_state = LDOM_STATE_STOPPING;
+ else if (strcmp((char *)content, "inactive") == 0)
+ ldom_state = LDOM_STATE_INACTIVE;
+ else if (strcmp((char *)content, "binding") == 0)
+ ldom_state = LDOM_STATE_BINDING;
+ else if (strcmp((char *)content, "unbinding") == 0)
+ ldom_state = LDOM_STATE_UNBINDING;
+ else if (strcmp((char *)content, "bound") == 0)
+ ldom_state = LDOM_STATE_BOUND;
+ else if (strcmp((char *)content, "starting") == 0)
+ ldom_state = LDOM_STATE_STARTING;
+
+ xmlFree(content);
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_state(EXIT): state=%d\n",ldom_state);
+ return(ldom_state);
+} /* parse_xml_get_ldom_state */
+
+
+/*
+ * parse_xml_get_response_status
+ *
+ * This function checks for the <response> <status> tags in the XML response.
+ * There are <response><status> tags associated with the document, <cmd> and
+ * <data> tags. This function is general to be able to check for
+ * <response><status> for any of these. If the <status> of the document is
+ * 'success', then the other <response><status> tags do not need to be checked.
+ *
+ * Input:
+ * node - pointer to the xml node to check the response status
+ *
+ * Returns:
+ * 0 if the response status is success
+ * -1 if the response status is failure or the operation fails
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>bind-domain</action>
+ * <data version="2.0">
+ * <response>
+ * <status>failure</status>
+ * <resp_msg>ldom does not have ldom_name tag</resp_msg>
+ * </response>
+ * </data>
+ * <response>
+ * <status>failure</status>
+ * </response>
+ * </cmd>
+ * <response>
+ * <status>failure</status>
+ * </response>
+ * </LDM_interface>
+ */
+int
+parse_xml_get_response_status(xmlNodePtr node)
+{
+ xmlNodePtr response_node = NULL;
+ xmlNodePtr status_node = NULL;
+ xmlNodePtr resp_msg_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr cmd_child_node = NULL;
+ xmlNodePtr data_child_node = NULL;
+ xmlNodePtr respmsg_node = NULL;
+ xmlChar *content = NULL;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_response_status(ENTER)\n");
+
+ response_node = xml_find_subnode(node, XML_RESPONSE);
+ if (response_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_response_status.. XML file does not have <response> tag\n");
+ return (-1);
+ }
+
+
+ status_node = xml_find_subnode(response_node, XML_STATUS);
+ if (status_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_response_status.. XML file does not have <status> tag within <response>\n");
+ return (-1);
+ }
+
+ content = xmlNodeGetContent(status_node);
+
+ /*
+ * The <status> tag must indicate 'success', otherwise we cannot process
+ * anymore or the XML response because there has been some type of error.
+ */
+ if (strcmp((char *)content, XML_SUCCESS) == 0) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() <response><status> is success\n");
+ xmlFree(content);
+ }
+
+ /* XML request failed, get the reason why, <resp_msg> */
+ else {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() <response><status>=%s\n", content);
+ xmlFree(content);
+ content = NULL;
+
+ /* response status is not success, get the response msg.
+ * The <resp_msg> tag is within the <data> tag, not the <cmd>
+ * or <LDM_interface> tags, so drill down to the first <data>
+ * tag and get the <response><resp_msg> tag contents to display
+ * in an error message
+ */
+
+ /*
+ * Get the <cmd> node first, then get a list of the child nodes.
+ * There can be multiple <data></data> nodes, which are peers,
+ * but usually there is only 1 <data> node, but code for multiple
+ */
+ cmd_node = xml_find_subnode(node, XML_CMD);
+ cmd_child_node = cmd_node->xmlChildrenNode;
+ while (cmd_child_node != NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() <cmd> child=%s\n",cmd_child_node->name);
+ /* Is current child node a <data> */
+ if (strcmp((const char*)cmd_child_node->name,(const char*)XML_DATA) != 0) {
+ cmd_child_node = cmd_child_node->next;
+ continue;
+ }
+
+ /* Found a <data> node, so get the list of child nodes */
+ data_child_node = cmd_child_node->xmlChildrenNode;
+ while (data_child_node != NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() <data> child=%s\n",data_child_node->name);
+ /* Is current child node a <response> */
+ if (strcmp((const char*)data_child_node->name,(const char*)XML_RESPONSE) != 0) {
+ data_child_node = data_child_node->next;
+ continue;
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() Found <response>\n");
+
+ /* Found a <response> node, so get the <resp_msg> node */
+ respmsg_node = xml_find_subnode(data_child_node, XML_RESP_MSG);
+ if (respmsg_node != NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() Found <resp_msg>\n");
+ content = xmlNodeGetContent(respmsg_node);
+ if (content != NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() <resp_msg>=%s\n", content);
+ cmd_child_node = NULL;
+ }
+ }
+ /* No more <response> nodes in the <data> node */
+ break;
+ }
+ }
+
+ if (content != NULL) {
+ ldomsError(NULL, NULL, VIR_ERR_OPERATION_FAILED, (const char*)content, VIR_ERR_ERROR);
+ xmlFree(content);
+ }
+ return (-1);
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_response_status(EXIT)\n");
+
+ return(0);
+} /* parse_xml_get_response_status */
+
+/*
+ * parse_xml_get_ldom_cnt
+ *
+ * This functions gets the number of ldoms from the input xml file
+ * by counting the <ldom> tags.
+ *
+ * Input:
+ * xml doc - XML document to read
+ *
+ * Output:
+ * ldom_cnt - number of ldoms
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * NOTE:
+ * Each <ldom> tag comes within the <data> tag.
+ *
+ * Example XML output from the LDOM Manager for the "list-domain" request:
+ *
+ * <?xml version="1.0"?>
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-domain</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * <state>active</state>
+ * </ldom_info>
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>ldg1</ldom_name>
+ * <state>bound</state>
+ * </ldom_info>
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>ldg3</ldom_name>
+ * <state>bound</state>
+ * </ldom_info>
+ * </ldom>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </data>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </cmd>
+ * <response>
+ * <status>success</status>
+ * </response>
+ * </LDM_interface>
+ *
+ * for the following LDOM Manager CLI output:
+ *
+ * # ldm list
+ * Name State Flags Cons VCPU Memory Util Uptime
+ * primary active -t-cv 4 1G 0.0% 0s
+ * ldg1 bound ----v 5000 4 1G
+ * ldg3 bound ----v 5001 4 1G
+ */
+int
+parse_xml_get_ldom_cnt(xmlDoc *doc, int *ldom_cnt)
+{
+ char *ldm_name = NULL;
+ int ret = 0;
+ int num_ldoms = 0;
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr response_node = NULL;
+ xmlNodePtr status_node = NULL;
+ xmlNodePtr subnode;
+ xmlChar *content = NULL;
+
+ *ldom_cnt = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_cnt(ENTER)\n");
+
+ root_node = xmlDocGetRootElement(doc);
+
+ if (parse_xml_get_response_status(root_node) == -1)
+ return(-1);
+
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_cnt.. XML file does not have <cmd> tag\n");
+ return (-1);
+ }
+
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+
+ /* We did not find a data section. No work can be done without this */
+ if (data_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_cnt.. XML file does not have <data> tag\n");
+ return (-1);
+ }
+
+ /*
+ * There will be a <data></data> tag pair for each <ldom><ldom_info> pair.
+ * We don't care about the <status> tags with the <data> tags becuase we
+ * already checked the outermost <status>
+ */
+ while (1) {
+
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+
+ if (ldom_node != NULL) {
+ subnode = ldom_node->xmlChildrenNode;
+
+ while (subnode != NULL) {
+ if (subnode->type != XML_ELEMENT_NODE) {
+ subnode = subnode->next;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldom_cnt.. found non-element node under <ldom_info> continue\n");
+ continue;
+ }
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldom_cnt.. found element node %s\n",subnode->name);
+
+ if (xmlStrcmp(subnode->name, (const xmlChar *)XML_LDM_INFO) == 0) {
+ subnode = subnode->next;
+ ++num_ldoms;
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_ldom_cnt.. found <ldom_info> ldom_cnt=%d\n", num_ldoms);
+
+ /* I think we can break at this point instead of continue. View the debug
+ to verify this. */
+ continue;
+ }
+ subnode = subnode->next;
+ }
+ }
+
+
+ /*
+ * xml response for list-domain has <data> tags for each ldom info,
+ * so get the next data section
+ */
+ data_node = xml_get_next_ele_node(data_node);
+
+ if (data_node == NULL)
+ break;
+ }
+
+ *ldom_cnt = num_ldoms;
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldom_cnt(EXIT): ldom_cnt=%d\n", num_ldoms);
+
+ return (ret);
+} /* parse_xml_get_ldom_cnt() */
+
+
+/*
+ * parse_xml_get_mem_rp
+ *
+ * This function gets the memory resource pool data (quantity and unit) by parsing the
+ * XML output from the LDOM Manager.
+ *
+ * Input:
+ * xml doc - XML document to read
+ * "list-devices" xml output for capacity data and
+ * "list-bindings" xml output for reserved data
+ * rp_type - indicates either capacity or reserved
+ * RP_CAPACITY = capacity resource
+ * RP_RESERVED = reserved resource
+ *
+ * Output (pointers are used to pass information from this function to the caller):
+ * rp_qty - pointer to the integer for the resource pool quantity
+ * unit - pointer to the allocation unit
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * NOTE:
+ * This function will tally up the available (with <free> tags in the "list-devices"
+ * xml output) and reserved (with <binding> tags in the "list-bindings" xml output)
+ * for the memory resource pool.
+ *
+ * Example - portion of the XML document that this function will parse to get the
+ * memory resource pool info:
+ *
+ * for capacity resource:
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-devices</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <memory>
+ * <free>
+ * <phys_addr>0xc4800000</phys_addr>
+ * <size>29624M</size>
+ * </free>
+ * </memory>
+ *..
+ * for reserved resource:
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-bindings</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <memory>
+ * <size>1G</size>
+ * <binding>
+ * <real_addr>0x4000000</real_addr>
+ * <phys_addr>0x4000000</phys_addr>
+ * <size>1G</size>
+ * </binding>
+ * </memory>
+ * ...
+ *
+ */
+int
+parse_xml_get_mem_rp(xmlDoc *doc, int rp_type, ulong_t *rp_qty, int *unit)
+{
+ int ret = 0;
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr memory_node = NULL;
+ xmlNodePtr phys_addr_node = NULL;
+ xmlNodePtr size_node = NULL;
+ xmlChar *content = NULL;
+ xmlChar *search_tag;
+
+ xmlNodePtr subnode;
+
+ unsigned long long size = 0;
+ unsigned long long total_size = 0;
+
+ /* use GB as default, but change it to smaller unit if found */
+ int mem_unit = LDOMMEMUNIT_GIGABYTES ;
+ char *endp;
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp (ENTER) \n");
+
+ root_node = xmlDocGetRootElement(doc);
+
+ if (parse_xml_get_response_status(root_node) == -1)
+ return(-1);
+
+ /* for capacity, look for <free> tag and
+ * for reserved, look for <binding> tag */
+ if (rp_type == RP_CAPACITY)
+ search_tag = XML_FREE;
+ else
+ search_tag = XML_BINDING;
+
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_mem_rp.. XML file does not have <cmd> tag\n");
+ return (-1);
+ }
+
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+ if (data_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_mem_rp.. XML file does not have <data> tag\n");
+ return (-1);
+ }
+
+ /* get capacity data from list-devices which does not have <ldom> tag
+ * and get reserved data from list-bindings which has <ldom> tag
+ */
+ if (rp_type == RP_RESERVED) {
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ if (ldom_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_mem_rp.. XML file does not have <ldom> tag\n");
+ return (-1);
+ }
+ }
+
+ while (1) {
+
+ if (rp_type == RP_CAPACITY)
+ memory_node = xml_find_subnode(data_node, MEMORY_NODE);
+ else
+ memory_node = xml_find_subnode(ldom_node, MEMORY_NODE);
+
+ if (memory_node == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. XML file does not have <mem> tag\n");
+ }
+
+ if (memory_node != NULL) {
+ subnode = memory_node->xmlChildrenNode;
+ while (subnode != NULL) {
+ if (subnode->type != XML_ELEMENT_NODE) {
+ subnode = subnode->next;
+ continue;
+ }
+
+ if (xmlStrcmp(subnode->name, search_tag) == 0) {
+
+ if (rp_type == 1)
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. <free>tag found\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. <binding>tag found\n");
+
+
+ /* get phys addr data */
+ phys_addr_node = xml_find_subnode(subnode, XML_PHYS_ADDR);
+ if (phys_addr_node != NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. <phys_addr>tag found\n");
+ content = xmlNodeGetContent(phys_addr_node);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. phys_addr=%s\n", content);
+ xmlFree(content);
+
+ }
+
+ /* get mem size data */
+ size_node = xml_find_subnode(subnode, SIZE_NODE);
+ if (size_node != NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. <size>tag found\n");
+ content = xmlNodeGetContent(size_node);
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. size=%s\n", content);
+
+ /* extract the number and unit from the content */
+ /* and calculate memory size in the smallest unit - "bytes" */
+ size = strtoull((char *)content, &endp, 0);
+ if (size <= 0) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. Invalid mem size specified: %s\n", content);
+ }
+ xmlFree(content);
+
+ /* get the memory unit */
+ /* and calculate the size in "bytes" which is the possible smallest memory unit */
+ switch (strlen(endp)) {
+ case 0: break;
+ default:
+ switch (endp[strlen(endp)-1]) {
+ case 'G':
+ case 'g':
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. unit in GB\n");
+ size = size * MEM_GB_BYTES;
+ break;
+ case 'M':
+ case 'm':
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. unit in MB\n");
+ size = size * MEM_MB_BYTES;
+ /* if megabyates is the smallest unit used so far,
+ * change the mem_unit to "megabyates" */
+ if (mem_unit == LDOMMEMUNIT_GIGABYTES)
+ mem_unit = LDOMMEMUNIT_MEGABYTES;
+ break;
+ case 'K':
+ case 'k':
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. unit in KB\n");
+ size = size * MEM_KB_BYTES;
+ /* if kilobytes is the smallest unit used so far,
+ * change the mem_unit to "kilobytes" */
+ if ((mem_unit == LDOMMEMUNIT_GIGABYTES) ||
+ (mem_unit == LDOMMEMUNIT_MEGABYTES))
+ mem_unit = LDOMMEMUNIT_KILOBYTES;
+ break;
+ default:
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp..unit in bytes\n");
+ /* if no memory unit is specified, use the default unit "bytes",
+ * and set the smallest unit used to "bytes" */
+ mem_unit = LDOMMEMUNIT_BYTES;
+ break;
+ }
+ break;
+ }
+
+ /* add up each strand rp_qty to calculate the total rp_qty */
+ total_size = total_size + size;
+
+ if (ldoms_detailed_debug) dprt(
+ "LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. size=%llu total_size=%llu in bytes\n",
+ size, total_size);
+ }
+
+
+ subnode = subnode->next;
+ continue;
+ }
+
+ subnode = subnode->next;
+ }
+
+ }
+
+ /* xml response for list has <data> tags for each <ldom_info>
+ * so, get the next data section
+ */
+ data_node = xml_get_next_ele_node(data_node);
+
+ if (data_node == NULL)
+ break;
+
+ if (rp_type == RP_RESERVED) {
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ if (ldom_node == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. XML file does not have <ldom> tag\n");
+ break;
+ }
+ }
+
+ }
+
+
+
+ /* recalculate mem size using the selected unit which is smallest unit in use */
+ if (mem_unit == LDOMMEMUNIT_BYTES)
+ *rp_qty = total_size;
+ else if (mem_unit == LDOMMEMUNIT_KILOBYTES)
+ *rp_qty = total_size / MEM_KB_BYTES;
+ else if (mem_unit == LDOMMEMUNIT_MEGABYTES)
+ *rp_qty = total_size / MEM_MB_BYTES;
+ else if (mem_unit == LDOMMEMUNIT_GIGABYTES)
+ *rp_qty = total_size / MEM_GB_BYTES;
+
+ *unit = mem_unit;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_mem_rp(EXIT): size=%llu in unit=%d\n",
+ total_size, mem_unit);
+
+ return(0);
+
+} /* parse_xml_get_mem_rp */
+
+
+/*
+ * parse_xml_get_cpu_rp
+ *
+ * This function gets the total number of CPUs (either free or bound depending on
+ * the rp_type) by parsing the XML output from the LDOM Manager.
+ *
+ * XX - copied from the MIB code, but changed to retrieve the number of
+ * CPUs instead of the CPU resource pool quantity.
+ *
+ * Input:
+ * xml doc - XML document to read
+ * "list-devices" xml output for capacity data and
+ * "list-bindings" xml output for reserved data
+ * rp_type - indicates either capacity or reserved
+ * RP_CAPACITY = capacity resource
+ * RP_RESERVED = reserved resource
+ *
+ * Output (pointers are used to pass information from this function to the caller):
+ * rp_qty - pointer to the integer for the number of CPUs
+ * unit - pointer to the allocation unit (always using 1 for Mhz)
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * NOTE:
+ * This function will tally up the number of free (with <free> tags in the "list-devices"
+ * xml output) and reserved (with <binding> tags in the "list-bindings" xml output) CPUs.
+ *
+ * Example - portion of the XML document that this function will parse to get the
+ * CPU resource pool info:
+ *
+ * for capacity resource:
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-devices</action>
+ * <data version="2.0">
+ * <cpu>
+ * <free>
+ * <pid>12</pid>
+ * <strand_percent>100</strand_percent>
+ * </free>
+ * <free>
+ * <pid>13</pid>
+ * <strand_percent>100</strand_percent>
+ * </free>
+ *..
+ *..
+ * for reserved resource:
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-bindings</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <cpu>
+ * <number>4</number>
+ * <binding>
+ * <vid>0</vid>
+ * <pid>0</pid>
+ * <strand_percent>100</strand_percent>
+ * </binding>
+ * ...
+ *
+ */
+int
+parse_xml_get_cpu_rp(xmlDoc *doc, int rp_type, ulong_t *rp_qty, int *unit)
+{
+ int ret = 0;
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr cpu_node = NULL;
+ xmlNodePtr pid_node = NULL;
+ xmlNodePtr strand_percent_node = NULL;
+ xmlChar *content = NULL;
+ xmlChar *search_tag;
+
+ xmlNodePtr subnode;
+
+ ulong_t strand_rp_qty = 0;
+ ulong_t total_rp_qty = 0;
+
+ int cpu_unit = 1; /* default MHz */
+
+ int ncpu = 0;
+
+ /*
+ * Get the processor clock speed using processor_info()
+ * which takes processor id as input and returns the status of
+ * the processor in the processor_info_t structure.
+ *
+ * The pi_clock member is the processor clock frequency rounded
+ * to the nearest MHz. It may be 0 if not known.
+ *
+ * Since processor_info doesn't provide the guest domain's
+ * processor info, we just need to find a CPU on the control
+ * domain, but we don't know which physical CPUs the control
+ * domain has. So just loop on the 1st 64, which should contain
+ * at least 1 CPU in the control domain.
+ */
+ processor_info_t cpu_info;
+ int pid = 0; /* use primary domain's processor id */
+ int p_clock = 1600; /* processor clock speed in MHz */
+ /* use 1600 MHz as default */
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_rp(ENTER)\n");
+
+
+ /* get the processor clock speed in MHz */
+ while ((pid < 64) && (processor_info(pid++, &cpu_info) != 0) );
+
+ /* get the processor clock speed in MHz */
+ if (pid <= 64) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: ldomsNodeGetInfo(). processor_info with pid=%d clock=%d\n",
+ pid, cpu_info.pi_clock);
+ p_clock = cpu_info.pi_clock;
+ }
+
+ root_node = xmlDocGetRootElement(doc);
+
+ if (parse_xml_get_response_status(root_node) == -1)
+ return(-1);
+
+ /* for capacity, look for <free> tag and
+ * for reserved, look for <binding> tag */
+ if (rp_type == 1)
+ search_tag = XML_FREE;
+ else
+ search_tag = XML_BINDING;
+
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_rp.. XML file does not have <cmd> tag\n");
+ return (-1);
+ }
+
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+ if (data_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_rp.. XML file does not have <data> tag\n");
+ return (-1);
+ }
+
+ /* get capacity data from list-devices which does not have <ldom> tag
+ * and get reserved data from list-bindings which has <ldom> tag
+ */
+ if (rp_type == RP_RESERVED) {
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ if (ldom_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_rp.. XML file does not have <ldom> tag\n");
+ return (-1);
+ }
+ }
+
+ while (1) {
+
+ if (rp_type == RP_CAPACITY)
+ cpu_node = xml_find_subnode(data_node, CPU_NODE);
+ else
+ cpu_node = xml_find_subnode(ldom_node, CPU_NODE);
+
+ if (cpu_node == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_rp.. XML file does not have <cpu> tag\n");
+ }
+
+ if (cpu_node != NULL) {
+
+ subnode = cpu_node->xmlChildrenNode;
+ while (subnode != NULL) {
+ if (subnode->type != XML_ELEMENT_NODE) {
+ subnode = subnode->next;
+ continue;
+ }
+
+
+ if (xmlStrcmp(subnode->name, search_tag) == 0) {
+
+ if (rp_type == RP_CAPACITY)
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_rp.. <free>tag found\n");
+ else
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_rp.. <binding>tag found\n");
+
+ /* add up the number of CPUs */
+ ncpu++;
+
+
+ subnode = subnode->next;
+ continue;
+ }
+
+ subnode = subnode->next;
+ }
+
+ }
+
+
+ /* xml response for list has <data> tags for each <ldom_info>
+ * so, get the next data section
+ */
+ data_node = xml_get_next_ele_node(data_node);
+
+ if (data_node == NULL)
+ break;
+
+ if (rp_type == RP_RESERVED) {
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ if (ldom_node == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_rp.. XML file does not have <ldom> tag\n");
+ break;
+ }
+ }
+
+ }
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_rp(EXIT): total number of CPUs=%d frequency (in Mhz)=%d\n", ncpu, p_clock);
+
+ *rp_qty = ncpu;
+ *unit = cpu_unit;
+
+ return(0);
+} /* parse_xml_get_cpu_rp */
+
+/*
+ * parse_xml_get_cpu_bindings
+ *
+ * This function gets the CPU binding info for a domain.
+ * Specifically, the real and virtual CPU ids, the State for the CPU,
+ * and the CPU uptime, which is pretty much the same as the uptime of
+ * the Domain.
+ *
+ * Input:
+ * xml_received - XML document to read
+ * cpuBindings - Pointer to a structure to hold the binding info
+ *
+ * Output
+ * cpuBindings - Pointer to a structure with the binding info
+ *
+ * Returns:
+ * 0 if the operation is successful
+ * -1 if the operation fails
+ *
+ * Example XML response from a list-bindings request for a domain
+ * <LDM_interface version="1.0">
+ * <cmd>
+ * <action>list-bindings</action>
+ * <data version="2.0">
+ * <ldom>
+ * <ldom_info>
+ * <ldom_name>primary</ldom_name>
+ * </ldom_info>
+ * <cpu>
+ * <number>4</number>
+ * <binding>
+ * <vid>0</vid>
+ * <pid>0</pid>
+ * <strand_percent>100</strand_percent>
+ * </binding>
+ * ...
+ *
+ */
+int
+parse_xml_get_cpu_bindings(xmlDoc *doc, cpuBindings_t **cpuBindings)
+{
+ cpuBindings_t *headcpuBindings = NULL;
+ cpuBindings_t *newBinding = NULL;
+ cpuBindings_t *prevBinding = NULL;
+
+ xmlNodePtr root_node = NULL;
+ xmlNodePtr cmd_node = NULL;
+ xmlNodePtr data_node = NULL;
+ xmlNodePtr ldom_node = NULL;
+ xmlNodePtr cpu_node = NULL;
+ xmlNodePtr id_node = NULL;
+ xmlChar *virtID = NULL;
+ xmlChar *realID = NULL;
+ xmlNodePtr subnode;
+
+ int ret = 0;
+ int numCpus = 0;
+ int ncpu = 0;
+
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_bindings(ENTER)\n");
+ root_node = xmlDocGetRootElement(doc);
+
+ if (parse_xml_get_response_status(root_node) == -1) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_bindings() no response/status tags in the XML rsp\n");
+ return(-1);
+ }
+
+ cmd_node = xml_find_subnode(root_node, XML_CMD);
+ if (cmd_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_bindings() XML file does not have <cmd> tag\n");
+ return (-1);
+ }
+
+ data_node = xml_find_subnode(cmd_node, XML_DATA);
+ if (data_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_bindings() XML file does not have <data> tag\n");
+ return (-1);
+ }
+
+ ldom_node = xml_find_subnode(data_node, LDOM_NODE);
+ if (ldom_node == NULL) {
+ if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_cpu_bindings() XML file does not have <ldom> tag\n");
+ return (-1);
+ }
+
+ cpu_node = xml_find_subnode(ldom_node, CPU_NODE);
+
+ if (cpu_node == NULL) {
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_bindings() XML file does not have <cpu> tag\n");
+ return(-1);
+ }
+
+ subnode = cpu_node->xmlChildrenNode;
+ while (subnode != NULL) {
+
+ if (xmlStrcmp(subnode->name, XML_BINDING) == 0) {
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_bindings() <binding>tag found\n");
+
+
+ /* Allocate a new cpuBindings struct to hold the info for the binding.
+ * This is regular single linked list stuff.
+ */
+ if (headcpuBindings == NULL) {
+ newBinding = malloc(sizeof(cpuBindings_t));
+ headcpuBindings = newBinding;
+ prevBinding = newBinding;
+ newBinding->next = NULL;
+ }
+ else {
+ newBinding = malloc(sizeof(cpuBindings_t));
+ prevBinding->next = newBinding;
+ newBinding->next = NULL;
+ prevBinding = newBinding;
+ }
+
+ /* Get the <vid> node and its value. subnode points to <binding> */
+ id_node = subnode->xmlChildrenNode;
+ virtID = xmlNodeGetContent(id_node);
+ newBinding->virt = (unsigned int)atoi((const char *)virtID);
+ xmlFree(virtID);
+
+ /* Get the <pid> node and its value */
+ id_node = id_node->next;
+ realID = xmlNodeGetContent(id_node);
+ newBinding->real = (int)atoi((const char *)realID);
+ xmlFree(realID);
+
+ if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_bindings() virt/real = %d/%d \n",newBinding->virt, newBinding->real);
+
+ numCpus++;
+
+ }
+
+ subnode = subnode->next;
+ } /* while */
+
+ *cpuBindings = headcpuBindings;
+ return(numCpus);
+} /* parse_xml_get_cpu_bindings */
+
+
+#endif /* WITH_LDOMS */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
16 years, 7 months
[Libvir] [PATCH] Implement SetVcpus and DomainGetMaxVcpus for qemu
by Cole Robinson
The attached patch fills in two of the vcpu functions for the qemu driver:
virDomainSetVcpus : set the number of vcpus the domain can use
virDomainGetMaxVcpus : max number of vcpus that can be assigned to the domain.
Code change is only in qemu_driver, as the backend stuff was already in place.
I also edited qemudGetMaxVcpus to ignore case when checking the passed OS
type, since it wasn't matching the returned results of qemudDomainGetOSType.
Thanks,
Cole
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index b65ae66..8bedf5a 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -113,6 +113,8 @@ static int qemudShutdownNetworkDaemon(virConnectPtr conn,
struct qemud_driver *driver,
struct qemud_network *network);
+static int qemudDomainGetMaxVcpus(virDomainPtr dom);
+
static struct qemud_driver *qemu_driver = NULL;
@@ -1524,21 +1526,23 @@ static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
return "QEMU";
}
-static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *type) {
+static int qemudGetMaxVCPUs(virConnectPtr conn, const char *type) {
if (!type)
return 16;
- if (!strcmp(type, "qemu"))
+ if (!strcasecmp(type, "qemu"))
return 16;
/* XXX future KVM will support SMP. Need to probe
kernel to figure out KVM module version i guess */
- if (!strcmp(type, "kvm"))
+ if (!strcasecmp(type, "kvm"))
return 1;
- if (!strcmp(type, "kqemu"))
+ if (!strcasecmp(type, "kqemu"))
return 1;
+
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+ _("unknown type '%s'"), type);
return -1;
}
@@ -2122,6 +2126,66 @@ static int qemudDomainSave(virDomainPtr dom,
}
+static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
+ struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+ struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
+ int max;
+
+ if (!vm) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+ _("no domain with matching uuid '%s'"), dom->uuid);
+ return -1;
+ }
+
+ if (qemudIsActiveVM(vm)) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot change vcpu count of an active domain"));
+ return -1;
+ }
+
+ if ((max = qemudDomainGetMaxVcpus(dom)) < 0) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("could not determine max vcpus for the domain"));
+ return -1;
+ }
+
+ if (nvcpus > max) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
+ _("requested vcpus is greater than max allowable"
+ " vcpus for the domain: %d > %d"), nvcpus, max);
+ return -1;
+ }
+
+ vm->def->vcpus = nvcpus;
+ return 0;
+}
+
+static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
+ struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+ struct qemud_vm *vm = qemudFindVMByUUID(driver, dom->uuid);
+ char *type;
+ int ret;
+
+ if (!vm) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+ _("no domain with matching uuid '%s'"), dom->uuid);
+ return -1;
+ }
+
+ if (!(type = qemudDomainGetOSType(dom))) {
+ return -1;
+ }
+
+ if ((ret = qemudGetMaxVCPUs(dom->conn, vm->def->virtType)) < 0) {
+ free(type);
+ return -1;
+ }
+
+ free(type);
+ return ret;
+}
+
+
static int qemudDomainRestore(virConnectPtr conn,
const char *path) {
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
@@ -3042,10 +3106,10 @@ static virDriver qemuDriver = {
qemudDomainSave, /* domainSave */
qemudDomainRestore, /* domainRestore */
NULL, /* domainCoreDump */
- NULL, /* domainSetVcpus */
+ qemudDomainSetVcpus, /* domainSetVcpus */
NULL, /* domainPinVcpu */
NULL, /* domainGetVcpus */
- NULL, /* domainGetMaxVcpus */
+ qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
qemudDomainDumpXML, /* domainDumpXML */
qemudListDefinedDomains, /* listDomains */
qemudNumDefinedDomains, /* numOfDomains */
16 years, 7 months
[Libvir] make syntax-check fails with bzr checkouts
by Soren Hansen
I seem to be completely unable to get make syntax-checks to function
properly with my bzr checkout of libvirt[1]. I've attached the output as
as-is.txt. I tried adding hacking bzr support into vc-list-files (see
vc-list-files-bzr.patch), but that didn't quite seem to do the trick, as
you can see in in vc-list-files-maybe-fixed.log, which is the output
after I patched vc-list-files.
I tried CVS, too, and that also fails (see cvs-syntax-check.log).
Is it only meant to work with git?
[1]: http://bazaar.launchpad.net/~vcs-imports/libvirt/trunk
--
Soren Hansen |
Virtualisation specialist | Ubuntu Server Team
Canonical Ltd. | http://www.ubuntu.com/
16 years, 7 months