On Wed, Feb 09, 2011 at 04:53:32AM -0500, Laine Stump wrote:
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-mac" displayed
in the output of the ifconfig command.
Problem that needs a solution:
-----------------------------
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 brought
up, if there is no MAC, I generate one then. One down side of this is
that the MAC is written to the *statedir* xml file (in
/var/lib/libvirt/networks) but no to the *config* xml (in
/etc/libvirt/qemu/networks). That means that if libvirtd is restarted
while the network is down, the next time it's started it will have a
different MAC.
It looks like the only place the *config* xml is written is in
networkDefine or networkCreate, but that's inadequate for this case,
as anyone upgrading their libvirt will want this change to take effect
for all their already-defined networks.
DV suggested that we could add a flag to the parser telling it whether
or not to auto-generate a MAC when one wasn't specified. That would
require (at least) adding a new arg to:
virNetworkDefParseFile
virNetworkDefParse
virNetworkDefParseNode
virNetworkDefParseXML
and adding this arg would be embedding details of the XML attributes
into the C API arglist, which doesn't seem very clean - this could set
a very bad precedent that would lead to argument clutter (one of the
things that using XML helps to prevent). Also, it would be one more
arg to be potentially set incorrectly by some new user of the parser.
Any advice on the cleanest way to solve this problem?
---
src/conf/network_conf.c | 21 ++++++++++++++++++-
src/conf/network_conf.h | 3 ++
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 47 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 71 insertions(+), 1 deletions(-)
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 28a3ee8..592e38c 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -628,6 +628,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay)
< 0)
def->delay = 0;
+ tmp = virXPathString("string(./bridge[1]/@mac)", ctxt);
+ if (tmp) {
+ if (virParseMacAddr(tmp, def->mac) < 0) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Invalid bridge mac address '%s' in
network '%s'"),
+ tmp, def->name);
+ VIR_FREE(tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ def->mac_specified = true;
+ }
I'd be inclined to say that the MAC address should be in the standard
XML format we use elsewhere, eg a subelement
<mac address='ab:bb:cc:dd:ee:ff'/>
diff --git a/src/network/bridge_driver.c
b/src/network/bridge_driver.c
index 08aaa36..1952dfd 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1566,6 +1566,7 @@ networkStartNetworkDaemon(struct network_driver *driver,
bool v4present = false, v6present = false;
virErrorPtr save_err = NULL;
virNetworkIpDefPtr ipdef;
+ char *macTapIfName;
if (virNetworkObjIsActive(network)) {
networkReportError(VIR_ERR_OPERATION_INVALID,
@@ -1585,6 +1586,27 @@ networkStartNetworkDaemon(struct network_driver *driver,
return -1;
}
+ virAsprintf(&macTapIfName, "%s-mac", network->def->bridge);
Not sure about the name suffix here, how about '-gw' or '-nic' ?
+ if (!macTapIfName) {
+ virReportOOMError();
+ goto err0;
+ }
+ if (!network->def->mac_specified) {
+ virGenerateMacAddr((unsigned char[]){ 0x52, 0x54, 0 },
+ network->def->mac);
+ network->def->mac_specified = true;
+ }
As you mentioned above I think this is the wrong place to be generating
this because to properly solve the bug above we want the MAC to be
stable forever & we require that libvirtd can be restarted without
loosing data.
I think we should do the auto-generation in the 'Define' and 'Create'
methods just afer we've parsed the initial XML.
We can also auto-generate in the method which loads configs off disk
as a safety net for upgrades. To make this persistent though, we
should write a %post script for the libvirt RPM that fixes up any
existing deployed networks in /etc/libvirt
Regards,
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|:
http://entangle-photo.org -o-
http://live.gnome.org/gtk-vnc :|