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 "}, +#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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; ildomState != 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; ildomName); + 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; ildomState == 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; iuuid, 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; ildomName,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; ildomState == 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 '. Any of the + * XML can be changed, but the 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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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': + * + * + * + * + * list-constraints + * + * + * + * primary + * + * + * + * + * + */ + 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: + * + * + * + * + * list-constraints + * + * + * + * primary + * + * + * 4 + * + * + * 1 + * + * + * 1G + * + * ..... + */ + /* parse the received XML file to get the ldom info */ + + /* + * 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: + * + * + * + * + * list-bindings + * + * + * + * primary + * + * + * + * + * + */ + + /* 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: + * + * + * + * + * list-constraints + * + * + * + * ldom-126 + * 00:14:4f:f9:1a:7d + * + * ..... + * + * primary-vcc0 + * 5005 + * + * ..... + * + * + * success + * + * + * + * success + * + * + * + * success + * + * + */ + + /* 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_ 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: + * + * + * + * + * list-domain + * + * + * + * + */ + 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: + * + * + * + * + * list-domain + * + * + * + * primary + * active + * + * + * + * success + * + * + * + * success + * + * + * + * success + * + * + */ + + /* 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 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 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 tag */ + ldom_node = xml_find_subnode(data_node, LDOM_NODE); + + + /* Need a 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 tag */ + if (xmlStrcmp(subnode->name, (const xmlChar *)XML_LDM_INFO) == 0) { + /* Need a tag */ + name_node = xml_find_subnode(subnode, XML_LDM_NAME); + + /* We did not find a 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 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 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 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 ' + * + * 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 + * or 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 and 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, , go after */ + if (strstr(xmlBuf, (char*)XML_LDM_INTERFACE) != NULL) { + sprintf(tags, "<%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 */ + while (filerc != NULL) { + /* goes before */ + if (strstr(xmlBuf, (char*)XML_LDM_INTERFACE) != NULL) { + sprintf(tags, "", 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 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 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 + * + * + * + * + * set-vcpu + * + * + * + * ldom1 + * + * + * 4 + * + * + * + * + * + */ + +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); + + /* tag with version attribute */ + root = xmlNewDocNode(xml_output, NULL, XML_LDM_INTERFACE, NULL); + xmlDocSetRootElement(xml_output, root); + xmlNewProp(root, VERSION_ATTR, LDOM_INTERFACE_VERSION); + + /* 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"); + + /* tag */ + xmlNewChild(cmd, NULL, XML_ACTION, XML_SET_VCPU); + + /* 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"); + + /* 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"); + + /* tag with child 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"); + + /* tag with child 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 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. + * + * + * + * + * set-memory + * + * + * + * ldom1 + * + * + * 256K + * + * + * + * + * + */ + +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); + + /* tag with version sttribute */ + root = xmlNewDocNode(xml_output, NULL, XML_LDM_INTERFACE, NULL); + xmlDocSetRootElement(xml_output, root); + xmlNewProp(root, VERSION_ATTR, LDOM_INTERFACE_VERSION); + + /* 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"); + + /* tag */ + xmlNewChild(cmd, NULL, XML_ACTION, XML_SET_MEM); + + /* 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"); + + /* 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"); + + /* tag with child 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)); + + /* tag with child 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 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 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'. + * + * + * + * + * list-bindings + * + * + * + * ldg3 + * + * + * + * + * + */ +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: + * + * + * + * + * list-bindings + * + * + * + * primary + * + * + * primary-vcc0 + * 5004 + * + *... + * + * + * success + * + * + * + * success + * + * + * + * success + * + * + */ +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 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 tag\n"); + return (-1); + } + + /* Get the tag */ + data_node = xml_find_subnode(cmd_node, XML_DATA); + if (data_node != NULL) + /* Get the 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 tag\n"); + return (-1); + } + + if (ldom_node == NULL) { + if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_console.. XML file does not have tag\n"); + return (-1); + } + + /* Get the 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 tag\n"); + console_xml = 0; + } else { + /* Get the 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 tag within tag\n"); + console_xml = 0; + } else { + /* Contents of the 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 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: + * + * + * + * + * list-constraints + * + * + * + * primary + * + * + * 4 + * + * + * 1 + * + * + * 1G + * + * + * pci@780 + * + * + * + * success + * + * + * + * success + * + * + * + * success + * + * + */ +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 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 tag\n"); + return (ret); + } + + if (ldom_node == NULL) { + if (ldoms_debug) dprt("LDOMS_DEBUG: parse_xml_get_ldominfo.. XML file does not have 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 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 tag within 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 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 tag within 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 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 tag within 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 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 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 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 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 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 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 tags in the XML response. + * There are tags associated with the document, and + * tags. This function is general to be able to check for + * for any of these. If the of the document is + * 'success', then the other 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 + * + * + * + * + * bind-domain + * + * + * failure + * ldom does not have ldom_name tag + * + * + * + * failure + * + * + * + * failure + * + * + */ +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 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 tag within \n"); + return (-1); + } + + content = xmlNodeGetContent(status_node); + + /* + * The 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() is success\n"); + xmlFree(content); + } + + /* XML request failed, get the reason why, */ + else { + if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() =%s\n", content); + xmlFree(content); + content = NULL; + + /* response status is not success, get the response msg. + * The tag is within the tag, not the + * or tags, so drill down to the first + * tag and get the tag contents to display + * in an error message + */ + + /* + * Get the node first, then get a list of the child nodes. + * There can be multiple nodes, which are peers, + * but usually there is only 1 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() child=%s\n",cmd_child_node->name); + /* Is current child node a */ + if (strcmp((const char*)cmd_child_node->name,(const char*)XML_DATA) != 0) { + cmd_child_node = cmd_child_node->next; + continue; + } + + /* Found a 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() child=%s\n",data_child_node->name); + /* Is current child node a */ + 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 \n"); + + /* Found a node, so get the 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 \n"); + content = xmlNodeGetContent(respmsg_node); + if (content != NULL) { + if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_response_status() =%s\n", content); + cmd_child_node = NULL; + } + } + /* No more nodes in the 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 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 tag comes within the tag. + * + * Example XML output from the LDOM Manager for the "list-domain" request: + * + * + * + * + * list-domain + * + * + * + * primary + * active + * + * + * + * success + * + * + * + * + * + * ldg1 + * bound + * + * + * + * success + * + * + * + * + * + * ldg3 + * bound + * + * + * + * success + * + * + * + * success + * + * + * + * success + * + * + * + * 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 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 tag\n"); + return (-1); + } + + /* + * There will be a tag pair for each pair. + * We don't care about the tags with the tags becuase we + * already checked the outermost + */ + 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 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_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 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 tags in the "list-devices" + * xml output) and reserved (with 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: + * + * + * list-devices + * + * + * + * primary + * + * + * + * 0xc4800000 + * 29624M + * + * + *.. + * for reserved resource: + * + * + * list-bindings + * + * + * + * primary + * + * + * 1G + * + * 0x4000000 + * 0x4000000 + * 1G + * + * + * ... + * + */ +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 tag and + * for reserved, look for 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 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 tag\n"); + return (-1); + } + + /* get capacity data from list-devices which does not have tag + * and get reserved data from list-bindings which has 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 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 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.. tag found\n"); + else + if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_mem_rp.. 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.. 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.. 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 tags for each + * 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 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 tags in the "list-devices" + * xml output) and reserved (with 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: + * + * + * list-devices + * + * + * + * 12 + * 100 + * + * + * 13 + * 100 + * + *.. + *.. + * for reserved resource: + * + * + * list-bindings + * + * + * + * primary + * + * + * 4 + * + * 0 + * 0 + * 100 + * + * ... + * + */ +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 tag and + * for reserved, look for 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 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 tag\n"); + return (-1); + } + + /* get capacity data from list-devices which does not have tag + * and get reserved data from list-bindings which has 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 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 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.. tag found\n"); + else + if (ldoms_detailed_debug) dprt("LDOMS_DETAILED_DEBUG: parse_xml_get_cpu_rp.. tag found\n"); + + /* add up the number of CPUs */ + ncpu++; + + + subnode = subnode->next; + continue; + } + + subnode = subnode->next; + } + + } + + + /* xml response for list has tags for each + * 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 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 + * + * + * list-bindings + * + * + * + * primary + * + * + * 4 + * + * 0 + * 0 + * 100 + * + * ... + * + */ +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 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 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 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 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() 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 node and its value. subnode points to */ + id_node = subnode->xmlChildrenNode; + virtID = xmlNodeGetContent(id_node); + newBinding->virt = (unsigned int)atoi((const char *)virtID); + xmlFree(virtID); + + /* Get the 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: + */ +