From: Michal Privoznik <mprivozn@redhat.com> There are several types of virtual network interfaces that libvirt creates (TUN, TAP, MACVLAN, MACVTAP, VETH). After these are created (e.g. on domain startup or device hotplug), libvirt often opens their /dev/XXX representation (e.g. /dev/tapNN) in order to pass FDs to the hypervisor. Well, if creation an open() happen in very quick succession, then host's udev might not have had enough time and depending on system's SELinux even we might see open() fail, with AVC message logged. Signs of us trying to mitigate this problem are still to be found in virNetDevMacVLanTapOpen() where upon failed open() a very short g_usleep() is called. Alternatively, in linked gitlab issue, the user reports seeing the following message: type=AVC msg=audit(1774535384.365:1238): avc: denied { open } for pid=6765 comm="rpc-virtqemud" path="/dev/tap33" dev="devtmpfs" ino=805 scontext=system_u:system_r:virtqemud_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=chr_file permissive=1 (For full reasoning why /dev/tap33 is of device_t type see linked issue). Long story short, /dev/tapNN devices are created initially with device_t SELinux type and udev later changes that to tun_tap_device_t. This device_t type is viewed as generic type that only an yet unlabelled device has. Hence missing rule in SELinux policy for virtqemud to open it. Therefore, to avoid this problem, wait for udev to settle by calling virWaitForDevices() (which under the hood spawns "udevadm settle". This may be a bit too heavy hammer though because the function is called basically once per (almost) each <interface/>. If we find that to be a performance drawback then we need to redesign how tun/tap/... devices are created (well, opened). Resolves: https://gitlab.com/libvirt/libvirt/-/work_items/866 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/util/virnetdevmacvlan.c | 4 ++++ src/util/virnetdevtap.c | 6 ++++++ src/util/virnetdevveth.c | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index cde9d70eef..347148542d 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -24,6 +24,7 @@ #include "virnetdevmacvlan.h" #include "virmacaddr.h" #include "virerror.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NET @@ -119,6 +120,9 @@ virNetDevMacVLanCreate(const char *ifname, return -1; } + /* Allow udev to process newly created mactap/macvlan. */ + virWaitForDevices(); + VIR_INFO("created device: '%s'", ifname); return 0; } diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index e3a6209642..38f50e959e 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -29,6 +29,7 @@ #include "viralloc.h" #include "virlog.h" #include "virstring.h" +#include "virutil.h" #include <unistd.h> #include <sys/types.h> @@ -265,6 +266,9 @@ int virNetDevTapCreate(char **ifname, tapfd[i] = fd; } + /* Allow udev to process newly created TUN/TAP. */ + virWaitForDevices(); + VIR_INFO("created device: '%s'", *ifname); ret = 0; @@ -375,6 +379,8 @@ int virNetDevTapCreate(char **ifname, if (virNetDevSetName(ifr.ifr_name, *ifname) == -1) goto cleanup; + /* Allow udev to process newly created TUN/TAP. */ + virWaitForDevices(); ret = 0; cleanup: diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c index 4365345664..77b017427a 100644 --- a/src/util/virnetdevveth.c +++ b/src/util/virnetdevveth.c @@ -26,6 +26,7 @@ #include "virerror.h" #include "virnetdev.h" #include "virnetlink.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -127,6 +128,9 @@ int virNetDevVethCreate(char **veth1, char **veth2) if (virNetDevVethCreateInternal(*veth1, *veth2) < 0) goto cleanup; + /* Allow udev to process newly created veth. */ + virWaitForDevices(); + VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2); return 0; -- 2.52.0