2012-07-23 07:08:39 +00:00
|
|
|
/*
|
|
|
|
* virsh-nodedev.c: Commands in node device group
|
|
|
|
*
|
2016-01-09 13:36:29 +00:00
|
|
|
* Copyright (C) 2005, 2007-2016 Red Hat, Inc.
|
2012-07-23 07:08:39 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-23 07:08:39 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2012-08-20 22:23:10 +00:00
|
|
|
#include <config.h>
|
|
|
|
#include "virsh-nodedev.h"
|
|
|
|
|
|
|
|
#include "internal.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2013-05-09 18:59:04 +00:00
|
|
|
#include "virfile.h"
|
2015-04-01 15:09:04 +00:00
|
|
|
#include "virstring.h"
|
2016-08-08 19:34:21 +00:00
|
|
|
#include "virtime.h"
|
2012-09-17 03:32:53 +00:00
|
|
|
#include "conf/node_device_conf.h"
|
2019-04-01 10:14:26 +00:00
|
|
|
#include "virenum.h"
|
2020-02-16 21:59:28 +00:00
|
|
|
#include "virutil.h"
|
2012-08-20 22:23:10 +00:00
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
/*
|
|
|
|
* "nodedev-create" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_create[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("create a device defined "
|
|
|
|
"by an XML file on the node")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Create a device on the node. Note that this "
|
|
|
|
"command creates devices on the physical host "
|
|
|
|
"that can then be assigned to a virtual machine.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_create[] = {
|
2016-01-09 13:36:29 +00:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("file containing an XML description "
|
|
|
|
"of the device")),
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virNodeDevicePtr dev = NULL;
|
|
|
|
const char *from = NULL;
|
|
|
|
bool ret = true;
|
|
|
|
char *buffer;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2013-01-21 16:29:14 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
dev = virNodeDeviceCreateXML(priv->conn, buffer, 0);
|
2012-07-23 07:08:39 +00:00
|
|
|
VIR_FREE(buffer);
|
|
|
|
|
|
|
|
if (dev != NULL) {
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, _("Node device %s created from %s\n"),
|
|
|
|
virNodeDeviceGetName(dev), from);
|
2012-07-23 07:08:39 +00:00
|
|
|
virNodeDeviceFree(dev);
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to create node device from %s"), from);
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-destroy" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_destroy[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("destroy (stop) a device on the node")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Destroy a device on the node. Note that this "
|
|
|
|
"command destroys devices on the physical host")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_destroy[] = {
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = "name",
|
2013-02-04 14:16:44 +00:00
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "device"
|
|
|
|
},
|
|
|
|
{.name = "device",
|
2013-01-14 14:30:11 +00:00
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 13:44:37 +00:00
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 14:30:11 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
2020-08-17 21:21:48 +00:00
|
|
|
static virNodeDevice*
|
|
|
|
vshFindNodeDevice(vshControl *ctl, const char *value)
|
2012-07-23 07:08:39 +00:00
|
|
|
{
|
|
|
|
virNodeDevicePtr dev = NULL;
|
2013-02-04 14:16:44 +00:00
|
|
|
char **arr = NULL;
|
|
|
|
int narr;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2020-08-17 21:21:48 +00:00
|
|
|
if (strchr(value, ',')) {
|
|
|
|
narr = vshStringToArray(value, &arr);
|
2013-02-04 14:16:44 +00:00
|
|
|
if (narr != 2) {
|
2020-08-17 21:21:48 +00:00
|
|
|
vshError(ctl, _("Malformed device value '%s'"), value);
|
2013-02-04 14:16:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virValidateWWN(arr[0]) || !virValidateWWN(arr[1]))
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
dev = virNodeDeviceLookupSCSIHostByWWN(priv->conn, arr[0], arr[1], 0);
|
2013-02-04 14:16:44 +00:00
|
|
|
} else {
|
2020-08-17 21:21:48 +00:00
|
|
|
dev = virNodeDeviceLookupByName(priv->conn, value);
|
2013-02-04 14:16:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!dev) {
|
2020-08-17 21:21:48 +00:00
|
|
|
vshError(ctl, "%s '%s'", _("Could not find matching device"), value);
|
2013-02-04 14:16:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2020-08-17 21:21:48 +00:00
|
|
|
cleanup:
|
|
|
|
g_strfreev(arr);
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virNodeDevice *dev = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
const char *device_value = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = vshFindNodeDevice(ctl, device_value);
|
|
|
|
if (!dev)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
if (virNodeDeviceDestroy(dev) == 0) {
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, _("Destroyed node device '%s'\n"), device_value);
|
2012-07-23 07:08:39 +00:00
|
|
|
} else {
|
2013-02-04 14:16:44 +00:00
|
|
|
vshError(ctl, _("Failed to destroy node device '%s'"), device_value);
|
|
|
|
goto cleanup;
|
2012-07-23 07:08:39 +00:00
|
|
|
}
|
|
|
|
|
2013-02-04 14:16:44 +00:00
|
|
|
ret = true;
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2014-06-02 14:48:22 +00:00
|
|
|
if (dev)
|
|
|
|
virNodeDeviceFree(dev);
|
2012-07-23 07:08:39 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
struct virshNodeList {
|
2012-07-23 07:08:39 +00:00
|
|
|
char **names;
|
|
|
|
char **parents;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshNodeListLookup(int devid, bool parent, void *opaque)
|
2012-07-23 07:08:39 +00:00
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
struct virshNodeList *arrays = opaque;
|
2012-07-23 07:08:39 +00:00
|
|
|
if (parent)
|
|
|
|
return arrays->parents[devid];
|
|
|
|
return arrays->names[devid];
|
|
|
|
}
|
|
|
|
|
2012-09-17 03:32:53 +00:00
|
|
|
static int
|
2015-06-15 16:53:58 +00:00
|
|
|
virshNodeDeviceSorter(const void *a, const void *b)
|
2012-09-17 03:32:53 +00:00
|
|
|
{
|
|
|
|
virNodeDevicePtr *na = (virNodeDevicePtr *) a;
|
|
|
|
virNodeDevicePtr *nb = (virNodeDevicePtr *) b;
|
|
|
|
|
|
|
|
if (*na && !*nb)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!*na)
|
|
|
|
return *nb != NULL;
|
|
|
|
|
|
|
|
return vshStrcasecmp(virNodeDeviceGetName(*na),
|
|
|
|
virNodeDeviceGetName(*nb));
|
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
struct virshNodeDeviceList {
|
2012-09-17 03:32:53 +00:00
|
|
|
virNodeDevicePtr *devices;
|
|
|
|
size_t ndevices;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virshNodeDeviceListFree(struct virshNodeDeviceList *list)
|
2012-09-17 03:32:53 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-09-17 03:32:53 +00:00
|
|
|
|
2013-08-27 11:27:50 +00:00
|
|
|
if (list && list->devices) {
|
2012-09-17 03:32:53 +00:00
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
|
|
|
if (list->devices[i])
|
|
|
|
virNodeDeviceFree(list->devices[i]);
|
|
|
|
}
|
2021-02-03 19:32:55 +00:00
|
|
|
g_free(list->devices);
|
2012-09-17 03:32:53 +00:00
|
|
|
}
|
2021-02-03 19:32:55 +00:00
|
|
|
g_free(list);
|
2012-09-17 03:32:53 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static struct virshNodeDeviceList *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshNodeDeviceListCollect(vshControl *ctl,
|
2012-09-17 03:32:53 +00:00
|
|
|
char **capnames,
|
|
|
|
int ncapnames,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
struct virshNodeDeviceList *list = g_new0(struct virshNodeDeviceList, 1);
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-09-17 03:32:53 +00:00
|
|
|
int ret;
|
|
|
|
virNodeDevicePtr device;
|
|
|
|
bool success = false;
|
|
|
|
size_t deleted = 0;
|
|
|
|
int ndevices = 0;
|
|
|
|
char **names = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-09-17 03:32:53 +00:00
|
|
|
|
|
|
|
/* try the list with flags support (0.10.2 and later) */
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((ret = virConnectListAllNodeDevices(priv->conn,
|
2012-09-17 03:32:53 +00:00
|
|
|
&list->devices,
|
|
|
|
flags)) >= 0) {
|
|
|
|
list->ndevices = ret;
|
|
|
|
goto finished;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the command is actually supported */
|
|
|
|
if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
|
|
|
|
goto fallback;
|
|
|
|
|
|
|
|
/* there was an error during the call */
|
|
|
|
vshError(ctl, "%s", _("Failed to list node devices"));
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
fallback:
|
2012-09-17 03:32:53 +00:00
|
|
|
/* fall back to old method (0.10.1 and older) */
|
|
|
|
vshResetLibvirtError();
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
ndevices = virNodeNumOfDevices(priv->conn, NULL, 0);
|
2012-09-17 03:32:53 +00:00
|
|
|
if (ndevices < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to count node devices"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ndevices == 0)
|
|
|
|
return list;
|
|
|
|
|
2020-10-05 16:50:09 +00:00
|
|
|
names = g_new0(char *, ndevices);
|
2012-09-17 03:32:53 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
ndevices = virNodeListDevices(priv->conn, NULL, names, ndevices, 0);
|
2012-09-17 03:32:53 +00:00
|
|
|
if (ndevices < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to list node devices"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-10-05 16:50:09 +00:00
|
|
|
list->devices = g_new0(virNodeDevicePtr, ndevices);
|
2012-09-17 03:32:53 +00:00
|
|
|
list->ndevices = 0;
|
|
|
|
|
|
|
|
/* get the node devices */
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; i < ndevices; i++) {
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, names[i])))
|
2012-09-17 03:32:53 +00:00
|
|
|
continue;
|
|
|
|
list->devices[list->ndevices++] = device;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* truncate domains that weren't found */
|
|
|
|
deleted = ndevices - list->ndevices;
|
|
|
|
|
|
|
|
if (!capnames)
|
|
|
|
goto finished;
|
|
|
|
|
|
|
|
/* filter the list if the list was acquired by fallback means */
|
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
|
|
|
char **caps = NULL;
|
|
|
|
int ncaps = 0;
|
|
|
|
bool match = false;
|
2020-08-03 15:27:58 +00:00
|
|
|
size_t j, k;
|
2012-09-17 03:32:53 +00:00
|
|
|
|
|
|
|
device = list->devices[i];
|
|
|
|
|
|
|
|
if ((ncaps = virNodeDeviceNumOfCaps(device)) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to get capability numbers "
|
|
|
|
"of the device"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-10-05 16:50:09 +00:00
|
|
|
caps = g_new0(char *, ncaps);
|
2012-09-17 03:32:53 +00:00
|
|
|
|
|
|
|
if ((ncaps = virNodeDeviceListCaps(device, caps, ncaps)) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to get capability names of the device"));
|
|
|
|
VIR_FREE(caps);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-10-15 12:44:06 +00:00
|
|
|
/* Check if the device's capability matches with provided
|
2012-09-17 03:32:53 +00:00
|
|
|
* capabilities.
|
|
|
|
*/
|
|
|
|
for (j = 0; j < ncaps; j++) {
|
|
|
|
for (k = 0; k < ncapnames; k++) {
|
|
|
|
if (STREQ(caps[j], capnames[k])) {
|
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(caps);
|
|
|
|
|
|
|
|
if (!match)
|
|
|
|
goto remove_entry;
|
|
|
|
|
|
|
|
/* the device matched all filters, it may stay */
|
|
|
|
continue;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
remove_entry:
|
2012-09-17 03:32:53 +00:00
|
|
|
/* the device has to be removed as it failed one of the filters */
|
|
|
|
virNodeDeviceFree(list->devices[i]);
|
|
|
|
list->devices[i] = NULL;
|
|
|
|
deleted++;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
finished:
|
2012-09-17 03:32:53 +00:00
|
|
|
/* sort the list */
|
|
|
|
if (list->devices && list->ndevices)
|
|
|
|
qsort(list->devices, list->ndevices,
|
2015-06-15 16:53:58 +00:00
|
|
|
sizeof(*list->devices), virshNodeDeviceSorter);
|
2012-09-17 03:32:53 +00:00
|
|
|
|
|
|
|
/* truncate the list if filter simulation deleted entries */
|
|
|
|
if (deleted)
|
|
|
|
VIR_SHRINK_N(list->devices, list->ndevices, deleted);
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-07-11 14:33:29 +00:00
|
|
|
for (i = 0; ndevices != -1 && i < ndevices; i++)
|
2012-09-17 03:32:53 +00:00
|
|
|
VIR_FREE(names[i]);
|
|
|
|
VIR_FREE(names);
|
|
|
|
|
|
|
|
if (!success) {
|
2015-06-15 16:53:58 +00:00
|
|
|
virshNodeDeviceListFree(list);
|
2012-09-17 03:32:53 +00:00
|
|
|
list = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
/*
|
|
|
|
* "nodedev-list" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_list_devices[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("enumerate devices on this host")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_list_devices[] = {
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = "tree",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list devices in a tree")
|
|
|
|
},
|
|
|
|
{.name = "cap",
|
|
|
|
.type = VSH_OT_STRING,
|
2019-07-14 09:47:34 +00:00
|
|
|
.completer = virshNodeDeviceCapabilityNameCompleter,
|
2013-01-14 14:30:11 +00:00
|
|
|
.help = N_("capability names, separated by comma")
|
|
|
|
},
|
2020-07-10 19:47:01 +00:00
|
|
|
{.name = "inactive",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list inactive devices")
|
|
|
|
},
|
|
|
|
{.name = "all",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list inactive & active devices")
|
|
|
|
},
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2019-10-14 12:44:29 +00:00
|
|
|
cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
2012-07-23 07:08:39 +00:00
|
|
|
{
|
2012-09-17 03:32:53 +00:00
|
|
|
const char *cap_str = NULL;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-23 07:08:39 +00:00
|
|
|
bool tree = vshCommandOptBool(cmd, "tree");
|
|
|
|
bool ret = true;
|
2012-09-17 03:32:53 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
char **caps = NULL;
|
|
|
|
int ncaps = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
struct virshNodeDeviceList *list = NULL;
|
2012-09-17 03:32:53 +00:00
|
|
|
int cap_type = -1;
|
2020-07-10 19:47:01 +00:00
|
|
|
bool inactive = vshCommandOptBool(cmd, "inactive");
|
|
|
|
bool all = vshCommandOptBool(cmd, "all");
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
ignore_value(vshCommandOptStringQuiet(ctl, cmd, "cap", &cap_str));
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2012-09-17 03:32:53 +00:00
|
|
|
if (cap_str) {
|
2013-08-15 16:20:05 +00:00
|
|
|
if ((ncaps = vshStringToArray(cap_str, &caps)) < 0)
|
|
|
|
return false;
|
2012-07-23 07:08:39 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 19:47:01 +00:00
|
|
|
if (all && inactive) {
|
|
|
|
vshError(ctl, "%s", _("Option --all is incompatible with --inactive"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tree && (cap_str || inactive || all)) {
|
|
|
|
vshError(ctl, "%s", _("Option --tree is incompatible with other options"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-17 03:32:53 +00:00
|
|
|
for (i = 0; i < ncaps; i++) {
|
|
|
|
if ((cap_type = virNodeDevCapTypeFromString(caps[i])) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Invalid capability type"));
|
2013-08-27 11:47:57 +00:00
|
|
|
ret = false;
|
|
|
|
goto cleanup;
|
2012-09-17 03:32:53 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 15:09:15 +00:00
|
|
|
switch ((virNodeDevCapType) cap_type) {
|
2012-09-17 03:32:53 +00:00
|
|
|
case VIR_NODE_DEV_CAP_SYSTEM:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_PCI_DEV:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_USB_DEV:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_USB_INTERFACE:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_NET:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_SCSI_HOST:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_SCSI_TARGET:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_SCSI:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_STORAGE:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE;
|
|
|
|
break;
|
2013-01-07 17:05:28 +00:00
|
|
|
case VIR_NODE_DEV_CAP_FC_HOST:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_VPORTS:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS;
|
|
|
|
break;
|
2013-06-03 10:05:35 +00:00
|
|
|
case VIR_NODE_DEV_CAP_SCSI_GENERIC:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_GENERIC;
|
|
|
|
break;
|
2017-02-17 15:09:15 +00:00
|
|
|
case VIR_NODE_DEV_CAP_DRM:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_DRM;
|
|
|
|
break;
|
2017-03-06 16:20:00 +00:00
|
|
|
case VIR_NODE_DEV_CAP_MDEV_TYPES:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV_TYPES;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_MDEV:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV;
|
|
|
|
break;
|
2017-05-22 06:38:22 +00:00
|
|
|
case VIR_NODE_DEV_CAP_CCW_DEV:
|
2017-05-22 06:38:23 +00:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCW_DEV;
|
|
|
|
break;
|
2020-09-14 19:11:44 +00:00
|
|
|
case VIR_NODE_DEV_CAP_CSS_DEV:
|
2020-09-14 19:11:45 +00:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_CSS_DEV;
|
|
|
|
break;
|
2020-10-14 17:08:30 +00:00
|
|
|
case VIR_NODE_DEV_CAP_VDPA:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VDPA;
|
|
|
|
break;
|
2020-12-03 17:59:33 +00:00
|
|
|
case VIR_NODE_DEV_CAP_AP_CARD:
|
2020-12-03 17:59:37 +00:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_CARD;
|
|
|
|
break;
|
2020-12-03 17:59:35 +00:00
|
|
|
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
2020-12-03 17:59:37 +00:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE;
|
|
|
|
break;
|
2020-12-03 17:59:38 +00:00
|
|
|
case VIR_NODE_DEV_CAP_AP_MATRIX:
|
2020-12-03 17:59:40 +00:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX;
|
|
|
|
break;
|
2017-02-17 15:09:15 +00:00
|
|
|
case VIR_NODE_DEV_CAP_LAST:
|
2012-09-17 03:32:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-07-23 07:08:39 +00:00
|
|
|
}
|
2012-09-17 03:32:53 +00:00
|
|
|
|
2020-07-10 19:47:01 +00:00
|
|
|
if (inactive || all)
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE;
|
|
|
|
if (!inactive)
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(list = virshNodeDeviceListCollect(ctl, caps, ncaps, flags))) {
|
2012-09-17 03:32:53 +00:00
|
|
|
ret = false;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
if (tree) {
|
2020-10-05 16:50:09 +00:00
|
|
|
char **parents = g_new0(char *, list->ndevices);
|
|
|
|
char **names = g_new0(char *, list->ndevices);
|
2015-06-15 16:53:58 +00:00
|
|
|
struct virshNodeList arrays = { names, parents };
|
2012-09-17 03:32:53 +00:00
|
|
|
|
|
|
|
for (i = 0; i < list->ndevices; i++)
|
2019-10-18 15:24:02 +00:00
|
|
|
names[i] = g_strdup(virNodeDeviceGetName(list->devices[i]));
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2012-09-17 03:32:53 +00:00
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
|
|
|
virNodeDevicePtr dev = list->devices[i];
|
|
|
|
if (STRNEQ(names[i], "computer")) {
|
2019-10-18 15:24:02 +00:00
|
|
|
parents[i] = g_strdup(virNodeDeviceGetParent(dev));
|
2012-07-23 07:08:39 +00:00
|
|
|
} else {
|
|
|
|
parents[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2012-09-17 03:32:53 +00:00
|
|
|
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
2012-07-23 07:08:39 +00:00
|
|
|
if (parents[i] == NULL &&
|
2015-06-15 16:53:58 +00:00
|
|
|
vshTreePrint(ctl, virshNodeListLookup, &arrays,
|
2012-09-17 03:32:53 +00:00
|
|
|
list->ndevices, i) < 0)
|
2012-07-23 07:08:39 +00:00
|
|
|
ret = false;
|
|
|
|
}
|
2012-09-17 03:32:53 +00:00
|
|
|
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; i < list->ndevices; i++)
|
2012-07-23 07:08:39 +00:00
|
|
|
VIR_FREE(parents[i]);
|
|
|
|
VIR_FREE(parents);
|
2012-09-17 03:32:53 +00:00
|
|
|
for (i = 0; i < list->ndevices; i++)
|
|
|
|
VIR_FREE(names[i]);
|
|
|
|
VIR_FREE(names);
|
2012-07-23 07:08:39 +00:00
|
|
|
} else {
|
2012-09-17 03:32:53 +00:00
|
|
|
for (i = 0; i < list->ndevices; i++)
|
|
|
|
vshPrint(ctl, "%s\n", virNodeDeviceGetName(list->devices[i]));
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2020-08-02 17:36:03 +00:00
|
|
|
g_strfreev(caps);
|
2015-06-15 16:53:58 +00:00
|
|
|
virshNodeDeviceListFree(list);
|
2012-07-23 07:08:39 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-dumpxml" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_dumpxml[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("node device details in XML")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Output the node device details as an XML dump to stdout.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_dumpxml[] = {
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2013-02-04 14:16:44 +00:00
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
2018-01-12 13:44:37 +00:00
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 14:30:11 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2013-01-21 16:41:14 +00:00
|
|
|
virNodeDevicePtr device = NULL;
|
|
|
|
char *xml = NULL;
|
2013-02-04 14:16:44 +00:00
|
|
|
const char *device_value = NULL;
|
2013-01-21 16:41:14 +00:00
|
|
|
bool ret = false;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2013-02-04 14:16:44 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2020-08-17 21:21:48 +00:00
|
|
|
device = vshFindNodeDevice(ctl, device_value);
|
2013-02-04 14:16:44 +00:00
|
|
|
|
2020-08-17 21:21:48 +00:00
|
|
|
if (!device)
|
2013-02-04 14:16:44 +00:00
|
|
|
goto cleanup;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2013-01-21 16:41:14 +00:00
|
|
|
if (!(xml = virNodeDeviceGetXMLDesc(device, 0)))
|
|
|
|
goto cleanup;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
|
|
|
vshPrint(ctl, "%s\n", xml);
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2013-02-04 14:16:44 +00:00
|
|
|
ret = true;
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2012-07-23 07:08:39 +00:00
|
|
|
VIR_FREE(xml);
|
2014-06-02 14:48:22 +00:00
|
|
|
if (device)
|
|
|
|
virNodeDeviceFree(device);
|
2013-01-21 16:41:14 +00:00
|
|
|
return ret;
|
2012-07-23 07:08:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-detach" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_detach[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detach node device from its device driver")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Detach node device from its device driver before assigning to a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_detach[] = {
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 13:44:37 +00:00
|
|
|
.help = N_("device key"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 14:30:11 +00:00
|
|
|
},
|
2013-04-24 18:22:36 +00:00
|
|
|
{.name = "driver",
|
|
|
|
.type = VSH_OT_STRING,
|
2013-06-27 11:21:07 +00:00
|
|
|
.help = N_("pci device assignment backend driver (e.g. 'vfio' or 'kvm')")
|
2013-04-24 18:22:36 +00:00
|
|
|
},
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDetach(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
2013-04-24 18:22:36 +00:00
|
|
|
const char *driverName = NULL;
|
2012-07-23 07:08:39 +00:00
|
|
|
virNodeDevicePtr device;
|
|
|
|
bool ret = true;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2013-01-21 16:29:14 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
ignore_value(vshCommandOptStringQuiet(ctl, cmd, "driver", &driverName));
|
2013-04-24 18:22:36 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
2013-01-21 16:41:14 +00:00
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-24 18:22:36 +00:00
|
|
|
if (driverName) {
|
|
|
|
/* we must use the newer API that accepts a driverName */
|
|
|
|
if (virNodeDeviceDetachFlags(device, driverName, 0) < 0)
|
|
|
|
ret = false;
|
2012-07-23 07:08:39 +00:00
|
|
|
} else {
|
2013-04-24 18:22:36 +00:00
|
|
|
/* Yes, our (old) public API is misspelled. At least virsh
|
|
|
|
* can accept either spelling. */
|
|
|
|
if (virNodeDeviceDettach(device) < 0)
|
|
|
|
ret = false;
|
2012-07-23 07:08:39 +00:00
|
|
|
}
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2013-04-24 18:22:36 +00:00
|
|
|
if (ret)
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, _("Device %s detached\n"), name);
|
2013-04-24 18:22:36 +00:00
|
|
|
else
|
|
|
|
vshError(ctl, _("Failed to detach device %s"), name);
|
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
virNodeDeviceFree(device);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-reattach" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_reattach[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("reattach node device to its device driver")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Reattach node device to its device driver once released by the domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_reattach[] = {
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 13:44:37 +00:00
|
|
|
.help = N_("device key"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 14:30:11 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceReAttach(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
|
|
|
virNodeDevicePtr device;
|
|
|
|
bool ret = true;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2013-01-21 16:29:14 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
2013-01-21 16:41:14 +00:00
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNodeDeviceReAttach(device) == 0) {
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, _("Device %s re-attached\n"), name);
|
2012-07-23 07:08:39 +00:00
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to re-attach device %s"), name);
|
|
|
|
ret = false;
|
|
|
|
}
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
virNodeDeviceFree(device);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-reset" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_reset[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("reset node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Reset node device before or after assigning to a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_reset[] = {
|
2013-01-14 14:30:11 +00:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 13:44:37 +00:00
|
|
|
.help = N_("device key"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 14:30:11 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 07:08:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
|
|
|
virNodeDevicePtr device;
|
|
|
|
bool ret = true;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 07:08:39 +00:00
|
|
|
|
2013-01-21 16:29:14 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
2013-01-21 16:41:14 +00:00
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
2012-07-23 07:08:39 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNodeDeviceReset(device) == 0) {
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, _("Device %s reset\n"), name);
|
2012-07-23 07:08:39 +00:00
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to reset device %s"), name);
|
|
|
|
ret = false;
|
|
|
|
}
|
2013-01-21 16:41:14 +00:00
|
|
|
|
2012-07-23 07:08:39 +00:00
|
|
|
virNodeDeviceFree(device);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-07-23 07:19:04 +00:00
|
|
|
|
2016-08-08 19:34:21 +00:00
|
|
|
/*
|
|
|
|
* "nodedev-event" command
|
|
|
|
*/
|
2019-01-20 16:04:56 +00:00
|
|
|
VIR_ENUM_DECL(virshNodeDeviceEvent);
|
2016-08-08 19:34:21 +00:00
|
|
|
VIR_ENUM_IMPL(virshNodeDeviceEvent,
|
|
|
|
VIR_NODE_DEVICE_EVENT_LAST,
|
|
|
|
N_("Created"),
|
2020-07-09 15:56:51 +00:00
|
|
|
N_("Deleted"),
|
|
|
|
N_("Defined"),
|
|
|
|
N_("Undefined"));
|
2016-08-08 19:34:21 +00:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
virshNodeDeviceEventToString(int event)
|
|
|
|
{
|
|
|
|
const char *str = virshNodeDeviceEventTypeToString(event);
|
|
|
|
return str ? _(str) : _("unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virshNodeDeviceEventData {
|
|
|
|
vshControl *ctl;
|
|
|
|
bool loop;
|
|
|
|
bool timestamp;
|
|
|
|
int count;
|
2019-07-14 09:47:34 +00:00
|
|
|
virshNodeDeviceEventCallback *cb;
|
2016-08-08 19:34:21 +00:00
|
|
|
};
|
|
|
|
typedef struct virshNodeDeviceEventData virshNodeDeviceEventData;
|
|
|
|
|
|
|
|
static void
|
2019-10-14 12:44:29 +00:00
|
|
|
vshEventLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
|
2016-08-08 19:34:21 +00:00
|
|
|
virNodeDevicePtr dev,
|
|
|
|
int event,
|
2019-10-14 12:44:29 +00:00
|
|
|
int detail G_GNUC_UNUSED,
|
2016-08-08 19:34:21 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virshNodeDeviceEventData *data = opaque;
|
|
|
|
|
|
|
|
if (!data->loop && data->count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (data->timestamp) {
|
|
|
|
char timestamp[VIR_TIME_STRING_BUFLEN];
|
|
|
|
|
|
|
|
if (virTimeStringNowRaw(timestamp) < 0)
|
|
|
|
timestamp[0] = '\0';
|
|
|
|
|
|
|
|
vshPrint(data->ctl, _("%s: event 'lifecycle' for node device %s: %s\n"),
|
|
|
|
timestamp,
|
|
|
|
virNodeDeviceGetName(dev), virshNodeDeviceEventToString(event));
|
|
|
|
} else {
|
|
|
|
vshPrint(data->ctl, _("event 'lifecycle' for node device %s: %s\n"),
|
|
|
|
virNodeDeviceGetName(dev), virshNodeDeviceEventToString(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
data->count++;
|
|
|
|
if (!data->loop)
|
|
|
|
vshEventDone(data->ctl);
|
|
|
|
}
|
|
|
|
|
2016-08-11 15:15:23 +00:00
|
|
|
static void
|
2019-10-14 12:44:29 +00:00
|
|
|
vshEventGenericPrint(virConnectPtr conn G_GNUC_UNUSED,
|
2016-08-11 15:15:23 +00:00
|
|
|
virNodeDevicePtr dev,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virshNodeDeviceEventData *data = opaque;
|
|
|
|
|
|
|
|
if (!data->loop && data->count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (data->timestamp) {
|
|
|
|
char timestamp[VIR_TIME_STRING_BUFLEN];
|
|
|
|
|
|
|
|
if (virTimeStringNowRaw(timestamp) < 0)
|
|
|
|
timestamp[0] = '\0';
|
|
|
|
|
2016-12-01 20:50:08 +00:00
|
|
|
vshPrint(data->ctl, _("%s: event '%s' for node device %s\n"),
|
2016-08-11 15:15:23 +00:00
|
|
|
timestamp,
|
|
|
|
data->cb->name,
|
|
|
|
virNodeDeviceGetName(dev));
|
|
|
|
} else {
|
|
|
|
vshPrint(data->ctl, _("event '%s' for node device %s\n"),
|
|
|
|
data->cb->name,
|
|
|
|
virNodeDeviceGetName(dev));
|
|
|
|
}
|
|
|
|
|
|
|
|
data->count++;
|
|
|
|
if (!data->loop)
|
|
|
|
vshEventDone(data->ctl);
|
|
|
|
}
|
|
|
|
|
2019-07-14 09:47:34 +00:00
|
|
|
virshNodeDeviceEventCallback virshNodeDeviceEventCallbacks[] = {
|
2016-08-11 15:15:23 +00:00
|
|
|
{ "lifecycle",
|
|
|
|
VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint), },
|
|
|
|
{ "update", vshEventGenericPrint, }
|
|
|
|
};
|
2020-01-09 10:39:55 +00:00
|
|
|
G_STATIC_ASSERT(VIR_NODE_DEVICE_EVENT_ID_LAST == G_N_ELEMENTS(virshNodeDeviceEventCallbacks));
|
2016-08-11 15:15:23 +00:00
|
|
|
|
|
|
|
|
2016-08-08 19:34:21 +00:00
|
|
|
static const vshCmdInfo info_node_device_event[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Node Device Events")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("List event types, or wait for node device events to occur")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_event[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_STRING,
|
2018-01-12 13:44:37 +00:00
|
|
|
.help = N_("filter by node device name"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2016-08-08 19:34:21 +00:00
|
|
|
},
|
|
|
|
{.name = "event",
|
|
|
|
.type = VSH_OT_STRING,
|
2019-07-14 09:47:34 +00:00
|
|
|
.completer = virshNodeDeviceEventNameCompleter,
|
2016-08-08 19:34:21 +00:00
|
|
|
.help = N_("which event type to wait for")
|
|
|
|
},
|
|
|
|
{.name = "loop",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("loop until timeout or interrupt, rather than one-shot")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("timeout seconds")
|
|
|
|
},
|
|
|
|
{.name = "list",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list valid event types")
|
|
|
|
},
|
|
|
|
{.name = "timestamp",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("show timestamp for each printed event")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virNodeDevicePtr dev = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
int eventId = -1;
|
|
|
|
int timeout = 0;
|
|
|
|
virshNodeDeviceEventData data;
|
|
|
|
const char *eventName = NULL;
|
|
|
|
const char *device_value = NULL;
|
|
|
|
int event;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2016-08-08 19:34:21 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "list")) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_NODE_DEVICE_EVENT_ID_LAST; i++)
|
2019-07-14 09:47:34 +00:00
|
|
|
vshPrint(ctl, "%s\n", virshNodeDeviceEventCallbacks[i].name);
|
2016-08-08 19:34:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0)
|
|
|
|
return false;
|
|
|
|
if (!eventName) {
|
2016-09-06 11:14:34 +00:00
|
|
|
vshError(ctl, "%s", _("either --list or --event <type> is required"));
|
2016-08-08 19:34:21 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-11 15:15:23 +00:00
|
|
|
|
|
|
|
for (event = 0; event < VIR_NODE_DEVICE_EVENT_ID_LAST; event++)
|
2019-07-14 09:47:34 +00:00
|
|
|
if (STREQ(eventName, virshNodeDeviceEventCallbacks[event].name))
|
2016-08-11 15:15:23 +00:00
|
|
|
break;
|
|
|
|
if (event == VIR_NODE_DEVICE_EVENT_ID_LAST) {
|
2016-08-08 19:34:21 +00:00
|
|
|
vshError(ctl, _("unknown event type %s"), eventName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
data.ctl = ctl;
|
|
|
|
data.loop = vshCommandOptBool(cmd, "loop");
|
|
|
|
data.timestamp = vshCommandOptBool(cmd, "timestamp");
|
|
|
|
data.count = 0;
|
2019-07-14 09:47:34 +00:00
|
|
|
data.cb = &virshNodeDeviceEventCallbacks[event];
|
2016-08-08 19:34:21 +00:00
|
|
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
|
|
|
return false;
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (device_value) {
|
|
|
|
if (!(dev = virNodeDeviceLookupByName(priv->conn, device_value))) {
|
|
|
|
vshError(ctl, "%s '%s'",
|
|
|
|
_("Could not find matching device"), device_value);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vshEventStart(ctl, timeout) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((eventId = virConnectNodeDeviceEventRegisterAny(priv->conn, dev, event,
|
2016-08-11 15:15:23 +00:00
|
|
|
data.cb->cb,
|
2016-08-08 19:34:21 +00:00
|
|
|
&data, NULL)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
switch (vshEventWait(ctl)) {
|
|
|
|
case VSH_EVENT_INTERRUPT:
|
|
|
|
vshPrint(ctl, "%s", _("event loop interrupted\n"));
|
|
|
|
break;
|
|
|
|
case VSH_EVENT_TIMEOUT:
|
|
|
|
vshPrint(ctl, "%s", _("event loop timed out\n"));
|
|
|
|
break;
|
|
|
|
case VSH_EVENT_DONE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
vshPrint(ctl, _("events received: %d\n"), data.count);
|
|
|
|
if (data.count)
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
vshEventCleanup(ctl);
|
|
|
|
if (eventId >= 0 &&
|
|
|
|
virConnectNodeDeviceEventDeregisterAny(priv->conn, eventId) < 0)
|
|
|
|
ret = false;
|
|
|
|
if (dev)
|
|
|
|
virNodeDeviceFree(dev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-13 21:56:48 +00:00
|
|
|
/*
|
|
|
|
* "nodedev-undefine" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_undefine[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Undefine an inactive node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Undefines the configuration for an inactive node device")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_undefine[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceUndefine(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
|
|
|
{
|
|
|
|
virNodeDevice *dev = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
const char *device_value = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = vshFindNodeDevice(ctl, device_value);
|
|
|
|
|
|
|
|
if (!dev)
|
|
|
|
goto cleanup;
|
|
|
|
|
2021-04-09 15:50:03 +00:00
|
|
|
if (virNodeDeviceUndefine(dev, 0) == 0) {
|
2020-07-13 21:56:48 +00:00
|
|
|
vshPrintExtra(ctl, _("Undefined node device '%s'\n"), device_value);
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to undefine node device '%s'"), device_value);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
cleanup:
|
|
|
|
if (dev)
|
|
|
|
virNodeDeviceFree(dev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-13 21:40:47 +00:00
|
|
|
/*
|
|
|
|
* "nodedev-define" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_define[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Define a device by an xml file on a node")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Defines a persistent device on the node that can be "
|
|
|
|
"assigned to a domain. The device must be started before "
|
|
|
|
"it can be assigned to a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_define[] = {
|
|
|
|
VIRSH_COMMON_OPT_FILE(N_("file containing an XML description "
|
|
|
|
"of the device")),
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDefine(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
|
|
|
{
|
|
|
|
virNodeDevice *dev = NULL;
|
|
|
|
const char *from = NULL;
|
|
|
|
bool ret = true;
|
|
|
|
char *buffer;
|
|
|
|
virshControl *priv = ctl->privData;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = virNodeDeviceDefineXML(priv->conn, buffer, 0);
|
|
|
|
VIR_FREE(buffer);
|
|
|
|
|
|
|
|
if (dev != NULL) {
|
|
|
|
vshPrintExtra(ctl, _("Node device '%s' defined from '%s'\n"),
|
|
|
|
virNodeDeviceGetName(dev), from);
|
|
|
|
virNodeDeviceFree(dev);
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to define node device from '%s'"), from);
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-09 21:05:41 +00:00
|
|
|
/*
|
|
|
|
* "nodedev-start" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_start[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Start an inactive node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Starts an inactive node device that was previously defined")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_start[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("device name"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceStart(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
|
|
|
virNodeDevice *device;
|
|
|
|
bool ret = true;
|
|
|
|
virshControl *priv = ctl->privData;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-09 15:50:03 +00:00
|
|
|
if (virNodeDeviceCreate(device, 0) == 0) {
|
2020-07-09 21:05:41 +00:00
|
|
|
vshPrintExtra(ctl, _("Device %s started\n"), name);
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to start device %s"), name);
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virNodeDeviceFree(device);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-20 22:23:10 +00:00
|
|
|
const vshCmdDef nodedevCmds[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "nodedev-create",
|
|
|
|
.handler = cmdNodeDeviceCreate,
|
|
|
|
.opts = opts_node_device_create,
|
|
|
|
.info = info_node_device_create,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-destroy",
|
|
|
|
.handler = cmdNodeDeviceDestroy,
|
|
|
|
.opts = opts_node_device_destroy,
|
|
|
|
.info = info_node_device_destroy,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-detach",
|
|
|
|
.handler = cmdNodeDeviceDetach,
|
|
|
|
.opts = opts_node_device_detach,
|
|
|
|
.info = info_node_device_detach,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-dettach",
|
2016-09-07 15:30:48 +00:00
|
|
|
.flags = VSH_CMD_FLAG_ALIAS,
|
|
|
|
.alias = "nodedev-detach"
|
2013-02-07 15:25:10 +00:00
|
|
|
},
|
|
|
|
{.name = "nodedev-dumpxml",
|
|
|
|
.handler = cmdNodeDeviceDumpXML,
|
|
|
|
.opts = opts_node_device_dumpxml,
|
|
|
|
.info = info_node_device_dumpxml,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-list",
|
|
|
|
.handler = cmdNodeListDevices,
|
|
|
|
.opts = opts_node_list_devices,
|
|
|
|
.info = info_node_list_devices,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-reattach",
|
|
|
|
.handler = cmdNodeDeviceReAttach,
|
|
|
|
.opts = opts_node_device_reattach,
|
|
|
|
.info = info_node_device_reattach,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-reset",
|
|
|
|
.handler = cmdNodeDeviceReset,
|
|
|
|
.opts = opts_node_device_reset,
|
|
|
|
.info = info_node_device_reset,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2016-08-08 19:34:21 +00:00
|
|
|
{.name = "nodedev-event",
|
|
|
|
.handler = cmdNodeDeviceEvent,
|
|
|
|
.opts = opts_node_device_event,
|
|
|
|
.info = info_node_device_event,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-07-13 21:40:47 +00:00
|
|
|
{.name = "nodedev-define",
|
|
|
|
.handler = cmdNodeDeviceDefine,
|
|
|
|
.opts = opts_node_device_define,
|
|
|
|
.info = info_node_device_define,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-07-13 21:56:48 +00:00
|
|
|
{.name = "nodedev-undefine",
|
|
|
|
.handler = cmdNodeDeviceUndefine,
|
|
|
|
.opts = opts_node_device_undefine,
|
|
|
|
.info = info_node_device_undefine,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-07-09 21:05:41 +00:00
|
|
|
{.name = "nodedev-start",
|
|
|
|
.handler = cmdNodeDeviceStart,
|
|
|
|
.opts = opts_node_device_start,
|
|
|
|
.info = info_node_device_start,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = NULL}
|
2012-07-23 07:19:04 +00:00
|
|
|
};
|