mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-29 17:15:23 +00:00
d7f38beb2e
There have been some reports that, due to libvirt always trying to assign the lowest numbered macvtap / tap device name possible, a new guest would sometimes be started using the same tap device name as previously used by another guest that is in the process of being destroyed *as the new guest is starting. In some cases this has led to, for example, the old guest's qemuProcessStop() code deleting a port from an OVS switch that had just been re-added by the new guest (because the port name is based on only the device name using the port). Similar problems can happen (and I believe have) with nwfilter rules and bandwidth rules (which are both instantiated based on the name of the tap device). A couple patches have been previously proposed to change the ordering of startup and shutdown processing, or to put a mutex around everything related to the tap/macvtap device name usage, but in the end no matter what you do there will still be possible holes, because the device could be deleted outside libvirt's control (for example, regular tap devices are automatically deleted when the qemu process terminates, and that isn't always initiated by libvirt but could instead happen completely asynchronously - libvirt then has no control over the ordering of shutdown operations, and no opportunity to protect it with a mutex.) But this only happens if a new device is created at the same time as one is being deleted. We can effectively eliminate the chance of this happening if we end the practice of always looking for the lowest numbered available device name, and instead just keep an integer that is incremented each time we need a new device name. At some point it will need to wrap back around to 0 (in order to avoid the IFNAMSIZ 15 character limit if nothing else), and we can't guarantee that the new name really will be the *least* recently used name, but "math" suggests that it will be *much* less common that we'll try to re-use the *most* recently used name. This patch implements such a counter for macvtap/macvlan, replacing the existing, and much more complicated, "ID reservation" system. The counter is set according to whatever macvtap/macvlan devices are already in use by guests when libvirtd is started, incremented each time a new device name is needed, and wraps back to 0 when either INT_MAX is reached, or when the resulting device name would be longer than IFNAMSIZ-1 characters (which actually is what happens when the template for the device name is "maccvtap%d"). The result is that no macvtap name will be re-used until the host has created (and possibly destroyed) 99,999,999 devices. Signed-off-by: Laine Stump <laine@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
124 lines
5.3 KiB
C
124 lines
5.3 KiB
C
/*
|
|
* Copyright (C) 2011, 2013, 2016 Red Hat, Inc.
|
|
* Copyright (C) 2010 IBM Corporation
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "internal.h"
|
|
#include "virmacaddr.h"
|
|
#include "virsocketaddr.h"
|
|
#include "virnetdevbandwidth.h"
|
|
#include "virnetdevvportprofile.h"
|
|
#include "virnetdevvlan.h"
|
|
#include "virenum.h"
|
|
|
|
/* the mode type for macvtap devices */
|
|
typedef enum {
|
|
VIR_NETDEV_MACVLAN_MODE_VEPA,
|
|
VIR_NETDEV_MACVLAN_MODE_PRIVATE,
|
|
VIR_NETDEV_MACVLAN_MODE_BRIDGE,
|
|
VIR_NETDEV_MACVLAN_MODE_PASSTHRU,
|
|
|
|
VIR_NETDEV_MACVLAN_MODE_LAST,
|
|
} virNetDevMacVLanMode;
|
|
VIR_ENUM_DECL(virNetDevMacVLanMode);
|
|
|
|
typedef enum {
|
|
VIR_NETDEV_MACVLAN_CREATE_NONE = 0,
|
|
/* Create with a tap device */
|
|
VIR_NETDEV_MACVLAN_CREATE_WITH_TAP = 1 << 0,
|
|
/* Bring the interface up */
|
|
VIR_NETDEV_MACVLAN_CREATE_IFUP = 1 << 1,
|
|
/* Enable VNET_HDR */
|
|
VIR_NETDEV_MACVLAN_VNET_HDR = 1 << 2,
|
|
} virNetDevMacVLanCreateFlags;
|
|
|
|
/* libvirt will start macvtap/macvlan interface names with one of
|
|
* these prefixes when it auto-generates the name
|
|
*/
|
|
#define VIR_NET_GENERATED_MACVTAP_PREFIX "macvtap"
|
|
#define VIR_NET_GENERATED_MACVLAN_PREFIX "macvlan"
|
|
|
|
void virNetDevMacVLanReserveName(const char *name);
|
|
|
|
bool virNetDevMacVLanIsMacvtap(const char *ifname)
|
|
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT G_GNUC_NO_INLINE;
|
|
|
|
int virNetDevMacVLanCreate(const char *ifname,
|
|
const char *type,
|
|
const virMacAddr *macaddress,
|
|
const char *srcdev,
|
|
uint32_t macvlan_mode)
|
|
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
|
G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanDelete(const char *ifname)
|
|
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanCreateWithVPortProfile(const char *ifname,
|
|
const virMacAddr *macaddress,
|
|
const char *linkdev,
|
|
virNetDevMacVLanMode mode,
|
|
const virNetDevVlan *vlan,
|
|
const unsigned char *vmuuid,
|
|
const virNetDevVPortProfile *virtPortProfile,
|
|
char **res_ifname,
|
|
virNetDevVPortProfileOp vmop,
|
|
char *stateDir,
|
|
int *tapfd,
|
|
size_t tapfdSize,
|
|
unsigned int flags)
|
|
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6)
|
|
ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(10) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanTapOpen(const char *ifname,
|
|
int *tapfd,
|
|
size_t tapfdSize)
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
|
|
G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanTapSetup(int *tapfd, size_t tapfdSize, bool vnet_hdr)
|
|
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
|
|
const virMacAddr *macaddress,
|
|
const char *linkdev,
|
|
int mode,
|
|
const virNetDevVPortProfile *virtPortProfile,
|
|
char *stateDir)
|
|
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
ATTRIBUTE_NONNULL(6) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
|
|
const virMacAddr *macaddress,
|
|
const char *linkdev,
|
|
const unsigned char *vmuuid,
|
|
const virNetDevVPortProfile *virtPortProfile,
|
|
virNetDevVPortProfileOp vmOp)
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT;
|
|
|
|
int virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
|
|
const virMacAddr *macaddress,
|
|
const char *linkdev,
|
|
const unsigned char *vmuuid,
|
|
const virNetDevVPortProfile *virtPortProfile,
|
|
virNetDevVPortProfileOp vmOp)
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT;
|