mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-27 02:51:16 +00:00
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().
This commit is contained in:
parent
e018cbc74f
commit
4e6c38e10f
110
ChangeLog
110
ChangeLog
@ -1,16 +1,108 @@
|
||||
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
|
||||
|
||||
|
22
configure.in
22
configure.in
@ -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 ==========================================================================
|
||||
|
@ -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 =
|
||||
|
||||
|
609
qemud/bridge.c
Normal file
609
qemud/bridge.c
Normal file
@ -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:
|
||||
*/
|
101
qemud/bridge.h
Normal file
101
qemud/bridge.h
Normal file
@ -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:
|
||||
*/
|
352
qemud/conf.c
352
qemud/conf.c
@ -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,19 +1683,76 @@ 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);
|
||||
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 (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;
|
||||
}
|
||||
|
||||
if (unlink(vm->configFile) < 0) {
|
||||
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for guest %s", vm->def.name);
|
||||
if (unlink(configFile) < 0) {
|
||||
qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for %s", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vm->configFile[0] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
127
qemud/qemud.c
127
qemud/qemud.c
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user