2008-10-10 13:57:13 +00:00
|
|
|
/*
|
2010-06-19 18:08:25 +00:00
|
|
|
* bridge_driver.c: core driver methods for managing network
|
2008-10-10 13:57:13 +00:00
|
|
|
*
|
2013-01-15 18:35:34 +00:00
|
|
|
* Copyright (C) 2006-2013 Red Hat, Inc.
|
2008-10-10 13:57:13 +00:00
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-10-10 13:57:13 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.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 <sys/wait.h>
|
|
|
|
#include <sys/ioctl.h>
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#include <net/if.h>
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2008-11-04 23:22:06 +00:00
|
|
|
#include "datatypes.h"
|
2009-09-15 17:52:58 +00:00
|
|
|
#include "bridge_driver.h"
|
2008-10-10 13:57:13 +00:00
|
|
|
#include "network_conf.h"
|
2012-08-16 15:42:31 +00:00
|
|
|
#include "device_conf.h"
|
2008-10-10 13:57:13 +00:00
|
|
|
#include "driver.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2011-08-05 13:13:12 +00:00
|
|
|
#include "virpidfile.h"
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2012-12-12 17:42:44 +00:00
|
|
|
#include "viriptables.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-12 16:43:54 +00:00
|
|
|
#include "virdnsmasq.h"
|
2010-11-16 14:54:17 +00:00
|
|
|
#include "configmake.h"
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#include "virnetdev.h"
|
2012-12-13 14:52:25 +00:00
|
|
|
#include "virpci.h"
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#include "virnetdevbridge.h"
|
|
|
|
#include "virnetdevtap.h"
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
#include "virnetdevvportprofile.h"
|
network: use firewalld instead of iptables, when available
* configure.ac, spec file: firewalld defaults to enabled if dbus is
available, otherwise is disabled. If --with_firewalld is explicitly
requested and dbus is not available, configure will fail.
* bridge_driver: add dbus filters to get the FirewallD1.Reloaded
signal and DBus.NameOwnerChanged on org.fedoraproject.FirewallD1.
When these are encountered, reload all the iptables reuls of all
libvirt's virtual networks (similar to what happens when libvirtd is
restarted).
* iptables, ebtables: use firewall-cmd's direct passthrough interface
when available, otherwise use iptables and ebtables commands. This
decision is made once the first time libvirt calls
iptables/ebtables, and that decision is maintained for the life of
libvirtd.
* Note that the nwfilter part of this patch was separated out into
another patch by Stefan in V2, so that needs to be revised and
re-reviewed as well.
================
All the configure.ac and specfile changes are unchanged from Thomas'
V3.
V3 re-ran "firewall-cmd --state" every time a new rule was added,
which was extremely inefficient. V4 uses VIR_ONCE_GLOBAL_INIT to set
up a one-time initialization function.
The VIR_ONCE_GLOBAL_INIT(x) macro references a static function called
vir(Ip|Eb)OnceInit(), which will then be called the first time that
the static function vir(Ip|Eb)TablesInitialize() is called (that
function is defined for you by the macro). This is
thread-safe, so there is no chance of any race.
IMPORTANT NOTE: I've left the VIR_DEBUG messages in these two init
functions (one for iptables, on for ebtables) as VIR_WARN so that I
don't have to turn on all the other debug message just to see
these. Even if this patch doesn't need any other modification, those
messages need to be changed to VIR_DEBUG before pushing.
This one-time initialization works well. However, I've encountered
problems with testing:
1) Whenever I have enabled the firewalld service, *all* attempts to
call firewall-cmd from within libvirtd end with firewall-cmd hanging
internally somewhere. This is *not* the case if firewall-cmd returns
non-0 in response to "firewall-cmd --state" (i.e. *that* command runs
and returns to libvirt successfully.)
2) If I start libvirtd while firewalld is stopped, then start
firewalld later, this triggers libvirtd to reload its iptables rules,
however it also spits out a *ton* of complaints about deletion failing
(I suppose because firewalld has nuked all of libvirt's rules). I
guess we need to suppress those messages (which is a more annoying
problem to fix than you might think, but that's another story).
3) I noticed a few times during this long line of errors that
firewalld made a complaint about "Resource Temporarily
unavailable. Having libvirtd access iptables commands directly at the
same time as firewalld is doing so is apparently problematic.
4) In general, I'm concerned about the "set it once and never change
it" method - if firewalld is disabled at libvirtd startup, causing
libvirtd to always use iptables/ebtables directly, this won't cause
*terrible* problems, but if libvirtd decides to use firewall-cmd and
firewalld is later disabled, libvirtd will not be able to recover.
2012-08-14 18:59:52 +00:00
|
|
|
#include "virdbus.h"
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
#include "virfile.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/* Main driver state */
|
|
|
|
struct network_driver {
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutex lock;
|
2008-12-04 21:38:38 +00:00
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
virNetworkObjList networks;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
iptablesContext *iptables;
|
|
|
|
char *networkConfigDir;
|
|
|
|
char *networkAutostartDir;
|
2013-05-02 17:59:52 +00:00
|
|
|
char *stateDir;
|
|
|
|
char *pidDir;
|
|
|
|
char *dnsmasqStateDir;
|
|
|
|
char *radvdStateDir;
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
dnsmasqCapsPtr dnsmasqCaps;
|
2008-10-10 13:57:13 +00:00
|
|
|
};
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
|
|
|
|
static void networkDriverLock(struct network_driver *driver)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&driver->lock);
|
2008-12-04 21:38:38 +00:00
|
|
|
}
|
|
|
|
static void networkDriverUnlock(struct network_driver *driver)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&driver->lock);
|
2008-12-04 21:38:38 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkStateCleanup(void);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
static int networkStartNetwork(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network);
|
|
|
|
|
|
|
|
static int networkShutdownNetwork(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network);
|
|
|
|
|
|
|
|
static int networkStartNetworkVirtual(struct network_driver *driver,
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkObjPtr network);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
static int networkShutdownNetworkVirtual(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network);
|
|
|
|
|
|
|
|
static int networkStartNetworkExternal(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network);
|
|
|
|
|
|
|
|
static int networkShutdownNetworkExternal(struct network_driver *driver,
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkObjPtr network);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2009-12-10 11:27:17 +00:00
|
|
|
static void networkReloadIptablesRules(struct network_driver *driver);
|
2012-09-17 01:22:27 +00:00
|
|
|
static void networkRefreshDaemons(struct network_driver *driver);
|
2009-12-10 11:27:17 +00:00
|
|
|
|
2012-11-16 13:29:01 +00:00
|
|
|
static int networkPlugBandwidth(virNetworkObjPtr net,
|
|
|
|
virDomainNetDefPtr iface);
|
|
|
|
static int networkUnplugBandwidth(virNetworkObjPtr net,
|
|
|
|
virDomainNetDefPtr iface);
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
static struct network_driver *driverState = NULL;
|
|
|
|
|
2011-03-11 18:20:48 +00:00
|
|
|
static char *
|
2011-06-27 14:55:13 +00:00
|
|
|
networkDnsmasqLeaseFileNameDefault(const char *netname)
|
2011-03-11 18:20:48 +00:00
|
|
|
{
|
|
|
|
char *leasefile;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
|
|
|
|
driverState->dnsmasqStateDir, netname));
|
2011-03-11 18:20:48 +00:00
|
|
|
return leasefile;
|
|
|
|
}
|
|
|
|
|
2011-06-27 14:55:13 +00:00
|
|
|
networkDnsmasqLeaseFileNameFunc networkDnsmasqLeaseFileName =
|
|
|
|
networkDnsmasqLeaseFileNameDefault;
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
static char *
|
|
|
|
networkDnsmasqConfigFileName(const char *netname)
|
|
|
|
{
|
|
|
|
char *conffile;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
ignore_value(virAsprintf(&conffile, "%s/%s.conf",
|
|
|
|
driverState->dnsmasqStateDir, netname));
|
2012-12-06 17:20:39 +00:00
|
|
|
return conffile;
|
|
|
|
}
|
|
|
|
|
2010-12-20 06:14:11 +00:00
|
|
|
static char *
|
|
|
|
networkRadvdPidfileBasename(const char *netname)
|
|
|
|
{
|
|
|
|
/* this is simple but we want to be sure it's consistently done */
|
|
|
|
char *pidfilebase;
|
|
|
|
|
2011-08-02 20:26:17 +00:00
|
|
|
ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
|
2010-12-20 06:14:11 +00:00
|
|
|
return pidfilebase;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
networkRadvdConfigFileName(const char *netname)
|
|
|
|
{
|
|
|
|
char *configfile;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
ignore_value(virAsprintf(&configfile, "%s/%s-radvd.conf",
|
|
|
|
driverState->radvdStateDir, netname));
|
2010-12-20 06:14:11 +00:00
|
|
|
return configfile;
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-10-25 14:13:57 +00:00
|
|
|
/* do needed cleanup steps and remove the network from the list */
|
|
|
|
static int
|
|
|
|
networkRemoveInactive(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr net)
|
|
|
|
{
|
|
|
|
char *leasefile = NULL;
|
|
|
|
char *radvdconfigfile = NULL;
|
2012-12-06 17:20:39 +00:00
|
|
|
char *configfile = NULL;
|
2012-10-25 14:13:57 +00:00
|
|
|
char *radvdpidbase = NULL;
|
2013-04-16 16:35:59 +00:00
|
|
|
char *statusfile = NULL;
|
2012-10-25 14:13:57 +00:00
|
|
|
dnsmasqContext *dctx = NULL;
|
|
|
|
virNetworkDefPtr def = virNetworkObjGetPersistentDef(net);
|
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/* remove the (possibly) existing dnsmasq and radvd files */
|
2013-05-02 17:59:52 +00:00
|
|
|
if (!(dctx = dnsmasqContextNew(def->name,
|
|
|
|
driverState->dnsmasqStateDir))) {
|
2012-10-25 14:13:57 +00:00
|
|
|
goto cleanup;
|
2013-05-02 17:59:52 +00:00
|
|
|
}
|
2012-10-25 14:13:57 +00:00
|
|
|
|
|
|
|
if (!(leasefile = networkDnsmasqLeaseFileName(def->name)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(radvdconfigfile = networkRadvdConfigFileName(def->name)))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
if (!(configfile = networkDnsmasqConfigFileName(def->name)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if (!(statusfile
|
|
|
|
= virNetworkConfigFile(driverState->stateDir, def->name)))
|
2013-04-16 16:35:59 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2012-10-25 14:13:57 +00:00
|
|
|
/* dnsmasq */
|
|
|
|
dnsmasqDelete(dctx);
|
|
|
|
unlink(leasefile);
|
2012-12-06 17:20:39 +00:00
|
|
|
unlink(configfile);
|
2012-10-25 14:13:57 +00:00
|
|
|
|
|
|
|
/* radvd */
|
|
|
|
unlink(radvdconfigfile);
|
2013-05-02 17:59:52 +00:00
|
|
|
virPidFileDelete(driverState->pidDir, radvdpidbase);
|
2012-10-25 14:13:57 +00:00
|
|
|
|
2013-04-16 16:35:59 +00:00
|
|
|
/* remove status file */
|
|
|
|
unlink(statusfile);
|
|
|
|
|
2012-10-25 14:13:57 +00:00
|
|
|
/* remove the network definition */
|
|
|
|
virNetworkRemoveInactive(&driver->networks, net);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(leasefile);
|
2012-12-06 17:20:39 +00:00
|
|
|
VIR_FREE(configfile);
|
2012-10-25 14:13:57 +00:00
|
|
|
VIR_FREE(radvdconfigfile);
|
|
|
|
VIR_FREE(radvdpidbase);
|
2013-04-16 16:35:59 +00:00
|
|
|
VIR_FREE(statusfile);
|
2012-10-25 14:13:57 +00:00
|
|
|
dnsmasqContextFree(dctx);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
static char *
|
|
|
|
networkBridgeDummyNicName(const char *brname)
|
|
|
|
{
|
network: truncate bridges' dummy tap device names to IFNAMSIZ (15) chars
This patch addresses:
https://bugzilla.redhat.com/show_bug.cgi?id=694382
In order to give each libvirt-created bridge a fixed MAC address,
commit 5754dbd56d4738112a86776c09e810e32f7c3224, added code to create
a dummy tap device with guaranteed lowest MAC address and attach it to
the bridge. This tap device was given the name "${bridgename}-nic".
However, an interface device name must be IFNAMSIZ (15) characters or
less, so a valid ${bridgename} such as "verylongname123" (15
characters) would lead to an invalid tap device name
("verylongname123-nic" - 19 characters), and that in turn led to a
failure to bring up the network.
The solution is to shorten the part of the original name used to
generate the tap device name. However, simply truncating it is
insufficient, because the last few characters of an interface name are
often a number used to indicate one of a list of several similar
devices (for example, "verylongname123", "verylongname124", etc) and
simple truncation would lead to duplicate names (eg "verlongnam-nic"
and "verylongnam-nic"). So instead we take the first 8 characters of
$bridgename ("verylong" in the example), add on the final 3 bytes
("123"), then add "-nic" (so "verylong123-nic"). Not pretty, but it
is much more likely to generate a unique name, and is reproducible
(unlike, say, a random number).
2011-04-13 16:38:58 +00:00
|
|
|
static const char dummyNicSuffix[] = "-nic";
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
char *nicname;
|
|
|
|
|
network: truncate bridges' dummy tap device names to IFNAMSIZ (15) chars
This patch addresses:
https://bugzilla.redhat.com/show_bug.cgi?id=694382
In order to give each libvirt-created bridge a fixed MAC address,
commit 5754dbd56d4738112a86776c09e810e32f7c3224, added code to create
a dummy tap device with guaranteed lowest MAC address and attach it to
the bridge. This tap device was given the name "${bridgename}-nic".
However, an interface device name must be IFNAMSIZ (15) characters or
less, so a valid ${bridgename} such as "verylongname123" (15
characters) would lead to an invalid tap device name
("verylongname123-nic" - 19 characters), and that in turn led to a
failure to bring up the network.
The solution is to shorten the part of the original name used to
generate the tap device name. However, simply truncating it is
insufficient, because the last few characters of an interface name are
often a number used to indicate one of a list of several similar
devices (for example, "verylongname123", "verylongname124", etc) and
simple truncation would lead to duplicate names (eg "verlongnam-nic"
and "verylongnam-nic"). So instead we take the first 8 characters of
$bridgename ("verylong" in the example), add on the final 3 bytes
("123"), then add "-nic" (so "verylong123-nic"). Not pretty, but it
is much more likely to generate a unique name, and is reproducible
(unlike, say, a random number).
2011-04-13 16:38:58 +00:00
|
|
|
if (strlen(brname) + sizeof(dummyNicSuffix) > IFNAMSIZ) {
|
|
|
|
/* because the length of an ifname is limited to IFNAMSIZ-1
|
|
|
|
* (usually 15), and we're adding 4 more characters, we must
|
|
|
|
* truncate the original name to 11 to fit. In order to catch
|
|
|
|
* a possible numeric ending (eg virbr0, virbr1, etc), we grab
|
|
|
|
* the first 8 and last 3 characters of the string.
|
|
|
|
*/
|
2011-08-02 20:26:17 +00:00
|
|
|
ignore_value(virAsprintf(&nicname, "%.*s%s%s",
|
|
|
|
/* space for last 3 chars + "-nic" + NULL */
|
|
|
|
(int)(IFNAMSIZ - (3 + sizeof(dummyNicSuffix))),
|
|
|
|
brname, brname + strlen(brname) - 3,
|
|
|
|
dummyNicSuffix));
|
network: truncate bridges' dummy tap device names to IFNAMSIZ (15) chars
This patch addresses:
https://bugzilla.redhat.com/show_bug.cgi?id=694382
In order to give each libvirt-created bridge a fixed MAC address,
commit 5754dbd56d4738112a86776c09e810e32f7c3224, added code to create
a dummy tap device with guaranteed lowest MAC address and attach it to
the bridge. This tap device was given the name "${bridgename}-nic".
However, an interface device name must be IFNAMSIZ (15) characters or
less, so a valid ${bridgename} such as "verylongname123" (15
characters) would lead to an invalid tap device name
("verylongname123-nic" - 19 characters), and that in turn led to a
failure to bring up the network.
The solution is to shorten the part of the original name used to
generate the tap device name. However, simply truncating it is
insufficient, because the last few characters of an interface name are
often a number used to indicate one of a list of several similar
devices (for example, "verylongname123", "verylongname124", etc) and
simple truncation would lead to duplicate names (eg "verlongnam-nic"
and "verylongnam-nic"). So instead we take the first 8 characters of
$bridgename ("verylong" in the example), add on the final 3 bytes
("123"), then add "-nic" (so "verylong123-nic"). Not pretty, but it
is much more likely to generate a unique name, and is reproducible
(unlike, say, a random number).
2011-04-13 16:38:58 +00:00
|
|
|
} else {
|
2011-08-02 20:26:17 +00:00
|
|
|
ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
|
network: truncate bridges' dummy tap device names to IFNAMSIZ (15) chars
This patch addresses:
https://bugzilla.redhat.com/show_bug.cgi?id=694382
In order to give each libvirt-created bridge a fixed MAC address,
commit 5754dbd56d4738112a86776c09e810e32f7c3224, added code to create
a dummy tap device with guaranteed lowest MAC address and attach it to
the bridge. This tap device was given the name "${bridgename}-nic".
However, an interface device name must be IFNAMSIZ (15) characters or
less, so a valid ${bridgename} such as "verylongname123" (15
characters) would lead to an invalid tap device name
("verylongname123-nic" - 19 characters), and that in turn led to a
failure to bring up the network.
The solution is to shorten the part of the original name used to
generate the tap device name. However, simply truncating it is
insufficient, because the last few characters of an interface name are
often a number used to indicate one of a list of several similar
devices (for example, "verylongname123", "verylongname124", etc) and
simple truncation would lead to duplicate names (eg "verlongnam-nic"
and "verylongnam-nic"). So instead we take the first 8 characters of
$bridgename ("verylong" in the example), add on the final 3 bytes
("123"), then add "-nic" (so "verylong123-nic"). Not pretty, but it
is much more likely to generate a unique name, and is reproducible
(unlike, say, a random number).
2011-04-13 16:38:58 +00:00
|
|
|
}
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
return nicname;
|
|
|
|
}
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
static void
|
2013-04-16 16:35:59 +00:00
|
|
|
networkFindActiveConfigs(struct network_driver *driver)
|
|
|
|
{
|
2009-01-20 22:36:10 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < driver->networks.count ; i++) {
|
|
|
|
virNetworkObjPtr obj = driver->networks.objs[i];
|
|
|
|
|
|
|
|
virNetworkObjLock(obj);
|
|
|
|
|
|
|
|
/* If bridge exists, then mark it active */
|
|
|
|
if (obj->def->bridge &&
|
2011-11-11 08:20:19 +00:00
|
|
|
virNetDevExists(obj->def->bridge) == 1) {
|
2009-01-20 22:36:10 +00:00
|
|
|
obj->active = 1;
|
|
|
|
|
2010-12-20 06:14:11 +00:00
|
|
|
/* Try and read dnsmasq/radvd pids if any */
|
|
|
|
if (obj->def->ips && (obj->def->nips > 0)) {
|
2011-08-05 13:41:25 +00:00
|
|
|
char *radvdpidbase;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
ignore_value(virPidFileReadIfAlive(driverState->pidDir, obj->def->name,
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
&obj->dnsmasqPid,
|
|
|
|
dnsmasqCapsGetBinaryPath(driver->dnsmasqCaps)));
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2010-12-20 06:14:11 +00:00
|
|
|
if (!(radvdpidbase = networkRadvdPidfileBasename(obj->def->name))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-10-16 10:09:13 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-05-02 17:59:52 +00:00
|
|
|
ignore_value(virPidFileReadIfAlive(driverState->pidDir, radvdpidbase,
|
2011-08-05 13:41:25 +00:00
|
|
|
&obj->radvdPid, RADVD));
|
2010-12-20 06:14:11 +00:00
|
|
|
VIR_FREE(radvdpidbase);
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-16 10:09:13 +00:00
|
|
|
cleanup:
|
2009-01-20 22:36:10 +00:00
|
|
|
virNetworkObjUnlock(obj);
|
|
|
|
}
|
2013-04-16 16:35:59 +00:00
|
|
|
|
|
|
|
/* remove inactive transient networks */
|
|
|
|
i = 0;
|
|
|
|
while (i < driver->networks.count) {
|
|
|
|
virNetworkObjPtr obj = driver->networks.objs[i];
|
|
|
|
virNetworkObjLock(obj);
|
|
|
|
|
|
|
|
if (!obj->persistent && !obj->active) {
|
|
|
|
networkRemoveInactive(driver, obj);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
virNetworkObjUnlock(obj);
|
|
|
|
i++;
|
|
|
|
}
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
static void
|
|
|
|
networkAutostartConfigs(struct network_driver *driver) {
|
|
|
|
unsigned int i;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
for (i = 0 ; i < driver->networks.count ; i++) {
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjLock(driver->networks.objs[i]);
|
2008-10-10 14:50:26 +00:00
|
|
|
if (driver->networks.objs[i]->autostart &&
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
!virNetworkObjIsActive(driver->networks.objs[i])) {
|
|
|
|
if (networkStartNetwork(driver, driver->networks.objs[i]) < 0) {
|
2009-05-20 13:37:30 +00:00
|
|
|
/* failed to start but already logged */
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
network: use firewalld instead of iptables, when available
* configure.ac, spec file: firewalld defaults to enabled if dbus is
available, otherwise is disabled. If --with_firewalld is explicitly
requested and dbus is not available, configure will fail.
* bridge_driver: add dbus filters to get the FirewallD1.Reloaded
signal and DBus.NameOwnerChanged on org.fedoraproject.FirewallD1.
When these are encountered, reload all the iptables reuls of all
libvirt's virtual networks (similar to what happens when libvirtd is
restarted).
* iptables, ebtables: use firewall-cmd's direct passthrough interface
when available, otherwise use iptables and ebtables commands. This
decision is made once the first time libvirt calls
iptables/ebtables, and that decision is maintained for the life of
libvirtd.
* Note that the nwfilter part of this patch was separated out into
another patch by Stefan in V2, so that needs to be revised and
re-reviewed as well.
================
All the configure.ac and specfile changes are unchanged from Thomas'
V3.
V3 re-ran "firewall-cmd --state" every time a new rule was added,
which was extremely inefficient. V4 uses VIR_ONCE_GLOBAL_INIT to set
up a one-time initialization function.
The VIR_ONCE_GLOBAL_INIT(x) macro references a static function called
vir(Ip|Eb)OnceInit(), which will then be called the first time that
the static function vir(Ip|Eb)TablesInitialize() is called (that
function is defined for you by the macro). This is
thread-safe, so there is no chance of any race.
IMPORTANT NOTE: I've left the VIR_DEBUG messages in these two init
functions (one for iptables, on for ebtables) as VIR_WARN so that I
don't have to turn on all the other debug message just to see
these. Even if this patch doesn't need any other modification, those
messages need to be changed to VIR_DEBUG before pushing.
This one-time initialization works well. However, I've encountered
problems with testing:
1) Whenever I have enabled the firewalld service, *all* attempts to
call firewall-cmd from within libvirtd end with firewall-cmd hanging
internally somewhere. This is *not* the case if firewall-cmd returns
non-0 in response to "firewall-cmd --state" (i.e. *that* command runs
and returns to libvirt successfully.)
2) If I start libvirtd while firewalld is stopped, then start
firewalld later, this triggers libvirtd to reload its iptables rules,
however it also spits out a *ton* of complaints about deletion failing
(I suppose because firewalld has nuked all of libvirt's rules). I
guess we need to suppress those messages (which is a more annoying
problem to fix than you might think, but that's another story).
3) I noticed a few times during this long line of errors that
firewalld made a complaint about "Resource Temporarily
unavailable. Having libvirtd access iptables commands directly at the
same time as firewalld is doing so is apparently problematic.
4) In general, I'm concerned about the "set it once and never change
it" method - if firewalld is disabled at libvirtd startup, causing
libvirtd to always use iptables/ebtables directly, this won't cause
*terrible* problems, but if libvirtd decides to use firewall-cmd and
firewalld is later disabled, libvirtd will not be able to recover.
2012-08-14 18:59:52 +00:00
|
|
|
#if HAVE_FIREWALLD
|
|
|
|
static DBusHandlerResult
|
|
|
|
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
|
|
|
|
DBusMessage *message, void *user_data) {
|
|
|
|
struct network_driver *_driverState = user_data;
|
|
|
|
|
|
|
|
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
|
|
|
|
"NameOwnerChanged") ||
|
|
|
|
dbus_message_is_signal(message, "org.fedoraproject.FirewallD1",
|
|
|
|
"Reloaded"))
|
|
|
|
{
|
|
|
|
VIR_DEBUG("Reload in bridge_driver because of firewalld.");
|
|
|
|
networkReloadIptablesRules(_driverState);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/**
|
2013-04-23 12:50:18 +00:00
|
|
|
* networkStateInitialize:
|
2008-10-10 13:57:13 +00:00
|
|
|
*
|
|
|
|
* Initialization function for the QEmu daemon
|
|
|
|
*/
|
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
networkStateInitialize(bool privileged,
|
|
|
|
virStateInhibitCallback callback ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
2012-10-31 19:03:55 +00:00
|
|
|
{
|
2013-05-02 17:59:52 +00:00
|
|
|
int ret = -1;
|
|
|
|
char *configdir = NULL;
|
|
|
|
char *rundir = NULL;
|
network: use firewalld instead of iptables, when available
* configure.ac, spec file: firewalld defaults to enabled if dbus is
available, otherwise is disabled. If --with_firewalld is explicitly
requested and dbus is not available, configure will fail.
* bridge_driver: add dbus filters to get the FirewallD1.Reloaded
signal and DBus.NameOwnerChanged on org.fedoraproject.FirewallD1.
When these are encountered, reload all the iptables reuls of all
libvirt's virtual networks (similar to what happens when libvirtd is
restarted).
* iptables, ebtables: use firewall-cmd's direct passthrough interface
when available, otherwise use iptables and ebtables commands. This
decision is made once the first time libvirt calls
iptables/ebtables, and that decision is maintained for the life of
libvirtd.
* Note that the nwfilter part of this patch was separated out into
another patch by Stefan in V2, so that needs to be revised and
re-reviewed as well.
================
All the configure.ac and specfile changes are unchanged from Thomas'
V3.
V3 re-ran "firewall-cmd --state" every time a new rule was added,
which was extremely inefficient. V4 uses VIR_ONCE_GLOBAL_INIT to set
up a one-time initialization function.
The VIR_ONCE_GLOBAL_INIT(x) macro references a static function called
vir(Ip|Eb)OnceInit(), which will then be called the first time that
the static function vir(Ip|Eb)TablesInitialize() is called (that
function is defined for you by the macro). This is
thread-safe, so there is no chance of any race.
IMPORTANT NOTE: I've left the VIR_DEBUG messages in these two init
functions (one for iptables, on for ebtables) as VIR_WARN so that I
don't have to turn on all the other debug message just to see
these. Even if this patch doesn't need any other modification, those
messages need to be changed to VIR_DEBUG before pushing.
This one-time initialization works well. However, I've encountered
problems with testing:
1) Whenever I have enabled the firewalld service, *all* attempts to
call firewall-cmd from within libvirtd end with firewall-cmd hanging
internally somewhere. This is *not* the case if firewall-cmd returns
non-0 in response to "firewall-cmd --state" (i.e. *that* command runs
and returns to libvirt successfully.)
2) If I start libvirtd while firewalld is stopped, then start
firewalld later, this triggers libvirtd to reload its iptables rules,
however it also spits out a *ton* of complaints about deletion failing
(I suppose because firewalld has nuked all of libvirt's rules). I
guess we need to suppress those messages (which is a more annoying
problem to fix than you might think, but that's another story).
3) I noticed a few times during this long line of errors that
firewalld made a complaint about "Resource Temporarily
unavailable. Having libvirtd access iptables commands directly at the
same time as firewalld is doing so is apparently problematic.
4) In general, I'm concerned about the "set it once and never change
it" method - if firewalld is disabled at libvirtd startup, causing
libvirtd to always use iptables/ebtables directly, this won't cause
*terrible* problems, but if libvirtd decides to use firewall-cmd and
firewalld is later disabled, libvirtd will not be able to recover.
2012-08-14 18:59:52 +00:00
|
|
|
#ifdef HAVE_FIREWALLD
|
|
|
|
DBusConnection *sysbus = NULL;
|
|
|
|
#endif
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(driverState) < 0)
|
2008-12-04 21:37:52 +00:00
|
|
|
goto error;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&driverState->lock) < 0) {
|
|
|
|
VIR_FREE(driverState);
|
|
|
|
goto error;
|
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driverState);
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
/* configuration/state paths are one of
|
|
|
|
* ~/.config/libvirt/... (session/unprivileged)
|
|
|
|
* /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
|
|
|
|
*
|
|
|
|
* NB: The qemu driver puts its domain state in /var/run, and I
|
|
|
|
* think the network driver should have used /var/run too (instead
|
|
|
|
* of /var/lib), but it's been this way for a long time, and we
|
|
|
|
* probably shouldn't change it now.
|
|
|
|
*/
|
2009-06-12 13:20:13 +00:00
|
|
|
if (privileged) {
|
2013-05-03 12:43:59 +00:00
|
|
|
if (VIR_STRDUP(driverState->networkConfigDir,
|
|
|
|
SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
|
|
|
|
VIR_STRDUP(driverState->networkAutostartDir,
|
|
|
|
SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
|
|
|
|
VIR_STRDUP(driverState->stateDir,
|
|
|
|
LOCALSTATEDIR "/lib/libvirt/network") < 0 ||
|
|
|
|
VIR_STRDUP(driverState->pidDir,
|
|
|
|
LOCALSTATEDIR "/run/libvirt/network") < 0 ||
|
|
|
|
VIR_STRDUP(driverState->dnsmasqStateDir,
|
|
|
|
LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
|
|
|
|
VIR_STRDUP(driverState->radvdStateDir,
|
|
|
|
LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
|
|
|
|
goto error;
|
2008-10-10 13:57:13 +00:00
|
|
|
} else {
|
2013-05-02 17:59:52 +00:00
|
|
|
configdir = virGetUserConfigDirectory();
|
|
|
|
rundir = virGetUserRuntimeDirectory();
|
|
|
|
if (!(configdir && rundir))
|
2009-01-22 19:41:48 +00:00
|
|
|
goto error;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if ((virAsprintf(&driverState->networkConfigDir,
|
|
|
|
"%s/qemu/networks", configdir) < 0) ||
|
|
|
|
(virAsprintf(&driverState->networkAutostartDir,
|
|
|
|
"%s/qemu/networks/autostart", configdir) < 0) ||
|
|
|
|
(virAsprintf(&driverState->stateDir,
|
|
|
|
"%s/network/lib", rundir) < 0) ||
|
|
|
|
(virAsprintf(&driverState->pidDir,
|
|
|
|
"%s/network/run", rundir) < 0) ||
|
|
|
|
(virAsprintf(&driverState->dnsmasqStateDir,
|
|
|
|
"%s/dnsmasq/lib", rundir) < 0) ||
|
|
|
|
(virAsprintf(&driverState->radvdStateDir,
|
|
|
|
"%s/radvd/lib", rundir) < 0)) {
|
2008-10-10 13:57:13 +00:00
|
|
|
goto out_of_memory;
|
2009-01-22 19:41:48 +00:00
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (!(driverState->iptables = iptablesContextNew())) {
|
2009-05-20 13:37:30 +00:00
|
|
|
goto out_of_memory;
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
/* if this fails now, it will be retried later with dnsmasqCapsRefresh() */
|
|
|
|
driverState->dnsmasqCaps = dnsmasqCapsNewFromBinary(DNSMASQ);
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2013-04-16 16:35:59 +00:00
|
|
|
if (virNetworkLoadAllState(&driverState->networks,
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->stateDir) < 0)
|
2013-04-16 16:35:59 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virNetworkLoadAllConfigs(&driverState->networks,
|
2008-10-10 13:57:13 +00:00
|
|
|
driverState->networkConfigDir,
|
2008-12-04 21:37:52 +00:00
|
|
|
driverState->networkAutostartDir) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
networkFindActiveConfigs(driverState);
|
2009-12-10 11:27:17 +00:00
|
|
|
networkReloadIptablesRules(driverState);
|
2012-09-17 01:22:27 +00:00
|
|
|
networkRefreshDaemons(driverState);
|
2008-10-10 13:57:13 +00:00
|
|
|
networkAutostartConfigs(driverState);
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driverState);
|
|
|
|
|
network: use firewalld instead of iptables, when available
* configure.ac, spec file: firewalld defaults to enabled if dbus is
available, otherwise is disabled. If --with_firewalld is explicitly
requested and dbus is not available, configure will fail.
* bridge_driver: add dbus filters to get the FirewallD1.Reloaded
signal and DBus.NameOwnerChanged on org.fedoraproject.FirewallD1.
When these are encountered, reload all the iptables reuls of all
libvirt's virtual networks (similar to what happens when libvirtd is
restarted).
* iptables, ebtables: use firewall-cmd's direct passthrough interface
when available, otherwise use iptables and ebtables commands. This
decision is made once the first time libvirt calls
iptables/ebtables, and that decision is maintained for the life of
libvirtd.
* Note that the nwfilter part of this patch was separated out into
another patch by Stefan in V2, so that needs to be revised and
re-reviewed as well.
================
All the configure.ac and specfile changes are unchanged from Thomas'
V3.
V3 re-ran "firewall-cmd --state" every time a new rule was added,
which was extremely inefficient. V4 uses VIR_ONCE_GLOBAL_INIT to set
up a one-time initialization function.
The VIR_ONCE_GLOBAL_INIT(x) macro references a static function called
vir(Ip|Eb)OnceInit(), which will then be called the first time that
the static function vir(Ip|Eb)TablesInitialize() is called (that
function is defined for you by the macro). This is
thread-safe, so there is no chance of any race.
IMPORTANT NOTE: I've left the VIR_DEBUG messages in these two init
functions (one for iptables, on for ebtables) as VIR_WARN so that I
don't have to turn on all the other debug message just to see
these. Even if this patch doesn't need any other modification, those
messages need to be changed to VIR_DEBUG before pushing.
This one-time initialization works well. However, I've encountered
problems with testing:
1) Whenever I have enabled the firewalld service, *all* attempts to
call firewall-cmd from within libvirtd end with firewall-cmd hanging
internally somewhere. This is *not* the case if firewall-cmd returns
non-0 in response to "firewall-cmd --state" (i.e. *that* command runs
and returns to libvirt successfully.)
2) If I start libvirtd while firewalld is stopped, then start
firewalld later, this triggers libvirtd to reload its iptables rules,
however it also spits out a *ton* of complaints about deletion failing
(I suppose because firewalld has nuked all of libvirt's rules). I
guess we need to suppress those messages (which is a more annoying
problem to fix than you might think, but that's another story).
3) I noticed a few times during this long line of errors that
firewalld made a complaint about "Resource Temporarily
unavailable. Having libvirtd access iptables commands directly at the
same time as firewalld is doing so is apparently problematic.
4) In general, I'm concerned about the "set it once and never change
it" method - if firewalld is disabled at libvirtd startup, causing
libvirtd to always use iptables/ebtables directly, this won't cause
*terrible* problems, but if libvirtd decides to use firewall-cmd and
firewalld is later disabled, libvirtd will not be able to recover.
2012-08-14 18:59:52 +00:00
|
|
|
#ifdef HAVE_FIREWALLD
|
|
|
|
if (!(sysbus = virDBusGetSystemBus())) {
|
|
|
|
virErrorPtr err = virGetLastError();
|
|
|
|
VIR_WARN("DBus not available, disabling firewalld support "
|
|
|
|
"in bridge_driver: %s", err->message);
|
|
|
|
} else {
|
|
|
|
/* add matches for
|
|
|
|
* NameOwnerChanged on org.freedesktop.DBus for firewalld start/stop
|
|
|
|
* Reloaded on org.fedoraproject.FirewallD1 for firewalld reload
|
|
|
|
*/
|
|
|
|
dbus_bus_add_match(sysbus,
|
|
|
|
"type='signal'"
|
|
|
|
",interface='"DBUS_INTERFACE_DBUS"'"
|
|
|
|
",member='NameOwnerChanged'"
|
|
|
|
",arg0='org.fedoraproject.FirewallD1'",
|
|
|
|
NULL);
|
|
|
|
dbus_bus_add_match(sysbus,
|
|
|
|
"type='signal'"
|
|
|
|
",interface='org.fedoraproject.FirewallD1'"
|
|
|
|
",member='Reloaded'",
|
|
|
|
NULL);
|
|
|
|
dbus_connection_add_filter(sysbus, firewalld_dbus_filter_bridge,
|
|
|
|
driverState, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(configdir);
|
|
|
|
VIR_FREE(rundir);
|
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
out_of_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-12-04 21:37:52 +00:00
|
|
|
error:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (driverState)
|
|
|
|
networkDriverUnlock(driverState);
|
2013-04-23 12:50:18 +00:00
|
|
|
networkStateCleanup();
|
2013-05-02 17:59:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-04-23 12:50:18 +00:00
|
|
|
* networkStateReload:
|
2008-10-10 13:57:13 +00:00
|
|
|
*
|
|
|
|
* Function to restart the QEmu daemon, it will recheck the configuration
|
|
|
|
* files and update its state and the networking
|
|
|
|
*/
|
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
networkStateReload(void) {
|
2008-10-10 14:50:26 +00:00
|
|
|
if (!driverState)
|
|
|
|
return 0;
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driverState);
|
2013-04-16 16:35:59 +00:00
|
|
|
virNetworkLoadAllState(&driverState->networks,
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->stateDir);
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkLoadAllConfigs(&driverState->networks,
|
2008-10-10 13:57:13 +00:00
|
|
|
driverState->networkConfigDir,
|
|
|
|
driverState->networkAutostartDir);
|
2009-12-10 11:27:17 +00:00
|
|
|
networkReloadIptablesRules(driverState);
|
2012-09-17 01:22:27 +00:00
|
|
|
networkRefreshDaemons(driverState);
|
2008-10-10 13:57:13 +00:00
|
|
|
networkAutostartConfigs(driverState);
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driverState);
|
2008-10-10 13:57:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-04-23 12:50:18 +00:00
|
|
|
* networkStateCleanup:
|
2008-10-10 13:57:13 +00:00
|
|
|
*
|
|
|
|
* Shutdown the QEmu daemon, it will stop all active domains and networks
|
|
|
|
*/
|
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
networkStateCleanup(void) {
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!driverState)
|
|
|
|
return -1;
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driverState);
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/* free inactive networks */
|
2008-10-10 14:50:26 +00:00
|
|
|
virNetworkObjListFree(&driverState->networks);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
VIR_FREE(driverState->networkConfigDir);
|
|
|
|
VIR_FREE(driverState->networkAutostartDir);
|
2013-05-02 17:59:52 +00:00
|
|
|
VIR_FREE(driverState->stateDir);
|
|
|
|
VIR_FREE(driverState->pidDir);
|
|
|
|
VIR_FREE(driverState->dnsmasqStateDir);
|
|
|
|
VIR_FREE(driverState->radvdStateDir);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
if (driverState->iptables)
|
|
|
|
iptablesContextFree(driverState->iptables);
|
|
|
|
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
virObjectUnref(driverState->dnsmasqCaps);
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driverState);
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(&driverState->lock);
|
2008-12-04 21:38:38 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
VIR_FREE(driverState);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
/* networkKillDaemon:
|
|
|
|
*
|
|
|
|
* kill the specified pid/name, and wait a bit to make sure it's dead.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
networkKillDaemon(pid_t pid, const char *daemonName, const char *networkName)
|
|
|
|
{
|
|
|
|
int ii, ret = -1;
|
|
|
|
const char *signame = "TERM";
|
|
|
|
|
|
|
|
/* send SIGTERM, then wait up to 3 seconds for the process to
|
|
|
|
* disappear, send SIGKILL, then wait for up to another 2
|
|
|
|
* seconds. If that fails, log a warning and continue, hoping
|
|
|
|
* for the best.
|
|
|
|
*/
|
|
|
|
for (ii = 0; ii < 25; ii++) {
|
|
|
|
int signum = 0;
|
|
|
|
if (ii == 0)
|
|
|
|
signum = SIGTERM;
|
|
|
|
else if (ii == 15) {
|
|
|
|
signum = SIGKILL;
|
|
|
|
signame = "KILL";
|
|
|
|
}
|
|
|
|
if (kill(pid, signum) < 0) {
|
|
|
|
if (errno == ESRCH) {
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
char ebuf[1024];
|
|
|
|
VIR_WARN("Failed to terminate %s process %d "
|
|
|
|
"for network '%s' with SIG%s: %s",
|
|
|
|
daemonName, pid, networkName, signame,
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* NB: since networks have no reference count like
|
|
|
|
* domains, there is no safe way to unlock the network
|
|
|
|
* object temporarily, and so we can't follow the
|
|
|
|
* procedure used by the qemu driver of 1) unlock driver
|
|
|
|
* 2) sleep, 3) add ref to object 4) unlock object, 5)
|
|
|
|
* re-lock driver, 6) re-lock object. We may need to add
|
|
|
|
* that functionality eventually, but for now this
|
|
|
|
* function is rarely used and, at worst, leaving the
|
|
|
|
* network driver locked during this loop of sleeps will
|
|
|
|
* have the effect of holding up any other thread trying
|
|
|
|
* to make modifications to a network for up to 5 seconds;
|
|
|
|
* since modifications to networks are much less common
|
|
|
|
* than modifications to domains, this seems a reasonable
|
|
|
|
* tradeoff in exchange for less code disruption.
|
|
|
|
*/
|
|
|
|
usleep(20 * 1000);
|
|
|
|
}
|
|
|
|
VIR_WARN("Timed out waiting after SIG%s to %s process %d "
|
|
|
|
"(network '%s')",
|
|
|
|
signame, daemonName, pid, networkName);
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* the following does not build a file, it builds a list
|
|
|
|
* which is later saved into a file
|
|
|
|
*/
|
|
|
|
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
static int
|
2012-12-06 17:20:38 +00:00
|
|
|
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
|
|
|
|
virNetworkIpDefPtr ipdef)
|
2010-04-26 14:07:25 +00:00
|
|
|
{
|
2012-12-06 17:20:38 +00:00
|
|
|
unsigned int i;
|
|
|
|
bool ipv6 = false;
|
2010-04-26 14:07:25 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
|
|
|
|
ipv6 = true;
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
for (i = 0; i < ipdef->nhosts; i++) {
|
|
|
|
virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
|
2012-12-06 17:20:38 +00:00
|
|
|
if (VIR_SOCKET_ADDR_VALID(&host->ip))
|
2013-02-15 19:02:26 +00:00
|
|
|
if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
|
|
|
|
host->name, host->id, ipv6) < 0)
|
2011-06-28 12:07:46 +00:00
|
|
|
return -1;
|
2011-06-24 10:04:40 +00:00
|
|
|
}
|
2010-04-26 14:07:25 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
|
|
|
|
virNetworkDNSDefPtr dnsdef)
|
|
|
|
{
|
|
|
|
unsigned int i, j;
|
|
|
|
|
2011-06-24 10:04:40 +00:00
|
|
|
if (dnsdef) {
|
|
|
|
for (i = 0; i < dnsdef->nhosts; i++) {
|
2012-11-11 23:59:28 +00:00
|
|
|
virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
|
2011-06-24 10:04:40 +00:00
|
|
|
for (j = 0; j < host->nnames; j++)
|
2011-06-28 12:07:46 +00:00
|
|
|
if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
|
|
|
|
return -1;
|
2011-06-24 10:04:40 +00:00
|
|
|
}
|
|
|
|
}
|
2010-04-26 14:07:25 +00:00
|
|
|
}
|
|
|
|
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
return 0;
|
2010-04-26 14:07:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
int
|
|
|
|
networkDnsmasqConfContents(virNetworkObjPtr network,
|
2012-12-13 16:40:47 +00:00
|
|
|
const char *pidfile,
|
|
|
|
char **configstr,
|
|
|
|
dnsmasqContext *dctx,
|
|
|
|
dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
{
|
2012-12-06 17:20:39 +00:00
|
|
|
virBuffer configbuf = VIR_BUFFER_INITIALIZER;
|
2010-12-10 18:54:48 +00:00
|
|
|
int r, ret = -1;
|
2009-11-06 16:53:45 +00:00
|
|
|
int nbleases = 0;
|
2011-01-31 20:31:57 +00:00
|
|
|
int ii;
|
2012-02-01 09:22:21 +00:00
|
|
|
char *record = NULL;
|
|
|
|
char *recordPort = NULL;
|
|
|
|
char *recordWeight = NULL;
|
|
|
|
char *recordPriority = NULL;
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
virNetworkDNSDefPtr dns = &network->def->dns;
|
2012-12-06 17:20:38 +00:00
|
|
|
virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
|
|
|
|
bool ipv6SLAAC;
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
*configstr = NULL;
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
/*
|
2012-12-06 17:20:39 +00:00
|
|
|
* All dnsmasq parameters are put into a configuration file, except the
|
|
|
|
* command line --conf-file=parameter which specifies the location of
|
|
|
|
* configuration file.
|
2009-01-20 22:36:10 +00:00
|
|
|
*
|
2012-12-06 17:20:39 +00:00
|
|
|
* All dnsmasq conf-file parameters must be specified as "foo=bar"
|
|
|
|
* as oppose to "--foo bar" which was acceptable on the command line.
|
2009-01-20 22:36:10 +00:00
|
|
|
*/
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Needed to ensure dnsmasq uses same algorithm for processing
|
|
|
|
* multiple namedriver entries in /etc/resolv.conf as GLibC.
|
|
|
|
*/
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
/* create dnsmasq config file appropriate for this network */
|
|
|
|
virBufferAsprintf(&configbuf,
|
2012-12-13 16:40:47 +00:00
|
|
|
"##WARNING: THIS IS AN AUTO-GENERATED FILE. "
|
|
|
|
"CHANGES TO IT ARE LIKELY TO BE\n"
|
|
|
|
"##OVERWRITTEN AND LOST. Changes to this "
|
|
|
|
"configuration should be made using:\n"
|
|
|
|
"## virsh net-edit %s\n"
|
|
|
|
"## or other application using the libvirt API.\n"
|
|
|
|
"##\n## dnsmasq conf file created by libvirt\n"
|
|
|
|
"strict-order\n"
|
|
|
|
"domain-needed\n",
|
|
|
|
network->def->name);
|
|
|
|
|
|
|
|
if (network->def->domain) {
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf,
|
2012-12-13 16:40:47 +00:00
|
|
|
"domain=%s\n"
|
|
|
|
"expand-hosts\n",
|
|
|
|
network->def->domain);
|
|
|
|
}
|
|
|
|
/* need to specify local even if no domain specified */
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf,
|
2012-12-13 16:40:47 +00:00
|
|
|
"local=/%s/\n",
|
|
|
|
network->def->domain ? network->def->domain : "");
|
2012-12-06 17:20:39 +00:00
|
|
|
|
2012-12-13 16:40:47 +00:00
|
|
|
if (pidfile)
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
network: prevent dnsmasq from listening on localhost
This patch resolves the problem reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=886663
The source of the problem was the fix for CVE 2011-3411:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
which was originally committed upstream in commit
753ff83a50263d6975f88d6605d4b5ddfcc97560. That commit improperly
removed the "--except-interface lo" from dnsmasq commandlines when
--bind-dynamic was used (based on comments in the latter bug).
It turns out that the problem reported in the CVE could be eliminated
without removing "--except-interface lo", and removing it actually
caused each instance of dnsmasq to listen on localhost on port 53,
which created a new problem:
If another instance of dnsmasq using "bind-interfaces" (instead of
"bind-dynamic") had already been started (or if another instance
started later used "bind-dynamic"), this wouldn't have any immediately
visible ill effects, but if you tried to start another dnsmasq
instance using "bind-interfaces" *after* starting any libvirt
networks, the new dnsmasq would fail to start, because there was
already another process listening on port 53.
(Subsequent to the CVE fix, another patch changed the network driver
to put dnsmasq options in a conf file rather than directly on the
dnsmasq commandline, but preserved the same options.)
This patch changes the network driver to *always* add
"except-interface=lo" to dnsmasq conf files, regardless of whether we use
bind-dynamic or bind-interfaces. This way no libvirt dnsmasq instances
are listening on localhost (and the CVE is still fixed).
The actual code change is miniscule, but must be propogated through all
of the test files as well.
2012-12-13 06:46:40 +00:00
|
|
|
/* dnsmasq will *always* listen on localhost unless told otherwise */
|
|
|
|
virBufferAddLit(&configbuf, "except-interface=lo\n");
|
|
|
|
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC)) {
|
|
|
|
/* using --bind-dynamic with only --interface (no
|
|
|
|
* --listen-address) prevents dnsmasq from responding to dns
|
|
|
|
* queries that arrive on some interface other than our bridge
|
|
|
|
* interface (in other words, requests originating somewhere
|
|
|
|
* other than one of the virtual guests connected directly to
|
|
|
|
* this network). This was added in response to CVE 2012-3411.
|
|
|
|
*/
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf,
|
2012-12-13 16:40:47 +00:00
|
|
|
"bind-dynamic\n"
|
|
|
|
"interface=%s\n",
|
|
|
|
network->def->bridge);
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
} else {
|
network: prevent dnsmasq from listening on localhost
This patch resolves the problem reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=886663
The source of the problem was the fix for CVE 2011-3411:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
which was originally committed upstream in commit
753ff83a50263d6975f88d6605d4b5ddfcc97560. That commit improperly
removed the "--except-interface lo" from dnsmasq commandlines when
--bind-dynamic was used (based on comments in the latter bug).
It turns out that the problem reported in the CVE could be eliminated
without removing "--except-interface lo", and removing it actually
caused each instance of dnsmasq to listen on localhost on port 53,
which created a new problem:
If another instance of dnsmasq using "bind-interfaces" (instead of
"bind-dynamic") had already been started (or if another instance
started later used "bind-dynamic"), this wouldn't have any immediately
visible ill effects, but if you tried to start another dnsmasq
instance using "bind-interfaces" *after* starting any libvirt
networks, the new dnsmasq would fail to start, because there was
already another process listening on port 53.
(Subsequent to the CVE fix, another patch changed the network driver
to put dnsmasq options in a conf file rather than directly on the
dnsmasq commandline, but preserved the same options.)
This patch changes the network driver to *always* add
"except-interface=lo" to dnsmasq conf files, regardless of whether we use
bind-dynamic or bind-interfaces. This way no libvirt dnsmasq instances
are listening on localhost (and the CVE is still fixed).
The actual code change is miniscule, but must be propogated through all
of the test files as well.
2012-12-13 06:46:40 +00:00
|
|
|
virBufferAddLit(&configbuf, "bind-interfaces\n");
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
/*
|
|
|
|
* --interface does not actually work with dnsmasq < 2.47,
|
|
|
|
* due to DAD for ipv6 addresses on the interface.
|
|
|
|
*
|
|
|
|
* virCommandAddArgList(cmd, "--interface", network->def->bridge, NULL);
|
|
|
|
*
|
|
|
|
* So listen on all defined IPv[46] addresses
|
|
|
|
*/
|
|
|
|
for (ii = 0;
|
|
|
|
(tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
|
|
|
ii++) {
|
|
|
|
char *ipaddr = virSocketAddrFormat(&tmpipdef->address);
|
|
|
|
|
|
|
|
if (!ipaddr)
|
|
|
|
goto cleanup;
|
2012-12-13 16:40:47 +00:00
|
|
|
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
/* also part of CVE 2012-3411 - if the host's version of
|
2012-12-06 17:20:39 +00:00
|
|
|
* dnsmasq doesn't have bind-dynamic, only allow listening on
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
* private/local IP addresses (see RFC1918/RFC3484/RFC4193)
|
|
|
|
*/
|
2012-12-17 17:49:18 +00:00
|
|
|
if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
|
|
|
|
!virSocketAddrIsPrivate(&tmpipdef->address)) {
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
unsigned long version = dnsmasqCapsGetVersion(caps);
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Publicly routable address %s is prohibited. "
|
2012-12-13 16:40:47 +00:00
|
|
|
"The version of dnsmasq on this host (%d.%d) "
|
2012-12-17 17:49:18 +00:00
|
|
|
"doesn't support the bind-dynamic option or "
|
|
|
|
"use SO_BINDTODEVICE on listening sockets, "
|
|
|
|
"one of which is required for safe operation "
|
|
|
|
"on a publicly routable subnet "
|
2012-12-13 16:40:47 +00:00
|
|
|
"(see CVE-2012-3411). You must either "
|
|
|
|
"upgrade dnsmasq, or use a private/local "
|
|
|
|
"subnet range for this network "
|
|
|
|
"(as described in RFC1918/RFC3484/RFC4193)."),
|
|
|
|
ipaddr, (int)version / 1000000,
|
|
|
|
(int)(version % 1000000) / 1000);
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
|
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following
bugzilla report:
https://bugzilla.redhat.com/show_bug.cgi?id=833033
The following report is specifically for libvirt on Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=874702
In short, a dnsmasq instance run with the intention of listening for
DHCP/DNS requests only on a libvirt virtual network (which is
constructed using a Linux host bridge) would also answer queries sent
from outside the virtualization host.
This patch takes advantage of a new dnsmasq option "--bind-dynamic",
which will cause the listening socket to be setup such that it will
only receive those requests that actually come in via the bridge
interface. In order for this behavior to actually occur, not only must
"--bind-interfaces" be replaced with "--bind-dynamic", but also all
"--listen-address" options must be replaced with a single
"--interface" option. Fully:
--bind-interfaces --except-interface lo --listen-address x.x.x.x ...
(with --listen-address possibly repeated) is replaced with:
--bind-dynamic --interface virbrX
Of course libvirt can't use this new option if the host's dnsmasq
doesn't have it, but we still want libvirt to function (because the
great majority of libvirt installations, which only have mode='nat'
networks using RFC1918 private address ranges (e.g. 192.168.122.0/24),
are immune to this vulnerability from anywhere beyond the local subnet
of the host), so we use the new dnsmasqCaps API to check if dnsmasq
supports the new option and, if not, we use the "old" option style
instead. In order to assure that this permissiveness doesn't lead to a
vulnerable system, we do check for non-private addresses in this case,
and refuse to start the network if both a) we are using the old-style
options, and b) the network has a publicly routable IP
address. Hopefully this will provide the proper balance of not being
disruptive to those not practically affected, and making sure that
those who *are* affected get their dnsmasq upgraded.
(--bind-dynamic was added to dnsmasq in upstream commit
54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in
dnsmasq-2.63)
2012-11-22 02:21:02 +00:00
|
|
|
VIR_FREE(ipaddr);
|
|
|
|
}
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2011-03-13 08:42:58 +00:00
|
|
|
/* If this is an isolated network, set the default route option
|
|
|
|
* (3) to be empty to avoid setting a default route that's
|
2012-12-06 17:20:39 +00:00
|
|
|
* guaranteed to not work, and set no-resolv so that no dns
|
2011-07-29 19:42:04 +00:00
|
|
|
* requests are forwarded on to the dns server listed in the
|
|
|
|
* host's /etc/resolv.conf (since this could be used as a channel
|
|
|
|
* to build a connection to the outside).
|
2011-03-13 08:42:58 +00:00
|
|
|
*/
|
2012-11-08 02:16:17 +00:00
|
|
|
if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) {
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAddLit(&configbuf, "dhcp-option=3\n"
|
2012-12-13 16:40:47 +00:00
|
|
|
"no-resolv\n");
|
2011-07-29 19:42:04 +00:00
|
|
|
}
|
2011-03-13 08:42:58 +00:00
|
|
|
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
for (ii = 0; ii < dns->ntxts; ii++) {
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
|
|
|
|
dns->txts[ii].name,
|
|
|
|
dns->txts[ii].value);
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
}
|
2012-01-02 14:23:54 +00:00
|
|
|
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
for (ii = 0; ii < dns->nsrvs; ii++) {
|
|
|
|
if (dns->srvs[ii].service && dns->srvs[ii].protocol) {
|
|
|
|
if (dns->srvs[ii].port) {
|
|
|
|
if (virAsprintf(&recordPort, "%d", dns->srvs[ii].port) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
2012-01-02 14:23:54 +00:00
|
|
|
}
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
}
|
|
|
|
if (dns->srvs[ii].priority) {
|
|
|
|
if (virAsprintf(&recordPriority, "%d", dns->srvs[ii].priority) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
2012-01-02 14:23:54 +00:00
|
|
|
}
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
}
|
|
|
|
if (dns->srvs[ii].weight) {
|
|
|
|
if (virAsprintf(&recordWeight, "%d", dns->srvs[ii].weight) < 0) {
|
2012-01-02 14:23:54 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
}
|
2012-01-02 14:23:54 +00:00
|
|
|
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
if (virAsprintf(&record, "%s.%s.%s,%s,%s,%s,%s",
|
|
|
|
dns->srvs[ii].service,
|
|
|
|
dns->srvs[ii].protocol,
|
2012-12-13 16:40:47 +00:00
|
|
|
dns->srvs[ii].domain ? dns->srvs[ii].domain : "",
|
|
|
|
dns->srvs[ii].target ? dns->srvs[ii].target : "",
|
|
|
|
recordPort ? recordPort : "",
|
|
|
|
recordPriority ? recordPriority : "",
|
|
|
|
recordWeight ? recordWeight : "") < 0) {
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
2012-01-02 14:23:54 +00:00
|
|
|
}
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "srv-host=%s\n", record);
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
VIR_FREE(record);
|
|
|
|
VIR_FREE(recordPort);
|
|
|
|
VIR_FREE(recordWeight);
|
|
|
|
VIR_FREE(recordPriority);
|
2012-01-02 14:23:54 +00:00
|
|
|
}
|
2011-06-24 10:04:36 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* Find the first dhcp for both IPv4 and IPv6 */
|
|
|
|
for (ii = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
|
|
|
ii++) {
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
if (ipv4def) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-12-13 16:40:47 +00:00
|
|
|
_("For IPv4, multiple DHCP definitions "
|
|
|
|
"cannot be specified."));
|
2012-12-06 17:20:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
ipv4def = ipdef;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
if (!DNSMASQ_DHCPv6_SUPPORT(caps)) {
|
|
|
|
unsigned long version = dnsmasqCapsGetVersion(caps);
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-12-13 16:40:47 +00:00
|
|
|
_("The version of dnsmasq on this host "
|
|
|
|
"(%d.%d) doesn't adequately support "
|
|
|
|
"IPv6 dhcp range or dhcp host "
|
|
|
|
"specification. Version %d.%d or later "
|
|
|
|
"is required."),
|
|
|
|
(int)version / 1000000,
|
|
|
|
(int)(version % 1000000) / 1000,
|
|
|
|
DNSMASQ_DHCPv6_MAJOR_REQD,
|
|
|
|
DNSMASQ_DHCPv6_MINOR_REQD);
|
2012-12-06 17:20:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (ipv6def) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-12-13 16:40:47 +00:00
|
|
|
_("For IPv6, multiple DHCP definitions "
|
|
|
|
"cannot be specified."));
|
2012-12-06 17:20:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
ipv6def = ipdef;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ipv6SLAAC = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipv6def && ipv6SLAAC) {
|
|
|
|
VIR_WARN("For IPv6, when DHCP is specified for one address, then "
|
|
|
|
"state-full Router Advertising will occur. The additional "
|
2012-12-13 16:40:47 +00:00
|
|
|
"IPv6 addresses specified require manually configured guest "
|
|
|
|
"network to work properly since both state-full (DHCP) "
|
|
|
|
"and state-less (SLAAC) addressing are not supported "
|
|
|
|
"on the same network interface.");
|
2012-12-06 17:20:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ipdef = ipv4def ? ipv4def : ipv6def;
|
|
|
|
|
|
|
|
while (ipdef) {
|
2011-03-11 17:07:09 +00:00
|
|
|
for (r = 0 ; r < ipdef->nranges ; r++) {
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start);
|
2011-03-11 17:07:09 +00:00
|
|
|
if (!saddr)
|
|
|
|
goto cleanup;
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
char *eaddr = virSocketAddrFormat(&ipdef->ranges[r].end);
|
2011-03-11 17:07:09 +00:00
|
|
|
if (!eaddr) {
|
|
|
|
VIR_FREE(saddr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-range=%s,%s\n",
|
2012-12-13 16:40:47 +00:00
|
|
|
saddr, eaddr);
|
Convert virNetwork to use virSocketAddr everywhere
Instead of storing the IP address string in virNetwork related
structs, store the parsed virSocketAddr. This will make it
easier to add IPv6 support in the future, by letting driver
code directly check what address family is present
* src/conf/network_conf.c, src/conf/network_conf.h,
src/network/bridge_driver.c: Convert to use virSocketAddr
in virNetwork, instead of char *.
* src/util/bridge.c, src/util/bridge.h,
src/util/dnsmasq.c, src/util/dnsmasq.h,
src/util/iptables.c, src/util/iptables.h: Convert to
take a virSocketAddr instead of char * for any IP
address parameters
* src/util/network.h: Add macros to determine if an address
is set, and what address family is set.
2010-10-21 12:14:33 +00:00
|
|
|
VIR_FREE(saddr);
|
2011-03-11 17:07:09 +00:00
|
|
|
VIR_FREE(eaddr);
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
nbleases += virSocketAddrGetRange(&ipdef->ranges[r].start,
|
|
|
|
&ipdef->ranges[r].end);
|
Convert virNetwork to use virSocketAddr everywhere
Instead of storing the IP address string in virNetwork related
structs, store the parsed virSocketAddr. This will make it
easier to add IPv6 support in the future, by letting driver
code directly check what address family is present
* src/conf/network_conf.c, src/conf/network_conf.h,
src/network/bridge_driver.c: Convert to use virSocketAddr
in virNetwork, instead of char *.
* src/util/bridge.c, src/util/bridge.h,
src/util/dnsmasq.c, src/util/dnsmasq.h,
src/util/iptables.c, src/util/iptables.h: Convert to
take a virSocketAddr instead of char * for any IP
address parameters
* src/util/network.h: Add macros to determine if an address
is set, and what address family is set.
2010-10-21 12:14:33 +00:00
|
|
|
}
|
2009-11-06 16:53:45 +00:00
|
|
|
|
2011-03-11 17:07:09 +00:00
|
|
|
/*
|
2012-12-13 16:40:47 +00:00
|
|
|
* For static-only DHCP, i.e. with no range but at least one
|
|
|
|
* host element, we have to add a special --dhcp-range option
|
|
|
|
* to enable the service in dnsmasq. (this is for dhcp-hosts=
|
|
|
|
* support)
|
2011-03-11 17:07:09 +00:00
|
|
|
*/
|
|
|
|
if (!ipdef->nranges && ipdef->nhosts) {
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
|
2011-03-11 17:07:09 +00:00
|
|
|
if (!bridgeaddr)
|
|
|
|
goto cleanup;
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-range=%s,static\n", bridgeaddr);
|
2011-03-11 17:07:09 +00:00
|
|
|
VIR_FREE(bridgeaddr);
|
|
|
|
}
|
2010-09-09 14:00:08 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
|
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* Note: the following is IPv4 only */
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts)
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAddLit(&configbuf, "dhcp-no-override\n");
|
2010-09-09 14:00:08 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (ipdef->tftproot) {
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAddLit(&configbuf, "enable-tftp\n");
|
|
|
|
virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
|
2012-12-06 17:20:38 +00:00
|
|
|
}
|
2011-06-25 05:14:38 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (ipdef->bootfile) {
|
|
|
|
if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
|
|
|
|
char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
|
2011-06-28 12:07:46 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (!bootserver) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
|
2012-12-13 16:40:47 +00:00
|
|
|
ipdef->bootfile, ",,", bootserver);
|
2012-12-06 17:20:38 +00:00
|
|
|
VIR_FREE(bootserver);
|
|
|
|
} else {
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
|
2012-12-06 17:20:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (nbleases > 0) {
|
|
|
|
char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
|
|
|
|
if (!leasefile) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
2011-03-11 17:07:09 +00:00
|
|
|
}
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile);
|
2012-12-06 17:20:38 +00:00
|
|
|
VIR_FREE(leasefile);
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
|
2012-12-06 17:20:38 +00:00
|
|
|
}
|
2010-12-10 18:54:48 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* this is done once per interface */
|
|
|
|
if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
|
2012-12-13 16:40:47 +00:00
|
|
|
goto cleanup;
|
2012-12-06 17:20:38 +00:00
|
|
|
|
|
|
|
/* Even if there are currently no static hosts, if we're
|
|
|
|
* listening for DHCP, we should write a 0-length hosts
|
|
|
|
* file to allow for runtime additions.
|
|
|
|
*/
|
|
|
|
if (ipv4def || ipv6def)
|
2012-12-13 16:40:47 +00:00
|
|
|
virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n",
|
|
|
|
dctx->hostsfile->path);
|
2012-12-06 17:20:38 +00:00
|
|
|
|
2012-12-13 16:40:47 +00:00
|
|
|
/* Likewise, always create this file and put it on the
|
|
|
|
* commandline, to allow for runtime additions.
|
2012-12-06 17:20:38 +00:00
|
|
|
*/
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
|
2012-12-13 16:40:47 +00:00
|
|
|
dctx->addnhostsfile->path);
|
2012-12-06 17:20:38 +00:00
|
|
|
|
|
|
|
/* Are we doing RA instead of radvd? */
|
|
|
|
if (DNSMASQ_RA_SUPPORT(caps)) {
|
|
|
|
if (ipv6def)
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAddLit(&configbuf, "enable-ra\n");
|
2012-12-06 17:20:38 +00:00
|
|
|
else {
|
|
|
|
for (ii = 0;
|
2012-12-13 16:40:47 +00:00
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
|
|
|
|
ii++) {
|
2012-12-06 17:20:38 +00:00
|
|
|
if (!(ipdef->nranges || ipdef->nhosts)) {
|
|
|
|
char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
|
|
|
|
if (!bridgeaddr)
|
|
|
|
goto cleanup;
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferAsprintf(&configbuf,
|
|
|
|
"dhcp-range=%s,ra-only\n", bridgeaddr);
|
2012-12-06 17:20:38 +00:00
|
|
|
VIR_FREE(bridgeaddr);
|
|
|
|
}
|
2011-03-11 17:07:09 +00:00
|
|
|
}
|
Convert virNetwork to use virSocketAddr everywhere
Instead of storing the IP address string in virNetwork related
structs, store the parsed virSocketAddr. This will make it
easier to add IPv6 support in the future, by letting driver
code directly check what address family is present
* src/conf/network_conf.c, src/conf/network_conf.h,
src/network/bridge_driver.c: Convert to use virSocketAddr
in virNetwork, instead of char *.
* src/util/bridge.c, src/util/bridge.h,
src/util/dnsmasq.c, src/util/dnsmasq.h,
src/util/iptables.c, src/util/iptables.h: Convert to
take a virSocketAddr instead of char * for any IP
address parameters
* src/util/network.h: Add macros to determine if an address
is set, and what address family is set.
2010-10-21 12:14:33 +00:00
|
|
|
}
|
2009-09-21 20:50:25 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
if (!(*configstr = virBufferContentAndReset(&configbuf)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-12-10 18:54:48 +00:00
|
|
|
ret = 0;
|
2012-12-06 17:20:38 +00:00
|
|
|
|
2010-12-10 18:54:48 +00:00
|
|
|
cleanup:
|
2012-12-06 17:20:39 +00:00
|
|
|
virBufferFreeAndReset(&configbuf);
|
2012-02-01 09:22:21 +00:00
|
|
|
VIR_FREE(record);
|
|
|
|
VIR_FREE(recordPort);
|
|
|
|
VIR_FREE(recordWeight);
|
|
|
|
VIR_FREE(recordPriority);
|
2010-12-10 18:54:48 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
/* build the dnsmasq command line */
|
2013-01-30 12:21:28 +00:00
|
|
|
static int ATTRIBUTE_NONNULL(2)
|
|
|
|
networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
|
|
|
|
virCommandPtr *cmdout,
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
char *pidfile, dnsmasqContext *dctx,
|
|
|
|
dnsmasqCapsPtr caps)
|
2008-10-10 13:57:13 +00:00
|
|
|
{
|
2010-12-10 18:54:48 +00:00
|
|
|
virCommandPtr cmd = NULL;
|
2012-12-06 17:20:38 +00:00
|
|
|
int ret = -1;
|
2012-12-06 17:20:39 +00:00
|
|
|
char *configfile = NULL;
|
|
|
|
char *configstr = NULL;
|
2009-01-20 22:36:10 +00:00
|
|
|
|
|
|
|
network->dnsmasqPid = -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
if (networkDnsmasqConfContents(network, pidfile, &configstr, dctx, caps) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (!configstr)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* construct the filename */
|
|
|
|
if (!(configfile = networkDnsmasqConfigFileName(network->def->name))) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write the file */
|
|
|
|
if (virFileWriteStr(configfile, configstr, 0600) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("couldn't write dnsmasq config file '%s'"),
|
|
|
|
configfile);
|
2011-06-24 10:04:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:39 +00:00
|
|
|
cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
|
|
|
|
virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
|
2013-01-30 12:21:28 +00:00
|
|
|
*cmdout = cmd;
|
2011-06-24 10:04:38 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkStartDhcpDaemon(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
2011-06-24 10:04:38 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
char *pidfile = NULL;
|
|
|
|
int ret = -1;
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
dnsmasqContext *dctx = NULL;
|
2011-06-24 10:04:38 +00:00
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) {
|
2012-12-06 17:20:38 +00:00
|
|
|
/* no IP addresses, so we don't need to run */
|
2012-08-20 04:59:46 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virFileMakePath(driverState->pidDir) < 0) {
|
2011-07-05 21:02:53 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 22:36:10 +00:00
|
|
|
_("cannot create directory %s"),
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->pidDir);
|
2010-12-10 18:54:48 +00:00
|
|
|
goto cleanup;
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virFileMakePath(driverState->stateDir) < 0) {
|
2011-07-05 21:02:53 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 22:36:10 +00:00
|
|
|
_("cannot create directory %s"),
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->stateDir);
|
2010-12-10 18:54:48 +00:00
|
|
|
goto cleanup;
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if (!(pidfile = virPidFileBuildPath(driverState->pidDir,
|
|
|
|
network->def->name))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2010-12-10 18:54:48 +00:00
|
|
|
goto cleanup;
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virFileMakePath(driverState->dnsmasqStateDir) < 0) {
|
2011-07-05 21:02:53 +00:00
|
|
|
virReportSystemError(errno,
|
2011-04-23 12:28:44 +00:00
|
|
|
_("cannot create directory %s"),
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->dnsmasqStateDir);
|
2011-04-23 12:28:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
dctx = dnsmasqContextNew(network->def->name, driverState->dnsmasqStateDir);
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
if (dctx == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
dnsmasqCapsRefresh(&driver->dnsmasqCaps, false);
|
|
|
|
|
|
|
|
ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile,
|
|
|
|
dctx, driver->dnsmasqCaps);
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = dnsmasqSave(dctx);
|
|
|
|
if (ret < 0)
|
2010-12-10 18:54:48 +00:00
|
|
|
goto cleanup;
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2011-07-23 21:24:21 +00:00
|
|
|
ret = virCommandRun(cmd, NULL);
|
|
|
|
if (ret < 0) {
|
2009-01-20 22:36:10 +00:00
|
|
|
goto cleanup;
|
2011-07-23 21:24:21 +00:00
|
|
|
}
|
2009-01-20 22:36:10 +00:00
|
|
|
|
|
|
|
/*
|
2010-12-10 18:54:48 +00:00
|
|
|
* There really is no race here - when dnsmasq daemonizes, its
|
|
|
|
* leader process stays around until its child has actually
|
|
|
|
* written its pidfile. So by time virCommandRun exits it has
|
|
|
|
* waitpid'd and guaranteed the proess has started and written a
|
|
|
|
* pid
|
2009-01-20 22:36:10 +00:00
|
|
|
*/
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
ret = virPidFileRead(driverState->pidDir, network->def->name,
|
2011-07-25 18:11:38 +00:00
|
|
|
&network->dnsmasqPid);
|
|
|
|
if (ret < 0)
|
2009-01-20 22:36:10 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(pidfile);
|
2010-12-10 18:54:48 +00:00
|
|
|
virCommandFree(cmd);
|
network: Fix dnsmasq hostsfile creation logic and related tests
networkSaveDnsmasqHostsfile was added in 8fa9c2214247 (Apr 2010).
It has a force flag. If the dnsmasq hostsfile already exists force
needs to be true to overwrite it. networkBuildDnsmasqArgv sets force
to false, networkDefine sets it to true. This results in the
hostsfile being written only in networkDefine in the common case.
If no error occurred networkSaveDnsmasqHostsfile returns true and
networkBuildDnsmasqArgv adds the --dhcp-hostsfile to the dnsmasq
command line.
networkSaveDnsmasqHostsfile was changed in 89ae9849f744 (24 Jun 2011)
to return a new dnsmasqContext instead of reusing one. This change broke
the logic of the force flag as now networkSaveDnsmasqHostsfile returns
NULL on error, but the early return -- if force was not set and the
hostsfile exists -- returns 0. This turned the early return in an error
case and networkBuildDnsmasqArgv didn't add the --dhcp-hostsfile option
anymore if the hostsfile already exists. It did because networkDefine
created the hostsfile already.
Then 9d4e2845d498 fixed the return 0 case in networkSaveDnsmasqHostsfile
but didn't apply the force option correctly to the new addnhosts file.
Now force doesn't control an early return anymore, but influences the
handling of the hostsfile context creation and dnsmasqSave is always
called now. This commit also added test cases that reveal several
problems. First, the tests now calls functions that try to write the
dnsmasq config files to disk. If someone runs this tests as root this
might overwrite actively used dnsmasq config files, this is a no-go. Also
the tests depend on configure --localstatedir, this needs to be fixed as
well, because it makes the tests fail when localstatedir is different
from /var.
This patch does several things to fix this:
1) Move dnsmasqContext creation and saving out of networkBuildDnsmasqArgv
to the caller to separate the command line generation from the config
file writing. This makes the command line generation testable without the
risk of interfering with system files, because the tests just don't call
dnsmasqSave.
2) This refactoring of networkSaveDnsmasqHostsfile makes the force flag
useless as the saving happens somewhere else now. This fixes the wrong
usage of the force flag in combination with then newly added addnhosts
file by removing the force flag.
3) Adapt the wrong test cases to the correct behavior, by adding the
missing --dhcp-hostsfile option. Both affected tests contain DHCP host
elements but missed the necessary --dhcp-hostsfile option.
4) Rename networkSaveDnsmasqHostsfile to networkBuildDnsmasqHostsfile,
because it doesn't save the dnsmasqContext anymore.
5) Move all directory creations in dnsmasq context handling code from
the *New functions to dnsmasqSave to avoid directory creations in system
paths in the test cases.
6) Now that networkBuildDnsmasqArgv doesn't create the dnsmasqContext
anymore the test case can create one with the localstatedir that is
expected by the tests instead of the configure --localstatedir given one.
2011-06-28 11:07:59 +00:00
|
|
|
dnsmasqContextFree(dctx);
|
2008-10-10 13:57:13 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
/* networkRefreshDhcpDaemon:
|
|
|
|
* Update dnsmasq config files, then send a SIGHUP so that it rereads
|
2012-12-06 17:20:38 +00:00
|
|
|
* them. This only works for the dhcp-hostsfile and the
|
|
|
|
* addn-hosts file.
|
2012-08-20 04:59:46 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
2010-12-20 06:14:11 +00:00
|
|
|
static int
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkRefreshDhcpDaemon(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
2010-12-20 06:14:11 +00:00
|
|
|
{
|
2011-07-05 21:02:53 +00:00
|
|
|
int ret = -1, ii;
|
2012-12-06 17:20:38 +00:00
|
|
|
virNetworkIpDefPtr ipdef, ipv4def, ipv6def;
|
2012-08-20 04:59:46 +00:00
|
|
|
dnsmasqContext *dctx = NULL;
|
2010-12-20 06:14:11 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* if no IP addresses specified, nothing to do */
|
2012-12-14 17:44:03 +00:00
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
|
2012-12-06 17:20:38 +00:00
|
|
|
return 0;
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
/* if there's no running dnsmasq, just start it */
|
|
|
|
if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0))
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
return networkStartDhcpDaemon(driver, network);
|
2010-12-20 06:14:11 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
VIR_INFO("Refreshing dnsmasq for network %s", network->def->bridge);
|
2013-05-02 17:59:52 +00:00
|
|
|
if (!(dctx = dnsmasqContextNew(network->def->name,
|
|
|
|
driverState->dnsmasqStateDir))) {
|
2012-12-06 17:20:38 +00:00
|
|
|
goto cleanup;
|
2013-05-02 17:59:52 +00:00
|
|
|
}
|
2012-12-06 17:20:38 +00:00
|
|
|
|
|
|
|
/* Look for first IPv4 address that has dhcp defined.
|
|
|
|
* We only support dhcp-host config on one IPv4 subnetwork
|
|
|
|
* and on one IPv6 subnetwork.
|
|
|
|
*/
|
|
|
|
ipv4def = NULL;
|
2012-08-20 04:59:46 +00:00
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
|
|
|
ii++) {
|
2012-12-06 17:20:38 +00:00
|
|
|
if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
|
|
|
|
ipv4def = ipdef;
|
2011-03-18 17:05:08 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
ipv6def = NULL;
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
|
|
|
|
ii++) {
|
|
|
|
if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
|
|
|
|
ipv6def = ipdef;
|
2010-12-20 06:14:11 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (ipv6def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv6def) < 0))
|
|
|
|
goto cleanup;
|
2012-08-20 04:59:46 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (networkBuildDnsmasqHostsList(dctx, &network->def->dns) < 0)
|
2012-08-20 04:59:46 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((ret = dnsmasqSave(dctx)) < 0)
|
2010-12-20 06:14:11 +00:00
|
|
|
goto cleanup;
|
2012-08-20 04:59:46 +00:00
|
|
|
|
|
|
|
ret = kill(network->dnsmasqPid, SIGHUP);
|
|
|
|
cleanup:
|
|
|
|
dnsmasqContextFree(dctx);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* networkRestartDhcpDaemon:
|
|
|
|
*
|
|
|
|
* kill and restart dnsmasq, in order to update any config that is on
|
|
|
|
* the dnsmasq commandline (and any placed in separate config files).
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
static int
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkRestartDhcpDaemon(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
2012-08-20 04:59:46 +00:00
|
|
|
{
|
|
|
|
/* if there is a running dnsmasq, kill it */
|
|
|
|
if (network->dnsmasqPid > 0) {
|
|
|
|
networkKillDaemon(network->dnsmasqPid, "dnsmasq",
|
|
|
|
network->def->name);
|
|
|
|
network->dnsmasqPid = -1;
|
2010-12-20 06:14:11 +00:00
|
|
|
}
|
2012-08-20 04:59:46 +00:00
|
|
|
/* now start dnsmasq if it should be started */
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
return networkStartDhcpDaemon(driver, network);
|
2012-08-20 04:59:46 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
static char radvd1[] = " AdvOtherConfigFlag off;\n\n";
|
|
|
|
static char radvd2[] = " AdvAutonomous off;\n";
|
|
|
|
static char radvd3[] = " AdvOnLink on;\n"
|
|
|
|
" AdvAutonomous on;\n"
|
|
|
|
" AdvRouterAddr off;\n";
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
static int
|
|
|
|
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
|
|
|
|
{
|
2012-10-15 15:08:19 +00:00
|
|
|
virBuffer configbuf = VIR_BUFFER_INITIALIZER;
|
2012-08-20 04:59:46 +00:00
|
|
|
int ret = -1, ii;
|
|
|
|
virNetworkIpDefPtr ipdef;
|
2012-12-06 17:20:38 +00:00
|
|
|
bool v6present = false, dhcp6 = false;
|
2012-08-20 04:59:46 +00:00
|
|
|
|
|
|
|
*configstr = NULL;
|
2010-12-20 06:14:11 +00:00
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* Check if DHCPv6 is needed */
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
|
|
|
|
ii++) {
|
|
|
|
v6present = true;
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
dhcp6 = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are no IPv6 addresses, then we are done */
|
|
|
|
if (!v6present) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
/* create radvd config file appropriate for this network;
|
|
|
|
* IgnoreIfMissing allows radvd to start even when the bridge is down
|
|
|
|
*/
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&configbuf, "interface %s\n"
|
2010-12-20 06:14:11 +00:00
|
|
|
"{\n"
|
|
|
|
" AdvSendAdvert on;\n"
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
" IgnoreIfMissing on;\n"
|
2012-12-06 17:20:38 +00:00
|
|
|
" AdvManagedFlag %s;\n"
|
|
|
|
"%s",
|
|
|
|
network->def->bridge,
|
|
|
|
dhcp6 ? "on" : "off",
|
|
|
|
dhcp6 ? "\n" : radvd1);
|
2012-08-20 04:59:46 +00:00
|
|
|
|
|
|
|
/* add a section for each IPv6 address in the config */
|
2010-12-20 06:14:11 +00:00
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
|
|
|
|
ii++) {
|
|
|
|
int prefix;
|
|
|
|
char *netaddr;
|
|
|
|
|
|
|
|
prefix = virNetworkIpDefPrefix(ipdef);
|
|
|
|
if (prefix < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("bridge '%s' has an invalid prefix"),
|
|
|
|
network->def->bridge);
|
2010-12-20 06:14:11 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
|
2010-12-20 06:14:11 +00:00
|
|
|
goto cleanup;
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&configbuf,
|
2010-12-20 06:14:11 +00:00
|
|
|
" prefix %s/%d\n"
|
2012-12-06 17:20:38 +00:00
|
|
|
" {\n%s };\n",
|
|
|
|
netaddr, prefix,
|
|
|
|
dhcp6 ? radvd2 : radvd3);
|
2010-12-20 06:14:11 +00:00
|
|
|
VIR_FREE(netaddr);
|
|
|
|
}
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
/* only create the string if we found at least one IPv6 address */
|
|
|
|
if (v6present) {
|
|
|
|
virBufferAddLit(&configbuf, "};\n");
|
2010-12-20 06:14:11 +00:00
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
if (virBufferError(&configbuf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (!(*configstr = virBufferContentAndReset(&configbuf))) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-12-20 06:14:11 +00:00
|
|
|
}
|
2012-08-20 04:59:46 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virBufferFreeAndReset(&configbuf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write file and return it's name (which must be freed by caller) */
|
|
|
|
static int
|
|
|
|
networkRadvdConfWrite(virNetworkObjPtr network, char **configFile)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *configStr = NULL;
|
|
|
|
char *myConfigFile = NULL;
|
|
|
|
|
|
|
|
if (!configFile)
|
|
|
|
configFile = &myConfigFile;
|
|
|
|
|
|
|
|
*configFile = NULL;
|
|
|
|
|
|
|
|
if (networkRadvdConfContents(network, &configStr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!configStr) {
|
|
|
|
ret = 0;
|
2010-12-20 06:14:11 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* construct the filename */
|
2012-08-20 04:59:46 +00:00
|
|
|
if (!(*configFile = networkRadvdConfigFileName(network->def->name))) {
|
2010-12-20 06:14:11 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* write the file */
|
2012-08-20 04:59:46 +00:00
|
|
|
if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
|
2010-12-20 06:14:11 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("couldn't write radvd config file '%s'"),
|
2012-08-20 04:59:46 +00:00
|
|
|
*configFile);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(configStr);
|
|
|
|
VIR_FREE(myConfigFile);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-12-06 17:20:38 +00:00
|
|
|
networkStartRadvd(struct network_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
virNetworkObjPtr network)
|
2012-08-20 04:59:46 +00:00
|
|
|
{
|
|
|
|
char *pidfile = NULL;
|
|
|
|
char *radvdpidbase = NULL;
|
|
|
|
char *configfile = NULL;
|
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
network->radvdPid = -1;
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* Is dnsmasq handling RA? */
|
2012-12-06 17:20:39 +00:00
|
|
|
if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
|
2012-12-06 17:20:38 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
|
|
|
|
/* no IPv6 addresses, so we don't need to run radvd */
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virFileIsExecutable(RADVD)) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot find %s - "
|
|
|
|
"Possibly the package isn't installed"),
|
|
|
|
RADVD);
|
2010-12-20 06:14:11 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virFileMakePath(driverState->pidDir) < 0) {
|
2012-08-20 04:59:46 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot create directory %s"),
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->pidDir);
|
2012-08-20 04:59:46 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virFileMakePath(driverState->radvdStateDir) < 0) {
|
2012-08-20 04:59:46 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot create directory %s"),
|
2013-05-02 17:59:52 +00:00
|
|
|
driverState->radvdStateDir);
|
2012-08-20 04:59:46 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* construct pidfile name */
|
|
|
|
if (!(radvdpidbase = networkRadvdPidfileBasename(network->def->name))) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-05-02 17:59:52 +00:00
|
|
|
if (!(pidfile = virPidFileBuildPath(driverState->pidDir, radvdpidbase))) {
|
2012-08-20 04:59:46 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (networkRadvdConfWrite(network, &configfile) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-12-20 06:14:11 +00:00
|
|
|
/* prevent radvd from daemonizing itself with "--debug 1", and use
|
|
|
|
* a dummy pidfile name - virCommand will create the pidfile we
|
|
|
|
* want to use (this is necessary because radvd's internal
|
|
|
|
* daemonization and pidfile creation causes a race, and the
|
2011-08-05 13:13:12 +00:00
|
|
|
* virPidFileRead() below will fail if we use them).
|
2010-12-20 06:14:11 +00:00
|
|
|
* Unfortunately, it isn't possible to tell radvd to not create
|
|
|
|
* its own pidfile, so we just let it do so, with a slightly
|
|
|
|
* different name. Unused, but harmless.
|
|
|
|
*/
|
|
|
|
cmd = virCommandNewArgList(RADVD, "--debug", "1",
|
|
|
|
"--config", configfile,
|
|
|
|
"--pidfile", NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%s-bin", pidfile);
|
|
|
|
|
|
|
|
virCommandSetPidFile(cmd, pidfile);
|
|
|
|
virCommandDaemonize(cmd);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virPidFileRead(driverState->pidDir, radvdpidbase, &network->radvdPid) < 0)
|
2010-12-20 06:14:11 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virCommandFree(cmd);
|
|
|
|
VIR_FREE(configfile);
|
|
|
|
VIR_FREE(radvdpidbase);
|
|
|
|
VIR_FREE(pidfile);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
static int
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkRefreshRadvd(struct network_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
virNetworkObjPtr network)
|
2012-08-20 04:59:46 +00:00
|
|
|
{
|
2012-12-06 17:20:38 +00:00
|
|
|
char *radvdpidbase;
|
|
|
|
|
|
|
|
/* Is dnsmasq handling RA? */
|
|
|
|
if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
|
|
|
|
if (network->radvdPid <= 0)
|
|
|
|
return 0;
|
|
|
|
/* radvd should not be running but in case it is */
|
|
|
|
if ((networkKillDaemon(network->radvdPid, "radvd",
|
|
|
|
network->def->name) >= 0) &&
|
|
|
|
((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
|
|
|
|
!= NULL)) {
|
2013-05-02 17:59:52 +00:00
|
|
|
virPidFileDelete(driverState->pidDir, radvdpidbase);
|
2012-12-06 17:20:38 +00:00
|
|
|
VIR_FREE(radvdpidbase);
|
|
|
|
}
|
|
|
|
network->radvdPid = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-20 04:59:46 +00:00
|
|
|
/* if there's no running radvd, just start it */
|
|
|
|
if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
|
2012-12-06 17:20:38 +00:00
|
|
|
return networkStartRadvd(driver, network);
|
2012-08-20 04:59:46 +00:00
|
|
|
|
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
|
|
|
|
/* no IPv6 addresses, so we don't need to run radvd */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (networkRadvdConfWrite(network, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return kill(network->radvdPid, SIGHUP);
|
|
|
|
}
|
|
|
|
|
2012-09-16 20:42:01 +00:00
|
|
|
#if 0
|
|
|
|
/* currently unused, so it causes a build error unless we #if it out */
|
2012-08-20 04:59:46 +00:00
|
|
|
static int
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkRestartRadvd(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
2012-08-20 04:59:46 +00:00
|
|
|
{
|
|
|
|
char *radvdpidbase;
|
|
|
|
|
|
|
|
/* if there is a running radvd, kill it */
|
|
|
|
if (network->radvdPid > 0) {
|
|
|
|
/* essentially ignore errors from the following two functions,
|
|
|
|
* since there's really no better recovery to be done than to
|
|
|
|
* just push ahead (and that may be exactly what's needed).
|
|
|
|
*/
|
2012-12-06 17:20:38 +00:00
|
|
|
if ((networkKillDaemon(network->radvdPid, "radvd",
|
2012-08-20 04:59:46 +00:00
|
|
|
network->def->name) >= 0) &&
|
|
|
|
((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
|
|
|
|
!= NULL)) {
|
2013-05-02 17:59:52 +00:00
|
|
|
virPidFileDelete(driverState->pidDir, radvdpidbase);
|
2012-08-20 04:59:46 +00:00
|
|
|
VIR_FREE(radvdpidbase);
|
|
|
|
}
|
|
|
|
network->radvdPid = -1;
|
|
|
|
}
|
|
|
|
/* now start radvd if it should be started */
|
|
|
|
return networkStartRadvd(network);
|
|
|
|
}
|
|
|
|
#endif /* #if 0 */
|
|
|
|
|
2012-09-17 01:22:27 +00:00
|
|
|
/* SIGHUP/restart any dnsmasq or radvd daemons.
|
|
|
|
* This should be called when libvirtd is restarted.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
networkRefreshDaemons(struct network_driver *driver)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
VIR_INFO("Refreshing network daemons");
|
|
|
|
|
|
|
|
for (i = 0 ; i < driver->networks.count ; i++) {
|
|
|
|
virNetworkObjPtr network = driver->networks.objs[i];
|
|
|
|
|
|
|
|
virNetworkObjLock(network);
|
|
|
|
if (virNetworkObjIsActive(network) &&
|
2012-11-08 02:16:17 +00:00
|
|
|
((network->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
|
|
|
|
(network->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
|
|
|
|
(network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
|
2012-09-17 01:22:27 +00:00
|
|
|
/* Only the three L3 network types that are configured by
|
|
|
|
* libvirt will have a dnsmasq or radvd daemon associated
|
|
|
|
* with them. Here we send a SIGHUP to an existing
|
|
|
|
* dnsmasq and/or radvd, or restart them if they've
|
|
|
|
* disappeared.
|
|
|
|
*/
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkRefreshDhcpDaemon(driver, network);
|
|
|
|
networkRefreshRadvd(driver, network);
|
2012-09-17 01:22:27 +00:00
|
|
|
}
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
static int
|
2010-02-04 20:02:58 +00:00
|
|
|
networkAddMasqueradingIptablesRules(struct network_driver *driver,
|
2010-12-10 21:04:37 +00:00
|
|
|
virNetworkObjPtr network,
|
|
|
|
virNetworkIpDefPtr ipdef)
|
2010-11-17 18:36:19 +00:00
|
|
|
{
|
|
|
|
int prefix = virNetworkIpDefPrefix(ipdef);
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
|
2010-11-30 19:35:58 +00:00
|
|
|
|
|
|
|
if (prefix < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid prefix or netmask for '%s'"),
|
|
|
|
network->def->bridge);
|
2010-11-30 19:35:58 +00:00
|
|
|
goto masqerr1;
|
|
|
|
}
|
2010-12-14 20:01:10 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/* allow forwarding packets from the bridge interface */
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardAllowOut(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2010-12-14 20:01:10 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow forwarding from '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto masqerr1;
|
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* allow forwarding packets to the bridge interface if they are
|
|
|
|
* part of an existing connection
|
|
|
|
*/
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardAllowRelatedIn(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2010-12-14 20:01:10 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow forwarding to '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto masqerr2;
|
|
|
|
}
|
|
|
|
|
2010-06-10 16:50:38 +00:00
|
|
|
/*
|
|
|
|
* Enable masquerading.
|
|
|
|
*
|
|
|
|
* We need to end up with 3 rules in the table in this order
|
|
|
|
*
|
2010-07-28 14:05:55 +00:00
|
|
|
* 1. protocol=tcp with sport mapping restriction
|
|
|
|
* 2. protocol=udp with sport mapping restriction
|
2010-06-10 16:50:38 +00:00
|
|
|
* 3. generic any protocol
|
|
|
|
*
|
|
|
|
* The sport mappings are required, because default IPtables
|
2010-07-28 14:05:55 +00:00
|
|
|
* MASQUERADE maintain port numbers unchanged where possible.
|
2010-06-10 16:50:38 +00:00
|
|
|
*
|
|
|
|
* NFS can be configured to only "trust" port numbers < 1023.
|
|
|
|
*
|
|
|
|
* Guests using NAT thus need to be prevented from having port
|
|
|
|
* numbers < 1023, otherwise they can bypass the NFS "security"
|
|
|
|
* check on the source port number.
|
|
|
|
*
|
|
|
|
* Since we use '--insert' to add rules to the header of the
|
|
|
|
* chain, we actually need to add them in the reverse of the
|
|
|
|
* order just mentioned !
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* First the generic masquerade rule for other protocols */
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardMasquerade(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-12-14 20:01:10 +00:00
|
|
|
NULL) < 0) {
|
2013-05-02 11:33:55 +00:00
|
|
|
if (forwardIf)
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to enable masquerading to %s"),
|
|
|
|
forwardIf);
|
|
|
|
else
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
|
|
|
|
_("failed to add iptables rule to enable masquerading"));
|
2008-10-10 13:57:13 +00:00
|
|
|
goto masqerr3;
|
|
|
|
}
|
|
|
|
|
2010-06-10 16:50:38 +00:00
|
|
|
/* UDP with a source port restriction */
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardMasquerade(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-12-14 20:01:10 +00:00
|
|
|
"udp") < 0) {
|
2013-05-02 11:33:55 +00:00
|
|
|
if (forwardIf)
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to enable UDP masquerading to %s"),
|
|
|
|
forwardIf);
|
|
|
|
else
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
|
|
|
|
_("failed to add iptables rule to enable UDP masquerading"));
|
2010-06-10 16:50:38 +00:00
|
|
|
goto masqerr4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TCP with a source port restriction */
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardMasquerade(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-12-14 20:01:10 +00:00
|
|
|
"tcp") < 0) {
|
2013-05-02 11:33:55 +00:00
|
|
|
if (forwardIf)
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to enable TCP masquerading to %s"),
|
|
|
|
forwardIf);
|
|
|
|
else
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
|
|
|
|
_("failed to add iptables rule to enable TCP masquerading"));
|
2010-06-10 16:50:38 +00:00
|
|
|
goto masqerr5;
|
|
|
|
}
|
|
|
|
|
2010-12-15 06:49:29 +00:00
|
|
|
return 0;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-06-10 16:50:38 +00:00
|
|
|
masqerr5:
|
|
|
|
iptablesRemoveForwardMasquerade(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-06-10 16:50:38 +00:00
|
|
|
"udp");
|
|
|
|
masqerr4:
|
|
|
|
iptablesRemoveForwardMasquerade(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-06-10 16:50:38 +00:00
|
|
|
NULL);
|
2008-10-10 13:57:13 +00:00
|
|
|
masqerr3:
|
|
|
|
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2010-10-25 14:10:33 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2008-10-10 13:57:13 +00:00
|
|
|
masqerr2:
|
|
|
|
iptablesRemoveForwardAllowOut(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2008-10-10 13:57:13 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2008-10-10 13:57:13 +00:00
|
|
|
masqerr1:
|
2010-12-15 06:49:29 +00:00
|
|
|
return -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
static void
|
|
|
|
networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network,
|
|
|
|
virNetworkIpDefPtr ipdef)
|
|
|
|
{
|
|
|
|
int prefix = virNetworkIpDefPrefix(ipdef);
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
|
2010-12-10 21:04:37 +00:00
|
|
|
|
|
|
|
if (prefix >= 0) {
|
|
|
|
iptablesRemoveForwardMasquerade(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-12-10 21:04:37 +00:00
|
|
|
"tcp");
|
|
|
|
iptablesRemoveForwardMasquerade(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-12-10 21:04:37 +00:00
|
|
|
"udp");
|
|
|
|
iptablesRemoveForwardMasquerade(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf,
|
2013-02-19 10:44:16 +00:00
|
|
|
&network->def->forward.addr,
|
|
|
|
&network->def->forward.port,
|
2010-12-10 21:04:37 +00:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2010-12-10 21:04:37 +00:00
|
|
|
iptablesRemoveForwardAllowOut(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2010-12-10 21:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
static int
|
2010-02-04 20:02:58 +00:00
|
|
|
networkAddRoutingIptablesRules(struct network_driver *driver,
|
2010-11-17 18:36:19 +00:00
|
|
|
virNetworkObjPtr network,
|
2010-12-10 21:04:37 +00:00
|
|
|
virNetworkIpDefPtr ipdef)
|
|
|
|
{
|
2010-11-17 18:36:19 +00:00
|
|
|
int prefix = virNetworkIpDefPrefix(ipdef);
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
|
2010-11-30 19:35:58 +00:00
|
|
|
|
|
|
|
if (prefix < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid prefix or netmask for '%s'"),
|
|
|
|
network->def->bridge);
|
2010-11-30 19:35:58 +00:00
|
|
|
goto routeerr1;
|
|
|
|
}
|
2010-12-14 20:01:10 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/* allow routing packets from the bridge interface */
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardAllowOut(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2010-12-14 20:01:10 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow routing from '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto routeerr1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allow routing packets to the bridge interface */
|
2010-12-14 20:01:10 +00:00
|
|
|
if (iptablesAddForwardAllowIn(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2010-12-14 20:01:10 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow routing to '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto routeerr2;
|
|
|
|
}
|
|
|
|
|
2010-12-15 06:49:29 +00:00
|
|
|
return 0;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
routeerr2:
|
2008-10-10 13:57:13 +00:00
|
|
|
iptablesRemoveForwardAllowOut(driver->iptables,
|
2010-11-17 18:36:19 +00:00
|
|
|
&ipdef->address,
|
2010-11-30 19:35:58 +00:00
|
|
|
prefix,
|
2008-10-10 13:57:13 +00:00
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2010-12-10 21:04:37 +00:00
|
|
|
routeerr1:
|
2010-12-15 06:49:29 +00:00
|
|
|
return -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
static void
|
|
|
|
networkRemoveRoutingIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network,
|
|
|
|
virNetworkIpDefPtr ipdef)
|
|
|
|
{
|
|
|
|
int prefix = virNetworkIpDefPrefix(ipdef);
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
|
2010-12-10 21:04:37 +00:00
|
|
|
|
|
|
|
if (prefix >= 0) {
|
|
|
|
iptablesRemoveForwardAllowIn(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2010-12-10 21:04:37 +00:00
|
|
|
|
|
|
|
iptablesRemoveForwardAllowOut(driver->iptables,
|
|
|
|
&ipdef->address,
|
|
|
|
prefix,
|
|
|
|
network->def->bridge,
|
conf: support abstracted interface info in network XML
The network XML is updated in the following ways:
1) The <forward> element can now contain a list of forward interfaces:
<forward .... >
<interface dev='eth10'/>
<interface dev='eth11'/>
<interface dev='eth12'/>
<interface dev='eth13'/>
</forward>
The first of these takes the place of the dev attribute that is
normally in <forward> - when defining a network you can specify
either one, and on output both will be present. If you specify
both on input, they must match.
2) In addition to forward modes of 'nat' and 'route', these new modes
are supported:
private, passthrough, vepa - when this network is referenced by a
domain's interface, it will have the same effect as if the
interface had been defined as type='direct', e.g.:
<interface type='direct'>
<source mode='${mode}' dev='${dev}>
...
</interface>
where ${mode} is one of the three new modes, and ${dev} is an interface
selected from the list given in <forward>.
bridge - if a <forward> dev (or multiple devs) is defined, and
forward mode is 'bridge' this is just like the modes 'private',
'passthrough', and 'vepa' above. If there is no forward dev
specified but a bridge name is given (e.g. "<bridge
name='br0'/>"), then guest interfaces using this network will use
libvirt's "host bridge" mode, equivalent to this:
<interface type='bridge'>
<source bridge='${bridge-name}'/>
...
</interface>
3) A network can have multiple <portgroup> elements, which may be
selected by the guest interface definition (by adding
"portgroup='${name}'" in the <source> element along with the
network name). Currently a portgroup can only contain a
virtportprofile, but the intent is that other configuration items
may be put there int the future (e.g. bandwidth config). When
building a guest's interface, if the <interface> XML itself has no
virtportprofile, and if the requested network has a portgroup with
a name matching the name given in the <interface> (or if one of the
network's portgroups is marked with the "default='yes'" attribute),
the virtportprofile from that portgroup will be used by the
interface.
4) A network can have a virtportprofile defined at the top level,
which will be used by a guest interface when connecting in one of
the 'direct' modes if the guest interface XML itself hasn't
specified any virtportprofile, and if there are also no matching
portgroups on the network.
2011-07-20 03:01:09 +00:00
|
|
|
forwardIf);
|
2010-12-10 21:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-03 16:13:36 +00:00
|
|
|
/* Add all once/network rules required for IPv6.
|
|
|
|
* If no IPv6 addresses are defined and <network ipv6='yes'> is
|
2012-12-06 17:20:38 +00:00
|
|
|
* specified, then allow IPv6 commuinications between virtual systems.
|
|
|
|
* If any IPv6 addresses are defined, then add the rules for regular operation.
|
2012-12-03 16:13:36 +00:00
|
|
|
*/
|
2010-12-16 20:50:01 +00:00
|
|
|
static int
|
|
|
|
networkAddGeneralIp6tablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
|
2012-12-03 16:13:36 +00:00
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
|
|
|
|
!network->def->ipv6nogw) {
|
2010-12-16 20:50:01 +00:00
|
|
|
return 0;
|
2012-12-03 16:13:36 +00:00
|
|
|
}
|
2010-12-16 20:50:01 +00:00
|
|
|
|
|
|
|
/* Catch all rules to block forwarding to/from bridges */
|
|
|
|
|
|
|
|
if (iptablesAddForwardRejectOut(driver->iptables, AF_INET6,
|
|
|
|
network->def->bridge) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add ip6tables rule to block outbound traffic from '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-16 20:50:01 +00:00
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iptablesAddForwardRejectIn(driver->iptables, AF_INET6,
|
|
|
|
network->def->bridge) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add ip6tables rule to block inbound traffic to '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-16 20:50:01 +00:00
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allow traffic between guests on the same bridge */
|
|
|
|
if (iptablesAddForwardAllowCross(driver->iptables, AF_INET6,
|
|
|
|
network->def->bridge) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add ip6tables rule to allow cross bridge traffic on '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-16 20:50:01 +00:00
|
|
|
goto err3;
|
|
|
|
}
|
|
|
|
|
2012-12-03 16:13:36 +00:00
|
|
|
/* if no IPv6 addresses are defined, we are done. */
|
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
|
|
|
|
return 0;
|
|
|
|
|
2011-01-31 20:31:57 +00:00
|
|
|
/* allow DNS over IPv6 */
|
|
|
|
if (iptablesAddTcpInput(driver->iptables, AF_INET6,
|
|
|
|
network->def->bridge, 53) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add ip6tables rule to allow DNS requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2011-01-31 20:31:57 +00:00
|
|
|
goto err4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iptablesAddUdpInput(driver->iptables, AF_INET6,
|
|
|
|
network->def->bridge, 53) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add ip6tables rule to allow DNS requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2011-01-31 20:31:57 +00:00
|
|
|
goto err5;
|
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
if (iptablesAddUdpInput(driver->iptables, AF_INET6,
|
|
|
|
network->def->bridge, 547) < 0) {
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add ip6tables rule to allow DHCP6 requests from '%s'"),
|
|
|
|
network->def->bridge);
|
|
|
|
goto err6;
|
|
|
|
}
|
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* unwind in reverse order from the point of failure */
|
2012-12-06 17:20:38 +00:00
|
|
|
err6:
|
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
|
2011-01-31 20:31:57 +00:00
|
|
|
err5:
|
|
|
|
iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
|
|
|
|
err4:
|
|
|
|
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6, network->def->bridge);
|
2010-12-16 20:50:01 +00:00
|
|
|
err3:
|
|
|
|
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET6, network->def->bridge);
|
|
|
|
err2:
|
|
|
|
iptablesRemoveForwardRejectOut(driver->iptables, AF_INET6, network->def->bridge);
|
|
|
|
err1:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
networkRemoveGeneralIp6tablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
2012-12-03 16:13:36 +00:00
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
|
2012-12-06 17:20:38 +00:00
|
|
|
!network->def->ipv6nogw) {
|
2010-12-16 20:50:01 +00:00
|
|
|
return;
|
2012-12-06 17:20:38 +00:00
|
|
|
}
|
2012-12-03 16:13:36 +00:00
|
|
|
if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
|
2012-12-06 17:20:38 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 547);
|
2012-12-03 16:13:36 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
|
|
|
|
iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
|
|
|
|
}
|
2010-12-16 20:50:01 +00:00
|
|
|
|
2012-12-03 16:13:36 +00:00
|
|
|
/* the following rules are there if no IPv6 address has been defined
|
|
|
|
* but network->def->ipv6nogw == true
|
|
|
|
*/
|
2010-12-16 20:50:01 +00:00
|
|
|
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6, network->def->bridge);
|
|
|
|
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET6, network->def->bridge);
|
|
|
|
iptablesRemoveForwardRejectOut(driver->iptables, AF_INET6, network->def->bridge);
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
static int
|
2010-12-10 21:04:37 +00:00
|
|
|
networkAddGeneralIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
int ii;
|
|
|
|
virNetworkIpDefPtr ipv4def;
|
|
|
|
|
|
|
|
/* First look for first IPv4 address that has dhcp or tftpboot defined. */
|
|
|
|
/* We support dhcp config on 1 IPv4 interface only. */
|
|
|
|
for (ii = 0;
|
|
|
|
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
|
|
|
ii++) {
|
|
|
|
if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
|
|
|
|
break;
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
/* allow DHCP requests through to dnsmasq */
|
2010-12-10 21:04:37 +00:00
|
|
|
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddTcpInput(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge, 67) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow DHCP requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddUdpInput(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge, 67) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow DHCP requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto err2;
|
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* If we are doing local DHCP service on this network, attempt to
|
|
|
|
* add a rule that will fixup the checksum of DHCP response
|
|
|
|
* packets back to the guests (but report failure without
|
|
|
|
* aborting, since not all iptables implementations support it).
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ipv4def && (ipv4def->nranges || ipv4def->nhosts) &&
|
|
|
|
(iptablesAddOutputFixUdpChecksum(driver->iptables,
|
|
|
|
network->def->bridge, 68) < 0)) {
|
|
|
|
VIR_WARN("Could not add rule to fixup DHCP response checksums "
|
|
|
|
"on network '%s'.", network->def->name);
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("May need to update iptables package & kernel to support CHECKSUM rule.");
|
2010-12-10 21:04:37 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/* allow DNS requests through to dnsmasq */
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddTcpInput(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge, 53) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow DNS requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto err3;
|
|
|
|
}
|
|
|
|
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddUdpInput(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge, 53) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow DNS requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto err4;
|
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* allow TFTP requests through to dnsmasq if necessary */
|
|
|
|
if (ipv4def && ipv4def->tftproot &&
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesAddUdpInput(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge, 69) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow TFTP requests from '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err5;
|
2010-06-19 18:08:26 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
/* Catch all rules to block forwarding to/from bridges */
|
|
|
|
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddForwardRejectOut(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to block outbound traffic from '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err6;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddForwardRejectIn(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to block inbound traffic to '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err7;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allow traffic between guests on the same bridge */
|
2010-12-08 19:09:25 +00:00
|
|
|
if (iptablesAddForwardAllowCross(driver->iptables, AF_INET,
|
|
|
|
network->def->bridge) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("failed to add iptables rule to allow cross bridge traffic on '%s'"),
|
|
|
|
network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err8;
|
2010-07-13 02:59:58 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
/* add IPv6 general rules, if needed */
|
|
|
|
if (networkAddGeneralIp6tablesRules(driver, network) < 0) {
|
|
|
|
goto err9;
|
|
|
|
}
|
|
|
|
|
2010-12-15 06:49:29 +00:00
|
|
|
return 0;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* unwind in reverse order from the point of failure */
|
2010-12-16 20:50:01 +00:00
|
|
|
err9:
|
|
|
|
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET, network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
err8:
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET, network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
err7:
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveForwardRejectOut(driver->iptables, AF_INET, network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
err6:
|
|
|
|
if (ipv4def && ipv4def->tftproot) {
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET, network->def->bridge, 69);
|
2010-06-19 18:08:26 +00:00
|
|
|
}
|
2010-12-10 21:04:37 +00:00
|
|
|
err5:
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET, network->def->bridge, 53);
|
2010-12-10 21:04:37 +00:00
|
|
|
err4:
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveTcpInput(driver->iptables, AF_INET, network->def->bridge, 53);
|
2010-12-10 21:04:37 +00:00
|
|
|
err3:
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET, network->def->bridge, 67);
|
2010-12-10 21:04:37 +00:00
|
|
|
err2:
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveTcpInput(driver->iptables, AF_INET, network->def->bridge, 67);
|
2010-12-10 21:04:37 +00:00
|
|
|
err1:
|
2010-12-15 06:49:29 +00:00
|
|
|
return -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-12-10 21:04:37 +00:00
|
|
|
networkRemoveGeneralIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
int ii;
|
|
|
|
virNetworkIpDefPtr ipv4def;
|
2010-11-17 18:36:19 +00:00
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
networkRemoveGeneralIp6tablesRules(driver, network);
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
for (ii = 0;
|
|
|
|
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
|
|
|
ii++) {
|
|
|
|
if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
|
|
|
|
break;
|
2010-07-13 02:59:58 +00:00
|
|
|
}
|
2010-11-30 19:35:58 +00:00
|
|
|
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET, network->def->bridge);
|
|
|
|
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET, network->def->bridge);
|
|
|
|
iptablesRemoveForwardRejectOut(driver->iptables, AF_INET, network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
if (ipv4def && ipv4def->tftproot) {
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET, network->def->bridge, 69);
|
2010-12-10 21:04:37 +00:00
|
|
|
}
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET, network->def->bridge, 53);
|
|
|
|
iptablesRemoveTcpInput(driver->iptables, AF_INET, network->def->bridge, 53);
|
2010-12-10 21:04:37 +00:00
|
|
|
if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) {
|
|
|
|
iptablesRemoveOutputFixUdpChecksum(driver->iptables,
|
|
|
|
network->def->bridge, 68);
|
|
|
|
}
|
2010-12-08 19:09:25 +00:00
|
|
|
iptablesRemoveUdpInput(driver->iptables, AF_INET, network->def->bridge, 67);
|
|
|
|
iptablesRemoveTcpInput(driver->iptables, AF_INET, network->def->bridge, 67);
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
static int
|
|
|
|
networkAddIpSpecificIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network,
|
|
|
|
virNetworkIpDefPtr ipdef)
|
|
|
|
{
|
2010-12-16 20:50:01 +00:00
|
|
|
/* NB: in the case of IPv6, routing rules are added when the
|
|
|
|
* forward mode is NAT. This is because IPv6 has no NAT.
|
|
|
|
*/
|
2010-12-10 21:04:37 +00:00
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) {
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
|
2010-12-16 20:50:01 +00:00
|
|
|
return networkAddMasqueradingIptablesRules(driver, network, ipdef);
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
|
2010-12-16 20:50:01 +00:00
|
|
|
return networkAddRoutingIptablesRules(driver, network, ipdef);
|
2012-11-08 02:16:17 +00:00
|
|
|
} else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
|
2010-12-16 20:50:01 +00:00
|
|
|
return networkAddRoutingIptablesRules(driver, network, ipdef);
|
|
|
|
}
|
2010-12-10 21:04:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
networkRemoveIpSpecificIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network,
|
|
|
|
virNetworkIpDefPtr ipdef)
|
|
|
|
{
|
2012-11-08 02:16:17 +00:00
|
|
|
if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) {
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
|
2010-12-16 20:50:01 +00:00
|
|
|
networkRemoveMasqueradingIptablesRules(driver, network, ipdef);
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
|
2010-12-16 20:50:01 +00:00
|
|
|
networkRemoveRoutingIptablesRules(driver, network, ipdef);
|
2012-11-08 02:16:17 +00:00
|
|
|
} else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
|
2010-12-10 21:04:37 +00:00
|
|
|
networkRemoveRoutingIptablesRules(driver, network, ipdef);
|
2010-12-16 20:50:01 +00:00
|
|
|
}
|
2010-12-10 21:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add all rules for all ip addresses (and general rules) on a network */
|
|
|
|
static int
|
|
|
|
networkAddIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
int ii;
|
|
|
|
virNetworkIpDefPtr ipdef;
|
2013-01-11 10:38:30 +00:00
|
|
|
virErrorPtr orig_error;
|
2010-12-10 21:04:37 +00:00
|
|
|
|
|
|
|
/* Add "once per network" rules */
|
|
|
|
if (networkAddGeneralIptablesRules(driver, network) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
|
|
|
ii++) {
|
|
|
|
/* Add address-specific iptables rules */
|
|
|
|
if (networkAddIpSpecificIptablesRules(driver, network, ipdef) < 0) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
2013-01-11 10:38:30 +00:00
|
|
|
/* store the previous error message before attempting removal of rules */
|
|
|
|
orig_error = virSaveLastError();
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* The final failed call to networkAddIpSpecificIptablesRules will
|
|
|
|
* have removed any rules it created, but we need to remove those
|
|
|
|
* added for previous IP addresses.
|
|
|
|
*/
|
|
|
|
while ((--ii >= 0) &&
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii))) {
|
|
|
|
networkRemoveIpSpecificIptablesRules(driver, network, ipdef);
|
|
|
|
}
|
|
|
|
networkRemoveGeneralIptablesRules(driver, network);
|
2013-01-11 10:38:30 +00:00
|
|
|
|
|
|
|
/* return the original error */
|
|
|
|
virSetError(orig_error);
|
2013-04-30 17:39:28 +00:00
|
|
|
virFreeError(orig_error);
|
2010-12-10 21:04:37 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove all rules for all ip addresses (and general rules) on a network */
|
|
|
|
static void
|
|
|
|
networkRemoveIptablesRules(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
int ii;
|
|
|
|
virNetworkIpDefPtr ipdef;
|
|
|
|
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
|
|
|
ii++) {
|
|
|
|
networkRemoveIpSpecificIptablesRules(driver, network, ipdef);
|
|
|
|
}
|
|
|
|
networkRemoveGeneralIptablesRules(driver, network);
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:27:17 +00:00
|
|
|
static void
|
|
|
|
networkReloadIptablesRules(struct network_driver *driver)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
maint: omit translation for all VIR_INFO
We were 31/73 on whether to translate; since less than 50% translated
and since VIR_INFO is less than VIR_WARN which also doesn't translate,
this makes sense.
* cfg.mk (sc_prohibit_gettext_markup): Add VIR_INFO, since it
falls between WARN and DEBUG.
* daemon/libvirtd.c (qemudDispatchSignalEvent, remoteCheckAccess)
(qemudDispatchServer): Adjust offenders.
* daemon/remote.c (remoteDispatchAuthPolkit): Likewise.
* src/network/bridge_driver.c (networkReloadIptablesRules)
(networkStartNetworkDaemon, networkShutdownNetworkDaemon)
(networkCreate, networkDefine, networkUndefine): Likewise.
* src/qemu/qemu_driver.c (qemudDomainDefine)
(qemudDomainUndefine): Likewise.
* src/storage/storage_driver.c (storagePoolCreate)
(storagePoolDefine, storagePoolUndefine, storagePoolStart)
(storagePoolDestroy, storagePoolDelete, storageVolumeCreateXML)
(storageVolumeCreateXMLFrom, storageVolumeDelete): Likewise.
* src/util/bridge.c (brProbeVnetHdr): Likewise.
* po/POTFILES.in: Drop src/util/bridge.c.
2011-05-11 15:08:44 +00:00
|
|
|
VIR_INFO("Reloading iptables rules");
|
2009-12-10 11:27:17 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < driver->networks.count ; i++) {
|
2011-12-06 20:13:50 +00:00
|
|
|
virNetworkObjPtr network = driver->networks.objs[i];
|
|
|
|
|
|
|
|
virNetworkObjLock(network);
|
|
|
|
if (virNetworkObjIsActive(network) &&
|
2012-11-08 02:16:17 +00:00
|
|
|
((network->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
|
|
|
|
(network->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
|
|
|
|
(network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
|
2011-12-06 20:13:50 +00:00
|
|
|
/* Only the three L3 network types that are configured by libvirt
|
|
|
|
* need to have iptables rules reloaded.
|
|
|
|
*/
|
|
|
|
networkRemoveIptablesRules(driver, network);
|
|
|
|
if (networkAddIptablesRules(driver, network) < 0) {
|
2010-12-10 21:04:37 +00:00
|
|
|
/* failed to add but already logged */
|
|
|
|
}
|
2009-12-10 11:27:17 +00:00
|
|
|
}
|
2011-12-06 20:13:50 +00:00
|
|
|
virNetworkObjUnlock(network);
|
2009-12-10 11:27:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-22 11:19:54 +00:00
|
|
|
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
|
2008-10-10 13:57:13 +00:00
|
|
|
static int
|
2010-12-20 06:14:11 +00:00
|
|
|
networkEnableIpForwarding(bool enableIPv4, bool enableIPv6)
|
2008-10-10 13:57:13 +00:00
|
|
|
{
|
2010-12-20 06:14:11 +00:00
|
|
|
int ret = 0;
|
|
|
|
if (enableIPv4)
|
|
|
|
ret = virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0);
|
|
|
|
if (enableIPv6 && ret == 0)
|
|
|
|
ret = virFileWriteStr("/proc/sys/net/ipv6/conf/all/forwarding", "1\n", 0);
|
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2009-07-30 15:34:56 +00:00
|
|
|
#define SYSCTL_PATH "/proc/sys"
|
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
static int
|
|
|
|
networkSetIPv6Sysctls(virNetworkObjPtr network)
|
2009-07-30 15:34:56 +00:00
|
|
|
{
|
|
|
|
char *field = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
|
|
|
|
/* Only set disable_ipv6 if there are no ipv6 addresses defined for
|
|
|
|
* the network.
|
|
|
|
*/
|
|
|
|
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6",
|
|
|
|
network->def->bridge) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-07-30 15:34:56 +00:00
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
if (access(field, W_OK) < 0 && errno == ENOENT) {
|
|
|
|
VIR_DEBUG("ipv6 appears to already be disabled on %s",
|
|
|
|
network->def->bridge);
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-08-10 10:16:37 +00:00
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
if (virFileWriteStr(field, "1", 0) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot write to %s to disable IPv6 on bridge %s"),
|
|
|
|
field, network->def->bridge);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(field);
|
2009-07-30 15:34:56 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
/* The rest of the ipv6 sysctl tunables should always be set,
|
|
|
|
* whether or not we're using ipv6 on this bridge.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Prevent guests from hijacking the host network by sending out
|
|
|
|
* their own router advertisements.
|
|
|
|
*/
|
|
|
|
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra",
|
|
|
|
network->def->bridge) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-30 15:34:56 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-03 09:47:08 +00:00
|
|
|
if (virFileWriteStr(field, "0", 0) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-07-30 15:34:56 +00:00
|
|
|
_("cannot disable %s"), field);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(field);
|
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
/* All interfaces used as a gateway (which is what this is, by
|
|
|
|
* definition), must always have autoconf=0.
|
|
|
|
*/
|
|
|
|
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/autoconf",
|
|
|
|
network->def->bridge) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-07-30 15:34:56 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-10-03 09:58:55 +00:00
|
|
|
if (virFileWriteStr(field, "0", 0) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2011-10-03 09:58:55 +00:00
|
|
|
_("cannot disable %s"), field);
|
2009-07-30 15:34:56 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(field);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-05-20 23:31:16 +00:00
|
|
|
#define PROC_NET_ROUTE "/proc/net/route"
|
|
|
|
|
|
|
|
/* XXX: This function can be a lot more exhaustive, there are certainly
|
|
|
|
* other scenarios where we can ruin host network connectivity.
|
|
|
|
* XXX: Using a proper library is preferred over parsing /proc
|
|
|
|
*/
|
2010-12-10 21:04:37 +00:00
|
|
|
static int
|
|
|
|
networkCheckRouteCollision(virNetworkObjPtr network)
|
2010-05-20 23:31:16 +00:00
|
|
|
{
|
2010-12-10 21:04:37 +00:00
|
|
|
int ret = 0, len;
|
2010-05-20 23:31:16 +00:00
|
|
|
char *cur, *buf = NULL;
|
|
|
|
enum {MAX_ROUTE_SIZE = 1024*64};
|
|
|
|
|
|
|
|
/* Read whole routing table into memory */
|
|
|
|
if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
goto out;
|
2010-05-20 23:31:16 +00:00
|
|
|
|
|
|
|
/* Dropping the last character shouldn't hurt */
|
|
|
|
if (len > 0)
|
|
|
|
buf[len-1] = '\0';
|
|
|
|
|
|
|
|
VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf);
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
if (!STRPREFIX(buf, "Iface"))
|
2010-05-20 23:31:16 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* First line is just headings, skip it */
|
|
|
|
cur = strchr(buf, '\n');
|
|
|
|
if (cur)
|
|
|
|
cur++;
|
|
|
|
|
|
|
|
while (cur) {
|
|
|
|
char iface[17], dest[128], mask[128];
|
|
|
|
unsigned int addr_val, mask_val;
|
2010-12-10 21:04:37 +00:00
|
|
|
virNetworkIpDefPtr ipdef;
|
|
|
|
int num, ii;
|
2010-05-20 23:31:16 +00:00
|
|
|
|
|
|
|
/* NUL-terminate the line, so sscanf doesn't go beyond a newline. */
|
|
|
|
char *nl = strchr(cur, '\n');
|
|
|
|
if (nl) {
|
|
|
|
*nl++ = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s",
|
|
|
|
iface, dest, mask);
|
|
|
|
cur = nl;
|
|
|
|
|
|
|
|
if (num != 3) {
|
|
|
|
VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) {
|
|
|
|
VIR_DEBUG("Failed to convert network address %s to uint", dest);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) {
|
|
|
|
VIR_DEBUG("Failed to convert network mask %s to uint", mask);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr_val &= mask_val;
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
|
|
|
ii++) {
|
|
|
|
|
|
|
|
unsigned int net_dest;
|
|
|
|
virSocketAddr netmask;
|
|
|
|
|
|
|
|
if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) {
|
|
|
|
VIR_WARN("Failed to get netmask of '%s'",
|
|
|
|
network->def->bridge);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_dest = (ipdef->address.data.inet4.sin_addr.s_addr &
|
|
|
|
netmask.data.inet4.sin_addr.s_addr);
|
|
|
|
|
|
|
|
if ((net_dest == addr_val) &&
|
|
|
|
(netmask.data.inet4.sin_addr.s_addr == mask_val)) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network is already in use by interface %s"),
|
|
|
|
iface);
|
2010-12-10 21:04:37 +00:00
|
|
|
ret = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
2010-05-20 23:31:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
VIR_FREE(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
static int
|
Remove 'brControl' object
The bridge management APIs in src/util/bridge.c require a brControl
object to be passed around. This holds the file descriptor for the
control socket. This extra object complicates use of the API for
only a minor efficiency gain, which is in turn entirely offset by
the need to fork/exec the brctl command for STP configuration.
This patch removes the 'brControl' object entirely, instead opening
the control socket & closing it again within the scope of each method.
The parameter names for the APIs are also made to consistently use
'brname' for bridge device name, and 'ifname' for an interface
device name. Finally annotations are added for non-NULL parameters
and return check validation
* src/util/bridge.c, src/util/bridge.h: Remove brControl object
and update API parameter names & annotations.
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/uml/uml_conf.h, src/uml/uml_conf.c, src/uml/uml_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_conf.h,
src/qemu/qemu_driver.c: Remove reference to 'brControl' object
2011-11-02 10:56:38 +00:00
|
|
|
networkAddAddrToBridge(virNetworkObjPtr network,
|
2010-12-10 21:04:37 +00:00
|
|
|
virNetworkIpDefPtr ipdef)
|
2010-02-10 10:22:52 +00:00
|
|
|
{
|
2010-12-10 21:04:37 +00:00
|
|
|
int prefix = virNetworkIpDefPrefix(ipdef);
|
|
|
|
|
|
|
|
if (prefix < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("bridge '%s' has an invalid netmask or IP address"),
|
|
|
|
network->def->bridge);
|
2010-12-10 21:04:37 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-11-02 12:35:18 +00:00
|
|
|
if (virNetDevSetIPv4Address(network->def->bridge,
|
|
|
|
&ipdef->address, prefix) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
networkStartNetworkVirtual(struct network_driver *driver,
|
2010-12-10 21:04:37 +00:00
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
2011-11-02 12:00:28 +00:00
|
|
|
int ii;
|
2010-12-16 20:50:01 +00:00
|
|
|
bool v4present = false, v6present = false;
|
2010-12-10 21:04:37 +00:00
|
|
|
virErrorPtr save_err = NULL;
|
|
|
|
virNetworkIpDefPtr ipdef;
|
2011-04-14 12:03:46 +00:00
|
|
|
char *macTapIfName = NULL;
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
int tapfd = -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* Check to see if any network IP collides with an existing route */
|
|
|
|
if (networkCheckRouteCollision(network) < 0)
|
2010-05-20 23:31:16 +00:00
|
|
|
return -1;
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* Create and configure the bridge device */
|
2011-11-02 12:35:18 +00:00
|
|
|
if (virNetDevBridgeCreate(network->def->bridge) < 0)
|
2008-10-10 13:57:13 +00:00
|
|
|
return -1;
|
|
|
|
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
if (network->def->mac_specified) {
|
|
|
|
/* To set a mac for the bridge, we need to define a dummy tap
|
|
|
|
* device, set its mac, then attach it to the bridge. As long
|
|
|
|
* as its mac address is lower than any other interface that
|
|
|
|
* gets attached, the bridge will always maintain this mac
|
|
|
|
* address.
|
|
|
|
*/
|
|
|
|
macTapIfName = networkBridgeDummyNicName(network->def->bridge);
|
|
|
|
if (!macTapIfName) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto err0;
|
|
|
|
}
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
/* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
|
2011-11-02 12:35:18 +00:00
|
|
|
if (virNetDevTapCreateInBridgePort(network->def->bridge,
|
2012-07-17 12:07:59 +00:00
|
|
|
&macTapIfName, &network->def->mac,
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
NULL, &tapfd, NULL, NULL,
|
|
|
|
VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
|
|
|
|
VIR_NETDEV_TAP_CREATE_IFUP |
|
|
|
|
VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
VIR_FREE(macTapIfName);
|
|
|
|
goto err0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* Set bridge options */
|
2012-08-23 15:21:47 +00:00
|
|
|
|
|
|
|
/* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
|
|
|
|
* expects milliseconds
|
|
|
|
*/
|
2011-11-02 12:35:18 +00:00
|
|
|
if (virNetDevBridgeSetSTPDelay(network->def->bridge,
|
2012-08-23 15:21:47 +00:00
|
|
|
network->def->delay * 1000) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2011-11-02 12:35:18 +00:00
|
|
|
if (virNetDevBridgeSetSTP(network->def->bridge,
|
2011-11-02 12:54:45 +00:00
|
|
|
network->def->stp ? true : false) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err1;
|
2010-11-30 19:35:58 +00:00
|
|
|
|
2010-12-16 20:50:01 +00:00
|
|
|
/* Disable IPv6 on the bridge if there are no IPv6 addresses
|
|
|
|
* defined, and set other IPv6 sysctl tunables appropriately.
|
|
|
|
*/
|
|
|
|
if (networkSetIPv6Sysctls(network) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err1;
|
2010-12-14 17:14:39 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* Add "once per network" rules */
|
|
|
|
if (networkAddIptablesRules(driver, network) < 0)
|
|
|
|
goto err1;
|
|
|
|
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
|
|
|
ii++) {
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
|
2010-12-10 21:04:37 +00:00
|
|
|
v4present = true;
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
|
2010-12-16 20:50:01 +00:00
|
|
|
v6present = true;
|
2010-12-14 17:14:39 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* Add the IP address/netmask to the bridge */
|
Remove 'brControl' object
The bridge management APIs in src/util/bridge.c require a brControl
object to be passed around. This holds the file descriptor for the
control socket. This extra object complicates use of the API for
only a minor efficiency gain, which is in turn entirely offset by
the need to fork/exec the brctl command for STP configuration.
This patch removes the 'brControl' object entirely, instead opening
the control socket & closing it again within the scope of each method.
The parameter names for the APIs are also made to consistently use
'brname' for bridge device name, and 'ifname' for an interface
device name. Finally annotations are added for non-NULL parameters
and return check validation
* src/util/bridge.c, src/util/bridge.h: Remove brControl object
and update API parameter names & annotations.
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/uml/uml_conf.h, src/uml/uml_conf.c, src/uml/uml_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_conf.h,
src/qemu/qemu_driver.c: Remove reference to 'brControl' object
2011-11-02 10:56:38 +00:00
|
|
|
if (networkAddAddrToBridge(network, ipdef) < 0) {
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err2;
|
2010-12-14 17:14:39 +00:00
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
/* Bring up the bridge interface */
|
2011-11-02 12:35:18 +00:00
|
|
|
if (virNetDevSetOnline(network->def->bridge, 1) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err2;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
/* If forward.type != NONE, turn on global IP forwarding */
|
|
|
|
if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
|
2010-12-20 06:14:11 +00:00
|
|
|
networkEnableIpForwarding(v4present, v6present) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-01-20 17:13:33 +00:00
|
|
|
_("failed to enable IP forwarding"));
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err3;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
|
network driver: Start dnsmasq even if no dhcp ranges/hosts are specified.
This fixes a regression introduced in commit ad48df, and reported on
the libvirt-users list:
https://www.redhat.com/archives/libvirt-users/2011-March/msg00018.html
The problem in that commit was that we began searching a list of ip
address definitions (rather than just having one) to look for a dhcp
range or static host; when we didn't find any, our pointer (ipdef) was
left at NULL, and when ipdef was NULL, we returned without starting up
dnsmasq.
Previously dnsmasq was started even without any dhcp ranges or static
entries, because it's still useful for DNS services.
Another problem I noticed while investigating was that, if there are
IPv6 addresses, but no IPv4 addresses of any kind, we would jump out
at an ever higher level in the call chain.
This patch does the following:
1) networkBuildDnsmasqArgv() = all uses of ipdef are protected from
NULL dereference. (this patch doesn't change indentation, to make
review easier. The next patch will change just the
indentation). ipdef is intended to point to the first IPv4 address
with DHCP info (or the first IPv4 address if none of them have any
dhcp info).
2) networkStartDhcpDaemon() = if the loop looking for an ipdef with
DHCP info comes up empty, we then grab the first IPv4 def from the
list. Also, instead of returning if there are no IPv4 defs, we just
return if there are no IP defs at all (either v4 or v6). This way a
network that is IPv6-only will still get dnsmasq listening for DNS
queries.
3) in networkStartNetworkDaemon() - we will startup dhcp not just if there
are any IPv4 addresses, but also if there are any IPv6 addresses.
2011-03-11 16:47:58 +00:00
|
|
|
/* start dnsmasq if there are any IP addresses (v4 or v6) */
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
if ((v4present || v6present) &&
|
|
|
|
networkStartDhcpDaemon(driver, network) < 0)
|
2010-12-10 21:04:37 +00:00
|
|
|
goto err3;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-20 06:14:11 +00:00
|
|
|
/* start radvd if there are any ipv6 addresses */
|
2012-12-06 17:20:38 +00:00
|
|
|
if (v6present && networkStartRadvd(driver, network) < 0)
|
2010-12-20 06:14:11 +00:00
|
|
|
goto err4;
|
|
|
|
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
/* DAD has happened (dnsmasq waits for it), dnsmasq is now bound to the
|
|
|
|
* bridge's IPv6 address, so we can now set the dummy tun down.
|
|
|
|
*/
|
|
|
|
if (tapfd >= 0) {
|
|
|
|
if (virNetDevSetOnline(macTapIfName, false) < 0)
|
|
|
|
goto err4;
|
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
|
|
|
}
|
|
|
|
|
2012-11-16 10:36:02 +00:00
|
|
|
if (virNetDevBandwidthSet(network->def->bridge,
|
|
|
|
network->def->bandwidth, true) < 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot set bandwidth limits on %s"),
|
|
|
|
network->def->bridge);
|
2011-07-22 14:07:27 +00:00
|
|
|
goto err5;
|
|
|
|
}
|
|
|
|
|
2011-04-14 12:03:46 +00:00
|
|
|
VIR_FREE(macTapIfName);
|
2008-10-10 13:57:13 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2011-07-22 14:07:27 +00:00
|
|
|
err5:
|
2012-09-18 10:01:18 +00:00
|
|
|
virNetDevBandwidthClear(network->def->bridge);
|
2011-07-22 14:07:27 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
err4:
|
|
|
|
if (!save_err)
|
|
|
|
save_err = virSaveLastError();
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (network->dnsmasqPid > 0) {
|
|
|
|
kill(network->dnsmasqPid, SIGTERM);
|
|
|
|
network->dnsmasqPid = -1;
|
|
|
|
}
|
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
err3:
|
|
|
|
if (!save_err)
|
|
|
|
save_err = virSaveLastError();
|
2011-11-02 12:35:18 +00:00
|
|
|
ignore_value(virNetDevSetOnline(network->def->bridge, 0));
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
err2:
|
|
|
|
if (!save_err)
|
|
|
|
save_err = virSaveLastError();
|
|
|
|
networkRemoveIptablesRules(driver, network);
|
|
|
|
|
|
|
|
err1:
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
if (!save_err)
|
|
|
|
save_err = virSaveLastError();
|
|
|
|
|
2011-11-11 08:20:19 +00:00
|
|
|
if (macTapIfName) {
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
2011-11-11 08:20:19 +00:00
|
|
|
ignore_value(virNetDevTapDelete(macTapIfName));
|
|
|
|
VIR_FREE(macTapIfName);
|
|
|
|
}
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
|
|
|
|
err0:
|
2010-12-10 21:04:37 +00:00
|
|
|
if (!save_err)
|
|
|
|
save_err = virSaveLastError();
|
2011-11-02 12:35:18 +00:00
|
|
|
ignore_value(virNetDevBridgeDelete(network->def->bridge));
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
if (save_err) {
|
|
|
|
virSetError(save_err);
|
|
|
|
virFreeError(save_err);
|
|
|
|
}
|
2013-01-22 14:41:03 +00:00
|
|
|
/* coverity[leaked_handle] - 'tapfd' is not leaked */
|
2008-10-10 13:57:13 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
static int networkShutdownNetworkVirtual(struct network_driver *driver,
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
2012-09-18 10:01:18 +00:00
|
|
|
virNetDevBandwidthClear(network->def->bridge);
|
2011-07-22 14:07:27 +00:00
|
|
|
|
2010-12-20 06:14:11 +00:00
|
|
|
if (network->radvdPid > 0) {
|
|
|
|
char *radvdpidbase;
|
|
|
|
|
|
|
|
kill(network->radvdPid, SIGTERM);
|
|
|
|
/* attempt to delete the pidfile we created */
|
|
|
|
if (!(radvdpidbase = networkRadvdPidfileBasename(network->def->name))) {
|
|
|
|
virReportOOMError();
|
|
|
|
} else {
|
2013-05-02 17:59:52 +00:00
|
|
|
virPidFileDelete(driverState->pidDir, radvdpidbase);
|
2010-12-20 06:14:11 +00:00
|
|
|
VIR_FREE(radvdpidbase);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (network->dnsmasqPid > 0)
|
|
|
|
kill(network->dnsmasqPid, SIGTERM);
|
|
|
|
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
if (network->def->mac_specified) {
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
char *macTapIfName = networkBridgeDummyNicName(network->def->bridge);
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
if (!macTapIfName) {
|
|
|
|
virReportOOMError();
|
|
|
|
} else {
|
2011-11-02 12:35:18 +00:00
|
|
|
ignore_value(virNetDevTapDelete(macTapIfName));
|
Give each virtual network bridge its own fixed MAC address
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=609463
The problem was that, since a bridge always acquires the MAC address
of the connected interface with the numerically lowest MAC, as guests
are started and stopped, it was possible for the MAC address to change
over time, and this change in the network was being detected by
Windows 7 (it sees the MAC of the default route change), so on each
reboot it would bring up a dialog box asking about this "new network".
The solution is to create a dummy tap interface with a MAC guaranteed
to be lower than any guest interface's MAC, and attach that tap to the
bridge as soon as it's created. Since all guest MAC addresses start
with 0xFE, we can just generate a MAC with the standard "0x52, 0x54,
0" prefix, and it's guaranteed to always win (physical interfaces are
never connected to these bridges, so we don't need to worry about
competing numerically with them).
Note that the dummy tap is never set to IFF_UP state - that's not
necessary in order for the bridge to take its MAC, and not setting it
to UP eliminates the clutter of having an (eg) "virbr0-nic" displayed
in the output of the ifconfig command.
I chose to not auto-generate the MAC address in the network XML
parser, as there are likely to be consumers of that API that don't
need or want to have a MAC address associated with the
bridge.
Instead, in bridge_driver.c when the network is being defined, if
there is no MAC, one is generated. To account for virtual network
configs that already exist when upgrading from an older version of
libvirt, I've added a %post script to the specfile that searches for
all network definitions in both the config directory
(/etc/libvirt/qemu/networks) and the state directory
(/var/lib/libvirt/network) that are missing a mac address, generates a
random address, and adds it to the config (and a matching address to
the state file, if there is one).
docs/formatnetwork.html.in: document <mac address.../>
docs/schemas/network.rng: add nac address to schema
libvirt.spec.in: %post script to update existing networks
src/conf/network_conf.[ch]: parse and format <mac address.../>
src/libvirt_private.syms: export a couple private symbols we need
src/network/bridge_driver.c:
auto-generate mac address when needed,
create dummy interface if mac address is present.
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlin/routed-network.xml
tests/networkxml2xmlout/isolated-network.xml
tests/networkxml2xmlout/routed-network.xml: add mac address to some tests
2011-02-09 08:28:12 +00:00
|
|
|
VIR_FREE(macTapIfName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-02 12:35:18 +00:00
|
|
|
ignore_value(virNetDevSetOnline(network->def->bridge, 0));
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-12-10 21:04:37 +00:00
|
|
|
networkRemoveIptablesRules(driver, network);
|
|
|
|
|
2011-11-02 12:35:18 +00:00
|
|
|
ignore_value(virNetDevBridgeDelete(network->def->bridge));
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
/* See if its still alive and really really kill it */
|
2008-10-10 13:57:13 +00:00
|
|
|
if (network->dnsmasqPid > 0 &&
|
2009-01-20 22:36:10 +00:00
|
|
|
(kill(network->dnsmasqPid, 0) == 0))
|
2008-10-10 13:57:13 +00:00
|
|
|
kill(network->dnsmasqPid, SIGKILL);
|
|
|
|
network->dnsmasqPid = -1;
|
2010-12-20 06:14:11 +00:00
|
|
|
|
|
|
|
if (network->radvdPid > 0 &&
|
|
|
|
(kill(network->radvdPid, 0) == 0))
|
|
|
|
kill(network->radvdPid, SIGKILL);
|
|
|
|
network->radvdPid = -1;
|
|
|
|
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
networkStartNetworkExternal(struct network_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
virNetworkObjPtr network ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
/* put anything here that needs to be done each time a network of
|
2012-08-16 15:42:31 +00:00
|
|
|
* type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
* failure, undo anything you've done, and return -1. On success
|
|
|
|
* return 0.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int networkShutdownNetworkExternal(struct network_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
virNetworkObjPtr network ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
/* put anything here that needs to be done each time a network of
|
2012-08-16 15:42:31 +00:00
|
|
|
* type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
* failure, undo anything you've done, and return -1. On success
|
|
|
|
* return 0.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
networkStartNetwork(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (virNetworkObjIsActive(network)) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("network is already active"));
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-14 15:35:35 +00:00
|
|
|
if (virNetworkObjSetDefTransient(network, true) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
switch (network->def->forward.type) {
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_NONE:
|
|
|
|
case VIR_NETWORK_FORWARD_NAT:
|
|
|
|
case VIR_NETWORK_FORWARD_ROUTE:
|
|
|
|
ret = networkStartNetworkVirtual(driver, network);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_BRIDGE:
|
|
|
|
case VIR_NETWORK_FORWARD_PRIVATE:
|
|
|
|
case VIR_NETWORK_FORWARD_VEPA:
|
|
|
|
case VIR_NETWORK_FORWARD_PASSTHROUGH:
|
2012-08-16 15:42:31 +00:00
|
|
|
case VIR_NETWORK_FORWARD_HOSTDEV:
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
ret = networkStartNetworkExternal(driver, network);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
network: free/null newDef if network fails to start
https://bugzilla.redhat.com/show_bug.cgi?id=866364
pointed out a crash due to virNetworkObjAssignDef free'ing
network->newDef without NULLing it afterward. A fix for this is in
upstream commit b7e9202401ebaa039b8f05acdefda8c24081537a. While the
NULLing of newDef was a legitimate fix, newDef should have already
been empty (NULL) anyway (as indicated in the comment that was deleted
by that commit).
The reason that newDef had a non-NULL value (i.e. the root cause) was
that networkStartNetwork() had failed after populating
network->newDef, but then neglected to free/NULL newDef in the
cleanup.
(A bit of background here: network->newDef should contain the
persistent config of a network when a network is active (and of course
only when it is persisten), and NULL at all other times. There is also
a network->def which should contain the persistent definition of the
network when it is inactive, and the current live state at all other
times. The idea is that you can make changes to network->newDef which
will take effect the next time the network is restarted, but won't
mess with the current state of the network (virDomainObj has a similar
pair of virDomainDefs that behave in the same fashion). Personally I
think there should be a network->live and network->config, and the
location of the persistent config should *always* be in
network->config, but that's for a later cleanup).
Since I love things to be symmetric, I created a new function called
virNetworkObjUnsetDefTransient(), which reverses the effects of
virNetworkObjSetDefTransient(). I don't really like the name of the
new function, but then I also didn't really like the name of the old
one either (it's just named that way to match a similar function in
the domain conf code).
2012-10-19 16:13:49 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
virNetworkObjUnsetDefTransient(network);
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
return ret;
|
network: free/null newDef if network fails to start
https://bugzilla.redhat.com/show_bug.cgi?id=866364
pointed out a crash due to virNetworkObjAssignDef free'ing
network->newDef without NULLing it afterward. A fix for this is in
upstream commit b7e9202401ebaa039b8f05acdefda8c24081537a. While the
NULLing of newDef was a legitimate fix, newDef should have already
been empty (NULL) anyway (as indicated in the comment that was deleted
by that commit).
The reason that newDef had a non-NULL value (i.e. the root cause) was
that networkStartNetwork() had failed after populating
network->newDef, but then neglected to free/NULL newDef in the
cleanup.
(A bit of background here: network->newDef should contain the
persistent config of a network when a network is active (and of course
only when it is persisten), and NULL at all other times. There is also
a network->def which should contain the persistent definition of the
network when it is inactive, and the current live state at all other
times. The idea is that you can make changes to network->newDef which
will take effect the next time the network is restarted, but won't
mess with the current state of the network (virDomainObj has a similar
pair of virDomainDefs that behave in the same fashion). Personally I
think there should be a network->live and network->config, and the
location of the persistent config should *always* be in
network->config, but that's for a later cleanup).
Since I love things to be symmetric, I created a new function called
virNetworkObjUnsetDefTransient(), which reverses the effects of
virNetworkObjSetDefTransient(). I don't really like the name of the
new function, but then I also didn't really like the name of the old
one either (it's just named that way to match a similar function in
the domain conf code).
2012-10-19 16:13:49 +00:00
|
|
|
}
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
|
|
|
|
/* Persist the live configuration now that anything autogenerated
|
|
|
|
* is setup.
|
|
|
|
*/
|
2013-05-02 17:59:52 +00:00
|
|
|
if ((ret = virNetworkSaveStatus(driverState->stateDir,
|
|
|
|
network)) < 0) {
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_INFO("Starting up network '%s'", network->def->name);
|
|
|
|
network->active = 1;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (ret < 0) {
|
|
|
|
virErrorPtr save_err = virSaveLastError();
|
|
|
|
int save_errno = errno;
|
|
|
|
networkShutdownNetwork(driver, network);
|
|
|
|
virSetError(save_err);
|
|
|
|
virFreeError(save_err);
|
|
|
|
errno = save_errno;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int networkShutdownNetwork(struct network_driver *driver,
|
|
|
|
virNetworkObjPtr network)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
char *stateFile;
|
|
|
|
|
|
|
|
VIR_INFO("Shutting down network '%s'", network->def->name);
|
|
|
|
|
|
|
|
if (!virNetworkObjIsActive(network))
|
|
|
|
return 0;
|
|
|
|
|
2013-05-02 17:59:52 +00:00
|
|
|
stateFile = virNetworkConfigFile(driverState->stateDir,
|
|
|
|
network->def->name);
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
if (!stateFile)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
unlink(stateFile);
|
|
|
|
VIR_FREE(stateFile);
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
switch (network->def->forward.type) {
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_NONE:
|
|
|
|
case VIR_NETWORK_FORWARD_NAT:
|
|
|
|
case VIR_NETWORK_FORWARD_ROUTE:
|
|
|
|
ret = networkShutdownNetworkVirtual(driver, network);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_BRIDGE:
|
|
|
|
case VIR_NETWORK_FORWARD_PRIVATE:
|
|
|
|
case VIR_NETWORK_FORWARD_VEPA:
|
|
|
|
case VIR_NETWORK_FORWARD_PASSTHROUGH:
|
2012-08-16 15:42:31 +00:00
|
|
|
case VIR_NETWORK_FORWARD_HOSTDEV:
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
ret = networkShutdownNetworkExternal(driver, network);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
network->active = 0;
|
network: free/null newDef if network fails to start
https://bugzilla.redhat.com/show_bug.cgi?id=866364
pointed out a crash due to virNetworkObjAssignDef free'ing
network->newDef without NULLing it afterward. A fix for this is in
upstream commit b7e9202401ebaa039b8f05acdefda8c24081537a. While the
NULLing of newDef was a legitimate fix, newDef should have already
been empty (NULL) anyway (as indicated in the comment that was deleted
by that commit).
The reason that newDef had a non-NULL value (i.e. the root cause) was
that networkStartNetwork() had failed after populating
network->newDef, but then neglected to free/NULL newDef in the
cleanup.
(A bit of background here: network->newDef should contain the
persistent config of a network when a network is active (and of course
only when it is persisten), and NULL at all other times. There is also
a network->def which should contain the persistent definition of the
network when it is inactive, and the current live state at all other
times. The idea is that you can make changes to network->newDef which
will take effect the next time the network is restarted, but won't
mess with the current state of the network (virDomainObj has a similar
pair of virDomainDefs that behave in the same fashion). Personally I
think there should be a network->live and network->config, and the
location of the persistent config should *always* be in
network->config, but that's for a later cleanup).
Since I love things to be symmetric, I created a new function called
virNetworkObjUnsetDefTransient(), which reverses the effects of
virNetworkObjSetDefTransient(). I don't really like the name of the
new function, but then I also didn't really like the name of the old
one either (it's just named that way to match a similar function in
the domain conf code).
2012-10-19 16:13:49 +00:00
|
|
|
virNetworkObjUnsetDefTransient(network);
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
|
|
|
|
const unsigned char *uuid) {
|
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
virNetworkPtr ret = NULL;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
ret = virGetNetwork(conn, network->def->name, network->def->uuid);
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
static virNetworkPtr networkLookupByName(virConnectPtr conn,
|
|
|
|
const char *name) {
|
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
virNetworkPtr ret = NULL;
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByName(&driver->networks, name);
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
_("no network with matching name '%s'"), name);
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
ret = virGetNetwork(conn, network->def->name, network->def->uuid);
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static virDrvOpenStatus networkOpen(virConnectPtr conn,
|
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
|
|
|
unsigned int flags)
|
2011-07-06 22:29:02 +00:00
|
|
|
{
|
|
|
|
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!driverState)
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
|
|
|
|
|
|
|
conn->networkPrivateData = driverState;
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkClose(virConnectPtr conn) {
|
2008-10-10 13:57:13 +00:00
|
|
|
conn->networkPrivateData = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkConnectNumOfNetworks(virConnectPtr conn) {
|
2008-10-10 14:50:26 +00:00
|
|
|
int nactive = 0, i;
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
2008-10-10 14:50:26 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
|
|
|
for (i = 0 ; i < driver->networks.count ; i++) {
|
|
|
|
virNetworkObjLock(driver->networks.objs[i]);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (virNetworkObjIsActive(driver->networks.objs[i]))
|
2008-10-10 13:57:13 +00:00
|
|
|
nactive++;
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
|
|
|
}
|
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 14:50:26 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
return nactive;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
2008-10-10 13:57:13 +00:00
|
|
|
int got = 0, i;
|
2008-10-10 14:50:26 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-10-10 14:50:26 +00:00
|
|
|
for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjLock(driver->networks.objs[i]);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (virNetworkObjIsActive(driver->networks.objs[i])) {
|
2013-05-03 12:43:59 +00:00
|
|
|
if (VIR_STRDUP(names[got], driver->networks.objs[i]->def->name) < 0) {
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
got++;
|
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
return got;
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
for (i = 0 ; i < got ; i++)
|
|
|
|
VIR_FREE(names[i]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkConnectNumOfDefinedNetworks(virConnectPtr conn) {
|
2008-10-10 14:50:26 +00:00
|
|
|
int ninactive = 0, i;
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
2008-10-10 14:50:26 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
|
|
|
for (i = 0 ; i < driver->networks.count ; i++) {
|
|
|
|
virNetworkObjLock(driver->networks.objs[i]);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (!virNetworkObjIsActive(driver->networks.objs[i]))
|
2008-10-10 13:57:13 +00:00
|
|
|
ninactive++;
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
|
|
|
}
|
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 14:50:26 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
return ninactive;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
2008-10-10 13:57:13 +00:00
|
|
|
int got = 0, i;
|
2008-10-10 14:50:26 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-10-10 14:50:26 +00:00
|
|
|
for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjLock(driver->networks.objs[i]);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (!virNetworkObjIsActive(driver->networks.objs[i])) {
|
2013-05-03 12:43:59 +00:00
|
|
|
if (VIR_STRDUP(names[got], driver->networks.objs[i]->def->name) < 0) {
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
2008-10-10 13:57:13 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
got++;
|
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjUnlock(driver->networks.objs[i]);
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
return got;
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
for (i = 0 ; i < got ; i++)
|
|
|
|
VIR_FREE(names[i]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-04 15:55:18 +00:00
|
|
|
static int
|
2013-04-23 12:50:18 +00:00
|
|
|
networkConnectListAllNetworks(virConnectPtr conn,
|
|
|
|
virNetworkPtr **nets,
|
|
|
|
unsigned int flags)
|
2012-09-04 15:55:18 +00:00
|
|
|
{
|
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
ret = virNetworkList(conn, driver->networks, nets, flags);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
|
|
|
|
static int networkIsActive(virNetworkPtr net)
|
|
|
|
{
|
2010-02-16 18:09:31 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
virNetworkObjPtr obj;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
obj = virNetworkFindByUUID(&driver->networks, net->uuid);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
if (!obj) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK, NULL);
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
ret = virNetworkObjIsActive(obj);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (obj)
|
|
|
|
virNetworkObjUnlock(obj);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int networkIsPersistent(virNetworkPtr net)
|
|
|
|
{
|
2010-02-16 18:09:31 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
virNetworkObjPtr obj;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
obj = virNetworkFindByUUID(&driver->networks, net->uuid);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
if (!obj) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK, NULL);
|
Implmentation of new APIs to checking state/persistence of objects
This implements the virConnectIsSecure, virConnectIsEncrypted,
virDomainIsPersistent, virDomainIsActive, virNetworkIsActive,
virNetworkIsPersistent, virStoragePoolIsActive,
virStoragePoolIsPersistent, virInterfaceIsActive APIs in
(nearly) all drivers. Exceptions are:
phyp: missing domainIsActive/Persistent
esx: missing domainIsPersistent
opennebula: missing domainIsActive/Persistent
* src/remote/remote_protocol.x: Define remote wire ABI for newly
added APIs.
* daemon/remote_dispatch*.h: Re-generated from remote_protocol.x
* src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/opennebula/one_driver.c, src/openvz/openvz_conf.c,
src/openvz/openvz_driver.c, src/phyp/phyp_driver.c,
src/remote/remote_driver.c, src/storage/storage_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c,
src/xen/xen_driver.c, src/xen/xen_driver.h, src/xen/xen_inotify.c,
src/xen/xen_inotify.h: Implement all the new APIs where possible
2009-10-20 14:12:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
ret = obj->persistent;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (obj)
|
|
|
|
virNetworkObjUnlock(obj);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
static int
|
2012-10-25 14:27:07 +00:00
|
|
|
networkValidate(struct network_driver *driver,
|
|
|
|
virNetworkDefPtr def,
|
|
|
|
bool check_active)
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
{
|
|
|
|
int ii;
|
2012-10-25 15:13:52 +00:00
|
|
|
bool vlanUsed, vlanAllowed, badVlanUse = false;
|
|
|
|
virPortGroupDefPtr defaultPortGroup = NULL;
|
2012-10-25 14:27:07 +00:00
|
|
|
virNetworkIpDefPtr ipdef;
|
2012-12-06 17:20:38 +00:00
|
|
|
bool ipv4def = false, ipv6def = false;
|
2012-10-25 14:27:07 +00:00
|
|
|
|
|
|
|
/* check for duplicate networks */
|
|
|
|
if (virNetworkObjIsDuplicate(&driver->networks, def, check_active) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Only the three L3 network types that are configured by libvirt
|
|
|
|
* need to have a bridge device name / mac address provided
|
|
|
|
*/
|
2012-11-08 02:16:17 +00:00
|
|
|
if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
|
|
|
|
def->forward.type == VIR_NETWORK_FORWARD_NAT ||
|
|
|
|
def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
|
2012-10-25 14:27:07 +00:00
|
|
|
|
|
|
|
if (virNetworkSetBridgeName(&driver->networks, def, 1))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virNetworkSetBridgeMacAddr(def);
|
network: prevent a few invalid configuration combinations
This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=767057
It was possible to define a network with <forward mode='bridge'> that
had both a bridge device and a forward device defined. These two are
mutually exclusive by definition (if you are using a bridge device,
then this is a host bridge, and if you have a forward dev defined,
this is using macvtap). It was also possible to put <ip>, <dns>, and
<domain> elements in this definition, although those aren't supported
by the current driver (although it's conceivable that some other
driver might support that).
The items that are invalid by definition, are now checked in the XML
parser (since they will definitely *always* be wrong), and the others
are checked in networkValidate() in the network driver (since, as
mentioned, it's possible that some other network driver, or even this
one, could some day support setting those).
2012-12-05 19:10:24 +00:00
|
|
|
} else {
|
|
|
|
/* They are also the only types that currently support setting
|
|
|
|
* an IP address for the host-side device (bridge)
|
|
|
|
*/
|
|
|
|
if (virNetworkDefGetIpByIndex(def, AF_UNSPEC, 0)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported <ip> element in network %s "
|
|
|
|
"with forward mode='%s'"),
|
|
|
|
def->name,
|
2012-11-08 02:16:17 +00:00
|
|
|
virNetworkForwardTypeToString(def->forward.type));
|
network: prevent a few invalid configuration combinations
This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=767057
It was possible to define a network with <forward mode='bridge'> that
had both a bridge device and a forward device defined. These two are
mutually exclusive by definition (if you are using a bridge device,
then this is a host bridge, and if you have a forward dev defined,
this is using macvtap). It was also possible to put <ip>, <dns>, and
<domain> elements in this definition, although those aren't supported
by the current driver (although it's conceivable that some other
driver might support that).
The items that are invalid by definition, are now checked in the XML
parser (since they will definitely *always* be wrong), and the others
are checked in networkValidate() in the network driver (since, as
mentioned, it's possible that some other network driver, or even this
one, could some day support setting those).
2012-12-05 19:10:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
conf: clear and parse functions for dns host/srv/txt records
Since there is only a single virNetworkDNSDef for any virNetworkDef,
and it's trivial to determine whether or not it contains any real
data, it's much simpler (and fits more uniformly with the parse
function calling sequence of the parsers for many other objects that
are subordinates of virNetworkDef) if virNetworkDef *contains* an
virNetworkDNSDef rather than pointing to one.
Since it is now just a part of another object rather than its own
object, it no longer makes sense to have a *Free() function, so that
is changed to a *Clear() function.
More importantly though, ParseXML and Clear functions are needed for
the individual items contained in a virNetworkDNSDef (srv, txt, and
host records), but none of them have a *Clear(), and only two of the
three had *ParseXML() functions (both of which used a non-uniform
arglist). Those problems are cleared up by this patch - it splits the
higher-level Clear function into separate functions for each of the
three, creates a parse for txt records, and cleans up the srv and host
parsers, so we now have all the utility functions necessary to
implement virNetworkDefUpdateDNS(Host|Srv|Txt).
2012-11-12 00:00:22 +00:00
|
|
|
if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
|
network: prevent a few invalid configuration combinations
This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=767057
It was possible to define a network with <forward mode='bridge'> that
had both a bridge device and a forward device defined. These two are
mutually exclusive by definition (if you are using a bridge device,
then this is a host bridge, and if you have a forward dev defined,
this is using macvtap). It was also possible to put <ip>, <dns>, and
<domain> elements in this definition, although those aren't supported
by the current driver (although it's conceivable that some other
driver might support that).
The items that are invalid by definition, are now checked in the XML
parser (since they will definitely *always* be wrong), and the others
are checked in networkValidate() in the network driver (since, as
mentioned, it's possible that some other network driver, or even this
one, could some day support setting those).
2012-12-05 19:10:24 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported <dns> element in network %s "
|
|
|
|
"with forward mode='%s'"),
|
|
|
|
def->name,
|
2012-11-08 02:16:17 +00:00
|
|
|
virNetworkForwardTypeToString(def->forward.type));
|
network: prevent a few invalid configuration combinations
This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=767057
It was possible to define a network with <forward mode='bridge'> that
had both a bridge device and a forward device defined. These two are
mutually exclusive by definition (if you are using a bridge device,
then this is a host bridge, and if you have a forward dev defined,
this is using macvtap). It was also possible to put <ip>, <dns>, and
<domain> elements in this definition, although those aren't supported
by the current driver (although it's conceivable that some other
driver might support that).
The items that are invalid by definition, are now checked in the XML
parser (since they will definitely *always* be wrong), and the others
are checked in networkValidate() in the network driver (since, as
mentioned, it's possible that some other network driver, or even this
one, could some day support setting those).
2012-12-05 19:10:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (def->domain) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported <domain> element in network %s "
|
|
|
|
"with forward mode='%s'"),
|
|
|
|
def->name,
|
2012-11-08 02:16:17 +00:00
|
|
|
virNetworkForwardTypeToString(def->forward.type));
|
network: prevent a few invalid configuration combinations
This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=767057
It was possible to define a network with <forward mode='bridge'> that
had both a bridge device and a forward device defined. These two are
mutually exclusive by definition (if you are using a bridge device,
then this is a host bridge, and if you have a forward dev defined,
this is using macvtap). It was also possible to put <ip>, <dns>, and
<domain> elements in this definition, although those aren't supported
by the current driver (although it's conceivable that some other
driver might support that).
The items that are invalid by definition, are now checked in the XML
parser (since they will definitely *always* be wrong), and the others
are checked in networkValidate() in the network driver (since, as
mentioned, it's possible that some other network driver, or even this
one, could some day support setting those).
2012-12-05 19:10:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-10-25 14:27:07 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:20:38 +00:00
|
|
|
/* We only support dhcp on one IPv4 address and
|
|
|
|
* on one IPv6 address per defined network
|
|
|
|
*/
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, ii));
|
|
|
|
ii++) {
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
if (ipv4def) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple IPv4 dhcp sections found -- "
|
2012-10-25 14:27:07 +00:00
|
|
|
"dhcp is supported only for a "
|
|
|
|
"single IPv4 address on each network"));
|
2012-12-06 17:20:38 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
ipv4def = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
if (ipv6def) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Multiple IPv6 dhcp sections found -- "
|
|
|
|
"dhcp is supported only for a "
|
|
|
|
"single IPv6 address on each network"));
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
ipv6def = true;
|
|
|
|
}
|
2012-10-25 14:27:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
|
|
|
|
/* The only type of networks that currently support transparent
|
|
|
|
* vlan configuration are those using hostdev sr-iov devices from
|
|
|
|
* a pool, and those using an Open vSwitch bridge.
|
|
|
|
*/
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
vlanAllowed = (def->forward.type == VIR_NETWORK_FORWARD_BRIDGE &&
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
def->virtPortProfile &&
|
|
|
|
def->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH);
|
|
|
|
|
|
|
|
vlanUsed = def->vlan.nTags > 0;
|
2012-10-25 15:13:52 +00:00
|
|
|
for (ii = 0; ii < def->nPortGroups; ii++) {
|
|
|
|
if (vlanUsed || def->portGroups[ii].vlan.nTags > 0) {
|
|
|
|
/* anyone using this portgroup will get a vlan tag. Verify
|
|
|
|
* that they will also be using an openvswitch connection,
|
|
|
|
* as that is the only type of network that currently
|
|
|
|
* supports a vlan tag.
|
|
|
|
*/
|
|
|
|
if (def->portGroups[ii].virtPortProfile) {
|
2012-11-08 02:16:17 +00:00
|
|
|
if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
|
2012-10-25 15:13:52 +00:00
|
|
|
def->portGroups[ii].virtPortProfile->virtPortType
|
|
|
|
!= VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
|
|
|
|
badVlanUse = true;
|
|
|
|
}
|
|
|
|
} else if (!vlanAllowed) {
|
|
|
|
/* virtualport taken from base network definition */
|
|
|
|
badVlanUse = true;
|
|
|
|
}
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
}
|
2012-10-20 08:39:18 +00:00
|
|
|
if (def->portGroups[ii].isDefault) {
|
|
|
|
if (defaultPortGroup) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("network '%s' has multiple default "
|
|
|
|
"<portgroup> elements (%s and %s), "
|
|
|
|
"but only one default is allowed"),
|
2012-10-25 15:13:52 +00:00
|
|
|
def->name, defaultPortGroup->name,
|
2012-10-20 08:39:18 +00:00
|
|
|
def->portGroups[ii].name);
|
2012-10-25 15:13:52 +00:00
|
|
|
return -1;
|
2012-10-20 08:39:18 +00:00
|
|
|
}
|
2012-10-25 15:13:52 +00:00
|
|
|
defaultPortGroup = &def->portGroups[ii];
|
2012-10-20 08:39:18 +00:00
|
|
|
}
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
}
|
2012-10-25 15:13:52 +00:00
|
|
|
if (badVlanUse ||
|
|
|
|
(vlanUsed && !vlanAllowed && !defaultPortGroup)) {
|
|
|
|
/* NB: if defaultPortGroup is set, we don't directly look at
|
|
|
|
* vlanUsed && !vlanAllowed, because the network will never be
|
|
|
|
* used without having a portgroup added in, so all necessary
|
|
|
|
* checks were done in the loop above.
|
|
|
|
*/
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("<vlan> element specified for network %s, "
|
|
|
|
"whose type doesn't support vlan configuration"),
|
|
|
|
def->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static virNetworkPtr networkCreateXML(virConnectPtr conn, const char *xml) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
2008-10-10 13:57:13 +00:00
|
|
|
virNetworkDefPtr def;
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjPtr network = NULL;
|
2008-12-04 21:37:52 +00:00
|
|
|
virNetworkPtr ret = NULL;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (!(def = virNetworkDefParseString(xml)))
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-10-25 14:27:07 +00:00
|
|
|
if (networkValidate(driver, def, true) < 0)
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-09-14 15:35:35 +00:00
|
|
|
/* NB: "live" is false because this transient network hasn't yet
|
|
|
|
* been started
|
|
|
|
*/
|
|
|
|
if (!(network = virNetworkAssignDef(&driver->networks, def, false)))
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
def = NULL;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
if (networkStartNetwork(driver, network) < 0) {
|
2008-10-10 13:57:13 +00:00
|
|
|
virNetworkRemoveInactive(&driver->networks,
|
|
|
|
network);
|
2008-12-04 21:38:38 +00:00
|
|
|
network = NULL;
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
maint: omit translation for all VIR_INFO
We were 31/73 on whether to translate; since less than 50% translated
and since VIR_INFO is less than VIR_WARN which also doesn't translate,
this makes sense.
* cfg.mk (sc_prohibit_gettext_markup): Add VIR_INFO, since it
falls between WARN and DEBUG.
* daemon/libvirtd.c (qemudDispatchSignalEvent, remoteCheckAccess)
(qemudDispatchServer): Adjust offenders.
* daemon/remote.c (remoteDispatchAuthPolkit): Likewise.
* src/network/bridge_driver.c (networkReloadIptablesRules)
(networkStartNetworkDaemon, networkShutdownNetworkDaemon)
(networkCreate, networkDefine, networkUndefine): Likewise.
* src/qemu/qemu_driver.c (qemudDomainDefine)
(qemudDomainUndefine): Likewise.
* src/storage/storage_driver.c (storagePoolCreate)
(storagePoolDefine, storagePoolUndefine, storagePoolStart)
(storagePoolDestroy, storagePoolDelete, storageVolumeCreateXML)
(storageVolumeCreateXMLFrom, storageVolumeDelete): Likewise.
* src/util/bridge.c (brProbeVnetHdr): Likewise.
* po/POTFILES.in: Drop src/util/bridge.c.
2011-05-11 15:08:44 +00:00
|
|
|
VIR_INFO("Creating network '%s'", network->def->name);
|
2008-12-04 21:37:52 +00:00
|
|
|
ret = virGetNetwork(conn, network->def->name, network->def->uuid);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virNetworkDefFree(def);
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
networkDriverUnlock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static virNetworkPtr networkDefineXML(virConnectPtr conn, const char *xml) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = conn->networkPrivateData;
|
2012-10-26 12:37:26 +00:00
|
|
|
virNetworkDefPtr def = NULL;
|
2011-08-03 19:33:24 +00:00
|
|
|
bool freeDef = true;
|
2008-12-04 21:38:38 +00:00
|
|
|
virNetworkObjPtr network = NULL;
|
2008-12-04 21:37:52 +00:00
|
|
|
virNetworkPtr ret = NULL;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (!(def = virNetworkDefParseString(xml)))
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-10-25 14:27:07 +00:00
|
|
|
if (networkValidate(driver, def, false) < 0)
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-10-26 12:37:26 +00:00
|
|
|
if ((network = virNetworkFindByName(&driver->networks, def->name))) {
|
|
|
|
network->persistent = 1;
|
|
|
|
if (virNetworkObjAssignDef(network, def, false) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (!(network = virNetworkAssignDef(&driver->networks, def, false)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-11-30 14:26:25 +00:00
|
|
|
|
2013-01-11 10:10:34 +00:00
|
|
|
/* define makes the network persistent - always */
|
|
|
|
network->persistent = 1;
|
|
|
|
|
2012-10-26 12:37:26 +00:00
|
|
|
/* def was asigned */
|
|
|
|
freeDef = false;
|
2011-11-30 14:26:25 +00:00
|
|
|
|
|
|
|
if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
|
2013-04-22 09:10:39 +00:00
|
|
|
if (!virNetworkObjIsActive(network)) {
|
|
|
|
virNetworkRemoveInactive(&driver->networks, network);
|
|
|
|
network = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
network->persistent = 0;
|
|
|
|
virNetworkDefFree(network->newDef);
|
|
|
|
network->newDef = NULL;
|
2011-11-30 14:26:25 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-08-03 19:33:24 +00:00
|
|
|
VIR_INFO("Defining network '%s'", def->name);
|
|
|
|
ret = virGetNetwork(conn, def->name, def->uuid);
|
2008-12-04 21:37:52 +00:00
|
|
|
|
|
|
|
cleanup:
|
2011-08-03 19:33:24 +00:00
|
|
|
if (freeDef)
|
|
|
|
virNetworkDefFree(def);
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
networkDriverUnlock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2012-10-25 14:13:57 +00:00
|
|
|
static int
|
|
|
|
networkUndefine(virNetworkPtr net) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
2010-11-17 18:36:19 +00:00
|
|
|
virNetworkObjPtr network;
|
2012-10-25 14:13:57 +00:00
|
|
|
int ret = -1;
|
2012-10-25 14:32:29 +00:00
|
|
|
bool active = false;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2012-10-25 14:32:29 +00:00
|
|
|
if (virNetworkObjIsActive(network))
|
|
|
|
active = true;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virNetworkDeleteConfig(driver->networkConfigDir,
|
2009-01-20 22:36:10 +00:00
|
|
|
driver->networkAutostartDir,
|
|
|
|
network) < 0)
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2012-10-25 14:32:29 +00:00
|
|
|
/* make the network transient */
|
|
|
|
network->persistent = 0;
|
2013-04-17 08:13:35 +00:00
|
|
|
network->autostart = 0;
|
2012-10-25 14:32:29 +00:00
|
|
|
virNetworkDefFree(network->newDef);
|
|
|
|
network->newDef = NULL;
|
|
|
|
|
2012-10-25 14:13:57 +00:00
|
|
|
VIR_INFO("Undefining network '%s'", network->def->name);
|
2012-10-25 14:32:29 +00:00
|
|
|
if (!active) {
|
|
|
|
if (networkRemoveInactive(driver, network) < 0) {
|
|
|
|
network = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-10-25 14:13:57 +00:00
|
|
|
network = NULL;
|
2010-12-20 06:14:11 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
ret = 0;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
networkDriverUnlock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2012-09-16 20:42:01 +00:00
|
|
|
static int
|
|
|
|
networkUpdate(virNetworkPtr net,
|
|
|
|
unsigned int command,
|
|
|
|
unsigned int section,
|
|
|
|
int parentIndex,
|
|
|
|
const char *xml,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network = NULL;
|
network: always create dnsmasq hosts and addnhosts files, even if empty
This fixes the problem reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=868389
Previously, the dnsmasq hosts file (used for static dhcp entries, and
addnhosts file (used for additional dns host entries) were only
created/referenced on the dnsmasq commandline if there was something
to put in them at the time the network was started. Once we can update
a network definition while it's active (which is now possible with
virNetworkUpdate), this is no longer a valid strategy - if there were
0 dhcp static hosts (resulting in no reference to the hosts file on the
commandline), then one was later added, the commandline wouldn't have
linked dnsmasq up to the file, so even though we create it, dnsmasq
doesn't pay any attention.
The solution is to just always create these files and reference them
on the dnsmasq commandline (almost always, anyway). That way dnsmasq
can notice when a new entry is added at runtime (a SIGHUP is sent to
dnsmasq by virNetworkUdpate whenever a host entry is added or removed)
The exception to this is that the dhcp static hosts file isn't created
if there are no lease ranges *and* no static hosts. This is because in
this case dnsmasq won't be setup to listen for dhcp requests anyway -
in that case, if the count of dhcp hosts goes from 0 to 1, dnsmasq
will need to be restarted anyway (to get it listening on the dhcp
port). Likewise, if the dhcp hosts count goes from 1 to 0 (and there
are no dhcp ranges) we need to restart dnsmasq so that it will stop
listening on port 67. These special situations are handled in the
bridge driver's networkUpdate() by checking for ((bool)
nranges||nhosts) both before and after the update, and triggering a
dnsmasq restart if the before and after don't match.
2012-10-19 20:15:44 +00:00
|
|
|
int isActive, ret = -1, ii;
|
|
|
|
virNetworkIpDefPtr ipdef;
|
|
|
|
bool oldDhcpActive = false;
|
|
|
|
|
2012-09-16 20:42:01 +00:00
|
|
|
|
|
|
|
virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
|
|
|
|
VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
|
|
|
-1);
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
|
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
|
|
|
if (!network) {
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
network: always create dnsmasq hosts and addnhosts files, even if empty
This fixes the problem reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=868389
Previously, the dnsmasq hosts file (used for static dhcp entries, and
addnhosts file (used for additional dns host entries) were only
created/referenced on the dnsmasq commandline if there was something
to put in them at the time the network was started. Once we can update
a network definition while it's active (which is now possible with
virNetworkUpdate), this is no longer a valid strategy - if there were
0 dhcp static hosts (resulting in no reference to the hosts file on the
commandline), then one was later added, the commandline wouldn't have
linked dnsmasq up to the file, so even though we create it, dnsmasq
doesn't pay any attention.
The solution is to just always create these files and reference them
on the dnsmasq commandline (almost always, anyway). That way dnsmasq
can notice when a new entry is added at runtime (a SIGHUP is sent to
dnsmasq by virNetworkUdpate whenever a host entry is added or removed)
The exception to this is that the dhcp static hosts file isn't created
if there are no lease ranges *and* no static hosts. This is because in
this case dnsmasq won't be setup to listen for dhcp requests anyway -
in that case, if the count of dhcp hosts goes from 0 to 1, dnsmasq
will need to be restarted anyway (to get it listening on the dhcp
port). Likewise, if the dhcp hosts count goes from 1 to 0 (and there
are no dhcp ranges) we need to restart dnsmasq so that it will stop
listening on port 67. These special situations are handled in the
bridge driver's networkUpdate() by checking for ((bool)
nranges||nhosts) both before and after the update, and triggering a
dnsmasq restart if the before and after don't match.
2012-10-19 20:15:44 +00:00
|
|
|
/* see if we are listening for dhcp pre-modification */
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
|
|
|
ii++) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
oldDhcpActive = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-16 20:42:01 +00:00
|
|
|
/* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
|
|
|
|
* is active, else change CONFIG
|
|
|
|
*/
|
|
|
|
isActive = virNetworkObjIsActive(network);
|
network: fix dnsmasq/radvd binding to IPv6 on recent kernels
I hit this problem recently when trying to create a bridge with an IPv6
address on a 3.2 kernel: dnsmasq (and, further, radvd) would not bind to
the given address, waiting 20s and then giving up with -EADDRNOTAVAIL
(resp. exiting immediately with "error parsing or activating the config
file", without libvirt noticing it, BTW). This can be reproduced with (I
think) any kernel >= 2.6.39 and the following XML (to be used with
"virsh net-create"):
<network>
<name>test-bridge</name>
<bridge name='testbr0' />
<ip family='ipv6' address='fd00::1' prefix='64'>
</ip>
</network>
(it happens even when you have an IPv4, too)
The problem is that since commit [1] (which, ironically, was made to
“help IPv6 autoconfiguration”) the linux bridge code makes bridges
behave like “real” devices regarding carrier detection. This makes the
bridges created by libvirt, which are started without any up devices,
stay with the NO-CARRIER flag set, and thus prevents DAD (Duplicate
address detection) from happening, thus letting the IPv6 address flagged
as “tentative”. Such addresses cannot be bound to (see RFC 2462), so
dnsmasq fails binding to it (for radvd, it detects that "interface XXX
is not RUNNING", thus that "interface XXX does not exist, ignoring the
interface" (sic)). It seems that this behavior was enhanced somehow with
commit [2] by avoiding setting NO-CARRIER on empty bridges, but I
couldn't reproduce this behavior on my kernel. Anyway, with the “dummy
tap to set MAC address” trick, this wouldn't work.
To fix this, the idea is to get the bridge's attached device to be up so
that DAD can happen (deactivating DAD altogether is not a good idea, I
think). Currently, libvirt creates a dummy TAP device to set the MAC
address of the bridge, keeping it down. But even if we set this device
up, it is not RUNNING as soon as the tap file descriptor attached to it
is closed, thus still preventing DAD. So, we must modify the API a bit,
so that we can get the fd, keep the tap device persistent, run the
daemons, and close it after DAD has taken place. After that, the bridge
will be flagged NO-CARRIER again, but the daemons will be running, even
if not happy about the device's state (but we don't really care about
the bridge's daemons doing anything when no up interface is connected to
it).
Other solutions that I envisioned were:
* Keeping the *-nic interface up: this would waste an fd for each
bridge during all its life. May be acceptable, I don't really
know.
* Stop using the dummy tap trick, and set the MAC address directly
on the bridge: it is possible since quite some time it seems,
even if then there is the problem of the bridge not being
RUNNING when empty, contrary to what [2] says, so this will need
fixing (and this fix only happened in 3.1, so it wouldn't work
for 2.6.39)
* Using the --interface option of dnsmasq, but I saw somewhere
that it's not used by libvirt for backward compatibility. I am
not sure this would solve this problem, though, as I don't know
how dnsmasq binds itself to it with this option.
This is why this patch does what's described earlier.
This patch also makes radvd start even if the interface is
“missing” (i.e. it is not RUNNING), as it daemonizes before binding to
it, and thus sometimes does it after the interface has been brought down
by us (by closing the tap fd), and then originally stops. This also
makes it stop yelling about it in the logs when the interface is down at
a later time.
[1]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=1faa4356a3bd89ea11fb92752d897cff3a20ec0e
[2]
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commit;h=b64b73d7d0c480f75684519c6134e79d50c1b341
2012-09-26 19:02:20 +00:00
|
|
|
if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
|
|
|
|
VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
|
2012-09-16 20:42:01 +00:00
|
|
|
VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
|
|
|
|
if (isActive)
|
|
|
|
flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
|
|
|
|
else
|
|
|
|
flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update the network config in memory/on disk */
|
|
|
|
if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
|
|
|
|
/* save updated persistent config to disk */
|
|
|
|
if (virNetworkSaveConfig(driver->networkConfigDir,
|
|
|
|
virNetworkObjGetPersistentDef(network)) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
|
|
|
|
/* rewrite dnsmasq host files, restart dnsmasq, update iptables
|
|
|
|
* rules, etc, according to which section was modified. Note that
|
|
|
|
* some sections require multiple actions, so a single switch
|
|
|
|
* statement is inadequate.
|
|
|
|
*/
|
|
|
|
if (section == VIR_NETWORK_SECTION_BRIDGE ||
|
|
|
|
section == VIR_NETWORK_SECTION_DOMAIN ||
|
|
|
|
section == VIR_NETWORK_SECTION_IP ||
|
|
|
|
section == VIR_NETWORK_SECTION_IP_DHCP_RANGE) {
|
|
|
|
/* these sections all change things on the dnsmasq commandline,
|
|
|
|
* so we need to kill and restart dnsmasq.
|
|
|
|
*/
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
if (networkRestartDhcpDaemon(driver, network) < 0)
|
2012-09-16 20:42:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
network: always create dnsmasq hosts and addnhosts files, even if empty
This fixes the problem reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=868389
Previously, the dnsmasq hosts file (used for static dhcp entries, and
addnhosts file (used for additional dns host entries) were only
created/referenced on the dnsmasq commandline if there was something
to put in them at the time the network was started. Once we can update
a network definition while it's active (which is now possible with
virNetworkUpdate), this is no longer a valid strategy - if there were
0 dhcp static hosts (resulting in no reference to the hosts file on the
commandline), then one was later added, the commandline wouldn't have
linked dnsmasq up to the file, so even though we create it, dnsmasq
doesn't pay any attention.
The solution is to just always create these files and reference them
on the dnsmasq commandline (almost always, anyway). That way dnsmasq
can notice when a new entry is added at runtime (a SIGHUP is sent to
dnsmasq by virNetworkUdpate whenever a host entry is added or removed)
The exception to this is that the dhcp static hosts file isn't created
if there are no lease ranges *and* no static hosts. This is because in
this case dnsmasq won't be setup to listen for dhcp requests anyway -
in that case, if the count of dhcp hosts goes from 0 to 1, dnsmasq
will need to be restarted anyway (to get it listening on the dhcp
port). Likewise, if the dhcp hosts count goes from 1 to 0 (and there
are no dhcp ranges) we need to restart dnsmasq so that it will stop
listening on port 67. These special situations are handled in the
bridge driver's networkUpdate() by checking for ((bool)
nranges||nhosts) both before and after the update, and triggering a
dnsmasq restart if the before and after don't match.
2012-10-19 20:15:44 +00:00
|
|
|
} else if (section == VIR_NETWORK_SECTION_IP_DHCP_HOST) {
|
|
|
|
/* if we previously weren't listening for dhcp and now we
|
|
|
|
* are (or vice-versa) then we need to do a restart,
|
|
|
|
* otherwise we just need to do a refresh (redo the config
|
|
|
|
* files and send SIGHUP)
|
|
|
|
*/
|
|
|
|
bool newDhcpActive = false;
|
|
|
|
|
|
|
|
for (ii = 0;
|
|
|
|
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
|
|
|
ii++) {
|
|
|
|
if (ipdef->nranges || ipdef->nhosts) {
|
|
|
|
newDhcpActive = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((newDhcpActive != oldDhcpActive &&
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
networkRestartDhcpDaemon(driver, network) < 0) ||
|
|
|
|
networkRefreshDhcpDaemon(driver, network) < 0) {
|
network: always create dnsmasq hosts and addnhosts files, even if empty
This fixes the problem reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=868389
Previously, the dnsmasq hosts file (used for static dhcp entries, and
addnhosts file (used for additional dns host entries) were only
created/referenced on the dnsmasq commandline if there was something
to put in them at the time the network was started. Once we can update
a network definition while it's active (which is now possible with
virNetworkUpdate), this is no longer a valid strategy - if there were
0 dhcp static hosts (resulting in no reference to the hosts file on the
commandline), then one was later added, the commandline wouldn't have
linked dnsmasq up to the file, so even though we create it, dnsmasq
doesn't pay any attention.
The solution is to just always create these files and reference them
on the dnsmasq commandline (almost always, anyway). That way dnsmasq
can notice when a new entry is added at runtime (a SIGHUP is sent to
dnsmasq by virNetworkUdpate whenever a host entry is added or removed)
The exception to this is that the dhcp static hosts file isn't created
if there are no lease ranges *and* no static hosts. This is because in
this case dnsmasq won't be setup to listen for dhcp requests anyway -
in that case, if the count of dhcp hosts goes from 0 to 1, dnsmasq
will need to be restarted anyway (to get it listening on the dhcp
port). Likewise, if the dhcp hosts count goes from 1 to 0 (and there
are no dhcp ranges) we need to restart dnsmasq so that it will stop
listening on port 67. These special situations are handled in the
bridge driver's networkUpdate() by checking for ((bool)
nranges||nhosts) both before and after the update, and triggering a
dnsmasq restart if the before and after don't match.
2012-10-19 20:15:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (section == VIR_NETWORK_SECTION_DNS_HOST ||
|
2012-09-16 20:42:01 +00:00
|
|
|
section == VIR_NETWORK_SECTION_DNS_TXT ||
|
|
|
|
section == VIR_NETWORK_SECTION_DNS_SRV) {
|
|
|
|
/* these sections only change things in config files, so we
|
|
|
|
* can just update the config files and send SIGHUP to
|
|
|
|
* dnsmasq.
|
|
|
|
*/
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
if (networkRefreshDhcpDaemon(driver, network) < 0)
|
2012-09-16 20:42:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (section == VIR_NETWORK_SECTION_IP) {
|
|
|
|
/* only a change in IP addresses will affect radvd, and all of radvd's
|
|
|
|
* config is stored in the conf file which will be re-read with a SIGHUP.
|
|
|
|
*/
|
util: capabilities detection for dnsmasq
In order to optionally take advantage of new features in dnsmasq when
the host's version of dnsmasq supports them, but still be able to run
on hosts that don't support the new features, we need to be able to
detect the version of dnsmasq running on the host, and possibly
determine from the help output what options are in this dnsmasq.
This patch implements a greatly simplified version of the capabilities
code we already have for qemu. A dnsmasqCaps device can be created and
populated either from running a program on disk, reading a file with
the concatenated output of "dnsmasq --version; dnsmasq --help", or
examining a buffer in memory that contains the concatenated output of
those two commands. Simple functions to retrieve capabilities flags,
the version number, and the path of the binary are also included.
bridge_driver.c creates a single dnsmasqCaps object at driver startup,
and disposes of it at driver shutdown. Any time it must be used, the
dnsmasqCapsRefresh method is called - it checks the mtime of the
binary, and re-runs the checks if the binary has changed.
networkxml2argvtest.c creates 2 "artificial" dnsmasqCaps objects at
startup - one "restricted" (doesn't support --bind-dynamic) and one
"full" (does support --bind-dynamic). Some of the test cases use one
and some the other, to make sure both code pathes are tested.
2012-11-20 17:22:15 +00:00
|
|
|
if (networkRefreshRadvd(driver, network) < 0)
|
2012-09-16 20:42:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-09-21 19:28:11 +00:00
|
|
|
if ((section == VIR_NETWORK_SECTION_IP ||
|
|
|
|
section == VIR_NETWORK_SECTION_FORWARD ||
|
|
|
|
section == VIR_NETWORK_SECTION_FORWARD_INTERFACE) &&
|
2012-11-08 02:16:17 +00:00
|
|
|
(network->def->forward.type == VIR_NETWORK_FORWARD_NONE ||
|
|
|
|
network->def->forward.type == VIR_NETWORK_FORWARD_NAT ||
|
|
|
|
network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
|
2012-09-16 20:42:01 +00:00
|
|
|
/* these could affect the iptables rules */
|
|
|
|
networkRemoveIptablesRules(driver, network);
|
|
|
|
if (networkAddIptablesRules(driver, network) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* save current network state to disk */
|
2013-05-02 17:59:52 +00:00
|
|
|
if ((ret = virNetworkSaveStatus(driverState->stateDir,
|
|
|
|
network)) < 0) {
|
2012-09-16 20:42:01 +00:00
|
|
|
goto cleanup;
|
2013-05-02 17:59:52 +00:00
|
|
|
}
|
2012-09-16 20:42:01 +00:00
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-04-23 12:50:18 +00:00
|
|
|
static int networkCreate(virNetworkPtr net) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
int ret = -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
network: separate Start/Shutdown functions for new network types
Previously all networks were composed of bridge devices created and
managed by libvirt, and the same operations needed to be done for all
of them when they were started and stopped (create and start the
bridge device, configure its MAC address and IP address, add iptables
rules). The new network types are (for now at least) managed outside
of libvirt, and the network object is used only to contain information
about the network, which is then used as each individual guest
connects itself.
This means that when starting/stopping one of these new networks, we
really want to do nothing, aside from marking the network as
active/inactive.
This has been setup as toplevel Start/Shutdown functions that do the
small bit of common stuff, then have a switch statement to execute
network type-specific start/shutdown code, then do a bit more common
code. The type-specific functions called for the new host bridge and
macvtap based types are currently empty.
In the future these functions may actually do something, and we will
surely add more functions that are similarly patterned. Once
everything has settled, we can make a table of "sub-driver" function
pointers for each network type, and store a pointer to that table in
the network object, then we can replace the switch statements with
calls to functions in the table.
The final step in this will be to add a new table (and corresponding
new functions) for new network types as they are added.
2011-06-30 21:05:07 +00:00
|
|
|
ret = networkStartNetwork(driver, network);
|
2008-12-04 21:37:52 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2009-05-19 11:06:25 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int networkDestroy(virNetworkPtr net) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
int ret = -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (!virNetworkObjIsActive(network)) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("network is not active"));
|
2009-05-29 14:14:32 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-10-25 14:13:57 +00:00
|
|
|
if ((ret = networkShutdownNetwork(driver, network)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (!network->persistent) {
|
2012-10-25 14:13:57 +00:00
|
|
|
if (networkRemoveInactive(driver, network) < 0) {
|
|
|
|
network = NULL;
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-12-04 21:38:38 +00:00
|
|
|
network = NULL;
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2009-05-19 11:06:25 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-07-06 20:40:19 +00:00
|
|
|
static char *networkGetXMLDesc(virNetworkPtr net,
|
2011-07-06 22:29:02 +00:00
|
|
|
unsigned int flags)
|
2011-07-06 20:40:19 +00:00
|
|
|
{
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
2012-06-04 18:45:16 +00:00
|
|
|
virNetworkDefPtr def;
|
2008-12-04 21:37:52 +00:00
|
|
|
char *ret = NULL;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2011-12-14 10:50:40 +00:00
|
|
|
virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
|
2011-07-06 22:29:02 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2012-06-04 18:45:16 +00:00
|
|
|
if ((flags & VIR_NETWORK_XML_INACTIVE) && network->newDef)
|
|
|
|
def = network->newDef;
|
|
|
|
else
|
|
|
|
def = network->def;
|
|
|
|
|
|
|
|
ret = virNetworkDefFormat(def, flags);
|
2008-12-04 21:37:52 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *networkGetBridgeName(virNetworkPtr net) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
char *bridge = NULL;
|
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching id"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 14:57:45 +00:00
|
|
|
if (!(network->def->bridge)) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' does not have a bridge name."),
|
|
|
|
network->def->name);
|
2008-12-11 14:57:45 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-03 12:43:59 +00:00
|
|
|
ignore_value(VIR_STRDUP(bridge, network->def->bridge));
|
2008-12-04 21:37:52 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2008-10-10 13:57:13 +00:00
|
|
|
return bridge;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int networkGetAutostart(virNetworkPtr net,
|
|
|
|
int *autostart) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
int ret = -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*autostart = network->autostart;
|
2008-12-04 21:37:52 +00:00
|
|
|
ret = 0;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
cleanup:
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int networkSetAutostart(virNetworkPtr net,
|
2009-01-20 22:36:10 +00:00
|
|
|
int autostart) {
|
2008-12-04 21:37:52 +00:00
|
|
|
struct network_driver *driver = net->conn->networkPrivateData;
|
|
|
|
virNetworkObjPtr network;
|
2009-01-20 22:36:10 +00:00
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
2008-12-04 21:37:52 +00:00
|
|
|
int ret = -1;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:38:38 +00:00
|
|
|
networkDriverLock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
network = virNetworkFindByUUID(&driver->networks, net->uuid);
|
2008-12-04 21:38:38 +00:00
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
"%s", _("no network with matching uuid"));
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2009-06-03 13:52:06 +00:00
|
|
|
if (!network->persistent) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
"%s", _("cannot set autostart for transient network"));
|
2009-06-03 13:52:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:57:13 +00:00
|
|
|
autostart = (autostart != 0);
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
if (network->autostart != autostart) {
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
|
2009-01-20 22:36:10 +00:00
|
|
|
goto cleanup;
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
|
2009-01-20 22:36:10 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
if (autostart) {
|
2011-07-05 21:02:53 +00:00
|
|
|
if (virFileMakePath(driver->networkAutostartDir) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot create autostart directory '%s'"),
|
|
|
|
driver->networkAutostartDir);
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (symlink(configFile, autostartLink) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("Failed to create symlink '%s' to '%s'"),
|
2009-01-20 22:36:10 +00:00
|
|
|
autostartLink, configFile);
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2009-01-20 22:36:10 +00:00
|
|
|
if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("Failed to delete symlink '%s'"),
|
2009-01-20 22:36:10 +00:00
|
|
|
autostartLink);
|
2008-12-04 21:37:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
network->autostart = autostart;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
2008-12-04 21:37:52 +00:00
|
|
|
ret = 0;
|
2008-10-10 13:57:13 +00:00
|
|
|
|
2008-12-04 21:37:52 +00:00
|
|
|
cleanup:
|
2009-01-20 22:36:10 +00:00
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
2008-12-04 21:38:38 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2009-05-19 11:06:25 +00:00
|
|
|
networkDriverUnlock(driver);
|
2008-12-04 21:37:52 +00:00
|
|
|
return ret;
|
2008-10-10 13:57:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virNetworkDriver networkDriver = {
|
|
|
|
"Network",
|
2013-04-23 12:50:18 +00:00
|
|
|
.networkOpen = networkOpen, /* 0.2.0 */
|
|
|
|
.networkClose = networkClose, /* 0.2.0 */
|
|
|
|
.connectNumOfNetworks = networkConnectNumOfNetworks, /* 0.2.0 */
|
|
|
|
.connectListNetworks = networkConnectListNetworks, /* 0.2.0 */
|
|
|
|
.connectNumOfDefinedNetworks = networkConnectNumOfDefinedNetworks, /* 0.2.0 */
|
|
|
|
.connectListDefinedNetworks = networkConnectListDefinedNetworks, /* 0.2.0 */
|
|
|
|
.connectListAllNetworks = networkConnectListAllNetworks, /* 0.10.2 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
|
|
|
|
.networkLookupByName = networkLookupByName, /* 0.2.0 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.networkCreateXML = networkCreateXML, /* 0.2.0 */
|
|
|
|
.networkDefineXML = networkDefineXML, /* 0.2.0 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.networkUndefine = networkUndefine, /* 0.2.0 */
|
2012-09-16 20:42:01 +00:00
|
|
|
.networkUpdate = networkUpdate, /* 0.10.2 */
|
2013-04-23 12:50:18 +00:00
|
|
|
.networkCreate = networkCreate, /* 0.2.0 */
|
2011-05-13 13:35:01 +00:00
|
|
|
.networkDestroy = networkDestroy, /* 0.2.0 */
|
|
|
|
.networkGetXMLDesc = networkGetXMLDesc, /* 0.2.0 */
|
|
|
|
.networkGetBridgeName = networkGetBridgeName, /* 0.2.0 */
|
|
|
|
.networkGetAutostart = networkGetAutostart, /* 0.2.1 */
|
|
|
|
.networkSetAutostart = networkSetAutostart, /* 0.2.1 */
|
|
|
|
.networkIsActive = networkIsActive, /* 0.7.3 */
|
|
|
|
.networkIsPersistent = networkIsPersistent, /* 0.7.3 */
|
2008-10-10 13:57:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static virStateDriver networkStateDriver = {
|
2012-10-31 19:03:50 +00:00
|
|
|
.name = "Network",
|
2013-04-23 12:50:18 +00:00
|
|
|
.stateInitialize = networkStateInitialize,
|
|
|
|
.stateCleanup = networkStateCleanup,
|
|
|
|
.stateReload = networkStateReload,
|
2008-10-10 13:57:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int networkRegister(void) {
|
|
|
|
virRegisterNetworkDriver(&networkDriver);
|
|
|
|
virRegisterStateDriver(&networkStateDriver);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
/********************************************************/
|
|
|
|
|
|
|
|
/* Private API to deal with logical switch capabilities.
|
|
|
|
* These functions are exported so that other parts of libvirt can
|
|
|
|
* call them, but are not part of the public API and not in the
|
|
|
|
* driver's function table. If we ever have more than one network
|
|
|
|
* driver, we will need to present these functions via a second
|
|
|
|
* "backend" function table.
|
|
|
|
*/
|
|
|
|
|
2012-08-16 15:41:24 +00:00
|
|
|
/* networkCreateInterfacePool:
|
|
|
|
* @netdef: the original NetDef from the network
|
|
|
|
*
|
|
|
|
* Creates an implicit interface pool of VF's when a PF dev is given
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
networkCreateInterfacePool(virNetworkDefPtr netdef) {
|
|
|
|
unsigned int num_virt_fns = 0;
|
|
|
|
char **vfname = NULL;
|
2013-01-14 22:11:44 +00:00
|
|
|
virPCIDeviceAddressPtr *virt_fns;
|
2012-08-16 15:41:24 +00:00
|
|
|
int ret = -1, ii = 0;
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev,
|
2012-08-16 15:41:58 +00:00
|
|
|
&vfname, &virt_fns, &num_virt_fns)) < 0) {
|
2012-08-16 15:41:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Could not get Virtual functions on %s"),
|
2012-11-08 02:16:17 +00:00
|
|
|
netdef->forward.pfs->dev);
|
2012-08-16 15:41:24 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_virt_fns == 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("No Vf's present on SRIOV PF %s"),
|
2012-11-08 02:16:17 +00:00
|
|
|
netdef->forward.pfs->dev);
|
2012-08-16 15:41:24 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if ((VIR_ALLOC_N(netdef->forward.ifs, num_virt_fns)) < 0) {
|
2012-08-16 15:41:24 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
netdef->forward.nifs = num_virt_fns;
|
2012-08-16 15:41:24 +00:00
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_VEPA) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
|
|
|
|
netdef->forward.ifs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
|
2012-10-17 09:23:12 +00:00
|
|
|
if (vfname[ii]) {
|
2013-05-03 12:43:59 +00:00
|
|
|
if (VIR_STRDUP(netdef->forward.ifs[ii].device.dev, vfname[ii]) < 0)
|
2012-08-16 15:41:58 +00:00
|
|
|
goto finish;
|
2013-05-03 12:43:59 +00:00
|
|
|
} else {
|
2012-08-16 15:41:58 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2012-08-22 18:29:18 +00:00
|
|
|
_("Direct mode types require interface names"));
|
2012-08-16 15:41:58 +00:00
|
|
|
goto finish;
|
|
|
|
}
|
2012-08-16 15:41:24 +00:00
|
|
|
}
|
2012-11-08 02:16:17 +00:00
|
|
|
else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
|
2012-08-16 15:42:31 +00:00
|
|
|
/* VF's are always PCI devices */
|
2012-11-08 02:16:17 +00:00
|
|
|
netdef->forward.ifs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI;
|
|
|
|
netdef->forward.ifs[ii].device.pci.domain = virt_fns[ii]->domain;
|
|
|
|
netdef->forward.ifs[ii].device.pci.bus = virt_fns[ii]->bus;
|
|
|
|
netdef->forward.ifs[ii].device.pci.slot = virt_fns[ii]->slot;
|
|
|
|
netdef->forward.ifs[ii].device.pci.function = virt_fns[ii]->function;
|
2012-08-16 15:42:31 +00:00
|
|
|
}
|
2012-08-16 15:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
finish:
|
2012-08-16 15:41:58 +00:00
|
|
|
for (ii = 0; ii < num_virt_fns; ii++) {
|
2012-08-16 15:41:24 +00:00
|
|
|
VIR_FREE(vfname[ii]);
|
2012-08-16 15:41:58 +00:00
|
|
|
VIR_FREE(virt_fns[ii]);
|
|
|
|
}
|
2012-08-16 15:41:24 +00:00
|
|
|
VIR_FREE(vfname);
|
2012-08-16 15:41:58 +00:00
|
|
|
VIR_FREE(virt_fns);
|
2012-08-16 15:41:24 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
/* networkAllocateActualDevice:
|
|
|
|
* @iface: the original NetDef from the domain
|
|
|
|
*
|
|
|
|
* Looks up the network reference by iface, allocates a physical
|
|
|
|
* device from that network (if appropriate), and returns with the
|
|
|
|
* virDomainActualNetDef filled in accordingly. If there are no
|
|
|
|
* changes to be made in the netdef, then just leave the actualdef
|
|
|
|
* empty.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
networkAllocateActualDevice(virDomainNetDefPtr iface)
|
|
|
|
{
|
|
|
|
struct network_driver *driver = driverState;
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
enum virDomainNetType actualType = iface->type;
|
|
|
|
virNetworkObjPtr network = NULL;
|
|
|
|
virNetworkDefPtr netdef = NULL;
|
2012-11-16 13:29:01 +00:00
|
|
|
virNetDevBandwidthPtr bandwidth = NULL;
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
virPortGroupDefPtr portgroup = NULL;
|
|
|
|
virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
|
|
|
|
virNetDevVlanPtr vlan = NULL;
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
virNetworkForwardIfDefPtr dev = NULL;
|
2011-12-14 10:50:30 +00:00
|
|
|
int ii;
|
2011-07-04 06:27:12 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
goto validate;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
virDomainActualNetDefFree(iface->data.network.actual);
|
|
|
|
iface->data.network.actual = NULL;
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
network = virNetworkFindByName(&driver->networks, iface->data.network.name);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
_("no network with matching name '%s'"),
|
|
|
|
iface->data.network.name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
netdef = network->def;
|
2011-10-04 03:53:36 +00:00
|
|
|
|
|
|
|
/* portgroup can be present for any type of network, in particular
|
|
|
|
* for bandwidth information, so we need to check for that and
|
|
|
|
* fill it in appropriately for all forward types.
|
|
|
|
*/
|
|
|
|
portgroup = virPortGroupFindByName(netdef, iface->data.network.portgroup);
|
|
|
|
|
|
|
|
/* If there is already interface-specific bandwidth, just use that
|
|
|
|
* (already in NetDef). Otherwise, if there is bandwidth info in
|
|
|
|
* the portgroup, fill that into the ActualDef.
|
|
|
|
*/
|
2012-11-16 13:29:01 +00:00
|
|
|
|
|
|
|
if (iface->bandwidth)
|
|
|
|
bandwidth = iface->bandwidth;
|
|
|
|
else if (portgroup && portgroup->bandwidth)
|
|
|
|
bandwidth = portgroup->bandwidth;
|
|
|
|
|
|
|
|
if (bandwidth) {
|
2011-10-04 03:53:36 +00:00
|
|
|
if (!iface->data.network.actual
|
|
|
|
&& (VIR_ALLOC(iface->data.network.actual) < 0)) {
|
|
|
|
virReportOOMError();
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-10-04 03:53:36 +00:00
|
|
|
}
|
|
|
|
|
Adjust naming of network device bandwidth management APIs
Rename virBandwidth to virNetDevBandwidth, and virRate to
virNetDevBandwidthRate.
* src/util/network.c, src/util/network.h: Rename bandwidth
structs and APIs
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/network_conf.c, src/conf/network_conf.h,
src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/util/macvtap.c,
src/util/macvtap.h, tools/virsh.c: Update for API changes.
2011-11-02 14:29:05 +00:00
|
|
|
if (virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
|
2012-11-16 13:29:01 +00:00
|
|
|
bandwidth) < 0)
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-10-04 03:53:36 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 18:35:34 +00:00
|
|
|
/* copy appropriate vlan info to actualNet */
|
|
|
|
if (iface->vlan.nTags > 0)
|
|
|
|
vlan = &iface->vlan;
|
|
|
|
else if (portgroup && portgroup->vlan.nTags > 0)
|
|
|
|
vlan = &portgroup->vlan;
|
|
|
|
else if (netdef->vlan.nTags > 0)
|
|
|
|
vlan = &netdef->vlan;
|
|
|
|
|
|
|
|
if (vlan) {
|
|
|
|
if (!iface->data.network.actual
|
|
|
|
&& (VIR_ALLOC(iface->data.network.actual) < 0)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
|
2011-10-04 03:53:36 +00:00
|
|
|
/* for these forward types, the actual net type really *is*
|
|
|
|
*NETWORK; we just keep the info from the portgroup in
|
|
|
|
* iface->data.network.actual
|
|
|
|
*/
|
|
|
|
if (iface->data.network.actual)
|
|
|
|
iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
|
2012-11-16 13:29:01 +00:00
|
|
|
|
|
|
|
if (networkPlugBandwidth(network, iface) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
} else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
|
2011-10-04 03:53:36 +00:00
|
|
|
netdef->bridge) {
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
/* <forward type='bridge'/> <bridge name='xxx'/>
|
|
|
|
* is VIR_DOMAIN_NET_TYPE_BRIDGE
|
|
|
|
*/
|
|
|
|
|
2011-10-04 03:53:36 +00:00
|
|
|
if (!iface->data.network.actual
|
|
|
|
&& (VIR_ALLOC(iface->data.network.actual) < 0)) {
|
2011-07-04 06:27:12 +00:00
|
|
|
virReportOOMError();
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
|
2013-05-03 12:43:59 +00:00
|
|
|
if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
|
|
|
|
netdef->bridge) < 0)
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
/* merge virtualports from interface, network, and portgroup to
|
|
|
|
* arrive at actual virtualport to use
|
|
|
|
*/
|
|
|
|
if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
|
|
|
|
iface->virtPortProfile,
|
|
|
|
netdef->virtPortProfile,
|
|
|
|
portgroup
|
|
|
|
? portgroup->virtPortProfile : NULL) < 0) {
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
}
|
|
|
|
virtport = iface->data.network.actual->virtPortProfile;
|
|
|
|
if (virtport) {
|
|
|
|
/* only type='openvswitch' is allowed for bridges */
|
|
|
|
if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("<virtualport type='%s'> not supported for network "
|
|
|
|
"'%s' which uses a bridge device"),
|
|
|
|
virNetDevVPortTypeToString(virtport->virtPortType),
|
|
|
|
netdef->name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
} else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
|
2012-08-16 15:42:31 +00:00
|
|
|
|
2013-04-26 20:23:27 +00:00
|
|
|
virDomainHostdevSubsysPciBackendType backend;
|
|
|
|
|
2012-08-16 15:42:31 +00:00
|
|
|
if (!iface->data.network.actual
|
|
|
|
&& (VIR_ALLOC(iface->data.network.actual) < 0)) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
|
2012-11-08 02:16:17 +00:00
|
|
|
if (netdef->forward.npfs > 0 && netdef->forward.nifs <= 0 &&
|
2012-08-16 15:42:31 +00:00
|
|
|
networkCreateInterfacePool(netdef) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pick first dev with 0 connections */
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].connections == 0) {
|
|
|
|
dev = &netdef->forward.ifs[ii];
|
2012-08-16 15:42:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' requires exclusive access "
|
|
|
|
"to interfaces, but none are available"),
|
|
|
|
netdef->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET;
|
|
|
|
iface->data.network.actual->data.hostdev.def.parent.data.net = iface;
|
|
|
|
iface->data.network.actual->data.hostdev.def.info = &iface->info;
|
|
|
|
iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
|
2012-11-08 02:16:17 +00:00
|
|
|
iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
|
2012-08-16 15:42:31 +00:00
|
|
|
iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
|
2013-03-18 19:56:12 +00:00
|
|
|
iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
|
2012-08-16 15:42:31 +00:00
|
|
|
|
2013-04-26 20:23:27 +00:00
|
|
|
switch (netdef->forward.driverName)
|
|
|
|
{
|
|
|
|
case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
|
2013-04-26 20:44:05 +00:00
|
|
|
backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
|
2013-04-26 20:23:27 +00:00
|
|
|
break;
|
|
|
|
case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
|
2013-04-26 20:44:05 +00:00
|
|
|
backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
|
2013-04-26 20:23:27 +00:00
|
|
|
break;
|
|
|
|
case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
|
2013-04-26 20:44:05 +00:00
|
|
|
backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
|
2013-04-26 20:23:27 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unrecognized driver name value %d "
|
|
|
|
" in network '%s'"),
|
|
|
|
netdef->forward.driverName, netdef->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.backend
|
|
|
|
= backend;
|
|
|
|
|
2012-08-16 15:42:31 +00:00
|
|
|
/* merge virtualports from interface, network, and portgroup to
|
|
|
|
* arrive at actual virtualport to use
|
|
|
|
*/
|
|
|
|
if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
|
|
|
|
iface->virtPortProfile,
|
|
|
|
netdef->virtPortProfile,
|
|
|
|
portgroup
|
|
|
|
? portgroup->virtPortProfile : NULL) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virtport = iface->data.network.actual->virtPortProfile;
|
|
|
|
if (virtport) {
|
|
|
|
/* make sure type is supported for hostdev connections */
|
|
|
|
if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
|
|
|
|
virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("<virtualport type='%s'> not supported for network "
|
|
|
|
"'%s' which uses an SR-IOV Virtual Function "
|
|
|
|
"via PCI passthrough"),
|
|
|
|
virNetDevVPortTypeToString(virtport->virtPortType),
|
|
|
|
netdef->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
} else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_VEPA) ||
|
|
|
|
(netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
/* <forward type='bridge|private|vepa|passthrough'> are all
|
|
|
|
* VIR_DOMAIN_NET_TYPE_DIRECT.
|
|
|
|
*/
|
|
|
|
|
2011-10-04 03:53:36 +00:00
|
|
|
if (!iface->data.network.actual
|
|
|
|
&& (VIR_ALLOC(iface->data.network.actual) < 0)) {
|
2011-07-04 06:27:12 +00:00
|
|
|
virReportOOMError();
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set type=direct and appropriate <source mode='xxx'/> */
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
|
2012-11-08 02:16:17 +00:00
|
|
|
switch (netdef->forward.type) {
|
2011-07-04 06:27:12 +00:00
|
|
|
case VIR_NETWORK_FORWARD_BRIDGE:
|
Rename Macvtap management APIs
In preparation for code re-organization, rename the Macvtap
management APIs to have the following patterns
virNetDevMacVLanXXXXX - macvlan/macvtap interface management
virNetDevVPortProfileXXXX - virtual port profile management
* src/util/macvtap.c, src/util/macvtap.h: Rename APIs
* src/conf/domain_conf.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_command.h,
src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/qemu/qemu_process.h: Update for renamed APIs
2011-11-02 16:51:01 +00:00
|
|
|
iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
case VIR_NETWORK_FORWARD_PRIVATE:
|
Rename Macvtap management APIs
In preparation for code re-organization, rename the Macvtap
management APIs to have the following patterns
virNetDevMacVLanXXXXX - macvlan/macvtap interface management
virNetDevVPortProfileXXXX - virtual port profile management
* src/util/macvtap.c, src/util/macvtap.h: Rename APIs
* src/conf/domain_conf.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_command.h,
src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/qemu/qemu_process.h: Update for renamed APIs
2011-11-02 16:51:01 +00:00
|
|
|
iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
case VIR_NETWORK_FORWARD_VEPA:
|
Rename Macvtap management APIs
In preparation for code re-organization, rename the Macvtap
management APIs to have the following patterns
virNetDevMacVLanXXXXX - macvlan/macvtap interface management
virNetDevVPortProfileXXXX - virtual port profile management
* src/util/macvtap.c, src/util/macvtap.h: Rename APIs
* src/conf/domain_conf.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_command.h,
src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/qemu/qemu_process.h: Update for renamed APIs
2011-11-02 16:51:01 +00:00
|
|
|
iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
case VIR_NETWORK_FORWARD_PASSTHROUGH:
|
Rename Macvtap management APIs
In preparation for code re-organization, rename the Macvtap
management APIs to have the following patterns
virNetDevMacVLanXXXXX - macvlan/macvtap interface management
virNetDevVPortProfileXXXX - virtual port profile management
* src/util/macvtap.c, src/util/macvtap.h: Rename APIs
* src/conf/domain_conf.c, src/network/bridge_driver.c,
src/qemu/qemu_command.c, src/qemu/qemu_command.h,
src/qemu/qemu_driver.c, src/qemu/qemu_hotplug.c,
src/qemu/qemu_migration.c, src/qemu/qemu_process.c,
src/qemu/qemu_process.h: Update for renamed APIs
2011-11-02 16:51:01 +00:00
|
|
|
iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
/* merge virtualports from interface, network, and portgroup to
|
|
|
|
* arrive at actual virtualport to use
|
|
|
|
*/
|
|
|
|
if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
|
|
|
|
iface->virtPortProfile,
|
|
|
|
netdef->virtPortProfile,
|
|
|
|
portgroup
|
|
|
|
? portgroup->virtPortProfile : NULL) < 0) {
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
virtport = iface->data.network.actual->virtPortProfile;
|
2011-07-04 06:27:12 +00:00
|
|
|
if (virtport) {
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
/* make sure type is supported for macvtap connections */
|
|
|
|
if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
|
|
|
|
virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("<virtualport type='%s'> not supported for network "
|
|
|
|
"'%s' which uses a macvtap device"),
|
|
|
|
virNetDevVPortTypeToString(virtport->virtPortType),
|
|
|
|
netdef->name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-26 12:42:37 +00:00
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
/* If there is only a single device, just return it (caller will detect
|
|
|
|
* any error if exclusive use is required but could not be acquired).
|
|
|
|
*/
|
2012-11-08 02:16:17 +00:00
|
|
|
if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' uses a direct mode, but "
|
|
|
|
"has no forward dev and no interface pool"),
|
|
|
|
netdef->name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
} else {
|
|
|
|
/* pick an interface from the pool */
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if (netdef->forward.npfs > 0 && netdef->forward.nifs == 0 &&
|
2012-08-16 15:41:58 +00:00
|
|
|
networkCreateInterfacePool(netdef) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-08-05 06:45:04 +00:00
|
|
|
/* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both
|
|
|
|
* require exclusive access to a device, so current
|
|
|
|
* connections count must be 0. Other modes can share, so
|
|
|
|
* just search for the one with the lowest number of
|
|
|
|
* connections.
|
2011-07-04 06:27:12 +00:00
|
|
|
*/
|
2012-11-08 02:16:17 +00:00
|
|
|
if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
|
|
|
|
((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
|
2012-08-16 15:41:58 +00:00
|
|
|
iface->data.network.actual->virtPortProfile &&
|
|
|
|
(iface->data.network.actual->virtPortProfile->virtPortType
|
|
|
|
== VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
|
2011-12-14 10:50:30 +00:00
|
|
|
|
2012-08-05 06:45:04 +00:00
|
|
|
/* pick first dev with 0 connections */
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].connections == 0) {
|
|
|
|
dev = &netdef->forward.ifs[ii];
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* pick least used dev */
|
2012-11-08 02:16:17 +00:00
|
|
|
dev = &netdef->forward.ifs[0];
|
|
|
|
for (ii = 1; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].connections < dev->connections)
|
|
|
|
dev = &netdef->forward.ifs[ii];
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* dev points at the physical device we want to use */
|
|
|
|
if (!dev) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' requires exclusive access "
|
|
|
|
"to interfaces, but none are available"),
|
|
|
|
netdef->name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
2013-05-03 12:43:59 +00:00
|
|
|
if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
|
|
|
|
dev->device.dev) < 0)
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
validate:
|
|
|
|
/* make sure that everything now specified for the device is
|
|
|
|
* actually supported on this type of network. NB: network,
|
|
|
|
* netdev, and iface->data.network.actual may all be NULL.
|
|
|
|
*/
|
|
|
|
|
2013-01-15 18:35:34 +00:00
|
|
|
if (virDomainNetGetActualVlan(iface)) {
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
/* vlan configuration via libvirt is only supported for
|
|
|
|
* PCI Passthrough SR-IOV devices and openvswitch bridges.
|
|
|
|
* otherwise log an error and fail
|
|
|
|
*/
|
|
|
|
if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
|
|
|
|
(actualType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
|
|
|
|
virtport && virtport->virtPortType
|
|
|
|
== VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
|
|
|
|
if (netdef) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("an interface connecting to network '%s' "
|
|
|
|
"is requesting a vlan tag, but that is not "
|
|
|
|
"supported for this type of network"),
|
|
|
|
netdef->name);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("an interface of type '%s' "
|
|
|
|
"is requesting a vlan tag, but that is not "
|
|
|
|
"supported for this type of connection"),
|
|
|
|
virDomainNetTypeToString(iface->type));
|
|
|
|
}
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
if (dev) {
|
|
|
|
/* we are now assured of success, so mark the allocation */
|
2012-08-05 06:45:04 +00:00
|
|
|
dev->connections++;
|
2012-08-16 15:42:31 +00:00
|
|
|
if (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
|
VIR_DEBUG("Using physical device %s, %d connections",
|
|
|
|
dev->device.dev, dev->connections);
|
|
|
|
} else {
|
|
|
|
VIR_DEBUG("Using physical device %04x:%02x:%02x.%x, connections %d",
|
|
|
|
dev->device.pci.domain, dev->device.pci.bus,
|
|
|
|
dev->device.pci.slot, dev->device.pci.function,
|
|
|
|
dev->connections);
|
|
|
|
}
|
network: merge relevant virtualports rather than choosing one
One of the original ideas behind allowing a <virtualport> in an
interface definition as well as in the <network> definition *and*one
or more <portgroup>s within the network, was that guest-specific
parameteres (like instanceid and interfaceid) could be given in the
interface's virtualport, and more general things (portid, managerid,
etc) could be given in the network and/or portgroup, with all the bits
brought together at guest startup time and combined into a single
virtualport to be used by the guest. This was somehow overlooked in
the implementation, though - it simply picks the "most specific"
virtualport, and uses the entire thing, with no attempt to merge in
details from the others.
This patch uses virNetDevVPortProfileMerge3() to combine the three
possible virtualports into one, then uses
virNetDevVPortProfileCheck*() to verify that the resulting virtualport
type is appropriate for the type of network, and that all the required
attributes for that type are present.
An example of usage is this: assuming a <network> definitions on host
ABC of:
<network>
<name>testA</name>
...
<virtualport type='openvswitch'/>
...
<portgroup name='engineering'>
<virtualport>
<parameters profileid='eng'/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters profileid='sales'/>
</virtualport>
</portgroup>
</network>
and the same <network> on host DEF of:
<network>
<name>testA</name>
...
<virtualport type='802.1Qbg'>
<parameters typeid="1193047" typeidversion="2"/>
</virtualport>
...
<portgroup name='engineering'>
<virtualport>
<parameters managerid="11"/>
</virtualport>
</portgroup>
<portgroup name='sales'>
<virtualport>
<parameters managerid="55"/>
</virtualport>
</portgroup>
</network>
and a guest <interface> definition of:
<interface type='network'>
<source network='testA' portgroup='sales'/>
<virtualport>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
interfaceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"\>
</virtualport>
...
</interface>
If the guest was started on host ABC, the <virtualport> used would be:
<virtualport type='openvswitch'>
<parameters interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'
profileid='sales'/>
</virtualport>
but if that guest was started on host DEF, the <virtualport> would be:
<virtualport type='802.1Qbg'>
<parameters instanceid="09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f"
typeid="1193047" typeidversion="2"
managerid="55"/>
</virtualport>
Additionally, if none of the involved <virtualport>s had a specified type
(this includes cases where no virtualport is given at all),
2012-08-02 18:10:00 +00:00
|
|
|
}
|
2012-08-06 20:17:58 +00:00
|
|
|
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
if (netdef) {
|
|
|
|
netdef->connections++;
|
|
|
|
VIR_DEBUG("Using network %s, %d connections",
|
|
|
|
netdef->name, netdef->connections);
|
|
|
|
}
|
2011-07-04 06:27:12 +00:00
|
|
|
ret = 0;
|
network: make network driver vlan-aware
The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)
At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used. Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).
Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.
This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate daemon, as we've
discussed recently.
2012-08-13 02:46:27 +00:00
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
cleanup:
|
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2012-08-06 17:45:57 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
2011-07-04 06:27:12 +00:00
|
|
|
virDomainActualNetDefFree(iface->data.network.actual);
|
|
|
|
iface->data.network.actual = NULL;
|
|
|
|
}
|
2012-08-06 17:45:57 +00:00
|
|
|
goto cleanup;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* networkNotifyActualDevice:
|
|
|
|
* @iface: the domain's NetDef with an "actual" device already filled in.
|
|
|
|
*
|
|
|
|
* Called to notify the network driver when libvirtd is restarted and
|
|
|
|
* finds an already running domain. If appropriate it will force an
|
|
|
|
* allocation of the actual->direct.linkdev to get everything back in
|
|
|
|
* order.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
networkNotifyActualDevice(virDomainNetDefPtr iface)
|
|
|
|
{
|
|
|
|
struct network_driver *driver = driverState;
|
2012-08-16 15:42:31 +00:00
|
|
|
enum virDomainNetType actualType = virDomainNetGetActualType(iface);
|
2011-07-04 06:27:12 +00:00
|
|
|
virNetworkObjPtr network;
|
|
|
|
virNetworkDefPtr netdef;
|
2012-08-16 15:42:31 +00:00
|
|
|
virNetworkForwardIfDefPtr dev = NULL;
|
|
|
|
int ii, ret = -1;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
network = virNetworkFindByName(&driver->networks, iface->data.network.name);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
_("no network with matching name '%s'"),
|
|
|
|
iface->data.network.name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
netdef = network->def;
|
|
|
|
|
|
|
|
if (!iface->data.network.actual ||
|
2012-08-16 15:42:31 +00:00
|
|
|
(actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
|
|
|
|
actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
|
2012-08-06 17:45:57 +00:00
|
|
|
VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
|
|
|
|
goto success;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if (netdef->forward.npfs > 0 && netdef->forward.nifs == 0 &&
|
2012-08-16 15:42:31 +00:00
|
|
|
networkCreateInterfacePool(netdef) < 0) {
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-11-10 11:18:57 +00:00
|
|
|
}
|
2012-11-08 02:16:17 +00:00
|
|
|
if (netdef->forward.nifs == 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-08-16 15:42:31 +00:00
|
|
|
_("network '%s' uses a direct or hostdev mode, "
|
|
|
|
"but has no forward dev and no interface pool"),
|
2012-07-18 11:50:10 +00:00
|
|
|
netdef->name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2012-08-16 15:42:31 +00:00
|
|
|
}
|
2011-07-04 06:27:12 +00:00
|
|
|
|
2012-08-16 15:42:31 +00:00
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
|
const char *actualDev;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
2012-08-16 15:42:31 +00:00
|
|
|
actualDev = virDomainNetGetActualDirectDev(iface);
|
|
|
|
if (!actualDev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("the interface uses a direct mode, "
|
|
|
|
"but has no source dev"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the matching interface and increment its connections */
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].type
|
2012-08-16 15:42:31 +00:00
|
|
|
== VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
|
2012-11-08 02:16:17 +00:00
|
|
|
STREQ(actualDev, netdef->forward.ifs[ii].device.dev)) {
|
|
|
|
dev = &netdef->forward.ifs[ii];
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* dev points at the physical device we want to use */
|
|
|
|
if (!dev) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-08-16 15:42:31 +00:00
|
|
|
_("network '%s' doesn't have dev='%s' "
|
|
|
|
"in use by domain"),
|
2012-07-18 11:50:10 +00:00
|
|
|
netdef->name, actualDev);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
2012-08-16 15:42:31 +00:00
|
|
|
/* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
|
2012-08-05 06:45:04 +00:00
|
|
|
* exclusive access to a device, so current connections count
|
|
|
|
* must be 0 in those cases.
|
2011-07-04 06:27:12 +00:00
|
|
|
*/
|
2012-08-05 06:45:04 +00:00
|
|
|
if ((dev->connections > 0) &&
|
2012-11-08 02:16:17 +00:00
|
|
|
((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
|
|
|
|
((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
|
2012-07-30 06:03:25 +00:00
|
|
|
iface->data.network.actual->virtPortProfile &&
|
|
|
|
(iface->data.network.actual->virtPortProfile->virtPortType
|
2011-11-02 14:43:16 +00:00
|
|
|
== VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-08-16 15:42:31 +00:00
|
|
|
_("network '%s' claims dev='%s' is already in "
|
|
|
|
"use by a different domain"),
|
2012-07-18 11:50:10 +00:00
|
|
|
netdef->name, actualDev);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
2012-08-16 15:42:31 +00:00
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
/* we are now assured of success, so mark the allocation */
|
2012-08-05 06:45:04 +00:00
|
|
|
dev->connections++;
|
2012-08-16 15:42:31 +00:00
|
|
|
VIR_DEBUG("Using physical device %s, connections %d",
|
2012-08-16 15:41:41 +00:00
|
|
|
dev->device.dev, dev->connections);
|
2012-08-16 15:42:31 +00:00
|
|
|
|
|
|
|
} else /* if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) */ {
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
|
|
|
|
|
|
|
hostdev = virDomainNetGetActualHostdev(iface);
|
|
|
|
if (!hostdev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("the interface uses a hostdev mode, "
|
|
|
|
"but has no hostdev"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the matching interface and increment its connections */
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].type
|
2012-08-16 15:42:31 +00:00
|
|
|
== VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
|
2013-03-18 19:56:12 +00:00
|
|
|
virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
|
2012-11-08 02:16:17 +00:00
|
|
|
&netdef->forward.ifs[ii].device.pci)) {
|
|
|
|
dev = &netdef->forward.ifs[ii];
|
2012-08-16 15:42:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* dev points at the physical device we want to use */
|
|
|
|
if (!dev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' doesn't have "
|
|
|
|
"PCI device %04x:%02x:%02x.%x in use by domain"),
|
|
|
|
netdef->name,
|
2013-03-18 19:56:12 +00:00
|
|
|
hostdev->source.subsys.u.pci.addr.domain,
|
|
|
|
hostdev->source.subsys.u.pci.addr.bus,
|
|
|
|
hostdev->source.subsys.u.pci.addr.slot,
|
|
|
|
hostdev->source.subsys.u.pci.addr.function);
|
2012-08-16 15:42:31 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PASSTHROUGH mode, PRIVATE Mode + 802.1Qbh, and hostdev (PCI
|
|
|
|
* passthrough) all require exclusive access to a device, so
|
|
|
|
* current connections count must be 0 in those cases.
|
|
|
|
*/
|
|
|
|
if ((dev->connections > 0) &&
|
2012-11-08 02:16:17 +00:00
|
|
|
netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
|
2012-08-16 15:42:31 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' claims the PCI device at "
|
|
|
|
"domain=%d bus=%d slot=%d function=%d "
|
|
|
|
"is already in use by a different domain"),
|
|
|
|
netdef->name,
|
|
|
|
dev->device.pci.domain, dev->device.pci.bus,
|
|
|
|
dev->device.pci.slot, dev->device.pci.function);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we are now assured of success, so mark the allocation */
|
|
|
|
dev->connections++;
|
|
|
|
VIR_DEBUG("Using physical device %04x:%02x:%02x.%x, connections %d",
|
|
|
|
dev->device.pci.domain, dev->device.pci.bus,
|
|
|
|
dev->device.pci.slot, dev->device.pci.function,
|
|
|
|
dev->connections);
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
2012-08-06 17:45:57 +00:00
|
|
|
success:
|
2012-08-06 20:17:58 +00:00
|
|
|
netdef->connections++;
|
|
|
|
VIR_DEBUG("Using network %s, %d connections",
|
|
|
|
netdef->name, netdef->connections);
|
2011-07-04 06:27:12 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
return ret;
|
2012-08-06 17:45:57 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
goto cleanup;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* networkReleaseActualDevice:
|
|
|
|
* @iface: a domain's NetDef (interface definition)
|
|
|
|
*
|
|
|
|
* Given a domain <interface> element that previously had its <actual>
|
|
|
|
* element filled in (and possibly a physical device allocated to it),
|
|
|
|
* free up the physical device for use by someone else, and free the
|
|
|
|
* virDomainActualNetDef.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
networkReleaseActualDevice(virDomainNetDefPtr iface)
|
|
|
|
{
|
|
|
|
struct network_driver *driver = driverState;
|
2012-08-16 15:42:31 +00:00
|
|
|
enum virDomainNetType actualType = virDomainNetGetActualType(iface);
|
2012-08-06 17:45:57 +00:00
|
|
|
virNetworkObjPtr network;
|
2011-07-04 06:27:12 +00:00
|
|
|
virNetworkDefPtr netdef;
|
2012-08-16 15:42:31 +00:00
|
|
|
virNetworkForwardIfDefPtr dev = NULL;
|
|
|
|
int ii, ret = -1;
|
2011-07-04 06:27:12 +00:00
|
|
|
|
|
|
|
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
networkDriverLock(driver);
|
|
|
|
network = virNetworkFindByName(&driver->networks, iface->data.network.name);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
_("no network with matching name '%s'"),
|
|
|
|
iface->data.network.name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
netdef = network->def;
|
|
|
|
|
2012-11-16 13:29:01 +00:00
|
|
|
if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
|
|
|
|
netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
|
|
|
|
netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) &&
|
|
|
|
networkUnplugBandwidth(network, iface) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2012-08-16 15:42:31 +00:00
|
|
|
if ((!iface->data.network.actual) ||
|
|
|
|
((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
|
|
|
|
(actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
|
2012-08-06 17:45:57 +00:00
|
|
|
VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
|
|
|
|
goto success;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
if (netdef->forward.nifs == 0) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-08-16 15:42:31 +00:00
|
|
|
_("network '%s' uses a direct/hostdev mode, but "
|
2012-07-18 11:50:10 +00:00
|
|
|
"has no forward dev and no interface pool"),
|
|
|
|
netdef->name);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2012-08-16 15:42:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
|
const char *actualDev;
|
|
|
|
|
|
|
|
actualDev = virDomainNetGetActualDirectDev(iface);
|
|
|
|
if (!actualDev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("the interface uses a direct mode, "
|
|
|
|
"but has no source dev"));
|
|
|
|
goto error;
|
|
|
|
}
|
2011-07-04 06:27:12 +00:00
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].type
|
2012-08-16 15:42:31 +00:00
|
|
|
== VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
|
2012-11-08 02:16:17 +00:00
|
|
|
STREQ(actualDev, netdef->forward.ifs[ii].device.dev)) {
|
|
|
|
dev = &netdef->forward.ifs[ii];
|
2011-07-04 06:27:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-16 15:42:31 +00:00
|
|
|
|
2011-07-04 06:27:12 +00:00
|
|
|
if (!dev) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-08-16 15:42:31 +00:00
|
|
|
_("network '%s' doesn't have dev='%s' "
|
|
|
|
"in use by domain"),
|
2012-07-18 11:50:10 +00:00
|
|
|
netdef->name, actualDev);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
2012-08-05 06:45:04 +00:00
|
|
|
dev->connections--;
|
2012-08-16 15:42:31 +00:00
|
|
|
VIR_DEBUG("Releasing physical device %s, connections %d",
|
2012-08-16 15:41:41 +00:00
|
|
|
dev->device.dev, dev->connections);
|
2012-08-16 15:42:31 +00:00
|
|
|
|
|
|
|
} else /* if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) */ {
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
|
|
|
|
|
|
|
hostdev = virDomainNetGetActualHostdev(iface);
|
|
|
|
if (!hostdev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("the interface uses a hostdev mode, but has no hostdev"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
for (ii = 0; ii < netdef->forward.nifs; ii++) {
|
|
|
|
if (netdef->forward.ifs[ii].type
|
2012-08-16 15:42:31 +00:00
|
|
|
== VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
|
2013-03-18 19:56:12 +00:00
|
|
|
virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
|
|
|
|
&netdef->forward.ifs[ii].device.pci)) {
|
2012-11-08 02:16:17 +00:00
|
|
|
dev = &netdef->forward.ifs[ii];
|
2012-08-16 15:42:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' doesn't have "
|
|
|
|
"PCI device %04x:%02x:%02x.%x in use by domain"),
|
|
|
|
netdef->name,
|
2013-03-18 19:56:12 +00:00
|
|
|
hostdev->source.subsys.u.pci.addr.domain,
|
|
|
|
hostdev->source.subsys.u.pci.addr.bus,
|
|
|
|
hostdev->source.subsys.u.pci.addr.slot,
|
|
|
|
hostdev->source.subsys.u.pci.addr.function);
|
2012-08-16 15:42:31 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->connections--;
|
|
|
|
VIR_DEBUG("Releasing physical device %04x:%02x:%02x.%x, connections %d",
|
|
|
|
dev->device.pci.domain, dev->device.pci.bus,
|
|
|
|
dev->device.pci.slot, dev->device.pci.function,
|
|
|
|
dev->connections);
|
|
|
|
}
|
2011-07-04 06:27:12 +00:00
|
|
|
|
2012-08-06 17:45:57 +00:00
|
|
|
success:
|
2012-08-06 20:17:58 +00:00
|
|
|
netdef->connections--;
|
|
|
|
VIR_DEBUG("Releasing network %s, %d connections",
|
|
|
|
netdef->name, netdef->connections);
|
2011-07-04 06:27:12 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
2012-08-06 17:45:57 +00:00
|
|
|
if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
|
|
|
virDomainActualNetDefFree(iface->data.network.actual);
|
|
|
|
iface->data.network.actual = NULL;
|
|
|
|
}
|
2011-07-04 06:27:12 +00:00
|
|
|
return ret;
|
2012-08-06 17:45:57 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
goto cleanup;
|
2011-07-04 06:27:12 +00:00
|
|
|
}
|
2011-07-07 04:24:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* networkGetNetworkAddress:
|
|
|
|
* @netname: the name of a network
|
|
|
|
* @netaddr: string representation of IP address for that network.
|
|
|
|
*
|
|
|
|
* Attempt to return an IP (v4) address associated with the named
|
|
|
|
* network. If a libvirt virtual network, that will be provided in the
|
|
|
|
* configuration. For host bridge and direct (macvtap) networks, we
|
|
|
|
* must do an ioctl to learn the address.
|
|
|
|
*
|
|
|
|
* Note: This function returns the 1st IPv4 address it finds. It might
|
|
|
|
* be useful if it was more flexible, but the current use (getting a
|
|
|
|
* listen address for qemu's vnc/spice graphics server) can only use a
|
|
|
|
* single address anyway.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, and puts a string (which must be free'd by
|
|
|
|
* the caller) into *netaddr. Returns -1 on failure or -2 if
|
|
|
|
* completely unsupported.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
networkGetNetworkAddress(const char *netname, char **netaddr)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
struct network_driver *driver = driverState;
|
2012-08-06 17:45:57 +00:00
|
|
|
virNetworkObjPtr network;
|
2011-07-07 04:24:08 +00:00
|
|
|
virNetworkDefPtr netdef;
|
|
|
|
virNetworkIpDefPtr ipdef;
|
|
|
|
virSocketAddr addr;
|
|
|
|
virSocketAddrPtr addrptr = NULL;
|
2011-09-16 12:05:58 +00:00
|
|
|
char *dev_name = NULL;
|
2011-07-07 04:24:08 +00:00
|
|
|
|
|
|
|
*netaddr = NULL;
|
|
|
|
networkDriverLock(driver);
|
|
|
|
network = virNetworkFindByName(&driver->networks, netname);
|
|
|
|
networkDriverUnlock(driver);
|
|
|
|
if (!network) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_NO_NETWORK,
|
|
|
|
_("no network with matching name '%s'"),
|
|
|
|
netname);
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-07-07 04:24:08 +00:00
|
|
|
}
|
|
|
|
netdef = network->def;
|
|
|
|
|
2012-11-08 02:16:17 +00:00
|
|
|
switch (netdef->forward.type) {
|
2011-07-07 04:24:08 +00:00
|
|
|
case VIR_NETWORK_FORWARD_NONE:
|
|
|
|
case VIR_NETWORK_FORWARD_NAT:
|
|
|
|
case VIR_NETWORK_FORWARD_ROUTE:
|
|
|
|
/* if there's an ipv4def, get it's address */
|
|
|
|
ipdef = virNetworkDefGetIpByIndex(netdef, AF_INET, 0);
|
|
|
|
if (!ipdef) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' doesn't have an IPv4 address"),
|
|
|
|
netdef->name);
|
2011-07-07 04:24:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
addrptr = &ipdef->address;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_BRIDGE:
|
2011-09-16 12:05:58 +00:00
|
|
|
if ((dev_name = netdef->bridge))
|
2011-07-07 04:24:08 +00:00
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* fall through if netdef->bridge wasn't set, since this is
|
|
|
|
* also a direct-mode interface.
|
|
|
|
*/
|
|
|
|
case VIR_NETWORK_FORWARD_PRIVATE:
|
|
|
|
case VIR_NETWORK_FORWARD_VEPA:
|
|
|
|
case VIR_NETWORK_FORWARD_PASSTHROUGH:
|
2012-11-08 02:16:17 +00:00
|
|
|
if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
|
|
|
|
dev_name = netdef->forward.ifs[0].device.dev;
|
2011-07-07 04:24:08 +00:00
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
if (!dev_name) {
|
2012-07-18 11:50:10 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network '%s' has no associated interface or bridge"),
|
|
|
|
netdef->name);
|
2011-07-07 04:24:08 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-09-16 12:05:58 +00:00
|
|
|
if (dev_name) {
|
2011-11-03 10:31:01 +00:00
|
|
|
if (virNetDevGetIPv4Address(dev_name, &addr) < 0)
|
2012-08-06 17:45:57 +00:00
|
|
|
goto error;
|
2011-11-03 10:31:01 +00:00
|
|
|
addrptr = &addr;
|
2011-07-07 04:24:08 +00:00
|
|
|
}
|
|
|
|
|
2012-08-06 17:45:57 +00:00
|
|
|
if (!(addrptr &&
|
|
|
|
(*netaddr = virSocketAddrFormat(addrptr)))) {
|
|
|
|
goto error;
|
2011-07-07 04:24:08 +00:00
|
|
|
}
|
|
|
|
|
2012-08-06 17:45:57 +00:00
|
|
|
ret = 0;
|
2011-07-07 04:24:08 +00:00
|
|
|
cleanup:
|
|
|
|
if (network)
|
|
|
|
virNetworkObjUnlock(network);
|
|
|
|
return ret;
|
2012-08-06 17:45:57 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
goto cleanup;
|
2011-07-07 04:24:08 +00:00
|
|
|
}
|
2012-11-16 13:29:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* networkCheckBandwidth:
|
|
|
|
* @net: network QoS
|
|
|
|
* @iface: interface QoS
|
|
|
|
* @new_rate: new rate for non guaranteed class
|
|
|
|
*
|
|
|
|
* Returns: -1 if plugging would overcommit network QoS
|
|
|
|
* 0 if plugging is safe (@new_rate updated)
|
|
|
|
* 1 if no QoS is set (@new_rate untouched)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
networkCheckBandwidth(virNetworkObjPtr net,
|
|
|
|
virDomainNetDefPtr iface,
|
|
|
|
unsigned long long *new_rate)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
virNetDevBandwidthPtr netBand = net->def->bandwidth;
|
2013-01-16 17:46:01 +00:00
|
|
|
virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
2012-11-16 13:29:01 +00:00
|
|
|
unsigned long long tmp_floor_sum = net->floor_sum;
|
|
|
|
unsigned long long tmp_new_rate = 0;
|
|
|
|
char ifmac[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
2013-03-07 09:53:21 +00:00
|
|
|
virMacAddrFormat(&iface->mac, ifmac);
|
|
|
|
|
|
|
|
if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
|
|
|
|
!(netBand && netBand->in)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
|
|
|
_("Invalid use of 'floor' on interface with MAC "
|
|
|
|
"address %s - network '%s' has no inbound QoS set"),
|
|
|
|
ifmac, net->def->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-11-16 13:29:01 +00:00
|
|
|
if (!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor ||
|
2013-03-07 09:53:21 +00:00
|
|
|
!netBand || !netBand->in) {
|
|
|
|
/* no QoS required, claim success */
|
2012-11-16 13:29:01 +00:00
|
|
|
return 1;
|
2013-03-07 09:53:21 +00:00
|
|
|
}
|
2012-11-16 13:29:01 +00:00
|
|
|
|
|
|
|
tmp_new_rate = netBand->in->average;
|
|
|
|
tmp_floor_sum += ifaceBand->in->floor;
|
|
|
|
|
|
|
|
/* check against peak */
|
|
|
|
if (netBand->in->peak) {
|
|
|
|
tmp_new_rate = netBand->in->peak;
|
|
|
|
if (tmp_floor_sum > netBand->in->peak) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("Cannot plug '%s' interface into '%s' because it "
|
|
|
|
"would overcommit 'peak' on network '%s'"),
|
|
|
|
ifmac,
|
|
|
|
net->def->bridge,
|
|
|
|
net->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else if (tmp_floor_sum > netBand->in->average) {
|
|
|
|
/* tmp_floor_sum can be between 'average' and 'peak' iff 'peak' is set.
|
|
|
|
* Otherwise, tmp_floor_sum must be below 'average'. */
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("Cannot plug '%s' interface into '%s' because it "
|
|
|
|
"would overcommit 'average' on network '%s'"),
|
|
|
|
ifmac,
|
|
|
|
net->def->bridge,
|
|
|
|
net->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
*new_rate = tmp_new_rate;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* networkNextClassID:
|
|
|
|
* @net: network object
|
|
|
|
*
|
|
|
|
* Find next free class ID. @net is supposed
|
|
|
|
* to be locked already. If there is a free ID,
|
|
|
|
* it is marked as used and returned.
|
|
|
|
*
|
|
|
|
* Returns next free class ID or -1 if none is available.
|
|
|
|
*/
|
|
|
|
static ssize_t
|
|
|
|
networkNextClassID(virNetworkObjPtr net)
|
|
|
|
{
|
|
|
|
size_t ret = 0;
|
|
|
|
bool is_set = false;
|
|
|
|
|
|
|
|
while (virBitmapGetBit(net->class_id, ret, &is_set) == 0 && is_set)
|
|
|
|
ret++;
|
|
|
|
|
|
|
|
if (is_set || virBitmapSetBit(net->class_id, ret) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
networkPlugBandwidth(virNetworkObjPtr net,
|
|
|
|
virDomainNetDefPtr iface)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int plug_ret;
|
|
|
|
unsigned long long new_rate = 0;
|
|
|
|
ssize_t class_id = 0;
|
|
|
|
char ifmac[VIR_MAC_STRING_BUFLEN];
|
2013-01-16 17:46:01 +00:00
|
|
|
virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
2012-11-16 13:29:01 +00:00
|
|
|
|
|
|
|
if ((plug_ret = networkCheckBandwidth(net, iface, &new_rate)) < 0) {
|
|
|
|
/* helper reported error */
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (plug_ret > 0) {
|
|
|
|
/* no QoS needs to be set; claim success */
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virMacAddrFormat(&iface->mac, ifmac);
|
|
|
|
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
|
|
!iface->data.network.actual) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot set bandwidth on interface '%s' of type %d"),
|
|
|
|
ifmac, iface->type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate new class_id */
|
|
|
|
if ((class_id = networkNextClassID(net)) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Could not generate next class ID"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-01-16 17:46:01 +00:00
|
|
|
plug_ret = virNetDevBandwidthPlug(net->def->bridge, net->def->bandwidth,
|
|
|
|
&iface->mac, ifaceBand, class_id);
|
2012-11-16 13:29:01 +00:00
|
|
|
if (plug_ret < 0) {
|
|
|
|
ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* QoS was set, generate new class ID */
|
|
|
|
iface->data.network.actual->class_id = class_id;
|
|
|
|
/* update sum of 'floor'-s of attached NICs */
|
2013-01-16 17:46:01 +00:00
|
|
|
net->floor_sum += ifaceBand->in->floor;
|
2012-11-18 15:59:21 +00:00
|
|
|
/* update status file */
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virNetworkSaveStatus(driverState->stateDir, net) < 0) {
|
2012-11-18 15:59:21 +00:00
|
|
|
ignore_value(virBitmapClearBit(net->class_id, class_id));
|
2013-01-16 17:46:01 +00:00
|
|
|
net->floor_sum -= ifaceBand->in->floor;
|
2012-11-18 15:59:21 +00:00
|
|
|
iface->data.network.actual->class_id = 0;
|
|
|
|
ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-16 13:29:01 +00:00
|
|
|
/* update rate for non guaranteed NICs */
|
|
|
|
new_rate -= net->floor_sum;
|
|
|
|
if (virNetDevBandwidthUpdateRate(net->def->bridge, "1:2",
|
|
|
|
net->def->bandwidth, new_rate) < 0)
|
|
|
|
VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
|
|
|
|
net->def->bridge);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
networkUnplugBandwidth(virNetworkObjPtr net,
|
|
|
|
virDomainNetDefPtr iface)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
unsigned long long new_rate;
|
2013-01-16 17:46:01 +00:00
|
|
|
virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
|
2012-11-16 13:29:01 +00:00
|
|
|
|
|
|
|
if (iface->data.network.actual &&
|
|
|
|
iface->data.network.actual->class_id) {
|
|
|
|
/* we must remove class from bridge */
|
|
|
|
new_rate = net->def->bandwidth->in->average;
|
|
|
|
|
|
|
|
if (net->def->bandwidth->in->peak > 0)
|
|
|
|
new_rate = net->def->bandwidth->in->peak;
|
|
|
|
|
|
|
|
ret = virNetDevBandwidthUnplug(net->def->bridge,
|
|
|
|
iface->data.network.actual->class_id);
|
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
|
|
|
/* update sum of 'floor'-s of attached NICs */
|
2013-01-16 17:46:01 +00:00
|
|
|
net->floor_sum -= ifaceBand->in->floor;
|
2012-11-18 15:59:21 +00:00
|
|
|
/* return class ID */
|
|
|
|
ignore_value(virBitmapClearBit(net->class_id,
|
|
|
|
iface->data.network.actual->class_id));
|
|
|
|
/* update status file */
|
2013-05-02 17:59:52 +00:00
|
|
|
if (virNetworkSaveStatus(driverState->stateDir, net) < 0) {
|
2013-01-16 17:46:01 +00:00
|
|
|
net->floor_sum += ifaceBand->in->floor;
|
2012-11-18 15:59:21 +00:00
|
|
|
ignore_value(virBitmapSetBit(net->class_id,
|
|
|
|
iface->data.network.actual->class_id));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-11-16 13:29:01 +00:00
|
|
|
/* update rate for non guaranteed NICs */
|
|
|
|
new_rate -= net->floor_sum;
|
|
|
|
if (virNetDevBandwidthUpdateRate(net->def->bridge, "1:2",
|
|
|
|
net->def->bandwidth, new_rate) < 0)
|
|
|
|
VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
|
|
|
|
net->def->bridge);
|
|
|
|
/* no class is associated any longer */
|
|
|
|
iface->data.network.actual->class_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|