> > The only feature we have until now is just to list the LPARs ("Logical > > PARtitions", the IBM virtual machines for Power). Once this code is safe > > and goot enough, the implementations of new commands will be much faster > > and easier. > > I think for a initial commit of the driver I'd like to see it able > to generate an XML description for each guest domain on the system. > And also implement the listing of inactive domains. > > So these three extra driver API points: > > > NULL, /* domainDumpXML */ > > NULL, /* listDefinedDomains */ > > NULL, /* numOfDefinedDomains */ > > This would be enough to make the 2 core virsh commands work > fully with the drier > > virsh list --all > virsh dumpxml GUEST I just opened a new thread in order to discuss the usage of this function and UUID. > > /*starting ssh connection */ > > if (ssh_connect(session)) { > > virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, > > NULL, NULL, NULL, 0, 0, "%s", > > _("connection failed")); > > ssh_disconnect(session); > > ssh_finalize(); > > } > > > > /*trying to use pub key */ > > if ((ssh_auth = > > ssh_userauth_autopubkey(session, NULL)) == SSH_AUTH_ERROR) { > > virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, > > NULL, NULL, NULL, 0, 0, "%s : %s", > > _("authenticating with public key ailed"), > > ssh_get_error(session)); > > } > > > > > > if ((banner = ssh_get_issue_banner(session))) { > > virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, > > NULL, NULL, NULL, 0, 0, "%s", banner); > > VIR_FREE(banner); > > } > > If you call virRaiseError in these 3 cases, then you need to also > return from this function with VIR_DRV_OPEN_ERROR so caller can > see it failed. If these are merely warnings, and you do intend > to continue, then VIR_WARN() (from logging.h is most appropriate) I adjusted the level of problem as I thought that would be more consistent. (the fixed phyp_driver.c is attatched) > > > > char *password = creds[0].result; > > char *username = conn->uri->user; > > > > if (ssh_userauth_password(session, username, password) != > > SSH_AUTH_SUCCESS) { > > virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, > > VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s : % > > s", > > "authentication failed", > > ssh_get_error(session)); > > ssh_disconnect(session); > > memset(password, 0, strlen(password)); > > memset(username, 0, strlen(username)); > > goto err; > > } else > > goto exec; > > I imagine you want to blank out the password in both branches > of that if() statement. Blanking the username is redundant > since its permanently stored in the xmlURIPtr Agreed and fixed. > > > } else > > goto exec; > > > > err: > > exit_status = SSH_CONN_ERR; > > return VIR_DRV_OPEN_DECLINED; > > You should use OPEN_ERROR in this location. Only use OPEN_DECLINED > if the initial conn->uri was not for the phy:// driver (you already > handle this scenario correctly earlier on in this method) ok. > > > > > /* this functions is the layer that manipulates the ssh channel itself > > * and executes the commands on the remote machine */ > > static char * > > __inner_exec_command(SSH_SESSION * session, char *cmd, int *exit_status) > > Having an exit_status var here is overkill, since the caller > already checks the return value for NULL and can thus detect > error there. The exit_status here refers to the exit status of the command executed remotely and not the return of the function. The return of the '__inner_exec_command' function is NULL or the textual return from the remote command. > > > { > > CHANNEL *channel = channel_new(session); > > char buf[4096] = { 0 }; > > virBuffer tex_ret = VIR_BUFFER_INITIALIZER; > > > > int ret = 0; > > > > if (channel_open_session(channel) == SSH_ERROR) > > goto err; > > > > if (channel_request_exec(channel, cmd) == SSH_ERROR) > > goto err; > > > > if (channel_send_eof(channel) == SSH_ERROR) > > goto err; > > It is desired to have each of these errors virRaiseError > with the specific details of what went wrong. Agreed. Actually this was at my todo list and its done now. > > > > > while (channel && channel_is_open(channel)) { > > ret = channel_read(channel, buf, sizeof(buf), 0); > > if (ret < 0) > > goto err; > > > > if (ret == 0) { > > channel_send_eof(channel); > > if (channel_get_exit_status(channel) == -1) > > goto err; > > > > if (channel_close(channel) == SSH_ERROR) > > goto err; > > > > channel_free(channel); > > channel = NULL; > > goto exit; > > } > > > > virBufferAdd(&tex_ret, (const char *) &buf, sizeof(buf)); > > } > > > > err: > > (*exit_status) = SSH_CMD_ERR; > > return NULL; > > Here you need to free the buffer > > char *buf = virBufferContentAndReset(&tex_ret) > VIR_FREE(buf); > > > > > exit: > > return virBufferContentAndReset(&tex_ret); > > This also needs a check for OOM, so you can report ther error > message > > if (virBufferError(&tex_ret)) > virReportOOMError(conn); > return NULL; > return virBufferContentAndReset(&tex_ret) In order to check virBufferError and virReportOOMError I added 'virConnectPtr conn' as parameter to __inner_exec_command function. Everything is recorded now. > > > > /* return the lpar name given a lpar_id and a managed system name */ > > static char * > > phypGetLparNAME(SSH_SESSION * ssh_session, const char *managed_system, > > unsigned int lpar_id, int *exit_status) > > { > > char *cmd; > > > > if (virAsprintf(&cmd, > > "lssyscfg -r lpar -m %s --filter lpar_ids=%d -F > > name", > > managed_system, lpar_id) < 0) > > return NULL; > > > > char *lpar_name = > > __inner_exec_command(ssh_session, cmd, (int *) exit_status); > > This is forgetting to check lpar_name for NULL. > > > > > char *striped_lpar_name = (char *) malloc(sizeof(lpar_name) - 1); > > > > stripNewline(striped_lpar_name, lpar_name); > > malloc()/free/calloc/realloc should all be avoided, in favour > of using the VIR_ALLOC/ALLOC_N/REALLOC_N/FREE comamnds instead. > > In this case though, the malloc() is overkill - just modify > the original string, rather than reallocating it 1 byte > shorter. > > eg replace those 2 lines with > > char *nl = strchr(lpar_name, '\n'); > if (nl) *nl = '\0'; These two lines opened my mind yesterday and made me remove those two ugly function. I wasn't happy with them and I was trying other ways to handle those chars. The new "stripPath" is reduced to: char *managed_system = conn->uri->path; if (managed_system[0] == '/') managed_system++; And the new "stripNewline" I did as you told me: char *char_ptr = strchr(lpar_uuid, '\n'); if (char_ptr) *char_ptr = '\0'; > > > > /* return the lpar_uuid (which for now is its logical serial number) > > * given a lpar id and a managed system name */ > > static unsigned char * > > phypGetLparUUID(SSH_SESSION * ssh_session, const char *managed_system, > > unsigned int lpar_id, int *exit_status) > > { > > char *cmd; > > > > if (virAsprintf(&cmd, > > "lssyscfg -r lpar -m %s --filter lpar_ids=%d -F > > logical_serial_num", > > managed_system, lpar_id) < 0) > > return NULL; > > unsigned char *lpar_uuid = > > (unsigned char *) __inner_exec_command(ssh_session, cmd, > > (int *) exit_status); > > > > unsigned char *striped_lpar_uuid = > > (unsigned char *) malloc(sizeof(lpar_uuid) - 1); > > stripNewline((char *) striped_lpar_uuid, (char *) lpar_uuid); > > When a UUID is declared 'unsigned char*', this is intended to > be the raw binary 16 byte array. So just casting from a NULL > terminated string is not sufficient. Instead call into the > virUUIDParse() method from src/uuid.h to convert from NULL > terminated string, to raw byte array. This is not fixed in the phyp_driver.c that is attatched here, but will be fixed as soon as we discuss that UUID issue in the thread is just opened. > > > > static virDomainPtr > > phypDomainLookupByName(virConnectPtr conn, const char *name) > > { > > SSH_SESSION *ssh_session = conn->privateData; > > virDomainPtr dom = NULL; > > > > int lpar_id = 0; > > int exit_status = 0; > > char managed_system[strlen(conn->uri->path) - 1]; > > This is allocating a variable length array on the stack which > is something its best to avoid - prefer to allocate on the > heap instead. This also made me think a better way to handle managed_system without this stack allocation. Also fixed. > > void > > stripPath(char *striped_path, char *path) > > { > > unsigned int i = 0; > > > > for (i = 1; i <= strlen(path); i++) > > striped_path[i - 1] = path[i]; > > striped_path[i] = '\0'; > > return; > > } > > > I'm not convinced that the compiler will optimize this loop > to avoid it being O(n^2) on strlen(path). It can be simplified > by just calling strcpy, or memmove()'ing the original string > inplace. Fixed! > > > /* function to strip out the '\n' of the end of some string */ > > void > > stripNewline(char *striped_string, char *string) > > { > > unsigned int i = 0; > > > > for (i = 0; i <= strlen(string); i++) > > if (string[i] != '\n') > > striped_string[i] = string[i]; > > striped_string[strlen(string) - 1] = '\0'; > > return; > > } > > This can also be done in-place with a simple strchr() call Fixed! -- Eduardo Otubo Software Engineer Linux Technology Center IBM Systems & Technology Group Mobile: +55 19 8135 0885 otubo@xxxxxxxxxxxxxxxxxx
/* * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <config.h> #include <sys/types.h> #include <limits.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <stdio.h> #include <libssh/libssh.h> #include "internal.h" #include "util.h" #include "datatypes.h" #include "buf.h" #include "memory.h" #include "logging.h" #include "driver.h" #include "libvirt/libvirt.h" #include "virterror_internal.h" #include "uuid.h" #include "phyp_driver.h" #define VIR_FROM_THIS VIR_FROM_PHYP /* * TODO: I still need to implement a way to distinguish * an HMC from an IVM * */ static virDrvOpenStatus phypOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) { int ssh_auth = 0, exit_status = 0; char *banner; SSH_SESSION *session; SSH_OPTIONS *opt; if (!conn || !conn->uri) return VIR_DRV_OPEN_DECLINED; if (conn->uri->scheme == NULL || conn->uri->server == NULL || conn->uri->path == NULL) return VIR_DRV_OPEN_DECLINED; session = ssh_new(); opt = ssh_options_new(); if (!conn->uri->port) conn->uri->port = 22; /*setting some ssh options */ ssh_options_set_host(opt, conn->uri->server); ssh_options_set_port(opt, conn->uri->port); ssh_options_set_username(opt, conn->uri->user); ssh_set_options(session, opt); /*starting ssh connection */ if (ssh_connect(session)) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("Connection failed.")); ssh_disconnect(session); ssh_finalize(); goto err; } /*trying to use pub key */ if ((ssh_auth = ssh_userauth_autopubkey(session, NULL)) == SSH_AUTH_ERROR) { VIR_WARN("%s", "Authentication with public key failed."); } if ((banner = ssh_get_issue_banner(session))) { VIR_WARN("%s", banner); VIR_FREE(banner); } if (ssh_auth != SSH_AUTH_SUCCESS) { int i; int hasPassphrase = 0; int auth_check = 0; virConnectCredential creds[] = { {VIR_CRED_PASSPHRASE, "password", "Password", NULL, NULL, 0}, }; if (!auth || !auth->cb) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("No authentication callback provided.")); goto err; } for (i = 0; i < auth->ncredtype; i++) { if (auth->credtype[i] == VIR_CRED_PASSPHRASE) hasPassphrase = 1; } if (!hasPassphrase) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("Required credentials are not supported.")); goto err; } int res = (auth->cb) (creds, ARRAY_CARDINALITY(creds), auth->cbdata); if (res < 0) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("Unable to fetch credentials.")); goto err; } char *password = creds[0].result; char *username = conn->uri->user; auth_check = ssh_userauth_password(session, username, password); memset(password, 0, strlen(password)); if (auth_check != SSH_AUTH_SUCCESS) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s : %s", "Authentication failed.", ssh_get_error(session)); ssh_disconnect(session); goto err; } else goto exec; } else goto exec; err: exit_status = SSH_CONN_ERR; return VIR_DRV_OPEN_ERROR; exec: conn->privateData = session; return VIR_DRV_OPEN_SUCCESS; } static int phypClose(virConnectPtr conn) { SSH_SESSION *ssh_session = conn->privateData; ssh_disconnect(ssh_session); return 0; } /* this functions is the layer that manipulates the ssh channel itself * and executes the commands on the remote machine */ static char * __inner_exec_command(SSH_SESSION * session, char *cmd, int *exit_status, virConnectPtr conn) { CHANNEL *channel = channel_new(session); char buf[4096] = { 0 }; virBuffer tex_ret = VIR_BUFFER_INITIALIZER; int ret = 0; if (channel_open_session(channel) == SSH_ERROR) { virRaiseError(NULL, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("Unable to open a SSH channel.")); goto err; } if (channel_request_exec(channel, cmd) == SSH_ERROR) { virRaiseError(NULL, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("Unable to execute remote command.")); goto err; } if (channel_send_eof(channel) == SSH_ERROR) { virRaiseError(NULL, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, "%s", _("Unable to send EOF.")); goto err; } while (channel && channel_is_open(channel)) { ret = channel_read(channel, buf, sizeof(buf), 0); if (ret < 0) goto err; if (ret == 0) { channel_send_eof(channel); if (channel_get_exit_status(channel) == -1) goto err; if (channel_close(channel) == SSH_ERROR) goto err; channel_free(channel); channel = NULL; goto exit; } virBufferAdd(&tex_ret, (const char *) &buf, sizeof(buf)); } err: (*exit_status) = SSH_CMD_ERR; char *cleanup_buf = virBufferContentAndReset(&tex_ret); VIR_FREE(cleanup_buf); return NULL; exit: if (virBufferError(&tex_ret)) { virReportOOMError(conn); return NULL; } return virBufferContentAndReset(&tex_ret); } /* return the lpar_id given a name and a managed system name */ static int phypGetLparID(SSH_SESSION * ssh_session, const char *managed_system, const char *name, virConnectPtr conn) { int exit_status = 0; int lpar_id = 0; char *char_ptr; char *cmd; if (virAsprintf(&cmd, "lssyscfg -r lpar -m %s --filter lpar_names=%s -F lpar_id", managed_system, name) < 0) { virReportOOMError(conn); goto err; } const char *tex_ret = __inner_exec_command(ssh_session, cmd, &exit_status, conn); if (exit_status < 0 || tex_ret == NULL) goto err; if (virStrToLong_i(tex_ret, &char_ptr, 10, &lpar_id) == -1) goto err; VIR_FREE(cmd); return lpar_id; err: VIR_FREE(cmd); return 0; } /* return the lpar name given a lpar_id and a managed system name */ static char * phypGetLparNAME(SSH_SESSION * ssh_session, const char *managed_system, unsigned int lpar_id, int *exit_status, virConnectPtr conn) { char *cmd; if (virAsprintf(&cmd, "lssyscfg -r lpar -m %s --filter lpar_ids=%d -F name", managed_system, lpar_id) < 0) { virReportOOMError(conn); goto err; } char *lpar_name = __inner_exec_command(ssh_session, cmd, (int *) exit_status, conn); if (lpar_name == NULL) goto err; char *char_ptr = strchr(lpar_name, '\n'); if (char_ptr) *char_ptr = '\0'; if ((*exit_status) < 0 || lpar_name == NULL) goto err; VIR_FREE(cmd); return lpar_name; err: VIR_FREE(cmd); return NULL; } /* return the lpar_uuid (which for now is its logical serial number) * given a lpar id and a managed system name */ static unsigned char * phypGetLparUUID(SSH_SESSION * ssh_session, const char *managed_system, unsigned int lpar_id, int *exit_status, virConnectPtr conn) { char *cmd; if (virAsprintf(&cmd, "lssyscfg -r lpar -m %s --filter lpar_ids=%d -F logical_serial_num", managed_system, lpar_id) < 0) { virReportOOMError(conn); goto err; } unsigned char *lpar_uuid = (unsigned char *) __inner_exec_command(ssh_session, cmd, (int *) exit_status, conn); if (lpar_uuid == NULL) goto err; char *char_ptr = strchr(lpar_uuid, '\n'); if (char_ptr) *char_ptr = '\0'; //unsigned char *uuid; //VIR_ALLOC_N(uuid, VIR_UUID_BUFLEN); //if (virUUIDParse(lpar_uuid, uuid) < 0) // goto err; if ((*exit_status) < 0) goto err; VIR_FREE(cmd); return lpar_uuid; err: VIR_FREE(cmd); return NULL; } static int phypNumDomains(virConnectPtr conn) { int exit_status = 0; int ndom = 0; char *char_ptr; char *cmd; char *managed_system = conn->uri->path; SSH_SESSION *ssh_session = conn->privateData; /* need to shift one byte in order to remove the first "/" of URI component */ if (managed_system[0] == '/') managed_system++; if (virAsprintf(&cmd, "lssyscfg -r lpar -m %s -F lpar_id|grep -c ^[0-9]*", managed_system) < 0) { virReportOOMError(conn); goto err; } char *ret = __inner_exec_command(ssh_session, cmd, &exit_status, conn); if (exit_status < 0 || ret == NULL) goto err; if (virStrToLong_i(ret, &char_ptr, 10, &ndom) == -1) goto err; VIR_FREE(cmd); return ndom; err: VIR_FREE(cmd); return 0; } static int phypListDomains(virConnectPtr conn, int *ids, int nids) { int exit_status = 0; int got = 0; char *char_ptr; unsigned int i = 0, j = 0; char id_c[10]; char *cmd; char *managed_system = conn->uri->path; SSH_SESSION *ssh_session = conn->privateData; /* need to shift one byte in order to remove the first "/" of URI component */ if (managed_system[0] == '/') managed_system++; memset(id_c, 0, 10); if (virAsprintf(&cmd, "lssyscfg -r lpar -m %s -F lpar_id", managed_system) < 0) { virReportOOMError(conn); goto err; } char *domains = __inner_exec_command(ssh_session, cmd, &exit_status, conn); /* I need to parse the textual return in order to get the domains */ if (exit_status < 0 || domains == NULL) goto err; else { while (got < nids) { if (domains[i] == '\n') { if (virStrToLong_i(id_c, &char_ptr, 10, &ids[got]) == -1) return 0; memset(id_c, 0, 10); j = 0; got++; } else { id_c[j] = domains[i]; j++; } i++; } } VIR_FREE(cmd); return got; err: VIR_FREE(cmd); return 0; } static virDomainPtr phypDomainLookupByName(virConnectPtr conn, const char *name) { SSH_SESSION *ssh_session = conn->privateData; virDomainPtr dom = NULL; int lpar_id = 0; int exit_status = 0; char *managed_system = conn->uri->path; /* need to shift one byte in order to remove the first "/" of uri component */ if (managed_system[0] == '/') managed_system++; lpar_id = phypGetLparID(ssh_session, managed_system, name, conn); if (lpar_id == PHYP_NO_MEM) goto err; unsigned char *lpar_uuid = phypGetLparUUID(ssh_session, managed_system, lpar_id, &exit_status, conn); if (exit_status == PHYP_NO_MEM || lpar_uuid == NULL) goto err; dom = virGetDomain(conn, name, lpar_uuid); if (dom) dom->id = lpar_id; VIR_FREE(lpar_uuid); return dom; err: VIR_FREE(lpar_uuid); return NULL; } static virDomainPtr phypDomainLookupByID(virConnectPtr conn, int lpar_id) { SSH_SESSION *ssh_session = conn->privateData; virDomainPtr dom = NULL; int exit_status = 0; char *managed_system = conn->uri->path; /* need to shift one byte in order to remove the first "/" of uri component */ if (managed_system[0] == '/') managed_system++; char *lpar_name = phypGetLparNAME(ssh_session, managed_system, lpar_id, &exit_status, conn); if (exit_status == PHYP_NO_MEM) goto err; unsigned char *lpar_uuid = phypGetLparUUID(ssh_session, managed_system, lpar_id, &exit_status, conn); if (exit_status == PHYP_NO_MEM) goto err; dom = virGetDomain(conn, lpar_name, lpar_uuid); if (dom) dom->id = lpar_id; VIR_FREE(lpar_name); VIR_FREE(lpar_uuid); return dom; err: VIR_FREE(lpar_name); VIR_FREE(lpar_uuid); return NULL; } static virDriver phypDriver = { VIR_DRV_PHYP, "PHYP", phypOpen, /* open */ phypClose, /* close */ NULL, /* supports_feature */ NULL, /* type */ NULL, /* version */ NULL, /* getHostname */ NULL, /* getMaxVcpus */ NULL, /* nodeGetInfo */ NULL, /* getCapabilities */ phypListDomains, /* listDomains */ phypNumDomains, /* numOfDomains */ NULL, /* domainCreateXML */ phypDomainLookupByID, /* domainLookupByID */ NULL, /* domainLookupByUUID */ phypDomainLookupByName, /* domainLookupByName */ NULL, /* domainSuspend */ NULL, /* domainResume */ NULL, /* domainShutdown */ NULL, /* domainReboot */ NULL, /* domainDestroy */ NULL, /* domainGetOSType */ NULL, /* domainGetMaxMemory */ NULL, /* domainSetMaxMemory */ NULL, /* domainSetMemory */ NULL, /* domainGetInfo */ NULL, /* domainSave */ NULL, /* domainRestore */ NULL, /* domainCoreDump */ NULL, /* domainSetVcpus */ NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ NULL, /* domainGetSecurityLabel */ NULL, /* nodeGetSecurityModel */ NULL, /* domainDumpXML */ NULL, /* listDefinedDomains */ NULL, /* numOfDefinedDomains */ NULL, /* domainCreate */ NULL, /* domainDefineXML */ NULL, /* domainUndefine */ NULL, /* domainAttachDevice */ NULL, /* domainDetachDevice */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ NULL, /* domainMigratePrepare */ NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */ NULL, /* domainBlockStats */ NULL, /* domainInterfaceStats */ NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ NULL, /* domainEventRegister */ NULL, /* domainEventDeregister */ NULL, /* domainMigratePrepare2 */ NULL, /* domainMigrateFinish2 */ NULL, /* nodeDeviceDettach */ NULL, /* nodeDeviceReAttach */ NULL, /* nodeDeviceReset */ }; int phypRegister(void) { virRegisterDriver(&phypDriver); return 0; }
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list