Add support for creating and deleting bridges. Also add a <bridge> element for configuring the bridges and an <ip> element for setting and IP address on the bridge interface. Note, we require a number of kernel headers in order to interface with the bridge and tun/tap drivers. We also optionally use libsysfs to configure various bridge parameters. Signed-off-by: Mark McLoughlin <markmc@xxxxxxxxxx> Index: libvirt-foo/configure.in =================================================================== --- libvirt-foo.orig/configure.in 2007-02-14 14:29:38.000000000 +0000 +++ libvirt-foo.orig/configure.in 2007-02-14 14:29:38.000000000 +0000 @@ -102,6 +102,28 @@ then dnl search for the Xen store library AC_SEARCH_LIBS(xs_read, [xenstore], [], [AC_MSG_ERROR([Xen store library not found])]) +dnl +dnl check for libsyfs (>= 2.0.0); allow disabling bridge parameters support altogether +dnl +AC_ARG_ENABLE(bridge-params, + AC_HELP_STRING([--disable-bridge-params], + [disable support for setting bridge parameters using libsysfs [default=no]]),, + enable_bridge_params=yes) + +if test x"$enable_bridge_params" == "xyes"; then + AC_CHECK_LIB(sysfs, sysfs_open_device, + [AC_CHECK_HEADER(sysfs/libsysfs.h, + AC_DEFINE(ENABLE_BRIDGE_PARAMS, , [enable setting bridge parameters using libsysfs]) + SYSFS_LIBS="-lsysfs" AC_SUBST(SYSFS_LIBS), + AC_MSG_ERROR([You must install libsysfs in order to compile libvirt]))]) +fi + +dnl +dnl check for kernel headers required by qemud/bridge.c +dnl +AC_CHECK_HEADERS(linux/param.h linux/sockios.h linux/if_bridge.h linux/if_tun.h,, + AC_MSG_ERROR([You must install kernel-headers in order to compile libvirt])) + dnl ========================================================================== dnl find libxml2 library, borrowed from xmlsec dnl ========================================================================== Index: libvirt-foo/qemud/Makefile.am =================================================================== --- libvirt-foo.orig/qemud/Makefile.am 2007-02-14 14:38:46.000000000 +0000 +++ libvirt-foo.orig/qemud/Makefile.am 2007-02-14 14:38:46.000000000 +0000 @@ -7,13 +7,14 @@ libexec_PROGRAMS = libvirt_qemud libvirt_qemud_SOURCES = qemud.c internal.h protocol.h \ driver.c driver.h \ dispatch.c dispatch.h \ - conf.c conf.h + conf.c conf.h \ + bridge.c bridge.h #-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L libvirt_qemud_CFLAGS = \ -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \ -Werror -Wall -Wextra -DLOCAL_STATE_DIR="\"$(localstatedir)\"" \ -DSYSCONF_DIR="\"$(sysconfdir)\"" -libvirt_qemud_LDFLAGS = $(LIBXML_LIBS) +libvirt_qemud_LDFLAGS = $(LIBXML_LIBS) $(SYSFS_LIBS) libvirt_qemud_DEPENDENCIES = libvirt_qemud_LDADD = Index: libvirt-foo/qemud/bridge.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,609 @@ +/* + * Copyright (C) 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 + * + * Authors: + * Mark McLoughlin <markmc@xxxxxxxxxx> + */ + +#include <config.h> + +#include "bridge.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <linux/param.h> /* HZ */ +#include <linux/sockios.h> /* SIOCBRADDBR etc. */ +#include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */ +#include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */ + +#include "internal.h" + +#define MAX_BRIDGE_ID 256 + +#define JIFFIES_TO_MS(j) (((j)*1000)/HZ) +#define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000) + +struct _brControl { + int fd; +}; + +int +brInit(brControl **ctlp) +{ + int fd; + + if (!ctlp || *ctlp) + return EINVAL; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + return errno; + + *ctlp = (brControl *)malloc(sizeof(struct _brControl)); + if (!*ctlp) + return ENOMEM; + + (*ctlp)->fd = fd; + + return 0; +} + +void +brShutdown(brControl *ctl) +{ + if (!ctl) + return; + + close(ctl->fd); + ctl->fd = 0; + + free(ctl); +} + +int +brAddBridge(brControl *ctl, + const char *nameOrFmt, + char *name, + int maxlen) +{ + int id, subst; + + if (!ctl || !ctl->fd || !nameOrFmt || !name) + return EINVAL; + + if (maxlen >= BR_IFNAME_MAXLEN) + maxlen = BR_IFNAME_MAXLEN; + + subst = id = 0; + + if (strstr(nameOrFmt, "%d")) + subst = 1; + + do { + char try[BR_IFNAME_MAXLEN]; + int len; + + if (subst) { + len = snprintf(try, maxlen, nameOrFmt, id); + if (len >= maxlen) + return EADDRINUSE; + } else { + len = strlen(nameOrFmt); + if (len >= maxlen - 1) + return EINVAL; + + strncpy(try, nameOrFmt, len); + try[len] = '\0'; + } + + if (ioctl(ctl->fd, SIOCBRADDBR, try) == 0) { + strncpy(name, try, maxlen); + return 0; + } + + id++; + } while (subst && id <= MAX_BRIDGE_ID); + + return errno; +} + +int +brDeleteBridge(brControl *ctl, + const char *name) +{ + if (!ctl || !ctl->fd || !name) + return EINVAL; + + return ioctl(ctl->fd, SIOCBRDELBR, name) == 0 ? 0 : errno; +} + +static int +brAddDelInterface(brControl *ctl, + int cmd, + const char *bridge, + const char *iface) +{ + struct ifreq ifr; + int len; + + if (!ctl || !ctl->fd || !bridge || !iface) + return EINVAL; + + if ((len = strlen(bridge)) >= BR_IFNAME_MAXLEN) + return EINVAL; + + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, bridge, len); + ifr.ifr_name[len] = '\0'; + + if (!(ifr.ifr_ifindex = if_nametoindex(iface))) + return ENODEV; + + return ioctl(ctl->fd, cmd, &ifr) == 0 ? 0 : errno; +} + +int +brAddInterface(brControl *ctl, + const char *bridge, + const char *iface) +{ + return brAddDelInterface(ctl, SIOCBRADDIF, bridge, iface); +} + +int +brDeleteInterface(brControl *ctl, + const char *bridge, + const char *iface) +{ + return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface); +} + +int +brAddTap(brControl *ctl, + const char *bridge, + const char *ifnameOrFmt, + char *ifname, + int maxlen, + int *tapfd) +{ + int id, subst, fd; + + if (!ctl || !ctl->fd || !bridge || !ifnameOrFmt || !tapfd) + return EINVAL; + + if (!ifname) + maxlen = BR_IFNAME_MAXLEN; + else if (maxlen >= BR_IFNAME_MAXLEN) + maxlen = BR_IFNAME_MAXLEN; + + subst = id = 0; + + if (strstr(ifnameOrFmt, "%d")) + subst = 1; + + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) + return errno; + + do { + struct ifreq try; + int len; + + memset(&try, 0, sizeof(struct ifreq)); + + try.ifr_flags = IFF_TAP|IFF_NO_PI; + + if (subst) { + len = snprintf(try.ifr_name, maxlen, ifnameOrFmt, id); + if (len >= maxlen) { + errno = EADDRINUSE; + goto error; + } + } else { + len = strlen(ifnameOrFmt); + if (len >= maxlen - 1) { + errno = EINVAL; + goto error; + } + + strncpy(try.ifr_name, ifnameOrFmt, len); + try.ifr_name[len] = '\0'; + } + + if (ioctl(fd, TUNSETIFF, &try) == 0) { + if ((errno = brAddInterface(ctl, bridge, try.ifr_name))) + goto error; + if ((errno = brSetInterfaceUp(ctl, try.ifr_name, 1))) + goto error; + if (ifname) + strncpy(ifname, try.ifr_name, maxlen); + *tapfd = fd; + return 0; + } + + id++; + } while (subst && id <= MAX_BRIDGE_ID); + + error: + close(fd); + + return errno; +} + +int +brSetInterfaceUp(brControl *ctl, + const char *ifname, + int up) +{ + struct ifreq ifr; + int len; + int flags; + + if (!ctl || !ifname) + return EINVAL; + + if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN) + return EINVAL; + + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, ifname, len); + ifr.ifr_name[len] = '\0'; + + if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0) + return errno; + + flags = up ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP); + + if (ifr.ifr_flags != flags) { + ifr.ifr_flags = flags; + + if (ioctl(ctl->fd, SIOCSIFFLAGS, &ifr) < 0) + return errno; + } + + return 0; +} + +int +brGetInterfaceUp(brControl *ctl, + const char *ifname, + int *up) +{ + struct ifreq ifr; + int len; + + if (!ctl || !ifname) + return EINVAL; + + if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN) + return EINVAL; + + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, ifname, len); + ifr.ifr_name[len] = '\0'; + + if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0) + return errno; + + *up = (ifr.ifr_flags & IFF_UP) ? 1 : 0; + + return 0; +} + +static int +brSetInetAddr(brControl *ctl, + const char *ifname, + int cmd, + const char *addr) +{ + struct ifreq ifr; + struct in_addr inaddr; + int len, ret; + + if (!ctl || !ctl->fd || !ifname || !addr) + return EINVAL; + + if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN) + return EINVAL; + + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, ifname, len); + ifr.ifr_name[len] = '\0'; + + if ((ret = inet_pton(AF_INET, addr, &inaddr)) < 0) + return errno; + else if (ret == 0) + return EINVAL; + + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = inaddr; + + if (ioctl(ctl->fd, cmd, &ifr) < 0) + return errno; + + return 0; +} + +static int +brGetInetAddr(brControl *ctl, + const char *ifname, + int cmd, + char *addr, + int maxlen) +{ + struct ifreq ifr; + struct in_addr *inaddr; + int len; + + if (!ctl || !ctl->fd || !ifname || !addr) + return EINVAL; + + if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN) + return EINVAL; + + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, ifname, len); + ifr.ifr_name[len] = '\0'; + + if (ioctl(ctl->fd, cmd, &ifr) < 0) + return errno; + + if (maxlen < BR_INET_ADDR_MAXLEN || ifr.ifr_addr.sa_family != AF_INET) + return EFAULT; + + inaddr = &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; + + if (!inet_ntop(AF_INET, inaddr, addr, maxlen)) + return errno; + + return 0; +} + +int +brSetInetAddress(brControl *ctl, + const char *ifname, + const char *addr) +{ + return brSetInetAddr(ctl, ifname, SIOCSIFADDR, addr); +} + +int +brGetInetAddress(brControl *ctl, + const char *ifname, + char *addr, + int maxlen) +{ + return brGetInetAddr(ctl, ifname, SIOCGIFADDR, addr, maxlen); +} + +int +brSetInetNetmask(brControl *ctl, + const char *ifname, + const char *addr) +{ + return brSetInetAddr(ctl, ifname, SIOCSIFNETMASK, addr); +} + +int +brGetInetNetmask(brControl *ctl, + const char *ifname, + char *addr, + int maxlen) +{ + return brGetInetAddr(ctl, ifname, SIOCGIFNETMASK, addr, maxlen); +} + +#ifdef ENABLE_BRIDGE_PARAMS + +#include <sysfs/libsysfs.h> + +static int +brSysfsPrep(struct sysfs_class_device **dev, + struct sysfs_attribute **attr, + const char *bridge, + const char *attrname) +{ + *dev = NULL; + *attr = NULL; + + if (!(*dev = sysfs_open_class_device("net", bridge))) + return errno; + + if (!(*attr = sysfs_get_classdev_attr(*dev, attrname))) { + int err = errno; + + sysfs_close_class_device(*dev); + *dev = NULL; + + return err; + } + + return 0; +} + +static int +brSysfsWriteInt(struct sysfs_attribute *attr, + int value) +{ + char buf[32]; + int len; + + len = snprintf(buf, sizeof(buf), "%d\n", value); + + if (len > (int)sizeof(buf)) + len = sizeof(buf); /* paranoia, shouldn't happen */ + + return sysfs_write_attribute(attr, buf, len) == 0 ? 0 : errno; +} + +int +brSetForwardDelay(brControl *ctl, + const char *bridge, + int delay) +{ + struct sysfs_class_device *dev; + struct sysfs_attribute *attr; + int err = 0; + + if (!ctl || !bridge) + return EINVAL; + + if ((err = brSysfsPrep(&dev, &attr, bridge, SYSFS_BRIDGE_ATTR "/forward_delay"))) + return err; + + err = brSysfsWriteInt(attr, MS_TO_JIFFIES(delay)); + + sysfs_close_class_device(dev); + + return err; +} + +int +brGetForwardDelay(brControl *ctl, + const char *bridge, + int *delayp) +{ + struct sysfs_class_device *dev; + struct sysfs_attribute *attr; + int err = 0; + + if (!ctl || !bridge || !delayp) + return EINVAL; + + if ((err = brSysfsPrep(&dev, &attr, bridge, SYSFS_BRIDGE_ATTR "/forward_delay"))) + return err; + + *delayp = strtoul(attr->value, NULL, 0); + + if (errno != ERANGE) { + *delayp = JIFFIES_TO_MS(*delayp); + } else { + err = errno; + } + + sysfs_close_class_device(dev); + + return err; +} + +int +brSetEnableSTP(brControl *ctl, + const char *bridge, + int enable) +{ + struct sysfs_class_device *dev; + struct sysfs_attribute *attr; + int err = 0; + + if (!ctl || !bridge) + return EINVAL; + + if ((err = brSysfsPrep(&dev, &attr, bridge, SYSFS_BRIDGE_ATTR "/stp_state"))) + return err; + + err = brSysfsWriteInt(attr, (enable == 0) ? 0 : 1); + + sysfs_close_class_device(dev); + + return err; +} + +int +brGetEnableSTP(brControl *ctl, + const char *bridge, + int *enablep) +{ + struct sysfs_class_device *dev; + struct sysfs_attribute *attr; + int err = 0; + + if (!ctl || !bridge || !enablep) + return EINVAL; + + if ((err = brSysfsPrep(&dev, &attr, bridge, SYSFS_BRIDGE_ATTR "/stp_state"))) + return err; + + *enablep = strtoul(attr->value, NULL, 0); + + if (errno != ERANGE) { + *enablep = (*enablep == 0) ? 0 : 1; + } else { + err = errno; + } + + sysfs_close_class_device(dev); + + return err; +} + +#else /* ENABLE_BRIDGE_PARAMS */ + +int +brSetForwardDelay(brControl *ctl ATTRIBUTE_UNUSED, + const char *bridge ATTRIBUTE_UNUSED, + int delay ATTRIBUTE_UNUSED) +{ + return 0; +} + +int +brGetForwardDelay(brControl *ctl ATTRIBUTE_UNUSED, + const char *bridge ATTRIBUTE_UNUSED, + int *delay ATTRIBUTE_UNUSED) +{ + return 0; +} + +int +brSetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED, + const char *bridge ATTRIBUTE_UNUSED, + int enable ATTRIBUTE_UNUSED) +{ + return 0; +} + +int +brGetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED, + const char *bridge ATTRIBUTE_UNUSED, + int *enable ATTRIBUTE_UNUSED) +{ + return 0; +} + +#endif /* ENABLE_BRIDGE_PARAMS */ + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: libvirt-foo/qemud/bridge.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,101 @@ +/* + * Copyright (C) 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 + * + * Authors: + * Mark McLoughlin <markmc@xxxxxxxxxx> + */ + +#ifndef __QEMUD_BRIDGE_H__ +#define __QEMUD_BRIDGE_H__ + +#include <net/if.h> +#include <netinet/in.h> + +#define BR_IFNAME_MAXLEN IF_NAMESIZE +#define BR_INET_ADDR_MAXLEN INET_ADDRSTRLEN + +typedef struct _brControl brControl; + +int brInit (brControl **ctl); +void brShutdown (brControl *ctl); + +int brAddBridge (brControl *ctl, + const char *nameOrFmt, + char *name, + int maxlen); +int brDeleteBridge (brControl *ctl, + const char *name); + +int brAddInterface (brControl *ctl, + const char *bridge, + const char *iface); +int brDeleteInterface (brControl *ctl, + const char *bridge, + const char *iface); + +int brAddTap (brControl *ctl, + const char *bridge, + const char *ifnameOrFmt, + char *ifname, + int maxlen, + int *tapfd); + +int brSetInterfaceUp (brControl *ctl, + const char *ifname, + int up); +int brGetInterfaceUp (brControl *ctl, + const char *ifname, + int *up); + +int brSetInetAddress (brControl *ctl, + const char *ifname, + const char *addr); +int brGetInetAddress (brControl *ctl, + const char *ifname, + char *addr, + int maxlen); +int brSetInetNetmask (brControl *ctl, + const char *ifname, + const char *netmask); +int brGetInetNetmask (brControl *ctl, + const char *ifname, + char *netmask, + int maxlen); + +int brSetForwardDelay (brControl *ctl, + const char *bridge, + int delay); +int brGetForwardDelay (brControl *ctl, + const char *bridge, + int *delay); +int brSetEnableSTP (brControl *ctl, + const char *bridge, + int enable); +int brGetEnableSTP (brControl *ctl, + const char *bridge, + int *enable); + +#endif /* __QEMUD_BRIDGE_H__ */ + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: libvirt-foo/qemud/conf.c =================================================================== --- libvirt-foo.orig/qemud/conf.c 2007-02-14 15:54:56.000000000 +0000 +++ libvirt-foo.orig/qemud/conf.c 2007-02-14 15:54:56.000000000 +0000 @@ -1145,6 +1145,64 @@ static int qemudSaveNetworkConfig(struct } +static int qemudParseBridgeXML(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_network *network, + xmlNodePtr node) { + xmlChar *name, *stp, *delay; + + name = xmlGetProp(node, BAD_CAST "name"); + if (name != NULL) { + strncpy(network->def.bridge, (const char *)name, IF_NAMESIZE-1); + network->def.bridge[IF_NAMESIZE-1] = '\0'; + xmlFree(name); + name = NULL; + } + + stp = xmlGetProp(node, BAD_CAST "stp"); + if (stp != NULL) { + if (xmlStrEqual(stp, BAD_CAST "off")) { + network->def.disableSTP = 1; + } + xmlFree(stp); + stp = NULL; + } + + delay = xmlGetProp(node, BAD_CAST "delay"); + if (delay != NULL) { + network->def.forwardDelay = strtol((const char *)delay, NULL, 10); + xmlFree(delay); + delay = NULL; + } + + return 1; +} + + +static int qemudParseInetXML(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_network *network, + xmlNodePtr node) { + xmlChar *address, *netmask; + + address = xmlGetProp(node, BAD_CAST "address"); + if (address != NULL) { + strncpy(network->def.ipAddress, (const char *)address, BR_INET_ADDR_MAXLEN-1); + network->def.ipAddress[BR_INET_ADDR_MAXLEN-1] = '\0'; + xmlFree(address); + address = NULL; + } + + netmask = xmlGetProp(node, BAD_CAST "netmask"); + if (netmask != NULL) { + strncpy(network->def.netmask, (const char *)netmask, BR_INET_ADDR_MAXLEN-1); + network->def.netmask[BR_INET_ADDR_MAXLEN-1] = '\0'; + xmlFree(netmask); + netmask = NULL; + } + + return 1; +} + + static int qemudParseNetworkXML(struct qemud_server *server, xmlDocPtr xml, struct qemud_network *network) { @@ -1195,6 +1253,26 @@ static int qemudParseNetworkXML(struct q } xmlXPathFreeObject(obj); + /* Parse bridge information */ + obj = xmlXPathEval(BAD_CAST "/network/bridge[1]", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr > 0)) { + if (!qemudParseBridgeXML(server, network, obj->nodesetval->nodeTab[0])) { + goto error; + } + } + xmlXPathFreeObject(obj); + + /* Parse IP information */ + obj = xmlXPathEval(BAD_CAST "/network/ip[1]", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr > 0)) { + if (!qemudParseInetXML(server, network, obj->nodesetval->nodeTab[0])) { + goto error; + } + } + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); return 0; @@ -1209,7 +1287,6 @@ static int qemudParseNetworkXML(struct q return -1; } - struct qemud_network *qemudLoadNetworkConfigXML(struct qemud_server *server, const char *file, const char *doc, @@ -1629,6 +1706,28 @@ char *qemudGenerateNetworkXML(struct qem uuid[12], uuid[13], uuid[14], uuid[15]) < 0) goto no_memory; + if (qemudBufferPrintf(&buf, " <bridge name='%s' stp='%s' delay='%d' />\n", + network->def.bridge, + network->def.disableSTP ? "off" : "on", + network->def.forwardDelay) < 0) + goto no_memory; + + if (network->def.ipAddress[0] || network->def.netmask[0]) { + if (qemudBufferAdd(&buf, " <ip") < 0) + goto no_memory; + + if (network->def.ipAddress[0] && + qemudBufferPrintf(&buf, " address='%s'", network->def.ipAddress) < 0) + goto no_memory; + + if (network->def.netmask[0] && + qemudBufferPrintf(&buf, " netmask='%s'", network->def.netmask) < 0) + goto no_memory; + + if (qemudBufferAdd(&buf, "/>\n") < 0) + goto no_memory; + } + if (qemudBufferAdd(&buf, "</network>\n") < 0) goto no_memory; Index: libvirt-foo/qemud/internal.h =================================================================== --- libvirt-foo.orig/qemud/internal.h 2007-02-14 15:54:56.000000000 +0000 +++ libvirt-foo.orig/qemud/internal.h 2007-02-14 15:54:56.000000000 +0000 @@ -30,6 +30,7 @@ #include <gnutls/gnutls.h> #include "protocol.h" +#include "bridge.h" #ifdef __GNUC__ #ifdef HAVE_ANSIDECL_H @@ -203,6 +204,13 @@ struct qemud_vm { struct qemud_network_def { unsigned char uuid[QEMUD_UUID_RAW_LEN]; char name[QEMUD_MAX_NAME_LEN]; + + char bridge[BR_IFNAME_MAXLEN]; + int disableSTP; + int forwardDelay; + + char ipAddress[BR_INET_ADDR_MAXLEN]; + char netmask[BR_INET_ADDR_MAXLEN]; }; /* Virtual Network runtime state */ @@ -210,6 +218,11 @@ struct qemud_network { char configFile[PATH_MAX]; struct qemud_network_def def; + + char bridge[BR_IFNAME_MAXLEN]; + + unsigned int active : 1; + struct qemud_network *next; }; @@ -249,6 +262,7 @@ struct qemud_server { struct qemud_network *activenetworks; int ninactivenetworks; struct qemud_network *inactivenetworks; + brControl *brctl; char configDir[PATH_MAX]; char networkConfigDir[PATH_MAX]; char errorMessage[QEMUD_MAX_ERROR_LEN]; Index: libvirt-foo/qemud/qemud.c =================================================================== --- libvirt-foo.orig/qemud/qemud.c 2007-02-14 15:54:56.000000000 +0000 +++ libvirt-foo.orig/qemud/qemud.c 2007-02-14 15:54:56.000000000 +0000 @@ -706,14 +706,115 @@ static int qemudDispatchVMFailure(struct int qemudStartNetworkDaemon(struct qemud_server *server, struct qemud_network *network) { - server = NULL; network = NULL; + const char *name; + int err; + + if (network->active) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "network is already active"); + return -1; + } + + if (!server->brctl && (err = brInit(&server->brctl))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "cannot initialize bridge support: %s", strerror(err)); + return -1; + } + + if (network->def.bridge[0] == '\0' || + strchr(network->def.bridge, '%')) { + name = "vnet%d"; + } else { + name = network->def.bridge; + } + + if ((err = brAddBridge(server->brctl, name, network->bridge, sizeof(network->bridge)))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "cannot create bridge '%s' : %s", name, strerror(err)); + return -1; + } + + if (network->def.ipAddress[0] && + (err = brSetInetAddress(server->brctl, network->bridge, network->def.ipAddress))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "cannot set IP address on bridge '%s' to '%s' : %s\n", + network->bridge, network->def.ipAddress, strerror(err)); + goto err_delbr; + } + + if (network->def.netmask[0] && + (err = brSetInetNetmask(server->brctl, network->bridge, network->def.netmask))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "cannot set netmask on bridge '%s' to '%s' : %s\n", + network->bridge, network->def.netmask, strerror(err)); + goto err_delbr; + } + + if (network->def.ipAddress[0] && + (err = brSetInterfaceUp(server->brctl, network->bridge, 1))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to bring the bridge '%s' up : %s\n", + network->bridge, strerror(err)); + goto err_delbr; + } + + network->active = 1; + return 0; + + err_delbr: + if ((err = brDeleteBridge(server->brctl, network->bridge))) { + printf("Damn! Couldn't delete bridge '%s' : %s\n", + network->bridge, strerror(err)); + } + + return -1; } int qemudShutdownNetworkDaemon(struct qemud_server *server, struct qemud_network *network) { - server = NULL; network = NULL; + struct qemud_network *prev, *curr; + int err; + + if (!network->active) + return 0; + + if (network->def.ipAddress[0] && + (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) { + printf("Damn! Failed to bring down bridge '%s' : %s\n", + network->bridge, strerror(err)); + } + + if ((err = brDeleteBridge(server->brctl, network->bridge))) { + printf("Damn! Failed to delete bridge '%s' : %s\n", + network->bridge, strerror(err)); + } + + /* Move it to inactive networks list */ + prev = NULL; + curr = server->activenetworks; + while (curr) { + if (curr == network) { + if (prev) { + prev->next = curr->next; + } else { + server->activenetworks = curr->next; + } + server->nactivenetworks--; + + curr->next = server->inactivenetworks; + server->inactivenetworks = curr; + server->ninactivenetworks++; + break; + } + prev = curr; + curr = curr->next; + } + + network->bridge[0] = '\0'; + network->active = 0; + return 0; } @@ -723,6 +824,7 @@ static int qemudDispatchPoll(struct qemu struct qemud_client *client = server->clients; struct qemud_vm *vm = server->activevms; struct qemud_vm *tmp; + struct qemud_network *network, *prevnet; int ret = 0; int fd = 0; @@ -806,6 +908,25 @@ static int qemudDispatchPoll(struct qemu } } + /* Cleanup any networks too */ + network = server->inactivenetworks; + prevnet = NULL; + while (network) { + if (!network->configFile[0]) { + struct qemud_network *next = network->next; + if (prevnet) { + prevnet->next = next; + } else { + server->inactivenetworks = next; + } + qemudFreeNetwork(network); + network = next; + } else { + prevnet = network; + network = network->next; + } + } + return ret; } @@ -896,6 +1017,8 @@ static void qemudCleanup(struct qemud_se close(sock->fd); sock = sock->next; } + if (server->brctl) + brShutdown(server->brctl); free(server); } --