[libvirt] [PATCHv2 2/2] Give each virtual network bridge its own fixed MAC address
Laine Stump
laine at laine.org
Fri Feb 11 08:29:07 UTC 2011
On 02/10/2011 04:09 PM, Eric Blake wrote:
> On 02/10/2011 02:57 AM, Laine Stump wrote:
>> 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).
>>
>> +++ b/docs/formatnetwork.html.in
>> @@ -105,12 +105,15 @@
>> <h3><a name="elementsAddress">Addressing</a></h3>
>>
>> <p>
>> - The final set of elements define the IPv4 address range available,
>> - and optionally enable DHCP sevices.
>> + The final set of elements define the addresses (IPv4 and/or
>> + IPv6, as well as MAC) to be assigned to the bridge device
>> + associated with the virtual network, and optionally enable DHCP
>> + sevices.
> s/sevices/services/
>
> (pre-existing, but as long as you're touching that sentence...)
Done.
>> <dl>
>> +<dt><code>mac</code></dt>
>> +<dd>The<code>address</code> attribute defines a MAC
>> + (hardware) address formatted as 6 groups of 2-digit
>> + hexadecimal numbers, the groups separated by colons
>> + (eg,<code>"52:54:00:1C:DA:2F"</code>). This MAC address is
>> + assigned to the bridge device when it is created. Generally
>> + it is best to not specify a mac address when creating a
> Hmm, for consistency, I'm thinking s/mac/MAC/g
>
>> + network - in this case, if a defined mac address is needed for
>> + proper operation, libvirt will automatically generate a random
>> + mac address and save it in the config. Allowing libvirt to
> (3 instances); but feel free to disregard that if you think it results
> in too many all-caps words.
Consistency is good. I made them all caps.
>> + generate the MAC address will assure that it is compatible
>> + with the idiosyncracies of the platform where libvirt is
> s/idiosyncracies/idiosyncrasies/
Strange - the "c" version is in /usr/share/dict/words, but not in the
dictionary.
>> +++ b/libvirt.spec.in
>> @@ -741,6 +741,44 @@ then
>> > %{_sysconfdir}/libvirt/qemu/networks/default.xml
>> ln -s ../default.xml %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
>> fi
>> +
>> +# All newly defined networks will have a mac address for the bridge
>> +# auto-generated, but networks already existing at the time of upgrade
>> +# will not. We need to go through all the network configs, look for
>> +# those that don't have a mac address, and add one.
>> +
>> +network_files=`(cd %{_localstatedir}/lib/libvirt/network; \
>> + ls *.xml | xargs grep -L "mac address"; \
>> + cd %{_sysconfdir}/libvirt/qemu/networks; \
>> + ls *.xml | xargs grep -L "mac address") \
>> + | sort | uniq`
> This leaks a message to stderr if globbing fails:
>
> ls: cannot access *.xml: No such file or directory
>
> You want to use&& rather than ; after cd (in case for some weird reason
> cd fails, you don't want to be globbing in the wrong location).
>
> sort | uniq wastes a process. For that matter, do we really expect the
> glob to result in so many networks that we exceed ARG_MAX limitations,
> or can we ditch the xargs process?
>
> `` is yucky - let's use $()
All good points. I've switched to your version. (this exercise makes me
realize how many shell-isms are just wired into my subconscious; for
example, I'm so used to the file list for grep coming from something
more complex than a simple glob, that I *always* pipe the filelist
through xargs to grep even when it's severe overkill, and have never
noticed sort -u)
> network_files=$( (cd %{_localstatedir}/lib/libvirt/network&& \
> grep -L "mac address" *.xml; \
> cd %{_sysconfdir}/libvirt/qemu/networks&& \
> grep -L "mac address" *.xml) 2>/dev/null \
> | sort -u)
>
>> +
>> +for file in $network_files
>> +do
>> + # each file exists in either the config or state directory (or both) and
>> + # does not have a mac address specified in either. We add the same mac
>> + # address to both files (or just one, if the other isn't there)
>> +
>> + mac4=`printf '%X' $(($RANDOM % 256))`
>> + mac5=`printf '%X' $(($RANDOM % 256))`
>> + mac6=`printf '%X' $(($RANDOM % 256))`
>> + for dir in %{_localstatedir}/lib/libvirt/network %{_sysconfdir}/libvirt/qemu/networks
>> + do
>> + if test -f $dir/$file
>> + then
>> + sed -i.orig -e \
> Is sed -i atomic? I know perl -i is not (that is, perl moves the file
> to a temporary, the puts output into the original, but there exists a
> window of time where the original file name refers to an incomplete
> file). Are we better off skipping -i, and doing sed into a secondary
> file, and atomically renaming that file over the original if all went
> well? On the other hand, then you have to start worrying about file
> permissions being accidentally changed.
>
> http://www.pixelbeat.org/docs/unix_file_replacement.html
>
> Or do we just give up on the atomicity requirement, and call this method
> good enough (that is, you are unlikely to be upgrading rpm at the same
> time that libvirt is trying to read (or worse modify) one of these .xml
> files).
My thinking was that sed -i is already used elsewhere in the %post
script on the same file (and that usage doesn't even make a backup in
case the operation somehow fails, but maybe that's overkill too), so it
must be good enough for this case too.
>> + "s|\(<bridge.*$\)|\0\n<mac address='52:54:00:$mac4:$mac5:$mac6'/>|" \
>> + $dir/$file
>> + if ! test $?
> Won't work. $? is always non-empty, which means test $? is always true,
> which means ! test $? will always take the else branch.
>
> You meant:
>
> if test $? != 0
Yes. It was late, and the script ran properly (only because it didn't
encounter an error), so I didn't notice.
> The code looked fine, but I think it would be wise to see a v3 with the
> spec file cleanups and spelling fixes.
Thanks for the (as usual) thorough review!
v3 coming up.
More information about the libvir-list
mailing list