From da4f146f83a15c55c4b18e7b5a35dacaea170311 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Tue, 21 Jul 2009 16:02:16 +0200 Subject: [PATCH] Netcf based interface driver implementation * src/interface_driver.c src/interface_driver.h: the new driver * src/Makefile.am qemud/Makefile.am qemud/qemud.c: hook the new driver in the build system and get ti activated by the daemon * src/libvirt_private.syms: export needed symbols internally --- qemud/Makefile.am | 4 + qemud/qemud.c | 6 + src/Makefile.am | 16 +- src/interface_driver.c | 527 +++++++++++++++++++++++++++++++++++++++ src/interface_driver.h | 29 +++ src/libvirt_private.syms | 3 + 6 files changed, 584 insertions(+), 1 deletion(-) 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 74dfd2215b..959ff8800a 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 e393db464a..3e551ca17d 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 9b662ae702..79826b153d 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 0000000000..975c4d604b --- /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 + */ + +#include + +#include + +#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 0000000000..b4ace5ba42 --- /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 + */ + + +#ifndef __VIR_INTERFACE__DRIVER_H +#define __VIR_INTERFACE__DRIVER_H + +int interfaceRegister(void); + +#endif /* __VIR_INTERFACE__DRIVER_H */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 59c78d53f8..efdb912e0c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -161,6 +161,8 @@ virInterfaceDefParseFile; virInterfaceDefParseString; virInterfaceDefFree; +# interface_driver.h +interfaceRegister; # iptables.h iptablesAddForwardAllowCross; @@ -199,6 +201,7 @@ virDomainMigrateFinish; virDomainMigratePrepare2; virDomainMigrateFinish2; virRegisterDriver; +virRegisterInterfaceDriver; virRegisterNetworkDriver; virRegisterStateDriver; virRegisterStorageDriver; -- GitLab