diff options
author | Daniel P. Berrange <berrange@redhat.com> | 2014-10-22 16:29:09 +0100 |
---|---|---|
committer | Daniel P. Berrange <berrange@redhat.com> | 2014-10-24 16:26:55 +0100 |
commit | e33ed8cdfefb901b24213f2f85b40ce31b6550a5 (patch) | |
tree | f9b43fd9bd97da57ba51eebef87af5e1aad8c547 /src/libvirt-nodedev.c | |
parent | 35ed98755fe8048a796ddf5b1c3cee73a4732731 (diff) | |
download | libvirt-e33ed8cdfefb901b24213f2f85b40ce31b6550a5.tar.gz |
Move virNodeDevice related APIs out of libvirt.c
Introduce a src/libvirt-nodedev.c file to hold all the
methods related to the virNodeDevice type.
Diffstat (limited to 'src/libvirt-nodedev.c')
-rw-r--r-- | src/libvirt-nodedev.c | 756 |
1 files changed, 756 insertions, 0 deletions
diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c new file mode 100644 index 0000000000..c19aeeff5b --- /dev/null +++ b/src/libvirt-nodedev.c @@ -0,0 +1,756 @@ +/* + * libvirt-nodedev.c: entry points for virNodeDevPtr APIs + * + * Copyright (C) 2006-2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include "datatypes.h" +#include "virlog.h" + +VIR_LOG_INIT("libvirt.nodedev"); + +#define VIR_FROM_THIS VIR_FROM_NODEDEV + + +/** + * virNodeNumOfDevices: + * @conn: pointer to the hypervisor connection + * @cap: capability name + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Provides the number of node devices. + * + * If the optional 'cap' argument is non-NULL, then the count + * will be restricted to devices with the specified capability + * + * Returns the number of node devices or -1 in case of error + */ +int +virNodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags) +{ + VIR_DEBUG("conn=%p, cap=%s, flags=%x", conn, NULLSTR(cap), flags); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + + if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeNumOfDevices) { + int ret; + ret = conn->nodeDeviceDriver->nodeNumOfDevices(conn, cap, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + + +/** + * virConnectListAllNodeDevices: + * @conn: Pointer to the hypervisor connection. + * @devices: Pointer to a variable to store the array containing the node + * device objects or NULL if the list is not required (just returns + * number of node devices). + * @flags: bitwise-OR of virConnectListAllNodeDevices. + * + * Collect the list of node devices, and allocate an array to store those + * objects. + * + * Normally, all node devices are returned; however, @flags can be used to + * filter the results for a smaller list of targeted node devices. The valid + * flags are divided into groups, where each group contains bits that + * describe mutually exclusive attributes of a node device, and where all bits + * within a group describe all possible node devices. + * + * Only one group of the @flags is provided to filter the node devices by + * capability type, flags include: + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_GENERIC + * + * Returns the number of node devices found or -1 and sets @devices to NULL in + * case of error. On success, the array stored into @devices is guaranteed to + * have an extra allocated element set to NULL but not included in the return + * count, to make iteration easier. The caller is responsible for calling + * virNodeDeviceFree() on each array element, then calling free() on + * @devices. + */ +int +virConnectListAllNodeDevices(virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, devices=%p, flags=%x", conn, devices, flags); + + virResetLastError(); + + if (devices) + *devices = NULL; + + virCheckConnectReturn(conn, -1); + + if (conn->nodeDeviceDriver && + conn->nodeDeviceDriver->connectListAllNodeDevices) { + int ret; + ret = conn->nodeDeviceDriver->connectListAllNodeDevices(conn, devices, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + + +/** + * virNodeListDevices: + * @conn: pointer to the hypervisor connection + * @cap: capability name + * @names: array to collect the list of node device names + * @maxnames: size of @names + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Collect the list of node devices, and store their names in @names + * + * For more control over the results, see virConnectListAllNodeDevices(). + * + * If the optional 'cap' argument is non-NULL, then the count + * will be restricted to devices with the specified capability + * + * Returns the number of node devices found or -1 in case of error + */ +int +virNodeListDevices(virConnectPtr conn, + const char *cap, + char **const names, int maxnames, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, cap=%s, names=%p, maxnames=%d, flags=%x", + conn, cap, names, maxnames, flags); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + virCheckNonNullArgGoto(names, error); + virCheckNonNegativeArgGoto(maxnames, error); + + if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeListDevices) { + int ret; + ret = conn->nodeDeviceDriver->nodeListDevices(conn, cap, names, maxnames, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return -1; +} + + +/** + * virNodeDeviceLookupByName: + * @conn: pointer to the hypervisor connection + * @name: unique device name + * + * Lookup a node device by its name. + * + * virNodeDeviceFree should be used to free the resources after the + * node device object is no longer needed. + * + * Returns a virNodeDevicePtr if found, NULL otherwise. + */ +virNodeDevicePtr +virNodeDeviceLookupByName(virConnectPtr conn, const char *name) +{ + VIR_DEBUG("conn=%p, name=%p", conn, name); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(name, error); + + if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeDeviceLookupByName) { + virNodeDevicePtr ret; + ret = conn->nodeDeviceDriver->nodeDeviceLookupByName(conn, name); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virNodeDeviceLookupSCSIHostByWWN: + * @conn: pointer to the hypervisor connection + * @wwnn: WWNN of the SCSI Host. + * @wwpn: WWPN of the SCSI Host. + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Lookup SCSI Host which is capable with 'fc_host' by its WWNN and WWPN. + * + * virNodeDeviceFree should be used to free the resources after the + * node device object is no longer needed. + * + * Returns a virNodeDevicePtr if found, NULL otherwise. + */ +virNodeDevicePtr +virNodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, wwnn=%p, wwpn=%p, flags=%x", conn, wwnn, wwpn, flags); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckNonNullArgGoto(wwnn, error); + virCheckNonNullArgGoto(wwpn, error); + + if (conn->nodeDeviceDriver && + conn->nodeDeviceDriver->nodeDeviceLookupSCSIHostByWWN) { + virNodeDevicePtr ret; + ret = conn->nodeDeviceDriver->nodeDeviceLookupSCSIHostByWWN(conn, wwnn, + wwpn, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virNodeDeviceGetXMLDesc: + * @dev: pointer to the node device + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Fetch an XML document describing all aspects of + * the device. + * + * Returns the XML document, or NULL on error + */ +char * +virNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags) +{ + VIR_DEBUG("dev=%p, conn=%p, flags=%x", dev, dev ? dev->conn : NULL, flags); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, NULL); + + if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceGetXMLDesc) { + char *ret; + ret = dev->conn->nodeDeviceDriver->nodeDeviceGetXMLDesc(dev, flags); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return NULL; +} + + +/** + * virNodeDeviceGetName: + * @dev: the device + * + * Just return the device name + * + * Returns the device name or NULL in case of error + */ +const char * +virNodeDeviceGetName(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, NULL); + + return dev->name; +} + + +/** + * virNodeDeviceGetParent: + * @dev: the device + * + * Accessor for the parent of the device + * + * Returns the name of the device's parent, or NULL if an + * error occurred or when the device has no parent. + */ +const char * +virNodeDeviceGetParent(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, NULL); + + if (!dev->parent) { + if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceGetParent) { + dev->parent = dev->conn->nodeDeviceDriver->nodeDeviceGetParent(dev); + } else { + virReportUnsupportedError(); + virDispatchError(dev->conn); + return NULL; + } + } + return dev->parent; +} + + +/** + * virNodeDeviceNumOfCaps: + * @dev: the device + * + * Accessor for the number of capabilities supported by the device. + * + * Returns the number of capabilities supported by the device or -1 + * in case of error. + */ +int +virNodeDeviceNumOfCaps(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + + if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceNumOfCaps) { + int ret; + ret = dev->conn->nodeDeviceDriver->nodeDeviceNumOfCaps(dev); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} + + +/** + * virNodeDeviceListCaps: + * @dev: the device + * @names: array to collect the list of capability names + * @maxnames: size of @names + * + * Lists the names of the capabilities supported by the device. + * + * Returns the number of capability names listed in @names or -1 + * in case of error. + */ +int +virNodeDeviceListCaps(virNodeDevicePtr dev, + char **const names, + int maxnames) +{ + VIR_DEBUG("dev=%p, conn=%p, names=%p, maxnames=%d", + dev, dev ? dev->conn : NULL, names, maxnames); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + virCheckNonNullArgGoto(names, error); + virCheckNonNegativeArgGoto(maxnames, error); + + if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceListCaps) { + int ret; + ret = dev->conn->nodeDeviceDriver->nodeDeviceListCaps(dev, names, maxnames); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} + + +/** + * virNodeDeviceFree: + * @dev: pointer to the node device + * + * Drops a reference to the node device, freeing it if + * this was the last reference. + * + * Returns the 0 for success, -1 for error. + */ +int +virNodeDeviceFree(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + + virObjectUnref(dev); + return 0; +} + + +/** + * virNodeDeviceRef: + * @dev: the dev to hold a reference on + * + * Increment the reference count on the dev. For each + * additional call to this method, there shall be a corresponding + * call to virNodeDeviceFree to release the reference count, once + * the caller no longer needs the reference to this object. + * + * This method is typically useful for applications where multiple + * threads are using a connection, and it is required that the + * connection remain open until all threads have finished using + * it. ie, each new thread using a dev would increment + * the reference count. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeDeviceRef(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p refs=%d", dev, dev ? dev->object.u.s.refs : 0); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + + virObjectRef(dev); + return 0; +} + + +/** + * virNodeDeviceDettach: + * @dev: pointer to the node device + * + * Dettach the node device from the node itself so that it may be + * assigned to a guest domain. + * + * Depending on the hypervisor, this may involve operations such + * as unbinding any device drivers from the device, binding the + * device to a dummy device driver and resetting the device. + * + * If the device is currently in use by the node, this method may + * fail. + * + * Once the device is not assigned to any guest, it may be re-attached + * to the node using the virNodeDeviceReattach() method. + * + * If the caller needs control over which backend driver will be used + * during PCI device assignment (to use something other than the + * default, for example VFIO), the newer virNodeDeviceDetachFlags() + * API should be used instead. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeDeviceDettach(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + virCheckReadOnlyGoto(dev->conn->flags, error); + + if (dev->conn->driver->nodeDeviceDettach) { + int ret; + ret = dev->conn->driver->nodeDeviceDettach(dev); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} + + +/** + * virNodeDeviceDetachFlags: + * @dev: pointer to the node device + * @driverName: name of backend driver that will be used + * for later device assignment to a domain. NULL + * means "use the hypervisor default driver" + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Detach the node device from the node itself so that it may be + * assigned to a guest domain. + * + * Depending on the hypervisor, this may involve operations such as + * unbinding any device drivers from the device, binding the device to + * a dummy device driver and resetting the device. Different backend + * drivers expect the device to be bound to different dummy + * devices. For example, QEMU's "kvm" backend driver (the default) + * expects the device to be bound to "pci-stub", but its "vfio" + * backend driver expects the device to be bound to "vfio-pci". + * + * If the device is currently in use by the node, this method may + * fail. + * + * Once the device is not assigned to any guest, it may be re-attached + * to the node using the virNodeDeviceReAttach() method. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeDeviceDetachFlags(virNodeDevicePtr dev, + const char *driverName, + unsigned int flags) +{ + VIR_DEBUG("dev=%p, conn=%p driverName=%s flags=%x", + dev, dev ? dev->conn : NULL, + driverName ? driverName : "(default)", flags); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + virCheckReadOnlyGoto(dev->conn->flags, error); + + if (dev->conn->driver->nodeDeviceDetachFlags) { + int ret; + ret = dev->conn->driver->nodeDeviceDetachFlags(dev, driverName, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} + + +/** + * virNodeDeviceReAttach: + * @dev: pointer to the node device + * + * Re-attach a previously dettached node device to the node so that it + * may be used by the node again. + * + * Depending on the hypervisor, this may involve operations such + * as resetting the device, unbinding it from a dummy device driver + * and binding it to its appropriate driver. + * + * If the device is currently in use by a guest, this method may fail. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeDeviceReAttach(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + virCheckReadOnlyGoto(dev->conn->flags, error); + + if (dev->conn->driver->nodeDeviceReAttach) { + int ret; + ret = dev->conn->driver->nodeDeviceReAttach(dev); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} + + +/** + * virNodeDeviceReset: + * @dev: pointer to the node device + * + * Reset a previously dettached node device to the node before or + * after assigning it to a guest. + * + * The exact reset semantics depends on the hypervisor and device + * type but, for example, KVM will attempt to reset PCI devices with + * a Function Level Reset, Secondary Bus Reset or a Power Management + * D-State reset. + * + * If the reset will affect other devices which are currently in use, + * this function may fail. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeDeviceReset(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + virCheckReadOnlyGoto(dev->conn->flags, error); + + if (dev->conn->driver->nodeDeviceReset) { + int ret; + ret = dev->conn->driver->nodeDeviceReset(dev); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} + + +/** + * virNodeDeviceCreateXML: + * @conn: pointer to the hypervisor connection + * @xmlDesc: string containing an XML description of the device to be created + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Create a new device on the VM host machine, for example, virtual + * HBAs created using vport_create. + * + * virNodeDeviceFree should be used to free the resources after the + * node device object is no longer needed. + * + * Returns a node device object if successful, NULL in case of failure + */ +virNodeDevicePtr +virNodeDeviceCreateXML(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + virCheckReadOnlyGoto(conn->flags, error); + virCheckNonNullArgGoto(xmlDesc, error); + + if (conn->nodeDeviceDriver && + conn->nodeDeviceDriver->nodeDeviceCreateXML) { + virNodeDevicePtr dev = conn->nodeDeviceDriver->nodeDeviceCreateXML(conn, xmlDesc, flags); + if (dev == NULL) + goto error; + return dev; + } + + virReportUnsupportedError(); + + error: + virDispatchError(conn); + return NULL; +} + + +/** + * virNodeDeviceDestroy: + * @dev: a device object + * + * Destroy the device object. The virtual device (only works for vHBA + * currently) is removed from the host operating system. This function + * may require privileged access. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virNodeDeviceDestroy(virNodeDevicePtr dev) +{ + VIR_DEBUG("dev=%p", dev); + + virResetLastError(); + + virCheckNodeDeviceReturn(dev, -1); + virCheckReadOnlyGoto(dev->conn->flags, error); + + if (dev->conn->nodeDeviceDriver && + dev->conn->nodeDeviceDriver->nodeDeviceDestroy) { + int retval = dev->conn->nodeDeviceDriver->nodeDeviceDestroy(dev); + if (retval < 0) { + goto error; + } + + return 0; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dev->conn); + return -1; +} |