From 5be54b40cbe505ecebd463c81fb3c16f2c28a1ab Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 14 Feb 2007 15:37:18 +0000 Subject: [PATCH] Tue Feb 14 15:33:05 EST 2007 Mark McLoughlin * include/libvirt/libvirt.h.in: add the networks APIs * include/libvirt/virterror.h: add some error codes * src/driver.h: add network driver vtable * src/hash.c: add networks hash * src/internal.h: add virNetwork * src/libvirt.c: hook up the APIs to the network driver * src/libvirt_sym.version: add the new APIs * src/virterror.c: handle the new error codes --- ChangeLog | 88 ++++- include/libvirt/libvirt.h.in | 84 +++++ include/libvirt/virterror.h | 5 +- src/driver.h | 60 +++ src/hash.c | 196 +++++++++- src/internal.h | 37 +- src/libvirt.c | 703 ++++++++++++++++++++++++++++++++++- src/libvirt_sym.version | 19 + src/virterror.c | 15 + 9 files changed, 1172 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index eb3ebfc34b..1446c02a6c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,90 @@ -Tue Feb 14 14:33:22 EST 2007 Mark McLoughlin + + * include/libvirt/libvirt.h.in: add the networks APIs + + * include/libvirt/virterror.h: add some error codes + + * src/driver.h: add network driver vtable + + * src/hash.c: add networks hash + + * src/internal.h: add virNetwork + + * src/libvirt.c: hook up the APIs to the network + driver + + * src/libvirt_sym.version: add the new APIs + + * src/virterror.c: handle the new error codes + +Tue Feb 14 15:07:26 EST 2007 Mark McLoughlin + + * src/conf.h: fix merge error - remove the argc argument + from qemudBuildCommandLine() + +Tue Feb 14 15:03:22 EST 2007 Mark McLoughlin + + * src/virsh.c: Re-name some of the VSH_DOMBYFOO stuff + to VSH_BYFOO in order to re-use it for the network stuff. + +Tue Feb 14 14:58:35 EST 2007 Mark McLoughlin + + * src/hash.c, src/internal.h: Re-name virConnect->domains_mux + to virConnect->hashes_mux since it will also be used to + protect the networks hash. + +Tue Feb 14 14:57:52 EST 2007 Mark McLoughlin + + * qemud/conf.c: qemudSaveConfig() will always report a + more specific error, so we should avoid overwriting + this error. + +Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin + + * qemud/qemud.c: Re-factor out qemudExec() so that it can + be used to launch dnsmasq. + + * qemud/conf.c: don't return argc from qemudBuildCommandLine() + as exec() doesn't need it. + +Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin + + * qemud/conf.c: Re-factor bits of conf.c so that: + + - qemudMakeConfigPath() can be re-used given another configDir + - split qemudEnsureConfigDir() out of qemudSaveConfig() so + that it may be re-used to create another configDir + - split qemudScanConfigDir() out so that qemudScanConfigs() + can scan multiple configDirs + +Tue Feb 14 14:50:22 EST 2007 Mark McLoughlin + + * qemud/conf.c: handle an unspecified MAC address, + fix the argv freeing code in qemudBuildCommandLine() + and fix copy and paste error in qemudGenerateXML() + +Tue Feb 14 14:42:38 EST 2007 Mark McLoughlin + + * src/internal.h: add virConnect->qemud_fd so that + xen and qemu don't share the handle member. + + * src/hash.c, src/qemu_internal.c: update + +Tue Feb 14 14:40:52 EST 2007 Mark McLoughlin + + * qemud/conf.c, qemud/dispatch.c, qemud/driver.c, + qemud/qemud.c: include autoconf's config.h + +Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin + + * conf.[ch]: rename from config.[ch] so we can use + autoconf's config.h + + * Makefile.am: update + + * driver.c, qemud.c: upd. + +Tue Feb 14 14:33:22 EST 2007 Mark McLoughlin * autogen.sh: run autoheader diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 489a83d457..72d5730ae3 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -443,6 +443,90 @@ int virDomainGetVcpus (virDomainPtr domain, int virDomainAttachDevice(virDomainPtr domain, char *xml); int virDomainDetachDevice(virDomainPtr domain, char *xml); +/* + * Virtual Networks API + */ + +/** + * virNetwork: + * + * a virNetwork is a private structure representing a virtual network. + */ +typedef struct _virNetwork virNetwork; + +/** + * virNetworkPtr: + * + * a virNetworkPtr is pointer to a virNetwork private structure, this is the + * type used to reference a virtual network in the API. + */ +typedef virNetwork *virNetworkPtr; + +/* + * List active networks + */ +int virConnectNumOfNetworks (virConnectPtr conn); +int virConnectListNetworks (virConnectPtr conn, + const char **names, + int maxnames); + +/* + * List inactive networks + */ +int virConnectNumOfDefinedNetworks (virConnectPtr conn); +int virConnectListDefinedNetworks (virConnectPtr conn, + const char **names, + int maxnames); + +/* + * Lookup network by name or uuid + */ +virNetworkPtr virNetworkLookupByName (virConnectPtr conn, + const char *name); +virNetworkPtr virNetworkLookupByUUID (virConnectPtr conn, + const unsigned char *uuid); +virNetworkPtr virNetworkLookupByUUIDString (virConnectPtr conn, + const char *uuid); + +/* + * Create active transient network + */ +virNetworkPtr virNetworkCreateXML (virConnectPtr conn, + const char *xmlDesc); + +/* + * Define inactive persistent network + */ +virNetworkPtr virNetworkDefineXML (virConnectPtr conn, + const char *xmlDesc); + +/* + * Delete persistent network + */ +int virNetworkUndefine (virNetworkPtr network); + +/* + * Activate persistent network + */ +int virNetworkCreate (virNetworkPtr network); + +/* + * Network destroy/free + */ +int virNetworkDestroy (virNetworkPtr network); +int virNetworkFree (virNetworkPtr network); + +/* + * Network informations + */ +const char* virNetworkGetName (virNetworkPtr network); +int virNetworkGetUUID (virNetworkPtr network, + unsigned char *uuid); +int virNetworkGetUUIDString (virNetworkPtr network, + char *buf); +char * virNetworkGetXMLDesc (virNetworkPtr network, + int flags); + #ifdef __cplusplus } #endif diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 8a7959eb5d..80d43f9cd9 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -48,6 +48,7 @@ typedef enum { VIR_FROM_PROXY, /* Error in the proxy code */ VIR_FROM_CONF, /* Error in the configuration file handling */ VIR_FROM_QEMU, /* Error at the QEMU daemon */ + VIR_FROM_NET, /* Error when operating on a network */ } virErrorDomain; @@ -114,7 +115,9 @@ typedef enum { VIR_ERR_PARSE_FAILED, /* failed to parse a conf file */ VIR_ERR_CONF_SYNTAX, /* failed to parse the syntax of a conf file */ VIR_ERR_WRITE_FAILED, /* failed to write a conf file */ - VIR_ERR_XML_DETAIL /* detail of an XML error */ + VIR_ERR_XML_DETAIL, /* detail of an XML error */ + VIR_ERR_INVALID_NETWORK, /* invalid network object */ + VIR_ERR_NETWORK_EXIST, /* the network already exist */ } virErrorNumber; /** diff --git a/src/driver.h b/src/driver.h index 838f70eb0c..3609041106 100644 --- a/src/driver.h +++ b/src/driver.h @@ -188,6 +188,65 @@ struct _virDriver { virDrvDomainDetachDevice domainDetachDevice; }; +typedef int + (*virDrvNumOfNetworks) (virConnectPtr conn); +typedef int + (*virDrvListNetworks) (virConnectPtr conn, + const char **names, + int maxnames); +typedef int + (*virDrvNumOfDefinedNetworks) (virConnectPtr conn); +typedef int + (*virDrvListDefinedNetworks) (virConnectPtr conn, + const char **names, + int maxnames); +typedef virNetworkPtr + (*virDrvNetworkLookupByUUID) (virConnectPtr conn, + const unsigned char *uuid); +typedef virNetworkPtr + (*virDrvNetworkLookupByName) (virConnectPtr conn, + const char *name); +typedef virNetworkPtr + (*virDrvNetworkCreateXML) (virConnectPtr conn, + const char *xmlDesc); +typedef virNetworkPtr + (*virDrvNetworkDefineXML) (virConnectPtr conn, const char *xml); +typedef int + (*virDrvNetworkUndefine) (virNetworkPtr network); +typedef int + (*virDrvNetworkCreate) (virNetworkPtr network); +typedef int + (*virDrvNetworkDestroy) (virNetworkPtr network); +typedef char * + (*virDrvNetworkDumpXML) (virNetworkPtr network, + int flags); + +typedef struct _virNetworkDriver virNetworkDriver; +typedef virNetworkDriver *virNetworkDriverPtr; + +/** + * _virNetworkDriver: + * + * Structure associated to a network virtualization driver, defining the various + * entry points for it. + */ +struct _virNetworkDriver { + virDrvOpen open; + virDrvClose close; + virDrvNumOfNetworks numOfNetworks; + virDrvListNetworks listNetworks; + virDrvNumOfDefinedNetworks numOfDefinedNetworks; + virDrvListDefinedNetworks listDefinedNetworks; + virDrvNetworkLookupByUUID networkLookupByUUID; + virDrvNetworkLookupByName networkLookupByName; + virDrvNetworkCreateXML networkCreateXML; + virDrvNetworkDefineXML networkDefineXML; + virDrvNetworkUndefine networkUndefine; + virDrvNetworkCreate networkCreate; + virDrvNetworkDestroy networkDestroy; + virDrvNetworkDumpXML networkDumpXML; +}; + /* * Registration @@ -195,6 +254,7 @@ struct _virDriver { * lookup based on the URI given in a virConnectOpen(ReadOnly) */ int virRegisterDriver(virDriverPtr); +int virRegisterNetworkDriver(virNetworkDriverPtr); #ifdef __cplusplus } diff --git a/src/hash.c b/src/hash.c index 6c39918c5d..8d7dd73063 100644 --- a/src/hash.c +++ b/src/hash.c @@ -636,6 +636,20 @@ virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED) return (virDomainFree(domain)); } +/** + * virNetworkFreeName: + * @network: a network object + * + * Destroy the network object, this is just used by the network hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static int +virNetworkFreeName(virNetworkPtr network, const char *name ATTRIBUTE_UNUSED) +{ + return (virNetworkFree(network)); +} + /** * virGetConnect: * @@ -655,11 +669,16 @@ virGetConnect(void) { memset(ret, 0, sizeof(virConnect)); ret->magic = VIR_CONNECT_MAGIC; ret->nb_drivers = 0; + ret->handle = -1; + ret->qemud_fd = -1; ret->domains = virHashCreate(20); if (ret->domains == NULL) goto failed; - ret->domains_mux = xmlNewMutex(); - if (ret->domains_mux == NULL) + ret->networks = virHashCreate(20); + if (ret->networks == NULL) + goto failed; + ret->hashes_mux = xmlNewMutex(); + if (ret->hashes_mux == NULL) goto failed; ret->uses = 1; @@ -669,8 +688,10 @@ failed: if (ret != NULL) { if (ret->domains != NULL) virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName); - if (ret->domains_mux != NULL) - xmlFreeMutex(ret->domains_mux); + if (ret->networks != NULL) + virHashFree(ret->networks, (virHashDeallocator) virNetworkFreeName); + if (ret->hashes_mux != NULL) + xmlFreeMutex(ret->hashes_mux); free(ret); } return(NULL); @@ -689,22 +710,24 @@ int virFreeConnect(virConnectPtr conn) { int ret; - if ((!VIR_IS_CONNECT(conn)) || (conn->domains_mux == NULL)) { + if ((!VIR_IS_CONNECT(conn)) || (conn->hashes_mux == NULL)) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); } - xmlMutexLock(conn->domains_mux); + xmlMutexLock(conn->hashes_mux); conn->uses--; ret = conn->uses; if (ret > 0) { - xmlMutexUnlock(conn->domains_mux); + xmlMutexUnlock(conn->hashes_mux); return(ret); } if (conn->domains != NULL) virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); - if (conn->domains_mux != NULL) - xmlFreeMutex(conn->domains_mux); + if (conn->networks != NULL) + virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); + if (conn->hashes_mux != NULL) + xmlFreeMutex(conn->hashes_mux); free(conn); return(0); } @@ -727,11 +750,11 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virDomainPtr ret = NULL; if ((!VIR_IS_CONNECT(conn)) || ((name == NULL) && (uuid == NULL)) || - (conn->domains_mux == NULL)) { + (conn->hashes_mux == NULL)) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); } - xmlMutexLock(conn->domains_mux); + xmlMutexLock(conn->hashes_mux); /* TODO search by UUID first as they are better differenciators */ @@ -769,11 +792,11 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { conn->uses++; done: ret->uses++; - xmlMutexUnlock(conn->domains_mux); + xmlMutexUnlock(conn->hashes_mux); return(ret); error: - xmlMutexUnlock(conn->domains_mux); + xmlMutexUnlock(conn->hashes_mux); if (ret != NULL) { if (ret->name != NULL) free(ret->name ); @@ -797,11 +820,11 @@ virFreeDomain(virConnectPtr conn, virDomainPtr domain) { int ret = 0; if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_DOMAIN(domain)) || - (domain->conn != conn) || (conn->domains_mux == NULL)) { + (domain->conn != conn) || (conn->hashes_mux == NULL)) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); } - xmlMutexLock(conn->domains_mux); + xmlMutexLock(conn->hashes_mux); /* * decrement the count for the domain @@ -837,13 +860,13 @@ virFreeDomain(virConnectPtr conn, virDomainPtr domain) { if (conn->domains != NULL) virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); - if (conn->domains_mux != NULL) - xmlFreeMutex(conn->domains_mux); + if (conn->hashes_mux != NULL) + xmlFreeMutex(conn->hashes_mux); free(conn); return(0); done: - xmlMutexUnlock(conn->domains_mux); + xmlMutexUnlock(conn->hashes_mux); return(ret); } @@ -868,7 +891,7 @@ virGetDomainByID(virConnectPtr conn, int id) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); } - xmlMutexLock(conn->domains_mux); + xmlMutexLock(conn->hashes_mux); table = conn->domains; if ((table == NULL) || (table->nbElems == 0)) @@ -888,9 +911,142 @@ virGetDomainByID(virConnectPtr conn, int id) { } } done: - xmlMutexUnlock(conn->domains_mux); + xmlMutexUnlock(conn->hashes_mux); return(ret); } + +/** + * virGetNetwork: + * @conn: the hypervisor connection + * @name: pointer to the network name or NULL + * @uuid: pointer to the uuid or NULL + * + * Lookup if the network is already registered for that connection, + * if yes return a new pointer to it, if no allocate a new structure, + * and register it in the table. In any case a corresponding call to + * virFreeNetwork() is needed to not leak data. + * + * Returns a pointer to the network, or NULL in case of failure + */ +virNetworkPtr +virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { + virNetworkPtr ret = NULL; + + if ((!VIR_IS_CONNECT(conn)) || ((name == NULL) && (uuid == NULL)) || + (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + xmlMutexLock(conn->hashes_mux); + + /* TODO search by UUID first as they are better differenciators */ + + ret = (virNetworkPtr) virHashLookup(conn->networks, name); + if (ret != NULL) { + /* TODO check the UUID */ + goto done; + } + + /* + * not found, allocate a new one + */ + ret = (virNetworkPtr) malloc(sizeof(virNetwork)); + if (ret == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating network")); + goto error; + } + memset(ret, 0, sizeof(virNetwork)); + ret->name = strdup(name); + if (ret->name == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating network")); + goto error; + } + ret->magic = VIR_NETWORK_MAGIC; + ret->conn = conn; + if (uuid != NULL) + memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); + + if (virHashAddEntry(conn->networks, name, ret) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to add network to connection hash table")); + goto error; + } + conn->uses++; +done: + ret->uses++; + xmlMutexUnlock(conn->hashes_mux); + return(ret); + +error: + xmlMutexUnlock(conn->hashes_mux); + if (ret != NULL) { + if (ret->name != NULL) + free(ret->name ); + free(ret); + } + return(NULL); +} + +/** + * virFreeNetwork: + * @conn: the hypervisor connection + * @network: the network to release + * + * Release the given network, if the reference count drops to zero, then + * the network is really freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virFreeNetwork(virConnectPtr conn, virNetworkPtr network) { + int ret = 0; + + if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_NETWORK(network)) || + (network->conn != conn) || (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + xmlMutexLock(conn->hashes_mux); + + /* + * decrement the count for the network + */ + network->uses--; + ret = network->uses; + if (ret > 0) + goto done; + + /* TODO search by UUID first as they are better differenciators */ + + if (virHashRemoveEntry(conn->networks, network->name, NULL) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("network missing from connection hash table")); + goto done; + } + network->magic = -1; + if (network->name) + free(network->name); + free(network); + + /* + * decrement the count for the connection + */ + conn->uses--; + if (conn->uses > 0) + goto done; + + if (conn->networks != NULL) + virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); + if (conn->hashes_mux != NULL) + xmlFreeMutex(conn->hashes_mux); + free(conn); + return(0); + +done: + xmlMutexUnlock(conn->hashes_mux); + return(ret); +} + /* * Local variables: * indent-tabs-mode: nil diff --git a/src/internal.h b/src/internal.h index a8938cd02f..d30a0a0d3b 100644 --- a/src/internal.h +++ b/src/internal.h @@ -84,6 +84,16 @@ extern "C" { #define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) #define VIR_IS_CONNECTED_DOMAIN(obj) (VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn)) +/** + * VIR_NETWORK_MAGIC: + * + * magic value used to protect the API when pointers to network structures + * are passed down by the uers. + */ +#define VIR_NETWORK_MAGIC 0xDEAD1234 +#define VIR_IS_NETWORK(obj) ((obj) && (obj)->magic==VIR_NETWORK_MAGIC) +#define VIR_IS_CONNECTED_NETWORK(obj) (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) + #define MAX_DRIVERS 10 /* @@ -104,6 +114,10 @@ struct _virConnect { virDriverPtr drivers[MAX_DRIVERS]; int nb_drivers; + /* the list of available network drivers */ + virNetworkDriverPtr networkDrivers[MAX_DRIVERS]; + int nb_network_drivers; + /* extra data needed by drivers */ int handle; /* internal handle used for hypercall */ struct xs_handle *xshandle;/* handle to talk to the xenstore */ @@ -117,14 +131,17 @@ struct _virConnect { struct sockaddr_un addr_un; /* the unix address */ struct sockaddr_in addr_in; /* the inet address */ + int qemud_fd; /* connection to qemud */ + /* error stuff */ virError err; /* the last error */ virErrorFunc handler; /* associated handlet */ void *userData; /* the user data */ /* misc */ - xmlMutexPtr domains_mux;/* a mutex to protect the domain hash table */ + xmlMutexPtr hashes_mux;/* a mutex to protect the domain and networks hash tables */ virHashTablePtr domains;/* hash table for known domains */ + virHashTablePtr networks;/* hash table for known domains */ int flags; /* a set of connection flags */ }; @@ -156,6 +173,19 @@ struct _virDomain { char *xml; /* the XML description for defined domains */ }; +/** +* _virNetwork: +* +* Internal structure associated to a domain +*/ +struct _virNetwork { + unsigned int magic; /* specific value to check */ + int uses; /* reference count */ + virConnectPtr conn; /* pointer back to the connection */ + char *name; /* the network external name */ + unsigned char uuid[VIR_UUID_BUFLEN]; /* the network unique identifier */ +}; + /* * Internal routines */ @@ -194,6 +224,11 @@ int virFreeDomain (virConnectPtr conn, virDomainPtr domain); virDomainPtr virGetDomainByID(virConnectPtr conn, int id); +virNetworkPtr virGetNetwork (virConnectPtr conn, + const char *name, + const unsigned char *uuid); +int virFreeNetwork (virConnectPtr conn, + virNetworkPtr domain); #ifdef __cplusplus } diff --git a/src/libvirt.c b/src/libvirt.c index b0ecafb50c..c93058c6f8 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -42,6 +42,7 @@ */ static virDriverPtr virDriverTab[MAX_DRIVERS]; +static virNetworkDriverPtr virNetworkDriverTab[MAX_DRIVERS]; static int initialized = 0; /** @@ -68,8 +69,10 @@ virInitialize(void) /* * should not be needed but... */ - for (i = 0;i < MAX_DRIVERS;i++) + for (i = 0;i < MAX_DRIVERS;i++) { virDriverTab[i] = NULL; + virNetworkDriverTab[i] = NULL; + } /* * Note that the order is important the first ones have a higher priority @@ -135,16 +138,36 @@ virLibDomainError(virDomainPtr domain, virErrorNumber error, } /** - * virRegisterDriver: - * @driver: pointer to a driver block - * - * Register a virtualization driver + * virLibNetworkError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string * - * Returns the driver priority or -1 in case of error. + * Handle an error at the connection level */ -int -virRegisterDriver(virDriverPtr driver) +static void +virLibNetworkError(virNetworkPtr network, virErrorNumber error, + const char *info) +{ + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_NETWORK) { + conn = network->conn; + } + /* XXX: should be able to pass network pointer here */ + __virRaiseError(conn, NULL, VIR_FROM_NET, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +static int +_virRegisterDriver(void *driver, int isNetwork) { + void **drivers; int i; if (!initialized) @@ -155,13 +178,14 @@ virRegisterDriver(virDriverPtr driver) virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); } + drivers = isNetwork ? (void **) virNetworkDriverTab : (void **) virDriverTab; for (i = 0;i < MAX_DRIVERS;i++) { - if (virDriverTab[i] == driver) + if (drivers[i] == driver) return(i); } for (i = 0;i < MAX_DRIVERS;i++) { - if (virDriverTab[i] == NULL) { - virDriverTab[i] = driver; + if (drivers[i] == NULL) { + drivers[i] = driver; return(i); } } @@ -169,6 +193,34 @@ virRegisterDriver(virDriverPtr driver) return(-1); } +/** + * virRegisterNetworkDriver: + * @driver: pointer to a network driver block + * + * Register a network virtualization driver + * + * Returns the driver priority or -1 in case of error. + */ +int +virRegisterNetworkDriver(virNetworkDriverPtr driver) +{ + return _virRegisterDriver(driver, 1); +} + +/** + * virRegisterDriver: + * @driver: pointer to a driver block + * + * Register a virtualization driver + * + * Returns the driver priority or -1 in case of error. + */ +int +virRegisterDriver(virDriverPtr driver) +{ + return _virRegisterDriver(driver, 0); +} + /** * virGetVersion: * @libVer: return value for the library version (OUT) @@ -265,7 +317,14 @@ virConnectOpen(const char *name) } } - if (ret->nb_drivers == 0) { + for (i = 0;i < MAX_DRIVERS;i++) { + if ((virNetworkDriverTab[i] != NULL) && (virNetworkDriverTab[i]->open != NULL) && + (res = virNetworkDriverTab[i]->open(ret, name, VIR_DRV_OPEN_QUIET)) == 0) { + ret->networkDrivers[ret->nb_network_drivers++] = virNetworkDriverTab[i]; + } + } + + if (ret->nb_drivers == 0 || ret->nb_network_drivers == 0) { /* we failed to find an adequate driver */ virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name); goto failed; @@ -279,6 +338,10 @@ failed: if ((ret->drivers[i] != NULL) && (ret->drivers[i]->close != NULL)) ret->drivers[i]->close(ret); } + for (i = 0;i < ret->nb_network_drivers;i++) { + if ((ret->networkDrivers[i] != NULL) && (ret->networkDrivers[i]->close != NULL)) + ret->networkDrivers[i]->close(ret); + } virFreeConnect(ret); } return (NULL); @@ -321,6 +384,10 @@ virConnectOpenReadOnly(const char *name) ret->drivers[ret->nb_drivers++] = virDriverTab[i]; } + if ((virNetworkDriverTab[i] != NULL) && (virNetworkDriverTab[i]->open != NULL) && + (res = virNetworkDriverTab[i]->open(ret, name, VIR_DRV_OPEN_QUIET)) == 0) { + ret->networkDrivers[ret->nb_network_drivers++] = virNetworkDriverTab[i]; + } } if (ret->nb_drivers == 0) { if (name == NULL) @@ -341,6 +408,10 @@ failed: if ((ret->drivers[i] != NULL) && (ret->drivers[i]->close != NULL)) ret->drivers[i]->close(ret); } + for (i = 0;i < ret->nb_network_drivers;i++) { + if ((ret->networkDrivers[i] != NULL) && (ret->networkDrivers[i]->close != NULL)) + ret->networkDrivers[i]->close(ret); + } virFreeConnect(ret); } return (NULL); @@ -368,6 +439,10 @@ virConnectClose(virConnectPtr conn) if ((conn->drivers[i] != NULL) && (conn->drivers[i]->close != NULL)) conn->drivers[i]->close(conn); } + for (i = 0;i < conn->nb_network_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && (conn->networkDrivers[i]->close != NULL)) + conn->networkDrivers[i]->close(conn); + } if (virFreeConnect(conn) < 0) return (-1); return (0); @@ -2053,3 +2128,607 @@ virDomainDetachDevice(virDomainPtr domain, char *xml) virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__); return (-1); } + +/** + * virConnectNumOfNetworks: + * @conn: pointer to the hypervisor connection + * + * Provides the number of active networks. + * + * Returns the number of network found or -1 in case of error + */ +int +virConnectNumOfNetworks(virConnectPtr conn) +{ + int ret = -1; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_network_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->numOfNetworks != NULL)) { + ret = conn->networkDrivers[i]->numOfNetworks(conn); + if (ret >= 0) + return(ret); + } + } + + return(-1); +} + +/** + * virConnectListNetworks: + * @conn: pointer to the hypervisor connection + * @names: array to collect the list of names of active networks + * @maxnames: size of @names + * + * Collect the list of active networks, and store their names in @names + * + * Returns the number of networks found or -1 in case of error + */ +int +virConnectListNetworks(virConnectPtr conn, const char **names, int maxnames) +{ + int ret = -1; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames <= 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->listNetworks != NULL)) { + ret = conn->networkDrivers[i]->listNetworks(conn, names, maxnames); + if (ret >= 0) + return(ret); + } + } + + return (-1); +} + +/** + * virConnectNumOfDefinedNetworks: + * @conn: pointer to the hypervisor connection + * + * Provides the number of inactive networks. + * + * Returns the number of networks found or -1 in case of error + */ +int +virConnectNumOfDefinedNetworks(virConnectPtr conn) +{ + int ret = -1; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->numOfDefinedNetworks != NULL)) { + ret = conn->networkDrivers[i]->numOfDefinedNetworks(conn); + if (ret >= 0) + return(ret); + } + } + + return(-1); +} + +/** + * virConnectListDefinedNetworks: + * @conn: pointer to the hypervisor connection + * @names: pointer to an array to store the names + * @maxnames: size of the array + * + * list the inactive networks, stores the pointers to the names in @names + * + * Returns the number of names provided in the array or -1 in case of error + */ +int +virConnectListDefinedNetworks(virConnectPtr conn, const char **names, + int maxnames) { + int ret = -1; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames <= 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->listDefinedNetworks != NULL)) { + ret = conn->networkDrivers[i]->listDefinedNetworks(conn, names, maxnames); + if (ret >= 0) + return(ret); + } + } + + return (-1); +} + +/** + * virNetworkLookupByName: + * @conn: pointer to the hypervisor connection + * @name: name for the network + * + * Try to lookup a network on the given hypervisor based on its name. + * + * Returns a new network object or NULL in case of failure + */ +virNetworkPtr +virNetworkLookupByName(virConnectPtr conn, const char *name) +{ + virNetworkPtr ret = NULL; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (name == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkLookupByName != NULL)) { + ret = conn->networkDrivers[i]->networkLookupByName(conn, name); + if (ret) + return(ret); + } + } + return (NULL); +} + +/** + * virNetworkLookupByUUID: + * @conn: pointer to the hypervisor connection + * @uuid: the raw UUID for the network + * + * Try to lookup a network on the given hypervisor based on its UUID. + * + * Returns a new network object or NULL in case of failure + */ +virNetworkPtr +virNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid) +{ + virNetworkPtr ret; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuid == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkLookupByUUID != NULL)) { + ret = conn->networkDrivers[i]->networkLookupByUUID(conn, uuid); + if (ret) + return(ret); + } + } + + return (NULL); +} + +/** + * virNetworkLookupByUUIDString: + * @conn: pointer to the hypervisor connection + * @uuidstr: the string UUID for the network + * + * Try to lookup a network on the given hypervisor based on its UUID. + * + * Returns a new network object or NULL in case of failure + */ +virNetworkPtr +virNetworkLookupByUUIDString(virConnectPtr conn, const char *uuidstr) +{ + int raw[VIR_UUID_BUFLEN], i; + unsigned char uuid[VIR_UUID_BUFLEN]; + int ret; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuidstr == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + /* XXX: sexpr_uuid() also supports 'xxxx-xxxx-xxxx-xxxx' format. + * We needn't it here. Right? + */ + ret = sscanf(uuidstr, + "%02x%02x%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + raw + 0, raw + 1, raw + 2, raw + 3, + raw + 4, raw + 5, raw + 6, raw + 7, + raw + 8, raw + 9, raw + 10, raw + 11, + raw + 12, raw + 13, raw + 14, raw + 15); + + if (ret!=VIR_UUID_BUFLEN) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + for (i = 0; i < VIR_UUID_BUFLEN; i++) + uuid[i] = raw[i] & 0xFF; + + return virNetworkLookupByUUID(conn, &uuid[0]); +} + +/** + * virNetworkCreateXML: + * @conn: pointer to the hypervisor connection + * @xmlDesc: an XML description of the network + * + * Create and start a new virtual network, based on an XML description + * similar to the one returned by virNetworkGetXMLDesc() + * + * Returns a new network object or NULL in case of failure + */ +virNetworkPtr +virNetworkCreateXML(virConnectPtr conn, const char *xmlDesc) +{ + virNetworkPtr ret; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (xmlDesc == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkCreateXML != NULL)) { + ret = conn->networkDrivers[i]->networkCreateXML(conn, xmlDesc); + if (ret != NULL) + return(ret); + } + } + return(NULL); +} + +/** + * virNetworkDefineXML: + * @conn: pointer to the hypervisor connection + * @xml: the XML description for the network, preferably in UTF-8 + * + * Define a network, but does not create it + * + * Returns NULL in case of error, a pointer to the network otherwise + */ +virNetworkPtr +virNetworkDefineXML(virConnectPtr conn, const char *xml) { + virNetworkPtr ret = NULL; + int i; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + if (xml == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkDefineXML != NULL)) { + ret = conn->networkDrivers[i]->networkDefineXML(conn, xml); + if (ret) + return(ret); + } + } + + return(ret); +} + +/** + * virNetworkUndefine: + * @network: pointer to a defined network + * + * Undefine a network but does not stop it if it is running + * + * Returns 0 in case of success, -1 in case of error + */ +int +virNetworkUndefine(virNetworkPtr network) { + int ret, i; + virConnectPtr conn; + + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + conn = network->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + /* Go though the driver registered entry points */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkUndefine != NULL)) { + ret = conn->networkDrivers[i]->networkUndefine(network); + if (ret >= 0) + return(ret); + } + } + + return(-1); +} + +/** + * virNetworkCreate: + * @network: pointer to a defined network + * + * Create and start a defined network. If the call succeed the network + * moves from the defined to the running networks pools. + * + * Returns 0 in case of success, -1 in case of error + */ +int +virNetworkCreate(virNetworkPtr network) { + int i, ret = -1; + virConnectPtr conn; + if (network == NULL) { + TODO + return (-1); + } + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + conn = network->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkCreate != NULL)) { + ret = conn->networkDrivers[i]->networkCreate(network); + if (ret == 0) + return(ret); + } + } + return(ret); +} + +/** + * virNetworkDestroy: + * @network: a network object + * + * Destroy the network object. The running instance is shutdown if not down + * already and all resources used by it are given back to the hypervisor. + * The data structure is freed and should not be used thereafter if the + * call does not return an error. + * This function may requires priviledged access + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virNetworkDestroy(virNetworkPtr network) +{ + int i; + virConnectPtr conn; + + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + + conn = network->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + /* + * Go though the driver registered entry points + */ + for (i = 0;i < conn->nb_drivers;i++) { + if ((conn->networkDrivers[i] != NULL) && + (conn->networkDrivers[i]->networkDestroy != NULL)) { + if (conn->networkDrivers[i]->networkDestroy(network) == 0) + return (0); + } + } + + virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__); + return (-1); +} + +/** + * virNetworkFree: + * @network: a network object + * + * Free the network object. The running instance is kept alive. + * The data structure is freed and should not be used thereafter. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virNetworkFree(virNetworkPtr network) +{ + if (!VIR_IS_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + if (virFreeNetwork(network->conn, network) < 0) + return (-1); + return(0); +} + +/** + * virNetworkGetName: + * @network: a network object + * + * Get the public name for that network + * + * Returns a pointer to the name or NULL, the string need not be deallocated + * its lifetime will be the same as the network object. + */ +const char * +virNetworkGetName(virNetworkPtr network) +{ + if (!VIR_IS_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (NULL); + } + return (network->name); +} + +/** + * virNetworkGetUUID: + * @network: a network object + * @uuid: pointer to a VIR_UUID_BUFLEN bytes array + * + * Get the UUID for a network + * + * Returns -1 in case of error, 0 in case of success + */ +int +virNetworkGetUUID(virNetworkPtr network, unsigned char *uuid) +{ + if (!VIR_IS_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + if (uuid == NULL) { + virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memcpy(uuid, &network->uuid[0], VIR_UUID_BUFLEN); + + return (0); +} + +/** + * virNetworkGetUUIDString: + * @network: a network object + * @buf: pointer to a VIR_UUID_STRING_BUFLEN bytes array + * + * Get the UUID for a network as string. For more information about + * UUID see RFC4122. + * + * Returns -1 in case of error, 0 in case of success + */ +int +virNetworkGetUUIDString(virNetworkPtr network, char *buf) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + + if (!VIR_IS_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + if (buf == NULL) { + virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (virNetworkGetUUID(network, &uuid[0])) + return (-1); + + snprintf(buf, VIR_UUID_STRING_BUFLEN, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + return (0); +} + +/** + * virNetworkGetXMLDesc: + * @network: a network object + * @flags: and OR'ed set of extraction flags, not used yet + * + * Provide an XML description of the network. The description may be reused + * later to relaunch the network with virNetworkCreateXML(). + * + * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error. + * the caller must free() the returned value. + */ +char * +virNetworkGetXMLDesc(virNetworkPtr network, int flags) +{ + int i; + char *ret = NULL; + if (!VIR_IS_NETWORK(network)) { + virLibNetworkError(network, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (NULL); + } + if (flags != 0) { + virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + for (i = 0;i < network->conn->nb_network_drivers;i++) { + if ((network->conn->networkDrivers[i] != NULL) && + (network->conn->networkDrivers[i]->networkDumpXML != NULL)) { + ret = network->conn->networkDrivers[i]->networkDumpXML(network, flags); + if (ret) + break; + } + } + if (!ret) { + virLibConnError(network->conn, VIR_ERR_CALL_FAILED, __FUNCTION__); + return (NULL); + } + return(ret); +} diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index 2d009da44c..d19ee7552b 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -57,5 +57,24 @@ virDomainAttachDevice; virDomainDetachDevice; + + virConnectNumOfNetworks; + virConnectListNetworks; + virConnectNumOfDefinedNetworks; + virConnectListDefinedNetworks; + virNetworkLookupByName; + virNetworkLookupByUUID; + virNetworkLookupByUUIDString; + virNetworkCreateXML; + virNetworkDefineXML; + virNetworkUndefine; + virNetworkCreate; + virNetworkDestroy; + virNetworkFree; + virNetworkGetName; + virNetworkGetUUID; + virNetworkGetUUIDString; + virNetworkGetXMLDesc; + local: *; }; diff --git a/src/virterror.c b/src/virterror.c index b180c4e72a..23446c1f45 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -271,6 +271,9 @@ virDefaultErrorFunc(virErrorPtr err) case VIR_FROM_QEMU: dom = "QEMU "; break; + case VIR_FROM_NET: + dom = "Network "; + break; } if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) { domain = err->dom->name; @@ -585,6 +588,18 @@ __virErrorMsg(virErrorNumber error, const char *info) else errmsg = "%s"; break; + case VIR_ERR_INVALID_NETWORK: + if (info == NULL) + errmsg = _("invalid network pointer in"); + else + errmsg = _("invalid network pointer in %s"); + break; + case VIR_ERR_NETWORK_EXIST: + if (info == NULL) + errmsg = _("this network exists already"); + else + errmsg = _("network %s exists already"); + break; } return (errmsg); } -- GitLab