Bug 1321546
| Summary: | libvirt fails to create a macvtap deivce if an attempted name was already created by some process other than libvirt | |||
|---|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | Shanzhi Yu <shyu> | |
| Component: | libvirt | Assignee: | Laine Stump <laine> | |
| Status: | CLOSED ERRATA | QA Contact: | Virtualization Bugs <virt-bugs> | |
| Severity: | high | Docs Contact: | ||
| Priority: | high | |||
| Version: | 7.3 | CC: | dyuan, laine, mzhan, rbalakri, yalzhang | |
| Target Milestone: | rc | |||
| Target Release: | --- | |||
| Hardware: | Unspecified | |||
| OS: | Unspecified | |||
| Whiteboard: | ||||
| Fixed In Version: | libvirt-1.3.3-1.el7 | Doc Type: | Bug Fix | |
| Doc Text: | Story Points: | --- | ||
| Clone Of: | ||||
| : | 1321637 (view as bug list) | Environment: | ||
| Last Closed: | 2016-11-03 18:40:50 UTC | Type: | Bug | |
| Regression: | --- | Mount Type: | --- | |
| Documentation: | --- | CRM: | ||
| Verified Versions: | Category: | --- | ||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | ||
| Cloudforms Team: | --- | Target Upstream Version: | ||
| Embargoed: | ||||
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>
Date: Mon Mar 28 10:14:04 2016 -0400
util: avoid getting stuck on macvtapN name created outside libvirt
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 :-) This bug was accidentally moved from POST to MODIFIED via an error in automation, please see mmccune with any questions 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
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 |
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