libvirt/src/util/virnetdevmacvlan.c

1166 lines
39 KiB
C
Raw Normal View History

/*
* Copyright (C) 2010-2017 Red Hat, Inc.
* Copyright (C) 2010-2012 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/>.
*
* Notes:
* netlink: http://lovezutto.googlepages.com/netlink.pdf
* iproute2 package
*
*/
#include <config.h>
#include "virnetdevmacvlan.h"
#include "virmacaddr.h"
#include "virerror.h"
#include "virthread.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NET
VIR_ENUM_IMPL(virNetDevMacVLanMode,
VIR_NETDEV_MACVLAN_MODE_LAST,
"vepa",
"private",
"bridge",
"passthrough",
);
#if WITH_MACVTAP
# include <fcntl.h>
# include <net/if.h>
# include <linux/if_tun.h>
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
# include <math.h>
/* Older kernels lacked this enum value. */
# if !WITH_DECL_MACVLAN_MODE_PASSTHRU
# define MACVLAN_MODE_PASSTHRU 8
# endif
2012-12-12 18:06:53 +00:00
# include "viralloc.h"
2012-12-12 17:59:27 +00:00
# include "virlog.h"
2012-12-13 18:01:25 +00:00
# include "viruuid.h"
# include "virfile.h"
# include "virnetlink.h"
# include "virnetdev.h"
# include "virpidfile.h"
2016-01-19 19:20:54 +00:00
# include "virbitmap.h"
# include "virsocket.h"
VIR_LOG_INIT("util.netdevmacvlan");
# define VIR_NET_GENERATED_MACVTAP_PATTERN VIR_NET_GENERATED_MACVTAP_PREFIX "%d"
# define VIR_NET_GENERATED_MACVLAN_PATTERN VIR_NET_GENERATED_MACVLAN_PREFIX "%d"
# define VIR_NET_GENERATED_PREFIX \
((flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ? \
VIR_NET_GENERATED_MACVTAP_PREFIX : VIR_NET_GENERATED_MACVLAN_PREFIX)
2016-01-19 19:20:54 +00:00
virMutex virNetDevMacVLanCreateMutex = VIR_MUTEX_INITIALIZER;
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
static int virNetDevMacVTapLastID = -1;
static int virNetDevMacVLanLastID = -1;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
static void
virNetDevMacVLanReserveNameInternal(const char *name)
2016-01-19 19:20:54 +00:00
{
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
unsigned int id;
const char *idstr = NULL;
int *lastID = NULL;
int len;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (STRPREFIX(name, VIR_NET_GENERATED_MACVTAP_PREFIX)) {
lastID = &virNetDevMacVTapLastID;
len = strlen(VIR_NET_GENERATED_MACVTAP_PREFIX);
} else if (STRPREFIX(name, VIR_NET_GENERATED_MACVLAN_PREFIX)) {
lastID = &virNetDevMacVTapLastID;
len = strlen(VIR_NET_GENERATED_MACVLAN_PREFIX);
} else {
return;
2016-01-19 19:20:54 +00:00
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
VIR_INFO("marking device in use: '%s'", name);
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
idstr = name + len;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
if (*lastID < (int)id)
*lastID = id;
2016-01-19 19:20:54 +00:00
}
}
/**
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
* virNetDevMacVLanReserveName:
* @name: name of an existing macvtap/macvlan device
2016-01-19 19:20:54 +00:00
*
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
* Set the value of virNetDevMacV(Lan|Tap)LastID to assure that any
* new device created with an autogenerated name will use a number
* higher than the number in the given device name.
*
* Returns nothing.
2016-01-19 19:20:54 +00:00
*/
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
void
virNetDevMacVLanReserveName(const char *name)
2016-01-19 19:20:54 +00:00
{
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
virMutexLock(&virNetDevMacVLanCreateMutex);
virNetDevMacVLanReserveNameInternal(name);
virMutexUnlock(&virNetDevMacVLanCreateMutex);
2016-01-19 19:20:54 +00:00
}
/**
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
* virNetDevMacVLanGenerateName:
* @ifname: pointer to pointer to string containing template
* @lastID: counter to add to the template to form the name
2016-01-19 19:20:54 +00:00
*
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
* generate a new (currently unused) name for a new macvtap/macvlan
* device based on the template string in @ifname - replace %d with
* ++(*counter), and keep trying new values until one is found
* that doesn't already exist, or we've tried 10000 different
* names. Once a usable name is found, replace the template with the
* actual name.
2016-01-19 19:20:54 +00:00
*
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
* Returns 0 on success, -1 on failure.
2016-01-19 19:20:54 +00:00
*/
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
static int
virNetDevMacVLanGenerateName(char **ifname, unsigned int flags)
2016-01-19 19:20:54 +00:00
{
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
const char *prefix;
const char *iftemplate;
int *lastID;
int id;
double maxIDd;
int maxID = INT_MAX;
int attempts = 0;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) {
prefix = VIR_NET_GENERATED_MACVTAP_PREFIX;
iftemplate = VIR_NET_GENERATED_MACVTAP_PREFIX "%d";
lastID = &virNetDevMacVTapLastID;
2016-01-19 19:20:54 +00:00
} else {
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
prefix = VIR_NET_GENERATED_MACVLAN_PREFIX;
iftemplate = VIR_NET_GENERATED_MACVLAN_PREFIX "%d";
lastID = &virNetDevMacVLanLastID;
2016-01-19 19:20:54 +00:00
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
maxIDd = pow(10, IFNAMSIZ - 1 - strlen(prefix));
if (maxIDd <= (double)INT_MAX)
maxID = (int)maxIDd;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
do {
g_autofree char *try = NULL;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
id = ++(*lastID);
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
/* reset before overflow */
if (*lastID == maxID)
*lastID = -1;
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
try = g_strdup_printf(iftemplate, id);
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (!virNetDevExists(try)) {
g_free(*ifname);
*ifname = g_steal_pointer(&try);
return 0;
}
} while (++attempts < 10000);
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no unused %s names available"),
*ifname);
return -1;
2016-01-19 19:20:54 +00:00
}
/**
* virNetDevMacVLanIsMacvtap:
* @ifname: Name of the interface
*
* Return T if the named netdev exists and is a macvtap device
* F in all other cases.
*/
bool
virNetDevMacVLanIsMacvtap(const char *ifname)
{
int ifindex;
g_autofree char *tapname = NULL;
if (virNetDevGetIndex(ifname, &ifindex) < 0)
return false;
tapname = g_strdup_printf("/dev/tap%d", ifindex);
return virFileExists(tapname);
}
/**
* virNetDevMacVLanCreate:
*
* @ifname: The name the interface is supposed to have; optional parameter
* @type: The type of device, i.e., "macvtap", "macvlan"
* @macaddress: The MAC address of the device
* @srcdev: The name of the 'link' device
* @macvlan_mode: The macvlan mode to use
* @retry: Pointer to integer that will be '1' upon return if an interface
* with the same name already exists and it is worth to try
* again with a different name
*
* Create a macvtap device with the given properties.
*
* Returns 0 on success, -1 on fatal error.
*/
int
virNetDevMacVLanCreate(const char *ifname,
const char *type,
maint: avoid 'const fooPtr' in virnet files 'const fooPtr' is the same as 'foo * const' (the pointer won't change, but it's contents can). But in general, if an interface is trying to be const-correct, it should be using 'const foo *' (the pointer is to data that can't be changed). Fix up remaining offenders in src/util. * src/util/virnetdev.h (virNetDevSetMAC) (virNetDevReplaceMacAddress, virNetDevValidateConfig) (virNetDevReplaceNetConfig): Use intended type. * src/util/virnetdevbandwidth.h (virNetDevBandwidthCopy) (virNetDevBandwidthPlug): Likewise. * src/util/virnetdevmacvlan.h (virNetDevMacVLanCreate) (virNetDevMacVLanCreateWithVPortProfile) (virNetDevMacVLanDeleteWithVPortProfile) (virNetDevMacVLanRestartWithVPortProfile) (virNetDevMacVLanVPortProfileRegisterCallback): Likewise. * src/util/virnetdevopenvswitch.h (virNetDevOpenvswitchAddPort): Likewise. * src/util/virnetdevtap.h (virNetDevTapCreateInBridgePort): Likewise. * src/util/virnetdevvlan.h (virNetDevVlanEqual) (virNetDevVlanCopy): Likewise. * src/util/virnetdevvportprofile.h (virNetDevVPortProfileAssociate) (virNetDevVPortProfileDisassociate): Likewise. * src/util/virnetlink.h (virNetlinkEventRemoveCallback) (virNetlinkEventAddClient, virNetlinkEventRemoveClient): Likewise. * src/util/virnetdev.c (virNetDevSetMAC) (virNetDevReplaceMacAddress, virNetDevValidateConfig) (virNetDevReplaceNetConfig): Fix fallout. * src/util/virnetdevbandwidth.c (virNetDevBandwidthCopy) (virNetDevBandwidthPlug): Likewise. * src/util/virnetdevmacvlan.c (virNetDevMacVLanCreate) (virNetDevMacVLanCreateWithVPortProfile) (virNetDevMacVLanDeleteWithVPortProfile) (virNetDevMacVLanRestartWithVPortProfile) (virNetDevMacVLanVPortProfileRegisterCallback): Likewise. * src/util/virnetdevopenvswitch.c (virNetDevOpenvswitchAddPort): Likewise. * src/util/virnetdevtap.c (virNetDevTapCreateInBridgePort): Likewise. * src/util/virnetdevvlan.c (virNetDevVlanEqual) (virNetDevVlanCopy): Likewise. * src/util/virnetdevvportprofile.c (virNetDevVPortProfileAssociate) (virNetDevVPortProfileDisassociate) (virNetDevVPortProfileOpSetLink, virNetDevVPortProfileOpCommon) (virNetDevVPortProfileOp8021Qbg, virNetDevVPortProfileOp8021Qbh): Likewise. * src/util/virnetlink.c (virNetlinkEventRemoveCallback) (virNetlinkEventAddClient, virNetlinkEventRemoveClient): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 19:41:44 +00:00
const virMacAddr *macaddress,
const char *srcdev,
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
uint32_t macvlan_mode)
{
int error = 0;
int ifindex = 0;
virNetlinkNewLinkData data = {
.macvlan_mode = &macvlan_mode,
.mac = macaddress,
};
if (virNetDevGetIndex(srcdev, &ifindex) < 0)
return -1;
data.ifindex = &ifindex;
if (virNetlinkNewLink(ifname, type, &data, &error) < 0) {
char macstr[VIR_MAC_STRING_BUFLEN];
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
virReportSystemError(-error,
_("error creating %s interface %s@%s (%s)"),
type, ifname, srcdev,
virMacAddrFormat(macaddress, macstr));
return -1;
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
VIR_INFO("created device: '%s'", ifname);
return 0;
}
/**
* virNetDevMacVLanDelete:
*
* @ifname: Name of the interface
*
* Tear down an interface with the given name.
*
* Returns 0 on success, -1 on fatal error.
*/
int virNetDevMacVLanDelete(const char *ifname)
{
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
VIR_INFO("delete device: '%s'", ifname);
return virNetlinkDelLink(ifname, NULL);
}
/**
* virNetDevMacVLanTapOpen:
* @ifname: Name of the macvtap interface
* @tapfd: array of file descriptor return value for the new macvtap device
* @tapfdSize: number of file descriptors in @tapfd
*
* Open the macvtap's tap device, possibly multiple times if @tapfdSize > 1.
*
* Returns 0 on success, -1 otherwise.
*/
int
virNetDevMacVLanTapOpen(const char *ifname,
int *tapfd,
size_t tapfdSize)
{
int retries = 10;
int ret = -1;
int ifindex;
size_t i = 0;
g_autofree char *tapname = NULL;
if (virNetDevGetIndex(ifname, &ifindex) < 0)
return -1;
tapname = g_strdup_printf("/dev/tap%d", ifindex);
for (i = 0; i < tapfdSize; i++) {
int fd = -1;
while (fd < 0) {
if ((fd = open(tapname, O_RDWR)) >= 0) {
tapfd[i] = fd;
} else if (retries-- > 0) {
/* may need to wait for udev to be done */
g_usleep(20000);
} else {
/* However, if haven't succeeded, quit. */
virReportSystemError(errno,
_("cannot open macvtap tap device %s"),
tapname);
goto cleanup;
}
}
}
ret = 0;
cleanup:
if (ret < 0) {
while (i--)
VIR_FORCE_CLOSE(tapfd[i]);
}
return ret;
}
/**
* virNetDevMacVLanTapSetup:
* @tapfd: array of file descriptors of the macvtap tap
* @tapfdSize: number of file descriptors in @tapfd
* @vnet_hdr: whether to enable or disable IFF_VNET_HDR
*
* Turn on the IFF_VNET_HDR flag if requested and available, but make sure
* it's off otherwise. Similarly, turn on IFF_MULTI_QUEUE if @tapfdSize is
* greater than one, but if it can't be set, consider it a fatal error
* (rather than ignoring as with @vnet_hdr).
*
* A fatal error is defined as the VNET_HDR flag being set but it cannot
* be turned off for some reason. This is reported with -1. Other fatal
* error is not being able to read the interface flags. In that case the
* macvtap device should not be used.
*
* Returns 0 on success, -1 in case of fatal error.
*/
int
virNetDevMacVLanTapSetup(int *tapfd, size_t tapfdSize, bool vnet_hdr)
{
unsigned int features;
struct ifreq ifreq;
short new_flags = 0;
size_t i;
for (i = 0; i < tapfdSize; i++) {
memset(&ifreq, 0, sizeof(ifreq));
if (ioctl(tapfd[i], TUNGETIFF, &ifreq) < 0) {
virReportSystemError(errno, "%s",
_("cannot get interface flags on macvtap tap"));
return -1;
}
new_flags = ifreq.ifr_flags;
if (vnet_hdr) {
if (ioctl(tapfd[i], TUNGETFEATURES, &features) < 0) {
virReportSystemError(errno, "%s",
_("cannot get feature flags on macvtap tap"));
return -1;
}
if (features & IFF_VNET_HDR)
new_flags |= IFF_VNET_HDR;
} else {
new_flags &= ~IFF_VNET_HDR;
}
# ifdef IFF_MULTI_QUEUE
if (tapfdSize > 1)
new_flags |= IFF_MULTI_QUEUE;
else
new_flags &= ~IFF_MULTI_QUEUE;
# else
if (tapfdSize > 1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Multiqueue devices are not supported on this system"));
return -1;
}
# endif
if (new_flags != ifreq.ifr_flags) {
ifreq.ifr_flags = new_flags;
if (ioctl(tapfd[i], TUNSETIFF, &ifreq) < 0) {
virReportSystemError(errno, "%s",
_("unable to set vnet or multiqueue flags on macvtap"));
return -1;
}
}
}
return 0;
}
static const uint32_t modeMap[VIR_NETDEV_MACVLAN_MODE_LAST] = {
[VIR_NETDEV_MACVLAN_MODE_VEPA] = MACVLAN_MODE_VEPA,
[VIR_NETDEV_MACVLAN_MODE_PRIVATE] = MACVLAN_MODE_PRIVATE,
[VIR_NETDEV_MACVLAN_MODE_BRIDGE] = MACVLAN_MODE_BRIDGE,
[VIR_NETDEV_MACVLAN_MODE_PASSTHRU] = MACVLAN_MODE_PASSTHRU,
};
/* Struct to hold the state and configuration of a 802.1qbg port */
struct virNetlinkCallbackData {
char *cr_ifname;
virNetDevVPortProfilePtr virtPortProfile;
virMacAddr macaddress;
char *linkdev;
int vf;
unsigned char vmuuid[VIR_UUID_BUFLEN];
virNetDevVPortProfileOp vmOp;
unsigned int linkState;
};
typedef struct virNetlinkCallbackData *virNetlinkCallbackDataPtr;
# define INSTANCE_STRLEN 36
static int instance2str(const unsigned char *p, char *dst, size_t size)
{
if (dst && size > INSTANCE_STRLEN) {
g_snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x-%02x%02x%02x%02x%02x%02x",
p[0], p[1], p[2], p[3],
p[4], p[5], p[6], p[7],
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
return 0;
}
return -1;
}
# define LLDPAD_PID_FILE "/var/run/lldpad.pid"
# define VIRIP_PID_FILE "/var/run/virip.pid"
/**
* virNetDevMacVLanVPortProfileCallback:
*
* @hdr: The buffer containing the received netlink header + payload
* @length: The length of the received netlink message.
* @peer: The netling sockaddr containing the peer information
* @handled: Contains information if the message has been replied to yet
* @opaque: Contains vital information regarding the associated vm an interface
*
* This function is called when a netlink message is received. The function
* reads the message and responds if it is pertinent to the running VMs
* network interface.
*/
static void
virNetDevMacVLanVPortProfileCallback(struct nlmsghdr *hdr,
unsigned int length,
struct sockaddr_nl *peer,
bool *handled,
void *opaque)
{
struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] = {
[IFLA_VF_MAC] = {.minlen = sizeof(struct ifla_vf_mac),
.maxlen = sizeof(struct ifla_vf_mac)},
[IFLA_VF_VLAN] = {.minlen = sizeof(struct ifla_vf_vlan),
.maxlen = sizeof(struct ifla_vf_vlan)},
};
struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = {
[IFLA_PORT_RESPONSE] = {.type = NLA_U16},
};
struct nlattr *tb[IFLA_MAX + 1], *tb3[IFLA_PORT_MAX + 1],
*tb_vfinfo[IFLA_VF_MAX + 1], *tb_vfinfo_list;
struct ifinfomsg ifinfo;
void *data;
int rem;
char *ifname;
bool indicate = false;
virNetlinkCallbackDataPtr calld = opaque;
pid_t lldpad_pid = 0;
pid_t virip_pid = 0;
char macaddr[VIR_MAC_STRING_BUFLEN];
data = nlmsg_data(hdr);
/* Quickly decide if we want this or not */
if (virPidFileReadPath(LLDPAD_PID_FILE, &lldpad_pid) < 0)
return;
ignore_value(virPidFileReadPath(VIRIP_PID_FILE, &virip_pid));
if (hdr->nlmsg_pid != lldpad_pid && hdr->nlmsg_pid != virip_pid)
return; /* we only care for lldpad and virip messages */
if (hdr->nlmsg_type != RTM_SETLINK)
return; /* we only care for RTM_SETLINK */
if (*handled)
return; /* if it has been handled - dont handle again */
/* DEBUG start */
VIR_INFO("netlink message nl_sockaddr: %p len: %d", peer, length);
VIR_DEBUG("nlmsg_type = 0x%02x", hdr->nlmsg_type);
VIR_DEBUG("nlmsg_len = 0x%04x", hdr->nlmsg_len);
VIR_DEBUG("nlmsg_pid = %d", hdr->nlmsg_pid);
VIR_DEBUG("nlmsg_seq = 0x%08x", hdr->nlmsg_seq);
VIR_DEBUG("nlmsg_flags = 0x%04x", hdr->nlmsg_flags);
VIR_DEBUG("lldpad pid = %d", lldpad_pid);
switch (hdr->nlmsg_type) {
case RTM_NEWLINK:
case RTM_DELLINK:
case RTM_SETLINK:
case RTM_GETLINK:
VIR_DEBUG(" IFINFOMSG");
VIR_DEBUG(" ifi_family = 0x%02x",
((struct ifinfomsg *)data)->ifi_family);
VIR_DEBUG(" ifi_type = 0x%x",
((struct ifinfomsg *)data)->ifi_type);
VIR_DEBUG(" ifi_index = %i",
((struct ifinfomsg *)data)->ifi_index);
VIR_DEBUG(" ifi_flags = 0x%04x",
((struct ifinfomsg *)data)->ifi_flags);
VIR_DEBUG(" ifi_change = 0x%04x",
((struct ifinfomsg *)data)->ifi_change);
}
/* DEBUG end */
/* Parse netlink message assume a setlink with vfports */
memcpy(&ifinfo, NLMSG_DATA(hdr), sizeof(ifinfo));
VIR_DEBUG("family:%#x type:%#x index:%d flags:%#x change:%#x",
ifinfo.ifi_family, ifinfo.ifi_type, ifinfo.ifi_index,
ifinfo.ifi_flags, ifinfo.ifi_change);
if (nlmsg_parse(hdr, sizeof(ifinfo),
(struct nlattr **)&tb, IFLA_MAX, NULL)) {
VIR_DEBUG("error parsing request...");
return;
}
if (tb[IFLA_VFINFO_LIST]) {
VIR_DEBUG("FOUND IFLA_VFINFO_LIST!");
nla_for_each_nested(tb_vfinfo_list, tb[IFLA_VFINFO_LIST], rem) {
if (nla_type(tb_vfinfo_list) != IFLA_VF_INFO) {
VIR_DEBUG("nested parsing of"
"IFLA_VFINFO_LIST failed.");
return;
}
if (nla_parse_nested(tb_vfinfo, IFLA_VF_MAX,
tb_vfinfo_list, ifla_vf_policy)) {
VIR_DEBUG("nested parsing of "
"IFLA_VF_INFO failed.");
return;
}
}
if (tb_vfinfo[IFLA_VF_MAC]) {
struct ifla_vf_mac *mac = RTA_DATA(tb_vfinfo[IFLA_VF_MAC]);
unsigned char *m = mac->mac;
VIR_DEBUG("IFLA_VF_MAC = %2x:%2x:%2x:%2x:%2x:%2x",
m[0], m[1], m[2], m[3], m[4], m[5]);
if (virMacAddrCmpRaw(&calld->macaddress, mac->mac)) {
/* Repeat the same check for a broadcast mac */
size_t i;
for (i = 0; i < VIR_MAC_BUFLEN; i++) {
if (calld->macaddress.addr[i] != 0xff) {
VIR_DEBUG("MAC address match failed (wasn't broadcast)");
return;
}
}
}
}
if (tb_vfinfo[IFLA_VF_VLAN]) {
struct ifla_vf_vlan *vlan = RTA_DATA(tb_vfinfo[IFLA_VF_VLAN]);
VIR_DEBUG("IFLA_VF_VLAN = %d", vlan->vlan);
}
}
if (tb[IFLA_IFNAME]) {
ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
VIR_DEBUG("IFLA_IFNAME = %s", ifname);
}
if (tb[IFLA_OPERSTATE]) {
rem = *(unsigned short *)RTA_DATA(tb[IFLA_OPERSTATE]);
VIR_DEBUG("IFLA_OPERSTATE = %d", rem);
}
if (tb[IFLA_VF_PORTS]) {
struct nlattr *tb_vf_ports;
VIR_DEBUG("found IFLA_VF_PORTS");
nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
VIR_DEBUG("iterating");
if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
VIR_DEBUG("not a IFLA_VF_PORT. skipping");
continue;
}
if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports,
ifla_port_policy)) {
VIR_DEBUG("nested parsing on level 2"
" failed.");
}
if (tb3[IFLA_PORT_VF]) {
VIR_DEBUG("IFLA_PORT_VF = %d",
*(uint32_t *) (RTA_DATA(tb3[IFLA_PORT_VF])));
}
if (tb3[IFLA_PORT_PROFILE]) {
VIR_DEBUG("IFLA_PORT_PROFILE = %s",
(char *) RTA_DATA(tb3[IFLA_PORT_PROFILE]));
}
if (tb3[IFLA_PORT_VSI_TYPE]) {
struct ifla_port_vsi *pvsi;
int tid = 0;
pvsi = (struct ifla_port_vsi *)
RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]);
tid = ((pvsi->vsi_type_id[2] << 16) |
(pvsi->vsi_type_id[1] << 8) |
pvsi->vsi_type_id[0]);
VIR_DEBUG("mgr_id: %d", pvsi->vsi_mgr_id);
VIR_DEBUG("type_id: %d", tid);
VIR_DEBUG("type_version: %d",
pvsi->vsi_type_version);
}
if (tb3[IFLA_PORT_INSTANCE_UUID]) {
char instance[INSTANCE_STRLEN + 2];
unsigned char *uuid;
uuid = (unsigned char *)
RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
instance2str(uuid, instance, sizeof(instance));
VIR_DEBUG("IFLA_PORT_INSTANCE_UUID = %s",
instance);
}
if (tb3[IFLA_PORT_REQUEST]) {
uint8_t req = *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]);
VIR_DEBUG("IFLA_PORT_REQUEST = %d", req);
if (req == PORT_REQUEST_DISASSOCIATE) {
VIR_DEBUG("Set disassociated.");
indicate = true;
}
}
if (tb3[IFLA_PORT_RESPONSE]) {
VIR_DEBUG("IFLA_PORT_RESPONSE = %d",
*(uint16_t *) RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
}
}
}
if (!indicate)
return;
VIR_INFO("Re-send 802.1qbg associate request:");
VIR_INFO(" if: %s", calld->cr_ifname);
VIR_INFO(" lf: %s", calld->linkdev);
VIR_INFO(" mac: %s", virMacAddrFormat(&calld->macaddress, macaddr));
ignore_value(virNetDevVPortProfileAssociate(calld->cr_ifname,
calld->virtPortProfile,
&calld->macaddress,
calld->linkdev,
calld->vf,
calld->vmuuid,
calld->vmOp, true));
*handled = true;
return;
}
/**
* virNetlinkCallbackDataFree
*
* @calld: pointer to a virNetlinkCallbackData object to free
*
* This function frees all the data associated with a virNetlinkCallbackData object
* as well as the object itself. If called with NULL, it does nothing.
*
* Returns nothing.
*/
static void
virNetlinkCallbackDataFree(virNetlinkCallbackDataPtr calld)
{
if (calld) {
VIR_FREE(calld->cr_ifname);
VIR_FREE(calld->virtPortProfile);
VIR_FREE(calld->linkdev);
}
VIR_FREE(calld);
}
/**
* virNetDevMacVLanVPortProfileDestroyCallback:
*
* @watch: watch whose handle to remove
* @macaddr: macaddr whose handle to remove
* @opaque: Contains vital information regarding the associated vm
*
* This function is called when a netlink message handler is terminated.
* The function frees locally allocated data referenced in the opaque
* data, and the opaque object itself.
*/
static void
virNetDevMacVLanVPortProfileDestroyCallback(int watch G_GNUC_UNUSED,
const virMacAddr *macaddr G_GNUC_UNUSED,
void *opaque)
{
virNetlinkCallbackDataFree((virNetlinkCallbackDataPtr)opaque);
}
int
virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
maint: avoid 'const fooPtr' in virnet files 'const fooPtr' is the same as 'foo * const' (the pointer won't change, but it's contents can). But in general, if an interface is trying to be const-correct, it should be using 'const foo *' (the pointer is to data that can't be changed). Fix up remaining offenders in src/util. * src/util/virnetdev.h (virNetDevSetMAC) (virNetDevReplaceMacAddress, virNetDevValidateConfig) (virNetDevReplaceNetConfig): Use intended type. * src/util/virnetdevbandwidth.h (virNetDevBandwidthCopy) (virNetDevBandwidthPlug): Likewise. * src/util/virnetdevmacvlan.h (virNetDevMacVLanCreate) (virNetDevMacVLanCreateWithVPortProfile) (virNetDevMacVLanDeleteWithVPortProfile) (virNetDevMacVLanRestartWithVPortProfile) (virNetDevMacVLanVPortProfileRegisterCallback): Likewise. * src/util/virnetdevopenvswitch.h (virNetDevOpenvswitchAddPort): Likewise. * src/util/virnetdevtap.h (virNetDevTapCreateInBridgePort): Likewise. * src/util/virnetdevvlan.h (virNetDevVlanEqual) (virNetDevVlanCopy): Likewise. * src/util/virnetdevvportprofile.h (virNetDevVPortProfileAssociate) (virNetDevVPortProfileDisassociate): Likewise. * src/util/virnetlink.h (virNetlinkEventRemoveCallback) (virNetlinkEventAddClient, virNetlinkEventRemoveClient): Likewise. * src/util/virnetdev.c (virNetDevSetMAC) (virNetDevReplaceMacAddress, virNetDevValidateConfig) (virNetDevReplaceNetConfig): Fix fallout. * src/util/virnetdevbandwidth.c (virNetDevBandwidthCopy) (virNetDevBandwidthPlug): Likewise. * src/util/virnetdevmacvlan.c (virNetDevMacVLanCreate) (virNetDevMacVLanCreateWithVPortProfile) (virNetDevMacVLanDeleteWithVPortProfile) (virNetDevMacVLanRestartWithVPortProfile) (virNetDevMacVLanVPortProfileRegisterCallback): Likewise. * src/util/virnetdevopenvswitch.c (virNetDevOpenvswitchAddPort): Likewise. * src/util/virnetdevtap.c (virNetDevTapCreateInBridgePort): Likewise. * src/util/virnetdevvlan.c (virNetDevVlanEqual) (virNetDevVlanCopy): Likewise. * src/util/virnetdevvportprofile.c (virNetDevVPortProfileAssociate) (virNetDevVPortProfileDisassociate) (virNetDevVPortProfileOpSetLink, virNetDevVPortProfileOpCommon) (virNetDevVPortProfileOp8021Qbg, virNetDevVPortProfileOp8021Qbh): Likewise. * src/util/virnetlink.c (virNetlinkEventRemoveCallback) (virNetlinkEventAddClient, virNetlinkEventRemoveClient): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 19:41:44 +00:00
const virMacAddr *macaddress,
const char *linkdev,
const unsigned char *vmuuid,
const virNetDevVPortProfile *virtPortProfile,
virNetDevVPortProfileOp vmOp)
{
virNetlinkCallbackDataPtr calld = NULL;
if (virtPortProfile && virNetlinkEventServiceIsRunning(NETLINK_ROUTE)) {
if (VIR_ALLOC(calld) < 0)
goto error;
calld->cr_ifname = g_strdup(ifname);
if (VIR_ALLOC(calld->virtPortProfile) < 0)
goto error;
memcpy(calld->virtPortProfile, virtPortProfile, sizeof(*virtPortProfile));
virMacAddrSet(&calld->macaddress, macaddress);
calld->linkdev = g_strdup(linkdev);
memcpy(calld->vmuuid, vmuuid, sizeof(calld->vmuuid));
calld->vmOp = vmOp;
if (virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback,
virNetDevMacVLanVPortProfileDestroyCallback,
calld, macaddress, NETLINK_ROUTE) < 0)
goto error;
}
return 0;
error:
virNetlinkCallbackDataFree(calld);
return -1;
}
/**
* virNetDevMacVLanCreateWithVPortProfile:
* Create an instance of a macvtap device and open its tap character
* device.
2016-01-19 19:20:54 +00:00
* @ifnameRequested: Interface name that the caller wants the macvtap
* device to have, or NULL to pick the first available name
* appropriate for the type (macvlan%d or macvtap%d). If the
* suggested name fits one of those patterns, but is already in
* use, we will fallback to finding the first available. If the
* suggested name *doesn't* fit a pattern and the name is in use,
* we will fail.
* @macaddress: The MAC address for the macvtap device
* @linkdev: The interface name of the NIC to connect to the external bridge
2016-01-19 19:20:54 +00:00
* @mode: macvtap mode (VIR_NETDEV_MACVLAN_MODE_(BRIDGE|VEPA|PRIVATE|PASSTHRU)
* @vmuuid: The UUID of the VM the macvtap belongs to
* @virtPortProfile: pointer to object holding the virtual port profile data
2016-01-19 19:20:54 +00:00
* @ifnameResult: Pointer to a string pointer where the actual name of the
* interface will be stored into if everything succeeded. It is up
* to the caller to free the string.
* @tapfd: array of file descriptor return value for the new tap device
* @tapfdSize: number of file descriptors in @tapfd
* @flags: OR of virNetDevMacVLanCreateFlags.
*
* Creates a macvlan device. Optionally, if flags &
* VIR_NETDEV_MACVLAN_CREATE_WITH_TAP is set, @tapfd is populated with FDs of
* tap devices up to @tapfdSize.
*
* Return 0 on success, -1 on error.
*/
2016-01-19 19:20:54 +00:00
int
virNetDevMacVLanCreateWithVPortProfile(const char *ifnameRequested,
const virMacAddr *macaddress,
const char *linkdev,
virNetDevMacVLanMode mode,
const virNetDevVlan *vlan,
2016-01-19 19:20:54 +00:00
const unsigned char *vmuuid,
const virNetDevVPortProfile *virtPortProfile,
2016-01-19 19:20:54 +00:00
char **ifnameResult,
virNetDevVPortProfileOp vmOp,
char *stateDir,
int *tapfd,
size_t tapfdSize,
unsigned int flags)
{
const char *type = VIR_NET_GENERATED_PREFIX;
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
g_autofree char *ifname = NULL;
uint32_t macvtapMode;
int vf = -1;
bool vnet_hdr = flags & VIR_NETDEV_MACVLAN_VNET_HDR;
macvtapMode = modeMap[mode];
2016-01-19 19:20:54 +00:00
*ifnameResult = NULL;
/** Note: When using PASSTHROUGH mode with MACVTAP devices the link
* device's MAC address must be set to the VMs MAC address. In
* order to not confuse the first switch or bridge in line this MAC
* address must be reset when the VM is shut down.
* This is especially important when using SRIOV capable cards that
* emulate their switch in firmware.
*/
util: don't use netlink to save/set mac for macvtap+passthrough+802.1Qbh Before libvirt sets the MAC address of the physdev (the physical ethernet device) linked to a macvtap passthrough device, it always saves the previous MAC address to restore when the guest is finished (following a "leave nothing behind" policy). For a long time it accomplished the save/restore with a combination of ioctl(SIOCGIFHWADDR) and ioctl(SIOCSIFHWADDR), but in commit cbfe38c (first in libvirt 1.2.15) this was changed to use netlink RTM_GETLINK and RTM_SETLINK commands sent to the Physical Function (PF) of any device that was detected to be a Virtual Function (VF). We later found out that this caused problems with any devices using the Cisco enic driver (e.g. vmfex cards) because the enic driver hasn't implemented the function that is called to gather the information in the IFLA_VFINFO_LIST attribute of RTM_GETLINK (ndo_get_vf_config() for those keeping score), so we would never get back a useful response. In an ideal world, all drivers would implement all functions, but it turns out that in this case we can work around this omission without any bad side effects - since all macvtap passthrough <interface> definitions pointing to a physdev that uses the enic driver *must* have a <virtualport type='802.1Qbh'>, and since no other type of ethernet devices use 802.1Qbh, libvirt can change its behavior in this case to use the old-style. ioctl(SIOC[GS]IFHWADDR). That's what this patch does. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1257004
2015-08-26 04:18:26 +00:00
if (mode == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) {
bool setVlan = true;
util: don't use netlink to save/set mac for macvtap+passthrough+802.1Qbh Before libvirt sets the MAC address of the physdev (the physical ethernet device) linked to a macvtap passthrough device, it always saves the previous MAC address to restore when the guest is finished (following a "leave nothing behind" policy). For a long time it accomplished the save/restore with a combination of ioctl(SIOCGIFHWADDR) and ioctl(SIOCSIFHWADDR), but in commit cbfe38c (first in libvirt 1.2.15) this was changed to use netlink RTM_GETLINK and RTM_SETLINK commands sent to the Physical Function (PF) of any device that was detected to be a Virtual Function (VF). We later found out that this caused problems with any devices using the Cisco enic driver (e.g. vmfex cards) because the enic driver hasn't implemented the function that is called to gather the information in the IFLA_VFINFO_LIST attribute of RTM_GETLINK (ndo_get_vf_config() for those keeping score), so we would never get back a useful response. In an ideal world, all drivers would implement all functions, but it turns out that in this case we can work around this omission without any bad side effects - since all macvtap passthrough <interface> definitions pointing to a physdev that uses the enic driver *must* have a <virtualport type='802.1Qbh'>, and since no other type of ethernet devices use 802.1Qbh, libvirt can change its behavior in this case to use the old-style. ioctl(SIOC[GS]IFHWADDR). That's what this patch does. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1257004
2015-08-26 04:18:26 +00:00
if (virtPortProfile &&
virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_8021QBH) {
/* The Cisco enic driver (the only SRIOV-capable card that
* uses 802.1Qbh) doesn't support IFLA_VFINFO_LIST, which
* is required to get/set the vlan tag of a VF.
util: don't use netlink to save/set mac for macvtap+passthrough+802.1Qbh Before libvirt sets the MAC address of the physdev (the physical ethernet device) linked to a macvtap passthrough device, it always saves the previous MAC address to restore when the guest is finished (following a "leave nothing behind" policy). For a long time it accomplished the save/restore with a combination of ioctl(SIOCGIFHWADDR) and ioctl(SIOCSIFHWADDR), but in commit cbfe38c (first in libvirt 1.2.15) this was changed to use netlink RTM_GETLINK and RTM_SETLINK commands sent to the Physical Function (PF) of any device that was detected to be a Virtual Function (VF). We later found out that this caused problems with any devices using the Cisco enic driver (e.g. vmfex cards) because the enic driver hasn't implemented the function that is called to gather the information in the IFLA_VFINFO_LIST attribute of RTM_GETLINK (ndo_get_vf_config() for those keeping score), so we would never get back a useful response. In an ideal world, all drivers would implement all functions, but it turns out that in this case we can work around this omission without any bad side effects - since all macvtap passthrough <interface> definitions pointing to a physdev that uses the enic driver *must* have a <virtualport type='802.1Qbh'>, and since no other type of ethernet devices use 802.1Qbh, libvirt can change its behavior in this case to use the old-style. ioctl(SIOC[GS]IFHWADDR). That's what this patch does. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1257004
2015-08-26 04:18:26 +00:00
*/
setVlan = false;
util: don't use netlink to save/set mac for macvtap+passthrough+802.1Qbh Before libvirt sets the MAC address of the physdev (the physical ethernet device) linked to a macvtap passthrough device, it always saves the previous MAC address to restore when the guest is finished (following a "leave nothing behind" policy). For a long time it accomplished the save/restore with a combination of ioctl(SIOCGIFHWADDR) and ioctl(SIOCSIFHWADDR), but in commit cbfe38c (first in libvirt 1.2.15) this was changed to use netlink RTM_GETLINK and RTM_SETLINK commands sent to the Physical Function (PF) of any device that was detected to be a Virtual Function (VF). We later found out that this caused problems with any devices using the Cisco enic driver (e.g. vmfex cards) because the enic driver hasn't implemented the function that is called to gather the information in the IFLA_VFINFO_LIST attribute of RTM_GETLINK (ndo_get_vf_config() for those keeping score), so we would never get back a useful response. In an ideal world, all drivers would implement all functions, but it turns out that in this case we can work around this omission without any bad side effects - since all macvtap passthrough <interface> definitions pointing to a physdev that uses the enic driver *must* have a <virtualport type='802.1Qbh'>, and since no other type of ethernet devices use 802.1Qbh, libvirt can change its behavior in this case to use the old-style. ioctl(SIOC[GS]IFHWADDR). That's what this patch does. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1257004
2015-08-26 04:18:26 +00:00
}
if (virNetDevSaveNetConfig(linkdev, -1, stateDir, setVlan) < 0)
return -1;
if (virNetDevSetNetConfig(linkdev, -1, NULL, vlan, macaddress, setVlan) < 0)
return -1;
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
virMutexLock(&virNetDevMacVLanCreateMutex);
2016-01-19 19:20:54 +00:00
if (ifnameRequested) {
int rc;
2016-01-19 19:20:54 +00:00
bool isAutoName
= (STRPREFIX(ifnameRequested, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
STRPREFIX(ifnameRequested, VIR_NET_GENERATED_MACVLAN_PREFIX));
2016-01-19 19:20:54 +00:00
VIR_INFO("Requested macvtap device name: %s", ifnameRequested);
if ((rc = virNetDevExists(ifnameRequested)) < 0) {
2016-01-19 19:20:54 +00:00
virMutexUnlock(&virNetDevMacVLanCreateMutex);
return -1;
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (rc) {
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
/* ifnameRequested is already being used */
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (!isAutoName) {
virReportSystemError(EEXIST,
_("Unable to create device '%s'"),
ifnameRequested);
virMutexUnlock(&virNetDevMacVLanCreateMutex);
return -1;
}
} else {
/* ifnameRequested is available. try to open it */
virNetDevMacVLanReserveNameInternal(ifnameRequested);
if (virNetDevMacVLanCreate(ifnameRequested, type, macaddress,
linkdev, macvtapMode) == 0) {
/* virNetDevMacVLanCreate() was successful - use this name */
ifname = g_strdup(ifnameRequested);
} else if (!isAutoName) {
/* coudn't open ifnameRequested, but it wasn't an
* autogenerated named, so there is nothing else to
* try - fail and return.
*/
virMutexUnlock(&virNetDevMacVLanCreateMutex);
return -1;
2016-01-19 19:20:54 +00:00
}
}
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (!ifname) {
/* ifnameRequested was NULL, or it was an already in use
* autogenerated name, so now we look for an unused
* autogenerated name.
*/
if (virNetDevMacVLanGenerateName(&ifname, flags) < 0 ||
virNetDevMacVLanCreate(ifname, type, macaddress,
linkdev, macvtapMode) < 0) {
2016-01-19 19:20:54 +00:00
virMutexUnlock(&virNetDevMacVLanCreateMutex);
return -1;
}
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
/* all done creating the device */
virMutexUnlock(&virNetDevMacVLanCreateMutex);
2016-01-19 19:20:54 +00:00
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (virNetDevVPortProfileAssociate(ifname,
virtPortProfile,
macaddress,
linkdev,
vf,
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
vmuuid, vmOp, false) < 0) {
goto link_del_exit;
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
}
if (flags & VIR_NETDEV_MACVLAN_CREATE_IFUP) {
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (virNetDevSetOnline(ifname, true) < 0)
goto disassociate_exit;
}
if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) {
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (virNetDevMacVLanTapOpen(ifname, tapfd, tapfdSize) < 0)
goto disassociate_exit;
if (virNetDevMacVLanTapSetup(tapfd, tapfdSize, vnet_hdr) < 0)
goto disassociate_exit;
}
if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_CREATE ||
vmOp == VIR_NETDEV_VPORT_PROFILE_OP_RESTORE) {
/* Only directly register upon a create or restore (restarting
* a saved image) - migration and libvirtd restart are handled
* elsewhere.
*/
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
if (virNetDevMacVLanVPortProfileRegisterCallback(ifname, macaddress,
linkdev, vmuuid,
virtPortProfile,
vmOp) < 0)
goto disassociate_exit;
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
*ifnameResult = g_steal_pointer(&ifname);
return 0;
disassociate_exit:
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
ignore_value(virNetDevVPortProfileDisassociate(ifname,
virtPortProfile,
macaddress,
linkdev,
vf,
vmOp));
while (tapfdSize--)
VIR_FORCE_CLOSE(tapfd[tapfdSize]);
link_del_exit:
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
ignore_value(virNetDevMacVLanDelete(ifname));
return -1;
}
/**
* virNetDevMacVLanDeleteWithVPortProfile:
* @ifname : The name of the macvtap interface
* @linkdev: The interface name of the NIC to connect to the external bridge
* @virtPortProfile: pointer to object holding the virtual port profile data
*
* Delete an interface given its name. Disassociate
* it with the switch if port profile parameters
* were provided.
*/
int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
maint: avoid 'const fooPtr' in virnet files 'const fooPtr' is the same as 'foo * const' (the pointer won't change, but it's contents can). But in general, if an interface is trying to be const-correct, it should be using 'const foo *' (the pointer is to data that can't be changed). Fix up remaining offenders in src/util. * src/util/virnetdev.h (virNetDevSetMAC) (virNetDevReplaceMacAddress, virNetDevValidateConfig) (virNetDevReplaceNetConfig): Use intended type. * src/util/virnetdevbandwidth.h (virNetDevBandwidthCopy) (virNetDevBandwidthPlug): Likewise. * src/util/virnetdevmacvlan.h (virNetDevMacVLanCreate) (virNetDevMacVLanCreateWithVPortProfile) (virNetDevMacVLanDeleteWithVPortProfile) (virNetDevMacVLanRestartWithVPortProfile) (virNetDevMacVLanVPortProfileRegisterCallback): Likewise. * src/util/virnetdevopenvswitch.h (virNetDevOpenvswitchAddPort): Likewise. * src/util/virnetdevtap.h (virNetDevTapCreateInBridgePort): Likewise. * src/util/virnetdevvlan.h (virNetDevVlanEqual) (virNetDevVlanCopy): Likewise. * src/util/virnetdevvportprofile.h (virNetDevVPortProfileAssociate) (virNetDevVPortProfileDisassociate): Likewise. * src/util/virnetlink.h (virNetlinkEventRemoveCallback) (virNetlinkEventAddClient, virNetlinkEventRemoveClient): Likewise. * src/util/virnetdev.c (virNetDevSetMAC) (virNetDevReplaceMacAddress, virNetDevValidateConfig) (virNetDevReplaceNetConfig): Fix fallout. * src/util/virnetdevbandwidth.c (virNetDevBandwidthCopy) (virNetDevBandwidthPlug): Likewise. * src/util/virnetdevmacvlan.c (virNetDevMacVLanCreate) (virNetDevMacVLanCreateWithVPortProfile) (virNetDevMacVLanDeleteWithVPortProfile) (virNetDevMacVLanRestartWithVPortProfile) (virNetDevMacVLanVPortProfileRegisterCallback): Likewise. * src/util/virnetdevopenvswitch.c (virNetDevOpenvswitchAddPort): Likewise. * src/util/virnetdevtap.c (virNetDevTapCreateInBridgePort): Likewise. * src/util/virnetdevvlan.c (virNetDevVlanEqual) (virNetDevVlanCopy): Likewise. * src/util/virnetdevvportprofile.c (virNetDevVPortProfileAssociate) (virNetDevVPortProfileDisassociate) (virNetDevVPortProfileOpSetLink, virNetDevVPortProfileOpCommon) (virNetDevVPortProfileOp8021Qbg, virNetDevVPortProfileOp8021Qbh): Likewise. * src/util/virnetlink.c (virNetlinkEventRemoveCallback) (virNetlinkEventAddClient, virNetlinkEventRemoveClient): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 19:41:44 +00:00
const virMacAddr *macaddr,
const char *linkdev,
int mode,
const virNetDevVPortProfile *virtPortProfile,
char *stateDir)
{
int ret = 0;
if (ifname) {
if (virNetDevVPortProfileDisassociate(ifname,
virtPortProfile,
macaddr,
linkdev,
-1,
VIR_NETDEV_VPORT_PROFILE_OP_DESTROY) < 0)
ret = -1;
if (virNetDevMacVLanDelete(ifname) < 0)
ret = -1;
}
if (mode == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) {
g_autoptr(virMacAddr) MAC = NULL;
g_autoptr(virMacAddr) adminMAC = NULL;
g_autoptr(virNetDevVlan) vlan = NULL;
if ((virNetDevReadNetConfig(linkdev, -1, stateDir,
&adminMAC, &vlan, &MAC) == 0) &&
(adminMAC || vlan || MAC)) {
ignore_value(virNetDevSetNetConfig(linkdev, -1,
adminMAC, vlan, MAC, !!vlan));
}
}
virNetlinkEventRemoveClient(0, macaddr, NETLINK_ROUTE);
return ret;
}
/**
* virNetDevMacVLanRestartWithVPortProfile:
* Register a port profile callback handler for a VM that
* is already running
* .
* @cr_ifname: Interface name that the macvtap has.
* @macaddress: The MAC address for the macvtap device
* @linkdev: The interface name of the NIC to connect to the external bridge
* @vmuuid: The UUID of the VM the macvtap belongs to
* @virtPortProfile: pointer to object holding the virtual port profile data
* @vmOp: Operation to use during setup of the association
*
* Returns 0; returns -1 on error.
*/
int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname,
const virMacAddr *macaddress,
const char *linkdev,
const unsigned char *vmuuid,
const virNetDevVPortProfile *virtPortProfile,
virNetDevVPortProfileOp vmOp)
{
int rc = 0;
rc = virNetDevMacVLanVPortProfileRegisterCallback(cr_ifname, macaddress,
linkdev, vmuuid,
virtPortProfile, vmOp);
if (rc < 0)
return rc;
ignore_value(virNetDevVPortProfileAssociate(cr_ifname,
virtPortProfile,
macaddress,
linkdev,
-1,
vmuuid,
vmOp, true));
return rc;
}
#else /* ! WITH_MACVTAP */
bool virNetDevMacVLanIsMacvtap(const char *ifname G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return false;
}
int virNetDevMacVLanCreate(const char *ifname G_GNUC_UNUSED,
const char *type G_GNUC_UNUSED,
const virMacAddr *macaddress G_GNUC_UNUSED,
const char *srcdev G_GNUC_UNUSED,
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
uint32_t macvlan_mode G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int virNetDevMacVLanDelete(const char *ifname G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int
virNetDevMacVLanTapOpen(const char *ifname G_GNUC_UNUSED,
int *tapfd G_GNUC_UNUSED,
size_t tapfdSize G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int
virNetDevMacVLanTapSetup(int *tapfd G_GNUC_UNUSED,
size_t tapfdSize G_GNUC_UNUSED,
bool vnet_hdr G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int virNetDevMacVLanCreateWithVPortProfile(const char *ifname G_GNUC_UNUSED,
const virMacAddr *macaddress G_GNUC_UNUSED,
const char *linkdev G_GNUC_UNUSED,
virNetDevMacVLanMode mode G_GNUC_UNUSED,
const virNetDevVlan *vlan G_GNUC_UNUSED,
const unsigned char *vmuuid G_GNUC_UNUSED,
const virNetDevVPortProfile *virtPortProfile G_GNUC_UNUSED,
char **res_ifname G_GNUC_UNUSED,
virNetDevVPortProfileOp vmop G_GNUC_UNUSED,
char *stateDir G_GNUC_UNUSED,
int *tapfd G_GNUC_UNUSED,
size_t tapfdSize G_GNUC_UNUSED,
unsigned int unused_flags G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname G_GNUC_UNUSED,
const virMacAddr *macaddress G_GNUC_UNUSED,
const char *linkdev G_GNUC_UNUSED,
int mode G_GNUC_UNUSED,
const virNetDevVPortProfile *virtPortProfile G_GNUC_UNUSED,
char *stateDir G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname G_GNUC_UNUSED,
const virMacAddr *macaddress G_GNUC_UNUSED,
const char *linkdev G_GNUC_UNUSED,
const unsigned char *vmuuid G_GNUC_UNUSED,
const virNetDevVPortProfile *virtPortProfile G_GNUC_UNUSED,
virNetDevVPortProfileOp vmOp G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
int virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname G_GNUC_UNUSED,
const virMacAddr *macaddress G_GNUC_UNUSED,
const char *linkdev G_GNUC_UNUSED,
const unsigned char *vmuuid G_GNUC_UNUSED,
const virNetDevVPortProfile *virtPortProfile G_GNUC_UNUSED,
virNetDevVPortProfileOp vmOp G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
return -1;
}
util: replace macvtap name reservation bitmap with a simple counter 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>
2020-08-23 18:57:19 +00:00
void virNetDevMacVLanReserveName(const char *name G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, "%s",
_("Cannot create macvlan devices on this platform"));
}
#endif /* ! WITH_MACVTAP */