diff --git a/ChangeLog b/ChangeLog index 3ded42eda1..0f554f7561 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,12 @@ +Fri Nov 21 12:20:14 BST 2008 Daniel P. Berrange + + * src/Makefile.am, src/node_device_conf.c, src/node_device_conf.h: + Internal APIs for handling node device XML configuration + (David Lively) + Fri Nov 21 12:19:14 BST 2008 Daniel P. Berrange - Public API for node device enumeration + Public API for node device enumeration (David Lively) * include/libvirt/libvirt.h.in, include/libvirt/virterror.h: New public APIs for node device enumeration * src/datatypes.c, src/datatypes.h: Internal impl of public diff --git a/src/Makefile.am b/src/Makefile.am index a7ae633ac0..0e9e71d207 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -136,6 +136,10 @@ STORAGE_DRIVER_SOURCES = \ storage_driver.h storage_driver.c \ storage_backend.h storage_backend.c +# Network driver generic impl APIs +NODE_DEVICE_CONF_SOURCES = \ + node_device_conf.c node_device_conf.h + STORAGE_DRIVER_FS_SOURCES = \ storage_backend_fs.h storage_backend_fs.c @@ -171,7 +175,9 @@ libvirt_driver_la_SOURCES = \ $(DRIVER_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ $(NETWORK_CONF_SOURCES) \ - $(STORAGE_CONF_SOURCES) + $(STORAGE_CONF_SOURCES) \ + $(NODE_DEVICE_CONF_SOURCES) + libvirt_driver_la_CFLAGS = $(XEN_CFLAGS) libvirt_driver_la_LDFLAGS = $(XEN_LIBS) diff --git a/src/node_device_conf.c b/src/node_device_conf.c new file mode 100644 index 0000000000..d04b73d29d --- /dev/null +++ b/src/node_device_conf.c @@ -0,0 +1,404 @@ +/* + * node_device_conf.c: config handling for node devices + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * 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 + * + * Author: David F. Lively + */ + +#include + +#include +#include + +#include "virterror_internal.h" +#include "memory.h" + +#include "node_device_conf.h" +#include "memory.h" +#include "xml.h" +#include "util.h" +#include "buf.h" +#include "uuid.h" + + +VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST, + "system", + "pci", + "usb_device", + "usb", + "net", + "block", + "scsi_host", + "scsi", + "storage"); + +VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST, + "80203", + "80211"); + + +#define virNodeDeviceLog(msg...) fprintf(stderr, msg) + +virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs, + const char *name) +{ + unsigned int i; + + for (i = 0; i < devs->count; i++) + if (STREQ(devs->objs[i]->def->name, name)) + return devs->objs[i]; + + return NULL; +} + + +void virNodeDeviceDefFree(virNodeDeviceDefPtr def) +{ + virNodeDevCapsDefPtr caps; + + if (!def) + return; + + VIR_FREE(def->name); + VIR_FREE(def->parent); + + caps = def->caps; + while (caps) { + virNodeDevCapsDefPtr next = caps->next; + virNodeDevCapsDefFree(caps); + caps = next; + } + + VIR_FREE(def); +} + +void virNodeDeviceObjFree(virNodeDeviceObjPtr dev) +{ + if (!dev) + return; + + virNodeDeviceDefFree(dev->def); + if (dev->privateFree) + (*dev->privateFree)(dev->privateData); + + VIR_FREE(dev); +} + +void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs) +{ + unsigned int i; + for (i = 0 ; i < devs->count ; i++) + virNodeDeviceObjFree(devs->objs[i]); + VIR_FREE(devs->objs); + devs->count = 0; +} + +virNodeDeviceObjPtr virNodeDeviceAssignDef(virConnectPtr conn, + virNodeDeviceObjListPtr devs, + const virNodeDeviceDefPtr def) +{ + virNodeDeviceObjPtr device; + + if ((device = virNodeDeviceFindByName(devs, def->name))) { + virNodeDeviceDefFree(device->def); + device->def = def; + return device; + } + + if (VIR_ALLOC(device) < 0) { + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + return NULL; + } + + device->def = def; + + if (VIR_REALLOC_N(devs->objs, devs->count+1) < 0) { + device->def = NULL; + virNodeDeviceObjFree(device); + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + return NULL; + } + devs->objs[devs->count++] = device; + + return device; + +} + +void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs, + const virNodeDeviceObjPtr dev) +{ + unsigned int i; + + for (i = 0; i < devs->count; i++) { + if (devs->objs[i] == dev) { + virNodeDeviceObjFree(devs->objs[i]); + + if (i < (devs->count - 1)) + memmove(devs->objs + i, devs->objs + i + 1, + sizeof(*(devs->objs)) * (devs->count - (i + 1))); + + if (VIR_REALLOC_N(devs->objs, devs->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + devs->count--; + + break; + } + } +} + +char *virNodeDeviceDefFormat(virConnectPtr conn, + const virNodeDeviceDefPtr def) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virNodeDevCapsDefPtr caps = def->caps; + char *tmp; + + virBufferAddLit(&buf, "\n"); + virBufferEscapeString(&buf, " %s\n", def->name); + + if (def->parent) + virBufferEscapeString(&buf, " %s\n", def->parent); + + for (caps = def->caps; caps; caps = caps->next) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + union _virNodeDevCapData *data = &caps->data; + + virBufferVSprintf(&buf, " \n", + virNodeDevCapTypeToString(caps->type)); + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + if (data->system.product_name) + virBufferEscapeString(&buf, " %s\n", + data->system.product_name); + virBufferAddLit(&buf, " \n"); + if (data->system.hardware.vendor_name) + virBufferEscapeString(&buf, " %s\n", + data->system.hardware.vendor_name); + if (data->system.hardware.version) + virBufferEscapeString(&buf, " %s\n", + data->system.hardware.version); + if (data->system.hardware.serial) + virBufferEscapeString(&buf, " %s\n", + data->system.hardware.serial); + virUUIDFormat(data->system.hardware.uuid, uuidstr); + virBufferVSprintf(&buf, " %s\n", uuidstr); + virBufferAddLit(&buf, " \n"); + virBufferAddLit(&buf, " \n"); + if (data->system.firmware.vendor_name) + virBufferEscapeString(&buf, " %s\n", + data->system.firmware.vendor_name); + if (data->system.firmware.version) + virBufferEscapeString(&buf, " %s\n", + data->system.firmware.version); + if (data->system.firmware.release_date) + virBufferEscapeString(&buf, + " %s\n", + data->system.firmware.release_date); + virBufferAddLit(&buf, " \n"); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + virBufferVSprintf(&buf, " %d\n", + data->pci_dev.domain); + virBufferVSprintf(&buf, " %d\n", data->pci_dev.bus); + virBufferVSprintf(&buf, " %d\n", + data->pci_dev.slot); + virBufferVSprintf(&buf, " %d\n", + data->pci_dev.function); + virBufferVSprintf(&buf, " pci_dev.product); + if (data->pci_dev.product_name) + virBufferEscapeString(&buf, ">%s\n", + data->pci_dev.product_name); + else + virBufferAddLit(&buf, " />\n"); + virBufferVSprintf(&buf, " pci_dev.vendor); + if (data->pci_dev.vendor_name) + virBufferEscapeString(&buf, ">%s\n", + data->pci_dev.vendor_name); + else + virBufferAddLit(&buf, " />\n"); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + virBufferVSprintf(&buf, " %d\n", data->usb_dev.bus); + virBufferVSprintf(&buf, " %d\n", + data->usb_dev.device); + virBufferVSprintf(&buf, " usb_dev.product); + if (data->usb_dev.product_name) + virBufferEscapeString(&buf, ">%s\n", + data->usb_dev.product_name); + else + virBufferAddLit(&buf, " />\n"); + virBufferVSprintf(&buf, " usb_dev.vendor); + if (data->usb_dev.vendor_name) + virBufferEscapeString(&buf, ">%s\n", + data->usb_dev.vendor_name); + else + virBufferAddLit(&buf, " />\n"); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + virBufferVSprintf(&buf, " %d\n", + data->usb_if.number); + virBufferVSprintf(&buf, " %d\n", + data->usb_if._class); + virBufferVSprintf(&buf, " %d\n", + data->usb_if.subclass); + virBufferVSprintf(&buf, " %d\n", + data->usb_if.protocol); + if (data->usb_if.description) + virBufferVSprintf(&buf, " %s\n", + data->usb_if.description); + break; + case VIR_NODE_DEV_CAP_NET: + virBufferVSprintf(&buf, " %s\n", + data->net.interface); + if (data->net.address) + virBufferVSprintf(&buf, "
%s
\n", + data->net.address); + if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { + const char *subtyp = + virNodeDevNetCapTypeToString(data->net.subtype); + virBufferVSprintf(&buf, " \n", subtyp); + } + break; + case VIR_NODE_DEV_CAP_BLOCK: + virBufferVSprintf(&buf, " %s\n", + data->block.device); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + virBufferVSprintf(&buf, " %d\n", + data->scsi_host.host); + break; + case VIR_NODE_DEV_CAP_SCSI: + virBufferVSprintf(&buf, " %d\n", data->scsi.host); + virBufferVSprintf(&buf, " %d\n", data->scsi.bus); + virBufferVSprintf(&buf, " %d\n", + data->scsi.target); + virBufferVSprintf(&buf, " %d\n", data->scsi.lun); + if (data->scsi.type) + virBufferVSprintf(&buf, " %s\n", + data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + if (data->storage.bus) + virBufferVSprintf(&buf, " %s\n", + data->storage.bus); + if (data->storage.drive_type) + virBufferVSprintf(&buf, " %s\n", + data->storage.drive_type); + if (data->storage.model) + virBufferVSprintf(&buf, " %s\n", + data->storage.model); + if (data->storage.vendor) + virBufferVSprintf(&buf, " %s\n", + data->storage.vendor); + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) { + int avl = data->storage.flags & + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + virBufferAddLit(&buf, " \n"); + virBufferVSprintf(&buf, + " %d" + "\n", avl ? 1 : 0); + virBufferVSprintf(&buf, " %llu\n", + data->storage.removable_media_size); + virBufferAddLit(&buf, " \n"); + } else { + virBufferVSprintf(&buf, " %llu\n", + data->storage.size); + } + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) + virBufferAddLit(&buf, + " \n"); + break; + case VIR_NODE_DEV_CAP_LAST: + /* ignore special LAST value */ + break; + } + + virBufferAddLit(&buf, " \n"); + } + + virBufferAddLit(&buf, "
\n"); + + if (virBufferError(&buf)) + goto no_memory; + + return virBufferContentAndReset(&buf); + + no_memory: + virNodeDeviceReportError(conn, VIR_ERR_NO_MEMORY, NULL); + tmp = virBufferContentAndReset(&buf); + VIR_FREE(tmp); + return NULL; +} + +void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) +{ + union _virNodeDevCapData *data = &caps->data; + + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + VIR_FREE(data->system.product_name); + VIR_FREE(data->system.hardware.vendor_name); + VIR_FREE(data->system.hardware.version); + VIR_FREE(data->system.hardware.serial); + VIR_FREE(data->system.firmware.vendor_name); + VIR_FREE(data->system.firmware.version); + VIR_FREE(data->system.firmware.release_date); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + VIR_FREE(data->pci_dev.product_name); + VIR_FREE(data->pci_dev.vendor_name); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + VIR_FREE(data->usb_dev.product_name); + VIR_FREE(data->usb_dev.vendor_name); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + VIR_FREE(data->usb_if.description); + break; + case VIR_NODE_DEV_CAP_NET: + VIR_FREE(data->net.interface); + VIR_FREE(data->net.address); + break; + case VIR_NODE_DEV_CAP_BLOCK: + VIR_FREE(data->block.device); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + break; + case VIR_NODE_DEV_CAP_SCSI: + VIR_FREE(data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + VIR_FREE(data->storage.bus); + VIR_FREE(data->storage.drive_type); + VIR_FREE(data->storage.model); + VIR_FREE(data->storage.vendor); + break; + case VIR_NODE_DEV_CAP_LAST: + /* This case is here to shutup the compiler */ + break; + } + + VIR_FREE(caps); +} + diff --git a/src/node_device_conf.h b/src/node_device_conf.h new file mode 100644 index 0000000000..abb176838c --- /dev/null +++ b/src/node_device_conf.h @@ -0,0 +1,195 @@ +/* + * node_device_conf.h: config handling for node devices + * + * Copyright (C) 2008 Virtual Iron Software, Inc. + * Copyright (C) 2008 David F. Lively + * + * 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 + * + * Author: David F. Lively + */ + +#ifndef __VIR_NODE_DEVICE_CONF_H__ +#define __VIR_NODE_DEVICE_CONF_H__ + +#include "internal.h" +#include "util.h" + +enum virNodeDevCapType { + /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ + VIR_NODE_DEV_CAP_SYSTEM, /* System capability */ + VIR_NODE_DEV_CAP_PCI_DEV, /* PCI device */ + VIR_NODE_DEV_CAP_USB_DEV, /* USB device */ + VIR_NODE_DEV_CAP_USB_INTERFACE, /* USB interface */ + VIR_NODE_DEV_CAP_NET, /* Network device */ + VIR_NODE_DEV_CAP_BLOCK, /* Block device */ + VIR_NODE_DEV_CAP_SCSI_HOST, /* SCSI Host Bus Adapter */ + VIR_NODE_DEV_CAP_SCSI, /* SCSI device */ + VIR_NODE_DEV_CAP_STORAGE, /* Storage device */ + VIR_NODE_DEV_CAP_LAST +}; + +enum virNodeDevNetCapType { + /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ + VIR_NODE_DEV_CAP_NET_80203, /* 802.03 network device */ + VIR_NODE_DEV_CAP_NET_80211, /* 802.11 network device */ + VIR_NODE_DEV_CAP_NET_LAST +}; + +VIR_ENUM_DECL(virNodeDevCap); +VIR_ENUM_DECL(virNodeDevNetCap); + +enum virNodeDevStorageCapFlags { + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE = (1 << 0), + VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE = (1 << 1), + VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE = (1 << 2), +}; + +typedef struct _virNodeDevCapsDef virNodeDevCapsDef; +typedef virNodeDevCapsDef *virNodeDevCapsDefPtr; +struct _virNodeDevCapsDef { + enum virNodeDevCapType type; + union _virNodeDevCapData { + struct { + char *product_name; + struct { + char *vendor_name; + char *version; + char *serial; + unsigned char uuid[VIR_UUID_BUFLEN]; + } hardware; + struct { + char *vendor_name; + char *version; + char *release_date; + } firmware; + } system; + struct { + unsigned domain; + unsigned bus; + unsigned slot; + unsigned function; + unsigned product; + unsigned vendor; + char *product_name; + char *vendor_name; + } pci_dev; + struct { + unsigned bus; + unsigned device; + unsigned product; + unsigned vendor; + char *product_name; + char *vendor_name; + } usb_dev; + struct { + unsigned number; + unsigned _class; /* "class" is reserved in C */ + unsigned subclass; + unsigned protocol; + char *description; + } usb_if; + struct { + char *address; + char *interface; + enum virNodeDevNetCapType subtype; /* LAST -> no subtype */ + } net; + struct { + char *device; + } block; + struct { + unsigned host; + } scsi_host; + struct { + unsigned host; + unsigned bus; + unsigned target; + unsigned lun; + char *type; + } scsi; + struct { + unsigned long long size; + unsigned long long removable_media_size; + char *bus; + char *drive_type; + char *model; + char *vendor; + unsigned flags; /* virNodeDevStorageCapFlags bits */ + } storage; + } data; + virNodeDevCapsDefPtr next; /* next capability */ +}; + + +typedef struct _virNodeDeviceDef virNodeDeviceDef; +typedef virNodeDeviceDef *virNodeDeviceDefPtr; +struct _virNodeDeviceDef { + char *name; /* device name (unique on node) */ + char *parent; /* optional parent device name */ + virNodeDevCapsDefPtr caps; /* optional device capabilities */ +}; + + +typedef struct _virNodeDeviceObj virNodeDeviceObj; +typedef virNodeDeviceObj *virNodeDeviceObjPtr; +struct _virNodeDeviceObj { + virNodeDeviceDefPtr def; /* device definition */ + void *privateData; /* driver-specific private data */ + void (*privateFree)(void *data); /* destructor for private data */ + +}; + +typedef struct _virNodeDeviceObjList virNodeDeviceObjList; +typedef virNodeDeviceObjList *virNodeDeviceObjListPtr; +struct _virNodeDeviceObjList { + unsigned int count; + virNodeDeviceObjPtr *objs; +}; + +typedef struct _virDeviceMonitorState virDeviceMonitorState; +typedef virDeviceMonitorState *virDeviceMonitorStatePtr; +struct _virDeviceMonitorState { + virNodeDeviceObjList devs; /* currently-known devices */ + void *privateData; /* driver-specific private data */ +}; + +#define virNodeDeviceReportError(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_NODEDEV, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs, + const char *name); + +virNodeDeviceObjPtr virNodeDeviceAssignDef(virConnectPtr conn, + virNodeDeviceObjListPtr devs, + const virNodeDeviceDefPtr def); + +void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs, + const virNodeDeviceObjPtr dev); + +char *virNodeDeviceDefFormat(virConnectPtr conn, + const virNodeDeviceDefPtr def); + +// TODO: virNodeDeviceDefParseString/File/Node for virNodeDeviceCreate + +void virNodeDeviceDefFree(virNodeDeviceDefPtr def); + +void virNodeDeviceObjFree(virNodeDeviceObjPtr dev); + +void virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs); + +void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps); + +#endif /* __VIR_NODE_DEVICE_CONF_H__ */