[libvirt] [PATCH RFC] network: try to eliminate default network conflict during package install

Laine Stump laine at laine.org
Fri Sep 12 16:27:02 UTC 2014


On 09/11/2014 05:15 PM, Eric Blake wrote:
> On 09/10/2014 11:54 AM, Laine Stump wrote:
>> Sometimes libvirt is installed on a host that is already using the
>> network 192.168.122.0/24. If the libvirt-daemon-config-network package
>> is installed, this creates a conflict, since that package has been
>> hard-coded to create a virtual network that also uses
>> 192.168.122.0/24. In the past libvirt has attempted to warn of /
>> remediate this situation by checking for conflicting routes when the
>> network is started, but it turns out that isn't always useful (for
>> example in the case that the *other* interface/network creating the
>> conflict hasn't yet been started at the time libvirtd start its owm
> s/owm/own/
>
>> networks).
>>
>> This patch attempts to catch the problem earlier - at install
>> time. During the %post install for libvirt-daemon-config-network, we
>> look through the output of "ip route show" for a route that exactly
>> matches 192.1 68.122.0/24, and if found we search for a similar route
>> that *doesn't* match (e.g. 192.168.123.0/24). When we find an
>> available route, we just replace all occurences of "122" in the
> s/occurences/occurrences/
>
>> default.xml that is being created with ${new_sub}. This could
>> obviously be made more complicated - automatically determine the
>> existing network address and mask from examining the template
>> default.xml, etc, but this scripting is simpler and gets the job done
>> as long as we continue to use 192.168.122.0/24 in the template. (If
>> anyone with mad bash skillz wants to suggest something to do that, by
>> all means please do).
> Is it worth adding comments into the template that the string "122" is
> magic and must not be altered without also considering distro packaging?
>
>> This is intended to at least "further reduce" the problems detailed in:
>>
>>   https://bugzilla.redhat.com/show_bug.cgi?id=811967
>>
>> I acknowledge that it doesn't help for cases of pre-built cloud images
>> (or live images that are created on real hardware and then run in a
>> virtual machine), but it should at least eliminate the troubles
>> encountered by individuals doing one-off installs (and could be used
>> to stifle complaints for live images, as long as libvirtd was running
>> on the system where the live image compose took place (or the compose
>> was itself done in a virtual machine that had a 192.168.122.0/24
>> interface address).
> No good suggestions on how to help those situations.
>
>> ---
>>
>> The question here is: "Will this help some people's situation without
>> causing new problems for anyone else?" I wouldn't mind pushing this
>> patch, but also wouldn't mind if it was just the catalyst for
>> discussion that leads to a better solution. We do need *some kind* of
>> solution though, as more and more people are installing OSes that
>> include the libvirt package in virtual machines, and are running into
>> this problem with increasing frequency.
>>
>>  libvirt.spec.in | 26 +++++++++++++++++++++++++-
>>  1 file changed, 25 insertions(+), 1 deletion(-)
>>
>> diff --git a/libvirt.spec.in b/libvirt.spec.in
>> index a6a58cf..539d9ef 100644
>> --- a/libvirt.spec.in
>> +++ b/libvirt.spec.in
>> @@ -1728,8 +1728,32 @@ fi
>>      %if %{with_network}
>>  %post daemon-config-network
>>  if test $1 -eq 1 && test ! -f %{_sysconfdir}/libvirt/qemu/networks/default.xml ; then
>> +    # see if the network used by default network creates a conflict,
>> +    # and try to resolve it
>> +    orig_sub=122
>> +    sub=${orig_sub}
>> +    net=192.168.${sub}.0/24
>> +    routes=$(ip route show | cut -d' ' -f1)
> How do we know that 'ip' is installed and available?  Do we need any
> Requires:, and/or making the script robust to 'ip' failing?


I thought of that as I was sending the patch, but didn't want to ruin
the momentum by going back to check if I needed to add a Requires: (I
was also curious if anyone else would think of it :-).

As it turns out, the iproute package (containing the ip command) is
included in the "core" set of packages used even for a minimal Fedora
install. However, we do have a "Requires: iproute", for the
libvirt-daemon package, and libvirt-daemon-config-network has "Requires:
libvirt-daemon", so we are guaranteed that the ip command will be present.


>> +    for route in $routes; do
>> +      if [ "${net}" = "${route}" ]; then
>> +        # there was a match, so we need to look for an unused subnet
> Rather than using cut and a shell for loop, why not just use grep? [1]
>
> if ip route show | grep -q "^192\\.168\\.$sub\\.0/24 "; then

Yeah, things like this are the reason I asked for suggestions :-)

>
>> +        for new_sub in $(seq 123 254); do
> seq is a GNU coreutils extension that can't be used in shell code
> designed to be portable everywhere; but this is a spec file for use by
> rpms where we know it will be installed.  So I'm fine with using it.
> (If this were a configure script, I would have suggested using:
> new_sub=123
> while [ $new_sub -lt 255 ]; do
>   ...
>   new_sub=$((new_sub + 1))
> done
>
> but that's overkill for this scenario.)
>
>> +          new_net="192.168.${new_sub}.0/24"
>> +          usable=yes
>> +          for route in ${routes}; do
> [1] Oh, I see.  You captured the ip output once, and are now scanning it
> multiple times.  In _that_ case, piping ip to grep on each loop is not
> as efficient.

What if I captured the ip output, then did:

if echo ${routes} | grep -q " 192\\.168\\.$sub\\.0/24 "; then
   ...


>
> But you could still do the lookup in shell instead of spawning child
> processes, and without needing a shell for loop:
>
> routes=$(ip route show)
> nl='
> '
> case $nl$routes in
>   *"${nl}192.168.$new_sub.0/24 "*) # code if found
>   *) # code if not found
> esac
>
>> +            [ "${new_net}" = "${route}" ] && usable=no
> Might be slightly faster if you skip the tail end of the for loop after
> a collision, as in:
>
> if [ "$new_net" = "$route" ]; then
>   usable=no
>   break
> fi
>
> that is, if you don't go with my case statement way to make the shell do
> the iteration over the entire input in one pass.

I was really just going for brevity rather than efficiency, since it's
only going to run once, and the list of routes will likely not be very
long (although I suppose if someone installed libvirt on a machine that
was in use as a core router (with full list of routes for the entire
internet) it could be a consideration :-)

>
>> +          done
>> +          if [ "${usable}" = "yes" ]; then
>> +            sub=${new_sub}
>> +            break;
>> +          fi
>> +        done
>> +      fi
>> +    done
>> +
>>      UUID=`/usr/bin/uuidgen`
>> -    sed -e "s,</name>,</name>\n  <uuid>$UUID</uuid>," \
>> +    sed -e "s/${orig_sub}/${sub}/g" \
>> +        -e "s,</name>,</name>\n  <uuid>$UUID</uuid>," \
>>           < %{_datadir}/libvirt/networks/default.xml \
>>           > %{_sysconfdir}/libvirt/qemu/networks/default.xml
>>      ln -s ../default.xml %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
>>
> Overall, looks like a good idea.  Your approach works, without giving me
> too much grief, so up to you if you want to spin a v2 incorporating some
> of my ideas, or leave it as-is.
>

I'm sending a new version that captures the output of ip route show,
then uses it in nested case statements.





More information about the libvir-list mailing list