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(a)redhat.com>
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(a)redhat.com>
+ */
+
+#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(a)redhat.com>
+ */
+
+#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);
}
--