Due to historical architectural restrictions the virtual network driver is actually part of the QEMU driver. The restrictions have long ago been removed, so its overdue to move the network driver out of the QEMU driver. This patch does this. It is a straight re-factoring with no functional change. The only minor pain point is that the network driver stores it config files under /etc/libvirt/qemu/networks, when ideally it would be in /etc/libvirt/networks. This patch leaves the config files where they already are, but I'm not too happy about that. I'd like to move them to the correct location and just leave a back-compatability symlink or something like that. b/src/network_driver.c | 1193 +++++++++++++++++++++++++++++++++++++++++++++++++ b/src/network_driver.h | 34 + configure.in | 12 src/Makefile.am | 8 src/libvirt.c | 6 src/qemu_conf.c | 15 src/qemu_conf.h | 5 src/qemu_driver.c | 965 --------------------------------------- 8 files changed, 1261 insertions(+), 977 deletions(-) Daniel diff -r f68f3fd13e9d configure.in --- a/configure.in Fri Oct 03 00:07:33 2008 +0100 +++ b/configure.in Fri Oct 03 10:46:41 2008 +0100 @@ -643,6 +643,17 @@ AC_SUBST([LIBVIRT_FEATURES]) +AC_ARG_WITH([network], +[ --with-network with virtual network driver (on)],[],[with_network=yes]) +if test "$with_libvirtd" = "no" ; then + with_network=no +fi +if test "$with_network" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_NETWORK], 1, [whether network driver is enabled]) +fi +AM_CONDITIONAL([WITH_NETWORK], [test "$with_network" = "yes"]) + + dnl dnl Storage driver checks dnl @@ -1070,6 +1081,7 @@ AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ Test: $with_test]) AC_MSG_NOTICE([ Remote: $with_remote]) +AC_MSG_NOTICE([ Network: $with_network]) AC_MSG_NOTICE([Libvirtd: $with_libvirtd]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Storage Drivers]) diff -r f68f3fd13e9d src/Makefile.am --- a/src/Makefile.am Fri Oct 03 00:07:33 2008 +0100 +++ b/src/Makefile.am Fri Oct 03 10:46:41 2008 +0100 @@ -102,11 +102,12 @@ openvz_conf.c openvz_conf.h \ openvz_driver.c openvz_driver.h -# XXX network driver should be split out of this QEMU_DRIVER_SOURCES = \ qemu_conf.c qemu_conf.h \ qemu_driver.c qemu_driver.h +NETWORK_DRIVER_SOURCES = \ + network_driver.h network_driver.c # And finally storage backend specific impls STORAGE_DRIVER_SOURCES = \ @@ -163,9 +164,11 @@ libvirt_la_SOURCES += $(OPENVZ_DRIVER_SOURCES) endif - # Drivers usable inside daemon context if WITH_LIBVIRTD +if WITH_NETWORK +libvirt_la_SOURCES += $(NETWORK_DRIVER_SOURCES) +endif libvirt_la_SOURCES += $(STORAGE_DRIVER_SOURCES) libvirt_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES) @@ -198,6 +201,7 @@ $(QEMU_DRIVER_SOURCES) \ $(LXC_DRIVER_SOURCES) \ $(OPENVZ_DRIVER_SOURCES) \ + $(NETWORK_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ diff -r f68f3fd13e9d src/libvirt.c --- a/src/libvirt.c Fri Oct 03 00:07:33 2008 +0100 +++ b/src/libvirt.c Fri Oct 03 10:46:41 2008 +0100 @@ -57,6 +57,9 @@ #include "lxc_driver.h" #endif #include "storage_driver.h" +#ifdef WITH_NETWORK +#include "network_driver.h" +#endif /* * TODO: @@ -295,6 +298,9 @@ #endif #ifdef WITH_LXC if (lxcRegister() == -1) return -1; +#endif +#ifdef WITH_NETWORK + if (networkRegister() == -1) return -1; #endif if (storageRegister() == -1) return -1; #ifdef WITH_REMOTE diff -r f68f3fd13e9d src/network_driver.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/network_driver.c Fri Oct 03 10:46:41 2008 +0100 @@ -0,0 +1,1193 @@ +/* + * driver.c: core driver methods for managing qemu guests + * + * Copyright (C) 2006, 2007, 2008 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/poll.h> +#include <dirent.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <strings.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/utsname.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <paths.h> +#include <pwd.h> +#include <stdio.h> +#include <sys/wait.h> +#include <sys/ioctl.h> + +#include "network_driver.h" +#include "network_conf.h" +#include "driver.h" +#include "c-ctype.h" +#include "event.h" +#include "buf.h" +#include "util.h" +#include "memory.h" +#include "uuid.h" +#include "iptables.h" +#include "bridge.h" + +/* Main driver state */ +struct network_driver { + virNetworkObjPtr networks; + + iptablesContext *iptables; + brControl *brctl; + char *networkConfigDir; + char *networkAutostartDir; + char *logDir; +}; + +static int networkShutdown(void); + +/* networkDebug statements should be changed to use this macro instead. */ +#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__) +#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg) + +#define networkLog(level, msg...) fprintf(stderr, msg) + +void networkReportError(virConnectPtr conn, + virDomainPtr dom, + virNetworkPtr net, + int code, const char *fmt, ...) + ATTRIBUTE_FORMAT(printf,5,6); + +void networkReportError(virConnectPtr conn, + virDomainPtr dom, + virNetworkPtr net, + int code, const char *fmt, ...) { + va_list args; + char errorMessage[1024]; + const char *virerr; + + if (fmt) { + va_start(args, fmt); + vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args); + va_end(args); + } else { + errorMessage[0] = '\0'; + } + + virerr = __virErrorMsg(code, (errorMessage[0] ? errorMessage : NULL)); + __virRaiseError(conn, dom, net, VIR_FROM_QEMU, code, VIR_ERR_ERROR, + virerr, errorMessage, NULL, -1, -1, virerr, errorMessage); +} + + +static int networkStartNetworkDaemon(virConnectPtr conn, + struct network_driver *driver, + virNetworkObjPtr network); + +static int networkShutdownNetworkDaemon(virConnectPtr conn, + struct network_driver *driver, + virNetworkObjPtr network); + +static struct network_driver *driverState = NULL; + + +static +void networkAutostartConfigs(struct network_driver *driver) { + virNetworkObjPtr network; + + network = driver->networks; + while (network != NULL) { + virNetworkObjPtr next = network->next; + + if (network->autostart && + !virNetworkIsActive(network) && + networkStartNetworkDaemon(NULL, driver, network) < 0) { + virErrorPtr err = virGetLastError(); + networkLog(NETWORK_ERR, _("Failed to autostart network '%s': %s\n"), + network->def->name, err->message); + } + + network = next; + } +} + +/** + * networkStartup: + * + * Initialization function for the QEmu daemon + */ +static int +networkStartup(void) { + uid_t uid = geteuid(); + struct passwd *pw; + char *base = NULL; + + if (VIR_ALLOC(driverState) < 0) + return -1; + + if (!uid) { + if (asprintf(&driverState->logDir, + "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1) + goto out_of_memory; + + if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL) + goto out_of_memory; + } else { + if (!(pw = getpwuid(uid))) { + networkLog(NETWORK_ERR, _("Failed to find user record for uid '%d': %s\n"), + uid, strerror(errno)); + goto out_of_memory; + } + + if (asprintf(&driverState->logDir, + "%s/.libvirt/qemu/log", pw->pw_dir) == -1) + goto out_of_memory; + + if (asprintf (&base, "%s/.libvirt", pw->pw_dir) == -1) { + networkLog (NETWORK_ERR, + "%s", _("out of memory in asprintf\n")); + goto out_of_memory; + } + } + + /* Configuration paths are either ~/.libvirt/qemu/... (session) or + * /etc/libvirt/qemu/... (system). + */ + if (asprintf (&driverState->networkConfigDir, "%s/qemu/networks", base) == -1) + goto out_of_memory; + + if (asprintf (&driverState->networkAutostartDir, "%s/qemu/networks/autostart", + base) == -1) + goto out_of_memory; + + VIR_FREE(base); + + if (virNetworkLoadAllConfigs(NULL, + &driverState->networks, + driverState->networkConfigDir, + driverState->networkAutostartDir) < 0) { + networkShutdown(); + return -1; + } + networkAutostartConfigs(driverState); + + return 0; + + out_of_memory: + networkLog (NETWORK_ERR, + "%s", _("networkStartup: out of memory\n")); + VIR_FREE(base); + VIR_FREE(driverState); + return -1; +} + +/** + * networkReload: + * + * Function to restart the QEmu daemon, it will recheck the configuration + * files and update its state and the networking + */ +static int +networkReload(void) { + virNetworkLoadAllConfigs(NULL, + &driverState->networks, + driverState->networkConfigDir, + driverState->networkAutostartDir); + + if (driverState->iptables) { + networkLog(NETWORK_INFO, + "%s", _("Reloading iptables rules\n")); + iptablesReloadRules(driverState->iptables); + } + + networkAutostartConfigs(driverState); + + return 0; +} + +/** + * networkActive: + * + * Checks if the QEmu daemon is active, i.e. has an active domain or + * an active network + * + * Returns 1 if active, 0 otherwise + */ +static int +networkActive(void) { + virNetworkObjPtr net = driverState->networks; + + while (net) { + if (virNetworkIsActive(net)) + return 1; + net = net->next; + } + + /* Otherwise we're happy to deal with a shutdown */ + return 0; +} + +/** + * networkShutdown: + * + * Shutdown the QEmu daemon, it will stop all active domains and networks + */ +static int +networkShutdown(void) { + virNetworkObjPtr network; + + if (!driverState) + return -1; + + /* shutdown active networks */ + network = driverState->networks; + while (network) { + virNetworkObjPtr next = network->next; + if (virNetworkIsActive(network)) + networkShutdownNetworkDaemon(NULL, driverState, network); + network = next; + } + + /* free inactive networks */ + network = driverState->networks; + while (network) { + virNetworkObjPtr next = network->next; + virNetworkObjFree(network); + network = next; + } + driverState->networks = NULL; + + VIR_FREE(driverState->logDir); + VIR_FREE(driverState->networkConfigDir); + VIR_FREE(driverState->networkAutostartDir); + + if (driverState->brctl) + brShutdown(driverState->brctl); + if (driverState->iptables) + iptablesContextFree(driverState->iptables); + + VIR_FREE(driverState); + + return 0; +} + + +static int +networkBuildDnsmasqArgv(virConnectPtr conn, + virNetworkObjPtr network, + const char ***argv) { + int i, len, r; + char buf[PATH_MAX]; + + len = + 1 + /* dnsmasq */ + 1 + /* --keep-in-foreground */ + 1 + /* --strict-order */ + 1 + /* --bind-interfaces */ + (network->def->domain?2:0) + /* --domain name */ + 2 + /* --pid-file "" */ + 2 + /* --conf-file "" */ + /*2 + *//* --interface virbr0 */ + 2 + /* --except-interface lo */ + 2 + /* --listen-address 10.0.0.1 */ + 1 + /* --dhcp-leasefile=path */ + (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */ + /* --dhcp-host 01:23:45:67:89:0a,hostname,10.0.0.3 */ + (2 * network->def->nhosts) + + 1; /* NULL */ + + if (VIR_ALLOC_N(*argv, len) < 0) + goto no_memory; + +#define APPEND_ARG(v, n, s) do { \ + if (!((v)[(n)] = strdup(s))) \ + goto no_memory; \ + } while (0) + + i = 0; + + APPEND_ARG(*argv, i++, DNSMASQ); + + APPEND_ARG(*argv, i++, "--keep-in-foreground"); + /* + * Needed to ensure dnsmasq uses same algorithm for processing + * multiple namedriver entries in /etc/resolv.conf as GLibC. + */ + APPEND_ARG(*argv, i++, "--strict-order"); + APPEND_ARG(*argv, i++, "--bind-interfaces"); + + if (network->def->domain) { + APPEND_ARG(*argv, i++, "--domain"); + APPEND_ARG(*argv, i++, network->def->domain); + } + + APPEND_ARG(*argv, i++, "--pid-file"); + APPEND_ARG(*argv, i++, ""); + + APPEND_ARG(*argv, i++, "--conf-file"); + APPEND_ARG(*argv, i++, ""); + + /* + * XXX does not actually work, due to some kind of + * race condition setting up ipv6 addresses on the + * interface. A sleep(10) makes it work, but that's + * clearly not practical + * + * APPEND_ARG(*argv, i++, "--interface"); + * APPEND_ARG(*argv, i++, network->def->bridge); + */ + APPEND_ARG(*argv, i++, "--listen-address"); + APPEND_ARG(*argv, i++, network->def->ipAddress); + + APPEND_ARG(*argv, i++, "--except-interface"); + APPEND_ARG(*argv, i++, "lo"); + + /* + * NB, dnsmasq command line arg bug means we need to + * use a single arg '--dhcp-leasefile=path' rather than + * two separate args in '--dhcp-leasefile path' style + */ + snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases", + LOCAL_STATE_DIR, network->def->name); + APPEND_ARG(*argv, i++, buf); + + for (r = 0 ; r < network->def->nranges ; r++) { + snprintf(buf, sizeof(buf), "%s,%s", + network->def->ranges[r].start, + network->def->ranges[r].end); + + APPEND_ARG(*argv, i++, "--dhcp-range"); + APPEND_ARG(*argv, i++, buf); + } + + for (r = 0 ; r < network->def->nhosts ; r++) { + virNetworkDHCPHostDefPtr host = &(network->def->hosts[r]); + if ((host->mac) && (host->name)) { + snprintf(buf, sizeof(buf), "%s,%s,%s", + host->mac, host->name, host->ip); + } else if (host->mac) { + snprintf(buf, sizeof(buf), "%s,%s", + host->mac, host->ip); + } else if (host->name) { + snprintf(buf, sizeof(buf), "%s,%s", + host->name, host->ip); + } else + continue; + + APPEND_ARG(*argv, i++, "--dhcp-host"); + APPEND_ARG(*argv, i++, buf); + } + +#undef APPEND_ARG + + return 0; + + no_memory: + if (argv) { + for (i = 0; (*argv)[i]; i++) + VIR_FREE((*argv)[i]); + VIR_FREE(*argv); + } + networkReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate space for dnsmasq argv")); + return -1; +} + + +static int +dhcpStartDhcpDaemon(virConnectPtr conn, + virNetworkObjPtr network) +{ + const char **argv; + int ret, i; + + if (network->def->ipAddress == NULL) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot start dhcp daemon without IP address for server")); + return -1; + } + + argv = NULL; + if (networkBuildDnsmasqArgv(conn, network, &argv) < 0) + return -1; + + ret = virExec(conn, argv, NULL, NULL, + &network->dnsmasqPid, -1, NULL, NULL, VIR_EXEC_NONBLOCK); + + for (i = 0; argv[i]; i++) + VIR_FREE(argv[i]); + VIR_FREE(argv); + + return ret; +} + +static int +networkAddMasqueradingIptablesRules(virConnectPtr conn, + struct network_driver *driver, + virNetworkObjPtr network) { + int err; + /* allow forwarding packets from the bridge interface */ + if ((err = iptablesAddForwardAllowOut(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow forwarding from '%s' : %s\n"), + network->def->bridge, strerror(err)); + goto masqerr1; + } + + /* allow forwarding packets to the bridge interface if they are part of an existing connection */ + if ((err = iptablesAddForwardAllowRelatedIn(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow forwarding to '%s' : %s\n"), + network->def->bridge, strerror(err)); + goto masqerr2; + } + + /* enable masquerading */ + if ((err = iptablesAddForwardMasquerade(driver->iptables, + network->def->network, + network->def->forwardDev))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to enable masquerading : %s\n"), + strerror(err)); + goto masqerr3; + } + + return 1; + + masqerr3: + iptablesRemoveForwardAllowRelatedIn(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev); + masqerr2: + iptablesRemoveForwardAllowOut(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev); + masqerr1: + return 0; +} + +static int +networkAddRoutingIptablesRules(virConnectPtr conn, + struct network_driver *driver, + virNetworkObjPtr network) { + int err; + /* allow routing packets from the bridge interface */ + if ((err = iptablesAddForwardAllowOut(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow routing from '%s' : %s\n"), + network->def->bridge, strerror(err)); + goto routeerr1; + } + + /* allow routing packets to the bridge interface */ + if ((err = iptablesAddForwardAllowIn(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow routing to '%s' : %s\n"), + network->def->bridge, strerror(err)); + goto routeerr2; + } + + return 1; + + + routeerr2: + iptablesRemoveForwardAllowOut(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev); + routeerr1: + return 0; +} + +static int +networkAddIptablesRules(virConnectPtr conn, + struct network_driver *driver, + virNetworkObjPtr network) { + int err; + + if (!driver->iptables && !(driver->iptables = iptablesContextNew())) { + networkReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate space for IP tables support")); + return 0; + } + + + /* allow DHCP requests through to dnsmasq */ + if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 67))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow DHCP requests from '%s' : %s"), + network->def->bridge, strerror(err)); + goto err1; + } + + if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 67))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow DHCP requests from '%s' : %s"), + network->def->bridge, strerror(err)); + goto err2; + } + + /* allow DNS requests through to dnsmasq */ + if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 53))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow DNS requests from '%s' : %s"), + network->def->bridge, strerror(err)); + goto err3; + } + + if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 53))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow DNS requests from '%s' : %s"), + network->def->bridge, strerror(err)); + goto err4; + } + + + /* Catch all rules to block forwarding to/from bridges */ + + if ((err = iptablesAddForwardRejectOut(driver->iptables, network->def->bridge))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to block outbound traffic from '%s' : %s"), + network->def->bridge, strerror(err)); + goto err5; + } + + if ((err = iptablesAddForwardRejectIn(driver->iptables, network->def->bridge))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to block inbound traffic to '%s' : %s"), + network->def->bridge, strerror(err)); + goto err6; + } + + /* Allow traffic between guests on the same bridge */ + if ((err = iptablesAddForwardAllowCross(driver->iptables, network->def->bridge))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to add iptables rule to allow cross bridge traffic on '%s' : %s"), + network->def->bridge, strerror(err)); + goto err7; + } + + + /* If masquerading is enabled, set up the rules*/ + if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT && + !networkAddMasqueradingIptablesRules(conn, driver, network)) + goto err8; + /* else if routing is enabled, set up the rules*/ + else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE && + !networkAddRoutingIptablesRules(conn, driver, network)) + goto err8; + + iptablesSaveRules(driver->iptables); + + return 1; + + err8: + iptablesRemoveForwardAllowCross(driver->iptables, + network->def->bridge); + err7: + iptablesRemoveForwardRejectIn(driver->iptables, + network->def->bridge); + err6: + iptablesRemoveForwardRejectOut(driver->iptables, + network->def->bridge); + err5: + iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53); + err4: + iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53); + err3: + iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67); + err2: + iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67); + err1: + return 0; +} + +static void +networkRemoveIptablesRules(struct network_driver *driver, + virNetworkObjPtr network) { + if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) { + iptablesRemoveForwardMasquerade(driver->iptables, + network->def->network, + network->def->forwardDev); + + if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) + iptablesRemoveForwardAllowRelatedIn(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev); + else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE) + iptablesRemoveForwardAllowIn(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev); + + iptablesRemoveForwardAllowOut(driver->iptables, + network->def->network, + network->def->bridge, + network->def->forwardDev); + } + iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge); + iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge); + iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge); + iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53); + iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53); + iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67); + iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67); + iptablesSaveRules(driver->iptables); +} + +static int +networkEnableIpForwarding(void) +{ +#define PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward" + + int fd, ret; + + if ((fd = open(PROC_IP_FORWARD, O_WRONLY|O_TRUNC)) == -1) + return 0; + + if (safewrite(fd, "1\n", 2) < 0) + ret = 0; + + close (fd); + + return 1; + +#undef PROC_IP_FORWARD +} + +static int networkStartNetworkDaemon(virConnectPtr conn, + struct network_driver *driver, + virNetworkObjPtr network) { + int err; + + if (virNetworkIsActive(network)) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("network is already active")); + return -1; + } + + if (!driver->brctl && (err = brInit(&driver->brctl))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot initialize bridge support: %s"), strerror(err)); + return -1; + } + + if ((err = brAddBridge(driver->brctl, &network->def->bridge))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot create bridge '%s' : %s"), + network->def->bridge, strerror(err)); + return -1; + } + + + if (brSetForwardDelay(driver->brctl, network->def->bridge, network->def->delay) < 0) + goto err_delbr; + + if (brSetEnableSTP(driver->brctl, network->def->bridge, network->def->stp ? 1 : 0) < 0) + goto err_delbr; + + if (network->def->ipAddress && + (err = brSetInetAddress(driver->brctl, network->def->bridge, network->def->ipAddress))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot set IP address on bridge '%s' to '%s' : %s"), + network->def->bridge, network->def->ipAddress, strerror(err)); + goto err_delbr; + } + + if (network->def->netmask && + (err = brSetInetNetmask(driver->brctl, network->def->bridge, network->def->netmask))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot set netmask on bridge '%s' to '%s' : %s"), + network->def->bridge, network->def->netmask, strerror(err)); + goto err_delbr; + } + + if (network->def->ipAddress && + (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to bring the bridge '%s' up : %s"), + network->def->bridge, strerror(err)); + goto err_delbr; + } + + if (!networkAddIptablesRules(conn, driver, network)) + goto err_delbr1; + + if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE && + !networkEnableIpForwarding()) { + networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to enable IP forwarding : %s"), strerror(err)); + goto err_delbr2; + } + + if (network->def->nranges && + dhcpStartDhcpDaemon(conn, network) < 0) + goto err_delbr2; + + network->active = 1; + + return 0; + + err_delbr2: + networkRemoveIptablesRules(driver, network); + + err_delbr1: + if (network->def->ipAddress && + (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) { + networkLog(NETWORK_WARN, _("Failed to bring down bridge '%s' : %s\n"), + network->def->bridge, strerror(err)); + } + + err_delbr: + if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) { + networkLog(NETWORK_WARN, _("Failed to delete bridge '%s' : %s\n"), + network->def->bridge, strerror(err)); + } + + return -1; +} + + +static int networkShutdownNetworkDaemon(virConnectPtr conn ATTRIBUTE_UNUSED, + struct network_driver *driver, + virNetworkObjPtr network) { + int err; + + networkLog(NETWORK_INFO, _("Shutting down network '%s'\n"), network->def->name); + + if (!virNetworkIsActive(network)) + return 0; + + if (network->dnsmasqPid > 0) + kill(network->dnsmasqPid, SIGTERM); + + networkRemoveIptablesRules(driver, network); + + if (network->def->ipAddress && + (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) { + networkLog(NETWORK_WARN, _("Failed to bring down bridge '%s' : %s\n"), + network->def->bridge, strerror(err)); + } + + if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) { + networkLog(NETWORK_WARN, _("Failed to delete bridge '%s' : %s\n"), + network->def->bridge, strerror(err)); + } + + if (network->dnsmasqPid > 0 && + waitpid(network->dnsmasqPid, NULL, WNOHANG) != network->dnsmasqPid) { + kill(network->dnsmasqPid, SIGKILL); + if (waitpid(network->dnsmasqPid, NULL, 0) != network->dnsmasqPid) + networkLog(NETWORK_WARN, + "%s", _("Got unexpected pid for dnsmasq\n")); + } + + network->dnsmasqPid = -1; + network->active = 0; + + if (network->newDef) { + virNetworkDefFree(network->def); + network->def = network->newDef; + network->newDef = NULL; + } + + if (!network->configFile) + virNetworkRemoveInactive(&driver->networks, + network); + + return 0; +} + + +static virNetworkPtr networkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, + const unsigned char *uuid) { + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, uuid); + virNetworkPtr net; + + if (!network) { + networkReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + return NULL; + } + + net = virGetNetwork(conn, network->def->name, network->def->uuid); + return net; +} +static virNetworkPtr networkLookupByName(virConnectPtr conn ATTRIBUTE_UNUSED, + const char *name) { + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByName(driver->networks, name); + virNetworkPtr net; + + if (!network) { + networkReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, + "%s", _("no network with matching name")); + return NULL; + } + + net = virGetNetwork(conn, network->def->name, network->def->uuid); + return net; +} + +static virDrvOpenStatus networkOpenNetwork(virConnectPtr conn, + xmlURIPtr uri ATTRIBUTE_UNUSED, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + if (!driverState) + return VIR_DRV_OPEN_DECLINED; + + conn->networkPrivateData = driverState; + return VIR_DRV_OPEN_SUCCESS; +} + +static int networkCloseNetwork(virConnectPtr conn) { + conn->networkPrivateData = NULL; + return 0; +} + +static int networkNumNetworks(virConnectPtr conn) { + int nactive = 0; + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkObjPtr net = driver->networks; + while (net) { + if (virNetworkIsActive(net)) + nactive++; + net = net->next; + } + return nactive; +} + +static int networkListNetworks(virConnectPtr conn, char **const names, int nnames) { + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkObjPtr network = driver->networks; + int got = 0, i; + while (network && got < nnames) { + if (virNetworkIsActive(network)) { + if (!(names[got] = strdup(network->def->name))) { + networkReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate space for VM name string")); + goto cleanup; + } + got++; + } + network = network->next; + } + return got; + + cleanup: + for (i = 0 ; i < got ; i++) + VIR_FREE(names[i]); + return -1; +} + +static int networkNumDefinedNetworks(virConnectPtr conn) { + int ninactive = 0; + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkObjPtr net = driver->networks; + while (net) { + if (!virNetworkIsActive(net)) + ninactive++; + net = net->next; + } + return ninactive; +} + +static int networkListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) { + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkObjPtr network = driver->networks; + int got = 0, i; + while (network && got < nnames) { + if (!virNetworkIsActive(network)) { + if (!(names[got] = strdup(network->def->name))) { + networkReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate space for VM name string")); + goto cleanup; + } + got++; + } + network = network->next; + } + return got; + + cleanup: + for (i = 0 ; i < got ; i++) + VIR_FREE(names[i]); + return -1; +} + +static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) { + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkDefPtr def; + virNetworkObjPtr network; + virNetworkPtr net; + + if (!(def = virNetworkDefParseString(conn, xml))) + return NULL; + + if (!(network = virNetworkAssignDef(conn, + &driver->networks, + def))) { + virNetworkDefFree(def); + return NULL; + } + + if (networkStartNetworkDaemon(conn, driver, network) < 0) { + virNetworkRemoveInactive(&driver->networks, + network); + return NULL; + } + + net = virGetNetwork(conn, network->def->name, network->def->uuid); + return net; +} + +static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) { + struct network_driver *driver = (struct network_driver *)conn->networkPrivateData; + virNetworkDefPtr def; + virNetworkObjPtr network; + + if (!(def = virNetworkDefParseString(conn, xml))) + return NULL; + + if (!(network = virNetworkAssignDef(conn, + &driver->networks, + def))) { + virNetworkDefFree(def); + return NULL; + } + + if (virNetworkSaveConfig(conn, + driver->networkConfigDir, + driver->networkAutostartDir, + network) < 0) { + virNetworkRemoveInactive(&driver->networks, + network); + return NULL; + } + + return virGetNetwork(conn, network->def->name, network->def->uuid); +} + +static int networkUndefine(virNetworkPtr net) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN, + "%s", _("no network with matching uuid")); + return -1; + } + + if (virNetworkIsActive(network)) { + networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, + "%s", _("network is still active")); + return -1; + } + + if (virNetworkDeleteConfig(net->conn, network) < 0) + return -1; + + virNetworkRemoveInactive(&driver->networks, + network); + + return 0; +} + +static int networkStart(virNetworkPtr net) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, + "%s", _("no network with matching uuid")); + return -1; + } + + return networkStartNetworkDaemon(net->conn, driver, network); +} + +static int networkDestroy(virNetworkPtr net) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + int ret; + + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, + "%s", _("no network with matching uuid")); + return -1; + } + + ret = networkShutdownNetworkDaemon(net->conn, driver, network); + + return ret; +} + +static char *networkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, + "%s", _("no network with matching uuid")); + return NULL; + } + + return virNetworkDefFormat(net->conn, network->def); +} + +static char *networkGetBridgeName(virNetworkPtr net) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + char *bridge; + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, + "%s", _("no network with matching id")); + return NULL; + } + + bridge = strdup(network->def->bridge); + if (!bridge) { + networkReportError(net->conn, NULL, net, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate space for network bridge string")); + return NULL; + } + return bridge; +} + +static int networkGetAutostart(virNetworkPtr net, + int *autostart) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, + "%s", _("no network with matching uuid")); + return -1; + } + + *autostart = network->autostart; + + return 0; +} + +static int networkSetAutostart(virNetworkPtr net, + int autostart) { + struct network_driver *driver = (struct network_driver *)net->conn->networkPrivateData; + virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); + + if (!network) { + networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, + "%s", _("no network with matching uuid")); + return -1; + } + + autostart = (autostart != 0); + + if (network->autostart == autostart) + return 0; + + if (autostart) { + int err; + + if ((err = virFileMakePath(driver->networkAutostartDir))) { + networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, + _("cannot create autostart directory %s: %s"), + driver->networkAutostartDir, strerror(err)); + return -1; + } + + if (symlink(network->configFile, network->autostartLink) < 0) { + networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, + _("Failed to create symlink '%s' to '%s': %s"), + network->autostartLink, network->configFile, strerror(errno)); + return -1; + } + } else { + if (unlink(network->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) { + networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, + _("Failed to delete symlink '%s': %s"), + network->autostartLink, strerror(errno)); + return -1; + } + } + + network->autostart = autostart; + + return 0; +} + + +static virNetworkDriver networkDriver = { + "Network", + networkOpenNetwork, /* open */ + networkCloseNetwork, /* close */ + networkNumNetworks, /* numOfNetworks */ + networkListNetworks, /* listNetworks */ + networkNumDefinedNetworks, /* numOfDefinedNetworks */ + networkListDefinedNetworks, /* listDefinedNetworks */ + networkLookupByUUID, /* networkLookupByUUID */ + networkLookupByName, /* networkLookupByName */ + networkCreate, /* networkCreateXML */ + networkDefine, /* networkDefineXML */ + networkUndefine, /* networkUndefine */ + networkStart, /* networkCreate */ + networkDestroy, /* networkDestroy */ + networkDumpXML, /* networkDumpXML */ + networkGetBridgeName, /* networkGetBridgeName */ + networkGetAutostart, /* networkGetAutostart */ + networkSetAutostart, /* networkSetAutostart */ +}; + +static virStateDriver networkStateDriver = { + networkStartup, + networkShutdown, + networkReload, + networkActive, + NULL +}; + +int networkRegister(void) { + virRegisterNetworkDriver(&networkDriver); + virRegisterStateDriver(&networkStateDriver); + return 0; +} + diff -r f68f3fd13e9d src/network_driver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/network_driver.h Fri Oct 03 10:46:41 2008 +0100 @@ -0,0 +1,34 @@ +/* + * network_driver.h: core driver methods for managing networks + * + * Copyright (C) 2006, 2007 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + + +#ifndef __VIR_NETWORK__DRIVER_H +#define __VIR_NETWORK__DRIVER_H + +#include <config.h> + +#include "internal.h" + +int networkRegister(void); + +#endif /* __VIR_NETWORK__DRIVER_H */ diff -r f68f3fd13e9d src/qemu_conf.c --- a/src/qemu_conf.c Fri Oct 03 00:07:33 2008 +0100 +++ b/src/qemu_conf.c Fri Oct 03 10:46:41 2008 +0100 @@ -537,7 +537,6 @@ virDomainNetDefPtr net, int vlan) { - virNetworkObjPtr network = NULL; char *brname; char tapfdstr[4+3+32+7]; char *retval = NULL; @@ -545,18 +544,24 @@ int tapfd = -1; if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { - if (!(network = virNetworkFindByName(driver->networks, net->data.network.name))) { + virNetworkPtr network = virNetworkLookupByName(conn, + net->data.network.name); + if (!network) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Network '%s' not found"), net->data.network.name); goto error; - } else if (network->def->bridge == NULL) { + } + brname = virNetworkGetBridgeName(network); + + virNetworkFree(network); + + if (brname == NULL) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Network '%s' not active"), + _("Network '%s' is not active"), net->data.network.name); goto error; } - brname = network->def->bridge; } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { brname = net->data.bridge.brname; } else { diff -r f68f3fd13e9d src/qemu_conf.h --- a/src/qemu_conf.h Fri Oct 03 00:07:33 2008 +0100 +++ b/src/qemu_conf.h Fri Oct 03 10:46:41 2008 +0100 @@ -27,7 +27,6 @@ #include <config.h> #include "internal.h" -#include "iptables.h" #include "bridge.h" #include "capabilities.h" #include "network_conf.h" @@ -53,14 +52,10 @@ int nextvmid; virDomainObjPtr domains; - virNetworkObjPtr networks; brControl *brctl; - iptablesContext *iptables; char *configDir; char *autostartDir; - char *networkConfigDir; - char *networkAutostartDir; char *logDir; unsigned int vncTLS : 1; unsigned int vncTLSx509verify : 1; diff -r f68f3fd13e9d src/qemu_driver.c --- a/src/qemu_driver.c Fri Oct 03 00:07:33 2008 +0100 +++ b/src/qemu_driver.c Fri Oct 03 10:46:41 2008 +0100 @@ -68,9 +68,7 @@ /* For storing short-lived temporary files. */ #define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt" -#ifdef WITH_LIBVIRTD static int qemudShutdown(void); -#endif /* qemudDebug statements should be changed to use this macro instead. */ #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__) @@ -118,13 +116,6 @@ struct qemud_driver *driver, virDomainObjPtr vm); -static int qemudStartNetworkDaemon(virConnectPtr conn, - struct qemud_driver *driver, - virNetworkObjPtr network); - -static int qemudShutdownNetworkDaemon(virConnectPtr conn, - struct qemud_driver *driver, - virNetworkObjPtr network); static int qemudDomainGetMaxVcpus(virDomainPtr dom); static int qemudMonitorCommand (const struct qemud_driver *driver, @@ -137,23 +128,7 @@ static void qemudAutostartConfigs(struct qemud_driver *driver) { - virNetworkObjPtr network; virDomainObjPtr vm; - - network = driver->networks; - while (network != NULL) { - virNetworkObjPtr next = network->next; - - if (network->autostart && - !virNetworkIsActive(network) && - qemudStartNetworkDaemon(NULL, driver, network) < 0) { - virErrorPtr err = virGetLastError(); - qemudLog(QEMUD_ERR, _("Failed to autostart network '%s': %s\n"), - network->def->name, err->message); - } - - network = next; - } vm = driver->domains; while (vm != NULL) { @@ -171,7 +146,6 @@ } } -#ifdef WITH_LIBVIRTD /** * qemudStartup: * @@ -228,13 +202,6 @@ if (asprintf (&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1) goto out_of_memory; - if (asprintf (&qemu_driver->networkConfigDir, "%s/qemu/networks", base) == -1) - goto out_of_memory; - - if (asprintf (&qemu_driver->networkAutostartDir, "%s/qemu/networks/autostart", - base) == -1) - goto out_of_memory; - VIR_FREE(base); if ((qemu_driver->caps = qemudCapsInit()) == NULL) @@ -250,13 +217,6 @@ &qemu_driver->domains, qemu_driver->configDir, qemu_driver->autostartDir) < 0) { - qemudShutdown(); - return -1; - } - if (virNetworkLoadAllConfigs(NULL, - &qemu_driver->networks, - qemu_driver->networkConfigDir, - qemu_driver->networkAutostartDir) < 0) { qemudShutdown(); return -1; } @@ -286,17 +246,6 @@ qemu_driver->configDir, qemu_driver->autostartDir); - virNetworkLoadAllConfigs(NULL, - &qemu_driver->networks, - qemu_driver->networkConfigDir, - qemu_driver->networkAutostartDir); - - if (qemu_driver->iptables) { - qemudLog(QEMUD_INFO, - "%s", _("Reloading iptables rules\n")); - iptablesReloadRules(qemu_driver->iptables); - } - qemudAutostartConfigs(qemu_driver); return 0; @@ -313,18 +262,11 @@ static int qemudActive(void) { virDomainObjPtr dom = qemu_driver->domains; - virNetworkObjPtr net = qemu_driver->networks; while (dom) { if (virDomainIsActive(dom)) return 1; dom = dom->next; - } - - while (net) { - if (virNetworkIsActive(net)) - return 1; - net = net->next; } /* Otherwise we're happy to deal with a shutdown */ @@ -339,7 +281,6 @@ static int qemudShutdown(void) { virDomainObjPtr vm; - virNetworkObjPtr network; if (!qemu_driver) return -1; @@ -367,41 +308,18 @@ } qemu_driver->domains = NULL; - /* shutdown active networks */ - network = qemu_driver->networks; - while (network) { - virNetworkObjPtr next = network->next; - if (virNetworkIsActive(network)) - qemudShutdownNetworkDaemon(NULL, qemu_driver, network); - network = next; - } - - /* free inactive networks */ - network = qemu_driver->networks; - while (network) { - virNetworkObjPtr next = network->next; - virNetworkObjFree(network); - network = next; - } - qemu_driver->networks = NULL; - VIR_FREE(qemu_driver->logDir); VIR_FREE(qemu_driver->configDir); VIR_FREE(qemu_driver->autostartDir); - VIR_FREE(qemu_driver->networkConfigDir); - VIR_FREE(qemu_driver->networkAutostartDir); VIR_FREE(qemu_driver->vncTLSx509certdir); if (qemu_driver->brctl) brShutdown(qemu_driver->brctl); - if (qemu_driver->iptables) - iptablesContextFree(qemu_driver->iptables); VIR_FREE(qemu_driver); return 0; } -#endif /* Return -1 for error, 1 to continue reading and 0 for success */ typedef int qemudHandlerMonitorOutput(virConnectPtr conn, @@ -1112,547 +1030,6 @@ if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - return 0; -} - -static int -qemudBuildDnsmasqArgv(virConnectPtr conn, - virNetworkObjPtr network, - const char ***argv) { - int i, len, r; - char buf[PATH_MAX]; - - len = - 1 + /* dnsmasq */ - 1 + /* --keep-in-foreground */ - 1 + /* --strict-order */ - 1 + /* --bind-interfaces */ - (network->def->domain?2:0) + /* --domain name */ - 2 + /* --pid-file "" */ - 2 + /* --conf-file "" */ - /*2 + *//* --interface virbr0 */ - 2 + /* --except-interface lo */ - 2 + /* --listen-address 10.0.0.1 */ - 1 + /* --dhcp-leasefile=path */ - (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */ - /* --dhcp-host 01:23:45:67:89:0a,hostname,10.0.0.3 */ - (2 * network->def->nhosts) + - 1; /* NULL */ - - if (VIR_ALLOC_N(*argv, len) < 0) - goto no_memory; - -#define APPEND_ARG(v, n, s) do { \ - if (!((v)[(n)] = strdup(s))) \ - goto no_memory; \ - } while (0) - - i = 0; - - APPEND_ARG(*argv, i++, DNSMASQ); - - APPEND_ARG(*argv, i++, "--keep-in-foreground"); - /* - * Needed to ensure dnsmasq uses same algorithm for processing - * multiple namedriver entries in /etc/resolv.conf as GLibC. - */ - APPEND_ARG(*argv, i++, "--strict-order"); - APPEND_ARG(*argv, i++, "--bind-interfaces"); - - if (network->def->domain) { - APPEND_ARG(*argv, i++, "--domain"); - APPEND_ARG(*argv, i++, network->def->domain); - } - - APPEND_ARG(*argv, i++, "--pid-file"); - APPEND_ARG(*argv, i++, ""); - - APPEND_ARG(*argv, i++, "--conf-file"); - APPEND_ARG(*argv, i++, ""); - - /* - * XXX does not actually work, due to some kind of - * race condition setting up ipv6 addresses on the - * interface. A sleep(10) makes it work, but that's - * clearly not practical - * - * APPEND_ARG(*argv, i++, "--interface"); - * APPEND_ARG(*argv, i++, network->def->bridge); - */ - APPEND_ARG(*argv, i++, "--listen-address"); - APPEND_ARG(*argv, i++, network->def->ipAddress); - - APPEND_ARG(*argv, i++, "--except-interface"); - APPEND_ARG(*argv, i++, "lo"); - - /* - * NB, dnsmasq command line arg bug means we need to - * use a single arg '--dhcp-leasefile=path' rather than - * two separate args in '--dhcp-leasefile path' style - */ - snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases", - LOCAL_STATE_DIR, network->def->name); - APPEND_ARG(*argv, i++, buf); - - for (r = 0 ; r < network->def->nranges ; r++) { - snprintf(buf, sizeof(buf), "%s,%s", - network->def->ranges[r].start, - network->def->ranges[r].end); - - APPEND_ARG(*argv, i++, "--dhcp-range"); - APPEND_ARG(*argv, i++, buf); - } - - for (r = 0 ; r < network->def->nhosts ; r++) { - virNetworkDHCPHostDefPtr host = &(network->def->hosts[r]); - if ((host->mac) && (host->name)) { - snprintf(buf, sizeof(buf), "%s,%s,%s", - host->mac, host->name, host->ip); - } else if (host->mac) { - snprintf(buf, sizeof(buf), "%s,%s", - host->mac, host->ip); - } else if (host->name) { - snprintf(buf, sizeof(buf), "%s,%s", - host->name, host->ip); - } else - continue; - - APPEND_ARG(*argv, i++, "--dhcp-host"); - APPEND_ARG(*argv, i++, buf); - } - -#undef APPEND_ARG - - return 0; - - no_memory: - if (argv) { - for (i = 0; (*argv)[i]; i++) - VIR_FREE((*argv)[i]); - VIR_FREE(*argv); - } - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for dnsmasq argv")); - return -1; -} - - -static int -dhcpStartDhcpDaemon(virConnectPtr conn, - virNetworkObjPtr network) -{ - const char **argv; - int ret, i; - - if (network->def->ipAddress == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot start dhcp daemon without IP address for server")); - return -1; - } - - argv = NULL; - if (qemudBuildDnsmasqArgv(conn, network, &argv) < 0) - return -1; - - ret = virExec(conn, argv, NULL, NULL, - &network->dnsmasqPid, -1, NULL, NULL, VIR_EXEC_NONBLOCK); - - for (i = 0; argv[i]; i++) - VIR_FREE(argv[i]); - VIR_FREE(argv); - - return ret; -} - -static int -qemudAddMasqueradingIptablesRules(virConnectPtr conn, - struct qemud_driver *driver, - virNetworkObjPtr network) { - int err; - /* allow forwarding packets from the bridge interface */ - if ((err = iptablesAddForwardAllowOut(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow forwarding from '%s' : %s\n"), - network->def->bridge, strerror(err)); - goto masqerr1; - } - - /* allow forwarding packets to the bridge interface if they are part of an existing connection */ - if ((err = iptablesAddForwardAllowRelatedIn(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow forwarding to '%s' : %s\n"), - network->def->bridge, strerror(err)); - goto masqerr2; - } - - /* enable masquerading */ - if ((err = iptablesAddForwardMasquerade(driver->iptables, - network->def->network, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to enable masquerading : %s\n"), - strerror(err)); - goto masqerr3; - } - - return 1; - - masqerr3: - iptablesRemoveForwardAllowRelatedIn(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev); - masqerr2: - iptablesRemoveForwardAllowOut(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev); - masqerr1: - return 0; -} - -static int -qemudAddRoutingIptablesRules(virConnectPtr conn, - struct qemud_driver *driver, - virNetworkObjPtr network) { - int err; - /* allow routing packets from the bridge interface */ - if ((err = iptablesAddForwardAllowOut(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow routing from '%s' : %s\n"), - network->def->bridge, strerror(err)); - goto routeerr1; - } - - /* allow routing packets to the bridge interface */ - if ((err = iptablesAddForwardAllowIn(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow routing to '%s' : %s\n"), - network->def->bridge, strerror(err)); - goto routeerr2; - } - - return 1; - - - routeerr2: - iptablesRemoveForwardAllowOut(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev); - routeerr1: - return 0; -} - -static int -qemudAddIptablesRules(virConnectPtr conn, - struct qemud_driver *driver, - virNetworkObjPtr network) { - int err; - - if (!driver->iptables && !(driver->iptables = iptablesContextNew())) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for IP tables support")); - return 0; - } - - - /* allow DHCP requests through to dnsmasq */ - if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 67))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow DHCP requests from '%s' : %s"), - network->def->bridge, strerror(err)); - goto err1; - } - - if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 67))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow DHCP requests from '%s' : %s"), - network->def->bridge, strerror(err)); - goto err2; - } - - /* allow DNS requests through to dnsmasq */ - if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 53))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow DNS requests from '%s' : %s"), - network->def->bridge, strerror(err)); - goto err3; - } - - if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 53))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow DNS requests from '%s' : %s"), - network->def->bridge, strerror(err)); - goto err4; - } - - - /* Catch all rules to block forwarding to/from bridges */ - - if ((err = iptablesAddForwardRejectOut(driver->iptables, network->def->bridge))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to block outbound traffic from '%s' : %s"), - network->def->bridge, strerror(err)); - goto err5; - } - - if ((err = iptablesAddForwardRejectIn(driver->iptables, network->def->bridge))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to block inbound traffic to '%s' : %s"), - network->def->bridge, strerror(err)); - goto err6; - } - - /* Allow traffic between guests on the same bridge */ - if ((err = iptablesAddForwardAllowCross(driver->iptables, network->def->bridge))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to add iptables rule to allow cross bridge traffic on '%s' : %s"), - network->def->bridge, strerror(err)); - goto err7; - } - - - /* If masquerading is enabled, set up the rules*/ - if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT && - !qemudAddMasqueradingIptablesRules(conn, driver, network)) - goto err8; - /* else if routing is enabled, set up the rules*/ - else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE && - !qemudAddRoutingIptablesRules(conn, driver, network)) - goto err8; - - iptablesSaveRules(driver->iptables); - - return 1; - - err8: - iptablesRemoveForwardAllowCross(driver->iptables, - network->def->bridge); - err7: - iptablesRemoveForwardRejectIn(driver->iptables, - network->def->bridge); - err6: - iptablesRemoveForwardRejectOut(driver->iptables, - network->def->bridge); - err5: - iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53); - err4: - iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53); - err3: - iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67); - err2: - iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67); - err1: - return 0; -} - -static void -qemudRemoveIptablesRules(struct qemud_driver *driver, - virNetworkObjPtr network) { - if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) { - iptablesRemoveForwardMasquerade(driver->iptables, - network->def->network, - network->def->forwardDev); - - if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) - iptablesRemoveForwardAllowRelatedIn(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev); - else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE) - iptablesRemoveForwardAllowIn(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev); - - iptablesRemoveForwardAllowOut(driver->iptables, - network->def->network, - network->def->bridge, - network->def->forwardDev); - } - iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge); - iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge); - iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge); - iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53); - iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53); - iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67); - iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67); - iptablesSaveRules(driver->iptables); -} - -static int -qemudEnableIpForwarding(void) -{ -#define PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward" - - int fd, ret; - - if ((fd = open(PROC_IP_FORWARD, O_WRONLY|O_TRUNC)) == -1) - return 0; - - if (safewrite(fd, "1\n", 2) < 0) - ret = 0; - - close (fd); - - return 1; - -#undef PROC_IP_FORWARD -} - -static int qemudStartNetworkDaemon(virConnectPtr conn, - struct qemud_driver *driver, - virNetworkObjPtr network) { - int err; - - if (virNetworkIsActive(network)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("network is already active")); - return -1; - } - - if (!driver->brctl && (err = brInit(&driver->brctl))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot initialize bridge support: %s"), strerror(err)); - return -1; - } - - if ((err = brAddBridge(driver->brctl, &network->def->bridge))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot create bridge '%s' : %s"), - network->def->bridge, strerror(err)); - return -1; - } - - - if (brSetForwardDelay(driver->brctl, network->def->bridge, network->def->delay) < 0) - goto err_delbr; - - if (brSetEnableSTP(driver->brctl, network->def->bridge, network->def->stp ? 1 : 0) < 0) - goto err_delbr; - - if (network->def->ipAddress && - (err = brSetInetAddress(driver->brctl, network->def->bridge, network->def->ipAddress))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot set IP address on bridge '%s' to '%s' : %s"), - network->def->bridge, network->def->ipAddress, strerror(err)); - goto err_delbr; - } - - if (network->def->netmask && - (err = brSetInetNetmask(driver->brctl, network->def->bridge, network->def->netmask))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot set netmask on bridge '%s' to '%s' : %s"), - network->def->bridge, network->def->netmask, strerror(err)); - goto err_delbr; - } - - if (network->def->ipAddress && - (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to bring the bridge '%s' up : %s"), - network->def->bridge, strerror(err)); - goto err_delbr; - } - - if (!qemudAddIptablesRules(conn, driver, network)) - goto err_delbr1; - - if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE && - !qemudEnableIpForwarding()) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to enable IP forwarding : %s"), strerror(err)); - goto err_delbr2; - } - - if (network->def->nranges && - dhcpStartDhcpDaemon(conn, network) < 0) - goto err_delbr2; - - network->active = 1; - - return 0; - - err_delbr2: - qemudRemoveIptablesRules(driver, network); - - err_delbr1: - if (network->def->ipAddress && - (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) { - qemudLog(QEMUD_WARN, _("Failed to bring down bridge '%s' : %s\n"), - network->def->bridge, strerror(err)); - } - - err_delbr: - if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) { - qemudLog(QEMUD_WARN, _("Failed to delete bridge '%s' : %s\n"), - network->def->bridge, strerror(err)); - } - - return -1; -} - - -static int qemudShutdownNetworkDaemon(virConnectPtr conn ATTRIBUTE_UNUSED, - struct qemud_driver *driver, - virNetworkObjPtr network) { - int err; - - qemudLog(QEMUD_INFO, _("Shutting down network '%s'\n"), network->def->name); - - if (!virNetworkIsActive(network)) - return 0; - - if (network->dnsmasqPid > 0) - kill(network->dnsmasqPid, SIGTERM); - - qemudRemoveIptablesRules(driver, network); - - if (network->def->ipAddress && - (err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) { - qemudLog(QEMUD_WARN, _("Failed to bring down bridge '%s' : %s\n"), - network->def->bridge, strerror(err)); - } - - if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) { - qemudLog(QEMUD_WARN, _("Failed to delete bridge '%s' : %s\n"), - network->def->bridge, strerror(err)); - } - - if (network->dnsmasqPid > 0 && - waitpid(network->dnsmasqPid, NULL, WNOHANG) != network->dnsmasqPid) { - kill(network->dnsmasqPid, SIGKILL); - if (waitpid(network->dnsmasqPid, NULL, 0) != network->dnsmasqPid) - qemudLog(QEMUD_WARN, - "%s", _("Got unexpected pid for dnsmasq\n")); - } - - network->dnsmasqPid = -1; - network->active = 0; - - if (network->newDef) { - virNetworkDefFree(network->def); - network->def = network->newDef; - network->newDef = NULL; - } - - if (!network->configFile) - virNetworkRemoveInactive(&driver->networks, - network); - return 0; } @@ -3706,323 +3083,6 @@ return ret; } -static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, - const unsigned char *uuid) { - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, uuid); - virNetworkPtr net; - - if (!network) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, - "%s", _("no network with matching uuid")); - return NULL; - } - - net = virGetNetwork(conn, network->def->name, network->def->uuid); - return net; -} -static virNetworkPtr qemudNetworkLookupByName(virConnectPtr conn ATTRIBUTE_UNUSED, - const char *name) { - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByName(driver->networks, name); - virNetworkPtr net; - - if (!network) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, - "%s", _("no network with matching name")); - return NULL; - } - - net = virGetNetwork(conn, network->def->name, network->def->uuid); - return net; -} - -static virDrvOpenStatus qemudOpenNetwork(virConnectPtr conn, - xmlURIPtr uri ATTRIBUTE_UNUSED, - virConnectAuthPtr auth ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED) { - if (!qemu_driver) - return VIR_DRV_OPEN_DECLINED; - - conn->networkPrivateData = qemu_driver; - return VIR_DRV_OPEN_SUCCESS; -} - -static int qemudCloseNetwork(virConnectPtr conn) { - conn->networkPrivateData = NULL; - return 0; -} - -static int qemudNumNetworks(virConnectPtr conn) { - int nactive = 0; - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkObjPtr net = driver->networks; - while (net) { - if (virNetworkIsActive(net)) - nactive++; - net = net->next; - } - return nactive; -} - -static int qemudListNetworks(virConnectPtr conn, char **const names, int nnames) { - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkObjPtr network = driver->networks; - int got = 0, i; - while (network && got < nnames) { - if (virNetworkIsActive(network)) { - if (!(names[got] = strdup(network->def->name))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for VM name string")); - goto cleanup; - } - got++; - } - network = network->next; - } - return got; - - cleanup: - for (i = 0 ; i < got ; i++) - VIR_FREE(names[i]); - return -1; -} - -static int qemudNumDefinedNetworks(virConnectPtr conn) { - int ninactive = 0; - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkObjPtr net = driver->networks; - while (net) { - if (!virNetworkIsActive(net)) - ninactive++; - net = net->next; - } - return ninactive; -} - -static int qemudListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) { - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkObjPtr network = driver->networks; - int got = 0, i; - while (network && got < nnames) { - if (!virNetworkIsActive(network)) { - if (!(names[got] = strdup(network->def->name))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for VM name string")); - goto cleanup; - } - got++; - } - network = network->next; - } - return got; - - cleanup: - for (i = 0 ; i < got ; i++) - VIR_FREE(names[i]); - return -1; -} - -static virNetworkPtr qemudNetworkCreate(virConnectPtr conn, const char *xml) { - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkDefPtr def; - virNetworkObjPtr network; - virNetworkPtr net; - - if (!(def = virNetworkDefParseString(conn, xml))) - return NULL; - - if (!(network = virNetworkAssignDef(conn, - &driver->networks, - def))) { - virNetworkDefFree(def); - return NULL; - } - - if (qemudStartNetworkDaemon(conn, driver, network) < 0) { - virNetworkRemoveInactive(&driver->networks, - network); - return NULL; - } - - net = virGetNetwork(conn, network->def->name, network->def->uuid); - return net; -} - -static virNetworkPtr qemudNetworkDefine(virConnectPtr conn, const char *xml) { - struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; - virNetworkDefPtr def; - virNetworkObjPtr network; - - if (!(def = virNetworkDefParseString(conn, xml))) - return NULL; - - if (!(network = virNetworkAssignDef(conn, - &driver->networks, - def))) { - virNetworkDefFree(def); - return NULL; - } - - if (virNetworkSaveConfig(conn, - driver->networkConfigDir, - driver->networkAutostartDir, - network) < 0) { - virNetworkRemoveInactive(&driver->networks, - network); - return NULL; - } - - return virGetNetwork(conn, network->def->name, network->def->uuid); -} - -static int qemudNetworkUndefine(virNetworkPtr net) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN, - "%s", _("no network with matching uuid")); - return -1; - } - - if (virNetworkIsActive(network)) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, - "%s", _("network is still active")); - return -1; - } - - if (virNetworkDeleteConfig(net->conn, network) < 0) - return -1; - - virNetworkRemoveInactive(&driver->networks, - network); - - return 0; -} - -static int qemudNetworkStart(virNetworkPtr net) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, - "%s", _("no network with matching uuid")); - return -1; - } - - return qemudStartNetworkDaemon(net->conn, driver, network); -} - -static int qemudNetworkDestroy(virNetworkPtr net) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - int ret; - - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, - "%s", _("no network with matching uuid")); - return -1; - } - - ret = qemudShutdownNetworkDaemon(net->conn, driver, network); - - return ret; -} - -static char *qemudNetworkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, - "%s", _("no network with matching uuid")); - return NULL; - } - - return virNetworkDefFormat(net->conn, network->def); -} - -static char *qemudNetworkGetBridgeName(virNetworkPtr net) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - char *bridge; - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, - "%s", _("no network with matching id")); - return NULL; - } - - bridge = strdup(network->def->bridge); - if (!bridge) { - qemudReportError(net->conn, NULL, net, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for network bridge string")); - return NULL; - } - return bridge; -} - -static int qemudNetworkGetAutostart(virNetworkPtr net, - int *autostart) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, - "%s", _("no network with matching uuid")); - return -1; - } - - *autostart = network->autostart; - - return 0; -} - -static int qemudNetworkSetAutostart(virNetworkPtr net, - int autostart) { - struct qemud_driver *driver = (struct qemud_driver *)net->conn->networkPrivateData; - virNetworkObjPtr network = virNetworkFindByUUID(driver->networks, net->uuid); - - if (!network) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK, - "%s", _("no network with matching uuid")); - return -1; - } - - autostart = (autostart != 0); - - if (network->autostart == autostart) - return 0; - - if (autostart) { - int err; - - if ((err = virFileMakePath(driver->networkAutostartDir))) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, - _("cannot create autostart directory %s: %s"), - driver->networkAutostartDir, strerror(err)); - return -1; - } - - if (symlink(network->configFile, network->autostartLink) < 0) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, - _("Failed to create symlink '%s' to '%s': %s"), - network->autostartLink, network->configFile, strerror(errno)); - return -1; - } - } else { - if (unlink(network->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) { - qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, - _("Failed to delete symlink '%s': %s"), - network->autostartLink, strerror(errno)); - return -1; - } - } - - network->autostart = autostart; - - return 0; -} static virDriver qemuDriver = { VIR_DRV_QEMU, @@ -4096,28 +3156,7 @@ #endif }; -static virNetworkDriver qemuNetworkDriver = { - "QEMU", - qemudOpenNetwork, /* open */ - qemudCloseNetwork, /* close */ - qemudNumNetworks, /* numOfNetworks */ - qemudListNetworks, /* listNetworks */ - qemudNumDefinedNetworks, /* numOfDefinedNetworks */ - qemudListDefinedNetworks, /* listDefinedNetworks */ - qemudNetworkLookupByUUID, /* networkLookupByUUID */ - qemudNetworkLookupByName, /* networkLookupByName */ - qemudNetworkCreate, /* networkCreateXML */ - qemudNetworkDefine, /* networkDefineXML */ - qemudNetworkUndefine, /* networkUndefine */ - qemudNetworkStart, /* networkCreate */ - qemudNetworkDestroy, /* networkDestroy */ - qemudNetworkDumpXML, /* networkDumpXML */ - qemudNetworkGetBridgeName, /* networkGetBridgeName */ - qemudNetworkGetAutostart, /* networkGetAutostart */ - qemudNetworkSetAutostart, /* networkSetAutostart */ -}; -#ifdef WITH_LIBVIRTD static virStateDriver qemuStateDriver = { qemudStartup, qemudShutdown, @@ -4125,14 +3164,10 @@ qemudActive, NULL }; -#endif int qemudRegister(void) { virRegisterDriver(&qemuDriver); - virRegisterNetworkDriver(&qemuNetworkDriver); -#ifdef WITH_LIBVIRTD virRegisterStateDriver(&qemuStateDriver); -#endif return 0; } -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list