[libvirt] [PATCH 0/6] virInterface bug fixes, test driver, and netcf backend driver

This series of patches first corrects a couple of bugs/deficiencies in existing virInterface code, then adds test and netcf-based backend interface drivers.

This code is used if a driver's virInterfaceLookupByMACString() function finds more than one interface with the desired MAC Address. --- include/libvirt/virterror.h | 1 + src/virterror.c | 6 ++++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 1092896..f587fbf 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -163,6 +163,7 @@ typedef enum { VIR_WAR_NO_INTERFACE, /* failed to start interface driver */ VIR_ERR_NO_INTERFACE, /* interface driver not running */ VIR_ERR_INVALID_INTERFACE, /* invalid interface object */ + VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ } virErrorNumber; /** diff --git a/src/virterror.c b/src/virterror.c index d284fb8..7d0f2e9 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -1056,6 +1056,12 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("invalid interface pointer in %s"); break; + case VIR_ERR_MULTIPLE_INTERFACES: + if (info == NULL) + errmsg = _("multiple matching interfaces found"); + else + errmsg = _("multiple matching interfaces found: %s"); + break; } return (errmsg); } -- 1.6.0.6

On Mon, Jul 20, 2009 at 01:42:02PM -0400, Laine Stump wrote:
This code is used if a driver's virInterfaceLookupByMACString() function finds more than one interface with the desired MAC Address. --- include/libvirt/virterror.h | 1 + src/virterror.c | 6 ++++++ 2 files changed, 7 insertions(+), 0 deletions(-)
ACK
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 1092896..f587fbf 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -163,6 +163,7 @@ typedef enum { VIR_WAR_NO_INTERFACE, /* failed to start interface driver */ VIR_ERR_NO_INTERFACE, /* interface driver not running */ VIR_ERR_INVALID_INTERFACE, /* invalid interface object */ + VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ } virErrorNumber;
/** diff --git a/src/virterror.c b/src/virterror.c index d284fb8..7d0f2e9 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -1056,6 +1056,12 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("invalid interface pointer in %s"); break; + case VIR_ERR_MULTIPLE_INTERFACES: + if (info == NULL) + errmsg = _("multiple matching interfaces found"); + else + errmsg = _("multiple matching interfaces found: %s"); + break; } return (errmsg); } -- 1.6.0.6
-- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- |: 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 :|

On Mon, Jul 20, 2009 at 01:42:02PM -0400, Laine Stump wrote:
This code is used if a driver's virInterfaceLookupByMACString() function finds more than one interface with the desired MAC Address.
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- src/libvirt.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index f4a7fa7..a2aa781 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -1026,9 +1026,6 @@ do_open (const char *name, } } -#if 0 - /* TODO: reactivate once we have an interface driver */ - for (i = 0; i < virInterfaceDriverTabCount; i++) { res = virInterfaceDriverTab[i]->open (ret, auth, flags); DEBUG("interface driver %d %s returned %s", @@ -1047,7 +1044,6 @@ do_open (const char *name, break; } } -#endif /* Secondary driver for storage. Optional */ for (i = 0; i < virStorageDriverTabCount; i++) { -- 1.6.0.6

On Mon, Jul 20, 2009 at 01:42:03PM -0400, Laine Stump wrote:
--- src/libvirt.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-)
ACk, though technically it should be last in the series :-)
diff --git a/src/libvirt.c b/src/libvirt.c index f4a7fa7..a2aa781 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -1026,9 +1026,6 @@ do_open (const char *name, } }
-#if 0 - /* TODO: reactivate once we have an interface driver */ - for (i = 0; i < virInterfaceDriverTabCount; i++) { res = virInterfaceDriverTab[i]->open (ret, auth, flags); DEBUG("interface driver %d %s returned %s", @@ -1047,7 +1044,6 @@ do_open (const char *name, break; } } -#endif
/* Secondary driver for storage. Optional */ for (i = 0; i < virStorageDriverTabCount; i++) { -- 1.6.0.6
-- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- |: 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 :|

On Mon, Jul 20, 2009 at 07:42:20PM +0100, Daniel P. Berrange wrote:
On Mon, Jul 20, 2009 at 01:42:03PM -0400, Laine Stump wrote:
--- src/libvirt.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-)
ACk, though technically it should be last in the series :-)
hehe :-) ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

MAC address of a particular interface may change over time, and the reduced virInterface object (which contains just name and mac) needs to reflect these changes. --- src/datatypes.c | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index a8bffd2..a0d027c 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -516,9 +516,10 @@ virUnrefNetwork(virNetworkPtr network) { * @mac: pointer to the mac * * Lookup if the interface 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 - * virUnrefInterface() is needed to not leak data. + * if yes return a new pointer to it (possibly updating the MAC + * address), if no allocate a new structure, and register it in the + * table. In any case a corresponding call to virUnrefInterface() is + * needed to not leak data. * * Returns a pointer to the interface, or NULL in case of failure */ @@ -532,11 +533,19 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { } virMutexLock(&conn->lock); - /* TODO search by MAC first as they are better differentiators */ - ret = (virInterfacePtr) virHashLookup(conn->interfaces, name); - /* TODO check the MAC */ - if (ret == NULL) { + + if (ret != NULL) { + /* update MAC address if necessary */ + if ((ret->mac == NULL) || STRNEQ(ret->mac, mac)) { + VIR_FREE(ret->mac); + ret->mac = strdup(mac); + if (ret->mac == NULL) { + virReportOOMError(conn); + goto error; + } + } + } else { if (VIR_ALLOC(ret) < 0) { virReportOOMError(conn); goto error; @@ -593,7 +602,6 @@ virReleaseInterface(virInterfacePtr iface) { virConnectPtr conn = iface->conn; DEBUG("release interface %p %s", iface, iface->name); - /* TODO search by MAC first as they are better differenciators */ if (virHashRemoveEntry(conn->interfaces, iface->name, NULL) < 0) virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, _("interface missing from connection hash table")); -- 1.6.0.6

On Mon, Jul 20, 2009 at 01:42:04PM -0400, Laine Stump wrote:
MAC address of a particular interface may change over time, and the reduced virInterface object (which contains just name and mac) needs to reflect these changes. --- src/datatypes.c | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/src/datatypes.c b/src/datatypes.c index a8bffd2..a0d027c 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -516,9 +516,10 @@ virUnrefNetwork(virNetworkPtr network) { * @mac: pointer to the mac * * Lookup if the interface 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 - * virUnrefInterface() is needed to not leak data. + * if yes return a new pointer to it (possibly updating the MAC + * address), if no allocate a new structure, and register it in the + * table. In any case a corresponding call to virUnrefInterface() is + * needed to not leak data. * * Returns a pointer to the interface, or NULL in case of failure */ @@ -532,11 +533,19 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { } virMutexLock(&conn->lock);
- /* TODO search by MAC first as they are better differentiators */ - ret = (virInterfacePtr) virHashLookup(conn->interfaces, name); - /* TODO check the MAC */ - if (ret == NULL) { + + if (ret != NULL) { + /* update MAC address if necessary */ + if ((ret->mac == NULL) || STRNEQ(ret->mac, mac)) { + VIR_FREE(ret->mac); + ret->mac = strdup(mac); + if (ret->mac == NULL) { + virReportOOMError(conn); + goto error; + } + } + } else {
There's a small edge case there. the 'ret' object you have there is a cached one, whose handled is already in use by other callers on libvirt public API. So although you are reported an OOM to this caller, other users of this cached object have a dangerous instance witha NULL 'mac' field. Easy solution, don't VIR_FREE the existing mac until you have successfully strdup'd the new one Regards, Daniel -- |: 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 :|

On Mon, Jul 20, 2009 at 07:44:43PM +0100, Daniel P. Berrange wrote:
On Mon, Jul 20, 2009 at 01:42:04PM -0400, Laine Stump wrote:
MAC address of a particular interface may change over time, and the reduced virInterface object (which contains just name and mac) needs to reflect these changes. --- src/datatypes.c | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/src/datatypes.c b/src/datatypes.c index a8bffd2..a0d027c 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -516,9 +516,10 @@ virUnrefNetwork(virNetworkPtr network) { * @mac: pointer to the mac * * Lookup if the interface 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 - * virUnrefInterface() is needed to not leak data. + * if yes return a new pointer to it (possibly updating the MAC + * address), if no allocate a new structure, and register it in the + * table. In any case a corresponding call to virUnrefInterface() is + * needed to not leak data. * * Returns a pointer to the interface, or NULL in case of failure */ @@ -532,11 +533,19 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { } virMutexLock(&conn->lock);
- /* TODO search by MAC first as they are better differentiators */ - ret = (virInterfacePtr) virHashLookup(conn->interfaces, name); - /* TODO check the MAC */ - if (ret == NULL) { + + if (ret != NULL) { + /* update MAC address if necessary */ + if ((ret->mac == NULL) || STRNEQ(ret->mac, mac)) { + VIR_FREE(ret->mac); + ret->mac = strdup(mac); + if (ret->mac == NULL) { + virReportOOMError(conn); + goto error; + } + } + } else {
There's a small edge case there. the 'ret' object you have there is a cached one, whose handled is already in use by other callers on libvirt public API. So although you are reported an OOM to this caller, other users of this cached object have a dangerous instance witha NULL 'mac' field. Easy solution, don't VIR_FREE the existing mac until you have successfully strdup'd the new one
Good point, actually if the size permits writing the new value over just avoids a new allocation. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 07/20/2009 03:22 PM, Daniel Veillard wrote:
On Mon, Jul 20, 2009 at 07:44:43PM +0100, Daniel P. Berrange wrote:
On Mon, Jul 20, 2009 at 01:42:04PM -0400, Laine Stump wrote:
MAC address of a particular interface may change over time, and the reduced virInterface object (which contains just name and mac) needs to reflect these changes. --- src/datatypes.c | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/src/datatypes.c b/src/datatypes.c index a8bffd2..a0d027c 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -516,9 +516,10 @@ virUnrefNetwork(virNetworkPtr network) { * @mac: pointer to the mac * * Lookup if the interface 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 - * virUnrefInterface() is needed to not leak data. + * if yes return a new pointer to it (possibly updating the MAC + * address), if no allocate a new structure, and register it in the + * table. In any case a corresponding call to virUnrefInterface() is + * needed to not leak data. * * Returns a pointer to the interface, or NULL in case of failure */ @@ -532,11 +533,19 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { } virMutexLock(&conn->lock);
- /* TODO search by MAC first as they are better differentiators */ - ret = (virInterfacePtr) virHashLookup(conn->interfaces, name); - /* TODO check the MAC */ - if (ret == NULL) { + + if (ret != NULL) { + /* update MAC address if necessary */ + if ((ret->mac == NULL) || STRNEQ(ret->mac, mac)) { + VIR_FREE(ret->mac); + ret->mac = strdup(mac); + if (ret->mac == NULL) { + virReportOOMError(conn); + goto error; + } + } + } else {
There's a small edge case there. the 'ret' object you have there is a cached one, whose handled is already in use by other callers on libvirt public API. So although you are reported an OOM to this caller, other users of this cached object have a dangerous instance witha NULL 'mac' field. Easy solution, don't VIR_FREE the existing mac until you have successfully strdup'd the new one
Good point, actually if the size permits writing the new value over just avoids a new allocation.
Now that you make me think about it - beyond that, if another thread has a pointer to this object, they may have already gotten a copy of the mac pointer into a temp variable, and if they then use it after I've freed it (and maybe someone else re-uses the same memory) they will get bad data. So I guess the *real* solution is to always compare the macs, and if they don't match create a new object. This will mean that this hypothetical "other thread" may be working with out-of-date information (it will still have the old mac address, at least for iface-list), but at least it will never stomp on someone else's data.

These functions are useful for an implementation of an interface driver that doesn't use a library that manages its own list of interfaces (as netcf does), for example the test interface driver. --- src/interface_conf.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/interface_conf.h | 15 ++++- 2 files changed, 148 insertions(+), 3 deletions(-) diff --git a/src/interface_conf.c b/src/interface_conf.c index 0b73c97..6a0b35e 100644 --- a/src/interface_conf.c +++ b/src/interface_conf.c @@ -1128,6 +1128,8 @@ cleanup: return NULL; } +/* virInterfaceObj manipulation */ + void virInterfaceObjLock(virInterfaceObjPtr obj) { virMutexLock(&obj->lock); @@ -1137,3 +1139,137 @@ void virInterfaceObjUnlock(virInterfaceObjPtr obj) { virMutexUnlock(&obj->lock); } + +void virInterfaceObjFree(virInterfaceObjPtr iface) +{ + if (!iface) + return; + + virInterfaceDefFree(iface->def); + virMutexDestroy(&iface->lock); + VIR_FREE(iface); +} + +/* virInterfaceObjList manipulation */ + +int virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, + const char *mac, + virInterfaceObjPtr *matches, int maxmatches) +{ + unsigned int i, matchct = 0; + + for (i = 0 ; i < interfaces->count ; i++) { + int lock_for_caller = 0; + virInterfaceObjLock(interfaces->objs[i]); + if (STREQ(interfaces->objs[i]->def->mac, mac)) { + if (matchct < maxmatches) { + matches[matchct] = interfaces->objs[i]; + lock_for_caller = 1; + } + matchct++; + } + if (!lock_for_caller) { + /* it is the caller's responsibility to unlock *all* matches */ + virInterfaceObjUnlock(interfaces->objs[i]); + } + } + + return matchct; +} + +virInterfaceObjPtr virInterfaceFindByName(const virInterfaceObjListPtr + interfaces, + const char *name) +{ + unsigned int i; + + for (i = 0 ; i < interfaces->count ; i++) { + virInterfaceObjLock(interfaces->objs[i]); + if (STREQ(interfaces->objs[i]->def->name, name)) + return interfaces->objs[i]; + virInterfaceObjUnlock(interfaces->objs[i]); + } + + return NULL; +} + +void virInterfaceObjListFree(virInterfaceObjListPtr interfaces) +{ + unsigned int i; + + for (i = 0 ; i < interfaces->count ; i++) + virInterfaceObjFree(interfaces->objs[i]); + + VIR_FREE(interfaces->objs); + interfaces->count = 0; +} + +virInterfaceObjPtr virInterfaceAssignDef(virConnectPtr conn, + virInterfaceObjListPtr interfaces, + const virInterfaceDefPtr def) +{ + virInterfaceObjPtr interface; + + if ((interface = virInterfaceFindByName(interfaces, def->name))) { + if (interface->def) + virInterfaceDefFree(interface->def); + interface->def = def; + + return interface; + } + + if (VIR_ALLOC(interface) < 0) { + virReportOOMError(conn); + return NULL; + } + if (virMutexInit(&interface->lock) < 0) { + virInterfaceReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot initialize mutex")); + VIR_FREE(interface); + return NULL; + } + virInterfaceObjLock(interface); + interface->def = def; + + if (VIR_REALLOC_N(interfaces->objs, interfaces->count + 1) < 0) { + virReportOOMError(conn); + VIR_FREE(interface); + return NULL; + } + + interfaces->objs[interfaces->count] = interface; + interfaces->count++; + + return interface; + +} + +void virInterfaceRemove(virInterfaceObjListPtr interfaces, + const virInterfaceObjPtr interface) +{ + unsigned int i; + + virInterfaceObjUnlock(interface); + for (i = 0 ; i < interfaces->count ; i++) { + virInterfaceObjLock(interfaces->objs[i]); + if (interfaces->objs[i] == interface) { + virInterfaceObjUnlock(interfaces->objs[i]); + virInterfaceObjFree(interfaces->objs[i]); + + if (i < (interfaces->count - 1)) + memmove(interfaces->objs + i, interfaces->objs + i + 1, + sizeof(*(interfaces->objs)) * (interfaces->count - (i + 1))); + + if (VIR_REALLOC_N(interfaces->objs, interfaces->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + interfaces->count--; + + break; + } + virInterfaceObjUnlock(interfaces->objs[i]); + } +} + + + diff --git a/src/interface_conf.h b/src/interface_conf.h index c77a230..aea1208 100644 --- a/src/interface_conf.h +++ b/src/interface_conf.h @@ -160,6 +160,7 @@ typedef virInterfaceObj *virInterfaceObjPtr; struct _virInterfaceObj { virMutex lock; + int active:1; /* 1 if interface is active (up) */ virInterfaceDefPtr def; /* The interface definition */ }; @@ -170,9 +171,17 @@ struct _virInterfaceObjList { virInterfaceObjPtr *objs; }; -virInterfaceObjPtr virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, - const char *mac); -virInterfaceObjPtr virInterfaceFindByName(const virInterfaceObjListPtr interfaces, +static inline int +virInterfaceIsActive(const virInterfaceObjPtr iface) +{ + return iface->active; +} + +int virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, + const char *mac, + virInterfaceObjPtr *matches, int maxmatches); +virInterfaceObjPtr virInterfaceFindByName(const virInterfaceObjListPtr + interfaces, const char *name); -- 1.6.0.6

On Mon, Jul 20, 2009 at 01:42:05PM -0400, Laine Stump wrote:
These functions are useful for an implementation of an interface driver that doesn't use a library that manages its own list of interfaces (as netcf does), for example the test interface driver.
+ +int virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, + const char *mac, + virInterfaceObjPtr *matches, int maxmatches) +{ + unsigned int i, matchct = 0; + + for (i = 0 ; i < interfaces->count ; i++) { + int lock_for_caller = 0; + virInterfaceObjLock(interfaces->objs[i]); + if (STREQ(interfaces->objs[i]->def->mac, mac)) { + if (matchct < maxmatches) { + matches[matchct] = interfaces->objs[i]; + lock_for_caller = 1; + } + matchct++; + } + if (!lock_for_caller) { + /* it is the caller's responsibility to unlock *all* matches */ + virInterfaceObjUnlock(interfaces->objs[i]); + } + }
I think it'd be a little nicer to just use 'continue' there instead of introducing the 'lock_for_caller = 1' assignment. Also minor indentation typo. ACK to this anyway Daniel -- |: 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 :|

--- src/test.c | 382 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 381 insertions(+), 1 deletions(-) diff --git a/src/test.c b/src/test.c index 6f07462..bdb2270 100644 --- a/src/test.c +++ b/src/test.c @@ -41,6 +41,7 @@ #include "capabilities.h" #include "memory.h" #include "network_conf.h" +#include "interface_conf.h" #include "domain_conf.h" #include "domain_event.h" #include "event.h" @@ -72,6 +73,7 @@ struct _testConn { virNodeInfo nodeInfo; virDomainObjList domains; virNetworkObjList networks; + virInterfaceObjList ifaces; virStoragePoolObjList pools; int numCells; testCell cells[MAX_CELLS]; @@ -202,6 +204,17 @@ static const char *defaultNetworkXML = " </ip>" "</network>"; +static const char *defaultInterfaceXML = +"<interface type=\"ethernet\" name=\"eth1\">" +" <start mode=\"onboot\"/>" +" <mac address=\"aa:bb:cc:dd:ee:ff\"/>" +" <mtu size=\"1492\"/>" +" <protocol family=\"ipv4\">" +" <ip address=\"192.168.0.5\" prefix=\"24\"/>" +" <route gateway=\"192.168.0.1\"/>" +" </protocol>" +"</interface>"; + static const char *defaultPoolXML = "<pool type='dir'>" " <name>default-pool</name>" @@ -223,6 +236,8 @@ static int testOpenDefault(virConnectPtr conn) { virDomainObjPtr domobj = NULL; virNetworkDefPtr netdef = NULL; virNetworkObjPtr netobj = NULL; + virInterfaceDefPtr interfacedef = NULL; + virInterfaceObjPtr interfaceobj = NULL; virStoragePoolDefPtr pooldef = NULL; virStoragePoolObjPtr poolobj = NULL; @@ -286,6 +301,15 @@ static int testOpenDefault(virConnectPtr conn) { netobj->persistent = 1; virNetworkObjUnlock(netobj); + if (!(interfacedef = virInterfaceDefParseString(conn, defaultInterfaceXML))) + goto error; + if (!(interfaceobj = virInterfaceAssignDef(conn, &privconn->ifaces, interfacedef))) { + virInterfaceDefFree(interfacedef); + goto error; + } + interfaceobj->active = 1; + virInterfaceObjUnlock(interfaceobj); + if (!(pooldef = virStoragePoolDefParseString(conn, defaultPoolXML))) goto error; @@ -309,6 +333,7 @@ static int testOpenDefault(virConnectPtr conn) { error: virDomainObjListFree(&privconn->domains); virNetworkObjListFree(&privconn->networks); + virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); virCapabilitiesFree(privconn->caps); testDriverUnlock(privconn); @@ -429,10 +454,11 @@ static int testOpenFromFile(virConnectPtr conn, char *str; xmlDocPtr xml = NULL; xmlNodePtr root = NULL; - xmlNodePtr *domains = NULL, *networks = NULL, *pools = NULL; + xmlNodePtr *domains = NULL, *networks = NULL, *ifaces = NULL, *pools = NULL; xmlXPathContextPtr ctxt = NULL; virNodeInfoPtr nodeInfo; virNetworkObjPtr net; + virInterfaceObjPtr iface; virDomainObjPtr dom; testConnPtr privconn; if (VIR_ALLOC(privconn) < 0) { @@ -629,6 +655,39 @@ static int testOpenFromFile(virConnectPtr conn, } VIR_FREE(networks); + /* Parse interface definitions */ + ret = virXPathNodeSet(conn, "/node/interface", ctxt, &ifaces); + if (ret < 0) { + testError(NULL, VIR_ERR_XML_ERROR, "%s", _("node interface list")); + goto error; + } + for (i = 0 ; i < ret ; i++) { + virInterfaceDefPtr def; + char *relFile = virXMLPropString(ifaces[i], "file"); + if (relFile != NULL) { + char *absFile = testBuildFilename(file, relFile); + VIR_FREE(relFile); + if (!absFile) { + testError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("resolving interface filename")); + goto error; + } + + def = virInterfaceDefParseFile(conn, absFile); + VIR_FREE(absFile); + if (!def) + goto error; + } else { + if ((def = virInterfaceDefParseNode(conn, xml, ifaces[i])) == NULL) + goto error; + } + if (!(iface = virInterfaceAssignDef(conn, &privconn->ifaces, def))) { + virInterfaceDefFree(def); + goto error; + } + virInterfaceObjUnlock(iface); + } + VIR_FREE(ifaces); + /* Parse Storage Pool list */ ret = virXPathNodeSet(conn, "/node/pool", ctxt, &pools); if (ret < 0) { @@ -692,11 +751,13 @@ static int testOpenFromFile(virConnectPtr conn, xmlFreeDoc(xml); VIR_FREE(domains); VIR_FREE(networks); + VIR_FREE(ifaces); VIR_FREE(pools); if (fd != -1) close(fd); virDomainObjListFree(&privconn->domains); virNetworkObjListFree(&privconn->networks); + virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); testDriverUnlock(privconn); VIR_FREE(privconn); @@ -765,6 +826,7 @@ static int testClose(virConnectPtr conn) virCapabilitiesFree(privconn->caps); virDomainObjListFree(&privconn->domains); virNetworkObjListFree(&privconn->networks); + virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); virDomainEventCallbackListFree(privconn->domainEventCallbacks); @@ -2365,6 +2427,304 @@ cleanup: /* + * Physical host interface routines + */ + +static virDrvOpenStatus testOpenInterface(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + if (STRNEQ(conn->driver->name, "Test")) + return VIR_DRV_OPEN_DECLINED; + + conn->interfacePrivateData = conn->privateData; + return VIR_DRV_OPEN_SUCCESS; +} + +static int testCloseInterface(virConnectPtr conn) +{ + conn->interfacePrivateData = NULL; + return 0; +} + + +static int testNumOfInterfaces(virConnectPtr conn) +{ + testConnPtr privconn = conn->privateData; + int i, count = 0; + + testDriverLock(privconn); + for (i = 0 ; (i < privconn->ifaces.count); i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (virInterfaceIsActive(privconn->ifaces.objs[i])) { + count++; + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + return count; +} + +static int testListInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + testConnPtr privconn = conn->privateData; + int n = 0, i; + + testDriverLock(privconn); + memset(names, 0, sizeof(*names)*nnames); + for (i = 0 ; (i < privconn->ifaces.count) && (n < nnames); i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (virInterfaceIsActive(privconn->ifaces.objs[i])) { + if (!(names[n++] = strdup(privconn->ifaces.objs[i]->def->name))) { + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + goto no_memory; + } + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + + return n; + +no_memory: + virReportOOMError(conn); + for (n = 0 ; n < nnames ; n++) + VIR_FREE(names[n]); + testDriverUnlock(privconn); + return -1; +} + +static int testNumOfDefinedInterfaces(virConnectPtr conn) +{ + testConnPtr privconn = conn->privateData; + int i, count = 0; + + testDriverLock(privconn); + for (i = 0 ; i < privconn->ifaces.count; i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (!virInterfaceIsActive(privconn->ifaces.objs[i])) { + count++; + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + return count; +} + +static int testListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + testConnPtr privconn = conn->privateData; + int n = 0, i; + + testDriverLock(privconn); + memset(names, 0, sizeof(*names)*nnames); + for (i = 0 ; (i < privconn->ifaces.count) && (n < nnames); i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (!virInterfaceIsActive(privconn->ifaces.objs[i])) { + if (!(names[n++] = strdup(privconn->ifaces.objs[i]->def->name))) { + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + goto no_memory; + } + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + + return n; + +no_memory: + virReportOOMError(conn); + for (n = 0 ; n < nnames ; n++) + VIR_FREE(names[n]); + testDriverUnlock(privconn); + return -1; +} + +static virInterfacePtr testLookupInterfaceByName(virConnectPtr conn, + const char *name) +{ + testConnPtr privconn = conn->privateData; + virInterfaceObjPtr iface; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + iface = virInterfaceFindByName(&privconn->ifaces, name); + testDriverUnlock(privconn); + + if (iface == NULL) { + testError (conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + if (iface) + virInterfaceObjUnlock(iface); + return ret; +} + +static virInterfacePtr testLookupInterfaceByMACString(virConnectPtr conn, + const char *mac) +{ + testConnPtr privconn = conn->privateData; + virInterfaceObjPtr iface; + int ifacect; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1); + testDriverUnlock(privconn); + + if (ifacect == 0) { + testError (conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + if (ifacect > 1) { + testError (conn, VIR_ERR_MULTIPLE_INTERFACES, NULL); + goto cleanup; + } + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + if (iface) + virInterfaceObjUnlock(iface); + return ret; +} + +static char *testInterfaceGetXMLDesc(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + char *ret = NULL; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + testDriverUnlock(privconn); + + if (privinterface == NULL) { + testError(iface->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto cleanup; + } + + ret = virInterfaceDefFormat(iface->conn, privinterface->def); + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + return ret; +} + + +static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = conn->privateData; + virInterfaceDefPtr def; + virInterfaceObjPtr iface = NULL; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + if ((def = virInterfaceDefParseString(conn, xmlStr)) == NULL) + goto cleanup; + + if ((iface = virInterfaceAssignDef(conn, &privconn->ifaces, def)) == NULL) + goto cleanup; + def = NULL; + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + virInterfaceDefFree(def); + if (iface) + virInterfaceObjUnlock(iface); + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceUndefine(virInterfacePtr iface) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + virInterfaceRemove(&privconn->ifaces, + privinterface); + ret = 0; + +cleanup: + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceCreate(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + privinterface->active = 1; + ret = 0; + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceDestroy(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + privinterface->active = 0; + ret = 0; + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + testDriverUnlock(privconn); + return ret; +} + + + +/* * Storage Driver routines */ @@ -3723,6 +4083,24 @@ static virNetworkDriver testNetworkDriver = { testNetworkSetAutostart, /* networkSetAutostart */ }; +static virInterfaceDriver testInterfaceDriver = { + "Test", /* name */ + testOpenInterface, /* open */ + testCloseInterface, /* close */ + testNumOfInterfaces, /* numOfInterfaces */ + testListInterfaces, /* listInterfaces */ + testNumOfDefinedInterfaces, /* numOfDefinedInterfaces */ + testListDefinedInterfaces, /* listDefinedInterfaces */ + testLookupInterfaceByName, /* interfaceLookupByName */ + testLookupInterfaceByMACString, /* interfaceLookupByMACString */ + testInterfaceGetXMLDesc, /* interfaceGetXMLDesc */ + testInterfaceDefineXML, /* interfaceDefineXML */ + testInterfaceUndefine, /* interfaceUndefine */ + testInterfaceCreate, /* interfaceCreate */ + testInterfaceDestroy, /* interfaceDestroy */ +}; + + static virStorageDriver testStorageDriver = { .name = "Test", .open = testStorageOpen, @@ -3782,6 +4160,8 @@ testRegister(void) return -1; if (virRegisterNetworkDriver(&testNetworkDriver) < 0) return -1; + if (virRegisterInterfaceDriver(&testInterfaceDriver) < 0) + return -1; if (virRegisterStorageDriver(&testStorageDriver) < 0) return -1; if (virRegisterDeviceMonitor(&testDevMonitor) < 0) -- 1.6.0.6

On Mon, Jul 20, 2009 at 01:42:06PM -0400, Laine Stump wrote:
+ +static char *testInterfaceGetXMLDesc(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + char *ret = NULL; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + testDriverUnlock(privconn); + + if (privinterface == NULL) { + testError(iface->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
Minor bug there - should be VIR_ERR_NO_INTERFACE.
+ goto cleanup; + } + + ret = virInterfaceDefFormat(iface->conn, privinterface->def); + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + return ret; +} + + +static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = conn->privateData; + virInterfaceDefPtr def; + virInterfaceObjPtr iface = NULL; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + if ((def = virInterfaceDefParseString(conn, xmlStr)) == NULL) + goto cleanup; + + if ((iface = virInterfaceAssignDef(conn, &privconn->ifaces, def)) == NULL) + goto cleanup; + def = NULL; + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + virInterfaceDefFree(def); + if (iface) + virInterfaceObjUnlock(iface); + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceUndefine(virInterfacePtr iface) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + virInterfaceRemove(&privconn->ifaces, + privinterface); + ret = 0; + +cleanup: + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceCreate(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + privinterface->active = 1; + ret = 0; + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceDestroy(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + privinterface->active = 0; + ret = 0; + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + testDriverUnlock(privconn); + return ret; +}
The destroy method should give an OPERATION_INVALID if it is not current active and likewise create should give an error if it is already active. Regards, Daniel -- |: 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 :|

--- qemud/Makefile.am | 4 + qemud/qemud.c | 6 + src/Makefile.am | 16 ++- src/interface_driver.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++ src/interface_driver.h | 29 +++ 5 files changed, 553 insertions(+), 1 deletions(-) create mode 100644 src/interface_driver.c create mode 100644 src/interface_driver.h diff --git a/qemud/Makefile.am b/qemud/Makefile.am index 74dfd22..959ff88 100644 --- a/qemud/Makefile.am +++ b/qemud/Makefile.am @@ -135,6 +135,10 @@ if WITH_NETWORK libvirtd_LDADD += ../src/libvirt_driver_network.la endif +if WITH_NETCF + libvirtd_LDADD += ../src/libvirt_driver_interface.la +endif + if WITH_NODE_DEVICES libvirtd_LDADD += ../src/libvirt_driver_nodedev.la endif diff --git a/qemud/qemud.c b/qemud/qemud.c index e393db4..3e551ca 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -83,6 +83,9 @@ #ifdef WITH_NETWORK #include "network_driver.h" #endif +#ifdef WITH_NETCF +#include "interface_driver.h" +#endif #ifdef WITH_STORAGE_DIR #include "storage_driver.h" #endif @@ -824,6 +827,9 @@ static struct qemud_server *qemudInitialize(int sigread) { #ifdef WITH_NETWORK networkRegister(); #endif +#ifdef WITH_NETCF + interfaceRegister(); +#endif #ifdef WITH_STORAGE_DIR storageRegister(); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 9b662ae..79826b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -159,6 +159,9 @@ ONE_DRIVER_SOURCES = \ NETWORK_DRIVER_SOURCES = \ network_driver.h network_driver.c +INTERFACE_DRIVER_SOURCES = \ + interface_driver.h interface_driver.c + # Storage backend specific impls STORAGE_DRIVER_SOURCES = \ storage_driver.h storage_driver.c \ @@ -390,8 +393,18 @@ libvirt_driver_network_la_SOURCES = $(NETWORK_DRIVER_SOURCES) endif if WITH_NETCF -libvirt_driver_interface_la_CFLAGS = $(NETCF_CFLAGS) libvirt_driver_interface_la_LDFLAGS = $(NETCF_LIBS) +libvirt_driver_interface_la_CFLAGS = $(NETCF_CFLAGS) +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_interface.la +else +noinst_LTLIBRARIES += libvirt_driver_interface.la +libvirt_la_LIBADD += libvirt_driver_interface.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_interface_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_interface_la_SOURCES = $(INTERFACE_DRIVER_SOURCES) endif # Needed to keep automake quiet about conditionals @@ -476,6 +489,7 @@ EXTRA_DIST += \ $(OPENVZ_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ + $(INTERFACE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ diff --git a/src/interface_driver.c b/src/interface_driver.c new file mode 100644 index 0000000..6fd0b76 --- /dev/null +++ b/src/interface_driver.c @@ -0,0 +1,499 @@ +/* + * interface_driver.c: backend driver methods to handle physical + * interface configuration using the netcf library. + * + * Copyright (C) 2006-2009 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Laine Stump <laine@redhat.com> + */ + +#include <config.h> + +#include <netcf.h> + +#include "virterror_internal.h" +#include "datatypes.h" +#include "interface_driver.h" +#include "memory.h" + +#define VIR_FROM_THIS VIR_FROM_INTERFACE + +#define interfaceReportError(conn, dom, net, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +/* Main driver state */ +struct interface_driver +{ + virMutex lock; + struct netcf *netcf; +}; + + +static void interfaceDriverLock(struct interface_driver *driver) +{ + virMutexLock(&driver->lock); +} + +static void interfaceDriverUnlock(struct interface_driver *driver) +{ + virMutexUnlock(&driver->lock); +} + +static int netcf_to_vir_err(int netcf_errcode) +{ + switch (netcf_errcode) + { + case NETCF_NOERROR: + /* no error, everything ok */ + return VIR_ERR_OK; + case NETCF_EINTERNAL: + /* internal error, aka bug */ + return VIR_ERR_INTERNAL_ERROR; + case NETCF_EOTHER: + /* other error, copout for being more specific */ + return VIR_ERR_INTERNAL_ERROR; + case NETCF_ENOMEM: + /* allocation failed */ + return VIR_ERR_NO_MEMORY; + case NETCF_EXMLPARSER: + /* XML parser choked */ + return VIR_ERR_XML_ERROR; + case NETCF_EXMLINVALID: + /* XML invalid in some form */ + return VIR_ERR_XML_ERROR; + case NETCF_ENOENT: + /* Required entry in a tree is missing */ + return VIR_ERR_INTERNAL_ERROR; + case NETCF_EEXEC: + /* external program execution failed or returned non-0 */ + return VIR_ERR_INTERNAL_ERROR; + default: + return VIR_ERR_INTERNAL_ERROR; + } +} + +static struct netcf_if *interfaceDriverGetNetcfIF(struct netcf *ncf, virInterfacePtr ifinfo) +{ + /* 1) caller already has lock, + * 2) caller cleans up iface on return + */ + struct netcf_if *iface = ncf_lookup_by_name(ncf, ifinfo->name); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(ncf, &errmsg, &details); + if (errcode != NETCF_NOERROR) { + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "couldn't find interface named '%s' (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + } else { + interfaceReportError(ifinfo->conn, NULL, ifinfo, VIR_ERR_NO_INTERFACE, + "couldn't find interface named '%s'", ifinfo->name); + } + } + return iface; +} + +static virDrvOpenStatus interfaceOpenInterface(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driverState; + + if (VIR_ALLOC(driverState) < 0) + { + virReportOOMError(conn); + goto alloc_error; + } + + /* initialize non-0 stuff in driverState */ + if (virMutexInit(&driverState->lock) < 0) + { + /* what error to report? */ + goto mutex_error; + } + + /* open netcf */ + if (ncf_init(&driverState->netcf, NULL) != 0) + { + /* what error to report? */ + goto netcf_error; + } + + conn->interfacePrivateData = driverState; + return 0; + +netcf_error: + if (driverState->netcf) + { + ncf_close(driverState->netcf); + } + virMutexDestroy (&driverState->lock); +mutex_error: + VIR_FREE(driverState); +alloc_error: + return -1; +} + +static int interfaceCloseInterface(virConnectPtr conn) +{ + + if (conn->interfacePrivateData != NULL) + { + struct interface_driver *driver = conn->interfacePrivateData; + + /* close netcf instance */ + ncf_close(driver->netcf); + /* destroy lock */ + virMutexDestroy(&driver->lock); + /* free driver state */ + VIR_FREE(driver); + } + conn->interfacePrivateData = NULL; + return 0; +} + +static int interfaceNumOfInterfaces(virConnectPtr conn) +{ + int count; + struct interface_driver *driver = conn->interfacePrivateData; + + interfaceDriverLock(driver); + count = ncf_num_of_interfaces(driver->netcf, NETCF_IFACE_ACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to get number of interfaces on host"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; +} + +static int interfaceListInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + struct interface_driver *driver = conn->interfacePrivateData; + int count; + + interfaceDriverLock(driver); + + count = ncf_list_interfaces(driver->netcf, nnames, names, NETCF_IFACE_ACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to list host interfaces"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; + +} + +static int interfaceNumOfDefinedInterfaces(virConnectPtr conn) +{ + int count; + struct interface_driver *driver = conn->interfacePrivateData; + + interfaceDriverLock(driver); + count = ncf_num_of_interfaces(driver->netcf, NETCF_IFACE_INACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to get number of defined interfaces on host"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; +} + +static int interfaceListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + struct interface_driver *driver = conn->interfacePrivateData; + int count; + + interfaceDriverLock(driver); + + count = ncf_list_interfaces(driver->netcf, nnames, names, NETCF_IFACE_INACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to list host defined interfaces"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; + +} + +static virInterfacePtr interfaceLookupByName(virConnectPtr conn, + const char *name) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + iface = ncf_lookup_by_name(driver->netcf, name); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + if (errcode != NETCF_NOERROR) { + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "couldn't find interface named '%s' (netcf: %s - %s)", + name, errmsg, details ? details : ""); + } else { + interfaceReportError(conn, NULL, NULL, VIR_ERR_NO_INTERFACE, + "couldn't find interface named '%s'", name); + } + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfacePtr interfaceLookupByMACString(virConnectPtr conn, + const char *macstr) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface; + int niface; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + niface = ncf_lookup_by_mac_string(driver->netcf, macstr, 1, &iface); + + if (niface < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "couldn't find interface with MAC address '%s' (netcf: %s - %s)", + macstr, errmsg, details ? details : ""); + goto cleanup; + } + if (niface == 0) { + interfaceReportError(conn, NULL, NULL, VIR_ERR_NO_INTERFACE, + "couldn't find interface with MAC address '%s'", + macstr); + goto cleanup; + } + if (niface > 1) { + interfaceReportError(conn, NULL, NULL, VIR_ERR_MULTIPLE_INTERFACES, + "%s", _("multiple interfaces with matching MAC address")); + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static char *interfaceGetXMLDesc(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + char *ret = NULL; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_xml_desc(iface); + if (!ret) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "could not get interface XML description (netcf: %s - %s)", + errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfacePtr interfaceDefineXML(virConnectPtr conn, + const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface = NULL; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + + /* + * This is where we will want to validate the XML, and possibly + * transform it before sending it on. + */ + + iface = ncf_define(driver->netcf, xml); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "could not get interface XML description (netcf: %s - %s)", + errmsg, details ? details : ""); + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static int interfaceUndefine(virInterfacePtr ifinfo) { + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + int ret = -1; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_undefine(iface); + if (ret < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "failed to undefine interface %s (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static int interfaceCreate(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + int ret = -1; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_up(iface); + if (ret < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "failed to create (start) interface %s (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static int interfaceDestroy(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + int ret = -1; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_down(iface); + if (ret < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "failed to destroy (stop) interface %s (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfaceDriver interfaceDriver = { + "Interface", + interfaceOpenInterface, /* open */ + interfaceCloseInterface, /* close */ + interfaceNumOfInterfaces, /* numOfInterfaces */ + interfaceListInterfaces, /* listInterfaces */ + interfaceNumOfDefinedInterfaces, /* numOfInterfaces */ + interfaceListDefinedInterfaces, /* listInterfaces */ + interfaceLookupByName, /* interfaceLookupByName */ + interfaceLookupByMACString, /* interfaceLookupByMACSTring */ + interfaceGetXMLDesc, /* interfaceGetXMLDesc */ + interfaceDefineXML, /* interfaceDefineXML */ + interfaceUndefine, /* interfaceUndefine */ + interfaceCreate, /* interfaceCreate */ + interfaceDestroy, /* interfaceDestroy */ +}; + +int interfaceRegister(void) { + virRegisterInterfaceDriver(&interfaceDriver); + return 0; +} diff --git a/src/interface_driver.h b/src/interface_driver.h new file mode 100644 index 0000000..b4ace5b --- /dev/null +++ b/src/interface_driver.h @@ -0,0 +1,29 @@ +/* + * interface_driver.h: core driver methods for managing physical host interfaces + * + * Copyright (C) 2006, 2007 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Laine Stump <laine@redhat.com> + */ + + +#ifndef __VIR_INTERFACE__DRIVER_H +#define __VIR_INTERFACE__DRIVER_H + +int interfaceRegister(void); + +#endif /* __VIR_INTERFACE__DRIVER_H */ -- 1.6.0.6

On Mon, Jul 20, 2009 at 01:42:07PM -0400, Laine Stump wrote:
+static char *interfaceGetXMLDesc(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + char *ret = NULL; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_xml_desc(iface); + if (!ret) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "could not get interface XML description (netcf: %s - %s)", + errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfacePtr interfaceDefineXML(virConnectPtr conn, + const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface = NULL; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + + /* + * This is where we will want to validate the XML, and possibly + * transform it before sending it on. + */ + + iface = ncf_define(driver->netcf, xml); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "could not get interface XML description (netcf: %s - %s)", + errmsg, details ? details : ""); + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +}
These two method should be round-tripping the XML via the virInterfaceDef parse/format methods really. Daniel -- |: 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 :|

On 07/20/2009 02:56 PM, Daniel P. Berrange wrote:
These two method should be round-tripping the XML via the virInterfaceDef parse/format methods really.
I pretend to understand, but I'm still a bit confused about this. Should I just be calling virInterfaceDefParseString() immediately followed by virInterfaceDefFormatString() within the driver method? Or are you looking for something more complicated?
Daniel

Dang! I forgot the git-send-email option that makes it list "[PATCH n/m]" in each subject. I'll refrain from resending though (unless someone is really bothered by that :-))

These patches correspond to patches 2-6 in the set I sent yesterday (the 1st and 2nd had no changes, so they stand as-is). They incorporate all changes brought up in review of the first set. In particular: 1) When looking for a cached virInterface object for an interface, I now check that the mac address being searched for matches the one in the virInterface (case insensitive comparison). If it doesn't match, I create a new object rather than trying to modify the existing object with the same interface name, as that could have led to "improper behavior". 2) in virInterfaceFindByMACString() I now follow danpb's suggestion and use continue, rather than getting fancy with booleans. 3) testinterfaceCreate() and testInterfaceDestroy() now check if the interface has already been created/destroyed, and won't do the same operation twice in a row. 4) in the netcf backend driver, I now "roundtrip" the xml data in both interfaceDefineXML() and interfaceGetXMLDesc().

On Tue, Jul 21, 2009 at 02:09:38AM -0400, Laine Stump wrote:
These patches correspond to patches 2-6 in the set I sent yesterday (the 1st and 2nd had no changes, so they stand as-is). They incorporate all changes brought up in review of the first set. In particular:
1) When looking for a cached virInterface object for an interface, I now check that the mac address being searched for matches the one in the virInterface (case insensitive comparison). If it doesn't match, I create a new object rather than trying to modify the existing object with the same interface name, as that could have led to "improper behavior".
2) in virInterfaceFindByMACString() I now follow danpb's suggestion and use continue, rather than getting fancy with booleans.
3) testinterfaceCreate() and testInterfaceDestroy() now check if the interface has already been created/destroyed, and won't do the same operation twice in a row.
4) in the netcf backend driver, I now "roundtrip" the xml data in both interfaceDefineXML() and interfaceGetXMLDesc().
ACK this series looks good now Daniel -- |: 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 :|

On Tue, Jul 21, 2009 at 02:09:38AM -0400, Laine Stump wrote:
These patches correspond to patches 2-6 in the set I sent yesterday (the 1st and 2nd had no changes, so they stand as-is). They incorporate all changes brought up in review of the first set. In particular:
1) When looking for a cached virInterface object for an interface, I now check that the mac address being searched for matches the one in the virInterface (case insensitive comparison). If it doesn't match, I create a new object rather than trying to modify the existing object with the same interface name, as that could have led to "improper behavior".
2) in virInterfaceFindByMACString() I now follow danpb's suggestion and use continue, rather than getting fancy with booleans.
3) testinterfaceCreate() and testInterfaceDestroy() now check if the interface has already been created/destroyed, and won't do the same operation twice in a row.
4) in the netcf backend driver, I now "roundtrip" the xml data in both interfaceDefineXML() and interfaceGetXMLDesc().
Okay I have applied everything, congrats ! I hope I didn't forgot anything ... I also applied my old patch to extend .syms, and had to cleanup a couple of things like superflous lines at end of module. One thing we we may have to revisit is how netcf NETCF_ENOMEM is handled, currently we just convert it to VIR_ERR_NO_MEMORY (which gave some syntax-check fun), but we should raise a proper virReportOOMError() instead, code around src/interface_driver.c line 72 may need some tweaking. But with the test driver commited in make check now works properly :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

MAC address of a particular interface may change over time, and the reduced virInterface object (which contains just name and mac) needs to reflect these changes. Since we can't modify the mac address of an existing virInterface (some other thread may currently be using it) we just create a new virInterface, and let the old one die a dignified death when its refct goes to 0. --- src/datatypes.c | 14 ++++++-------- 1 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index a8bffd2..5f90aad 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -516,9 +516,10 @@ virUnrefNetwork(virNetworkPtr network) { * @mac: pointer to the mac * * Lookup if the interface 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 - * virUnrefInterface() is needed to not leak data. + * if yes return a new pointer to it (possibly updating the MAC + * address), if no allocate a new structure, and register it in the + * table. In any case a corresponding call to virUnrefInterface() is + * needed to not leak data. * * Returns a pointer to the interface, or NULL in case of failure */ @@ -532,11 +533,9 @@ virGetInterface(virConnectPtr conn, const char *name, const char *mac) { } virMutexLock(&conn->lock); - /* TODO search by MAC first as they are better differentiators */ - ret = (virInterfacePtr) virHashLookup(conn->interfaces, name); - /* TODO check the MAC */ - if (ret == NULL) { + + if ((ret == NULL) || STRCASENEQ(ret->mac, mac)) { if (VIR_ALLOC(ret) < 0) { virReportOOMError(conn); goto error; @@ -593,7 +592,6 @@ virReleaseInterface(virInterfacePtr iface) { virConnectPtr conn = iface->conn; DEBUG("release interface %p %s", iface, iface->name); - /* TODO search by MAC first as they are better differenciators */ if (virHashRemoveEntry(conn->interfaces, iface->name, NULL) < 0) virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, _("interface missing from connection hash table")); -- 1.6.0.6

These functions are useful for an implementation of an interface driver that doesn't use a library that manages its own list of interfaces (as netcf does), for example the test interface driver. --- src/interface_conf.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/interface_conf.h | 15 +++++- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/src/interface_conf.c b/src/interface_conf.c index 0b73c97..1cc9f36 100644 --- a/src/interface_conf.c +++ b/src/interface_conf.c @@ -1128,6 +1128,8 @@ cleanup: return NULL; } +/* virInterfaceObj manipulation */ + void virInterfaceObjLock(virInterfaceObjPtr obj) { virMutexLock(&obj->lock); @@ -1137,3 +1139,136 @@ void virInterfaceObjUnlock(virInterfaceObjPtr obj) { virMutexUnlock(&obj->lock); } + +void virInterfaceObjFree(virInterfaceObjPtr iface) +{ + if (!iface) + return; + + virInterfaceDefFree(iface->def); + virMutexDestroy(&iface->lock); + VIR_FREE(iface); +} + +/* virInterfaceObjList manipulation */ + +int virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, + const char *mac, + virInterfaceObjPtr *matches, int maxmatches) +{ + unsigned int i, matchct = 0; + + for (i = 0 ; i < interfaces->count ; i++) { + + virInterfaceObjLock(interfaces->objs[i]); + if (STRCASEEQ(interfaces->objs[i]->def->mac, mac)) { + matchct++; + if (matchct <= maxmatches) { + matches[matchct - 1] = interfaces->objs[i]; + /* keep the lock if we're returning object to caller */ + /* it is the caller's responsibility to unlock *all* matches */ + continue; + } + } + virInterfaceObjUnlock(interfaces->objs[i]); + + } + return matchct; +} + +virInterfaceObjPtr virInterfaceFindByName(const virInterfaceObjListPtr + interfaces, + const char *name) +{ + unsigned int i; + + for (i = 0 ; i < interfaces->count ; i++) { + virInterfaceObjLock(interfaces->objs[i]); + if (STREQ(interfaces->objs[i]->def->name, name)) + return interfaces->objs[i]; + virInterfaceObjUnlock(interfaces->objs[i]); + } + + return NULL; +} + +void virInterfaceObjListFree(virInterfaceObjListPtr interfaces) +{ + unsigned int i; + + for (i = 0 ; i < interfaces->count ; i++) + virInterfaceObjFree(interfaces->objs[i]); + + VIR_FREE(interfaces->objs); + interfaces->count = 0; +} + +virInterfaceObjPtr virInterfaceAssignDef(virConnectPtr conn, + virInterfaceObjListPtr interfaces, + const virInterfaceDefPtr def) +{ + virInterfaceObjPtr interface; + + if ((interface = virInterfaceFindByName(interfaces, def->name))) { + if (interface->def) + virInterfaceDefFree(interface->def); + interface->def = def; + + return interface; + } + + if (VIR_ALLOC(interface) < 0) { + virReportOOMError(conn); + return NULL; + } + if (virMutexInit(&interface->lock) < 0) { + virInterfaceReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot initialize mutex")); + VIR_FREE(interface); + return NULL; + } + virInterfaceObjLock(interface); + interface->def = def; + + if (VIR_REALLOC_N(interfaces->objs, interfaces->count + 1) < 0) { + virReportOOMError(conn); + VIR_FREE(interface); + return NULL; + } + + interfaces->objs[interfaces->count] = interface; + interfaces->count++; + + return interface; + +} + +void virInterfaceRemove(virInterfaceObjListPtr interfaces, + const virInterfaceObjPtr interface) +{ + unsigned int i; + + virInterfaceObjUnlock(interface); + for (i = 0 ; i < interfaces->count ; i++) { + virInterfaceObjLock(interfaces->objs[i]); + if (interfaces->objs[i] == interface) { + virInterfaceObjUnlock(interfaces->objs[i]); + virInterfaceObjFree(interfaces->objs[i]); + + if (i < (interfaces->count - 1)) + memmove(interfaces->objs + i, interfaces->objs + i + 1, + sizeof(*(interfaces->objs)) * (interfaces->count - (i + 1))); + + if (VIR_REALLOC_N(interfaces->objs, interfaces->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + interfaces->count--; + + break; + } + virInterfaceObjUnlock(interfaces->objs[i]); + } +} + + + diff --git a/src/interface_conf.h b/src/interface_conf.h index c77a230..aea1208 100644 --- a/src/interface_conf.h +++ b/src/interface_conf.h @@ -160,6 +160,7 @@ typedef virInterfaceObj *virInterfaceObjPtr; struct _virInterfaceObj { virMutex lock; + int active:1; /* 1 if interface is active (up) */ virInterfaceDefPtr def; /* The interface definition */ }; @@ -170,9 +171,17 @@ struct _virInterfaceObjList { virInterfaceObjPtr *objs; }; -virInterfaceObjPtr virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, - const char *mac); -virInterfaceObjPtr virInterfaceFindByName(const virInterfaceObjListPtr interfaces, +static inline int +virInterfaceIsActive(const virInterfaceObjPtr iface) +{ + return iface->active; +} + +int virInterfaceFindByMACString(const virInterfaceObjListPtr interfaces, + const char *mac, + virInterfaceObjPtr *matches, int maxmatches); +virInterfaceObjPtr virInterfaceFindByName(const virInterfaceObjListPtr + interfaces, const char *name); -- 1.6.0.6

--- src/test.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 391 insertions(+), 1 deletions(-) diff --git a/src/test.c b/src/test.c index 6f07462..098d235 100644 --- a/src/test.c +++ b/src/test.c @@ -41,6 +41,7 @@ #include "capabilities.h" #include "memory.h" #include "network_conf.h" +#include "interface_conf.h" #include "domain_conf.h" #include "domain_event.h" #include "event.h" @@ -72,6 +73,7 @@ struct _testConn { virNodeInfo nodeInfo; virDomainObjList domains; virNetworkObjList networks; + virInterfaceObjList ifaces; virStoragePoolObjList pools; int numCells; testCell cells[MAX_CELLS]; @@ -202,6 +204,17 @@ static const char *defaultNetworkXML = " </ip>" "</network>"; +static const char *defaultInterfaceXML = +"<interface type=\"ethernet\" name=\"eth1\">" +" <start mode=\"onboot\"/>" +" <mac address=\"aa:bb:cc:dd:ee:ff\"/>" +" <mtu size=\"1492\"/>" +" <protocol family=\"ipv4\">" +" <ip address=\"192.168.0.5\" prefix=\"24\"/>" +" <route gateway=\"192.168.0.1\"/>" +" </protocol>" +"</interface>"; + static const char *defaultPoolXML = "<pool type='dir'>" " <name>default-pool</name>" @@ -223,6 +236,8 @@ static int testOpenDefault(virConnectPtr conn) { virDomainObjPtr domobj = NULL; virNetworkDefPtr netdef = NULL; virNetworkObjPtr netobj = NULL; + virInterfaceDefPtr interfacedef = NULL; + virInterfaceObjPtr interfaceobj = NULL; virStoragePoolDefPtr pooldef = NULL; virStoragePoolObjPtr poolobj = NULL; @@ -286,6 +301,15 @@ static int testOpenDefault(virConnectPtr conn) { netobj->persistent = 1; virNetworkObjUnlock(netobj); + if (!(interfacedef = virInterfaceDefParseString(conn, defaultInterfaceXML))) + goto error; + if (!(interfaceobj = virInterfaceAssignDef(conn, &privconn->ifaces, interfacedef))) { + virInterfaceDefFree(interfacedef); + goto error; + } + interfaceobj->active = 1; + virInterfaceObjUnlock(interfaceobj); + if (!(pooldef = virStoragePoolDefParseString(conn, defaultPoolXML))) goto error; @@ -309,6 +333,7 @@ static int testOpenDefault(virConnectPtr conn) { error: virDomainObjListFree(&privconn->domains); virNetworkObjListFree(&privconn->networks); + virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); virCapabilitiesFree(privconn->caps); testDriverUnlock(privconn); @@ -429,10 +454,11 @@ static int testOpenFromFile(virConnectPtr conn, char *str; xmlDocPtr xml = NULL; xmlNodePtr root = NULL; - xmlNodePtr *domains = NULL, *networks = NULL, *pools = NULL; + xmlNodePtr *domains = NULL, *networks = NULL, *ifaces = NULL, *pools = NULL; xmlXPathContextPtr ctxt = NULL; virNodeInfoPtr nodeInfo; virNetworkObjPtr net; + virInterfaceObjPtr iface; virDomainObjPtr dom; testConnPtr privconn; if (VIR_ALLOC(privconn) < 0) { @@ -629,6 +655,39 @@ static int testOpenFromFile(virConnectPtr conn, } VIR_FREE(networks); + /* Parse interface definitions */ + ret = virXPathNodeSet(conn, "/node/interface", ctxt, &ifaces); + if (ret < 0) { + testError(NULL, VIR_ERR_XML_ERROR, "%s", _("node interface list")); + goto error; + } + for (i = 0 ; i < ret ; i++) { + virInterfaceDefPtr def; + char *relFile = virXMLPropString(ifaces[i], "file"); + if (relFile != NULL) { + char *absFile = testBuildFilename(file, relFile); + VIR_FREE(relFile); + if (!absFile) { + testError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("resolving interface filename")); + goto error; + } + + def = virInterfaceDefParseFile(conn, absFile); + VIR_FREE(absFile); + if (!def) + goto error; + } else { + if ((def = virInterfaceDefParseNode(conn, xml, ifaces[i])) == NULL) + goto error; + } + if (!(iface = virInterfaceAssignDef(conn, &privconn->ifaces, def))) { + virInterfaceDefFree(def); + goto error; + } + virInterfaceObjUnlock(iface); + } + VIR_FREE(ifaces); + /* Parse Storage Pool list */ ret = virXPathNodeSet(conn, "/node/pool", ctxt, &pools); if (ret < 0) { @@ -692,11 +751,13 @@ static int testOpenFromFile(virConnectPtr conn, xmlFreeDoc(xml); VIR_FREE(domains); VIR_FREE(networks); + VIR_FREE(ifaces); VIR_FREE(pools); if (fd != -1) close(fd); virDomainObjListFree(&privconn->domains); virNetworkObjListFree(&privconn->networks); + virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); testDriverUnlock(privconn); VIR_FREE(privconn); @@ -765,6 +826,7 @@ static int testClose(virConnectPtr conn) virCapabilitiesFree(privconn->caps); virDomainObjListFree(&privconn->domains); virNetworkObjListFree(&privconn->networks); + virInterfaceObjListFree(&privconn->ifaces); virStoragePoolObjListFree(&privconn->pools); virDomainEventCallbackListFree(privconn->domainEventCallbacks); @@ -2365,6 +2427,314 @@ cleanup: /* + * Physical host interface routines + */ + +static virDrvOpenStatus testOpenInterface(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + if (STRNEQ(conn->driver->name, "Test")) + return VIR_DRV_OPEN_DECLINED; + + conn->interfacePrivateData = conn->privateData; + return VIR_DRV_OPEN_SUCCESS; +} + +static int testCloseInterface(virConnectPtr conn) +{ + conn->interfacePrivateData = NULL; + return 0; +} + + +static int testNumOfInterfaces(virConnectPtr conn) +{ + testConnPtr privconn = conn->privateData; + int i, count = 0; + + testDriverLock(privconn); + for (i = 0 ; (i < privconn->ifaces.count); i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (virInterfaceIsActive(privconn->ifaces.objs[i])) { + count++; + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + return count; +} + +static int testListInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + testConnPtr privconn = conn->privateData; + int n = 0, i; + + testDriverLock(privconn); + memset(names, 0, sizeof(*names)*nnames); + for (i = 0 ; (i < privconn->ifaces.count) && (n < nnames); i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (virInterfaceIsActive(privconn->ifaces.objs[i])) { + if (!(names[n++] = strdup(privconn->ifaces.objs[i]->def->name))) { + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + goto no_memory; + } + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + + return n; + +no_memory: + virReportOOMError(conn); + for (n = 0 ; n < nnames ; n++) + VIR_FREE(names[n]); + testDriverUnlock(privconn); + return -1; +} + +static int testNumOfDefinedInterfaces(virConnectPtr conn) +{ + testConnPtr privconn = conn->privateData; + int i, count = 0; + + testDriverLock(privconn); + for (i = 0 ; i < privconn->ifaces.count; i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (!virInterfaceIsActive(privconn->ifaces.objs[i])) { + count++; + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + return count; +} + +static int testListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + testConnPtr privconn = conn->privateData; + int n = 0, i; + + testDriverLock(privconn); + memset(names, 0, sizeof(*names)*nnames); + for (i = 0 ; (i < privconn->ifaces.count) && (n < nnames); i++) { + virInterfaceObjLock(privconn->ifaces.objs[i]); + if (!virInterfaceIsActive(privconn->ifaces.objs[i])) { + if (!(names[n++] = strdup(privconn->ifaces.objs[i]->def->name))) { + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + goto no_memory; + } + } + virInterfaceObjUnlock(privconn->ifaces.objs[i]); + } + testDriverUnlock(privconn); + + return n; + +no_memory: + virReportOOMError(conn); + for (n = 0 ; n < nnames ; n++) + VIR_FREE(names[n]); + testDriverUnlock(privconn); + return -1; +} + +static virInterfacePtr testLookupInterfaceByName(virConnectPtr conn, + const char *name) +{ + testConnPtr privconn = conn->privateData; + virInterfaceObjPtr iface; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + iface = virInterfaceFindByName(&privconn->ifaces, name); + testDriverUnlock(privconn); + + if (iface == NULL) { + testError (conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + if (iface) + virInterfaceObjUnlock(iface); + return ret; +} + +static virInterfacePtr testLookupInterfaceByMACString(virConnectPtr conn, + const char *mac) +{ + testConnPtr privconn = conn->privateData; + virInterfaceObjPtr iface; + int ifacect; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1); + testDriverUnlock(privconn); + + if (ifacect == 0) { + testError (conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + if (ifacect > 1) { + testError (conn, VIR_ERR_MULTIPLE_INTERFACES, NULL); + goto cleanup; + } + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + if (iface) + virInterfaceObjUnlock(iface); + return ret; +} + +static char *testInterfaceGetXMLDesc(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + char *ret = NULL; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + testDriverUnlock(privconn); + + if (privinterface == NULL) { + testError(iface->conn, VIR_ERR_NO_INTERFACE, __FUNCTION__); + goto cleanup; + } + + ret = virInterfaceDefFormat(iface->conn, privinterface->def); + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + return ret; +} + + +static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = conn->privateData; + virInterfaceDefPtr def; + virInterfaceObjPtr iface = NULL; + virInterfacePtr ret = NULL; + + testDriverLock(privconn); + if ((def = virInterfaceDefParseString(conn, xmlStr)) == NULL) + goto cleanup; + + if ((iface = virInterfaceAssignDef(conn, &privconn->ifaces, def)) == NULL) + goto cleanup; + def = NULL; + + ret = virGetInterface(conn, iface->def->name, iface->def->mac); + +cleanup: + virInterfaceDefFree(def); + if (iface) + virInterfaceObjUnlock(iface); + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceUndefine(virInterfacePtr iface) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + virInterfaceRemove(&privconn->ifaces, + privinterface); + ret = 0; + +cleanup: + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceCreate(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + if (privinterface->active != 0) { + testError (iface->conn, VIR_ERR_OPERATION_INVALID, NULL); + goto cleanup; + } + + privinterface->active = 1; + ret = 0; + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + testDriverUnlock(privconn); + return ret; +} + +static int testInterfaceDestroy(virInterfacePtr iface, + unsigned int flags ATTRIBUTE_UNUSED) +{ + testConnPtr privconn = iface->conn->privateData; + virInterfaceObjPtr privinterface; + int ret = -1; + + testDriverLock(privconn); + privinterface = virInterfaceFindByName(&privconn->ifaces, + iface->name); + + if (privinterface == NULL) { + testError (iface->conn, VIR_ERR_NO_INTERFACE, NULL); + goto cleanup; + } + + if (privinterface->active == 0) { + testError (iface->conn, VIR_ERR_OPERATION_INVALID, NULL); + goto cleanup; + } + + privinterface->active = 0; + ret = 0; + +cleanup: + if (privinterface) + virInterfaceObjUnlock(privinterface); + testDriverUnlock(privconn); + return ret; +} + + + +/* * Storage Driver routines */ @@ -3723,6 +4093,24 @@ static virNetworkDriver testNetworkDriver = { testNetworkSetAutostart, /* networkSetAutostart */ }; +static virInterfaceDriver testInterfaceDriver = { + "Test", /* name */ + testOpenInterface, /* open */ + testCloseInterface, /* close */ + testNumOfInterfaces, /* numOfInterfaces */ + testListInterfaces, /* listInterfaces */ + testNumOfDefinedInterfaces, /* numOfDefinedInterfaces */ + testListDefinedInterfaces, /* listDefinedInterfaces */ + testLookupInterfaceByName, /* interfaceLookupByName */ + testLookupInterfaceByMACString, /* interfaceLookupByMACString */ + testInterfaceGetXMLDesc, /* interfaceGetXMLDesc */ + testInterfaceDefineXML, /* interfaceDefineXML */ + testInterfaceUndefine, /* interfaceUndefine */ + testInterfaceCreate, /* interfaceCreate */ + testInterfaceDestroy, /* interfaceDestroy */ +}; + + static virStorageDriver testStorageDriver = { .name = "Test", .open = testStorageOpen, @@ -3782,6 +4170,8 @@ testRegister(void) return -1; if (virRegisterNetworkDriver(&testNetworkDriver) < 0) return -1; + if (virRegisterInterfaceDriver(&testInterfaceDriver) < 0) + return -1; if (virRegisterStorageDriver(&testStorageDriver) < 0) return -1; if (virRegisterDeviceMonitor(&testDevMonitor) < 0) -- 1.6.0.6

The DefineXML and GetXMLDesc functions now do a roundtrip of virInterfaceDefParseString->virInterfaceDefFormat. --- qemud/Makefile.am | 4 + qemud/qemud.c | 6 + src/Makefile.am | 16 ++- src/interface_driver.c | 527 ++++++++++++++++++++++++++++++++++++++++++++++++ src/interface_driver.h | 29 +++ 5 files changed, 581 insertions(+), 1 deletions(-) create mode 100644 src/interface_driver.c create mode 100644 src/interface_driver.h diff --git a/qemud/Makefile.am b/qemud/Makefile.am index 74dfd22..959ff88 100644 --- a/qemud/Makefile.am +++ b/qemud/Makefile.am @@ -135,6 +135,10 @@ if WITH_NETWORK libvirtd_LDADD += ../src/libvirt_driver_network.la endif +if WITH_NETCF + libvirtd_LDADD += ../src/libvirt_driver_interface.la +endif + if WITH_NODE_DEVICES libvirtd_LDADD += ../src/libvirt_driver_nodedev.la endif diff --git a/qemud/qemud.c b/qemud/qemud.c index e393db4..3e551ca 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -83,6 +83,9 @@ #ifdef WITH_NETWORK #include "network_driver.h" #endif +#ifdef WITH_NETCF +#include "interface_driver.h" +#endif #ifdef WITH_STORAGE_DIR #include "storage_driver.h" #endif @@ -824,6 +827,9 @@ static struct qemud_server *qemudInitialize(int sigread) { #ifdef WITH_NETWORK networkRegister(); #endif +#ifdef WITH_NETCF + interfaceRegister(); +#endif #ifdef WITH_STORAGE_DIR storageRegister(); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 9b662ae..79826b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -159,6 +159,9 @@ ONE_DRIVER_SOURCES = \ NETWORK_DRIVER_SOURCES = \ network_driver.h network_driver.c +INTERFACE_DRIVER_SOURCES = \ + interface_driver.h interface_driver.c + # Storage backend specific impls STORAGE_DRIVER_SOURCES = \ storage_driver.h storage_driver.c \ @@ -390,8 +393,18 @@ libvirt_driver_network_la_SOURCES = $(NETWORK_DRIVER_SOURCES) endif if WITH_NETCF -libvirt_driver_interface_la_CFLAGS = $(NETCF_CFLAGS) libvirt_driver_interface_la_LDFLAGS = $(NETCF_LIBS) +libvirt_driver_interface_la_CFLAGS = $(NETCF_CFLAGS) +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_interface.la +else +noinst_LTLIBRARIES += libvirt_driver_interface.la +libvirt_la_LIBADD += libvirt_driver_interface.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_interface_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_interface_la_SOURCES = $(INTERFACE_DRIVER_SOURCES) endif # Needed to keep automake quiet about conditionals @@ -476,6 +489,7 @@ EXTRA_DIST += \ $(OPENVZ_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ + $(INTERFACE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ diff --git a/src/interface_driver.c b/src/interface_driver.c new file mode 100644 index 0000000..5378439 --- /dev/null +++ b/src/interface_driver.c @@ -0,0 +1,527 @@ +/* + * interface_driver.c: backend driver methods to handle physical + * interface configuration using the netcf library. + * + * Copyright (C) 2006-2009 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Laine Stump <laine@redhat.com> + */ + +#include <config.h> + +#include <netcf.h> + +#include "virterror_internal.h" +#include "datatypes.h" +#include "interface_driver.h" +#include "interface_conf.h" +#include "memory.h" + +#define VIR_FROM_THIS VIR_FROM_INTERFACE + +#define interfaceReportError(conn, dom, net, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +/* Main driver state */ +struct interface_driver +{ + virMutex lock; + struct netcf *netcf; +}; + + +static void interfaceDriverLock(struct interface_driver *driver) +{ + virMutexLock(&driver->lock); +} + +static void interfaceDriverUnlock(struct interface_driver *driver) +{ + virMutexUnlock(&driver->lock); +} + +static int netcf_to_vir_err(int netcf_errcode) +{ + switch (netcf_errcode) + { + case NETCF_NOERROR: + /* no error, everything ok */ + return VIR_ERR_OK; + case NETCF_EINTERNAL: + /* internal error, aka bug */ + return VIR_ERR_INTERNAL_ERROR; + case NETCF_EOTHER: + /* other error, copout for being more specific */ + return VIR_ERR_INTERNAL_ERROR; + case NETCF_ENOMEM: + /* allocation failed */ + return VIR_ERR_NO_MEMORY; + case NETCF_EXMLPARSER: + /* XML parser choked */ + return VIR_ERR_XML_ERROR; + case NETCF_EXMLINVALID: + /* XML invalid in some form */ + return VIR_ERR_XML_ERROR; + case NETCF_ENOENT: + /* Required entry in a tree is missing */ + return VIR_ERR_INTERNAL_ERROR; + case NETCF_EEXEC: + /* external program execution failed or returned non-0 */ + return VIR_ERR_INTERNAL_ERROR; + default: + return VIR_ERR_INTERNAL_ERROR; + } +} + +static struct netcf_if *interfaceDriverGetNetcfIF(struct netcf *ncf, virInterfacePtr ifinfo) +{ + /* 1) caller already has lock, + * 2) caller cleans up iface on return + */ + struct netcf_if *iface = ncf_lookup_by_name(ncf, ifinfo->name); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(ncf, &errmsg, &details); + if (errcode != NETCF_NOERROR) { + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "couldn't find interface named '%s' (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + } else { + interfaceReportError(ifinfo->conn, NULL, ifinfo, VIR_ERR_NO_INTERFACE, + "couldn't find interface named '%s'", ifinfo->name); + } + } + return iface; +} + +static virDrvOpenStatus interfaceOpenInterface(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driverState; + + if (VIR_ALLOC(driverState) < 0) + { + virReportOOMError(conn); + goto alloc_error; + } + + /* initialize non-0 stuff in driverState */ + if (virMutexInit(&driverState->lock) < 0) + { + /* what error to report? */ + goto mutex_error; + } + + /* open netcf */ + if (ncf_init(&driverState->netcf, NULL) != 0) + { + /* what error to report? */ + goto netcf_error; + } + + conn->interfacePrivateData = driverState; + return 0; + +netcf_error: + if (driverState->netcf) + { + ncf_close(driverState->netcf); + } + virMutexDestroy (&driverState->lock); +mutex_error: + VIR_FREE(driverState); +alloc_error: + return -1; +} + +static int interfaceCloseInterface(virConnectPtr conn) +{ + + if (conn->interfacePrivateData != NULL) + { + struct interface_driver *driver = conn->interfacePrivateData; + + /* close netcf instance */ + ncf_close(driver->netcf); + /* destroy lock */ + virMutexDestroy(&driver->lock); + /* free driver state */ + VIR_FREE(driver); + } + conn->interfacePrivateData = NULL; + return 0; +} + +static int interfaceNumOfInterfaces(virConnectPtr conn) +{ + int count; + struct interface_driver *driver = conn->interfacePrivateData; + + interfaceDriverLock(driver); + count = ncf_num_of_interfaces(driver->netcf, NETCF_IFACE_ACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to get number of interfaces on host"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; +} + +static int interfaceListInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + struct interface_driver *driver = conn->interfacePrivateData; + int count; + + interfaceDriverLock(driver); + + count = ncf_list_interfaces(driver->netcf, nnames, names, NETCF_IFACE_ACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to list host interfaces"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; + +} + +static int interfaceNumOfDefinedInterfaces(virConnectPtr conn) +{ + int count; + struct interface_driver *driver = conn->interfacePrivateData; + + interfaceDriverLock(driver); + count = ncf_num_of_interfaces(driver->netcf, NETCF_IFACE_INACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to get number of defined interfaces on host"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; +} + +static int interfaceListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames) +{ + struct interface_driver *driver = conn->interfacePrivateData; + int count; + + interfaceDriverLock(driver); + + count = ncf_list_interfaces(driver->netcf, nnames, names, NETCF_IFACE_INACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "%s (netcf: %s - %s)", + _("failed to list host defined interfaces"), + errmsg, details ? details : ""); + } + + interfaceDriverUnlock(driver); + return count; + +} + +static virInterfacePtr interfaceLookupByName(virConnectPtr conn, + const char *name) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + iface = ncf_lookup_by_name(driver->netcf, name); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + if (errcode != NETCF_NOERROR) { + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "couldn't find interface named '%s' (netcf: %s - %s)", + name, errmsg, details ? details : ""); + } else { + interfaceReportError(conn, NULL, NULL, VIR_ERR_NO_INTERFACE, + "couldn't find interface named '%s'", name); + } + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfacePtr interfaceLookupByMACString(virConnectPtr conn, + const char *macstr) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface; + int niface; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + niface = ncf_lookup_by_mac_string(driver->netcf, macstr, 1, &iface); + + if (niface < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "couldn't find interface with MAC address '%s' (netcf: %s - %s)", + macstr, errmsg, details ? details : ""); + goto cleanup; + } + if (niface == 0) { + interfaceReportError(conn, NULL, NULL, VIR_ERR_NO_INTERFACE, + "couldn't find interface with MAC address '%s'", + macstr); + goto cleanup; + } + if (niface > 1) { + interfaceReportError(conn, NULL, NULL, VIR_ERR_MULTIPLE_INTERFACES, + "%s", _("multiple interfaces with matching MAC address")); + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static char *interfaceGetXMLDesc(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + char *xmlstr = NULL; + virInterfaceDefPtr ifacedef = NULL; + char *ret = NULL; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + xmlstr = ncf_if_xml_desc(iface); + if (!xmlstr) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "could not get interface XML description (netcf: %s - %s)", + errmsg, details ? details : ""); + goto cleanup; + } + + ifacedef = virInterfaceDefParseString(ifinfo->conn, xmlstr); + if (!ifacedef) { + /* error was already reported */ + goto cleanup; + } + + ret = virInterfaceDefFormat(ifinfo->conn, ifacedef); + if (!ret) { + /* error was already reported */ + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + VIR_FREE(xmlstr); + virInterfaceDefFree(ifacedef); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfacePtr interfaceDefineXML(virConnectPtr conn, + const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = conn->interfacePrivateData; + struct netcf_if *iface = NULL; + char *xmlstr = NULL; + virInterfaceDefPtr ifacedef = NULL; + virInterfacePtr ret = NULL; + + interfaceDriverLock(driver); + + ifacedef = virInterfaceDefParseString(conn, xml); + if (!ifacedef) { + /* error was already reported */ + goto cleanup; + } + + xmlstr = virInterfaceDefFormat(conn, ifacedef); + if (!xmlstr) { + /* error was already reported */ + goto cleanup; + } + + iface = ncf_define(driver->netcf, xmlstr); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(conn, NULL, NULL, netcf_to_vir_err(errcode), + "could not get interface XML description (netcf: %s - %s)", + errmsg, details ? details : ""); + goto cleanup; + } + + ret = virGetInterface(conn, ncf_if_name(iface), ncf_if_mac_string(iface)); + +cleanup: + ncf_if_free(iface); + VIR_FREE(xmlstr); + virInterfaceDefFree(ifacedef); + interfaceDriverUnlock(driver); + return ret; +} + +static int interfaceUndefine(virInterfacePtr ifinfo) { + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + int ret = -1; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_undefine(iface); + if (ret < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "failed to undefine interface %s (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static int interfaceCreate(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + int ret = -1; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_up(iface); + if (ret < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "failed to create (start) interface %s (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static int interfaceDestroy(virInterfacePtr ifinfo, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct interface_driver *driver = ifinfo->conn->interfacePrivateData; + struct netcf_if *iface = NULL; + int ret = -1; + + interfaceDriverLock(driver); + + iface = interfaceDriverGetNetcfIF(driver->netcf, ifinfo); + if (!iface) { + /* helper already reported error */ + goto cleanup; + } + + ret = ncf_if_down(iface); + if (ret < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + interfaceReportError(ifinfo->conn, NULL, ifinfo, netcf_to_vir_err(errcode), + "failed to destroy (stop) interface %s (netcf: %s - %s)", + ifinfo->name, errmsg, details ? details : ""); + goto cleanup; + } + +cleanup: + ncf_if_free(iface); + interfaceDriverUnlock(driver); + return ret; +} + +static virInterfaceDriver interfaceDriver = { + "Interface", + interfaceOpenInterface, /* open */ + interfaceCloseInterface, /* close */ + interfaceNumOfInterfaces, /* numOfInterfaces */ + interfaceListInterfaces, /* listInterfaces */ + interfaceNumOfDefinedInterfaces, /* numOfInterfaces */ + interfaceListDefinedInterfaces, /* listInterfaces */ + interfaceLookupByName, /* interfaceLookupByName */ + interfaceLookupByMACString, /* interfaceLookupByMACSTring */ + interfaceGetXMLDesc, /* interfaceGetXMLDesc */ + interfaceDefineXML, /* interfaceDefineXML */ + interfaceUndefine, /* interfaceUndefine */ + interfaceCreate, /* interfaceCreate */ + interfaceDestroy, /* interfaceDestroy */ +}; + +int interfaceRegister(void) { + virRegisterInterfaceDriver(&interfaceDriver); + return 0; +} diff --git a/src/interface_driver.h b/src/interface_driver.h new file mode 100644 index 0000000..b4ace5b --- /dev/null +++ b/src/interface_driver.h @@ -0,0 +1,29 @@ +/* + * interface_driver.h: core driver methods for managing physical host interfaces + * + * Copyright (C) 2006, 2007 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Laine Stump <laine@redhat.com> + */ + + +#ifndef __VIR_INTERFACE__DRIVER_H +#define __VIR_INTERFACE__DRIVER_H + +int interfaceRegister(void); + +#endif /* __VIR_INTERFACE__DRIVER_H */ -- 1.6.0.6
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Laine Stump