diff --git a/ChangeLog b/ChangeLog index c30b530b8d..c7f128017c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Fri Oct 10 14:56:00 BST 2008 Daniel P. Berrange + + * configure.in: option to enable/disable network driver + * src/Makefile.am: Add network_driver.c/.h files + * src/libvirt.c: Import network_driver.h file + * src/qemu_conf.c, src/qemu-conf.h, src/qemu_driver.c: Remove + all network driver support + * src/network_driver.c, src/network_driver.h: Add standalone + network driver + Fri Oct 10 13:30:00 BST 2008 Daniel P. Berrange * src/xml.c, src/xen_internal.c: Cast some args to unsigned diff --git a/configure.in b/configure.in index 0843f9534c..51bc022238 100644 --- a/configure.in +++ b/configure.in @@ -643,6 +643,17 @@ AC_SUBST([WITH_XEN]) 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([ OpenVZ: $with_openvz]) 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 --git a/src/Makefile.am b/src/Makefile.am index 9a00e36173..7d52b54bc7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,11 +104,12 @@ OPENVZ_DRIVER_SOURCES = \ 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 = \ @@ -165,9 +166,11 @@ if WITH_OPENVZ 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) @@ -200,6 +203,7 @@ EXTRA_DIST += \ $(QEMU_DRIVER_SOURCES) \ $(LXC_DRIVER_SOURCES) \ $(OPENVZ_DRIVER_SOURCES) \ + $(NETWORK_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ diff --git a/src/libvirt.c b/src/libvirt.c index 10b577d560..fd6422d682 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -57,6 +57,9 @@ #include "lxc_driver.h" #endif #include "storage_driver.h" +#ifdef WITH_NETWORK +#include "network_driver.h" +#endif /* * TODO: @@ -292,6 +295,9 @@ virInitialize(void) #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 --git a/src/network_driver.c b/src/network_driver.c new file mode 100644 index 0000000000..72860b1d26 --- /dev/null +++ b/src/network_driver.c @@ -0,0 +1,1168 @@ +/* + * 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 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 networkLog(level, msg...) fprintf(stderr, msg) + +#define networkReportError(conn, dom, net, code, fmt...) \ + __virReportErrorHelper(conn, VIR_FROM_QEMU, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + + +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 --git a/src/network_driver.h b/src/network_driver.h new file mode 100644 index 0000000000..5951833ad1 --- /dev/null +++ b/src/network_driver.h @@ -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 + */ + + +#ifndef __VIR_NETWORK__DRIVER_H +#define __VIR_NETWORK__DRIVER_H + +#include + +#include "internal.h" + +int networkRegister(void); + +#endif /* __VIR_NETWORK__DRIVER_H */ diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 4c01f5c7e4..fdd7256838 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -516,7 +516,6 @@ qemudNetworkIfaceConnect(virConnectPtr conn, virDomainNetDefPtr net, int vlan) { - virNetworkObjPtr network = NULL; char *brname; char tapfdstr[4+3+32+7]; char *retval = NULL; @@ -524,18 +523,24 @@ qemudNetworkIfaceConnect(virConnectPtr conn, 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 --git a/src/qemu_conf.h b/src/qemu_conf.h index 5ea57f039b..e77a871f49 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -27,7 +27,6 @@ #include #include "internal.h" -#include "iptables.h" #include "bridge.h" #include "capabilities.h" #include "network_conf.h" @@ -53,14 +52,10 @@ struct qemud_driver { 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 --git a/src/qemu_driver.c b/src/qemu_driver.c index 0a0efb6bbf..ea5e3bf344 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -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 @@ static void qemudShutdownVMDaemon(virConnectPtr conn, 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,24 +128,8 @@ static struct qemud_driver *qemu_driver = NULL; 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) { virDomainObjPtr next = vm->next; @@ -171,7 +146,6 @@ void qemudAutostartConfigs(struct qemud_driver *driver) { } } -#ifdef WITH_LIBVIRTD /** * qemudStartup: * @@ -225,13 +199,6 @@ qemudStartup(void) { 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 @@ qemudStartup(void) { qemudShutdown(); return -1; } - if (virNetworkLoadAllConfigs(NULL, - &qemu_driver->networks, - qemu_driver->networkConfigDir, - qemu_driver->networkAutostartDir) < 0) { - qemudShutdown(); - return -1; - } qemudAutostartConfigs(qemu_driver); return 0; @@ -284,17 +244,6 @@ qemudReload(void) { 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; @@ -311,7 +260,6 @@ qemudReload(void) { static int qemudActive(void) { virDomainObjPtr dom = qemu_driver->domains; - virNetworkObjPtr net = qemu_driver->networks; while (dom) { if (virDomainIsActive(dom)) @@ -319,12 +267,6 @@ qemudActive(void) { dom = dom->next; } - while (net) { - if (virNetworkIsActive(net)) - return 1; - net = net->next; - } - /* Otherwise we're happy to deal with a shutdown */ return 0; } @@ -337,7 +279,6 @@ qemudActive(void) { static int qemudShutdown(void) { virDomainObjPtr vm; - virNetworkObjPtr network; if (!qemu_driver) return -1; @@ -365,41 +306,18 @@ qemudShutdown(void) { } 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, @@ -1098,547 +1016,6 @@ static int qemudDispatchVMFailure(struct qemud_driver *driver, virDomainObjPtr v 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; -} - static void qemudDispatchVMEvent(int fd, int events, void *opaque) { struct qemud_driver *driver = (struct qemud_driver *)opaque; @@ -3690,323 +3067,6 @@ done: 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, @@ -4080,42 +3140,17 @@ static virDriver qemuDriver = { #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 = { .initialize = qemudStartup, .cleanup = qemudShutdown, .reload = qemudReload, .active = qemudActive, }; -#endif int qemudRegister(void) { virRegisterDriver(&qemuDriver); - virRegisterNetworkDriver(&qemuNetworkDriver); -#ifdef WITH_LIBVIRTD virRegisterStateDriver(&qemuStateDriver); -#endif return 0; }