[libvirt] [PATCH 0/2] updated/working patches for netcf backend and virsh commands for virInterface*

These are updated versions of patches I previously sent: 1 - add iface-* commands to virsh to expose virInterface* functions to the cli. 2 - add the netcf backend driver. These haven't been exhaustively tested, but appear to work in simple smoke tests. Note that they all depend on the submitted-but-not-yet-committed virConnectListDefinedInterfaces() patch.

Commands all start with "iface-", for example, iface-list, iface-dumpxml, etc. --- src/virsh.c | 536 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 536 insertions(+), 0 deletions(-) diff --git a/src/virsh.c b/src/virsh.c index 5623499..1ba4e37 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -228,6 +228,7 @@ static int vshCommandOptBool(const vshCmd *cmd, const char *name); #define VSH_BYID (1 << 1) #define VSH_BYUUID (1 << 2) #define VSH_BYNAME (1 << 3) +#define VSH_BYMAC (1 << 4) static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, char **name, int flag); @@ -244,6 +245,14 @@ static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd, vshCommandOptNetworkBy(_ctl, _cmd, _name, \ VSH_BYUUID|VSH_BYNAME) +static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, + char **name, int flag); + +/* default is lookup by Name and MAC */ +#define vshCommandOptInterface(_ctl, _cmd, _name) \ + vshCommandOptInterfaceBy(_ctl, _cmd, _name, \ + VSH_BYMAC|VSH_BYNAME) + static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, char **name, int flag); @@ -275,6 +284,10 @@ static const char *vshDomainVcpuStateToString(int state); static int vshConnectionUsability(vshControl *ctl, virConnectPtr conn, int showerror); +static char *editWriteToTempFile (vshControl *ctl, const char *doc); +static int editFile (vshControl *ctl, const char *filename); +static char *editReadBackFile (vshControl *ctl, const char *filename); + static void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line); #define vshMalloc(_ctl, _sz) _vshMalloc(_ctl, _sz, __FILE__, __LINE__) @@ -2692,6 +2705,106 @@ cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd) /* + * "iface-edit" command + */ +static const vshCmdInfo info_interface_edit[] = { + {"help", gettext_noop("edit XML configuration for a physical host interface")}, + {"desc", gettext_noop("Edit the XML configuration for a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_edit[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceEdit (vshControl *ctl, const vshCmd *cmd) +{ + int ret = FALSE; + virInterfacePtr iface = NULL; + char *tmp = NULL; + char *doc = NULL; + char *doc_edited = NULL; + char *doc_reread = NULL; + int flags = 0; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + goto cleanup; + + iface = vshCommandOptInterface (ctl, cmd, NULL); + if (iface == NULL) + goto cleanup; + + /* Get the XML configuration of the interface. */ + doc = virInterfaceGetXMLDesc (iface, flags); + if (!doc) + goto cleanup; + + /* Create and open the temporary file. */ + tmp = editWriteToTempFile (ctl, doc); + if (!tmp) goto cleanup; + + /* Start the editor. */ + if (editFile (ctl, tmp) == -1) goto cleanup; + + /* Read back the edited file. */ + doc_edited = editReadBackFile (ctl, tmp); + if (!doc_edited) goto cleanup; + + unlink (tmp); + tmp = NULL; + + /* Compare original XML with edited. Has it changed at all? */ + if (STREQ (doc, doc_edited)) { + vshPrint (ctl, _("Interface %s XML configuration not changed.\n"), + virInterfaceGetName (iface)); + ret = TRUE; + goto cleanup; + } + + /* Now re-read the interface XML. Did someone else change it while + * it was being edited? This also catches problems such as us + * losing a connection or the interface going away. + */ + doc_reread = virInterfaceGetXMLDesc (iface, flags); + if (!doc_reread) + goto cleanup; + + if (STRNEQ (doc, doc_reread)) { + vshError (ctl, FALSE, + "%s", _("ERROR: the XML configuration was changed by another user")); + goto cleanup; + } + + /* Everything checks out, so redefine the interface. */ + virInterfaceFree (iface); + iface = virInterfaceDefineXML (ctl->conn, doc_edited, 0); + if (!iface) + goto cleanup; + + vshPrint (ctl, _("Interface %s XML configuration edited.\n"), + virInterfaceGetName(iface)); + + ret = TRUE; + +cleanup: + if (iface) + virInterfaceFree (iface); + + free (doc); + free (doc_edited); + free (doc_reread); + + if (tmp) { + unlink (tmp); + free (tmp); + } + + return ret; +} + +/* * "net-list" command */ static const vshCmdInfo info_network_list[] = { @@ -2957,6 +3070,378 @@ cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd) } +/**************************************************************************/ +/* + * "iface-list" command + */ +static const vshCmdInfo info_interface_list[] = { + {"help", gettext_noop("list physical host interfaces")}, + {"desc", gettext_noop("Returns list of physical host interfaces.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_list[] = { + {"inactive", VSH_OT_BOOL, 0, gettext_noop("list inactive interfaces")}, + {"all", VSH_OT_BOOL, 0, gettext_noop("list inactive & active interfaces")}, + {NULL, 0, 0, NULL} +}; +static int +cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + int inactive = vshCommandOptBool(cmd, "inactive"); + int all = vshCommandOptBool(cmd, "all"); + int active = !inactive || all ? 1 : 0; + int maxactive = 0, maxinactive = 0, i; + char **activeNames = NULL, **inactiveNames = NULL; + inactive |= all; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (active) { + maxactive = virConnectNumOfInterfaces(ctl->conn); + if (maxactive < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list active interfaces")); + return FALSE; + } + if (maxactive) { + activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); + + if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames, + maxactive)) < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list active interfaces")); + free(activeNames); + return FALSE; + } + + qsort(&activeNames[0], maxactive, sizeof(char *), namesorter); + } + } + if (inactive) { + maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn); + if (maxinactive < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list inactive interfaces")); + free(activeNames); + return FALSE; + } + if (maxinactive) { + inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); + + if ((maxinactive = virConnectListDefinedInterfaces(ctl->conn, inactiveNames, maxinactive)) < 0) { + vshError(ctl, FALSE, "%s", _("Failed to list inactive interfaces")); + free(activeNames); + free(inactiveNames); + return FALSE; + } + + qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter); + } + } + vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"), _("MAC Address")); + vshPrintExtra(ctl, "--------------------------------------------\n"); + + for (i = 0; i < maxactive; i++) { + virInterfacePtr iface = virInterfaceLookupByName(ctl->conn, activeNames[i]); + const char *autostartStr; + int autostart = 0; + + /* this kind of work with interfaces is not atomic */ + if (!iface) { + free(activeNames[i]); + continue; + } + + vshPrint(ctl, "%-20s %-10s %s\n", + virInterfaceGetName(iface), + _("active"), + virInterfaceGetMACString(iface)); + virInterfaceFree(iface); + free(activeNames[i]); + } + for (i = 0; i < maxinactive; i++) { + virInterfacePtr iface = virInterfaceLookupByName(ctl->conn, inactiveNames[i]); + const char *autostartStr; + int autostart = 0; + + /* this kind of work with interfaces is not atomic */ + if (!iface) { + free(inactiveNames[i]); + continue; + } + + vshPrint(ctl, "%-20s %-10s %s\n", + virInterfaceGetName(iface), + _("inactive"), + virInterfaceGetMACString(iface)); + virInterfaceFree(iface); + free(inactiveNames[i]); + } + free(activeNames); + free(inactiveNames); + return TRUE; + +} + +/* + * "iface-name" command + */ +static const vshCmdInfo info_interface_name[] = { + {"help", gettext_noop("convert an interface MAC address to interface name")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_name[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface mac")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceName(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL, + VSH_BYMAC))) + return FALSE; + + vshPrint(ctl, "%s\n", virInterfaceGetName(iface)); + virInterfaceFree(iface); + return TRUE; +} + +/* + * "iface-mac" command + */ +static const vshCmdInfo info_interface_mac[] = { + {"help", gettext_noop("convert an interface name to interface MAC address")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_mac[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL, + VSH_BYNAME))) + return FALSE; + + vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface)); + virInterfaceFree(iface); + return TRUE; +} + +/* + * "iface-dumpxml" command + */ +static const vshCmdInfo info_interface_dumpxml[] = { + {"help", gettext_noop("interface information in XML")}, + {"desc", gettext_noop("Output the physical host interface information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_dumpxml[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + int ret = TRUE; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(iface = vshCommandOptInterface(ctl, cmd, NULL))) + return FALSE; + + dump = virInterfaceGetXMLDesc(iface, 0); + if (dump != NULL) { + printf("%s", dump); + free(dump); + } else { + ret = FALSE; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-define" command + */ +static const vshCmdInfo info_interface_define[] = { + {"help", gettext_noop("define (but don't start) a physical host interface from an XML file")}, + {"desc", gettext_noop("Define a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML interface description")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr interface; + char *from; + int found; + int ret = TRUE; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + interface = virInterfaceDefineXML(ctl->conn, buffer, 0); + free (buffer); + + if (interface != NULL) { + vshPrint(ctl, _("Interface %s defined from %s\n"), + virInterfaceGetName(interface), from); + } else { + vshError(ctl, FALSE, _("Failed to define interface from %s"), from); + ret = FALSE; + } + return ret; +} + +/* + * "iface-undefine" command + */ +static const vshCmdInfo info_interface_undefine[] = { + {"help", gettext_noop("undefine a physical host interface (remove it from configuration)")}, + {"desc", gettext_noop("undefine an interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_undefine[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + int ret = TRUE; + char *name; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) + return FALSE; + + if (virInterfaceUndefine(iface) == 0) { + vshPrint(ctl, _("Interface %s undefined\n"), name); + } else { + vshError(ctl, FALSE, _("Failed to undefine interface %s"), name); + ret = FALSE; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-start" command + */ +static const vshCmdInfo info_interface_start[] = { + {"help", gettext_noop("start a physical host interface (enable it / \"if-up\")")}, + {"desc", gettext_noop("start a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_start[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + int ret = TRUE; + char *name; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) + return FALSE; + + if (virInterfaceCreate(iface, 0) == 0) { + vshPrint(ctl, _("Interface %s started\n"), name); + } else { + vshError(ctl, FALSE, _("Failed to start interface %s"), name); + ret = FALSE; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-destroy" command + */ +static const vshCmdInfo info_interface_destroy[] = { + {"help", gettext_noop("destroy a physical host interface (disable it / \"if-down\")")}, + {"desc", gettext_noop("destroy a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_destroy[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + int ret = TRUE; + char *name; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) + return FALSE; + + if (virInterfaceDestroy(iface, 0) == 0) { + vshPrint(ctl, _("Interface %s destroyed\n"), name); + } else { + vshError(ctl, FALSE, _("Failed to destroy interface %s"), name); + ret = FALSE; + } + + virInterfaceFree(iface); + return ret; +} + +/**************************************************************************/ /* * "pool-autostart" command */ @@ -6249,6 +6734,17 @@ static const vshCmdDef commands[] = { {"net-start", cmdNetworkStart, opts_network_start, info_network_start}, {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine}, {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid}, + + {"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list}, + {"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name}, + {"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac}, + {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, info_interface_dumpxml}, + {"iface-define", cmdInterfaceDefine, opts_interface_define, info_interface_define}, + {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, info_interface_undefine}, + {"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit}, + {"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start}, + {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy}, + {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo}, {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices}, @@ -6700,6 +7196,46 @@ vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd, return network; } +static virInterfacePtr +vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, + char **name, int flag) +{ + virInterfacePtr iface = NULL; + char *n; + const char *optname = "interface"; + if (!cmd_has_option (ctl, cmd, optname)) + return NULL; + + if (!(n = vshCommandOptString(cmd, optname, NULL))) { + vshError(ctl, FALSE, "%s", _("undefined interface identifier")); + return NULL; + } + + vshDebug(ctl, 5, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by NAME */ + if ((iface == NULL) && (flag & VSH_BYNAME)) { + vshDebug(ctl, 5, "%s: <%s> trying as interface NAME\n", + cmd->def->name, optname); + iface = virInterfaceLookupByName(ctl->conn, n); + } + /* try it by MAC */ + if ((iface == NULL) && (flag & VSH_BYMAC)) { + vshDebug(ctl, 5, "%s: <%s> trying as interface MAC\n", + cmd->def->name, optname); + iface = virInterfaceLookupByMACString(ctl->conn, n); + } + + if (!iface) + vshError(ctl, FALSE, _("failed to get interface '%s'"), n); + + return iface; +} + static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, char **name, int flag) -- 1.6.3.3.353.g4f2b1

On Tue, Jul 07, 2009 at 02:40:25AM -0400, Laine Stump wrote:
Commands all start with "iface-", for example, iface-list, iface-dumpxml, etc. --- src/virsh.c | 536 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Okay, makes sense, applied. I just had to remove 4 unused variables about autostart, I also split a few long lines to get back to 80 columns as a separate commit, thanks ! 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/

--- include/libvirt/virterror.h | 1 + qemud/Makefile.am | 4 + qemud/qemud.c | 6 + src/Makefile.am | 16 ++- src/interface_driver.c | 499 +++++++++++++++++++++++++++++++++++++++++++ src/interface_driver.h | 29 +++ src/libvirt.c | 4 - src/virterror.c | 6 + 8 files changed, 560 insertions(+), 5 deletions(-) create mode 100644 src/interface_driver.c create mode 100644 src/interface_driver.h 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/qemud/Makefile.am b/qemud/Makefile.am index 403846a..9f982ba 100644 --- a/qemud/Makefile.am +++ b/qemud/Makefile.am @@ -134,6 +134,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 da20aa9..e43f7e3 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -81,6 +81,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 @@ -822,6 +825,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 0c284c0..e94006e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -156,6 +156,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 \ @@ -386,8 +389,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 @@ -472,6 +485,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 */ diff --git a/src/libvirt.c b/src/libvirt.c index c1699f4..b85718c 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++) { 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.3.3.353.g4f2b1

On Tue, Jul 07, 2009 at 02:40:26AM -0400, Laine Stump wrote:
--- include/libvirt/virterror.h | 1 +
Patch is fine, except: 1/ it misses an export of symbols to add some of the new private entry points to the list (trivial to fix see attached patch) 2/ unfortunately since there is no test driver for the Interface stuff, running make check tries to access the system running libvirtd, and that's a blocker to commit (it can turn especially frustrating if you don't want to give the root passwd to the repeating prompts !) So we need to commit first a test driver for the interface driver (dummy entry points should be sufficient), before pushing that last patch Courage it's nearly there ! :-) thanks, 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/
participants (2)
-
Daniel Veillard
-
Laine Stump