/*
* Copyright (C) 2010-2015 Red Hat, Inc.
* Copyright IBM Corp. 2009
*
* phyp_driver.c: ssh layer to access Power Hypervisors
*
* 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
* .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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 "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, G_N_ELEMENTS(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);
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;
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 topology causing
* unexpected failures. We don't want to break the QEMU
* driver in this scenario, so log errors & carry on
*/
if (virCapabilitiesInitNUMA(caps) < 0) {
virCapabilitiesFreeNUMAInfo(caps);
VIR_WARN
("Failed to query host NUMA topology, disabling NUMA capabilities");
}
if (virCapabilitiesInitCaches(caps) < 0)
VIR_WARN("Failed to get host CPU cache info");
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;
remote_file = g_strdup_printf("/home/%s/libvirt_uuid_table",
NULLSTR(conn->uri->user));
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:
VIR_FREE(remote_file);
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;
remote_file = g_strdup_printf("/home/%s/libvirt_uuid_table",
NULLSTR(conn->uri->user));
/* 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;
pubkey = g_strdup_printf("%s/.ssh/id_rsa.pub", userhome);
pvtkey = g_strdup_printf("%s/.ssh/id_rsa", userhome);
if (conn->uri->user != NULL) {
username = g_strdup(conn->uri->user);
} else {
if (!(username = virAuthGetUsername(conn, auth, "ssh", NULL,
conn->uri->server)))
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 (!(password = virAuthGetPassword(conn, auth, "ssh", username,
conn->uri->server)))
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,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque,
void *parseOpaque G_GNUC_UNUSED)
{
phyp_driverPtr driver = opaque;
if (!virCapabilitiesDomainSupported(driver->caps, def->os.type,
def->os.arch,
def->virtType))
return -1;
return 0;
}
static int
phypDomainDeviceDefPostParse(virDomainDeviceDefPtr dev G_GNUC_UNUSED,
const virDomainDef *def G_GNUC_UNUSED,
unsigned int parseFlags G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
void *parseOpaque G_GNUC_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 G_GNUC_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 (VIR_ALLOC(phyp_driver) < 0)
goto failure;
phyp_driver->sock = -1;
if (VIR_ALLOC(uuid_table) < 0)
goto failure;
if (conn->uri->path[0] != '\0') {
/* need to shift one byte in order to remove the first "/" of URI component */
managed_system = g_strdup(conn->uri->path + (conn->uri->path[0] == '/'));
/* 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;
virPhypDriverDomainDefParserConfig.priv = phyp_driver;
if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(&virPhypDriverDomainDefParserConfig,
NULL, NULL, 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 G_GNUC_UNUSED)
{
/* Phyp uses an SSH tunnel, so is always encrypted */
return 1;
}
static int
phypConnectIsSecure(virConnectPtr conn G_GNUC_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 G_GNUC_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 *)
G_GNUC_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;
backing_device = g_strdup(char_ptr);
} else {
backing_device = g_steal_pointer(&ret);
}
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
phypDomainAttachDeviceFlags(virDomainPtr domain,
const char *xml,
unsigned int flags)
{
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;
virCheckFlags(0, -1);
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, 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 int
phypDomainAttachDevice(virDomainPtr domain, const char *xml)
{
return phypDomainAttachDeviceFlags(domain, xml, 0);
}
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);
virStorageVolPtr vol = NULL;
virStorageVolPtr dup_vol = NULL;
char *key = NULL;
g_autoptr(virStorageVolDef) voldef = NULL;
g_autoptr(virStoragePoolDef) spdef = 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);
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;
}
voldef.key = g_strdup(vol->key);
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;
path = g_strdup_printf("/%s/%s/%s", pv, ret, vol->name);
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';
volumes[got++] = g_strdup(volumes_list);
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_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';
pools[got++] = g_strdup(storage_pools);
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';
names[got++] = g_strdup(networks);
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 *) G_GNUC_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';
names[got++] = g_strdup(domains);
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;
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;
return virGetDomain(conn, lpar_name, lpar_uuid, lpar_id);
}
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, 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;
virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
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->xmlopt, 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
phypDomainShutdownFlags(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", 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)
{
return phypDomainShutdownFlags(dom, 0);
}
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 on the domain XML file is "
"missing or has invalid value"));
goto cleanup;
}
if (!virDomainDefGetMemoryInitial(def)) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Field 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 element."));
goto cleanup;
}
if (!virDomainDiskGetSource(def->disks[0])) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Field under 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,
NULL,
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, def->id)) == 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 */
.domainShutdownFlags = phypDomainShutdownFlags, /* 5.6.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 */
.domainAttachDeviceFlags = phypDomainAttachDeviceFlags, /* 5.6.0 */
.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 = {
.remoteOnly = true,
.uriSchemes = (const char *[]){ "phyp", NULL },
.hypervisorDriver = &phypHypervisorDriver,
.interfaceDriver = &phypInterfaceDriver,
.storageDriver = &phypStorageDriver,
};
int
phypRegister(void)
{
return virRegisterConnectDriver(&phypConnectDriver,
false);
}