libvirt/src/phyp/phyp_driver.c
Michal Privoznik 940d91c55b virDomainDefPostParse: Introduce @parseOpaque argument
Some callers might want to pass yet another pointer to opaque
data to post parse callbacks. The driver generic one is not
enough because two threads executing post parse callback might
want to see different data (e.g. domain object pointer that
domain def belongs to).

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2016-09-26 16:50:12 +02:00

3782 lines
107 KiB
C

/*
* Copyright (C) 2010-2015 Red Hat, Inc.
* Copyright IBM Corp. 2009
*
* phyp_driver.c: ssh layer to access Power Hypervisors
*
* Authors:
* Eduardo Otubo <otubo at linux.vnet.ibm.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <libssh2.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <domain_event.h>
#include <poll.h>
#include "internal.h"
#include "virauth.h"
#include "datatypes.h"
#include "virbuffer.h"
#include "viralloc.h"
#include "virlog.h"
#include "driver.h"
#include "virerror.h"
#include "viruuid.h"
#include "domain_conf.h"
#include "storage_conf.h"
#include "nodeinfo.h"
#include "virfile.h"
#include "interface_conf.h"
#include "phyp_driver.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_PHYP
VIR_LOG_INIT("phyp.phyp_driver");
#define LPAR_EXEC_ERR (-1)
#define SSH_CONN_ERR (-2) /* error while trying to connect to remote host */
#define SSH_CMD_ERR (-3) /* error while trying to execute the remote cmd */
/* This is the lpar (domain) struct that relates
* the ID with UUID generated by the API
* */
typedef struct _lpar lpar_t;
typedef lpar_t *lparPtr;
struct _lpar {
unsigned char uuid[VIR_UUID_BUFLEN];
int id;
};
/* Struct that holds how many lpars (domains) we're
* handling and a pointer to an array of lpar structs
* */
typedef struct _uuid_table uuid_table_t;
typedef uuid_table_t *uuid_tablePtr;
struct _uuid_table {
size_t nlpars;
lparPtr *lpars;
};
/* This is the main structure of the driver
* */
typedef struct _phyp_driver phyp_driver_t;
typedef phyp_driver_t *phyp_driverPtr;
struct _phyp_driver {
LIBSSH2_SESSION *session;
int sock;
uuid_tablePtr uuid_table;
virCapsPtr caps;
virDomainXMLOptionPtr xmlopt;
int vios_id;
/* system_type:
* 0 = hmc
* 127 = ivm
* */
int system_type;
char *managed_system;
};
/*
* URI: phyp://user@[hmc|ivm]/managed_system
* */
enum {
HMC = 0,
PHYP_IFACENAME_SIZE = 24,
PHYP_MAC_SIZE = 12,
};
static int
waitsocket(int socket_fd, LIBSSH2_SESSION * session)
{
struct pollfd fds[1];
int dir;
memset(fds, 0, sizeof(fds));
fds[0].fd = socket_fd;
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if (dir & LIBSSH2_SESSION_BLOCK_INBOUND)
fds[0].events |= POLLIN;
if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
fds[0].events |= POLLOUT;
return poll(fds, ARRAY_CARDINALITY(fds), -1);
}
/* this function is the layer that manipulates the ssh channel itself
* and executes the commands on the remote machine */
static char *phypExec(LIBSSH2_SESSION *, const char *, int *, virConnectPtr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_NONNULL(4);
static char *
phypExec(LIBSSH2_SESSION *session, const char *cmd, int *exit_status,
virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_CHANNEL *channel;
virBuffer tex_ret = VIR_BUFFER_INITIALIZER;
char *buffer = NULL;
size_t buffer_size = 16384;
int exitcode;
int bytecount = 0;
int sock = phyp_driver->sock;
int rc = 0;
if (VIR_ALLOC_N(buffer, buffer_size) < 0)
return NULL;
/* Exec non-blocking on the remove host */
while ((channel = libssh2_channel_open_session(session)) == NULL &&
libssh2_session_last_error(session, NULL, NULL, 0) ==
LIBSSH2_ERROR_EAGAIN) {
if (waitsocket(sock, session) < 0 && errno != EINTR) {
virReportSystemError(errno, "%s",
_("unable to wait on libssh2 socket"));
goto err;
}
}
if (channel == NULL)
goto err;
while ((rc = libssh2_channel_exec(channel, cmd)) ==
LIBSSH2_ERROR_EAGAIN) {
if (waitsocket(sock, session) < 0 && errno != EINTR) {
virReportSystemError(errno, "%s",
_("unable to wait on libssh2 socket"));
goto err;
}
}
if (rc != 0)
goto err;
for (;;) {
/* loop until we block */
do {
rc = libssh2_channel_read(channel, buffer, buffer_size);
if (rc > 0) {
bytecount += rc;
virBufferAdd(&tex_ret, buffer, -1);
}
}
while (rc > 0);
/* this is due to blocking that would occur otherwise so we loop on
* this condition */
if (rc == LIBSSH2_ERROR_EAGAIN) {
if (waitsocket(sock, session) < 0 && errno != EINTR) {
virReportSystemError(errno, "%s",
_("unable to wait on libssh2 socket"));
goto err;
}
} else {
break;
}
}
exitcode = 127;
while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) {
if (waitsocket(sock, session) < 0 && errno != EINTR) {
virReportSystemError(errno, "%s",
_("unable to wait on libssh2 socket"));
goto err;
}
}
if (rc == 0)
exitcode = libssh2_channel_get_exit_status(channel);
(*exit_status) = exitcode;
libssh2_channel_free(channel);
channel = NULL;
VIR_FREE(buffer);
if (virBufferCheckError(&tex_ret) < 0)
return NULL;
return virBufferContentAndReset(&tex_ret);
err:
(*exit_status) = SSH_CMD_ERR;
virBufferFreeAndReset(&tex_ret);
VIR_FREE(buffer);
return NULL;
}
/* Convenience wrapper function */
static char *phypExecBuffer(LIBSSH2_SESSION *, virBufferPtr buf, int *,
virConnectPtr, bool) ATTRIBUTE_NONNULL(1)
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
static char *
phypExecBuffer(LIBSSH2_SESSION *session, virBufferPtr buf, int *exit_status,
virConnectPtr conn, bool strip_newline)
{
char *cmd;
char *ret;
if (virBufferCheckError(buf) < 0)
return NULL;
cmd = virBufferContentAndReset(buf);
ret = phypExec(session, cmd, exit_status, conn);
VIR_FREE(cmd);
if (ret && *exit_status == 0 && strip_newline) {
char *nl = strchr(ret, '\n');
if (nl)
*nl = '\0';
}
return ret;
}
/* Convenience wrapper function */
static int phypExecInt(LIBSSH2_SESSION *, virBufferPtr, virConnectPtr, int *)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
static int
phypExecInt(LIBSSH2_SESSION *session, virBufferPtr buf, virConnectPtr conn,
int *result)
{
char *str;
int ret;
char *char_ptr;
str = phypExecBuffer(session, buf, &ret, conn, true);
if (!str || ret) {
VIR_FREE(str);
return -1;
}
ret = virStrToLong_i(str, &char_ptr, 10, result);
if (ret == 0 && *char_ptr)
VIR_WARN("ignoring suffix during integer parsing of '%s'", str);
VIR_FREE(str);
return ret;
}
static int
phypGetSystemType(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *ret = NULL;
int exit_status = 0;
ret = phypExec(session, "lshmc -V", &exit_status, conn);
VIR_FREE(ret);
return exit_status;
}
static int
phypGetVIOSPartitionID(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int id = -1;
char *managed_system = phyp_driver->managed_system;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lssyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env"
"|sed -n '/vioserver/ {\n s/,.*$//\n p\n}'");
phypExecInt(session, &buf, conn, &id);
return id;
}
static virCapsPtr
phypCapsInit(void)
{
virCapsPtr caps;
virCapsGuestPtr guest;
if ((caps = virCapabilitiesNew(virArchFromHost(),
false, false)) == NULL)
goto no_memory;
/* Some machines have problematic NUMA toplogy causing
* unexpected failures. We don't want to break the QEMU
* driver in this scenario, so log errors & carry on
*/
if (nodeCapsInitNUMA(caps) < 0) {
virCapabilitiesFreeNUMAInfo(caps);
VIR_WARN
("Failed to query host NUMA topology, disabling NUMA capabilities");
}
if ((guest = virCapabilitiesAddGuest(caps,
VIR_DOMAIN_OSTYPE_LINUX,
caps->host.arch,
NULL, NULL, 0, NULL)) == NULL)
goto no_memory;
if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_PHYP,
NULL, NULL, 0, NULL) == NULL)
goto no_memory;
return caps;
no_memory:
virObjectUnref(caps);
return NULL;
}
/* This is a generic function that won't be used directly by
* libvirt api. The function returns the number of domains
* in different states: Running, Not Activated and all:
*
* type: 0 - Running
* 1 - Not Activated
* * - All
* */
static int
phypConnectNumOfDomainsGeneric(virConnectPtr conn, unsigned int type)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int ndom = -1;
char *managed_system = phyp_driver->managed_system;
const char *state;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (type == 0) {
state = "|grep Running";
} else if (type == 1) {
if (system_type == HMC) {
state = "|grep \"Not Activated\"";
} else {
state = "|grep \"Open Firmware\"";
}
} else {
state = " ";
}
virBufferAddLit(&buf, "lssyscfg -r lpar");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9][0-9]*'",
state);
phypExecInt(session, &buf, conn, &ndom);
return ndom;
}
/* This is a generic function that won't be used directly by
* libvirt api. The function returns the ids of domains
* in different states: Running, and all:
*
* type: 0 - Running
* 1 - all
* */
static int
phypConnectListDomainsGeneric(virConnectPtr conn, int *ids, int nids,
unsigned int type)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
int got = -1;
char *ret = NULL;
char *line, *next_line;
const char *state;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (type == 0)
state = "|grep Running";
else
state = " ";
virBufferAddLit(&buf, "lssyscfg -r lpar");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'",
state);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
/* I need to parse the textual return in order to get the ids */
line = ret;
got = 0;
while (*line && got < nids) {
if (virStrToLong_i(line, &next_line, 10, &ids[got]) == -1) {
VIR_ERROR(_("Cannot parse number from '%s'"), line);
got = -1;
goto cleanup;
}
got++;
line = next_line;
while (*line == '\n')
line++; /* skip \n */
}
cleanup:
VIR_FREE(ret);
return got;
}
static int
phypUUIDTable_WriteFile(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
uuid_tablePtr uuid_table = phyp_driver->uuid_table;
size_t i = 0;
int fd = -1;
char local_file[] = "./uuid_table";
if ((fd = creat(local_file, 0755)) == -1)
goto err;
for (i = 0; i < uuid_table->nlpars; i++) {
if (safewrite(fd, &uuid_table->lpars[i]->id,
sizeof(uuid_table->lpars[i]->id)) !=
sizeof(uuid_table->lpars[i]->id)) {
VIR_ERROR(_("Unable to write information to local file."));
goto err;
}
if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) !=
VIR_UUID_BUFLEN) {
VIR_ERROR(_("Unable to write information to local file."));
goto err;
}
}
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno, _("Could not close %s"),
local_file);
goto err;
}
return 0;
err:
VIR_FORCE_CLOSE(fd);
return -1;
}
static int
phypUUIDTable_Push(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
LIBSSH2_CHANNEL *channel = NULL;
struct stat local_fileinfo;
char buffer[1024];
int rc = 0;
FILE *f = NULL;
size_t nread, sent;
char *ptr;
char local_file[] = "./uuid_table";
char *remote_file = NULL;
int ret = -1;
if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
NULLSTR(conn->uri->user)) < 0)
goto cleanup;
if (stat(local_file, &local_fileinfo) == -1) {
VIR_WARN("Unable to stat local file.");
goto cleanup;
}
if (!(f = fopen(local_file, "rb"))) {
VIR_WARN("Unable to open local file.");
goto cleanup;
}
do {
channel =
libssh2_scp_send(session, remote_file,
0x1FF & local_fileinfo.st_mode,
(unsigned long) local_fileinfo.st_size);
if ((!channel) && (libssh2_session_last_errno(session) !=
LIBSSH2_ERROR_EAGAIN))
goto cleanup;
} while (!channel);
do {
nread = fread(buffer, 1, sizeof(buffer), f);
if (nread <= 0) {
if (feof(f)) {
/* end of file */
break;
} else {
VIR_ERROR(_("Failed to read from %s"), local_file);
goto cleanup;
}
}
ptr = buffer;
sent = 0;
do {
/* write the same data over and over, until error or completion */
rc = libssh2_channel_write(channel, ptr, nread);
if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */
continue;
} else if (rc > 0) {
/* rc indicates how many bytes were written this time */
sent += rc;
}
ptr += sent;
nread -= sent;
} while (rc > 0 && sent < nread);
} while (1);
ret = 0;
cleanup:
if (channel) {
libssh2_channel_send_eof(channel);
libssh2_channel_wait_eof(channel);
libssh2_channel_wait_closed(channel);
libssh2_channel_free(channel);
channel = NULL;
}
VIR_FORCE_FCLOSE(f);
return ret;
}
static int
phypUUIDTable_RemLpar(virConnectPtr conn, int id)
{
phyp_driverPtr phyp_driver = conn->privateData;
uuid_tablePtr uuid_table = phyp_driver->uuid_table;
size_t i = 0;
for (i = 0; i <= uuid_table->nlpars; i++) {
if (uuid_table->lpars[i]->id == id) {
uuid_table->lpars[i]->id = -1;
memset(uuid_table->lpars[i]->uuid, 0, VIR_UUID_BUFLEN);
}
}
if (phypUUIDTable_WriteFile(conn) == -1)
goto err;
if (phypUUIDTable_Push(conn) == -1)
goto err;
return 0;
err:
return -1;
}
static int
phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id)
{
phyp_driverPtr phyp_driver = conn->privateData;
uuid_tablePtr uuid_table = phyp_driver->uuid_table;
lparPtr item = NULL;
if (VIR_ALLOC(item) < 0)
goto err;
item->id = id;
memcpy(item->uuid, uuid, VIR_UUID_BUFLEN);
if (VIR_APPEND_ELEMENT_COPY(uuid_table->lpars, uuid_table->nlpars, item) < 0)
goto err;
if (phypUUIDTable_WriteFile(conn) == -1)
goto err;
if (phypUUIDTable_Push(conn) == -1)
goto err;
return 0;
err:
VIR_FREE(item);
return -1;
}
static int
phypUUIDTable_ReadFile(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
uuid_tablePtr uuid_table = phyp_driver->uuid_table;
size_t i = 0;
int fd = -1;
char local_file[] = "./uuid_table";
int rc = 0;
int id;
if ((fd = open(local_file, O_RDONLY)) == -1) {
VIR_WARN("Unable to read information from local file.");
goto err;
}
/* Creating a new data base and writing to local file */
if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) {
for (i = 0; i < uuid_table->nlpars; i++) {
rc = read(fd, &id, sizeof(int));
if (rc == sizeof(int)) {
if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
goto err;
uuid_table->lpars[i]->id = id;
} else {
VIR_WARN
("Unable to read from information from local file.");
goto err;
}
rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN);
if (rc != VIR_UUID_BUFLEN) {
VIR_WARN("Unable to read information from local file.");
goto err;
}
}
}
VIR_FORCE_CLOSE(fd);
return 0;
err:
VIR_FORCE_CLOSE(fd);
return -1;
}
static int
phypUUIDTable_Pull(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
LIBSSH2_CHANNEL *channel = NULL;
struct stat fileinfo;
char buffer[1024];
int rc = 0;
int fd = -1;
int got = 0;
int amount = 0;
int total = 0;
int sock = 0;
char local_file[] = "./uuid_table";
char *remote_file = NULL;
int ret = -1;
if (virAsprintf(&remote_file, "/home/%s/libvirt_uuid_table",
NULLSTR(conn->uri->user)) < 0)
goto cleanup;
/* Trying to stat the remote file. */
do {
channel = libssh2_scp_recv(session, remote_file, &fileinfo);
if (!channel) {
if (libssh2_session_last_errno(session) !=
LIBSSH2_ERROR_EAGAIN) {
goto cleanup;
} else {
if (waitsocket(sock, session) < 0 && errno != EINTR) {
virReportSystemError(errno, "%s",
_("unable to wait on libssh2 socket"));
goto cleanup;
}
}
}
} while (!channel);
/* Creating a new data base based on remote file */
if ((fd = creat(local_file, 0755)) == -1)
goto cleanup;
/* Request a file via SCP */
while (got < fileinfo.st_size) {
do {
amount = sizeof(buffer);
if ((fileinfo.st_size - got) < amount)
amount = fileinfo.st_size - got;
rc = libssh2_channel_read(channel, buffer, amount);
if (rc > 0) {
if (safewrite(fd, buffer, rc) != rc)
VIR_WARN
("Unable to write information to local file.");
got += rc;
total += rc;
}
} while (rc > 0);
if ((rc == LIBSSH2_ERROR_EAGAIN)
&& (got < fileinfo.st_size)) {
/* this is due to blocking that would occur otherwise
* so we loop on this condition */
/* now we wait */
if (waitsocket(sock, session) < 0 && errno != EINTR) {
virReportSystemError(errno, "%s",
_("unable to wait on libssh2 socket"));
goto cleanup;
}
continue;
}
break;
}
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno, _("Could not close %s"),
local_file);
goto cleanup;
}
ret = 0;
cleanup:
if (channel) {
libssh2_channel_send_eof(channel);
libssh2_channel_wait_eof(channel);
libssh2_channel_wait_closed(channel);
libssh2_channel_free(channel);
channel = NULL;
}
VIR_FORCE_CLOSE(fd);
return ret;
}
static int
phypUUIDTable_Init(virConnectPtr conn)
{
uuid_tablePtr uuid_table = NULL;
phyp_driverPtr phyp_driver;
int nids_numdomains = 0;
int nids_listdomains = 0;
int *ids = NULL;
size_t i = 0;
int ret = -1;
bool table_created = false;
if ((nids_numdomains = phypConnectNumOfDomainsGeneric(conn, 2)) < 0)
goto cleanup;
if (VIR_ALLOC_N(ids, nids_numdomains) < 0)
goto cleanup;
if ((nids_listdomains =
phypConnectListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0)
goto cleanup;
/* exit early if there are no domains */
if (nids_numdomains == 0 && nids_listdomains == 0) {
ret = 0;
goto cleanup;
}
if (nids_numdomains != nids_listdomains) {
VIR_ERROR(_("Unable to determine number of domains."));
goto cleanup;
}
phyp_driver = conn->privateData;
uuid_table = phyp_driver->uuid_table;
uuid_table->nlpars = nids_listdomains;
/* try to get the table from server */
if (phypUUIDTable_Pull(conn) == -1) {
/* file not found in the server, creating a new one */
table_created = true;
if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) {
for (i = 0; i < uuid_table->nlpars; i++) {
if (VIR_ALLOC(uuid_table->lpars[i]) < 0)
goto cleanup;
uuid_table->lpars[i]->id = ids[i];
if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0)
VIR_WARN("Unable to generate UUID for domain %d",
ids[i]);
}
} else {
goto cleanup;
}
if (phypUUIDTable_WriteFile(conn) == -1)
goto cleanup;
if (phypUUIDTable_Push(conn) == -1)
goto cleanup;
} else {
if (phypUUIDTable_ReadFile(conn) == -1)
goto cleanup;
}
ret = 0;
cleanup:
if (ret < 0 && table_created) {
for (i = 0; i < uuid_table->nlpars; i++)
VIR_FREE(uuid_table->lpars[i]);
VIR_FREE(uuid_table->lpars);
}
VIR_FREE(ids);
return ret;
}
static void
phypUUIDTable_Free(uuid_tablePtr uuid_table)
{
size_t i;
if (uuid_table == NULL)
return;
for (i = 0; i < uuid_table->nlpars; i++)
VIR_FREE(uuid_table->lpars[i]);
VIR_FREE(uuid_table->lpars);
VIR_FREE(uuid_table);
}
#define SPECIALCHARACTER_CASES \
case '&': case ';': case '`': case '@': case '"': case '|': case '*': \
case '?': case '~': case '<': case '>': case '^': case '(': case ')': \
case '[': case ']': case '{': case '}': case '$': case '%': case '#': \
case '\\': case '\n': case '\r': case '\t':
static bool
contains_specialcharacters(const char *src)
{
size_t len = strlen(src);
size_t i = 0;
if (len == 0)
return false;
for (i = 0; i < len; i++) {
switch (src[i]) {
SPECIALCHARACTER_CASES
return true;
default:
continue;
}
}
return false;
}
static char *
escape_specialcharacters(const char *src)
{
size_t len = strlen(src);
size_t i = 0, j = 0;
char *dst;
if (len == 0)
return NULL;
if (VIR_ALLOC_N(dst, len + 1) < 0)
return NULL;
for (i = 0; i < len; i++) {
switch (src[i]) {
SPECIALCHARACTER_CASES
continue;
default:
dst[j] = src[i];
j++;
}
}
dst[j] = '\0';
return dst;
}
static LIBSSH2_SESSION *
openSSHSession(virConnectPtr conn, virConnectAuthPtr auth,
int *internal_socket)
{
LIBSSH2_SESSION *session;
const char *hostname = conn->uri->server;
char *username = NULL;
char *password = NULL;
int sock = -1;
int rc;
struct addrinfo *ai = NULL, *cur;
struct addrinfo hints;
int ret;
char *pubkey = NULL;
char *pvtkey = NULL;
char *userhome = virGetUserDirectory();
struct stat pvt_stat, pub_stat;
if (userhome == NULL)
goto err;
if (virAsprintf(&pubkey, "%s/.ssh/id_rsa.pub", userhome) < 0)
goto err;
if (virAsprintf(&pvtkey, "%s/.ssh/id_rsa", userhome) < 0)
goto err;
if (conn->uri->user != NULL) {
if (VIR_STRDUP(username, conn->uri->user) < 0)
goto err;
} else {
if (auth == NULL || auth->cb == NULL) {
virReportError(VIR_ERR_AUTH_FAILED,
"%s", _("No authentication callback provided."));
goto err;
}
username = virAuthGetUsername(conn, auth, "ssh", NULL, conn->uri->server);
if (username == NULL) {
virReportError(VIR_ERR_AUTH_FAILED, "%s",
_("Username request failed"));
goto err;
}
}
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
ret = getaddrinfo(hostname, "22", &hints, &ai);
if (ret != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Error while getting %s address info"), hostname);
goto err;
}
cur = ai;
while (cur != NULL) {
sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
if (sock >= 0) {
if (connect(sock, cur->ai_addr, cur->ai_addrlen) == 0) {
freeaddrinfo(ai);
goto connected;
}
VIR_FORCE_CLOSE(sock);
}
cur = cur->ai_next;
}
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to connect to %s"), hostname);
freeaddrinfo(ai);
goto err;
connected:
(*internal_socket) = sock;
/* Create a session instance */
session = libssh2_session_init();
if (!session)
goto err;
/* tell libssh2 we want it all done non-blocking */
libssh2_session_set_blocking(session, 0);
while ((rc = libssh2_session_startup(session, sock)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Failure establishing SSH session."));
goto disconnect;
}
/* Trying authentication by pubkey */
if (stat(pvtkey, &pvt_stat) || stat(pubkey, &pub_stat)) {
rc = LIBSSH2_ERROR_SOCKET_NONE;
goto keyboard_interactive;
}
while ((rc =
libssh2_userauth_publickey_fromfile(session, username,
pubkey,
pvtkey,
NULL)) ==
LIBSSH2_ERROR_EAGAIN);
keyboard_interactive:
if (rc == LIBSSH2_ERROR_SOCKET_NONE
|| rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED
|| rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) {
if (auth == NULL || auth->cb == NULL) {
virReportError(VIR_ERR_AUTH_FAILED,
"%s", _("No authentication callback provided."));
goto disconnect;
}
password = virAuthGetPassword(conn, auth, "ssh", username, conn->uri->server);
if (password == NULL) {
virReportError(VIR_ERR_AUTH_FAILED, "%s",
_("Password request failed"));
goto disconnect;
}
while ((rc =
libssh2_userauth_password(session, username,
password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
virReportError(VIR_ERR_AUTH_FAILED,
"%s", _("Authentication failed"));
goto disconnect;
} else {
goto exit;
}
} else if (rc == LIBSSH2_ERROR_NONE) {
goto exit;
} else if (rc == LIBSSH2_ERROR_ALLOC || rc == LIBSSH2_ERROR_SOCKET_SEND
|| rc == LIBSSH2_ERROR_SOCKET_TIMEOUT) {
goto err;
}
disconnect:
libssh2_session_disconnect(session, "Disconnecting...");
libssh2_session_free(session);
err:
VIR_FORCE_CLOSE(sock);
VIR_FREE(userhome);
VIR_FREE(pubkey);
VIR_FREE(pvtkey);
VIR_FREE(username);
VIR_FREE(password);
return NULL;
exit:
VIR_FREE(userhome);
VIR_FREE(pubkey);
VIR_FREE(pvtkey);
VIR_FREE(username);
VIR_FREE(password);
return session;
}
static int
phypDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED,
unsigned int parseFlags ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED,
void *parseOpaque ATTRIBUTE_UNUSED)
{
return 0;
}
static int
phypDomainDeviceDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
const virDomainDef *def ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED,
unsigned int parseFlags ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
return 0;
}
virDomainDefParserConfig virPhypDriverDomainDefParserConfig = {
.devicesPostParseCallback = phypDomainDeviceDefPostParse,
.domainPostParseCallback = phypDomainDefPostParse,
.features = VIR_DOMAIN_DEF_FEATURE_NAME_SLASH,
};
static virDrvOpenStatus
phypConnectOpen(virConnectPtr conn,
virConnectAuthPtr auth,
virConfPtr conf ATTRIBUTE_UNUSED,
unsigned int flags)
{
LIBSSH2_SESSION *session = NULL;
int internal_socket = -1;
uuid_tablePtr uuid_table = NULL;
phyp_driverPtr phyp_driver = NULL;
char *char_ptr;
char *managed_system = NULL;
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
if (!conn || !conn->uri)
return VIR_DRV_OPEN_DECLINED;
if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "phyp"))
return VIR_DRV_OPEN_DECLINED;
if (conn->uri->server == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Missing server name in phyp:// URI"));
return VIR_DRV_OPEN_ERROR;
}
if (VIR_ALLOC(phyp_driver) < 0)
goto failure;
phyp_driver->sock = -1;
if (VIR_ALLOC(uuid_table) < 0)
goto failure;
if (conn->uri->path) {
/* need to shift one byte in order to remove the first "/" of URI component */
if (VIR_STRDUP(managed_system,
conn->uri->path + (conn->uri->path[0] == '/')) < 0)
goto failure;
/* here we are handling only the first component of the path,
* so skipping the second:
* */
char_ptr = strchr(managed_system, '/');
if (char_ptr)
*char_ptr = '\0';
if (contains_specialcharacters(conn->uri->path)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s",
_("Error parsing 'path'. Invalid characters."));
goto failure;
}
}
if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Error while opening SSH session."));
goto failure;
}
phyp_driver->session = session;
phyp_driver->sock = internal_socket;
uuid_table->nlpars = 0;
uuid_table->lpars = NULL;
if (conn->uri->path)
phyp_driver->managed_system = managed_system;
phyp_driver->uuid_table = uuid_table;
if ((phyp_driver->caps = phypCapsInit()) == NULL)
goto failure;
if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(&virPhypDriverDomainDefParserConfig,
NULL, NULL)))
goto failure;
conn->privateData = phyp_driver;
if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1)
goto failure;
if (phypUUIDTable_Init(conn) == -1)
goto failure;
if (phyp_driver->system_type == HMC) {
if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1)
goto failure;
}
return VIR_DRV_OPEN_SUCCESS;
failure:
VIR_FREE(managed_system);
if (phyp_driver != NULL) {
virObjectUnref(phyp_driver->caps);
virObjectUnref(phyp_driver->xmlopt);
VIR_FREE(phyp_driver);
}
phypUUIDTable_Free(uuid_table);
if (session != NULL) {
libssh2_session_disconnect(session, "Disconnecting...");
libssh2_session_free(session);
}
VIR_FORCE_CLOSE(internal_socket);
return VIR_DRV_OPEN_ERROR;
}
static int
phypConnectClose(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
libssh2_session_disconnect(session, "Disconnecting...");
libssh2_session_free(session);
virObjectUnref(phyp_driver->caps);
virObjectUnref(phyp_driver->xmlopt);
phypUUIDTable_Free(phyp_driver->uuid_table);
VIR_FREE(phyp_driver->managed_system);
VIR_FORCE_CLOSE(phyp_driver->sock);
VIR_FREE(phyp_driver);
return 0;
}
static int
phypConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* Phyp uses an SSH tunnel, so is always encrypted */
return 1;
}
static int
phypConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* Phyp uses an SSH tunnel, so is always secure */
return 1;
}
static int
phypConnectIsAlive(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
/* XXX we should be able to do something better but this is simple, safe,
* and good enough for now. In worst case, the function will return true
* even though the connection is not alive.
*/
if (phyp_driver->session)
return 1;
else
return 0;
}
static int
phypDomainIsUpdated(virDomainPtr conn ATTRIBUTE_UNUSED)
{
return 0;
}
/* return the lpar_id given a name and a managed system name */
static int
phypGetLparID(LIBSSH2_SESSION * session, const char *managed_system,
const char *name, virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
int system_type = phyp_driver->system_type;
int lpar_id = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lssyscfg -r lpar");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " --filter lpar_names=%s -F lpar_id", name);
phypExecInt(session, &buf, conn, &lpar_id);
return lpar_id;
}
/* return the lpar name given a lpar_id and a managed system name */
static char *
phypGetLparNAME(LIBSSH2_SESSION * session, const char *managed_system,
unsigned int lpar_id, virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
int system_type = phyp_driver->system_type;
char *ret = NULL;
int exit_status = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lssyscfg -r lpar");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " --filter lpar_ids=%d -F name", lpar_id);
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0)
VIR_FREE(ret);
return ret;
}
/* Search into the uuid_table for a lpar_uuid given a lpar_id
* and a managed system name
*
* return: 0 - record found
* -1 - not found
* */
static int
phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
uuid_tablePtr uuid_table = phyp_driver->uuid_table;
lparPtr *lpars = uuid_table->lpars;
size_t i = 0;
for (i = 0; i < uuid_table->nlpars; i++) {
if (lpars[i]->id == lpar_id) {
memcpy(uuid, lpars[i]->uuid, VIR_UUID_BUFLEN);
return 0;
}
}
return -1;
}
/*
* type:
* 0 - maxmem
* 1 - memory
* */
static unsigned long
phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id,
int type)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int memory = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (type != 1 && type != 0)
return 0;
virBufferAddLit(&buf, "lshwres");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -r mem --level lpar -F %s --filter lpar_ids=%d",
type ? "curr_mem" : "curr_max_mem", lpar_id);
phypExecInt(session, &buf, conn, &memory);
return memory;
}
static unsigned long
phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system,
int lpar_id, int type)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int vcpus = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lshwres");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -r proc --level lpar -F %s --filter lpar_ids=%d",
type ? "curr_max_procs" : "curr_procs", lpar_id);
phypExecInt(session, &buf, conn, &vcpus);
return vcpus;
}
static unsigned long
phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id)
{
return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0);
}
static int
phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
phyp_driverPtr phyp_driver = dom->conn->privateData;
char *managed_system = phyp_driver->managed_system;
if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
return -1;
}
return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1);
}
static int
phypDomainGetMaxVcpus(virDomainPtr dom)
{
return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
VIR_DOMAIN_VCPU_MAXIMUM));
}
static int
phypGetRemoteSlot(virConnectPtr conn, const char *managed_system,
const char *lpar_name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int remote_slot = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lshwres");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
"remote_slot_num --filter lpar_names=%s", lpar_name);
phypExecInt(session, &buf, conn, &remote_slot);
return remote_slot;
}
/* XXX - is this needed? */
static char *phypGetBackingDevice(virConnectPtr, const char *, char *)
ATTRIBUTE_UNUSED;
static char *
phypGetBackingDevice(virConnectPtr conn, const char *managed_system,
char *lpar_name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *ret = NULL;
int remote_slot = 0;
int exit_status = 0;
char *char_ptr;
char *backing_device = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if ((remote_slot =
phypGetRemoteSlot(conn, managed_system, lpar_name)) == -1)
return NULL;
virBufferAddLit(&buf, "lshwres");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r virtualio --rsubtype scsi -F "
"backing_devices --filter slots=%d", remote_slot);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
/* here is a little trick to deal returns of this kind:
*
* 0x8100000000000000//lv01
*
* the information we really need is only lv01, so we
* need to skip a lot of things on the string.
* */
char_ptr = strchr(ret, '/');
if (char_ptr) {
char_ptr++;
if (char_ptr[0] == '/')
char_ptr++;
else
goto cleanup;
if (VIR_STRDUP(backing_device, char_ptr) < 0)
goto cleanup;
} else {
backing_device = ret;
ret = NULL;
}
char_ptr = strchr(backing_device, '\n');
if (char_ptr)
*char_ptr = '\0';
cleanup:
VIR_FREE(ret);
return backing_device;
}
static char *
phypGetLparProfile(virConnectPtr conn, int lpar_id)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lssyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -r prof --filter lpar_ids=%d -F name|head -n 1",
lpar_id);
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0)
VIR_FREE(ret);
return ret;
}
static int
phypGetVIOSNextSlotNumber(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
char *profile = NULL;
int slot = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (!(profile = phypGetLparProfile(conn, vios_id))) {
VIR_ERROR(_("Unable to get VIOS profile name."));
return -1;
}
virBufferAddLit(&buf, "lssyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r prof --filter "
"profile_names=%s -F virtual_eth_adapters,"
"virtual_opti_pool_id,virtual_scsi_adapters,"
"virtual_serial_adapters|sed -e 's/\"//g' -e "
"'s/,/\\n/g'|sed -e 's/\\(^[0-9][0-9]\\*\\).*$/\\1/'"
"|sort|tail -n 1", profile);
if (phypExecInt(session, &buf, conn, &slot) < 0)
return -1;
return slot + 1;
}
static int
phypCreateServerSCSIAdapter(virConnectPtr conn)
{
int result = -1;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
char *profile = NULL;
int slot = 0;
char *vios_name = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (!
(vios_name =
phypGetLparNAME(session, managed_system, vios_id, conn))) {
VIR_ERROR(_("Unable to get VIOS name"));
goto cleanup;
}
if (!(profile = phypGetLparProfile(conn, vios_id))) {
VIR_ERROR(_("Unable to get VIOS profile name."));
goto cleanup;
}
if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) {
VIR_ERROR(_("Unable to get free slot number"));
goto cleanup;
}
/* Listing all the virtual_scsi_adapter interfaces, the new adapter must
* be appended to this list
* */
virBufferAddLit(&buf, "lssyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r prof --filter lpar_ids=%d,profile_names=%s"
" -F virtual_scsi_adapters|sed -e s/\\\"//g",
vios_id, profile);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
/* Here I change the VIOS configuration to append the new adapter
* with the free slot I got with phypGetVIOSNextSlotNumber.
* */
virBufferAddLit(&buf, "chsyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r prof -i 'name=%s,lpar_id=%d,"
"\"virtual_scsi_adapters=%s,%d/server/any/any/1\"'",
vios_name, vios_id, ret, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
/* Finally I add the new scsi adapter to VIOS using the same slot
* I used in the VIOS configuration.
* */
virBufferAddLit(&buf, "chhwres -r virtualio --rsubtype scsi");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
vios_name, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
result = 0;
cleanup:
VIR_FREE(profile);
VIR_FREE(vios_name);
VIR_FREE(ret);
return result;
}
static char *
phypGetVIOSFreeSCSIAdapter(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAddLit(&buf, "lsmap -all -field svsa backing -fmt , ");
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed '/,[^.*]/d; s/,//g; q'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0)
VIR_FREE(ret);
return ret;
}
static int
phypDomainAttachDevice(virDomainPtr domain, const char *xml)
{
int result = -1;
virConnectPtr conn = domain->conn;
phyp_driverPtr phyp_driver = domain->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
char *scsi_adapter = NULL;
int slot = 0;
char *vios_name = NULL;
char *profile = NULL;
virDomainDeviceDefPtr dev = NULL;
virDomainDefPtr def = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *domain_name = NULL;
if (!(def = virDomainDefNew()))
goto cleanup;
domain_name = escape_specialcharacters(domain->name);
if (domain_name == NULL)
goto cleanup;
def->os.type = VIR_DOMAIN_OSTYPE_LINUX;
dev = virDomainDeviceDefParse(xml, def, phyp_driver->caps, NULL,
VIR_DOMAIN_DEF_PARSE_INACTIVE);
if (!dev)
goto cleanup;
if (!
(vios_name =
phypGetLparNAME(session, managed_system, vios_id, conn))) {
VIR_ERROR(_("Unable to get VIOS name"));
goto cleanup;
}
/* First, let's look for a free SCSI Adapter
* */
if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
/* If not found, let's create one.
* */
if (phypCreateServerSCSIAdapter(conn) == -1) {
VIR_ERROR(_("Unable to create new virtual adapter"));
goto cleanup;
} else {
if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) {
VIR_ERROR(_("Unable to create new virtual adapter"));
goto cleanup;
}
}
}
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "mkvdev -vdev %s -vadapter %s",
virDomainDiskGetSource(dev->data.disk), scsi_adapter);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
if (!(profile = phypGetLparProfile(conn, domain->id))) {
VIR_ERROR(_("Unable to get VIOS profile name."));
goto cleanup;
}
/* Let's get the slot number for the adapter we just created
* */
virBufferAddLit(&buf, "lshwres -r virtualio --rsubtype scsi");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" slot_num,backing_device|grep %s|cut -d, -f1",
virDomainDiskGetSource(dev->data.disk));
if (phypExecInt(session, &buf, conn, &slot) < 0)
goto cleanup;
/* Listing all the virtual_scsi_adapter interfaces, the new adapter must
* be appended to this list
* */
virBufferAddLit(&buf, "lssyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -r prof --filter lpar_ids=%d,profile_names=%s"
" -F virtual_scsi_adapters|sed -e 's/\"//g'",
vios_id, profile);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
/* Here I change the LPAR configuration to append the new adapter
* with the new slot we just created
* */
virBufferAddLit(&buf, "chsyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -r prof -i 'name=%s,lpar_id=%d,"
"\"virtual_scsi_adapters=%s,%d/client/%d/%s/0\"'",
domain_name, domain->id, ret, slot,
vios_id, vios_name);
if (phypExecInt(session, &buf, conn, &slot) < 0)
goto cleanup;
/* Finally I add the new scsi adapter to VIOS using the same slot
* I used in the VIOS configuration.
* */
virBufferAddLit(&buf, "chhwres -r virtualio --rsubtype scsi");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -p %s -o a -s %d -d 0 -a \"adapter_type=server\"",
domain_name, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL) {
VIR_ERROR(_
("Possibly you don't have IBM Tools installed in your LPAR."
"Contact your support to enable this feature."));
goto cleanup;
}
result = 0;
cleanup:
VIR_FREE(ret);
virDomainDeviceDefFree(dev);
virDomainDefFree(def);
VIR_FREE(vios_name);
VIR_FREE(scsi_adapter);
VIR_FREE(profile);
VIR_FREE(domain_name);
return result;
}
static char *
phypStorageVolGetKey(virConnectPtr conn, const char *name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lslv %s -field lvid", name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed -e 's/^LV IDENTIFIER://' -e 's/ //g'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0)
VIR_FREE(ret);
return ret;
}
static char *
phypGetStoragePoolDevice(virConnectPtr conn, char *name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lssp -detail -sp %s -field name", name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed '1d; s/ //g'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0)
VIR_FREE(ret);
return ret;
}
static unsigned long int
phypGetStoragePoolSize(virConnectPtr conn, char *name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int sp_size = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lssp -detail -sp %s -field size", name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed '1d; s/ //g'");
phypExecInt(session, &buf, conn, &sp_size);
return sp_size;
}
static char *
phypBuildVolume(virConnectPtr conn, const char *lvname, const char *spname,
unsigned int capacity)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int vios_id = phyp_driver->vios_id;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
char *ret = NULL;
int exit_status = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *key = NULL;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0) {
VIR_ERROR(_("Unable to create Volume: %s"), NULLSTR(ret));
goto cleanup;
}
key = phypStorageVolGetKey(conn, lvname);
cleanup:
VIR_FREE(ret);
return key;
}
static virStorageVolPtr
phypStorageVolLookupByName(virStoragePoolPtr pool, const char *volname)
{
char *key;
virStorageVolPtr vol;
key = phypStorageVolGetKey(pool->conn, volname);
if (key == NULL)
return NULL;
vol = virGetStorageVol(pool->conn, pool->name, volname, key, NULL, NULL);
VIR_FREE(key);
return vol;
}
static virStorageVolPtr
phypStorageVolCreateXML(virStoragePoolPtr pool,
const char *xml, unsigned int flags)
{
virCheckFlags(0, NULL);
virStorageVolDefPtr voldef = NULL;
virStoragePoolDefPtr spdef = NULL;
virStorageVolPtr vol = NULL;
virStorageVolPtr dup_vol = NULL;
char *key = NULL;
if (VIR_ALLOC(spdef) < 0)
return NULL;
/* Filling spdef manually
* */
if (pool->name != NULL) {
spdef->name = pool->name;
} else {
VIR_ERROR(_("Unable to determine storage pool's name."));
goto err;
}
if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
VIR_ERROR(_("Unable to determine storage pool's uuid."));
goto err;
}
if ((spdef->capacity =
phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
VIR_ERROR(_("Unable to determine storage pools's size."));
goto err;
}
/* Information not available */
spdef->allocation = 0;
spdef->available = 0;
spdef->source.ndevice = 1;
/*XXX source adapter not working properly, should show hdiskX */
if ((spdef->source.adapter.data.scsi_host.name =
phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
VIR_ERROR(_("Unable to determine storage pools's source adapter."));
goto err;
}
if ((voldef = virStorageVolDefParseString(spdef, xml, 0)) == NULL) {
VIR_ERROR(_("Error parsing volume XML."));
goto err;
}
/* checking if this name already exists on this system */
if ((dup_vol = phypStorageVolLookupByName(pool, voldef->name)) != NULL) {
VIR_ERROR(_("StoragePool name already exists."));
virObjectUnref(dup_vol);
goto err;
}
/* The key must be NULL, the Power Hypervisor creates a key
* in the moment you create the volume.
* */
if (voldef->key) {
VIR_ERROR(_("Key must be empty, Power Hypervisor will create one for you."));
goto err;
}
if (!voldef->target.capacity) {
VIR_ERROR(_("Capacity cannot be empty."));
goto err;
}
key = phypBuildVolume(pool->conn, voldef->name, spdef->name,
voldef->target.capacity);
if (key == NULL)
goto err;
if ((vol =
virGetStorageVol(pool->conn, pool->name, voldef->name,
key, NULL, NULL)) == NULL)
goto err;
VIR_FREE(key);
return vol;
err:
VIR_FREE(key);
virStorageVolDefFree(voldef);
virStoragePoolDefFree(spdef);
virObjectUnref(vol);
return NULL;
}
static char *
phypStorageVolGetPhysicalVolumeByStoragePool(virStorageVolPtr vol, char *sp)
{
virConnectPtr conn = vol->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lssp -detail -sp %s -field pvname", sp);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed 1d");
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0)
VIR_FREE(ret);
return ret;
}
static virStorageVolPtr
phypStorageVolLookupByPath(virConnectPtr conn, const char *volname)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
char *key = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virStorageVolPtr vol = NULL;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lslv %s -field vgname", volname);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0 || ret == NULL)
goto cleanup;
key = phypStorageVolGetKey(conn, volname);
if (key == NULL)
goto cleanup;
vol = virGetStorageVol(conn, ret, volname, key, NULL, NULL);
cleanup:
VIR_FREE(ret);
VIR_FREE(key);
return vol;
}
static int
phypGetStoragePoolUUID(virConnectPtr conn, unsigned char *uuid,
const char *name)
{
int result = -1;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lsdev -dev %s -attr vgserial_id", name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed '1,2d'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
if (memcpy(uuid, ret, VIR_UUID_BUFLEN) == NULL)
goto cleanup;
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static virStoragePoolPtr
phypStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
unsigned char uuid[VIR_UUID_BUFLEN];
if (phypGetStoragePoolUUID(conn, uuid, name) == -1)
return NULL;
return virGetStoragePool(conn, name, uuid, NULL, NULL);
}
static char *
phypStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
virStorageVolDef voldef;
virStoragePoolDef pool;
virStoragePoolPtr sp;
char *xml = NULL;
virCheckFlags(0, NULL);
memset(&voldef, 0, sizeof(virStorageVolDef));
memset(&pool, 0, sizeof(virStoragePoolDef));
sp = phypStoragePoolLookupByName(vol->conn, vol->pool);
if (!sp)
goto cleanup;
if (sp->name != NULL) {
pool.name = sp->name;
} else {
VIR_ERROR(_("Unable to determine storage sp's name."));
goto cleanup;
}
if (memcpy(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) {
VIR_ERROR(_("Unable to determine storage sp's uuid."));
goto cleanup;
}
if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) {
VIR_ERROR(_("Unable to determine storage sps's size."));
goto cleanup;
}
/* Information not available */
pool.allocation = 0;
pool.available = 0;
pool.source.ndevice = 1;
if ((pool.source.adapter.data.scsi_host.name =
phypGetStoragePoolDevice(sp->conn, sp->name)) == NULL) {
VIR_ERROR(_("Unable to determine storage sps's source adapter."));
goto cleanup;
}
if (vol->name != NULL) {
voldef.name = vol->name;
} else {
VIR_ERROR(_("Unable to determine storage pool's name."));
goto cleanup;
}
if (VIR_STRDUP(voldef.key, vol->key) < 0)
goto cleanup;
voldef.type = VIR_STORAGE_POOL_LOGICAL;
xml = virStorageVolDefFormat(&pool, &voldef);
VIR_FREE(voldef.key);
cleanup:
virObjectUnref(sp);
return xml;
}
/* The Volume Group path here will be treated as suggested in the
* email on the libvirt mailling list. As soon as I can't get the
* path for every volume, the path will be a representation in
* the form:
*
* /physical_volume/storage_pool/logical_volume
*
* */
static char *
phypStorageVolGetPath(virStorageVolPtr vol)
{
virConnectPtr conn = vol->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
char *ret = NULL;
char *path = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *pv;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lslv %s -field vgname", vol->name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAsprintf(&buf,
"|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0 || ret == NULL)
goto cleanup;
pv = phypStorageVolGetPhysicalVolumeByStoragePool(vol, ret);
if (!pv)
goto cleanup;
if (virAsprintf(&path, "/%s/%s/%s", pv, ret, vol->name) < 0)
goto cleanup;
cleanup:
VIR_FREE(ret);
VIR_FREE(path);
return path;
}
static int
phypStoragePoolListVolumes(virStoragePoolPtr pool, char **const volumes,
int nvolumes)
{
bool success = false;
virConnectPtr conn = pool->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
int got = 0;
size_t i;
char *ret = NULL;
char *volumes_list = NULL;
char *char_ptr = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|sed '1,2d'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
/* I need to parse the textual return in order to get the volumes */
if (exit_status < 0 || ret == NULL) {
goto cleanup;
} else {
volumes_list = ret;
while (got < nvolumes) {
char_ptr = strchr(volumes_list, '\n');
if (char_ptr) {
*char_ptr = '\0';
if (VIR_STRDUP(volumes[got++], volumes_list) < 0)
goto cleanup;
char_ptr++;
volumes_list = char_ptr;
} else {
break;
}
}
}
success = true;
cleanup:
if (!success) {
for (i = 0; i < got; i++)
VIR_FREE(volumes[i]);
got = -1;
}
VIR_FREE(ret);
return got;
}
static int
phypStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
virConnectPtr conn = pool->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int nvolumes = -1;
char *managed_system = phyp_driver->managed_system;
int vios_id = phyp_driver->vios_id;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "lsvg -lv %s -field lvname", pool->name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|grep -c '^.*$'");
if (phypExecInt(session, &buf, conn, &nvolumes) < 0)
return -1;
/* We need to remove 2 line from the header text output */
return nvolumes - 2;
}
static int
phypStoragePoolDestroy(virStoragePoolPtr pool)
{
int result = -1;
virConnectPtr conn = pool->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int vios_id = phyp_driver->vios_id;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
char *ret = NULL;
int exit_status = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "rmsp %s", pool->name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0) {
VIR_ERROR(_("Unable to destroy Storage Pool: %s"), NULLSTR(ret));
goto cleanup;
}
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def)
{
int result = -1;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virStoragePoolSource source = def->source;
int vios_id = phyp_driver->vios_id;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
char *ret = NULL;
int exit_status = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (source.adapter.type !=
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Only 'scsi_host' adapter is supported"));
goto cleanup;
}
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAsprintf(&buf, "mksp -f %schild %s", def->name,
source.adapter.data.scsi_host.name);
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0) {
VIR_ERROR(_("Unable to create Storage Pool: %s"), NULLSTR(ret));
goto cleanup;
}
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypConnectNumOfStoragePools(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
int nsp = -1;
char *managed_system = phyp_driver->managed_system;
int vios_id = phyp_driver->vios_id;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAddLit(&buf, "lsvg");
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
virBufferAddLit(&buf, "|grep -c '^.*$'");
phypExecInt(session, &buf, conn, &nsp);
return nsp;
}
static int
phypConnectListStoragePools(virConnectPtr conn, char **const pools, int npools)
{
bool success = false;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
int got = 0;
size_t i;
char *ret = NULL;
char *storage_pools = NULL;
char *char_ptr = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (system_type == HMC)
virBufferAsprintf(&buf, "viosvrcmd -m %s --id %d -c '",
managed_system, vios_id);
virBufferAddLit(&buf, "lsvg");
if (system_type == HMC)
virBufferAddChar(&buf, '\'');
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
/* I need to parse the textual return in order to get the storage pools */
if (exit_status < 0 || ret == NULL) {
goto cleanup;
} else {
storage_pools = ret;
while (got < npools) {
char_ptr = strchr(storage_pools, '\n');
if (char_ptr) {
*char_ptr = '\0';
if (VIR_STRDUP(pools[got++], storage_pools) < 0)
goto cleanup;
char_ptr++;
storage_pools = char_ptr;
} else {
break;
}
}
}
success = true;
cleanup:
if (!success) {
for (i = 0; i < got; i++)
VIR_FREE(pools[i]);
got = -1;
}
VIR_FREE(ret);
return got;
}
static virStoragePoolPtr
phypStoragePoolLookupByUUID(virConnectPtr conn,
const unsigned char *uuid)
{
virStoragePoolPtr sp = NULL;
int npools = 0;
int gotpools = 0;
char **pools = NULL;
size_t i = 0;
unsigned char *local_uuid = NULL;
if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0)
goto err;
if ((npools = phypConnectNumOfStoragePools(conn)) == -1)
goto err;
if (VIR_ALLOC_N(pools, npools) < 0)
goto err;
if ((gotpools = phypConnectListStoragePools(conn, pools, npools)) == -1)
goto err;
if (gotpools != npools) {
virReportOOMError();
goto err;
}
for (i = 0; i < gotpools; i++) {
if (phypGetStoragePoolUUID(conn, local_uuid, pools[i]) == -1)
continue;
if (!memcmp(local_uuid, uuid, VIR_UUID_BUFLEN)) {
sp = virGetStoragePool(conn, pools[i], uuid, NULL, NULL);
VIR_FREE(local_uuid);
VIR_FREE(pools);
if (sp)
return sp;
else
goto err;
}
}
err:
VIR_FREE(local_uuid);
VIR_FREE(pools);
return NULL;
}
static virStoragePoolPtr
phypStoragePoolCreateXML(virConnectPtr conn,
const char *xml, unsigned int flags)
{
virCheckFlags(0, NULL);
virStoragePoolDefPtr def = NULL;
virStoragePoolPtr dup_sp = NULL;
virStoragePoolPtr sp = NULL;
if (!(def = virStoragePoolDefParseString(xml)))
goto err;
/* checking if this name already exists on this system */
if ((dup_sp = phypStoragePoolLookupByName(conn, def->name)) != NULL) {
VIR_WARN("StoragePool name already exists.");
virObjectUnref(dup_sp);
goto err;
}
/* checking if ID or UUID already exists on this system */
if ((dup_sp = phypStoragePoolLookupByUUID(conn, def->uuid)) != NULL) {
VIR_WARN("StoragePool uuid already exists.");
virObjectUnref(dup_sp);
goto err;
}
if ((sp = virGetStoragePool(conn, def->name, def->uuid, NULL, NULL)) == NULL)
goto err;
if (phypBuildStoragePool(conn, def) == -1)
goto err;
return sp;
err:
virStoragePoolDefFree(def);
virObjectUnref(sp);
return NULL;
}
static char *
phypStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
{
virCheckFlags(0, NULL);
virStoragePoolDef def;
memset(&def, 0, sizeof(virStoragePoolDef));
if (pool->name != NULL) {
def.name = pool->name;
} else {
VIR_ERROR(_("Unable to determine storage pool's name."));
goto err;
}
if (memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) {
VIR_ERROR(_("Unable to determine storage pool's uuid."));
goto err;
}
if ((def.capacity =
phypGetStoragePoolSize(pool->conn, pool->name)) == -1) {
VIR_ERROR(_("Unable to determine storage pools's size."));
goto err;
}
/* Information not available */
def.allocation = 0;
def.available = 0;
def.source.ndevice = 1;
/*XXX source adapter not working properly, should show hdiskX */
if ((def.source.adapter.data.scsi_host.name =
phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) {
VIR_ERROR(_("Unable to determine storage pools's source adapter."));
goto err;
}
return virStoragePoolDefFormat(&def);
err:
return NULL;
}
static int
phypInterfaceDestroy(virInterfacePtr iface,
unsigned int flags)
{
virCheckFlags(0, -1);
phyp_driverPtr phyp_driver = iface->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int exit_status = 0;
int slot_num = 0;
int lpar_id = 0;
char *ret = NULL;
int rv = -1;
/* Getting the remote slot number */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth --level lpar "
" -F mac_addr,slot_num|"
" sed -n '/%s/ s/^.*,//p'", iface->mac);
if (phypExecInt(session, &buf, iface->conn, &slot_num) < 0)
goto cleanup;
/* Getting the remote slot number */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth --level lpar "
" -F mac_addr,lpar_id|"
" sed -n '/%s/ s/^.*,//p'", iface->mac);
if (phypExecInt(session, &buf, iface->conn, &lpar_id) < 0)
goto cleanup;
/* excluding interface */
virBufferAddLit(&buf, "chhwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth"
" --id %d -o r -s %d", lpar_id, slot_num);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, iface->conn, false);
if (exit_status < 0 || ret != NULL)
goto cleanup;
rv = 0;
cleanup:
VIR_FREE(ret);
return rv;
}
static virInterfacePtr
phypInterfaceDefineXML(virConnectPtr conn, const char *xml,
unsigned int flags)
{
virCheckFlags(0, NULL);
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int exit_status = 0;
int slot = 0;
char *ret = NULL;
char name[PHYP_IFACENAME_SIZE];
char mac[PHYP_MAC_SIZE];
virInterfaceDefPtr def;
virInterfacePtr result = NULL;
if (!(def = virInterfaceDefParseString(xml)))
goto cleanup;
/* Now need to get the next free slot number */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype slot --level slot"
" -Fslot_num --filter lpar_names=%s"
" |sort|tail -n 1", def->name);
if (phypExecInt(session, &buf, conn, &slot) < 0)
goto cleanup;
/* The next free slot itself: */
slot++;
/* Now adding the new network interface */
virBufferAddLit(&buf, "chhwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth"
" -p %s -o a -s %d -a port_vlan_id=1,"
"ieee_virtual_eth=0", def->name, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret != NULL)
goto cleanup;
/* Need to sleep a little while to wait for the HMC to
* complete the execution of the command.
* */
sleep(1);
/* Getting the new interface name */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype slot --level slot"
" |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
"s/^.*drc_name=//'", def->name, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL) {
/* roll back and excluding interface if error*/
virBufferAddLit(&buf, "chhwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth"
" -p %s -o r -s %d", def->name, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
goto cleanup;
}
memcpy(name, ret, PHYP_IFACENAME_SIZE-1);
/* Getting the new interface mac addr */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
"-r virtualio --rsubtype eth --level lpar "
" |sed '/lpar_name=%s/!d; /slot_num=%d/!d; "
"s/^.*mac_addr=//'", def->name, slot);
VIR_FREE(ret);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
memcpy(mac, ret, PHYP_MAC_SIZE-1);
result = virGetInterface(conn, name, mac);
cleanup:
VIR_FREE(ret);
virInterfaceDefFree(def);
return result;
}
static virInterfacePtr
phypInterfaceLookupByName(virConnectPtr conn, const char *name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int exit_status = 0;
char *ret = NULL;
int slot = 0;
int lpar_id = 0;
char mac[PHYP_MAC_SIZE];
virInterfacePtr result = NULL;
/*Getting the slot number for the interface */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype slot --level slot "
" -F drc_name,slot_num |"
" sed -n '/%s/ s/^.*,//p'", name);
if (phypExecInt(session, &buf, conn, &slot) < 0)
goto cleanup;
/*Getting the lpar_id for the interface */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype slot --level slot "
" -F drc_name,lpar_id |"
" sed -n '/%s/ s/^.*,//p'", name);
if (phypExecInt(session, &buf, conn, &lpar_id) < 0)
goto cleanup;
/*Getting the interface mac */
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth --level lpar "
" -F lpar_id,slot_num,mac_addr|"
" sed -n '/%d,%d/ s/^.*,//p'", lpar_id, slot);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0 || ret == NULL)
goto cleanup;
memcpy(mac, ret, PHYP_MAC_SIZE-1);
result = virGetInterface(conn, name, ret);
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypInterfaceIsActive(virInterfacePtr iface)
{
phyp_driverPtr phyp_driver = iface->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int state = -1;
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
" -r virtualio --rsubtype eth --level lpar "
" -F mac_addr,state |"
" sed -n '/%s/ s/^.*,//p'", iface->mac);
phypExecInt(session, &buf, iface->conn, &state);
return state;
}
static int
phypConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int vios_id = phyp_driver->vios_id;
int exit_status = 0;
int got = 0;
size_t i;
char *ret = NULL;
char *networks = NULL;
char *char_ptr = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
bool success = false;
virBufferAddLit(&buf, "lshwres");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r virtualio --rsubtype slot --level slot|"
" sed '/eth/!d; /lpar_id=%d/d; s/^.*drc_name=//g'",
vios_id);
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
/* I need to parse the textual return in order to get the network
* interfaces */
if (exit_status < 0 || ret == NULL)
goto cleanup;
networks = ret;
while (got < nnames) {
char_ptr = strchr(networks, '\n');
if (char_ptr) {
*char_ptr = '\0';
if (VIR_STRDUP(names[got++], networks) < 0)
goto cleanup;
char_ptr++;
networks = char_ptr;
} else {
break;
}
}
cleanup:
if (!success) {
for (i = 0; i < got; i++)
VIR_FREE(names[i]);
}
VIR_FREE(ret);
return got;
}
static int
phypConnectNumOfInterfaces(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
int system_type = phyp_driver->system_type;
int vios_id = phyp_driver->vios_id;
int nnets = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lshwres ");
if (system_type == HMC)
virBufferAsprintf(&buf, "-m %s ", managed_system);
virBufferAsprintf(&buf,
"-r virtualio --rsubtype eth --level lpar|"
"grep -v lpar_id=%d|grep -c lpar_name", vios_id);
phypExecInt(session, &buf, conn, &nnets);
return nnets;
}
static int
phypGetLparState(virConnectPtr conn, unsigned int lpar_id)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *ret = NULL;
int exit_status = 0;
char *managed_system = phyp_driver->managed_system;
int state = VIR_DOMAIN_NOSTATE;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lssyscfg -r lpar");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -F state --filter lpar_ids=%d", lpar_id);
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0 || ret == NULL)
goto cleanup;
if (STREQ(ret, "Running"))
state = VIR_DOMAIN_RUNNING;
else if (STREQ(ret, "Not Activated"))
state = VIR_DOMAIN_SHUTOFF;
else if (STREQ(ret, "Shutting Down"))
state = VIR_DOMAIN_SHUTDOWN;
cleanup:
VIR_FREE(ret);
return state;
}
/* XXX - is this needed? */
static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED;
static int
phypDiskType(virConnectPtr conn, char *backing_device)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *ret = NULL;
int exit_status = 0;
char *managed_system = phyp_driver->managed_system;
int vios_id = phyp_driver->vios_id;
int disk_type = -1;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "viosvrcmd");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -p %d -c \"lssp -field name type "
"-fmt , -all|sed -n '/%s/ {\n s/^.*,//\n p\n}'\"",
vios_id, backing_device);
ret = phypExecBuffer(session, &buf, &exit_status, conn, true);
if (exit_status < 0 || ret == NULL)
goto cleanup;
if (STREQ(ret, "LVPOOL"))
disk_type = VIR_STORAGE_TYPE_BLOCK;
else if (STREQ(ret, "FBPOOL"))
disk_type = VIR_STORAGE_TYPE_FILE;
cleanup:
VIR_FREE(ret);
return disk_type;
}
static int
phypConnectNumOfDefinedDomains(virConnectPtr conn)
{
return phypConnectNumOfDomainsGeneric(conn, 1);
}
static int
phypConnectNumOfDomains(virConnectPtr conn)
{
return phypConnectNumOfDomainsGeneric(conn, 0);
}
static int
phypConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
return phypConnectListDomainsGeneric(conn, ids, nids, 0);
}
static int
phypConnectListDefinedDomains(virConnectPtr conn, char **const names, int nnames)
{
bool success = false;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
int got = 0;
size_t i;
char *ret = NULL;
char *domains = NULL;
char *char_ptr = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "lssyscfg -r lpar");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAddLit(&buf, " -F name,state"
"|sed -n '/Not Activated/ {\n s/,.*$//\n p\n}'");
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
/* I need to parse the textual return in order to get the domains */
if (exit_status < 0 || ret == NULL) {
goto cleanup;
} else {
domains = ret;
while (got < nnames) {
char_ptr = strchr(domains, '\n');
if (char_ptr) {
*char_ptr = '\0';
if (VIR_STRDUP(names[got++], domains) < 0)
goto cleanup;
char_ptr++;
domains = char_ptr;
} else {
break;
}
}
}
success = true;
cleanup:
if (!success) {
for (i = 0; i < got; i++)
VIR_FREE(names[i]);
got = -1;
}
VIR_FREE(ret);
return got;
}
static virDomainPtr
phypDomainLookupByName(virConnectPtr conn, const char *lpar_name)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virDomainPtr dom = NULL;
int lpar_id = 0;
char *managed_system = phyp_driver->managed_system;
unsigned char lpar_uuid[VIR_UUID_BUFLEN];
lpar_id = phypGetLparID(session, managed_system, lpar_name, conn);
if (lpar_id == -1)
return NULL;
if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
return NULL;
dom = virGetDomain(conn, lpar_name, lpar_uuid);
if (dom)
dom->id = lpar_id;
return dom;
}
static virDomainPtr
phypDomainLookupByID(virConnectPtr conn, int lpar_id)
{
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virDomainPtr dom = NULL;
char *managed_system = phyp_driver->managed_system;
unsigned char lpar_uuid[VIR_UUID_BUFLEN];
char *lpar_name = phypGetLparNAME(session, managed_system, lpar_id,
conn);
if (phypGetLparUUID(lpar_uuid, lpar_id, conn) == -1)
goto cleanup;
dom = virGetDomain(conn, lpar_name, lpar_uuid);
if (dom)
dom->id = lpar_id;
cleanup:
VIR_FREE(lpar_name);
return dom;
}
static char *
phypDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
{
phyp_driverPtr phyp_driver = dom->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virDomainDef def;
char *managed_system = phyp_driver->managed_system;
unsigned long long memory;
unsigned int vcpus;
/* Flags checked by virDomainDefFormat */
memset(&def, 0, sizeof(virDomainDef));
def.virtType = VIR_DOMAIN_VIRT_PHYP;
def.id = dom->id;
char *lpar_name = phypGetLparNAME(session, managed_system, def.id,
dom->conn);
if (lpar_name == NULL) {
VIR_ERROR(_("Unable to determine domain's name."));
goto err;
}
if (phypGetLparUUID(def.uuid, dom->id, dom->conn) == -1) {
VIR_ERROR(_("Unable to generate random uuid."));
goto err;
}
if ((memory = phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0) {
VIR_ERROR(_("Unable to determine domain's max memory."));
goto err;
}
virDomainDefSetMemoryTotal(&def, memory);
if ((def.mem.cur_balloon =
phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0) {
VIR_ERROR(_("Unable to determine domain's memory."));
goto err;
}
if ((vcpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
VIR_ERROR(_("Unable to determine domain's CPU."));
goto err;
}
if (virDomainDefSetVcpusMax(&def, vcpus, phyp_driver->xmlopt) < 0)
goto err;
if (virDomainDefSetVcpus(&def, vcpus) < 0)
goto err;
return virDomainDefFormat(&def, phyp_driver->caps,
virDomainDefFormatConvertXMLFlags(flags));
err:
return NULL;
}
static int
phypDomainResume(virDomainPtr dom)
{
int result = -1;
phyp_driverPtr phyp_driver = dom->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "chsysstate");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r lpar -o on --id %d -f %s",
dom->id, dom->name);
ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
if (exit_status < 0)
goto cleanup;
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypDomainReboot(virDomainPtr dom, unsigned int flags)
{
int result = -1;
virConnectPtr conn = dom->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virCheckFlags(0, -1);
virBufferAddLit(&buf, "chsysstate");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf,
" -r lpar -o shutdown --id %d --immed --restart",
dom->id);
ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
if (exit_status < 0)
goto cleanup;
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypDomainShutdown(virDomainPtr dom)
{
int result = -1;
virConnectPtr conn = dom->conn;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "chsysstate");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r lpar -o shutdown --id %d", dom->id);
ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
if (exit_status < 0)
goto cleanup;
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
phyp_driverPtr phyp_driver = dom->conn->privateData;
char *managed_system = phyp_driver->managed_system;
info->state = phypGetLparState(dom->conn, dom->id);
if ((info->maxMem =
phypGetLparMem(dom->conn, managed_system, dom->id, 0)) == 0)
VIR_WARN("Unable to determine domain's max memory.");
if ((info->memory =
phypGetLparMem(dom->conn, managed_system, dom->id, 1)) == 0)
VIR_WARN("Unable to determine domain's memory.");
if ((info->nrVirtCpu =
phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
VIR_WARN("Unable to determine domain's CPU.");
return 0;
}
static int
phypDomainGetState(virDomainPtr dom,
int *state,
int *reason,
unsigned int flags)
{
virCheckFlags(0, -1);
*state = phypGetLparState(dom->conn, dom->id);
if (reason)
*reason = 0;
return 0;
}
static int
phypDomainDestroyFlags(virDomainPtr dom,
unsigned int flags)
{
int result = -1;
phyp_driverPtr phyp_driver = dom->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
char *ret = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virCheckFlags(0, -1);
virBufferAddLit(&buf, "rmsyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r lpar --id %d", dom->id);
ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
if (exit_status < 0)
goto cleanup;
if (phypUUIDTable_RemLpar(dom->conn, dom->id) == -1)
goto cleanup;
dom->id = -1;
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static int
phypDomainDestroy(virDomainPtr dom)
{
return phypDomainDestroyFlags(dom, 0);
}
static int
phypBuildLpar(virConnectPtr conn, virDomainDefPtr def)
{
int result = -1;
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
char *ret = NULL;
int exit_status = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (!def->mem.cur_balloon) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Field <currentMemory> on the domain XML file is "
"missing or has invalid value"));
goto cleanup;
}
if (!virDomainDefGetMemoryInitial(def)) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Field <memory> on the domain XML file is missing or "
"has invalid value"));
goto cleanup;
}
if (def->ndisks < 1) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Domain XML must contain at least one <disk> element."));
goto cleanup;
}
if (!virDomainDiskGetSource(def->disks[0])) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Field <src> under <disk> on the domain XML file is "
"missing."));
goto cleanup;
}
virBufferAddLit(&buf, "mksyscfg");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " -r lpar -p %s -i min_mem=%lld,desired_mem=%lld,"
"max_mem=%lld,desired_procs=%u,virtual_scsi_adapters=%s",
def->name, def->mem.cur_balloon,
def->mem.cur_balloon,
virDomainDefGetMemoryInitial(def),
virDomainDefGetVcpus(def),
virDomainDiskGetSource(def->disks[0]));
ret = phypExecBuffer(session, &buf, &exit_status, conn, false);
if (exit_status < 0) {
VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), NULLSTR(ret));
goto cleanup;
}
if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) {
VIR_ERROR(_("Unable to add LPAR to the table"));
goto cleanup;
}
result = 0;
cleanup:
VIR_FREE(ret);
return result;
}
static virDomainPtr
phypDomainCreateXML(virConnectPtr conn,
const char *xml, unsigned int flags)
{
virCheckFlags(0, NULL);
phyp_driverPtr phyp_driver = conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
virDomainDefPtr def = NULL;
virDomainPtr dom = NULL;
uuid_tablePtr uuid_table = phyp_driver->uuid_table;
lparPtr *lpars = uuid_table->lpars;
size_t i = 0;
char *managed_system = phyp_driver->managed_system;
unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
if (flags & VIR_DOMAIN_START_VALIDATE)
parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
if (!(def = virDomainDefParseString(xml, phyp_driver->caps,
phyp_driver->xmlopt,
parse_flags)))
goto err;
/* checking if this name already exists on this system */
if (phypGetLparID(session, managed_system, def->name, conn) != -1) {
VIR_WARN("LPAR name already exists.");
goto err;
}
/* checking if ID or UUID already exists on this system */
for (i = 0; i < uuid_table->nlpars; i++) {
if (lpars[i]->id == def->id || lpars[i]->uuid == def->uuid) {
VIR_WARN("LPAR ID or UUID already exists.");
goto err;
}
}
if ((dom = virGetDomain(conn, def->name, def->uuid)) == NULL)
goto err;
if (phypBuildLpar(conn, def) == -1)
goto err;
if (phypDomainResume(dom) == -1)
goto err;
return dom;
err:
virDomainDefFree(def);
virObjectUnref(dom);
return NULL;
}
static char *
phypConnectGetCapabilities(virConnectPtr conn)
{
phyp_driverPtr phyp_driver = conn->privateData;
return virCapabilitiesFormatXML(phyp_driver->caps);
}
static int
phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
unsigned int flags)
{
phyp_driverPtr phyp_driver = dom->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
int system_type = phyp_driver->system_type;
char *managed_system = phyp_driver->managed_system;
int exit_status = 0;
char *ret = NULL;
char operation;
unsigned long ncpus = 0;
unsigned int amount = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
if (flags != VIR_DOMAIN_VCPU_LIVE) {
virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
return -1;
}
if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0)
return 0;
if (nvcpus > phypDomainGetMaxVcpus(dom)) {
VIR_ERROR(_("You are trying to set a number of CPUs bigger than "
"the max possible."));
return 0;
}
if (ncpus > nvcpus) {
operation = 'r';
amount = nvcpus - ncpus;
} else if (ncpus < nvcpus) {
operation = 'a';
amount = nvcpus - ncpus;
} else {
return 0;
}
virBufferAddLit(&buf, "chhwres -r proc");
if (system_type == HMC)
virBufferAsprintf(&buf, " -m %s", managed_system);
virBufferAsprintf(&buf, " --id %d -o %c --procunits %d 2>&1 |sed "
"-e 's/^.*\\([0-9][0-9]*.[0-9][0-9]*\\).*$/\\1/'",
dom->id, operation, amount);
ret = phypExecBuffer(session, &buf, &exit_status, dom->conn, false);
if (exit_status < 0) {
VIR_ERROR(_
("Possibly you don't have IBM Tools installed in your LPAR."
" Contact your support to enable this feature."));
}
VIR_FREE(ret);
return 0;
}
static int
phypDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}
static int
phypDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
phyp_driverPtr phyp_driver = dom->conn->privateData;
LIBSSH2_SESSION *session = phyp_driver->session;
char *managed_system = phyp_driver->managed_system;
char *lpar_name = NULL;
int ret = -1;
virCheckFlags(0, -1);
lpar_name = phypGetLparNAME(session, managed_system, dom->id, dom->conn);
if (lpar_name == NULL) {
VIR_ERROR(_("Unable to determine domain's name."));
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(lpar_name);
return ret;
}
static virHypervisorDriver phypHypervisorDriver = {
.name = "PHYP",
.connectOpen = phypConnectOpen, /* 0.7.0 */
.connectClose = phypConnectClose, /* 0.7.0 */
.connectGetCapabilities = phypConnectGetCapabilities, /* 0.7.3 */
.connectListDomains = phypConnectListDomains, /* 0.7.0 */
.connectNumOfDomains = phypConnectNumOfDomains, /* 0.7.0 */
.domainCreateXML = phypDomainCreateXML, /* 0.7.3 */
.domainLookupByID = phypDomainLookupByID, /* 0.7.0 */
.domainLookupByName = phypDomainLookupByName, /* 0.7.0 */
.domainResume = phypDomainResume, /* 0.7.0 */
.domainShutdown = phypDomainShutdown, /* 0.7.0 */
.domainReboot = phypDomainReboot, /* 0.9.1 */
.domainDestroy = phypDomainDestroy, /* 0.7.3 */
.domainDestroyFlags = phypDomainDestroyFlags, /* 0.9.4 */
.domainGetInfo = phypDomainGetInfo, /* 0.7.0 */
.domainGetState = phypDomainGetState, /* 0.9.2 */
.domainSetVcpus = phypDomainSetVcpus, /* 0.7.3 */
.domainSetVcpusFlags = phypDomainSetVcpusFlags, /* 0.8.5 */
.domainGetVcpusFlags = phypDomainGetVcpusFlags, /* 0.8.5 */
.domainGetMaxVcpus = phypDomainGetMaxVcpus, /* 0.7.3 */
.domainGetXMLDesc = phypDomainGetXMLDesc, /* 0.7.0 */
.connectListDefinedDomains = phypConnectListDefinedDomains, /* 0.7.0 */
.connectNumOfDefinedDomains = phypConnectNumOfDefinedDomains, /* 0.7.0 */
.domainAttachDevice = phypDomainAttachDevice, /* 0.8.2 */
.connectIsEncrypted = phypConnectIsEncrypted, /* 0.7.3 */
.connectIsSecure = phypConnectIsSecure, /* 0.7.3 */
.domainIsUpdated = phypDomainIsUpdated, /* 0.8.6 */
.connectIsAlive = phypConnectIsAlive, /* 0.9.8 */
.domainHasManagedSaveImage = phypDomainHasManagedSaveImage, /* 1.2.13 */
};
static virStorageDriver phypStorageDriver = {
.connectNumOfStoragePools = phypConnectNumOfStoragePools, /* 0.8.2 */
.connectListStoragePools = phypConnectListStoragePools, /* 0.8.2 */
.storagePoolLookupByName = phypStoragePoolLookupByName, /* 0.8.2 */
.storagePoolLookupByUUID = phypStoragePoolLookupByUUID, /* 0.8.2 */
.storagePoolCreateXML = phypStoragePoolCreateXML, /* 0.8.2 */
.storagePoolDestroy = phypStoragePoolDestroy, /* 0.8.2 */
.storagePoolGetXMLDesc = phypStoragePoolGetXMLDesc, /* 0.8.2 */
.storagePoolNumOfVolumes = phypStoragePoolNumOfVolumes, /* 0.8.2 */
.storagePoolListVolumes = phypStoragePoolListVolumes, /* 0.8.2 */
.storageVolLookupByName = phypStorageVolLookupByName, /* 0.8.2 */
.storageVolLookupByPath = phypStorageVolLookupByPath, /* 0.8.2 */
.storageVolCreateXML = phypStorageVolCreateXML, /* 0.8.2 */
.storageVolGetXMLDesc = phypStorageVolGetXMLDesc, /* 0.8.2 */
.storageVolGetPath = phypStorageVolGetPath, /* 0.8.2 */
};
static virInterfaceDriver phypInterfaceDriver = {
.connectNumOfInterfaces = phypConnectNumOfInterfaces, /* 0.9.1 */
.connectListInterfaces = phypConnectListInterfaces, /* 0.9.1 */
.interfaceLookupByName = phypInterfaceLookupByName, /* 0.9.1 */
.interfaceDefineXML = phypInterfaceDefineXML, /* 0.9.1 */
.interfaceDestroy = phypInterfaceDestroy, /* 0.9.1 */
.interfaceIsActive = phypInterfaceIsActive /* 0.9.1 */
};
static virConnectDriver phypConnectDriver = {
.hypervisorDriver = &phypHypervisorDriver,
.interfaceDriver = &phypInterfaceDriver,
.storageDriver = &phypStorageDriver,
};
int
phypRegister(void)
{
return virRegisterConnectDriver(&phypConnectDriver,
false);
}