[libvirt] [PATCH] util: generate correct macvtap name

Shanzhi Yu shyu at redhat.com
Tue Mar 29 06:24:51 UTC 2016



On 03/29/2016 12:23 AM, Laine Stump wrote:
> On 03/28/2016 10:42 AM, Laine Stump wrote:
>> On 03/28/2016 06:43 AM, Shanzhi Yu wrote:
>>> in commit 370608b, bitmap of in-used macvtap devices was introduced.
>>> if there is already macvtap device created not by libvirt,
>>> virNetDevMacVLanCreateWithVPortProfile will failed after try
>>> MACVLAN_MAX_ID times call virNetDevMacVLanReleaseID
>>>
>>> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1321546
>>
>> NACK.
>>
>> This is a bonafide bug, but not the right fix. Your patch would go
>> back and pick up the unused "macvtap0" name rather than trying
>> macvtap2, but once macvtap0 was in use, the next call (for yet another
>> macvtap device) would attempt to use macvtap2 (since macvtap0 and
>> macvtap1 were in use) and would then end up looping in the same manner
>> as it did without your patch (MACVLAN_MAX_ID times == 8191) and then
>> still reporting a failure.
>
> Sigh. The above is incorrect, as I was trying to trace through the code
> in my mind after mentally applying the patch, rather than actually
> trying it.
>

Thanks for your explanations, actually your fix is really what I want, I 
should go through virNetDevMacVLanReserveID carefully.


> As a matter of fact, the reality is worse than the above description.
> With this patch the device name is constructed by using the id number
> that we *want* to reserve rather than the one that we actually do
> reserve, but the bug in virNetDevMacVLanReserveID() is still there, so
> in fact what will happen is that the newly patched loop will
>
>   1) format the name to use as "macvtap0"
>   2) ask for macvtap0
>   3) get back macvtap2, but ignore that
>   4) try/fail to create macvtap0
>   5) *NOT* release the id that it just allocated (which was macvtap2)
>   6) loop again
>   7) format "macvtap2"
>   8) ask for macvtap2
>   9) get back macvtap3, but ignore that
> 10) try/fail to create macvtap2
> 11) *NOT release the id that was just reserved (macvtap3)
> 12) loop again
> 13) format macvtap3
> 14) ask for macvtap3
> 15) get back macvtap4 (even though nobody is using macvtap3,
>      we reserved it in the last iteration, didn't use it,
>      and didn't free it!)
> 16) try/succeed to create macvtap3
>
> So at this point, we have reserved macvtap2, macvtap3, and macvtap4,
> even though libvirt is only using macvtap3 (and something outside of
> libvirt is using macvtap2). The next time someone wants a macvtap
> device, we'll again start out at 0, get back 5, try/fail to create 0,
> ask for 1, get back 6, try/fail to create 1, ask for 2, get back 7,
> try/fail to create 2, ask for 3, get back 8, try/fail to create 3, ask
> for 4, get back 9, and finally succeed with macvtap4. So *now* we've
> reserved all names up through macvtap9, but are only using macvtap0,
> macvtap1 (these from previous), macvtap3, and macvtap4. We'll continue
> like this, reserving n-1 extra names for each new macvtap device "n",
> thus running out much more quickly.
>
> Anyway, that's probably much more analysis than necessary. The main
> points (in addition to the fact that it doesn't fix the root cause) are:
>
> a) it creates the macvtap name based on the desired id# rather than the
> one that was actually reserved
> b) it never frees the id's that it ends up not using because the create
> failed.
>
>
>>
>> The proper fix is to call virBitmapNextClearBit() (inside
>> virNetDevMacVLanReserveID()) with the most recently failed id (or -1)
>> rather than with 0. This is what I've done in the following patch:
>>
>> https://www.redhat.com/archives/libvir-list/2016-March/msg01286.html
>>
>>
>>>
>>> Signed-off-by: Shanzhi Yu <shyu at redhat.com>
>>> ---
>>>   src/util/virnetdevmacvlan.c | 16 +++++++++-------
>>>   1 file changed, 9 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
>>> index 2409113..973363e 100644
>>> --- a/src/util/virnetdevmacvlan.c
>>> +++ b/src/util/virnetdevmacvlan.c
>>> @@ -988,7 +988,8 @@ virNetDevMacVLanCreateWithVPortProfile(const char
>>> *ifnameRequested,
>>>           MACVTAP_NAME_PREFIX : MACVLAN_NAME_PREFIX;
>>>       const char *pattern = (flags &
>>> VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
>>>           MACVTAP_NAME_PATTERN : MACVLAN_NAME_PATTERN;
>>> -    int rc, reservedID = -1;
>>> +    int rc = -1;
>>> +    int reservedID = 0;
>>>       char ifname[IFNAMSIZ];
>>>       int retries, do_retry = 0;
>>>       uint32_t macvtapMode;
>>> @@ -1072,16 +1073,17 @@ virNetDevMacVLanCreateWithVPortProfile(const
>>> char *ifnameRequested,
>>>       retries = MACVLAN_MAX_ID;
>>>       while (!ifnameCreated && retries) {
>>>           virMutexLock(&virNetDevMacVLanCreateMutex);
>>> -        reservedID = virNetDevMacVLanReserveID(reservedID, flags,
>>> false, true);
>>> -        if (reservedID < 0) {
>>> -            virMutexUnlock(&virNetDevMacVLanCreateMutex);
>>> -            return -1;
>>> -        }
>>>           snprintf(ifname, sizeof(ifname), pattern, reservedID);
>>>           rc = virNetDevMacVLanCreate(ifname, type, macaddress, linkdev,
>>>                                       macvtapMode, &do_retry);
>>>           if (rc < 0) {
>>> -            virNetDevMacVLanReleaseID(reservedID, flags);
>>> +            reservedID++;
>>> +            reservedID = virNetDevMacVLanReserveID(reservedID,
>>> flags, false, true);
>>> +            if (reservedID < 0) {
>>> + virMutexUnlock(&virNetDevMacVLanCreateMutex);
>>> +                return -1;
>>> +            }
>>> +
>>>               virMutexUnlock(&virNetDevMacVLanCreateMutex);
>>>               if (!do_retry)
>>>                   return -1;
>>
>> --
>> libvir-list mailing list
>> libvir-list at redhat.com
>> https://www.redhat.com/mailman/listinfo/libvir-list
>>
>

-- 
Regards
shyu




More information about the libvir-list mailing list