This is the basic internal driver support code for the node device APIs. The actual registration of the drivers was pushed to a later patch to allow this to compile on its own & thus be fully bisectable. Daniel diff -r 6812c3044043 src/Makefile.am --- a/src/Makefile.am Wed Nov 12 21:11:46 2008 +0000 +++ b/src/Makefile.am Wed Nov 12 21:11:51 2008 +0000 @@ -132,6 +132,10 @@ 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 @@ -167,7 +171,8 @@ $(DRIVER_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ $(NETWORK_CONF_SOURCES) \ - $(STORAGE_CONF_SOURCES) + $(STORAGE_CONF_SOURCES) \ + $(NODE_DEVICE_CONF_SOURCES) if WITH_TEST if WITH_DRIVER_MODULES diff -r 6812c3044043 src/node_device_conf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_conf.c Wed Nov 12 21:11:51 2008 +0000 @@ -0,0 +1,425 @@ +/* + * 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 <dlively@xxxxxxxxxxxxxxx> + */ + +#include <config.h> + +#include <unistd.h> +#include <errno.h> + +#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, "<device>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", def->name); + + if (def->parent) + virBufferEscapeString(&buf, " <parent>%s</parent>\n", def->parent); + + for (caps = def->caps; caps; caps = caps->next) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + union _virNodeDevCapData *data = &caps->data; + + virBufferVSprintf(&buf, " <capability type='%s'>\n", + virNodeDevCapTypeToString(caps->type)); + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + if (data->system.product_name) + virBufferEscapeString(&buf, " <product>%s</product>\n", + data->system.product_name); + virBufferAddLit(&buf, " <hardware>\n"); + if (data->system.hardware.vendor_name) + virBufferEscapeString(&buf, " <vendor>%s</vendor>\n", + data->system.hardware.vendor_name); + if (data->system.hardware.version) + virBufferEscapeString(&buf, " <version>%s</version>\n", + data->system.hardware.version); + if (data->system.hardware.serial) + virBufferEscapeString(&buf, " <serial>%s</serial>\n", + data->system.hardware.serial); + virUUIDFormat(data->system.hardware.uuid, uuidstr); + virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", uuidstr); + virBufferAddLit(&buf, " </hardware>\n"); + virBufferAddLit(&buf, " <firmware>\n"); + if (data->system.firmware.vendor_name) + virBufferEscapeString(&buf, " <vendor>%s</vendor>\n", + data->system.firmware.vendor_name); + if (data->system.firmware.version) + virBufferEscapeString(&buf, " <version>%s</version>\n", + data->system.firmware.version); + if (data->system.firmware.release_date) + virBufferEscapeString(&buf, + " <release_date>%s</release_date>\n", + data->system.firmware.release_date); + virBufferAddLit(&buf, " </firmware>\n"); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + virBufferVSprintf(&buf, " <domain>%d</domain>\n", + data->pci_dev.domain); + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->pci_dev.bus); + virBufferVSprintf(&buf, " <slot>%d</slot>\n", + data->pci_dev.slot); + virBufferVSprintf(&buf, " <function>%d</function>\n", + data->pci_dev.function); + virBufferVSprintf(&buf, " <product id='%d'", + data->pci_dev.product); + if (data->pci_dev.product_name) + virBufferEscapeString(&buf, ">%s</product>\n", + data->pci_dev.product_name); + else + virBufferAddLit(&buf, " />\n"); + virBufferVSprintf(&buf, " <vendor id='%d'", + data->pci_dev.vendor); + if (data->pci_dev.vendor_name) + virBufferEscapeString(&buf, ">%s</vendor>\n", + data->pci_dev.vendor_name); + else + virBufferAddLit(&buf, " />\n"); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->usb_dev.bus); + virBufferVSprintf(&buf, " <device>%d</device>\n", + data->usb_dev.device); + virBufferVSprintf(&buf, " <product id='%d'", + data->usb_dev.product); + if (data->usb_dev.product_name) + virBufferEscapeString(&buf, ">%s</product>\n", + data->usb_dev.product_name); + else + virBufferAddLit(&buf, " />\n"); + virBufferVSprintf(&buf, " <vendor id='%d'", + data->usb_dev.vendor); + if (data->usb_dev.vendor_name) + virBufferEscapeString(&buf, ">%s</vendor>\n", + data->usb_dev.vendor_name); + else + virBufferAddLit(&buf, " />\n"); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + virBufferVSprintf(&buf, " <number>%d</number>\n", + data->usb_if.number); + virBufferVSprintf(&buf, " <class>%d</class>\n", + data->usb_if._class); + virBufferVSprintf(&buf, " <subclass>%d</subclass>\n", + data->usb_if.subclass); + virBufferVSprintf(&buf, " <protocol>%d</protocol>\n", + data->usb_if.protocol); + if (data->usb_if.description) + virBufferVSprintf(&buf, " <description>%s</description>\n", + data->usb_if.description); + break; + case VIR_NODE_DEV_CAP_NET: + virBufferVSprintf(&buf, " <interface>%s</interface>\n", + data->net.interface); + if (data->net.address) + virBufferVSprintf(&buf, " <address>%s</address>\n", + data->net.address); + if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { + const char *subtyp = + virNodeDevNetCapTypeToString(data->net.subtype); + virBufferVSprintf(&buf, " <capability type='%s'>\n", subtyp); + switch (data->net.subtype) { + case VIR_NODE_DEV_CAP_NET_80203: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80203.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_80211: + virBufferVSprintf(&buf, + " <mac_address>%012llx</address>\n", + data->net.data.ieee80211.mac_address); + break; + case VIR_NODE_DEV_CAP_NET_LAST: + /* Keep dumb compiler happy */ + break; + } + virBufferAddLit(&buf, " </capability>\n"); + } + break; + case VIR_NODE_DEV_CAP_BLOCK: + virBufferVSprintf(&buf, " <device>%s</device>\n", + data->block.device); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + virBufferVSprintf(&buf, " <host>%d</host>\n", + data->scsi_host.host); + break; + case VIR_NODE_DEV_CAP_SCSI: + virBufferVSprintf(&buf, " <host>%d</host>\n", data->scsi.host); + virBufferVSprintf(&buf, " <bus>%d</bus>\n", data->scsi.bus); + virBufferVSprintf(&buf, " <target>%d</target>\n", + data->scsi.target); + virBufferVSprintf(&buf, " <lun>%d</lun>\n", data->scsi.lun); + if (data->scsi.type) + virBufferVSprintf(&buf, " <type>%s</type>\n", + data->scsi.type); + break; + case VIR_NODE_DEV_CAP_STORAGE: + if (data->storage.bus) + virBufferVSprintf(&buf, " <bus>%s</bus>\n", + data->storage.bus); + if (data->storage.drive_type) + virBufferVSprintf(&buf, " <drive_type>%s</drive_type>\n", + data->storage.drive_type); + if (data->storage.originating_device) + virBufferVSprintf(&buf, + " <originating_device>%s" + "</originating_device>\n", + data->storage.originating_device); + if (data->storage.model) + virBufferVSprintf(&buf, " <model>%s</model>\n", + data->storage.model); + if (data->storage.vendor) + virBufferVSprintf(&buf, " <vendor>%s</vendor>\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, " <capability type='removable'>\n"); + virBufferVSprintf(&buf, + " <media_available>%d" + "</media_available>\n", avl ? 1 : 0); + virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n", + data->storage.removable_media_size); + virBufferAddLit(&buf, " </capability>\n"); + } else { + virBufferVSprintf(&buf, " <size>%llu</size>\n", + data->storage.size); + } + if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE) + virBufferAddLit(&buf, + " <capability type='hotpluggable' />\n"); + break; + case VIR_NODE_DEV_CAP_LAST: + /* ignore special LAST value */ + break; + } + + virBufferAddLit(&buf, " </capability>\n"); + } + + virBufferAddLit(&buf, "</device>\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 -r 6812c3044043 src/node_device_conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node_device_conf.h Wed Nov 12 21:11:51 2008 +0000 @@ -0,0 +1,204 @@ +/* + * 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 <dlively@xxxxxxxxxxxxxxx> + */ + +#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 */ + union { + struct { + unsigned long long mac_address; + } ieee80203; + struct { + unsigned long long mac_address; + } ieee80211; + } data; + } 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 *originating_device; + 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_DEVMONITOR, 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__ */ -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list