]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Tue Feb 14 16:02:23 IST 2007 Mark McLoughlin <markmc@redhat.com>
authorMark McLoughlin <markmc@redhat.com>
Wed, 14 Feb 2007 16:02:40 +0000 (16:02 +0000)
committerMark McLoughlin <markmc@redhat.com>
Wed, 14 Feb 2007 16:02:40 +0000 (16:02 +0000)
        * configure.in: add --disable-bridge-params, check
        for libsysfs and various kernel headers

        * bridge.[ch]: add code for managing bridges

        * qemud/Makefile.am: add bridge.[ch] and link against
        libsysfs if enabled.

        * qemud/conf.c: add support for bridge config.

        * qemud/internal.h: add various bridging bits

        * qemud/qemud.c: implement qemudStartNetworkDaemon()
        and qemudShutdownNetworkDaemon().

ChangeLog
configure.in
qemud/Makefile.am
qemud/bridge.c [new file with mode: 0644]
qemud/bridge.h [new file with mode: 0644]
qemud/conf.c
qemud/internal.h
qemud/qemud.c

index f33dffe65b748e04fa520d22cd283a947c98395b..08eddde8bd7faede66bb8f9010d7c4e71d954f09 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-Tue Feb 14 14:58:35 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 16:02:23 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * configure.in: add --disable-bridge-params, check
+       for libsysfs and various kernel headers
+
+       * bridge.[ch]: add code for managing bridges
+       
+       * qemud/Makefile.am: add bridge.[ch] and link against
+       libsysfs if enabled.
+       
+       * qemud/conf.c: add support for bridge config.
+       
+       * qemud/internal.h: add various bridging bits
+
+       * qemud/qemud.c: implement qemudStartNetworkDaemon()
+       and qemudShutdownNetworkDaemon().
+       
+Tue Feb 14 15:55:02 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * qemud/conf.[ch]: implement parsing and saving network
+       configs.
+
+       * qemud/driver.c: flesh out the stubs
+       
+       * qemud/internal.h: add networks list etc. to
+       struct qemud_server
+       
+       * qemud/qemud.c: add qemudStartNetworkDaemon() and
+       qemudShutdownNetworkDaemon() stubs.
+       
+Tue Feb 14 15:52:34 EST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * qemud/protocol.h: add the protocol for virtual networks
+
+       * qemud/dispatch.c: implement the protocol
+
+       * qemud/driver.[ch]: add stubs for the driver
+
+       * qemud/internal.h: add struct qemud_network
+
+       * src/qemu_internal.c: add a virtual networks driver
+       
+Tue Feb 14 15:43:28 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * src/virsh.c: add the net-* commands.
+       
+Tue Feb 14 15:37:17 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       Note: potential ABI break here, but people should
+       only really be using virError structs returned from
+       libvirt itself.
+
+       * include/libvirt/virterror.h: add virNetwork
+       to virError
+       
+       * src/internal.h, src/virterror.c: add network param
+       to __virRaiseError()
+       
+       * src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
+       src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
+       src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
+       src/xs_internal.c: update.
+       
+Tue Feb 14 15:33:05 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * include/libvirt/libvirt.h.in: add the networks APIs
+       
+       * include/libvirt/virterror.h: add some error codes
+       
+       * src/driver.h: add network driver vtable
+       
+       * src/hash.c: add networks hash
+       
+       * src/internal.h: add virNetwork
+
+       * src/libvirt.c: hook up the APIs to the network
+       driver
+       
+       * src/libvirt_sym.version: add the new APIs
+       
+       * src/virterror.c: handle the new error codes
+       
+Tue Feb 14 15:07:26 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * src/conf.h: fix merge error - remove the argc argument
+       from qemudBuildCommandLine()
+       
+Tue Feb 14 15:03:22 IST 2007 Mark McLoughlin <markmc@redhat.com>
+
+       * src/virsh.c: Re-name some of the VSH_DOMBYFOO stuff
+       to VSH_BYFOO in order to re-use it for the network stuff.
+       
+Tue Feb 14 14:58:35 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * src/hash.c, src/internal.h: Re-name virConnect->domains_mux
        to virConnect->hashes_mux since it will also be used to
        protect the networks hash.
        
-Tue Feb 14 14:57:52 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:57:52 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * qemud/conf.c: qemudSaveConfig() will always report a
        more specific error, so we should avoid overwriting
        this error.
        
-Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:54:25 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * qemud/qemud.c: Re-factor out qemudExec() so that it can
        be used to launch dnsmasq.
@@ -18,7 +110,7 @@ Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin <markmc@redhat.com
        * qemud/conf.c: don't return argc from qemudBuildCommandLine()
        as exec() doesn't need it.
        
-Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:52:12 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * qemud/conf.c: Re-factor bits of conf.c so that:
 
@@ -28,25 +120,25 @@ Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin <markmc@redhat.com
          - split qemudScanConfigDir() out so that qemudScanConfigs()
            can scan multiple configDirs
        
-Tue Feb 14 14:50:22 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:50:22 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * qemud/conf.c: handle an unspecified MAC address, 
        fix the argv freeing code in qemudBuildCommandLine()
        and fix copy and paste error in qemudGenerateXML()
        
-Tue Feb 14 14:42:38 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:42:38 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * src/internal.h: add virConnect->qemud_fd so that
        xen and qemu don't share the handle member.
 
        * src/hash.c, src/qemu_internal.c: update
        
-Tue Feb 14 14:40:52 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:40:52 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * qemud/conf.c, qemud/dispatch.c, qemud/driver.c,
          qemud/qemud.c: include autoconf's config.h
        
-Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:39:18 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * conf.[ch]: rename from config.[ch] so we can use
        autoconf's config.h
@@ -55,7 +147,7 @@ Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin <markmc@redhat.com
 
        * driver.c, qemud.c: upd.
        
-Tue Feb 14 14:33:22 EST 2007 Mark McLoughlin <markmc@redhat.com
+Tue Feb 14 14:33:22 IST 2007 Mark McLoughlin <markmc@redhat.com>
 
        * autogen.sh: run autoheader
 
index 21168d128fd5d5736ce9480ab05c70b7d94cff26..082576d63799753cbf3a4b41a5f3295e34d4d46b 100644 (file)
@@ -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 e0692ff7007bd47e988a6185c84ed08a496309c6..73243c10d07fe33067a3fd0a55306012c12a956b 100644 (file)
@@ -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 =
 
diff --git a/qemud/bridge.c b/qemud/bridge.c
new file mode 100644 (file)
index 0000000..7438241
--- /dev/null
@@ -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@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:
+ */
diff --git a/qemud/bridge.h b/qemud/bridge.h
new file mode 100644 (file)
index 0000000..8109944
--- /dev/null
@@ -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@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 306abe5b78a6aeca7894e6278bedac3d2beab2d6..da80dfc048dbc89fb2b9cfbe042a9385b42732a2 100644 (file)
@@ -1098,17 +1098,263 @@ struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server,
 }
 
 
+void qemudFreeNetwork(struct qemud_network *network) {
+    free(network);
+}
+
+
+static int qemudSaveNetworkConfig(struct qemud_server *server,
+                                  struct qemud_network *network) {
+    char *xml;
+    int fd, ret = -1;
+    int towrite;
+
+    if (!(xml = qemudGenerateNetworkXML(server, network))) {
+        return -1;
+    }
+
+    if (qemudEnsureConfigDir(server, server->networkConfigDir) < 0) {
+        goto cleanup;
+    }
+
+    if ((fd = open(network->configFile,
+                   O_WRONLY | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR )) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create config file %s", network->configFile);
+        goto cleanup;
+    }
+
+    towrite = strlen(xml);
+    if (write(fd, xml, towrite) != towrite) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot write config file %s", network->configFile);
+        goto cleanup;
+    }
+
+    if (close(fd) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot save config file %s", network->configFile);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+
+    free(xml);
+
+    return ret;
+}
+
+
+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) {
+    xmlNodePtr root = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlXPathObjectPtr obj = NULL;
+
+    /* Prepare parser / xpath context */
+    root = xmlDocGetRootElement(xml);
+    if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "network"))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "incorrect root element");
+        goto error;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        qemudReportError(server, VIR_ERR_NO_MEMORY, "xmlXPathContext");
+        goto error;
+    }
+
+
+    /* Extract network name */
+    obj = xmlXPathEval(BAD_CAST "string(/network/name[1])", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        qemudReportError(server, VIR_ERR_NO_NAME, NULL);
+        goto error;
+    }
+    if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "network name length too long");
+        goto error;
+    }
+    strcpy(network->def.name, (const char *)obj->stringval);
+    xmlXPathFreeObject(obj);
+
+
+    /* Extract network uuid */
+    obj = xmlXPathEval(BAD_CAST "string(/network/uuid[1])", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        /* XXX auto-generate a UUID */
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "missing uuid element");
+        goto error;
+    }
+    if (qemudParseUUID((const char *)obj->stringval, network->def.uuid) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "malformed uuid element");
+        goto error;
+    }
+    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;
+
+ error:
+    /* XXX free all the stuff in the qemud_network struct, or leave it upto
+       the caller ? */
+    if (obj)
+        xmlXPathFreeObject(obj);
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    return -1;
+}
+
+struct qemud_network *qemudLoadNetworkConfigXML(struct qemud_server *server,
+                                                const char *file,
+                                                const char *doc,
+                                                int save) {
+    struct qemud_network *network = NULL;
+    xmlDocPtr xml;
+
+    if (!(xml = xmlReadDoc(BAD_CAST doc, file ? file : "network.xml", NULL,
+                           XML_PARSE_NOENT | XML_PARSE_NONET |
+                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+        qemudReportError(server, VIR_ERR_XML_ERROR, NULL);
+        return NULL;
+    }
+
+    if (!(network = calloc(1, sizeof(struct qemud_network)))) {
+        qemudReportError(server, VIR_ERR_NO_MEMORY, "network");
+        return NULL;
+    }
+
+    if (qemudParseNetworkXML(server, xml, network) < 0) {
+        xmlFreeDoc(xml);
+        qemudFreeNetwork(network);
+        return NULL;
+    }
+    xmlFreeDoc(xml);
+
+    if (qemudFindNetworkByUUID(server, network->def.uuid) ||
+        qemudFindNetworkByName(server, network->def.name)) {
+        qemudReportError(server, VIR_ERR_NETWORK_EXIST, network->def.name);
+        qemudFreeNetwork(network);
+        return NULL;
+    }
+
+    if (file) {
+        strncpy(network->configFile, file, PATH_MAX);
+        network->configFile[PATH_MAX-1] = '\0';
+    } else {
+        if (save) {
+            if (qemudMakeConfigPath(server->networkConfigDir, network->def.name, ".xml", network->configFile, PATH_MAX) < 0) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot construct config file path");
+                qemudFreeNetwork(network);
+                return NULL;
+            }
+
+            if (qemudSaveNetworkConfig(server, network) < 0) {
+                qemudFreeNetwork(network);
+                return NULL;
+            }
+        } else {
+            network->configFile[0] = '\0';
+        }
+    }
+
+    return network;
+}
+
+
 /* Load a guest from its persistent config file */
 static void qemudLoadConfig(struct qemud_server *server,
-                            const char *file) {
+                            const char *file,
+                            int isGuest) {
     FILE *fh;
     struct stat st;
-    struct qemud_vm *vm;
     char xml[QEMUD_MAX_XML_LEN];
     int ret;
 
     if (!(fh = fopen(file, "r"))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open guest config file %s", file);
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open config file %s", file);
         return;
     }
 
@@ -1118,7 +1364,7 @@ static void qemudLoadConfig(struct qemud_server *server,
     }
 
     if (st.st_size >= QEMUD_MAX_XML_LEN) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "guest config too large in file %s", file);
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "config too large in file %s", file);
         goto cleanup;
     }
 
@@ -1128,10 +1374,20 @@ static void qemudLoadConfig(struct qemud_server *server,
     }
     xml[st.st_size] = '\0';
 
-    if ((vm = qemudLoadConfigXML(server, file, xml, 1))) {
-        vm->next = server->inactivevms;
-        server->inactivevms = vm;
-        server->ninactivevms++;
+    if (isGuest) {
+        struct qemud_vm *vm;
+        if ((vm = qemudLoadConfigXML(server, file, xml, 1))) {
+            vm->next = server->inactivevms;
+            server->inactivevms = vm;
+            server->ninactivevms++;
+        }
+    } else {
+        struct qemud_network *network;
+        if ((network = qemudLoadNetworkConfigXML(server, file, xml, 1))) {
+            network->next = server->inactivenetworks;
+            server->inactivenetworks = network;
+            server->ninactivenetworks++;
+        }
     }
   
  cleanup:
@@ -1141,7 +1397,8 @@ static void qemudLoadConfig(struct qemud_server *server,
 
 static
 int qemudScanConfigDir(struct qemud_server *server,
-                       const char *configDir) {
+                       const char *configDir,
+                       int isGuest) {
     DIR *dir;
     struct dirent *entry;
 
@@ -1159,7 +1416,7 @@ int qemudScanConfigDir(struct qemud_server *server,
         if (qemudMakeConfigPath(configDir, entry->d_name, NULL, file, PATH_MAX) < 0)
             continue;
 
-        qemudLoadConfig(server, file);
+        qemudLoadConfig(server, file, isGuest);
     }
 
     closedir(dir);
@@ -1169,7 +1426,9 @@ int qemudScanConfigDir(struct qemud_server *server,
 
 /* Scan for all guest and network config files */
 int qemudScanConfigs(struct qemud_server *server) {
-    return qemudScanConfigDir(server, server->configDir);
+    if (qemudScanConfigDir(server, server->configDir, 0) < 0)
+        return -1;
+    return qemudScanConfigDir(server, server->networkConfigDir, 1);
 }
 
 /* Simple grow-on-demand string buffer */
@@ -1424,18 +1683,75 @@ char *qemudGenerateXML(struct qemud_server *server, struct qemud_vm *vm) {
 }
 
 
-int qemudDeleteConfigXML(struct qemud_server *server, struct qemud_vm *vm) {
-    if (!vm->configFile[0]) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for guest %s", vm->def.name);
-        return -1;
+char *qemudGenerateNetworkXML(struct qemud_server *server,
+                              struct qemud_network *network) {
+    struct qemudBuffer buf;
+    unsigned char *uuid;
+
+    buf.len = QEMUD_MAX_XML_LEN;
+    buf.used = 0;
+    buf.data = malloc(buf.len);
+
+    if (qemudBufferPrintf(&buf, "<network>\n") < 0)
+        goto no_memory;
+
+    if (qemudBufferPrintf(&buf, "  <name>%s</name>\n", network->def.name) < 0)
+        goto no_memory;
+
+    uuid = network->def.uuid;
+    if (qemudBufferPrintf(&buf, "  <uuid>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\n",
+                          uuid[0], uuid[1], uuid[2], uuid[3],
+                          uuid[4], uuid[5], uuid[6], uuid[7],
+                          uuid[8], uuid[9], uuid[10], uuid[11],
+                          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 (unlink(vm->configFile) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for guest %s", vm->def.name);
+    if (qemudBufferAdd(&buf, "</network>\n") < 0)
+        goto no_memory;
+
+    return buf.data;
+
+ no_memory:
+    qemudReportError(server, VIR_ERR_NO_MEMORY, "xml");
+    free(buf.data);
+    return NULL;
+}
+
+
+int qemudDeleteConfig(struct qemud_server *server,
+                      const char *configFile,
+                      const char *name) {
+    if (!configFile[0]) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for %s", name);
         return -1;
     }
 
-    vm->configFile[0] = '\0';
+    if (unlink(configFile) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for %s", name);
+        return -1;
+    }
 
     return 0;
 }
index 7a6d86b52ad0774281957df6d9086e716dcb576e..95528291233eb0624b6b522e9d131b43bf8ee12c 100644 (file)
@@ -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 a6c99a041aea4f31793f2129d1d5f545cdfe4eea..061eaecd91a73c6d5b4be6b967fc3a19d7af62c3 100644 (file)
@@ -706,14 +706,115 @@ static int qemudDispatchVMFailure(struct qemud_server *server, struct qemud_vm *
 
 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 qemud_server *server, struct pollfd *fds) {
     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 qemud_server *server, struct pollfd *fds) {
         }
     }
 
+    /* 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_server *server) {
         close(sock->fd);
         sock = sock->next;
     }
+    if (server->brctl)
+        brShutdown(server->brctl);
     free(server);
 }