Bug 1321546 - libvirt fails to create a macvtap deivce if an attempted name was already created by some process other than libvirt
Summary: libvirt fails to create a macvtap deivce if an attempted name was already cre...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: libvirt
Version: 7.3
Hardware: Unspecified
OS: Unspecified
high
high
Target Milestone: rc
: ---
Assignee: Laine Stump
QA Contact: Virtualization Bugs
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2016-03-28 10:25 UTC by Shanzhi Yu
Modified: 2016-11-03 18:40 UTC (History)
5 users (show)

Fixed In Version: libvirt-1.3.3-1.el7
Doc Type: Bug Fix
Doc Text:
Clone Of:
: 1321637 (view as bug list)
Environment:
Last Closed: 2016-11-03 18:40:50 UTC
Target Upstream Version:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2016:2577 0 normal SHIPPED_LIVE Moderate: libvirt security, bug fix, and enhancement update 2016-11-03 12:07:06 UTC

Description Shanzhi Yu 2016-03-28 10:25:54 UTC
Description of problem:

libvirt fail to generate correct macvtap name if there is already one 

Version-Release number of selected component (if applicable):

libvirt-1.3.2-1.el7.x86_64

How reproducible:

100%

Steps to Reproduce:

1. Create a macvtap device by ip command named macvtap1

# ip l add li enp2s0  macvtap1  type  macvtap
# ip -d l show macvtap1
6: macvtap1@enp2s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
    link/ether d2:d9:bb:d7:f6:5b brd ff:ff:ff:ff:ff:ff promiscuity 0 
    macvtap  mode vepa addrgenmode eui64 

2. Start a defined guest with interface type is direct

# virsh dumpxml r7 |grep "interface type" -A4
    <interface type='direct'>
      <mac address='52:54:00:0c:84:4d'/>
      <source dev='enp2s0' mode='vepa'/>
      <model type='rtl8139'/>
      <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/>

# time virsh start r7 
error: Failed to start domain r7
error: internal error: Too many unreserved macvtap devices in use


real	0m50.638s
user	0m0.013s
sys	0m0.008s


3. Check libvirtd log

# grep virNetDevMacVLanCreateWithVPortProfile /tmp/libvirtd.log |wc -l
8192


2016-03-28 08:35:30.890+0000: 28927: info : virNetDevMacVLanReserveID:166 : reserving device macvtap1
2016-03-28 08:35:30.902+0000: 28927: debug : virFileClose:103 : Closed fd 25
2016-03-28 08:35:30.902+0000: 28927: info : virNetDevMacVLanReleaseID:203 : releasing device macvtap1
2016-03-28 08:35:30.902+0000: 28927: info : virNetDevMacVLanCreateWithVPortProfile:1089 : Device macvtap1 wasn't reserved but already existed, skipping
2016-03-28 08:35:30.902+0000: 28927: info : virNetDevMacVLanReserveID:166 : reserving device macvtap1


Actual results:


Expected results:

guest should started successfully with correct macvtap device, like macvtap2 if there is already macvtap1(which create not by libvirt) existing on host. 

Additional info:

this is a regression of commit 370608b, which introduce bitmap of in-use macvtap devices.

It works good with below patch.

# git diff
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;




I did some test, when guest with 100 macvtap device, the boot time is around 10s.

# virsh dumpxml rh7|grep "interface type='direct'" -A 5

    <interface type='direct'>
      <mac address='52:54:00:3d:15:b1'/>
      <source dev='eth0' mode='vepa'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/>
    </interface>
    <interface type='direct'>
      <mac address='52:54:00:75:0b:9a'/>
      <source dev='eth0' mode='vepa'/>
      <model type='rtl8139'/>
      <address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0'/>
    </interface>

....
# virsh dumpxml rh7|grep "interface type='direct'"|wc -l
100

there're six macvtap device named macvtap0 macvtap2 macvtap4 macvtap6 macvtap8 macvtap10

# ip l |grep macvtap
209: macvtap0@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
210: macvtap2@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
211: macvtap4@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
212: macvtap6@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
213: macvtap8@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
214: macvtap10@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500



# time virsh start rh7 
Domain rh7 started


real	0m10.372s
user	0m0.005s
sys	0m0.004s

# ip l |grep macvtap|wc -l
106

Comment 1 Laine Stump 2016-03-28 17:13:54 UTC
This is a bonafide bug, but the patch doesn't address the root cause, and results in the loss of all performance gains from keeping track of the used macvtap names in the bitmap, as well as causing libvirt to run out of available macvtap names after creating only 7 macvtap devices! (The number of reserved bits in the bitmap would be N! ("n factorial"), and once all 8192 entries in the bitmap are reserved, libvirt would fail to create a new device). See this mail for the details of what the above patch does:

  https://www.redhat.com/archives/libvir-list/2016-March/msg01294.html

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, now pushed upstream:


commit 5b5f12cffa86a1b4527bde620c2a86c5e96ad7c5
Author: Laine Stump <laine@laine.org>
Date:   Mon Mar 28 10:14:04 2016 -0400

    util: avoid getting stuck on macvtapN name created outside libvirt

Comment 2 Laine Stump 2016-03-28 17:27:18 UTC
Oops, I should start spending more time thinking before I speak. The number of ID's used isn't N! ( 1 * 2 * 3 * 4 * .... * N), it is just the sum of all values from 1..N (1 + 2 + 3 + 4 + .... + N). So you would be able to get 127 usable macvtap devices before you hit the 8191 limit. Much better, but still not ideal :-)

Comment 3 Mike McCune 2016-03-28 22:54:17 UTC
This bug was accidentally moved from POST to MODIFIED via an error in automation, please see mmccune@redhat.com with any questions

Comment 5 yalzhang@redhat.com 2016-04-07 06:32:57 UTC
verified on libvirt-1.3.3-1.el7.x86_64, the results is as expected. And libvirt create the macvtap device from macvtapx, x is from 0 to 1,2,3,4 and so on, not from 1.
1. Single guest, hot plug
# ip l add li eth0  macvtap1  type  macvtap
# ip -d l show macvtap1
28: macvtap1@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
    link/ether a2:a2:ba:58:f6:98 brd ff:ff:ff:ff:ff:ff promiscuity 0 
    macvtap  mode vepa addrgenmode eui64
# virsh dumpxml rhel7.2 |grep "interface type" -A4
    <interface type='direct'>
      <mac address='52:54:00:0c:84:4d'/>
      <source dev='eth0' mode='vepa'/>
      <model type='rtl8139'/>
      <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/>
# virsh start rhel7.2
Domain rhel7.2 started
# ifconfig -a| grep macvtap
macvtap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500 ====>libvirt create this, it is ordered from "0"
macvtap1: flags=4098<BROADCAST,MULTICAST>  mtu 1500

# virsh attach-interface rhel7.2 direct eth0
Interface attached successfully
# ifconfig -a| grep macvtap
macvtap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
macvtap1: flags=4098<BROADCAST,MULTICAST>  mtu 1500
macvtap2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500 ===> hot plug

2. Single guest with multiple direct interfaces.
# ip l add li eth0  macvtap0  type  macvtap
# ip l add li eth0  macvtap1  type  macvtap
# ip l add li eth0  macvtap5  type  macvtap
# ip l add li eth0  macvtapd  type  macvtap
# ip link show | grep macvtap
28: macvtap1@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
32: macvtap5@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
37: macvtap0@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
38: macvtapd@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
Edit a guest with 5 direct interface with different mode private, vepa, bridge.
# time virsh start rhel7.2
Domain rhel7.2 started
# ip link show | grep macvtap
28: macvtap1@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
32: macvtap5@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
37: macvtap0@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
38: macvtapd@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
39: macvtap2@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500
40: macvtap3@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500
41: macvtap4@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500
42: macvtap6@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500
43: macvtap7@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500

3.create macvtap device, then start multiple guests with direct interface.
# ip l add li eth0  macvtap0  type  macvtap
# ip l add li eth0  macvtap2  type  macvtap
# ip l add li eth0  macvtap3  type  macvtap
# ip link show | grep macvtap
46: macvtap0@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
47: macvtap2@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
48: macvtap3@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
start 3 guests with direct interface.
# ip link show | grep macvtap
46: macvtap0@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
47: macvtap2@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
48: macvtap3@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 500
49: macvtap1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500
50: macvtap4@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500
51: macvtap5@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 500

Comment 8 errata-xmlrpc 2016-11-03 18:40:50 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHSA-2016-2577.html


Note You need to log in before you can comment on or make changes to this bug.