libvirt/src/util/virnetdevtap.h
Laine Stump 95089f481e util: assign tap device names using a monotonically increasing integer
When creating a standard tap device, if provided with an ifname that
contains "%d", rather than taking that literally as the name to use
for the new device, the kernel will instead use that string as a
template, and search for the lowest number that could be put in place
of %d and produce an otherwise unused and unique name for the new
device. For example, if there is no tap device name given in the XML,
libvirt will always send "vnet%d" as the device name, and the kernel
will create new devices named "vnet0", "vnet1", etc. If one of those
devices is deleted, creating a "hole" in the name list, the kernel
will always attempt to reuse the name in the hole first before using a
name with a higher number (i.e. it finds the lowest possible unused
number).

The problem with this, as described in the previous patch dealing with
macvtap device naming, is that it makes "immediate reuse" of a newly
freed tap device name *much* more common, and in the aftermath of
deleting a tap device, there is some other necessary cleanup of things
which are named based on the device name (nwfilter rules, bandwidth
rules, OVS switch ports, to name a few) that could end up stomping
over the top of the setup of a new device of the same name for a
different guest.

Since the kernel "create a name based on a template" functionality for
tap devices doesn't exist for macvtap, this patch for standard tap
devices is a bit different from the previous patch for macvtap - in
particular there was no previous "bitmap ID reservation system" or
overly-complex retry loop that needed to be removed. We simply find
and unused name, and pass that name on to the kernel instead of
"vnet%d".

This counter is also wrapped when either it gets to INT_MAX or if the
full name would overflow IFNAMSIZ-1 characters. In the case of
"vnet%d" and a 32 bit int, we would reach INT_MAX first, but possibly
someday someone will change the name from vnet to something else.

(NB: It is still possible for a user to provide their own
parameterized template name (e.g. "mytap%d") in the XML, and libvirt
will just pass that through to the kernel as it always has.)

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2020-09-01 14:16:44 -04:00

112 lines
4.4 KiB
C

/*
* Copyright (C) 2007-2011, 2013 Red Hat, Inc.
*
* 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 "virnetdev.h"
#include "virnetdevvportprofile.h"
#include "virnetdevvlan.h"
#ifdef __FreeBSD__
/* This should be defined on OSes that don't automatically
* cleanup released devices */
# define VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP 1
#endif
void
virNetDevTapReserveName(const char *name)
ATTRIBUTE_NONNULL(1);
int virNetDevTapCreate(char **ifname,
const char *tunpath,
int *tapfd,
size_t tapfdSize,
unsigned int flags)
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT G_GNUC_NO_INLINE;
int virNetDevTapDelete(const char *ifname,
const char *tunpath)
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT;
int virNetDevTapGetName(int tapfd, char **ifname)
ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
char* virNetDevTapGetRealDeviceName(char *ifname)
ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT G_GNUC_NO_INLINE;
typedef enum {
VIR_NETDEV_TAP_CREATE_NONE = 0,
/* Bring the interface up */
VIR_NETDEV_TAP_CREATE_IFUP = 1 << 0,
/* Enable IFF_VNET_HDR on the tap device */
VIR_NETDEV_TAP_CREATE_VNET_HDR = 1 << 1,
/* Set this interface's MAC as the bridge's MAC address */
VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE = 1 << 2,
/* The device will persist after the file descriptor is closed */
VIR_NETDEV_TAP_CREATE_PERSIST = 1 << 3,
} virNetDevTapCreateFlags;
int
virNetDevTapAttachBridge(const char *tapname,
const char *brname,
const virMacAddr *macaddr,
const unsigned char *vmuuid,
const virNetDevVPortProfile *virtPortProfile,
const virNetDevVlan *virtVlan,
virTristateBool isolatedPort,
unsigned int mtu,
unsigned int *actualMTU)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
G_GNUC_WARN_UNUSED_RESULT;
int
virNetDevTapReattachBridge(const char *tapname,
const char *brname,
const virMacAddr *macaddr,
const unsigned char *vmuuid,
const virNetDevVPortProfile *virtPortProfile,
const virNetDevVlan *virtVlan,
virTristateBool isolatedPort,
unsigned int mtu,
unsigned int *actualMTU)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
G_GNUC_WARN_UNUSED_RESULT;
int virNetDevTapCreateInBridgePort(const char *brname,
char **ifname,
const virMacAddr *macaddr,
const unsigned char *vmuuid,
const char *tunpath,
int *tapfd,
size_t tapfdSize,
const virNetDevVPortProfile *virtPortProfile,
const virNetDevVlan *virtVlan,
virTristateBool isolatedPort,
virNetDevCoalescePtr coalesce,
unsigned int mtu,
unsigned int *actualMTU,
unsigned int flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
G_GNUC_WARN_UNUSED_RESULT G_GNUC_NO_INLINE;
int virNetDevTapInterfaceStats(const char *ifname,
virDomainInterfaceStatsPtr stats,
bool swapped)
G_GNUC_WARN_UNUSED_RESULT;