Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/*
|
2016-05-04 17:18:16 +00:00
|
|
|
* Copyright (C) 2007-2016 Red Hat, Inc.
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
2020-12-14 01:50:32 +00:00
|
|
|
#include <math.h>
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
#include "virnetdev.h"
|
2019-04-01 14:28:05 +00:00
|
|
|
#include "viralloc.h"
|
2016-06-13 11:59:12 +00:00
|
|
|
#include "virnetlink.h"
|
2012-01-27 17:23:05 +00:00
|
|
|
#include "virmacaddr.h"
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#include "virfile.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.h"
|
2012-12-13 14:52:25 +00:00
|
|
|
#include "virpci.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
|
|
|
#include "virutil.h"
|
2017-02-20 21:14:53 +00:00
|
|
|
#include "virjson.h"
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2020-01-17 12:17:58 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
#endif
|
2011-11-02 17:40:50 +00:00
|
|
|
#include <fcntl.h>
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2011-11-03 09:27:45 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
# include <linux/sockios.h>
|
|
|
|
# include <linux/if_vlan.h>
|
2017-03-17 21:33:42 +00:00
|
|
|
# define VIR_NETDEV_FAMILY AF_UNIX
|
2020-09-01 11:27:44 +00:00
|
|
|
#elif defined(WITH_STRUCT_IFREQ) && defined(AF_LOCAL)
|
2013-04-27 15:50:19 +00:00
|
|
|
# define VIR_NETDEV_FAMILY AF_LOCAL
|
|
|
|
#else
|
2020-09-01 11:27:44 +00:00
|
|
|
# undef WITH_STRUCT_IFREQ
|
2011-11-03 09:27:45 +00:00
|
|
|
#endif
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCETHTOOL) && defined(WITH_STRUCT_IFREQ)
|
2015-03-10 16:00:15 +00:00
|
|
|
# include <linux/types.h>
|
2015-03-05 11:04:11 +00:00
|
|
|
# include <linux/ethtool.h>
|
|
|
|
#endif
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if WITH_DECL_LINK_ADDR
|
2013-05-03 13:35:20 +00:00
|
|
|
# include <sys/sockio.h>
|
|
|
|
# include <net/if_dl.h>
|
|
|
|
#endif
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if WITH_LINUX_DEVLINK_H
|
2017-08-21 09:19:53 +00:00
|
|
|
# include <linux/devlink.h>
|
|
|
|
#endif
|
|
|
|
|
2014-10-31 18:00:19 +00:00
|
|
|
#ifndef IFNAMSIZ
|
|
|
|
# define IFNAMSIZ 16
|
|
|
|
#endif
|
|
|
|
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.netdev");
|
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
#define PROC_NET_DEV_MCAST "/proc/net/dev_mcast"
|
|
|
|
#define MAX_MCAST_SIZE 50*14336
|
|
|
|
#define VIR_MCAST_NAME_LEN (IFNAMSIZ + 1)
|
|
|
|
#define VIR_MCAST_TOKEN_DELIMS " \n"
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCSIFFLAGS) && defined(WITH_STRUCT_IFREQ)
|
2015-02-03 10:20:40 +00:00
|
|
|
# define VIR_IFF_UP IFF_UP
|
|
|
|
# define VIR_IFF_PROMISC IFF_PROMISC
|
|
|
|
# define VIR_IFF_MULTICAST IFF_MULTICAST
|
|
|
|
# define VIR_IFF_ALLMULTI IFF_ALLMULTI
|
|
|
|
#else
|
|
|
|
# define VIR_IFF_UP 0
|
|
|
|
# define VIR_IFF_PROMISC 0
|
|
|
|
# define VIR_IFF_MULTICAST 0
|
|
|
|
# define VIR_IFF_ALLMULTI 0
|
|
|
|
#endif
|
|
|
|
|
2015-07-19 10:11:07 +00:00
|
|
|
#define RESOURCE_FILE_LEN 4096
|
2020-09-01 11:27:44 +00:00
|
|
|
#if WITH_DECL_ETHTOOL_GFEATURES
|
2015-07-19 10:11:07 +00:00
|
|
|
# define TX_UDP_TNL 25
|
|
|
|
# define GFEATURES_SIZE 2
|
|
|
|
# define FEATURE_WORD(blocks, index, field) ((blocks)[(index) / 32U].field)
|
|
|
|
# define FEATURE_FIELD_FLAG(index) (1U << (index) % 32U)
|
2017-11-03 12:09:47 +00:00
|
|
|
# define FEATURE_BIT_IS_SET(blocks, index, field) \
|
2015-07-19 10:11:07 +00:00
|
|
|
(FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
|
|
|
|
#endif
|
|
|
|
|
2020-12-14 01:50:32 +00:00
|
|
|
|
|
|
|
static virNetDevGenName
|
|
|
|
virNetDevGenNames[VIR_NET_DEV_GEN_NAME_LAST] = {
|
|
|
|
{-1, VIR_NET_GENERATED_VNET_PREFIX, VIR_MUTEX_INITIALIZER},
|
|
|
|
{-1, VIR_NET_GENERATED_MACVTAP_PREFIX, VIR_MUTEX_INITIALIZER},
|
|
|
|
{-1, VIR_NET_GENERATED_MACVLAN_PREFIX, VIR_MUTEX_INITIALIZER},
|
|
|
|
};
|
|
|
|
|
2014-10-29 20:57:58 +00:00
|
|
|
typedef enum {
|
|
|
|
VIR_MCAST_TYPE_INDEX_TOKEN,
|
|
|
|
VIR_MCAST_TYPE_NAME_TOKEN,
|
|
|
|
VIR_MCAST_TYPE_USERS_TOKEN,
|
|
|
|
VIR_MCAST_TYPE_GLOBAL_TOKEN,
|
|
|
|
VIR_MCAST_TYPE_ADDR_TOKEN,
|
|
|
|
|
|
|
|
VIR_MCAST_TYPE_LAST
|
|
|
|
} virMCastType;
|
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
typedef struct _virNetDevMcastEntry virNetDevMcastEntry;
|
|
|
|
struct _virNetDevMcastEntry {
|
2015-04-14 11:34:24 +00:00
|
|
|
int idx;
|
2014-10-10 17:55:42 +00:00
|
|
|
char name[VIR_MCAST_NAME_LEN];
|
|
|
|
int users;
|
|
|
|
bool global;
|
|
|
|
virMacAddr macaddr;
|
|
|
|
};
|
|
|
|
|
2018-07-28 18:01:20 +00:00
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevMcastEntryFree(virNetDevMcastEntry *entry)
|
2018-07-28 18:01:20 +00:00
|
|
|
{
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(entry);
|
2018-07-28 18:01:20 +00:00
|
|
|
}
|
|
|
|
|
2019-10-15 12:47:50 +00:00
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetDevMcastEntry, virNetDevMcastEntryFree);
|
2018-07-28 18:01:20 +00:00
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
typedef struct _virNetDevMcastList virNetDevMcastList;
|
|
|
|
struct _virNetDevMcastList {
|
|
|
|
size_t nentries;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevMcastEntry **entries;
|
2014-10-10 17:55:42 +00:00
|
|
|
};
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(WITH_STRUCT_IFREQ)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
static int virNetDevSetupControlFull(const char *ifname,
|
|
|
|
struct ifreq *ifr,
|
|
|
|
int domain,
|
|
|
|
int type)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2013-06-21 16:57:12 +00:00
|
|
|
if (ifr && ifname) {
|
|
|
|
memset(ifr, 0, sizeof(*ifr));
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(ifr->ifr_name, ifname) < 0) {
|
2013-06-21 16:57:12 +00:00
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("Network interface name '%s' is too long"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = socket(domain, type, 0)) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot open network interface control socket"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virSetInherit(fd, false) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot set close-on-exec flag for socket"));
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-13 06:26:20 +00:00
|
|
|
int
|
|
|
|
virNetDevSetupControl(const char *ifname,
|
|
|
|
struct ifreq *ifr)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
2013-04-27 15:50:19 +00:00
|
|
|
return virNetDevSetupControlFull(ifname, ifr, VIR_NETDEV_FAMILY, SOCK_DGRAM);
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
2020-09-01 11:27:44 +00:00
|
|
|
#else /* !WITH_STRUCT_IFREQ */
|
2013-06-13 06:26:20 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevSetupControl(const char *ifname G_GNUC_UNUSED,
|
|
|
|
void *ifr G_GNUC_UNUSED)
|
2013-06-13 06:26:20 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Network device configuration is not supported "
|
|
|
|
"on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2020-09-01 11:27:44 +00:00
|
|
|
#endif /* WITH_STRUCT_IFREQ */
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFFLAGS) && defined(WITH_STRUCT_IFREQ)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/**
|
|
|
|
* virNetDevExists:
|
|
|
|
* @ifname
|
|
|
|
*
|
|
|
|
* Check if the network device @ifname exists
|
|
|
|
*
|
|
|
|
* Returns 1 if it exists, 0 if it does not, -1 on error
|
|
|
|
*/
|
|
|
|
int virNetDevExists(const char *ifname)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
|
2013-05-03 13:35:20 +00:00
|
|
|
if (errno == ENODEV || errno == ENXIO)
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
virReportSystemError(errno, _("Unable to check interface flags for %s"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevExists(const char *ifname)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Unable to check interface %s"), ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-04-30 19:42:59 +00:00
|
|
|
#if defined(SIOCGIFHWADDR) && defined(SIOCSIFHWADDR) && \
|
2020-09-01 11:27:44 +00:00
|
|
|
defined(WITH_STRUCT_IFREQ)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/**
|
2017-03-09 19:04:16 +00:00
|
|
|
* virNetDevSetMACInternal:
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
* @ifname: interface name to set MTU for
|
2012-07-17 12:07:59 +00:00
|
|
|
* @macaddr: MAC address
|
2017-04-17 14:50:48 +00:00
|
|
|
* @quiet: true if a failure to set MAC address with
|
|
|
|
* errno == EADDRNOTAVAIL || errno == EPERM
|
2017-03-09 19:04:16 +00:00
|
|
|
* should be silent (still returns error, but without log)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*
|
2017-03-09 19:04:16 +00:00
|
|
|
* This function sets the @macaddr for a given interface @ifname.
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
2017-03-09 19:04:16 +00:00
|
|
|
static int
|
|
|
|
virNetDevSetMACInternal(const char *ifname,
|
|
|
|
const virMacAddr *macaddr,
|
|
|
|
bool quiet)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2017-03-11 15:29:29 +00:00
|
|
|
char macstr[VIR_MAC_STRING_BUFLEN];
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* To fill ifr.ifr_hdaddr.sa_family field */
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
2018-09-12 09:46:38 +00:00
|
|
|
virReportSystemError(errno, _("Cannot get interface MAC on '%s'"),
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("SIOCSIFHWADDR %s get MAC - Fail", ifname);
|
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data);
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) {
|
2015-12-18 17:08:54 +00:00
|
|
|
|
2017-04-17 14:50:48 +00:00
|
|
|
if (quiet &&
|
2018-09-12 09:46:38 +00:00
|
|
|
(errno == EADDRNOTAVAIL || errno == EPERM)) {
|
|
|
|
VIR_DEBUG("SIOCSIFHWADDR %s MAC=%s - Fail",
|
|
|
|
ifname, virMacAddrFormat(macaddr, macstr));
|
|
|
|
return -1;
|
|
|
|
}
|
2017-03-09 19:04:16 +00:00
|
|
|
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
virReportSystemError(errno,
|
2015-12-18 17:08:54 +00:00
|
|
|
_("Cannot set interface MAC to %s on '%s'"),
|
|
|
|
virMacAddrFormat(macaddr, macstr), ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_DEBUG("SIOCSIFHWADDR %s MAC=%s - Success",
|
|
|
|
ifname, virMacAddrFormat(macaddr, macstr));
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
2017-03-09 19:04:16 +00:00
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#elif defined(SIOCSIFLLADDR) && defined(WITH_STRUCT_IFREQ) && \
|
|
|
|
WITH_DECL_LINK_ADDR
|
2017-03-09 19:04:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevSetMACInternal(const char *ifname,
|
|
|
|
const virMacAddr *macaddr,
|
|
|
|
bool quiet)
|
2013-05-03 13:35:20 +00:00
|
|
|
{
|
2018-09-13 08:55:20 +00:00
|
|
|
struct ifreq ifr;
|
|
|
|
struct sockaddr_dl sdl;
|
|
|
|
char mac[VIR_MAC_STRING_BUFLEN + 1] = ":";
|
|
|
|
VIR_AUTOCLOSE s = -1;
|
2013-05-03 13:35:20 +00:00
|
|
|
|
2018-09-13 08:55:20 +00:00
|
|
|
if ((s = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
2013-05-03 13:35:20 +00:00
|
|
|
|
2018-09-13 08:55:20 +00:00
|
|
|
virMacAddrFormat(macaddr, mac + 1);
|
|
|
|
sdl.sdl_len = sizeof(sdl);
|
|
|
|
link_addr(mac, &sdl);
|
2013-05-03 13:35:20 +00:00
|
|
|
|
2018-09-13 08:55:20 +00:00
|
|
|
memcpy(ifr.ifr_addr.sa_data, sdl.sdl_data, VIR_MAC_BUFLEN);
|
|
|
|
ifr.ifr_addr.sa_len = VIR_MAC_BUFLEN;
|
2017-03-09 19:04:16 +00:00
|
|
|
|
2018-09-13 08:55:20 +00:00
|
|
|
if (ioctl(s, SIOCSIFLLADDR, &ifr) < 0) {
|
|
|
|
if (quiet &&
|
|
|
|
(errno == EADDRNOTAVAIL || errno == EPERM)) {
|
|
|
|
VIR_DEBUG("SIOCSIFLLADDR %s MAC=%s - Fail", ifname, mac + 1);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2013-05-03 13:35:20 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 08:55:20 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set interface MAC to %s on '%s'"),
|
|
|
|
mac + 1, ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("SIOCSIFLLADDR %s MAC=%s - Success", ifname, mac + 1);
|
|
|
|
return 0;
|
2013-05-03 13:35:20 +00:00
|
|
|
}
|
2017-03-09 19:04:16 +00:00
|
|
|
|
|
|
|
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#else
|
2017-03-09 19:04:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevSetMACInternal(const char *ifname,
|
2019-10-14 12:45:33 +00:00
|
|
|
const virMacAddr *macaddr G_GNUC_UNUSED,
|
|
|
|
bool quiet G_GNUC_UNUSED)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot set interface MAC on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-03-09 19:04:16 +00:00
|
|
|
|
|
|
|
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2017-03-09 19:04:16 +00:00
|
|
|
int
|
|
|
|
virNetDevSetMAC(const char *ifname,
|
|
|
|
const virMacAddr *macaddr)
|
|
|
|
{
|
|
|
|
return virNetDevSetMACInternal(ifname, macaddr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFHWADDR) && defined(WITH_STRUCT_IFREQ)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetMAC:
|
|
|
|
* @ifname: interface name to set MTU for
|
2012-07-17 12:07:59 +00:00
|
|
|
* @macaddr: MAC address
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*
|
|
|
|
* This function gets the @macaddr for a given interface @ifname.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevGetMAC(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr *macaddr)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface MAC on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrSetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data);
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevGetMAC(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr *macaddr G_GNUC_UNUSED)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot get interface MAC on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFMTU) && defined(WITH_STRUCT_IFREQ)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetMTU:
|
|
|
|
* @ifname: interface name get MTU for
|
|
|
|
*
|
|
|
|
* This function gets the @mtu value set for a given interface @ifname.
|
|
|
|
*
|
|
|
|
* Returns the MTU value in case of success, or -1 on failure.
|
|
|
|
*/
|
|
|
|
int virNetDevGetMTU(const char *ifname)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface MTU on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return ifr.ifr_mtu;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevGetMTU(const char *ifname)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot get interface MTU on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCSIFMTU) && defined(WITH_STRUCT_IFREQ)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/**
|
|
|
|
* virNetDevSetMTU:
|
|
|
|
* @ifname: interface name to set MTU for
|
|
|
|
* @mtu: MTU value
|
|
|
|
*
|
|
|
|
* This function sets the @mtu for a given interface @ifname. Typically
|
|
|
|
* used on a tap device to set up for Jumbo Frames.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevSetMTU(const char *ifname, int mtu)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ifr.ifr_mtu = mtu;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set interface MTU on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevSetMTU(const char *ifname, int mtu G_GNUC_UNUSED)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot set interface MTU on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSetMTUFromDevice:
|
|
|
|
* @ifname: name of the interface whose MTU we want to set
|
|
|
|
* @otherifname: name of the interface whose MTU we want to copy
|
|
|
|
*
|
|
|
|
* Sets the interface mtu to the same MTU as another interface
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevSetMTUFromDevice(const char *ifname,
|
|
|
|
const char *otherifname)
|
|
|
|
{
|
|
|
|
int mtu = virNetDevGetMTU(otherifname);
|
|
|
|
|
|
|
|
if (mtu < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virNetDevSetMTU(ifname, mtu);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-02 16:03:09 +00:00
|
|
|
/**
|
|
|
|
* virNetDevSetNamespace:
|
|
|
|
* @ifname: name of device
|
|
|
|
* @pidInNs: PID of process in target net namespace
|
|
|
|
*
|
|
|
|
* Moves the given device into the target net namespace specified by the given
|
|
|
|
* pid using this command:
|
|
|
|
* ip link set @iface netns @pidInNs
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
build: use correct type for pid and similar types
No thanks to 64-bit windows, with 64-bit pid_t, we have to avoid
constructs like 'int pid'. Our API in libvirt-qemu cannot be
changed without breaking ABI; but then again, libvirt-qemu can
only be used on systems that support UNIX sockets, which rules
out Windows (even if qemu could be compiled there) - so for all
points on the call chain that interact with this API decision,
we require a different variable name to make it clear that we
audited the use for safety.
Adding a syntax-check rule only solves half the battle; anywhere
that uses printf on a pid_t still needs to be converted, but that
will be a separate patch.
* cfg.mk (sc_correct_id_types): New syntax check.
* src/libvirt-qemu.c (virDomainQemuAttach): Document why we didn't
use pid_t for pid, and validate for overflow.
* include/libvirt/libvirt-qemu.h (virDomainQemuAttach): Tweak name
for syntax check.
* src/vmware/vmware_conf.c (vmwareExtractPid): Likewise.
* src/driver.h (virDrvDomainQemuAttach): Likewise.
* tools/virsh.c (cmdQemuAttach): Likewise.
* src/remote/qemu_protocol.x (qemu_domain_attach_args): Likewise.
* src/qemu_protocol-structs (qemu_domain_attach_args): Likewise.
* src/util/cgroup.c (virCgroupPidCode, virCgroupKillInternal):
Likewise.
* src/qemu/qemu_command.c(qemuParseProcFileStrings): Likewise.
(qemuParseCommandLinePid): Use pid_t for pid.
* daemon/libvirtd.c (daemonForkIntoBackground): Likewise.
* src/conf/domain_conf.h (_virDomainObj): Likewise.
* src/probes.d (rpc_socket_new): Likewise.
* src/qemu/qemu_command.h (qemuParseCommandLinePid): Likewise.
* src/qemu/qemu_driver.c (qemudGetProcessInfo, qemuDomainAttach):
Likewise.
* src/qemu/qemu_process.c (qemuProcessAttach): Likewise.
* src/qemu/qemu_process.h (qemuProcessAttach): Likewise.
* src/uml/uml_driver.c (umlGetProcessInfo): Likewise.
* src/util/virnetdev.h (virNetDevSetNamespace): Likewise.
* src/util/virnetdev.c (virNetDevSetNamespace): Likewise.
* tests/testutils.c (virtTestCaptureProgramOutput): Likewise.
* src/conf/storage_conf.h (_virStoragePerms): Use mode_t, uid_t,
and gid_t rather than int.
* src/security/security_dac.c (virSecurityDACSetOwnership): Likewise.
* src/conf/storage_conf.c (virStorageDefParsePerms): Avoid
compiler warning.
2012-02-10 23:08:11 +00:00
|
|
|
int virNetDevSetNamespace(const char *ifname, pid_t pidInNs)
|
2011-11-02 16:03:09 +00:00
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pid = NULL;
|
|
|
|
g_autofree char *phy = NULL;
|
|
|
|
g_autofree char *phy_path = NULL;
|
2020-04-22 14:25:24 +00:00
|
|
|
g_autoptr(virCommand) cmd = NULL;
|
2015-04-14 16:21:44 +00:00
|
|
|
int len;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
pid = g_strdup_printf("%lld", (long long) pidInNs);
|
2011-11-02 16:03:09 +00:00
|
|
|
|
2015-04-14 16:21:44 +00:00
|
|
|
/* The 802.11 wireless devices only move together with their PHY. */
|
|
|
|
if (virNetDevSysfsFile(&phy_path, ifname, "phy80211/name") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2015-04-14 16:21:44 +00:00
|
|
|
|
2015-06-01 18:40:23 +00:00
|
|
|
if ((len = virFileReadAllQuiet(phy_path, 1024, &phy)) <= 0) {
|
|
|
|
/* Not a wireless device. */
|
2020-04-22 14:25:24 +00:00
|
|
|
cmd = virCommandNewArgList("ip", "link",
|
|
|
|
"set", ifname, "netns", pid, NULL);
|
2015-06-01 18:40:23 +00:00
|
|
|
} else {
|
|
|
|
/* Remove a line break. */
|
|
|
|
phy[len - 1] = '\0';
|
|
|
|
|
2020-04-22 14:25:24 +00:00
|
|
|
cmd = virCommandNewArgList("iw", "phy", phy,
|
|
|
|
"set", "netns", pid, NULL);
|
2015-06-01 18:40:23 +00:00
|
|
|
}
|
2015-04-14 16:21:44 +00:00
|
|
|
|
2020-04-22 14:25:24 +00:00
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2011-11-02 16:03:09 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCSIFNAME) && defined(WITH_STRUCT_IFREQ)
|
2011-11-02 16:03:09 +00:00
|
|
|
/**
|
|
|
|
* virNetDevSetName:
|
|
|
|
* @ifname: name of device
|
|
|
|
* @newifname: new name of @ifname
|
|
|
|
*
|
|
|
|
* Changes the name of the given device.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on error
|
|
|
|
*/
|
|
|
|
int virNetDevSetName(const char* ifname, const char *newifname)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2011-11-02 16:03:09 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
# ifdef WITH_STRUCT_IFREQ_IFR_NEWNAME
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_newname, newifname) < 0) {
|
2011-11-02 16:03:09 +00:00
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("Network interface name '%s' is too long"),
|
|
|
|
newifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-02 16:03:09 +00:00
|
|
|
}
|
2013-04-27 15:50:19 +00:00
|
|
|
# else
|
|
|
|
ifr.ifr_data = (caddr_t)newifname;
|
|
|
|
# endif
|
2011-11-02 16:03:09 +00:00
|
|
|
|
|
|
|
if (ioctl(fd, SIOCSIFNAME, &ifr)) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to rename '%s' to '%s'"),
|
|
|
|
ifname, newifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-02 16:03:09 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2011-11-02 16:03:09 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevSetName(const char* ifname, const char *newifname)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot rename interface '%s' to '%s' on this platform"),
|
|
|
|
ifname, newifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCSIFFLAGS) && defined(WITH_STRUCT_IFREQ)
|
2015-01-30 16:56:15 +00:00
|
|
|
static int
|
|
|
|
virNetDevSetIFFlag(const char *ifname, int flag, bool val)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
int ifflags;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface flags on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 19:47:02 +00:00
|
|
|
if (val)
|
|
|
|
ifflags = ifr.ifr_flags | flag;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
else
|
2015-01-22 19:47:02 +00:00
|
|
|
ifflags = ifr.ifr_flags & ~flag;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if (ifr.ifr_flags != ifflags) {
|
|
|
|
ifr.ifr_flags = ifflags;
|
|
|
|
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set interface flags on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
2015-01-30 16:56:15 +00:00
|
|
|
static int
|
|
|
|
virNetDevSetIFFlag(const char *ifname,
|
2019-10-14 12:45:33 +00:00
|
|
|
int flag G_GNUC_UNUSED,
|
|
|
|
bool val G_GNUC_UNUSED)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot set interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2015-01-22 19:47:02 +00:00
|
|
|
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
/**
|
2015-01-22 19:47:02 +00:00
|
|
|
* virNetDevSetOnline:
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
* @ifname: the interface name
|
2015-01-22 19:47:02 +00:00
|
|
|
* @online: true for up, false for down
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*
|
2015-01-22 19:47:02 +00:00
|
|
|
* Function to control if an interface is activated (up, true) or not (down, false)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*
|
2015-01-22 19:47:02 +00:00
|
|
|
* Returns 0 in case of success or -1 on error.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevSetOnline(const char *ifname,
|
|
|
|
bool online)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevSetIFFlag(ifname, VIR_IFF_UP, online);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSetPromiscuous:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @promiscuous: true for receive all packets, false for do not receive
|
|
|
|
* all packets
|
|
|
|
*
|
|
|
|
* Function to control if an interface is to receive all
|
|
|
|
* packets (receive all, true) or not (do not receive all, false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on error.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevSetPromiscuous(const char *ifname,
|
|
|
|
bool promiscuous)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevSetIFFlag(ifname, VIR_IFF_PROMISC, promiscuous);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSetRcvMulti:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @:receive true for receive multicast packets, false for do not receive
|
|
|
|
* multicast packets
|
|
|
|
*
|
|
|
|
* Function to control if an interface is to receive multicast
|
|
|
|
* packets in which it is interested (receive, true)
|
|
|
|
* or not (do not receive, false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on error.
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevSetRcvMulti(const char *ifname,
|
|
|
|
bool receive)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevSetIFFlag(ifname, VIR_IFF_MULTICAST, receive);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSetRcvAllMulti:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @:receive true for receive all packets, false for do not receive all packets
|
|
|
|
*
|
|
|
|
* Function to control if an interface is to receive all multicast
|
|
|
|
* packets (receive, true) or not (do not receive, false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on error.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevSetRcvAllMulti(const char *ifname,
|
|
|
|
bool receive)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevSetIFFlag(ifname, VIR_IFF_ALLMULTI, receive);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFFLAGS) && defined(WITH_STRUCT_IFREQ)
|
2015-01-30 16:56:15 +00:00
|
|
|
static int
|
|
|
|
virNetDevGetIFFlag(const char *ifname, int flag, bool *val)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface flags on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 19:47:02 +00:00
|
|
|
*val = (ifr.ifr_flags & flag) ? true : false;
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
2015-01-30 16:56:15 +00:00
|
|
|
static int
|
|
|
|
virNetDevGetIFFlag(const char *ifname,
|
2019-10-14 12:45:33 +00:00
|
|
|
int flag G_GNUC_UNUSED,
|
|
|
|
bool *val G_GNUC_UNUSED)
|
Split bridge.h into three separate files
Following the renaming of the bridge management APIs, we can now
split the source file into 3 corresponding pieces
* src/util/virnetdev.c: APIs for any type of network interface
* src/util/virnetdevbridge.c: APIs for bridge interfaces
* src/util/virnetdevtap.c: APIs for TAP interfaces
* src/util/virnetdev.c, src/util/virnetdev.h,
src/util/virnetdevbridge.c, src/util/virnetdevbridge.h,
src/util/virnetdevtap.c, src/util/virnetdevtap.h: Copied
from bridge.{c,h}
* src/util/bridge.c, src/util/bridge.h: Split into 3 pieces
* src/lxc/lxc_driver.c, src/network/bridge_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_command.c,
src/qemu/qemu_conf.h, src/uml/uml_conf.c, src/uml/uml_conf.h,
src/uml/uml_driver.c: Update #include directives
2011-11-02 13:41:58 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot get interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2015-01-22 19:47:02 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetOnline:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @online: where to store the status
|
|
|
|
*
|
|
|
|
* Function to query if an interface is activated (true) or not (false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevGetOnline(const char *ifname,
|
|
|
|
bool *online)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevGetIFFlag(ifname, VIR_IFF_UP, online);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevIsPromiscuous:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @promiscuous: where to store the status
|
|
|
|
*
|
|
|
|
* Function to query if an interface is receiving all packets (true) or
|
|
|
|
* not (false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevGetPromiscuous(const char *ifname,
|
|
|
|
bool *promiscuous)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevGetIFFlag(ifname, VIR_IFF_PROMISC, promiscuous);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevIsRcvMulti:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @receive where to store the status
|
|
|
|
*
|
|
|
|
* Function to query whether an interface is receiving multicast packets (true)
|
|
|
|
* in which it is interested, or not (false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on error.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevGetRcvMulti(const char *ifname,
|
|
|
|
bool *receive)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevGetIFFlag(ifname, VIR_IFF_MULTICAST, receive);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevIsRcvAllMulti:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @:receive where to store the status
|
|
|
|
*
|
|
|
|
* Function to query whether an interface is receiving all multicast
|
|
|
|
* packets (receiving, true) or not (is not receiving, false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on error.
|
|
|
|
*/
|
2015-02-03 10:20:40 +00:00
|
|
|
int
|
|
|
|
virNetDevGetRcvAllMulti(const char *ifname,
|
|
|
|
bool *receive)
|
2015-01-22 19:47:02 +00:00
|
|
|
{
|
2015-02-03 10:20:40 +00:00
|
|
|
return virNetDevGetIFFlag(ifname, VIR_IFF_ALLMULTI, receive);
|
2015-01-22 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(WITH_IF_INDEXTONAME)
|
2017-03-15 13:46:56 +00:00
|
|
|
char *virNetDevGetName(int ifindex)
|
|
|
|
{
|
|
|
|
char name[IFNAMSIZ];
|
|
|
|
|
|
|
|
memset(&name, 0, sizeof(name));
|
|
|
|
|
|
|
|
if (!if_indextoname(ifindex, name)) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to convert interface index %d to a name"),
|
|
|
|
ifindex);
|
2020-01-06 21:57:45 +00:00
|
|
|
return NULL;
|
2017-03-15 13:46:56 +00:00
|
|
|
}
|
|
|
|
|
2020-01-06 21:57:45 +00:00
|
|
|
return g_strdup(name);
|
2017-03-15 13:46:56 +00:00
|
|
|
}
|
2017-03-27 19:49:06 +00:00
|
|
|
#else
|
|
|
|
char *virNetDevGetName(int ifindex)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot get interface name for index '%i'"),
|
|
|
|
ifindex);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2015-01-22 19:47:02 +00:00
|
|
|
|
2011-11-03 09:27:45 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetIndex:
|
|
|
|
* @ifname : Name of the interface whose index is to be found
|
|
|
|
* @ifindex: Pointer to int where the index will be written into
|
|
|
|
*
|
|
|
|
* Get the index of an interface given its name.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*/
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFINDEX) && defined(WITH_STRUCT_IFREQ)
|
2011-11-03 09:27:45 +00:00
|
|
|
int virNetDevGetIndex(const char *ifname, int *ifindex)
|
|
|
|
{
|
|
|
|
struct ifreq ifreq;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = socket(VIR_NETDEV_FAMILY, SOCK_DGRAM, 0);
|
2011-11-03 09:27:45 +00:00
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to open control socket"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&ifreq, 0, sizeof(ifreq));
|
|
|
|
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(ifreq.ifr_name, ifname) < 0) {
|
2011-11-03 09:27:45 +00:00
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("invalid interface name %s"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-03 09:27:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFINDEX, &ifreq) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to get index for interface %s"), ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-03 09:27:45 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
# ifdef WITH_STRUCT_IFREQ_IFR_INDEX
|
2013-04-27 15:50:19 +00:00
|
|
|
*ifindex = ifreq.ifr_index;
|
|
|
|
# else
|
2011-11-03 09:27:45 +00:00
|
|
|
*ifindex = ifreq.ifr_ifindex;
|
2013-04-27 15:50:19 +00:00
|
|
|
# endif
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2011-11-03 09:27:45 +00:00
|
|
|
}
|
2011-12-01 13:31:18 +00:00
|
|
|
#else /* ! SIOCGIFINDEX */
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevGetIndex(const char *ifname G_GNUC_UNUSED,
|
|
|
|
int *ifindex G_GNUC_UNUSED)
|
2011-11-03 09:27:45 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get interface index on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2011-12-01 13:31:18 +00:00
|
|
|
#endif /* ! SIOCGIFINDEX */
|
2011-11-03 09:27:45 +00:00
|
|
|
|
|
|
|
|
2020-09-28 21:29:41 +00:00
|
|
|
#if defined(WITH_LIBNL)
|
2017-03-18 00:57:18 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetMaster:
|
|
|
|
* @ifname: name of interface we're interested in
|
|
|
|
* @master: used to return a string containing the name of @ifname's "master"
|
|
|
|
* (this is the bridge or bond device that this device is attached to)
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure (if @ifname has no master
|
|
|
|
* @master will be NULL, but return value will still be 0 (success)).
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetMaster(const char *ifname, char **master)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree void *nlData = NULL;
|
2017-03-18 00:57:18 +00:00
|
|
|
struct nlattr *tb[IFLA_MAX + 1] = {NULL, };
|
|
|
|
|
|
|
|
*master = NULL;
|
|
|
|
|
|
|
|
if (virNetlinkDumpLink(ifname, -1, &nlData, tb, 0, 0) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-03-18 00:57:18 +00:00
|
|
|
|
|
|
|
if (tb[IFLA_MASTER]) {
|
|
|
|
if (!(*master = virNetDevGetName(*(int *)RTA_DATA(tb[IFLA_MASTER]))))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-03-18 00:57:18 +00:00
|
|
|
}
|
|
|
|
|
2018-07-01 23:27:17 +00:00
|
|
|
VIR_DEBUG("IFLA_MASTER for %s is %s", ifname, *master ? *master : "(none)");
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2017-03-18 00:57:18 +00:00
|
|
|
}
|
|
|
|
|
2020-09-30 21:56:00 +00:00
|
|
|
#elif defined(__linux__)
|
2017-03-18 00:57:18 +00:00
|
|
|
|
2020-09-30 21:56:00 +00:00
|
|
|
/* libnl isn't available, so we can't use netlink.
|
|
|
|
* Fall back to using sysfs
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetMaster(const char *ifname, char **master)
|
|
|
|
{
|
|
|
|
g_autofree char *path = NULL;
|
|
|
|
g_autofree char *canonical = NULL;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&path, ifname, "master") < 0)
|
|
|
|
return -1;
|
2017-03-18 00:57:18 +00:00
|
|
|
|
2020-09-30 21:56:00 +00:00
|
|
|
if (!(canonical = virFileCanonicalizePath(path)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*master = g_path_get_basename(canonical);
|
|
|
|
|
|
|
|
VIR_DEBUG("IFLA_MASTER for %s is %s", ifname, *master ? *master : "(none)");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2017-03-18 00:57:18 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetMaster(const char *ifname G_GNUC_UNUSED,
|
|
|
|
char **master G_GNUC_UNUSED)
|
2017-03-18 00:57:18 +00:00
|
|
|
{
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to get device master from netlink on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-28 21:29:41 +00:00
|
|
|
#endif /* defined(WITH_LIBNL) */
|
2017-03-18 00:57:18 +00:00
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFVLAN) && defined(WITH_STRUCT_IFREQ) && WITH_DECL_GET_VLAN_VID_CMD
|
2011-11-03 09:27:45 +00:00
|
|
|
int virNetDevGetVLanID(const char *ifname, int *vlanid)
|
|
|
|
{
|
|
|
|
struct vlan_ioctl_args vlanargs = {
|
|
|
|
.cmd = GET_VLAN_VID_CMD,
|
|
|
|
};
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = socket(PF_PACKET, SOCK_DGRAM, 0);
|
2011-11-03 09:27:45 +00:00
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to open control socket"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(vlanargs.device1, ifname) < 0) {
|
2011-11-03 09:27:45 +00:00
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("invalid interface name %s"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-03 09:27:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFVLAN, &vlanargs) != 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to get VLAN for interface %s"), ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-03 09:27:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*vlanid = vlanargs.u.VID;
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2011-11-03 09:27:45 +00:00
|
|
|
}
|
2011-12-01 13:31:18 +00:00
|
|
|
#else /* ! SIOCGIFVLAN */
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevGetVLanID(const char *ifname G_GNUC_UNUSED,
|
|
|
|
int *vlanid G_GNUC_UNUSED)
|
2011-11-03 09:27:45 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get VLAN on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2011-12-01 13:31:18 +00:00
|
|
|
#endif /* ! SIOCGIFVLAN */
|
2011-11-03 09:27:45 +00:00
|
|
|
|
|
|
|
|
2011-11-03 12:32:38 +00:00
|
|
|
/**
|
|
|
|
* virNetDevValidateConfig:
|
|
|
|
* @ifname: Name of the interface
|
|
|
|
* @macaddr: expected MAC address of the interface; not checked if NULL
|
|
|
|
* @ifindex: expected index of the interface; not checked if '-1'
|
|
|
|
*
|
|
|
|
* Determine whether a given interface is still available. If so,
|
|
|
|
* it must have the given MAC address and if an interface index is
|
|
|
|
* passed, it must also match the interface index.
|
|
|
|
*
|
|
|
|
* Returns 1 if the config matches, 0 if the config does not match, or interface does not exist, -1 on error
|
|
|
|
*/
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCGIFHWADDR) && defined(WITH_STRUCT_IFREQ)
|
2011-11-03 12:32:38 +00:00
|
|
|
int virNetDevValidateConfig(const char *ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr, int ifindex)
|
2011-11-03 12:32:38 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
int idx;
|
|
|
|
int rc;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2011-11-03 12:32:38 +00:00
|
|
|
|
|
|
|
if ((rc = virNetDevExists(ifname)) < 0)
|
|
|
|
return -1;
|
2018-09-12 09:46:38 +00:00
|
|
|
if (rc == 0)
|
|
|
|
return 0;
|
2011-11-03 12:32:38 +00:00
|
|
|
|
|
|
|
if (macaddr != NULL) {
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
2018-09-12 09:46:38 +00:00
|
|
|
if (errno == ENODEV)
|
|
|
|
return 0;
|
|
|
|
|
2011-11-03 12:32:38 +00:00
|
|
|
virReportSystemError(errno,
|
2011-12-30 14:22:43 +00:00
|
|
|
_("could not get MAC address of interface %s"),
|
2011-11-03 12:32:38 +00:00
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2011-11-03 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
if (virMacAddrCmpRaw(macaddr,
|
2018-09-12 09:46:38 +00:00
|
|
|
(unsigned char *)ifr.ifr_hwaddr.sa_data) != 0)
|
|
|
|
return 0;
|
2011-11-03 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ifindex != -1) {
|
|
|
|
if (virNetDevGetIndex(ifname, &idx) < 0)
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
|
|
|
if (idx != ifindex)
|
|
|
|
return 0;
|
2011-11-03 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 1;
|
2011-11-03 12:32:38 +00:00
|
|
|
}
|
2013-04-27 15:50:19 +00:00
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevValidateConfig(const char *ifname G_GNUC_UNUSED,
|
|
|
|
const virMacAddr *macaddr G_GNUC_UNUSED,
|
|
|
|
int ifindex G_GNUC_UNUSED)
|
2011-11-03 12:32:38 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to check interface config on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-04-27 15:50:19 +00:00
|
|
|
#endif
|
2011-11-03 12:40:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
2014-06-11 13:05:00 +00:00
|
|
|
int
|
2011-11-03 12:40:33 +00:00
|
|
|
virNetDevSysfsFile(char **pf_sysfs_device_link, const char *ifname,
|
2014-06-11 13:05:00 +00:00
|
|
|
const char *file)
|
2011-11-03 12:40:33 +00:00
|
|
|
{
|
2019-10-22 13:26:14 +00:00
|
|
|
*pf_sysfs_device_link = g_strdup_printf(SYSFS_NET_DIR "%s/%s", ifname, file);
|
2013-07-18 10:13:46 +00:00
|
|
|
return 0;
|
2011-11-03 12:40:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname,
|
2018-09-19 08:38:14 +00:00
|
|
|
const char *file)
|
2011-11-03 12:40:33 +00:00
|
|
|
{
|
2019-10-22 13:26:14 +00:00
|
|
|
*pf_sysfs_device_link = g_strdup_printf(SYSFS_NET_DIR "%s/device/%s", ifname,
|
|
|
|
file);
|
2013-07-18 10:13:46 +00:00
|
|
|
return 0;
|
2011-11-03 12:40:33 +00:00
|
|
|
}
|
|
|
|
|
2020-09-30 20:36:52 +00:00
|
|
|
|
|
|
|
# if defined(WITH_LIBNL)
|
|
|
|
|
2018-01-06 00:10:47 +00:00
|
|
|
/**
|
|
|
|
* Determine if the device path specified in devpath is a PCI Device
|
|
|
|
* by resolving the 'subsystem'-link in devpath and looking for
|
|
|
|
* 'pci' in the last component. For more information see the rules
|
|
|
|
* for accessing sysfs in the kernel docs
|
|
|
|
*
|
|
|
|
* https://www.kernel.org/doc/html/latest/admin-guide/sysfs-rules.html
|
|
|
|
*
|
2020-07-09 04:42:21 +00:00
|
|
|
* Returns true if devpath's subsystem is pci, false otherwise.
|
2018-01-06 00:10:47 +00:00
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
virNetDevIsPCIDevice(const char *devpath)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *subsys_link = NULL;
|
|
|
|
g_autofree char *abs_path = NULL;
|
2019-12-23 15:47:21 +00:00
|
|
|
g_autofree char *subsys = NULL;
|
2018-01-06 00:10:47 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
subsys_link = g_strdup_printf("%s/subsystem", devpath);
|
2018-01-06 00:10:47 +00:00
|
|
|
|
|
|
|
if (!virFileExists(subsys_link))
|
2020-04-19 05:24:40 +00:00
|
|
|
return false;
|
2018-01-06 00:10:47 +00:00
|
|
|
|
|
|
|
if (virFileResolveLink(subsys_link, &abs_path) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to resolve device subsystem symlink %s"),
|
|
|
|
subsys_link);
|
2020-04-19 05:24:40 +00:00
|
|
|
return false;
|
2018-01-06 00:10:47 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 15:47:21 +00:00
|
|
|
subsys = g_path_get_basename(abs_path);
|
2020-04-19 05:24:40 +00:00
|
|
|
return STRPREFIX(subsys, "pci");
|
2018-01-06 00:10:47 +00:00
|
|
|
}
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
2020-09-30 20:36:52 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virPCIDevice *
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
virNetDevGetPCIDevice(const char *devName)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *vfSysfsDevicePath = NULL;
|
|
|
|
g_autoptr(virPCIDeviceAddress) vfPCIAddr = NULL;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&vfSysfsDevicePath, devName, "device") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return NULL;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
2018-01-06 00:10:47 +00:00
|
|
|
if (!virNetDevIsPCIDevice(vfSysfsDevicePath))
|
2020-04-19 05:24:40 +00:00
|
|
|
return NULL;
|
2018-01-06 00:10:47 +00:00
|
|
|
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
vfPCIAddr = virPCIGetDeviceAddressFromSysfsLink(vfSysfsDevicePath);
|
|
|
|
if (!vfPCIAddr)
|
2020-04-19 05:24:40 +00:00
|
|
|
return NULL;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
virpci.c: simplify virPCIDeviceNew() signature
The current virPCIDeviceNew() signature, receiving 4 uints in sequence
(domain, bus, slot, function), is not neat.
We already have a way to represent a PCI address in virPCIDeviceAddress
that is used in the code. Aside from the test files, most of
virPCIDeviceNew() callers have access to a virPCIDeviceAddress reference,
but then we need to retrieve the 4 required uints (addr.domain, addr.bus,
addr.slot, addr.function) to satisfy virPCIDeviceNew(). The result is
that we have extra verbosity/boilerplate to retrieve an information that
is already available in virPCIDeviceAddress.
A better way is presented by virNVMEDeviceNew(), where the caller just
supplies a virPCIDeviceAddress pointer and the function handles the
details internally.
This patch changes virPCIDeviceNew() to receive a virPCIDeviceAddress
pointer instead of 4 uints.
Reviewed-by: Laine Stump <laine@redhat.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
2021-01-04 12:54:28 +00:00
|
|
|
return virPCIDeviceNew(vfPCIAddr);
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
}
|
2020-09-30 20:36:52 +00:00
|
|
|
# endif
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
|
2021-01-21 12:15:21 +00:00
|
|
|
/* A wrapper to get content of file from ifname SYSFS_NET_DIR
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetDevGetSysfsFileValue(const char *ifname,
|
|
|
|
const char *fileName,
|
|
|
|
char **sysfsFileData)
|
|
|
|
{
|
|
|
|
g_autofree char *sysfsFile = NULL;
|
|
|
|
|
|
|
|
*sysfsFileData = NULL;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&sysfsFile, ifname, fileName) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* a failure to read just means the driver doesn't support
|
|
|
|
* <fileName>, so set success now and ignore the return from
|
|
|
|
* virFileReadAllQuiet().
|
|
|
|
*/
|
|
|
|
|
|
|
|
ignore_value(virFileReadAllQuiet(sysfsFile, 1024, sysfsFileData));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-31 03:32:43 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetPhysPortID:
|
|
|
|
*
|
|
|
|
* @ifname: name of a netdev
|
|
|
|
*
|
|
|
|
* @physPortID: pointer to char* that will receive @ifname's
|
|
|
|
* phys_port_id from sysfs (null terminated
|
|
|
|
* string). Could be NULL if @ifname's net driver doesn't
|
|
|
|
* support phys_port_id (most netdev drivers
|
|
|
|
* don't). Caller is responsible for freeing the string
|
|
|
|
* when finished.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetPhysPortID(const char *ifname,
|
|
|
|
char **physPortID)
|
|
|
|
{
|
2021-01-21 12:15:21 +00:00
|
|
|
return virNetDevGetSysfsFileValue(ifname, "phys_port_id", physPortID);
|
|
|
|
}
|
2017-07-31 03:32:43 +00:00
|
|
|
|
|
|
|
|
2021-01-21 12:15:21 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetPhysPortName:
|
|
|
|
*
|
|
|
|
* @ifname: name of a netdev
|
|
|
|
*
|
|
|
|
* @physPortName: pointer to char* that will receive @ifname's
|
|
|
|
* phys_port_name from sysfs (null terminated
|
|
|
|
* string). Could be NULL if @ifname's net driver doesn't
|
|
|
|
* support phys_port_name (most netdev drivers
|
|
|
|
* don't). Caller is responsible for freeing the string
|
|
|
|
* when finished.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetPhysPortName(const char *ifname,
|
|
|
|
char **physPortName)
|
|
|
|
{
|
|
|
|
return virNetDevGetSysfsFileValue(ifname, "phys_port_name", physPortName);
|
2017-07-31 03:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-14 10:50:14 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetVirtualFunctions:
|
|
|
|
*
|
|
|
|
* @pfname : name of the physical function interface name
|
|
|
|
* @vfname: array that will hold the interface names of the virtual_functions
|
|
|
|
* @n_vfname: pointer to the number of virtual functions
|
|
|
|
*
|
|
|
|
* Returns 0 on success and -1 on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetDevGetVirtualFunctions(const char *pfname,
|
|
|
|
char ***vfname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virPCIDeviceAddress ***virt_fns,
|
nodedev: report maxCount for virtual_functions capability
A PCI device may have the capability to setup virtual functions (VFs)
but have them currently all disabled. Prior to this patch, if that was
the case the the node device XML for the device wouldn't report any
virtual_functions capability.
With this patch, if a file called "sriov_totalvfs" is found in the
device's sysfs directory, its contents will be interpreted as a
decimal number, and that value will be reported as "maxCount" in a
capability element of the device's XML, e.g.:
<capability type='virtual_functions' maxCount='7'/>
This will be reported regardless of whether or not any VFs are
currently enabled for the device.
NB: sriov_numvfs (the number of VFs currently active) is also
available in sysfs, but that value is implied by the number of items
in the list that is inside the capability element, so there is no
reason to explicitly provide it as an attribute.
sriov_totalvfs and sriov_numvfs are available in kernels at least as far
back as the 2.6.32 that is in RHEL6.7, but in the case that they
simply aren't there, libvirt will behave as it did prior to this patch
- no maxCount will be displayed, and the virtual_functions capability
will be absent from the device's XML when 0 VFs are enabled.
2015-11-23 19:19:13 +00:00
|
|
|
size_t *n_vfname,
|
|
|
|
unsigned int *max_vfs)
|
2011-12-14 10:50:14 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int ret = -1;
|
|
|
|
size_t i;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pf_sysfs_device_link = NULL;
|
|
|
|
g_autofree char *pfPhysPortID = NULL;
|
2011-12-14 10:50:14 +00:00
|
|
|
|
2013-07-01 03:52:43 +00:00
|
|
|
*virt_fns = NULL;
|
|
|
|
*n_vfname = 0;
|
nodedev: report maxCount for virtual_functions capability
A PCI device may have the capability to setup virtual functions (VFs)
but have them currently all disabled. Prior to this patch, if that was
the case the the node device XML for the device wouldn't report any
virtual_functions capability.
With this patch, if a file called "sriov_totalvfs" is found in the
device's sysfs directory, its contents will be interpreted as a
decimal number, and that value will be reported as "maxCount" in a
capability element of the device's XML, e.g.:
<capability type='virtual_functions' maxCount='7'/>
This will be reported regardless of whether or not any VFs are
currently enabled for the device.
NB: sriov_numvfs (the number of VFs currently active) is also
available in sysfs, but that value is implied by the number of items
in the list that is inside the capability element, so there is no
reason to explicitly provide it as an attribute.
sriov_totalvfs and sriov_numvfs are available in kernels at least as far
back as the 2.6.32 that is in RHEL6.7, but in the case that they
simply aren't there, libvirt will behave as it did prior to this patch
- no maxCount will be displayed, and the virtual_functions capability
will be absent from the device's XML when 0 VFs are enabled.
2015-11-23 19:19:13 +00:00
|
|
|
*max_vfs = 0;
|
2013-07-01 03:52:43 +00:00
|
|
|
|
2017-07-31 05:55:49 +00:00
|
|
|
if (virNetDevGetPhysPortID(pfname, &pfPhysPortID) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-12-14 10:50:14 +00:00
|
|
|
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0)
|
2017-07-31 05:55:49 +00:00
|
|
|
goto cleanup;
|
2011-12-14 10:50:14 +00:00
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virPCIGetVirtualFunctions(pf_sysfs_device_link, virt_fns,
|
nodedev: report maxCount for virtual_functions capability
A PCI device may have the capability to setup virtual functions (VFs)
but have them currently all disabled. Prior to this patch, if that was
the case the the node device XML for the device wouldn't report any
virtual_functions capability.
With this patch, if a file called "sriov_totalvfs" is found in the
device's sysfs directory, its contents will be interpreted as a
decimal number, and that value will be reported as "maxCount" in a
capability element of the device's XML, e.g.:
<capability type='virtual_functions' maxCount='7'/>
This will be reported regardless of whether or not any VFs are
currently enabled for the device.
NB: sriov_numvfs (the number of VFs currently active) is also
available in sysfs, but that value is implied by the number of items
in the list that is inside the capability element, so there is no
reason to explicitly provide it as an attribute.
sriov_totalvfs and sriov_numvfs are available in kernels at least as far
back as the 2.6.32 that is in RHEL6.7, but in the case that they
simply aren't there, libvirt will behave as it did prior to this patch
- no maxCount will be displayed, and the virtual_functions capability
will be absent from the device's XML when 0 VFs are enabled.
2015-11-23 19:19:13 +00:00
|
|
|
n_vfname, max_vfs) < 0)
|
2011-12-14 10:50:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2020-10-05 17:08:12 +00:00
|
|
|
*vfname = g_new0(char *, *n_vfname);
|
2011-12-14 10:50:14 +00:00
|
|
|
|
2014-09-03 22:24:43 +00:00
|
|
|
for (i = 0; i < *n_vfname; i++) {
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pci_sysfs_device_link = NULL;
|
|
|
|
|
2020-10-12 18:58:26 +00:00
|
|
|
if (virPCIDeviceAddressGetSysfsFile((*virt_fns)[i],
|
|
|
|
&pci_sysfs_device_link) < 0) {
|
2011-12-14 10:50:14 +00:00
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Failed to get PCI SYSFS file"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-07-31 04:21:45 +00:00
|
|
|
if (virPCIGetNetName(pci_sysfs_device_link, 0,
|
2017-07-31 05:55:49 +00:00
|
|
|
pfPhysPortID, &((*vfname)[i])) < 0) {
|
2017-03-03 16:54:59 +00:00
|
|
|
goto cleanup;
|
2017-07-31 04:21:45 +00:00
|
|
|
}
|
2017-03-03 16:54:59 +00:00
|
|
|
|
|
|
|
if (!(*vfname)[i])
|
2012-08-16 15:41:58 +00:00
|
|
|
VIR_INFO("VF does not have an interface name");
|
2011-12-14 10:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-08-16 15:41:58 +00:00
|
|
|
if (ret < 0) {
|
2020-04-19 05:24:40 +00:00
|
|
|
virStringListFreeCount(*vfname, *n_vfname);
|
|
|
|
|
|
|
|
for (i = 0; i < *n_vfname; i++)
|
|
|
|
VIR_FREE((*virt_fns)[i]);
|
2012-08-16 15:41:58 +00:00
|
|
|
VIR_FREE(*virt_fns);
|
2020-04-19 05:24:40 +00:00
|
|
|
*vfname = NULL;
|
|
|
|
*n_vfname = 0;
|
2012-08-16 15:41:58 +00:00
|
|
|
}
|
2011-12-14 10:50:14 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-03 12:40:33 +00:00
|
|
|
/**
|
|
|
|
* virNetDevIsVirtualFunction:
|
|
|
|
* @ifname : name of the interface
|
|
|
|
*
|
|
|
|
* Checks if an interface is a SRIOV virtual function.
|
|
|
|
*
|
|
|
|
* Returns 1 if interface is SRIOV virtual function, 0 if not and -1 if error
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevIsVirtualFunction(const char *ifname)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *if_sysfs_device_link = NULL;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&if_sysfs_device_link, ifname, "device") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return virPCIIsVirtualFunction(if_sysfs_device_link);
|
2011-11-03 12:40:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGetVirtualFunctionIndex
|
|
|
|
*
|
|
|
|
* @pfname : name of the physical function interface name
|
|
|
|
* @vfname : name of the virtual function interface name
|
|
|
|
* @vf_index : Pointer to int. Contains vf index of interface upon successful
|
|
|
|
* return
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetVirtualFunctionIndex(const char *pfname, const char *vfname,
|
|
|
|
int *vf_index)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pf_sysfs_device_link = NULL;
|
|
|
|
g_autofree char *vf_sysfs_device_link = NULL;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
if (virNetDevSysfsFile(&vf_sysfs_device_link, vfname, "device") < 0)
|
|
|
|
return -1;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return virPCIGetVirtualFunctionIndex(pf_sysfs_device_link,
|
|
|
|
vf_sysfs_device_link,
|
|
|
|
vf_index);
|
2011-11-03 12:40:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGetPhysicalFunction
|
|
|
|
*
|
|
|
|
* @ifname : name of the physical function interface name
|
|
|
|
* @pfname : Contains sriov physical function for interface ifname
|
util: don't log error if SRIOV PF has no associated netdev
Some SRIOV PFs don't have a netdev associated with them (the spec
apparently doesn't require it). In most cases when libvirt is dealing
with an SRIOV VF, that VF must have a PF, and the PF *must* have an
associated netdev (the only way to set the MAC address of a VF is by
sending a netlink message to the netdev of that VF's PF). But there
are times when we don't need for the PF to have a netdev; in
particular, when we're just getting the Switchdev Features for a VF,
we don't need the PF netdev - the netdev of the VF (apparently) works
just as well.
Commit 6452e2f5 (libvirt 5.1.0) *kind of* made libvirt work around PFs
with no netdevs in this case - if virNetDevGetPhysicalFunction
returned an error when setting up to retrieve Switchdev feature info,
it would ignore the error, and then check if the PF netdev name was
NULL and, if so it would reset the error object and continue on rather
than returning early with a failure. The problem is that by the time
this special handling occured, the error message about missing netdev
had already been logged, which was harmless to proper operation, but
confused the user.
Fortunately there are only 2 users of virNetDevGetPhysicalFunction, so
it is easy to redefine it's API to state that a missing netdev name is
*not* an error - in that case it will still return success, but the
caller must be prepared for the PF netdev name to be NULL. After
making this change, we can modify the two callers to behave properly
with the new semantics (for one of the callers it *is* still an error,
so the error message is moved there, but for the other it is okay to
continue), and our spurious error messages are a thing of the past.
Resolves: https://bugzilla.redhat.com/1924616
Fixes: 6452e2f5e1837bd753ee465e6607ed3c4f62b815
Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-02-24 03:19:56 +00:00
|
|
|
* upon successful return (might be NULL if the PF has no
|
|
|
|
* associated netdev. This is *not* an error)
|
2011-11-03 12:40:33 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *physfn_sysfs_path = NULL;
|
|
|
|
g_autofree char *vfPhysPortID = NULL;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
2017-07-31 05:55:49 +00:00
|
|
|
if (virNetDevGetPhysPortID(ifname, &vfPhysPortID) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-07-31 05:55:49 +00:00
|
|
|
|
2011-11-03 12:40:33 +00:00
|
|
|
if (virNetDevSysfsDeviceFile(&physfn_sysfs_path, ifname, "physfn") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2011-11-03 12:40:33 +00:00
|
|
|
|
2017-07-31 04:21:45 +00:00
|
|
|
if (virPCIGetNetName(physfn_sysfs_path, 0,
|
2017-07-31 05:55:49 +00:00
|
|
|
vfPhysPortID, pfname) < 0) {
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-07-31 05:55:49 +00:00
|
|
|
}
|
2011-11-03 12:40:33 +00:00
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2011-11-03 12:40:33 +00:00
|
|
|
}
|
2011-12-14 10:50:14 +00:00
|
|
|
|
2017-03-02 19:55:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevPFGetVF:
|
|
|
|
*
|
|
|
|
* @pfname: netdev name of the physical function (PF)
|
|
|
|
* @vf: virtual function (VF) number for the device of interest
|
|
|
|
* @vfname: name of the physical function interface name
|
|
|
|
*
|
|
|
|
* Finds the netdev name of VF# @vf of SRIOV PF @pfname, and puts it
|
|
|
|
* in @vfname. The caller must free @vfname when it's finished with
|
|
|
|
* it.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
* NB: if the VF has no netdev name, that is *not* considered an
|
|
|
|
* error; *vfname simply gets a NULL and the return value is 0
|
|
|
|
* (success).
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevPFGetVF(const char *pfname, int vf, char **vfname)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *virtfnName = NULL;
|
|
|
|
g_autofree char *virtfnSysfsPath = NULL;
|
|
|
|
g_autofree char *pfPhysPortID = NULL;
|
2017-03-02 19:55:01 +00:00
|
|
|
|
2017-07-31 05:55:49 +00:00
|
|
|
/* a VF may have multiple "ports", each one having its own netdev,
|
|
|
|
* and each netdev having a different phys_port_id. Be sure we get
|
|
|
|
* the VF netdev with a phys_port_id matchine that of pfname
|
|
|
|
*/
|
|
|
|
if (virNetDevGetPhysPortID(pfname, &pfPhysPortID) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-07-31 05:55:49 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
virtfnName = g_strdup_printf("virtfn%d", vf);
|
2017-03-02 19:55:01 +00:00
|
|
|
|
|
|
|
/* this provides the path to the VF's directory in sysfs,
|
|
|
|
* e.g. "/sys/class/net/enp2s0f0/virtfn3"
|
|
|
|
*/
|
|
|
|
if (virNetDevSysfsDeviceFile(&virtfnSysfsPath, pfname, virtfnName) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-03-02 19:55:01 +00:00
|
|
|
|
|
|
|
/* and this gets the netdev name associated with it, which is a
|
|
|
|
* directory entry in [virtfnSysfsPath]/net,
|
|
|
|
* e.g. "/sys/class/net/enp2s0f0/virtfn3/net/enp2s11f4" - in this
|
|
|
|
* example the VF for enp2s0f0 vf#3 is "enp2s11f4". (If the VF
|
|
|
|
* isn't bound to a netdev driver, it won't have a netdev name,
|
|
|
|
* and vfname will be NULL).
|
|
|
|
*/
|
2020-04-19 05:24:40 +00:00
|
|
|
return virPCIGetNetName(virtfnSysfsPath, 0, pfPhysPortID, vfname);
|
2017-03-02 19:55:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-06 01:12:34 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetVirtualFunctionInfo:
|
|
|
|
* @vfname: name of the virtual function interface
|
|
|
|
* @pfname: name of the physical function
|
|
|
|
* @vf: vf index
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -errno on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetVirtualFunctionInfo(const char *vfname, char **pfname,
|
|
|
|
int *vf)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virNetDevGetPhysicalFunction(vfname, pfname) < 0)
|
2019-01-22 19:26:13 +00:00
|
|
|
return -1;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
util: don't log error if SRIOV PF has no associated netdev
Some SRIOV PFs don't have a netdev associated with them (the spec
apparently doesn't require it). In most cases when libvirt is dealing
with an SRIOV VF, that VF must have a PF, and the PF *must* have an
associated netdev (the only way to set the MAC address of a VF is by
sending a netlink message to the netdev of that VF's PF). But there
are times when we don't need for the PF to have a netdev; in
particular, when we're just getting the Switchdev Features for a VF,
we don't need the PF netdev - the netdev of the VF (apparently) works
just as well.
Commit 6452e2f5 (libvirt 5.1.0) *kind of* made libvirt work around PFs
with no netdevs in this case - if virNetDevGetPhysicalFunction
returned an error when setting up to retrieve Switchdev feature info,
it would ignore the error, and then check if the PF netdev name was
NULL and, if so it would reset the error object and continue on rather
than returning early with a failure. The problem is that by the time
this special handling occured, the error message about missing netdev
had already been logged, which was harmless to proper operation, but
confused the user.
Fortunately there are only 2 users of virNetDevGetPhysicalFunction, so
it is easy to redefine it's API to state that a missing netdev name is
*not* an error - in that case it will still return success, but the
caller must be prepared for the PF netdev name to be NULL. After
making this change, we can modify the two callers to behave properly
with the new semantics (for one of the callers it *is* still an error,
so the error message is moved there, but for the other it is okay to
continue), and our spurious error messages are a thing of the past.
Resolves: https://bugzilla.redhat.com/1924616
Fixes: 6452e2f5e1837bd753ee465e6607ed3c4f62b815
Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-02-24 03:19:56 +00:00
|
|
|
if (!*pfname) {
|
|
|
|
/* The SRIOV standard does not require VF netdevs to have the
|
|
|
|
* netdev assigned to a PF, but our method of retrieving
|
|
|
|
* VFINFO does.
|
|
|
|
*/
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("The PF device for VF %s has no network device name, cannot get virtual function info"),
|
|
|
|
vfname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-01-22 19:26:13 +00:00
|
|
|
if (virNetDevGetVirtualFunctionIndex(*pfname, vfname, vf) < 0)
|
2012-03-06 01:12:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2019-01-22 19:26:13 +00:00
|
|
|
ret = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-03-06 01:12:34 +00:00
|
|
|
if (ret < 0)
|
|
|
|
VIR_FREE(*pfname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !__linux__ */
|
2017-07-31 03:32:43 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetPhysPortID(const char *ifname G_GNUC_UNUSED,
|
2017-07-31 03:32:43 +00:00
|
|
|
char **physPortID)
|
|
|
|
{
|
|
|
|
/* this actually should never be called, and is just here to
|
|
|
|
* satisfy the linker.
|
|
|
|
*/
|
|
|
|
*physPortID = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-21 12:15:21 +00:00
|
|
|
int
|
|
|
|
virNetDevGetPhysPortName(const char *ifname G_GNUC_UNUSED,
|
|
|
|
char **physPortName)
|
|
|
|
{
|
|
|
|
/* this actually should never be called, and is just here to
|
|
|
|
* satisfy the linker.
|
|
|
|
*/
|
|
|
|
*physPortName = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-14 10:50:14 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetVirtualFunctions(const char *pfname G_GNUC_UNUSED,
|
|
|
|
char ***vfname G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virPCIDeviceAddress ***virt_fns G_GNUC_UNUSED,
|
2019-10-14 12:45:33 +00:00
|
|
|
size_t *n_vfname G_GNUC_UNUSED,
|
|
|
|
unsigned int *max_vfs G_GNUC_UNUSED)
|
2011-12-14 10:50:14 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
2012-04-01 09:23:56 +00:00
|
|
|
_("Unable to get virtual functions on this platform"));
|
2011-12-14 10:50:14 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-11-03 12:40:33 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevIsVirtualFunction(const char *ifname G_GNUC_UNUSED)
|
2011-11-03 12:40:33 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
2011-12-30 14:22:43 +00:00
|
|
|
_("Unable to check virtual function status on this platform"));
|
2011-11-03 12:40:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetVirtualFunctionIndex(const char *pfname G_GNUC_UNUSED,
|
|
|
|
const char *vfname G_GNUC_UNUSED,
|
|
|
|
int *vf_index G_GNUC_UNUSED)
|
2011-11-03 12:40:33 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
2011-12-30 14:22:43 +00:00
|
|
|
_("Unable to get virtual function index on this platform"));
|
2011-11-03 12:40:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetPhysicalFunction(const char *ifname G_GNUC_UNUSED,
|
|
|
|
char **pfname G_GNUC_UNUSED)
|
2011-11-03 12:40:33 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
2011-12-30 14:22:43 +00:00
|
|
|
_("Unable to get physical function status on this platform"));
|
2011-11-03 12:40:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2017-03-02 19:55:01 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevPFGetVF(const char *pfname G_GNUC_UNUSED,
|
|
|
|
int vf G_GNUC_UNUSED,
|
|
|
|
char **vfname G_GNUC_UNUSED)
|
2017-03-02 19:55:01 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get virtual function name on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-06 01:12:34 +00:00
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetVirtualFunctionInfo(const char *vfname G_GNUC_UNUSED,
|
|
|
|
char **pfname G_GNUC_UNUSED,
|
|
|
|
int *vf G_GNUC_UNUSED)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get virtual function info on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2015-04-14 19:53:04 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevSysfsFile(char **pf_sysfs_device_link G_GNUC_UNUSED,
|
|
|
|
const char *ifname G_GNUC_UNUSED,
|
|
|
|
const char *file G_GNUC_UNUSED)
|
2015-04-14 19:53:04 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get sysfs info on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-08-31 21:09:01 +00:00
|
|
|
|
2011-11-03 12:40:33 +00:00
|
|
|
#endif /* !__linux__ */
|
2020-09-28 21:29:41 +00:00
|
|
|
#if defined(WITH_LIBNL)
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2015-04-22 08:14:57 +00:00
|
|
|
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
static virMacAddr zeroMAC = { .addr = { 0, 0, 0, 0, 0, 0 } };
|
|
|
|
|
|
|
|
/* if a net driver doesn't allow setting MAC to all 0, try setting
|
|
|
|
* to this (the only bit that is set is the "locally administered" bit")
|
|
|
|
*/
|
|
|
|
static virMacAddr altZeroMAC = { .addr = { 2, 0, 0, 0, 0, 0 } };
|
|
|
|
|
|
|
|
|
2012-03-06 01:12:34 +00:00
|
|
|
static struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
|
|
|
|
[IFLA_VF_MAC] = { .type = NLA_UNSPEC,
|
|
|
|
.maxlen = sizeof(struct ifla_vf_mac) },
|
|
|
|
[IFLA_VF_VLAN] = { .type = NLA_UNSPEC,
|
|
|
|
.maxlen = sizeof(struct ifla_vf_vlan) },
|
2020-10-15 11:21:14 +00:00
|
|
|
[IFLA_VF_STATS] = { .type = NLA_NESTED },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct nla_policy ifla_vfstats_policy[IFLA_VF_STATS_MAX+1] = {
|
|
|
|
[IFLA_VF_STATS_RX_PACKETS] = { .type = NLA_U64 },
|
|
|
|
[IFLA_VF_STATS_TX_PACKETS] = { .type = NLA_U64 },
|
|
|
|
[IFLA_VF_STATS_RX_BYTES] = { .type = NLA_U64 },
|
|
|
|
[IFLA_VF_STATS_TX_BYTES] = { .type = NLA_U64 },
|
|
|
|
[IFLA_VF_STATS_BROADCAST] = { .type = NLA_U64 },
|
|
|
|
[IFLA_VF_STATS_MULTICAST] = { .type = NLA_U64 },
|
2012-03-06 01:12:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
util: remove unused args from virNetDevSetVfConfig()
This function is only called in two places, and the ifindex,
nltarget_kernel, and getPidFunc args are never used (and never will
be).
ifindex - we always know the name of the device, and never know the
ifindex - if we really did need the ifindex we would have to get it
from the name using virNetDevGetIndex(). In practice, we just send -1
to virNetDevSetVfConfig(), which doesn't bother to learn the real
ifindex (you only need a name *or* an ifindex for the netlink command
to succeed, not both).
nltarget_kernel - messages to set the config of an SRIOV VF will
always go to netlink in the kernel, not to another user process, so
this arg is always true (there are other uses of netlink messages
where the message might need to go to another user process, but never
in the case of RTM_SETLINK for SRIOV).
getPidFunc - this arg is only used if nltarget_kernel is false, and it
never is.
None of this has any functional effect, it just makes it easier to
follow what's happening when virNetDevSetVfConfig() is called.
2017-02-20 03:06:33 +00:00
|
|
|
virNetDevSetVfConfig(const char *ifname, int vf,
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
const virMacAddr *macaddr, int vlanid,
|
|
|
|
bool *allowRetry)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
int rc = -1;
|
2017-03-11 15:29:29 +00:00
|
|
|
char macstr[VIR_MAC_STRING_BUFLEN];
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree struct nlmsghdr *resp = NULL;
|
2012-03-06 01:12:34 +00:00
|
|
|
struct nlmsgerr *err;
|
|
|
|
unsigned int recvbuflen = 0;
|
|
|
|
struct nl_msg *nl_msg;
|
|
|
|
struct nlattr *vfinfolist, *vfinfo;
|
|
|
|
struct ifinfomsg ifinfo = {
|
|
|
|
.ifi_family = AF_UNSPEC,
|
util: remove unused args from virNetDevSetVfConfig()
This function is only called in two places, and the ifindex,
nltarget_kernel, and getPidFunc args are never used (and never will
be).
ifindex - we always know the name of the device, and never know the
ifindex - if we really did need the ifindex we would have to get it
from the name using virNetDevGetIndex(). In practice, we just send -1
to virNetDevSetVfConfig(), which doesn't bother to learn the real
ifindex (you only need a name *or* an ifindex for the netlink command
to succeed, not both).
nltarget_kernel - messages to set the config of an SRIOV VF will
always go to netlink in the kernel, not to another user process, so
this arg is always true (there are other uses of netlink messages
where the message might need to go to another user process, but never
in the case of RTM_SETLINK for SRIOV).
getPidFunc - this arg is only used if nltarget_kernel is false, and it
never is.
None of this has any functional effect, it just makes it easier to
follow what's happening when virNetDevSetVfConfig() is called.
2017-02-20 03:06:33 +00:00
|
|
|
.ifi_index = -1,
|
2012-03-06 01:12:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (!macaddr && vlanid < 0)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-24 08:51:19 +00:00
|
|
|
nl_msg = virNetlinkMsgNew(RTM_SETLINK, NLM_F_REQUEST);
|
2012-03-06 01:12:34 +00:00
|
|
|
|
|
|
|
if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (ifname &&
|
|
|
|
nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(vfinfolist = nla_nest_start(nl_msg, IFLA_VFINFO_LIST)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (macaddr) {
|
|
|
|
struct ifla_vf_mac ifla_vf_mac = {
|
|
|
|
.vf = vf,
|
|
|
|
.mac = { 0, },
|
|
|
|
};
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrGetRaw(macaddr, ifla_vf_mac.mac);
|
2012-03-06 01:12:34 +00:00
|
|
|
|
|
|
|
if (nla_put(nl_msg, IFLA_VF_MAC, sizeof(ifla_vf_mac),
|
|
|
|
&ifla_vf_mac) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vlanid >= 0) {
|
|
|
|
struct ifla_vf_vlan ifla_vf_vlan = {
|
|
|
|
.vf = vf,
|
|
|
|
.vlan = vlanid,
|
|
|
|
.qos = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof(ifla_vf_vlan),
|
|
|
|
&ifla_vf_vlan) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(nl_msg, vfinfo);
|
|
|
|
nla_nest_end(nl_msg, vfinfolist);
|
|
|
|
|
util: remove unused args from virNetDevSetVfConfig()
This function is only called in two places, and the ifindex,
nltarget_kernel, and getPidFunc args are never used (and never will
be).
ifindex - we always know the name of the device, and never know the
ifindex - if we really did need the ifindex we would have to get it
from the name using virNetDevGetIndex(). In practice, we just send -1
to virNetDevSetVfConfig(), which doesn't bother to learn the real
ifindex (you only need a name *or* an ifindex for the netlink command
to succeed, not both).
nltarget_kernel - messages to set the config of an SRIOV VF will
always go to netlink in the kernel, not to another user process, so
this arg is always true (there are other uses of netlink messages
where the message might need to go to another user process, but never
in the case of RTM_SETLINK for SRIOV).
getPidFunc - this arg is only used if nltarget_kernel is false, and it
never is.
None of this has any functional effect, it just makes it easier to
follow what's happening when virNetDevSetVfConfig() is called.
2017-02-20 03:06:33 +00:00
|
|
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
|
2012-08-22 04:10:23 +00:00
|
|
|
NETLINK_ROUTE, 0) < 0)
|
2012-03-06 01:12:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-04-03 13:09:19 +00:00
|
|
|
if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
|
2012-03-06 01:12:34 +00:00
|
|
|
goto malformed_resp;
|
|
|
|
|
|
|
|
switch (resp->nlmsg_type) {
|
|
|
|
case NLMSG_ERROR:
|
|
|
|
err = (struct nlmsgerr *)NLMSG_DATA(resp);
|
|
|
|
if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
|
|
|
|
goto malformed_resp;
|
|
|
|
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
/* if allowRetry is true and the error was EINVAL, then
|
|
|
|
* silently return a failure so the caller can retry with a
|
|
|
|
* different MAC address
|
|
|
|
*/
|
|
|
|
if (err->error == -EINVAL && *allowRetry &&
|
|
|
|
macaddr && !virMacAddrCmp(macaddr, &zeroMAC)) {
|
|
|
|
goto cleanup;
|
|
|
|
} else if (err->error) {
|
|
|
|
/* other errors are permanent */
|
2012-03-06 01:12:34 +00:00
|
|
|
virReportSystemError(-err->error,
|
2015-12-18 17:08:54 +00:00
|
|
|
_("Cannot set interface MAC/vlanid to %s/%d "
|
util: remove unused args from virNetDevSetVfConfig()
This function is only called in two places, and the ifindex,
nltarget_kernel, and getPidFunc args are never used (and never will
be).
ifindex - we always know the name of the device, and never know the
ifindex - if we really did need the ifindex we would have to get it
from the name using virNetDevGetIndex(). In practice, we just send -1
to virNetDevSetVfConfig(), which doesn't bother to learn the real
ifindex (you only need a name *or* an ifindex for the netlink command
to succeed, not both).
nltarget_kernel - messages to set the config of an SRIOV VF will
always go to netlink in the kernel, not to another user process, so
this arg is always true (there are other uses of netlink messages
where the message might need to go to another user process, but never
in the case of RTM_SETLINK for SRIOV).
getPidFunc - this arg is only used if nltarget_kernel is false, and it
never is.
None of this has any functional effect, it just makes it easier to
follow what's happening when virNetDevSetVfConfig() is called.
2017-02-20 03:06:33 +00:00
|
|
|
"for ifname %s vf %d"),
|
2015-12-18 17:08:54 +00:00
|
|
|
(macaddr
|
|
|
|
? virMacAddrFormat(macaddr, macstr)
|
|
|
|
: "(unchanged)"),
|
|
|
|
vlanid,
|
|
|
|
ifname ? ifname : "(unspecified)",
|
util: remove unused args from virNetDevSetVfConfig()
This function is only called in two places, and the ifindex,
nltarget_kernel, and getPidFunc args are never used (and never will
be).
ifindex - we always know the name of the device, and never know the
ifindex - if we really did need the ifindex we would have to get it
from the name using virNetDevGetIndex(). In practice, we just send -1
to virNetDevSetVfConfig(), which doesn't bother to learn the real
ifindex (you only need a name *or* an ifindex for the netlink command
to succeed, not both).
nltarget_kernel - messages to set the config of an SRIOV VF will
always go to netlink in the kernel, not to another user process, so
this arg is always true (there are other uses of netlink messages
where the message might need to go to another user process, but never
in the case of RTM_SETLINK for SRIOV).
getPidFunc - this arg is only used if nltarget_kernel is false, and it
never is.
None of this has any functional effect, it just makes it easier to
follow what's happening when virNetDevSetVfConfig() is called.
2017-02-20 03:06:33 +00:00
|
|
|
vf);
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
*allowRetry = false; /* no use retrying */
|
2012-03-06 01:12:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NLMSG_DONE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto malformed_resp;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2017-03-11 15:29:29 +00:00
|
|
|
VIR_DEBUG("RTM_SETLINK %s vf %d MAC=%s vlanid=%d - %s",
|
|
|
|
ifname, vf,
|
|
|
|
macaddr ? virMacAddrFormat(macaddr, macstr) : "(unchanged)",
|
|
|
|
vlanid, rc < 0 ? "Fail" : "Success");
|
|
|
|
|
2012-03-06 01:12:34 +00:00
|
|
|
nlmsg_free(nl_msg);
|
|
|
|
return rc;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
malformed_resp:
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2012-03-06 01:12:34 +00:00
|
|
|
_("malformed netlink response message"));
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
buffer_too_small:
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2012-03-06 01:12:34 +00:00
|
|
|
_("allocated netlink buffer is too small"));
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 11:21:15 +00:00
|
|
|
/**
|
|
|
|
* virNetDevParseVfInfo:
|
2021-04-15 08:12:12 +00:00
|
|
|
* Get the VF interface information from kernel by netlink, To make netlink
|
2020-10-15 11:21:15 +00:00
|
|
|
* parsing logic easy to maintain, extending this function to get some new
|
|
|
|
* data is better than add a new function.
|
|
|
|
*/
|
2012-03-06 01:12:34 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevParseVfInfo(struct nlattr **tb, int32_t vf, virMacAddr *mac,
|
2020-10-15 11:21:15 +00:00
|
|
|
int *vlanid, virDomainInterfaceStatsPtr stats)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
int rc = -1;
|
2012-12-20 19:52:41 +00:00
|
|
|
struct ifla_vf_mac *vf_mac;
|
|
|
|
struct ifla_vf_vlan *vf_vlan;
|
|
|
|
struct nlattr *tb_vf_info = {NULL, };
|
|
|
|
struct nlattr *tb_vf[IFLA_VF_MAX+1];
|
2020-10-15 11:21:14 +00:00
|
|
|
struct nlattr *tb_vf_stats[IFLA_VF_STATS_MAX+1];
|
2012-12-20 19:52:41 +00:00
|
|
|
int rem;
|
|
|
|
|
|
|
|
if (!tb[IFLA_VFINFO_LIST]) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing IFLA_VF_INFO in netlink response"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return rc;
|
2012-12-20 19:52:41 +00:00
|
|
|
}
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2012-12-20 19:52:41 +00:00
|
|
|
nla_for_each_nested(tb_vf_info, tb[IFLA_VFINFO_LIST], rem) {
|
|
|
|
if (nla_type(tb_vf_info) != IFLA_VF_INFO)
|
|
|
|
continue;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2012-12-20 19:52:41 +00:00
|
|
|
if (nla_parse_nested(tb_vf, IFLA_VF_MAX, tb_vf_info,
|
|
|
|
ifla_vf_policy)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("error parsing IFLA_VF_INFO"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return rc;
|
2012-12-20 19:52:41 +00:00
|
|
|
}
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2020-10-21 02:31:27 +00:00
|
|
|
if (mac && tb_vf[IFLA_VF_MAC]) {
|
2012-12-20 19:52:41 +00:00
|
|
|
vf_mac = RTA_DATA(tb_vf[IFLA_VF_MAC]);
|
|
|
|
if (vf_mac && vf_mac->vf == vf) {
|
|
|
|
virMacAddrSetRaw(mac, vf_mac->mac);
|
2013-05-24 10:29:28 +00:00
|
|
|
rc = 0;
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
2012-12-20 19:52:41 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 02:31:27 +00:00
|
|
|
if (vlanid && tb_vf[IFLA_VF_VLAN]) {
|
2012-12-20 19:52:41 +00:00
|
|
|
vf_vlan = RTA_DATA(tb_vf[IFLA_VF_VLAN]);
|
|
|
|
if (vf_vlan && vf_vlan->vf == vf) {
|
|
|
|
*vlanid = vf_vlan->vlan;
|
2013-05-24 10:29:28 +00:00
|
|
|
rc = 0;
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-24 10:29:28 +00:00
|
|
|
|
2020-10-15 11:21:14 +00:00
|
|
|
if (stats && tb_vf[IFLA_VF_STATS] && tb_vf[IFLA_VF_MAC]) {
|
|
|
|
vf_mac = RTA_DATA(tb_vf[IFLA_VF_MAC]);
|
|
|
|
if (vf_mac && vf_mac->vf == vf) {
|
|
|
|
rc = nla_parse_nested(tb_vf_stats, IFLA_VF_STATS_MAX,
|
|
|
|
tb_vf[IFLA_VF_STATS],
|
|
|
|
ifla_vfstats_policy);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("error parsing IFLA_VF_STATS"));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
stats->rx_bytes = nla_get_u64(tb_vf_stats[IFLA_VF_STATS_RX_BYTES]);
|
|
|
|
stats->tx_bytes = nla_get_u64(tb_vf_stats[IFLA_VF_STATS_TX_BYTES]);
|
|
|
|
stats->rx_packets = nla_get_u64(tb_vf_stats[IFLA_VF_STATS_RX_PACKETS]);
|
|
|
|
stats->tx_packets = nla_get_u64(tb_vf_stats[IFLA_VF_STATS_TX_PACKETS]);
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-24 10:29:28 +00:00
|
|
|
if (rc == 0)
|
|
|
|
break;
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
2013-05-24 10:29:28 +00:00
|
|
|
if (rc < 0)
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("couldn't find IFLA_VF_INFO for VF %d "
|
|
|
|
"in netlink response"), vf);
|
2012-03-06 01:12:34 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevGetVfConfig(const char *ifname, int vf, virMacAddr *mac,
|
2012-03-06 01:12:34 +00:00
|
|
|
int *vlanid)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree void *nlData = NULL;
|
2012-03-06 01:12:34 +00:00
|
|
|
struct nlattr *tb[IFLA_MAX + 1] = {NULL, };
|
|
|
|
int ifindex = -1;
|
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
if (virNetlinkDumpLink(ifname, ifindex, &nlData, tb, 0, 0) < 0)
|
|
|
|
return -1;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2020-10-15 11:21:15 +00:00
|
|
|
return virNetDevParseVfInfo(tb, vf, mac, vlanid, NULL);
|
2020-10-15 11:21:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevVFInterfaceStats:
|
|
|
|
* @vfAddr: PCI address of a VF
|
|
|
|
* @stats: returns stats of the VF interface
|
|
|
|
*
|
|
|
|
* Get the VF interface from kernel by netlink.
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevVFInterfaceStats(virPCIDeviceAddress *vfAddr,
|
2020-10-15 11:21:14 +00:00
|
|
|
virDomainInterfaceStatsPtr stats)
|
|
|
|
{
|
|
|
|
g_autofree void *nlData = NULL;
|
|
|
|
struct nlattr *tb[IFLA_MAX + 1] = {NULL, };
|
|
|
|
g_autofree char *vfSysfsPath = NULL;
|
|
|
|
g_autofree char *pfname = NULL;
|
|
|
|
int vf = -1;
|
|
|
|
|
|
|
|
if (virPCIDeviceAddressGetSysfsFile(vfAddr, &vfSysfsPath) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!virPCIIsVirtualFunction(vfSysfsPath)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, _("'%s' is not a VF device"), vfSysfsPath);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virPCIGetVirtualFunctionInfo(vfSysfsPath, -1, &pfname, &vf) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virNetlinkDumpLink(pfname, -1, &nlData, tb, 0, 0) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-10-15 11:21:15 +00:00
|
|
|
return virNetDevParseVfInfo(tb, vf, NULL, NULL, stats);
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-20 21:14:53 +00:00
|
|
|
# define VIR_NETDEV_KEYNAME_ADMIN_MAC "adminMac"
|
|
|
|
# define VIR_NETDEV_KEYNAME_VLAN_TAG "vlanTag"
|
|
|
|
# define VIR_NETDEV_KEYNAME_MAC "mac"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSaveNetConfig:
|
|
|
|
* @linkdev: name of the interface
|
|
|
|
* @vf: vf index if linkdev is a pf
|
|
|
|
* @stateDir: directory to store old net config
|
|
|
|
* @saveVlan: false if we shouldn't attempt to save vlan tag info
|
|
|
|
* (eg for interfaces using 802.1Qbg, since it handles
|
|
|
|
* vlan tags internally)
|
|
|
|
*
|
|
|
|
* Save current MAC address and (if linkdev itself is a VF, or if @vf
|
|
|
|
* >= 0) the "admin MAC address" and vlan tag the device described by
|
|
|
|
* @linkdev:@vf to @stateDir. (the "admin MAC address" is stored in
|
|
|
|
* the PF, and is what the VF MAC will be initialized to the next time
|
|
|
|
* its driver is reloaded (either on host or guest).
|
|
|
|
*
|
|
|
|
* File Format:
|
|
|
|
*
|
|
|
|
* The file is in json format and will contain 1 or more of the
|
|
|
|
* following values:
|
|
|
|
*
|
|
|
|
* "mac" - VF MAC address (or missing if VF has no host net driver)
|
|
|
|
* "vlanTag" - a single vlan tag id
|
|
|
|
* "adminMac" - admin MAC address (stored in the PF)
|
|
|
|
*
|
|
|
|
* For example:
|
|
|
|
*
|
|
|
|
* {"mac": "9A:11:22:33:44:55",
|
|
|
|
* "vlanTag": "42",
|
|
|
|
* "adminMac": "00:00:00:00:00:00"
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* File Name:
|
|
|
|
*
|
|
|
|
* If the device is a VF and we're allowed to save vlan tag info, the
|
|
|
|
* file will be named ${pfDevName_vf#{vf} (e.g. "enp2s0f0_vf5") and
|
|
|
|
* will contain at least "adminMac" and "vlanTag" (if the device was bound
|
|
|
|
* to a net driver on the host prior to use, it will also have "mac"..
|
|
|
|
* If the device isn't a VF, or we're not allowed to save vlan tag
|
|
|
|
* info, the file will be named ${linkdev} (e.g. "enp3s0f0") and will
|
|
|
|
* contain just linkdev's MAC address.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevSaveNetConfig(const char *linkdev, int vf,
|
|
|
|
const char *stateDir,
|
|
|
|
bool saveVlan)
|
|
|
|
{
|
|
|
|
const char *pfDevName = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pfDevOrig = NULL;
|
|
|
|
g_autofree char *vfDevOrig = NULL;
|
2017-02-20 21:14:53 +00:00
|
|
|
virMacAddr oldMAC;
|
|
|
|
char MACStr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
int oldVlanTag = -1;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *filePath = NULL;
|
|
|
|
g_autofree char *fileStr = NULL;
|
|
|
|
g_autoptr(virJSONValue) configJSON = NULL;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (vf >= 0) {
|
|
|
|
/* linkdev is the PF */
|
|
|
|
pfDevName = linkdev;
|
|
|
|
|
|
|
|
/* linkdev should get the VF's netdev name (or NULL if none) */
|
|
|
|
if (virNetDevPFGetVF(pfDevName, vf, &vfDevOrig) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
linkdev = vfDevOrig;
|
util: check for PF online status earlier in guest startup
When using a VF from an SRIOV-capable network card in a guest (either
in macvtap passthrough mode, or via VFIO PCI device assignment), The
associated PF netdev must be online in order for the VF to be usable
by the guest. The guest, however, is not able to change the state of
the PF. And libvirt *could* set the PF online as needed, but that
could lead to the host receiving unexpected IPv6 traffic (since the
default for an unconfigured interface is to participate in IPv6
autoconf). For this reason, before assigning a VF to a guest, libvirt
verifies that the related PF netdev is online - if it isn't, then we
log an error and don't allow the guest startup to continue.
Until now, this check was done during virNetDevSetNetConfig(). This
works nicely because the same function is called both for macvtap
passthrough and for VFIO device assignment. But in the case of VFIO,
the VF has already been unbound from its netdev driver by the time we
get to virNetDevSetNetConfig(), and in the case of dual port Mellanox
NICs that have their VFs setup in single port mode, the *only* way to
determine the proper PF netdev to query for online status is via the
"phys_port_id" file that is in the VF netdev's sysfs directory. *BUT*
if we've unbound the VF from the netdev driver, then it doesn't *have*
a netdev sysfs directory.
So, in order to check the correct PF netdev for online status, this
patch moved the check earlier in the setup, into
virNetDevSaveNetConfig(), which is called *before* unbinding the VF
from its netdev driver.
(Note that this implies that if you are using VFIO device assignment
for the VFs of a Mellanox NIC that has the VFs programmed in single
port mode, you must let the VFs be bound to their net driver and use
"managed='yes'" in the device definition. To be more specific, this is
only true if the VFs in single port mode are using port *2* of the PF
- if the VFs are using only port 1, then the correct PF netdev will be
arrived at by default/chance))
This resolves: https://bugzilla.redhat.com/267191
2017-08-10 19:46:38 +00:00
|
|
|
saveVlan = true;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
util: check for PF online status earlier in guest startup
When using a VF from an SRIOV-capable network card in a guest (either
in macvtap passthrough mode, or via VFIO PCI device assignment), The
associated PF netdev must be online in order for the VF to be usable
by the guest. The guest, however, is not able to change the state of
the PF. And libvirt *could* set the PF online as needed, but that
could lead to the host receiving unexpected IPv6 traffic (since the
default for an unconfigured interface is to participate in IPv6
autoconf). For this reason, before assigning a VF to a guest, libvirt
verifies that the related PF netdev is online - if it isn't, then we
log an error and don't allow the guest startup to continue.
Until now, this check was done during virNetDevSetNetConfig(). This
works nicely because the same function is called both for macvtap
passthrough and for VFIO device assignment. But in the case of VFIO,
the VF has already been unbound from its netdev driver by the time we
get to virNetDevSetNetConfig(), and in the case of dual port Mellanox
NICs that have their VFs setup in single port mode, the *only* way to
determine the proper PF netdev to query for online status is via the
"phys_port_id" file that is in the VF netdev's sysfs directory. *BUT*
if we've unbound the VF from the netdev driver, then it doesn't *have*
a netdev sysfs directory.
So, in order to check the correct PF netdev for online status, this
patch moved the check earlier in the setup, into
virNetDevSaveNetConfig(), which is called *before* unbinding the VF
from its netdev driver.
(Note that this implies that if you are using VFIO device assignment
for the VFs of a Mellanox NIC that has the VFs programmed in single
port mode, you must let the VFs be bound to their net driver and use
"managed='yes'" in the device definition. To be more specific, this is
only true if the VFs in single port mode are using port *2* of the PF
- if the VFs are using only port 1, then the correct PF netdev will be
arrived at by default/chance))
This resolves: https://bugzilla.redhat.com/267191
2017-08-10 19:46:38 +00:00
|
|
|
} else if (virNetDevIsVirtualFunction(linkdev) == 1) {
|
2017-02-20 21:14:53 +00:00
|
|
|
/* when vf is -1, linkdev might be a standard netdevice (not
|
|
|
|
* SRIOV), or it might be an SRIOV VF. If it's a VF, normalize
|
|
|
|
* it to PF + VFname
|
|
|
|
*/
|
|
|
|
|
2019-01-22 19:26:13 +00:00
|
|
|
if (virNetDevGetVirtualFunctionInfo(linkdev, &pfDevOrig, &vf) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
pfDevName = pfDevOrig;
|
|
|
|
}
|
|
|
|
|
util: check for PF online status earlier in guest startup
When using a VF from an SRIOV-capable network card in a guest (either
in macvtap passthrough mode, or via VFIO PCI device assignment), The
associated PF netdev must be online in order for the VF to be usable
by the guest. The guest, however, is not able to change the state of
the PF. And libvirt *could* set the PF online as needed, but that
could lead to the host receiving unexpected IPv6 traffic (since the
default for an unconfigured interface is to participate in IPv6
autoconf). For this reason, before assigning a VF to a guest, libvirt
verifies that the related PF netdev is online - if it isn't, then we
log an error and don't allow the guest startup to continue.
Until now, this check was done during virNetDevSetNetConfig(). This
works nicely because the same function is called both for macvtap
passthrough and for VFIO device assignment. But in the case of VFIO,
the VF has already been unbound from its netdev driver by the time we
get to virNetDevSetNetConfig(), and in the case of dual port Mellanox
NICs that have their VFs setup in single port mode, the *only* way to
determine the proper PF netdev to query for online status is via the
"phys_port_id" file that is in the VF netdev's sysfs directory. *BUT*
if we've unbound the VF from the netdev driver, then it doesn't *have*
a netdev sysfs directory.
So, in order to check the correct PF netdev for online status, this
patch moved the check earlier in the setup, into
virNetDevSaveNetConfig(), which is called *before* unbinding the VF
from its netdev driver.
(Note that this implies that if you are using VFIO device assignment
for the VFs of a Mellanox NIC that has the VFs programmed in single
port mode, you must let the VFs be bound to their net driver and use
"managed='yes'" in the device definition. To be more specific, this is
only true if the VFs in single port mode are using port *2* of the PF
- if the VFs are using only port 1, then the correct PF netdev will be
arrived at by default/chance))
This resolves: https://bugzilla.redhat.com/267191
2017-08-10 19:46:38 +00:00
|
|
|
if (pfDevName) {
|
|
|
|
bool pfIsOnline;
|
|
|
|
|
|
|
|
/* Assure that PF is online before trying to use it to set
|
|
|
|
* anything up for this VF. It *should* be online already,
|
|
|
|
* but if it isn't online the changes made to the VF via the
|
|
|
|
* PF won't take effect, yet there will be no error
|
|
|
|
* reported. In the case that the PF isn't online, we need to
|
|
|
|
* fail and report the error, rather than automatically
|
|
|
|
* setting it online, since setting an unconfigured interface
|
|
|
|
* online automatically turns on IPv6 autoconfig, which may
|
|
|
|
* not be what the admin expects, so we require them to
|
|
|
|
* explicitly enable the PF in the host system network config.
|
|
|
|
*/
|
|
|
|
if (virNetDevGetOnline(pfDevName, &pfIsOnline) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: check for PF online status earlier in guest startup
When using a VF from an SRIOV-capable network card in a guest (either
in macvtap passthrough mode, or via VFIO PCI device assignment), The
associated PF netdev must be online in order for the VF to be usable
by the guest. The guest, however, is not able to change the state of
the PF. And libvirt *could* set the PF online as needed, but that
could lead to the host receiving unexpected IPv6 traffic (since the
default for an unconfigured interface is to participate in IPv6
autoconf). For this reason, before assigning a VF to a guest, libvirt
verifies that the related PF netdev is online - if it isn't, then we
log an error and don't allow the guest startup to continue.
Until now, this check was done during virNetDevSetNetConfig(). This
works nicely because the same function is called both for macvtap
passthrough and for VFIO device assignment. But in the case of VFIO,
the VF has already been unbound from its netdev driver by the time we
get to virNetDevSetNetConfig(), and in the case of dual port Mellanox
NICs that have their VFs setup in single port mode, the *only* way to
determine the proper PF netdev to query for online status is via the
"phys_port_id" file that is in the VF netdev's sysfs directory. *BUT*
if we've unbound the VF from the netdev driver, then it doesn't *have*
a netdev sysfs directory.
So, in order to check the correct PF netdev for online status, this
patch moved the check earlier in the setup, into
virNetDevSaveNetConfig(), which is called *before* unbinding the VF
from its netdev driver.
(Note that this implies that if you are using VFIO device assignment
for the VFs of a Mellanox NIC that has the VFs programmed in single
port mode, you must let the VFs be bound to their net driver and use
"managed='yes'" in the device definition. To be more specific, this is
only true if the VFs in single port mode are using port *2* of the PF
- if the VFs are using only port 1, then the correct PF netdev will be
arrived at by default/chance))
This resolves: https://bugzilla.redhat.com/267191
2017-08-10 19:46:38 +00:00
|
|
|
|
|
|
|
if (!pfIsOnline) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to configure VF %d of PF '%s' "
|
|
|
|
"because the PF is not online. Please "
|
|
|
|
"change host network config to put the "
|
|
|
|
"PF online."),
|
|
|
|
vf, pfDevName);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: check for PF online status earlier in guest startup
When using a VF from an SRIOV-capable network card in a guest (either
in macvtap passthrough mode, or via VFIO PCI device assignment), The
associated PF netdev must be online in order for the VF to be usable
by the guest. The guest, however, is not able to change the state of
the PF. And libvirt *could* set the PF online as needed, but that
could lead to the host receiving unexpected IPv6 traffic (since the
default for an unconfigured interface is to participate in IPv6
autoconf). For this reason, before assigning a VF to a guest, libvirt
verifies that the related PF netdev is online - if it isn't, then we
log an error and don't allow the guest startup to continue.
Until now, this check was done during virNetDevSetNetConfig(). This
works nicely because the same function is called both for macvtap
passthrough and for VFIO device assignment. But in the case of VFIO,
the VF has already been unbound from its netdev driver by the time we
get to virNetDevSetNetConfig(), and in the case of dual port Mellanox
NICs that have their VFs setup in single port mode, the *only* way to
determine the proper PF netdev to query for online status is via the
"phys_port_id" file that is in the VF netdev's sysfs directory. *BUT*
if we've unbound the VF from the netdev driver, then it doesn't *have*
a netdev sysfs directory.
So, in order to check the correct PF netdev for online status, this
patch moved the check earlier in the setup, into
virNetDevSaveNetConfig(), which is called *before* unbinding the VF
from its netdev driver.
(Note that this implies that if you are using VFIO device assignment
for the VFs of a Mellanox NIC that has the VFs programmed in single
port mode, you must let the VFs be bound to their net driver and use
"managed='yes'" in the device definition. To be more specific, this is
only true if the VFs in single port mode are using port *2* of the PF
- if the VFs are using only port 1, then the correct PF netdev will be
arrived at by default/chance))
This resolves: https://bugzilla.redhat.com/267191
2017-08-10 19:46:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-04 09:04:33 +00:00
|
|
|
configJSON = virJSONValueNewObject();
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
/* if there is a PF, it's now in pfDevName, and linkdev is either
|
|
|
|
* the VF's name, or NULL (if the VF isn't bound to a net driver
|
|
|
|
* on the host)
|
|
|
|
*/
|
|
|
|
|
util: check for PF online status earlier in guest startup
When using a VF from an SRIOV-capable network card in a guest (either
in macvtap passthrough mode, or via VFIO PCI device assignment), The
associated PF netdev must be online in order for the VF to be usable
by the guest. The guest, however, is not able to change the state of
the PF. And libvirt *could* set the PF online as needed, but that
could lead to the host receiving unexpected IPv6 traffic (since the
default for an unconfigured interface is to participate in IPv6
autoconf). For this reason, before assigning a VF to a guest, libvirt
verifies that the related PF netdev is online - if it isn't, then we
log an error and don't allow the guest startup to continue.
Until now, this check was done during virNetDevSetNetConfig(). This
works nicely because the same function is called both for macvtap
passthrough and for VFIO device assignment. But in the case of VFIO,
the VF has already been unbound from its netdev driver by the time we
get to virNetDevSetNetConfig(), and in the case of dual port Mellanox
NICs that have their VFs setup in single port mode, the *only* way to
determine the proper PF netdev to query for online status is via the
"phys_port_id" file that is in the VF netdev's sysfs directory. *BUT*
if we've unbound the VF from the netdev driver, then it doesn't *have*
a netdev sysfs directory.
So, in order to check the correct PF netdev for online status, this
patch moved the check earlier in the setup, into
virNetDevSaveNetConfig(), which is called *before* unbinding the VF
from its netdev driver.
(Note that this implies that if you are using VFIO device assignment
for the VFs of a Mellanox NIC that has the VFs programmed in single
port mode, you must let the VFs be bound to their net driver and use
"managed='yes'" in the device definition. To be more specific, this is
only true if the VFs in single port mode are using port *2* of the PF
- if the VFs are using only port 1, then the correct PF netdev will be
arrived at by default/chance))
This resolves: https://bugzilla.redhat.com/267191
2017-08-10 19:46:38 +00:00
|
|
|
if (pfDevName && saveVlan) {
|
2019-10-22 13:26:14 +00:00
|
|
|
filePath = g_strdup_printf("%s/%s_vf%d", stateDir, pfDevName, vf);
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
/* get admin MAC and vlan tag */
|
2017-08-13 15:32:31 +00:00
|
|
|
if (virNetDevGetVfConfig(pfDevName, vf, &oldMAC, &oldVlanTag) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (virJSONValueObjectAppendString(configJSON,
|
|
|
|
VIR_NETDEV_KEYNAME_ADMIN_MAC,
|
|
|
|
virMacAddrFormat(&oldMAC, MACStr)) < 0 ||
|
|
|
|
virJSONValueObjectAppendNumberInt(configJSON,
|
|
|
|
VIR_NETDEV_KEYNAME_VLAN_TAG,
|
|
|
|
oldVlanTag) < 0) {
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2019-10-22 13:26:14 +00:00
|
|
|
filePath = g_strdup_printf("%s/%s", stateDir, linkdev);
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (linkdev) {
|
|
|
|
if (virNetDevGetMAC(linkdev, &oldMAC) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
/* for interfaces with no pfDevName (i.e. not a VF, this will
|
|
|
|
* be the only value in the file.
|
|
|
|
*/
|
|
|
|
if (virJSONValueObjectAppendString(configJSON, VIR_NETDEV_KEYNAME_MAC,
|
|
|
|
virMacAddrFormat(&oldMAC, MACStr)) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(fileStr = virJSONValueToString(configJSON, true)))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (virFileWriteStr(filePath, fileStr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to preserve mac/vlan tag "
|
|
|
|
"for device = %s, vf = %d"), linkdev, vf);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevReadNetConfig:
|
|
|
|
* @linkdev: name of the interface
|
|
|
|
* @vf: vf index if linkdev is a pf
|
|
|
|
* @stateDir: directory where net config is stored
|
|
|
|
* @adminMAC: returns admin MAC to store in the PF (if this is a VF)
|
|
|
|
* @MAC: returns MAC to set on device immediately
|
|
|
|
*
|
|
|
|
* Read saved MAC address and (if linkdev itself is a VF, or if @vf >=
|
|
|
|
* 0) "admin MAC address" and vlan tag of the device described by
|
|
|
|
* @linkdev:@vf from a file in @stateDir. (see virNetDevSaveNetConfig
|
|
|
|
* for details of file name and format).
|
|
|
|
*
|
util: restructure virNetDevReadNetConfig() to eliminate false error logs
virHostdevRestoreNetConfig() calls virNetDevReadNetConfig() to try and
read the "original config" of a netdev, and if that fails, it tries
again with a different directory/netdev name. This achieves the
desired effect (we end up finding the config wherever it may be), but
for each failure, virNetDevReadNetConfig() places a nice error message
in the system logs. Experience has shown that false-positive error
logs like this lead to erroneous bug reports, and can often mislead
those searching for *real* bugs.
This patch changes virNetDevReadNetConfig() to explicitly check if the
file exists before calling virFileReadAll(); if it doesn't exist,
virNetDevReadNetConfig() returns a success, but leaves all the
variables holding the results as NULL. (This makes sense if you define
the purpose of the function as "read a netdev's config from its config
file *if that file exists*).
To take advantage of that change, the caller,
virHostdevRestoreNetConfig() is modified to fail immediately if
virNetDevReadNetConfig() returns an error, and otherwise to try the
different directory/netdev name if adminMAC & vlan & MAC are all NULL
after the preceding attempt.
2017-08-10 00:49:26 +00:00
|
|
|
* Returns 0 on success, -1 on failure. It is *NOT* considered failure
|
|
|
|
* if no file is found to read. In that case, adminMAC, vlan, and MAC
|
|
|
|
* are set to NULL, and success is returned.
|
2017-02-20 21:14:53 +00:00
|
|
|
*
|
|
|
|
* The caller MUST free adminMAC, vlan, and MAC when it is finished
|
|
|
|
* with them (they will be NULL if they weren't found in the file)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevReadNetConfig(const char *linkdev, int vf,
|
|
|
|
const char *stateDir,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr **adminMAC,
|
|
|
|
virNetDevVlan **vlan,
|
|
|
|
virMacAddr **MAC)
|
2017-02-20 21:14:53 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
const char *pfDevName = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pfDevOrig = NULL;
|
|
|
|
g_autofree char *vfDevOrig = NULL;
|
|
|
|
g_autofree char *filePath = NULL;
|
|
|
|
g_autofree char *fileStr = NULL;
|
|
|
|
g_autoptr(virJSONValue) configJSON = NULL;
|
2017-02-20 21:14:53 +00:00
|
|
|
const char *MACStr = NULL;
|
|
|
|
const char *adminMACStr = NULL;
|
|
|
|
int vlanTag = -1;
|
|
|
|
|
|
|
|
*adminMAC = NULL;
|
|
|
|
*vlan = NULL;
|
|
|
|
*MAC = NULL;
|
|
|
|
|
|
|
|
if (vf >= 0) {
|
|
|
|
/* linkdev is the PF */
|
|
|
|
pfDevName = linkdev;
|
|
|
|
|
|
|
|
/* linkdev should get the VF's netdev name (or NULL if none) */
|
|
|
|
if (virNetDevPFGetVF(pfDevName, vf, &vfDevOrig) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
linkdev = vfDevOrig;
|
|
|
|
|
|
|
|
} else if (virNetDevIsVirtualFunction(linkdev) == 1) {
|
|
|
|
/* when vf is -1, linkdev might be a standard netdevice (not
|
|
|
|
* SRIOV), or it might be an SRIOV VF. If it's a VF, normalize
|
|
|
|
* it to PF + VFname
|
|
|
|
*/
|
|
|
|
|
2019-01-22 19:26:13 +00:00
|
|
|
if (virNetDevGetVirtualFunctionInfo(linkdev, &pfDevOrig, &vf) < 0)
|
2017-02-20 21:14:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
pfDevName = pfDevOrig;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if there is a PF, it's now in pfDevName, and linkdev is either
|
|
|
|
* the VF's name, or NULL (if the VF isn't bound to a net driver
|
|
|
|
* on the host)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (pfDevName) {
|
2019-10-22 13:26:14 +00:00
|
|
|
filePath = g_strdup_printf("%s/%s_vf%d", stateDir, pfDevName, vf);
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (linkdev && !virFileExists(filePath)) {
|
|
|
|
/* the device may have been stored in a file named for the
|
|
|
|
* VF due to saveVlan == false (or an older version of
|
util: restructure virNetDevReadNetConfig() to eliminate false error logs
virHostdevRestoreNetConfig() calls virNetDevReadNetConfig() to try and
read the "original config" of a netdev, and if that fails, it tries
again with a different directory/netdev name. This achieves the
desired effect (we end up finding the config wherever it may be), but
for each failure, virNetDevReadNetConfig() places a nice error message
in the system logs. Experience has shown that false-positive error
logs like this lead to erroneous bug reports, and can often mislead
those searching for *real* bugs.
This patch changes virNetDevReadNetConfig() to explicitly check if the
file exists before calling virFileReadAll(); if it doesn't exist,
virNetDevReadNetConfig() returns a success, but leaves all the
variables holding the results as NULL. (This makes sense if you define
the purpose of the function as "read a netdev's config from its config
file *if that file exists*).
To take advantage of that change, the caller,
virHostdevRestoreNetConfig() is modified to fail immediately if
virNetDevReadNetConfig() returns an error, and otherwise to try the
different directory/netdev name if adminMAC & vlan & MAC are all NULL
after the preceding attempt.
2017-08-10 00:49:26 +00:00
|
|
|
* libvirt), so reset filePath and pfDevName so we'll try
|
|
|
|
* the other filename.
|
2017-02-20 21:14:53 +00:00
|
|
|
*/
|
|
|
|
VIR_FREE(filePath);
|
|
|
|
pfDevName = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
if (!pfDevName)
|
|
|
|
filePath = g_strdup_printf("%s/%s", stateDir, linkdev);
|
2017-02-20 21:14:53 +00:00
|
|
|
|
util: restructure virNetDevReadNetConfig() to eliminate false error logs
virHostdevRestoreNetConfig() calls virNetDevReadNetConfig() to try and
read the "original config" of a netdev, and if that fails, it tries
again with a different directory/netdev name. This achieves the
desired effect (we end up finding the config wherever it may be), but
for each failure, virNetDevReadNetConfig() places a nice error message
in the system logs. Experience has shown that false-positive error
logs like this lead to erroneous bug reports, and can often mislead
those searching for *real* bugs.
This patch changes virNetDevReadNetConfig() to explicitly check if the
file exists before calling virFileReadAll(); if it doesn't exist,
virNetDevReadNetConfig() returns a success, but leaves all the
variables holding the results as NULL. (This makes sense if you define
the purpose of the function as "read a netdev's config from its config
file *if that file exists*).
To take advantage of that change, the caller,
virHostdevRestoreNetConfig() is modified to fail immediately if
virNetDevReadNetConfig() returns an error, and otherwise to try the
different directory/netdev name if adminMAC & vlan & MAC are all NULL
after the preceding attempt.
2017-08-10 00:49:26 +00:00
|
|
|
if (!virFileExists(filePath)) {
|
|
|
|
/* having no file to read is not necessarily an error, so we
|
|
|
|
* just return success, but with MAC, adminMAC, and vlan set to NULL
|
|
|
|
*/
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-02-20 21:14:53 +00:00
|
|
|
if (virFileReadAll(filePath, 128, &fileStr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (strchr("0123456789abcdefABCDEF", fileStr[0])) {
|
|
|
|
const char *vlanStr = NULL;
|
|
|
|
|
|
|
|
/* old version of file - just two lines of text. Line 1 is the
|
|
|
|
* MAC address (or if line 2 is present, line 1 is adminMAC),
|
|
|
|
* and line 2 (if present) is the vlan tag
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((vlanStr = strchr(fileStr, '\n'))) {
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
/* if there are 2 lines, the first is adminMAC */
|
|
|
|
adminMACStr = fileStr;
|
|
|
|
vlanStr++;
|
|
|
|
|
|
|
|
if ((virStrToLong_i(vlanStr, &endptr, 10, &vlanTag) < 0) ||
|
|
|
|
(endptr && *endptr != '\n' && *endptr != 0)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse vlan tag '%s' from file '%s'"),
|
|
|
|
vlanStr, filePath);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* if there is only one line, it is MAC */
|
|
|
|
MACStr = fileStr;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* if it doesn't start with a hex digit, it is a modern
|
|
|
|
* version of the config file - JSON format as described in
|
|
|
|
* preamble to virNetDevSaveNetConfig()
|
|
|
|
*/
|
|
|
|
if (!(configJSON = virJSONValueFromString(fileStr))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("invalid json in net device saved "
|
|
|
|
"config file '%s': '%.60s'"),
|
|
|
|
filePath, fileStr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACStr = virJSONValueObjectGetString(configJSON,
|
|
|
|
VIR_NETDEV_KEYNAME_MAC);
|
|
|
|
adminMACStr = virJSONValueObjectGetString(configJSON,
|
|
|
|
VIR_NETDEV_KEYNAME_ADMIN_MAC);
|
|
|
|
ignore_value(virJSONValueObjectGetNumberInt(configJSON,
|
|
|
|
VIR_NETDEV_KEYNAME_VLAN_TAG,
|
|
|
|
&vlanTag));
|
|
|
|
|
|
|
|
if (!(MACStr || adminMACStr)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("network device saved config file '%s' "
|
|
|
|
"has unexpected contents, missing both "
|
|
|
|
"'MAC' and 'adminMAC': '%.60s'"),
|
|
|
|
filePath, fileStr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MACStr) {
|
2020-10-05 17:08:12 +00:00
|
|
|
*MAC = g_new0(virMacAddr, 1);
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (virMacAddrParse(MACStr, *MAC) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse MAC address '%s' from file '%s'"),
|
|
|
|
MACStr, filePath);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (adminMACStr) {
|
2020-10-05 17:08:12 +00:00
|
|
|
*adminMAC = g_new0(virMacAddr, 1);
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (virMacAddrParse(adminMACStr, *adminMAC) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse MAC address '%s' from file '%s'"),
|
|
|
|
adminMACStr, filePath);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vlanTag != -1) {
|
|
|
|
/* construct a simple virNetDevVlan object with a single tag */
|
2020-10-05 17:08:12 +00:00
|
|
|
*vlan = g_new0(virNetDevVlan, 1);
|
|
|
|
(*vlan)->tag = g_new0(unsigned int, 1);
|
2017-02-20 21:14:53 +00:00
|
|
|
(*vlan)->nTags = 1;
|
|
|
|
(*vlan)->tag[0] = vlanTag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we won't need the file again */
|
2018-09-20 12:08:19 +00:00
|
|
|
unlink(filePath);
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (ret < 0) {
|
|
|
|
VIR_FREE(*adminMAC);
|
|
|
|
VIR_FREE(*MAC);
|
|
|
|
VIR_FREE(*vlan);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSetNetConfig:
|
|
|
|
* @linkdev: name of the interface
|
|
|
|
* @vf: vf index if linkdev is a PF
|
|
|
|
* @adminMAC: new admin MAC address (will be stored in PF and
|
|
|
|
* used for next initialization of VF driver)
|
|
|
|
* @vlan: new vlan tag info (or NULL)
|
|
|
|
* @MAC: new MAC address to set on the device immediately
|
|
|
|
* @setVlan: true to enable setting vlan tag (even if @vlan is NULL,
|
|
|
|
* the interface vlan tag will be set to 0).
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Set new MAC address and (optionally) admin MAC and vlan tag of
|
|
|
|
* @linkdev VF# @vf.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevSetNetConfig(const char *linkdev, int vf,
|
|
|
|
const virMacAddr *adminMAC,
|
2019-10-01 16:25:47 +00:00
|
|
|
const virNetDevVlan *vlan,
|
2017-02-20 21:14:53 +00:00
|
|
|
const virMacAddr *MAC,
|
|
|
|
bool setVlan)
|
|
|
|
{
|
|
|
|
char MACStr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
const char *pfDevName = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pfDevOrig = NULL;
|
|
|
|
g_autofree char *vfDevOrig = NULL;
|
2017-02-20 21:14:53 +00:00
|
|
|
int vlanTag = -1;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autoptr(virPCIDevice) vfPCIDevice = NULL;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
if (vf >= 0) {
|
|
|
|
/* linkdev is the PF */
|
|
|
|
pfDevName = linkdev;
|
|
|
|
|
|
|
|
/* linkdev should get the VF's netdev name (or NULL if none) */
|
|
|
|
if (virNetDevPFGetVF(pfDevName, vf, &vfDevOrig) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
linkdev = vfDevOrig;
|
|
|
|
|
|
|
|
} else if (virNetDevIsVirtualFunction(linkdev) == 1) {
|
|
|
|
/* when vf is -1, linkdev might be a standard netdevice (not
|
|
|
|
* SRIOV), or it might be an SRIOV VF. If it's a VF, normalize
|
|
|
|
* it to PF + VFname
|
|
|
|
*/
|
|
|
|
|
2019-01-22 19:26:13 +00:00
|
|
|
if (virNetDevGetVirtualFunctionInfo(linkdev, &pfDevOrig, &vf))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
pfDevName = pfDevOrig;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!pfDevName) {
|
|
|
|
/* if it's not SRIOV, then we can't set the admin MAC address
|
|
|
|
* or vlan tag
|
|
|
|
*/
|
|
|
|
if (adminMAC) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("admin MAC can only be set for SR-IOV VFs, but "
|
|
|
|
"%s is not a VF"), linkdev);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vlan) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("vlan can only be set for SR-IOV VFs, but "
|
|
|
|
"%s is not a VF"), linkdev);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (vlan) {
|
|
|
|
if (vlan->nTags != 1 || vlan->trunk) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("vlan trunking is not supported "
|
|
|
|
"by SR-IOV network devices"));
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!setVlan) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("vlan tag set for interface %s but "
|
|
|
|
"caller requested it not be set"));
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vlanTag = vlan->tag[0];
|
|
|
|
|
|
|
|
} else if (setVlan) {
|
|
|
|
vlanTag = 0; /* assure any existing vlan tag is reset */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MAC) {
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
int setMACrc;
|
|
|
|
|
2017-02-20 21:14:53 +00:00
|
|
|
if (!linkdev) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("VF %d of PF '%s' is not bound to a net driver, "
|
|
|
|
"so its MAC address cannot be set to %s"),
|
|
|
|
vf, pfDevName, virMacAddrFormat(MAC, MACStr));
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
setMACrc = virNetDevSetMACInternal(linkdev, MAC, !!pfDevOrig);
|
|
|
|
if (setMACrc < 0) {
|
|
|
|
bool allowRetry = false;
|
|
|
|
int retries = 100;
|
|
|
|
|
|
|
|
/* if pfDevOrig == NULL, this isn't a VF, so we've failed */
|
2017-04-17 14:50:48 +00:00
|
|
|
if (!pfDevOrig ||
|
|
|
|
(errno != EADDRNOTAVAIL && errno != EPERM))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
/* Otherwise this is a VF, and virNetDevSetMAC failed with
|
2017-04-17 14:50:48 +00:00
|
|
|
* EADDRNOTAVAIL/EPERM, which could be due to the
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
* "administratively set" flag being set in the PF for
|
|
|
|
* this VF. When this happens, we can attempt to use an
|
|
|
|
* alternate method to set the VF MAC: first set it into
|
|
|
|
* the admin MAC for this VF in the PF, then unbind/rebind
|
|
|
|
* the VF from its net driver. This causes the VF's MAC to
|
|
|
|
* be initialized to whatever was stored in the admin MAC.
|
2017-02-20 21:14:53 +00:00
|
|
|
*/
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
if (virNetDevSetVfConfig(pfDevName, vf,
|
|
|
|
MAC, vlanTag, &allowRetry) < 0) {
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* admin MAC is set, now we need to construct a virPCIDevice
|
|
|
|
* object so we can call virPCIDeviceRebind()
|
|
|
|
*/
|
|
|
|
if (!(vfPCIDevice = virNetDevGetPCIDevice(linkdev)))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
/* Rebind the device. This should set the proper MAC address */
|
|
|
|
if (virPCIDeviceRebind(vfPCIDevice) < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
/* Wait until virNetDevGetIndex for the VF netdev returns success.
|
|
|
|
* This indicates that the device is ready to be used. If we don't
|
|
|
|
* wait, then upcoming operations on the VF may fail.
|
|
|
|
*/
|
|
|
|
while (retries-- > 0 && !virNetDevExists(linkdev))
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(1000);
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
util: try *really* hard to set the MAC address of an SRIOV VF
If an SRIOV VF has previously been used for VFIO device assignment,
the "admin MAC" that is stored in the PF driver's table of VF info
will have been set to the MAC address that the virtual machine wanted
the device to have. Setting the admin MAC for a VF also sets a flag in
the PF that is loosely called the "administratively set" flag. Once
that flag is set, it is no longer possible for the net driver of the
VF (either on the host or in a virtual machine) to directly set the
VF's MAC again; this flag isn't reset until the *PF* driver is
restarted, and that requires taking *all* VFs offline, so it's not
really feasible to do.
If the same SRIOV VF is later used for macvtap passthrough mode, the
VF's MAC address must be set, but normally we don't unbind the VF from
its host net driver (since we actually need the host net driver in
this case). Since setting the VF MAC directly will fail, in the past
"we" ("I") had tried to fix the problem by simply setting the admin MAC
(via the PF) instead. This *appeared* to work (and might have at one
time, due to promiscuous mode being turned on somewhere or something),
but it currently creates a non-working interface because only the
value for admin MAC is set to the desired value, *not* the actual MAC
that the VF is using.
Earlier patches in this series reverted that behavior, so that we once
again set the MAC of the VF itself for macvtap passthrough operation,
not the admin MAC. But that brings back the original bug - if the
interface has been used for VFIO device assignment, you can no longer
use it for macvtap passthrough.
This patch solves that problem by noticing when virNetDevSetMAC()
fails for a VF, and in that case it sets the desired MAC to the admin
MAC via the PF, then "bounces" the VF driver (by unbinding and the
immediately rebinding it to the VF). This causes the VF's MAC to be
reinitialized from the admin MAC, and everybody is happy (until the
*next* time someone wants to set the VF's MAC address, since the
"administratively set" bit is still turned on).
2017-03-07 19:24:37 +00:00
|
|
|
|
|
|
|
if (pfDevOrig && setMACrc == 0) {
|
|
|
|
/* if pfDevOrig is set, it that the caller was *really*
|
|
|
|
* only interested in setting the MAC of the VF itself,
|
|
|
|
* *not* the admin MAC via the PF. In those cases, the
|
|
|
|
* adminMAC was only provided in case we need to set the
|
|
|
|
* VF's MAC by temporarily unbinding/rebinding the VF's
|
|
|
|
* net driver with the admin MAC set to the desired MAC,
|
|
|
|
* and then want to restore the admin MAC to its original
|
|
|
|
* setting when we're finished. We would only need to do
|
|
|
|
* that if the virNetDevSetMAC() above had failed; since
|
|
|
|
* setMACrc == 0, we know it didn't fail and we don't need
|
|
|
|
* to set the adminMAC, so we are NULLing it out here to
|
|
|
|
* avoid that below.
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
* (NB: since setting the admin MAC sets the
|
|
|
|
* "administratively set" flag for the VF in the PF's
|
|
|
|
* driver, which prevents any future changes to the VF's
|
|
|
|
* MAC address, we want to avoid setting the admin MAC as
|
|
|
|
* much as possible.)
|
|
|
|
*/
|
|
|
|
adminMAC = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (adminMAC || vlanTag >= 0) {
|
|
|
|
/* Set vlanTag and admin MAC using an RTM_SETLINK request sent to
|
|
|
|
* PFdevname+VF#, if mac != NULL this will set the "admin MAC" via
|
|
|
|
* the PF, *not* the actual VF MAC - the admin MAC only takes
|
|
|
|
* effect the next time the VF's driver is initialized (either in
|
|
|
|
* guest or host). if there is a vlanTag to set, it will take
|
|
|
|
* effect immediately though.
|
|
|
|
*/
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
bool allowRetry = true;
|
|
|
|
|
|
|
|
if (virNetDevSetVfConfig(pfDevName, vf,
|
|
|
|
adminMAC, vlanTag, &allowRetry) < 0) {
|
|
|
|
/* allowRetry will still be true if the failure was due to
|
|
|
|
* trying to set the MAC address to all 0. In that case,
|
|
|
|
* we can retry with "altZeroMAC", which is just an all-0 MAC
|
|
|
|
* with the "locally administered" bit set.
|
|
|
|
*/
|
|
|
|
if (!allowRetry)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
|
|
|
|
allowRetry = false;
|
|
|
|
if (virNetDevSetVfConfig(pfDevName, vf,
|
|
|
|
&altZeroMAC, vlanTag, &allowRetry) < 0) {
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
util: if setting admin MAC to 00:00:00:00:00:00 fails, try 02:00:00:00:00:00
Some PF drivers allow setting the admin MAC (that is the MAC address
that the VF will be initialized to the next time the VF's driver is
loaded) to 00:00:00:00:00:00, and some don't. Multiple drivers
initialize the admin MACs to all 0, but don't allow setting it to that
very same value. It has been an uphill battle convincing the driver
people that it's reasonable to expect The argument that's used is
that an all 0 device MAC address on a device is invalid; however, from
an outsider's point of view, when the admin MAC is set to 0 at the
time the VF driver is loaded, the VF's MAC is *not* set to 0, but to a
random non-0 value. But that's beside the point - even if I could
convince one or two SRIOV driver maintainers to permit setting the
admin MAC to 0, there are still several other drivers.
So rather than fighting that losing battle, this patch checks for a
failure to set the admin MAC due to an all 0 value, and retries it
with 02:00:00:00:00:00. That won't result in a random value being set
in the VF MAC at next VF driver init, but that's okay, because we
always want to set a specific value anyway. Rather, the "almost 0"
setting makes it easy to visually detect from the output of "ip link
show" which VFs are currently in use and which are free.
2017-03-06 18:59:29 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-28 21:29:41 +00:00
|
|
|
#else /* defined(WITH_LIBNL) */
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2017-02-20 21:14:53 +00:00
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevSaveNetConfig(const char *linkdev G_GNUC_UNUSED,
|
|
|
|
int vf G_GNUC_UNUSED,
|
|
|
|
const char *stateDir G_GNUC_UNUSED,
|
|
|
|
bool saveVlan G_GNUC_UNUSED)
|
2017-02-20 21:14:53 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to save net device config on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevReadNetConfig(const char *linkdev G_GNUC_UNUSED,
|
|
|
|
int vf G_GNUC_UNUSED,
|
|
|
|
const char *stateDir G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr **adminMAC G_GNUC_UNUSED,
|
|
|
|
virNetDevVlan **vlan G_GNUC_UNUSED,
|
|
|
|
virMacAddr **MAC G_GNUC_UNUSED)
|
2017-02-20 21:14:53 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to read net device config on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevSetNetConfig(const char *linkdev G_GNUC_UNUSED,
|
|
|
|
int vf G_GNUC_UNUSED,
|
|
|
|
const virMacAddr *adminMAC G_GNUC_UNUSED,
|
2019-10-01 16:25:47 +00:00
|
|
|
const virNetDevVlan *vlan G_GNUC_UNUSED,
|
2019-10-14 12:45:33 +00:00
|
|
|
const virMacAddr *MAC G_GNUC_UNUSED,
|
|
|
|
bool setVlan G_GNUC_UNUSED)
|
2017-02-20 21:14:53 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to set net device config on this platform"));
|
|
|
|
return -1;
|
2020-10-15 11:21:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevVFInterfaceStats(virPCIDeviceAddress *vfAddr G_GNUC_UNUSED,
|
2020-10-15 11:21:14 +00:00
|
|
|
virDomainInterfaceStatsPtr stats G_GNUC_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get VF net device stats on this platform"));
|
|
|
|
return -1;
|
2017-02-20 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-28 21:29:41 +00:00
|
|
|
#endif /* defined(WITH_LIBNL) */
|
2014-06-05 14:14:49 +00:00
|
|
|
|
2016-06-13 17:06:15 +00:00
|
|
|
VIR_ENUM_IMPL(virNetDevIfState,
|
|
|
|
VIR_NETDEV_IF_STATE_LAST,
|
|
|
|
"" /* value of zero means no state */,
|
|
|
|
"unknown", "notpresent",
|
|
|
|
"down", "lowerlayerdown",
|
2019-01-20 16:30:15 +00:00
|
|
|
"testing", "dormant", "up",
|
|
|
|
);
|
2016-06-13 17:06:15 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virNetDevFeature,
|
|
|
|
VIR_NET_DEV_FEAT_LAST,
|
|
|
|
"rx",
|
|
|
|
"tx",
|
|
|
|
"sg",
|
|
|
|
"tso",
|
|
|
|
"gso",
|
|
|
|
"gro",
|
|
|
|
"lro",
|
|
|
|
"rxvlan",
|
|
|
|
"txvlan",
|
|
|
|
"ntuple",
|
|
|
|
"rxhash",
|
|
|
|
"rdma",
|
2017-08-21 09:19:53 +00:00
|
|
|
"txudptnl",
|
2019-01-20 16:30:15 +00:00
|
|
|
"switchdev",
|
|
|
|
);
|
2016-06-13 17:06:15 +00:00
|
|
|
|
2014-06-05 14:14:49 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
int
|
|
|
|
virNetDevGetLinkInfo(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevIfLink *lnk)
|
2014-06-05 14:14:49 +00:00
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *path = NULL;
|
|
|
|
g_autofree char *buf = NULL;
|
2014-06-05 14:14:49 +00:00
|
|
|
char *tmp;
|
|
|
|
int tmp_state;
|
|
|
|
unsigned int tmp_speed;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&path, ifname, "operstate") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
|
2020-04-16 15:57:46 +00:00
|
|
|
/* The device may have been removed or moved by the time we got here.
|
|
|
|
* Obviously attempting to get LinkInfo on a no longer existing device
|
|
|
|
* is useless, so stop processing. If we got here via the udev monitor
|
|
|
|
* a remove or move event will follow and we will be able to get valid
|
|
|
|
* LinkInfo at that time */
|
|
|
|
if (!virFileExists(path)) {
|
|
|
|
VIR_INFO("The interface '%s' was removed before we could query it.",
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-06-05 14:14:49 +00:00
|
|
|
if (virFileReadAll(path, 1024, &buf) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("unable to read: %s"),
|
|
|
|
path);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(tmp = strchr(buf, '\n'))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse: %s"),
|
|
|
|
buf);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*tmp = '\0';
|
|
|
|
|
|
|
|
/* We shouldn't allow 0 here, because
|
|
|
|
* virInterfaceState enum starts from 1. */
|
2016-06-13 17:06:15 +00:00
|
|
|
if ((tmp_state = virNetDevIfStateTypeFromString(buf)) <= 0) {
|
2014-06-05 14:14:49 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse: %s"),
|
|
|
|
buf);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lnk->state = tmp_state;
|
|
|
|
|
2014-06-13 09:29:48 +00:00
|
|
|
/* Shortcut to avoid some kernel issues. If link is not up several drivers
|
|
|
|
* report several misleading values. While igb reports 65535, realtek goes
|
|
|
|
* with 10. To avoid muddying XML with insane values, don't report link
|
|
|
|
* speed if that's the case. */
|
2016-06-13 17:06:15 +00:00
|
|
|
if (lnk->state != VIR_NETDEV_IF_STATE_UP) {
|
2014-06-13 09:29:48 +00:00
|
|
|
lnk->speed = 0;
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2014-06-13 09:29:48 +00:00
|
|
|
}
|
|
|
|
|
2014-06-05 14:14:49 +00:00
|
|
|
VIR_FREE(path);
|
|
|
|
VIR_FREE(buf);
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&path, ifname, "speed") < 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
|
2014-06-30 13:00:33 +00:00
|
|
|
if (virFileReadAllQuiet(path, 1024, &buf) < 0) {
|
2014-06-05 14:14:49 +00:00
|
|
|
/* Some devices doesn't report speed, in which case we get EINVAL */
|
2020-04-19 05:24:40 +00:00
|
|
|
if (errno == EINVAL)
|
|
|
|
return 0;
|
2014-06-05 14:14:49 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("unable to read: %s"),
|
|
|
|
path);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrToLong_ui(buf, &tmp, 10, &tmp_speed) < 0 ||
|
|
|
|
*tmp != '\n') {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse: %s"),
|
|
|
|
buf);
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-06-05 14:14:49 +00:00
|
|
|
}
|
|
|
|
|
2014-06-13 09:29:48 +00:00
|
|
|
lnk->speed = tmp_speed;
|
2014-06-05 14:14:49 +00:00
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2014-06-05 14:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetDevGetLinkInfo(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevIfLink *lnk)
|
2014-06-05 14:14:49 +00:00
|
|
|
{
|
|
|
|
/* Port me */
|
2014-06-11 11:05:17 +00:00
|
|
|
VIR_DEBUG("Getting link info on %s is not implemented on this platform",
|
|
|
|
ifname);
|
2014-06-05 14:14:49 +00:00
|
|
|
lnk->speed = lnk->state = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* defined(__linux__) */
|
2014-09-20 18:39:44 +00:00
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCADDMULTI) && defined(WITH_STRUCT_IFREQ) && \
|
|
|
|
defined(WITH_STRUCT_IFREQ_IFR_HWADDR)
|
2014-10-10 17:55:42 +00:00
|
|
|
/**
|
|
|
|
* virNetDevAddMulti:
|
|
|
|
* @ifname: interface name to which to add multicast MAC address
|
|
|
|
* @macaddr: MAC address
|
|
|
|
*
|
|
|
|
* This function adds the @macaddr to the multicast list for a given interface
|
|
|
|
* @ifname.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevAddMulti(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr *macaddr)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
|
|
|
virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data);
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCADDMULTI, &ifr) < 0) {
|
|
|
|
char macstr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot add multicast MAC %s on '%s' interface"),
|
|
|
|
virMacAddrFormat(macaddr, macstr), ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2014-10-10 17:55:42 +00:00
|
|
|
}
|
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevAddMulti(const char *ifname G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr *macaddr G_GNUC_UNUSED)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to add address to interface "
|
|
|
|
"multicast list on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCDELMULTI) && defined(WITH_STRUCT_IFREQ) && \
|
|
|
|
defined(WITH_STRUCT_IFREQ_IFR_HWADDR)
|
2014-10-10 17:55:42 +00:00
|
|
|
/**
|
|
|
|
* virNetDevDelMulti:
|
|
|
|
* @ifname: interface name from which to delete the multicast MAC address
|
|
|
|
* @macaddr: MAC address
|
|
|
|
*
|
|
|
|
* This function deletes the @macaddr from the multicast list for a given
|
|
|
|
* interface @ifname.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevDelMulti(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr *macaddr)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
|
|
|
virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data);
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCDELMULTI, &ifr) < 0) {
|
|
|
|
char macstr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot add multicast MAC %s on '%s' interface"),
|
|
|
|
virMacAddrFormat(macaddr, macstr), ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2014-10-10 17:55:42 +00:00
|
|
|
}
|
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevDelMulti(const char *ifname G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacAddr *macaddr G_GNUC_UNUSED)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to delete address from interface "
|
|
|
|
"multicast list on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static int virNetDevParseMcast(char *buf, virNetDevMcastEntry *mcast)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
int ifindex;
|
|
|
|
int num;
|
|
|
|
char *next;
|
|
|
|
char *token;
|
|
|
|
char *saveptr;
|
|
|
|
char *endptr;
|
|
|
|
|
2015-08-01 05:43:58 +00:00
|
|
|
for (ifindex = VIR_MCAST_TYPE_INDEX_TOKEN, next = buf; ifindex < VIR_MCAST_TYPE_LAST; ifindex++,
|
2014-10-10 17:55:42 +00:00
|
|
|
next = NULL) {
|
|
|
|
token = strtok_r(next, VIR_MCAST_TOKEN_DELIMS, &saveptr);
|
|
|
|
|
|
|
|
if (token == NULL) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("failed to parse multicast address from '%s'"),
|
|
|
|
buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-29 20:57:58 +00:00
|
|
|
switch ((virMCastType)ifindex) {
|
|
|
|
case VIR_MCAST_TYPE_INDEX_TOKEN:
|
2014-10-10 17:55:42 +00:00
|
|
|
if (virStrToLong_i(token, &endptr, 10, &num) < 0) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Failed to parse interface index from '%s'"),
|
|
|
|
buf);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
2015-04-14 11:34:24 +00:00
|
|
|
mcast->idx = num;
|
2014-10-10 17:55:42 +00:00
|
|
|
break;
|
2014-10-29 20:57:58 +00:00
|
|
|
case VIR_MCAST_TYPE_NAME_TOKEN:
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpy(mcast->name, token, VIR_MCAST_NAME_LEN) < 0) {
|
2014-10-10 17:55:42 +00:00
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Failed to parse network device name from '%s'"),
|
|
|
|
buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
2014-10-29 20:57:58 +00:00
|
|
|
case VIR_MCAST_TYPE_USERS_TOKEN:
|
2014-10-10 17:55:42 +00:00
|
|
|
if (virStrToLong_i(token, &endptr, 10, &num) < 0) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Failed to parse users from '%s'"),
|
|
|
|
buf);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
mcast->users = num;
|
|
|
|
break;
|
2014-10-29 20:57:58 +00:00
|
|
|
case VIR_MCAST_TYPE_GLOBAL_TOKEN:
|
2014-10-10 17:55:42 +00:00
|
|
|
if (virStrToLong_i(token, &endptr, 10, &num) < 0) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Failed to parse users from '%s'"),
|
|
|
|
buf);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
mcast->global = num;
|
|
|
|
break;
|
2014-10-29 20:57:58 +00:00
|
|
|
case VIR_MCAST_TYPE_ADDR_TOKEN:
|
2014-10-10 17:55:42 +00:00
|
|
|
if (virMacAddrParseHex((const char*)token,
|
2018-09-19 08:38:14 +00:00
|
|
|
&mcast->macaddr) < 0) {
|
2014-10-10 17:55:42 +00:00
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Failed to parse MAC address from '%s'"),
|
|
|
|
buf);
|
|
|
|
}
|
|
|
|
break;
|
2014-10-29 20:57:58 +00:00
|
|
|
|
|
|
|
/* coverity[dead_error_begin] */
|
|
|
|
case VIR_MCAST_TYPE_LAST:
|
2014-10-10 17:55:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static void virNetDevMcastListClear(virNetDevMcastList *mcast)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < mcast->nentries; i++)
|
|
|
|
VIR_FREE(mcast->entries[i]);
|
|
|
|
VIR_FREE(mcast->entries);
|
|
|
|
mcast->nentries = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int virNetDevGetMcastList(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevMcastList *mcast)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
char *cur = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *buf = NULL;
|
2014-10-10 17:55:42 +00:00
|
|
|
char *next = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
int len;
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virNetDevMcastEntry) entry = NULL;
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
mcast->entries = NULL;
|
|
|
|
mcast->nentries = 0;
|
|
|
|
|
|
|
|
/* Read entire multicast table into memory */
|
|
|
|
if ((len = virFileReadAll(PROC_NET_DEV_MCAST, MAX_MCAST_SIZE, &buf)) <= 0)
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
cur = buf;
|
|
|
|
while (cur) {
|
2020-10-05 17:08:12 +00:00
|
|
|
if (!entry)
|
|
|
|
entry = g_new0(virNetDevMcastEntry, 1);
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
next = strchr(cur, '\n');
|
|
|
|
if (next)
|
|
|
|
next++;
|
|
|
|
if (virNetDevParseMcast(cur, entry))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
/* Only return global multicast MAC addresses for
|
|
|
|
* specified interface */
|
|
|
|
if (entry->global && STREQ(ifname, entry->name)) {
|
|
|
|
if (VIR_APPEND_ELEMENT(mcast->entries, mcast->nentries, entry))
|
2020-04-19 05:24:40 +00:00
|
|
|
return -1;
|
2014-10-10 17:55:42 +00:00
|
|
|
} else {
|
|
|
|
memset(entry, 0, sizeof(virNetDevMcastEntry));
|
|
|
|
}
|
|
|
|
cur = next && ((next - buf) < len) ? next : NULL;
|
|
|
|
}
|
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return 0;
|
2014-10-10 17:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-20 18:39:44 +00:00
|
|
|
VIR_ENUM_IMPL(virNetDevRxFilterMode,
|
|
|
|
VIR_NETDEV_RX_FILTER_MODE_LAST,
|
|
|
|
"none",
|
|
|
|
"normal",
|
2019-01-20 16:30:15 +00:00
|
|
|
"all",
|
|
|
|
);
|
2014-09-20 18:39:44 +00:00
|
|
|
|
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
static int virNetDevGetMulticastTable(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevRxFilter *filter)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int ret = -1;
|
|
|
|
virNetDevMcastList mcast;
|
|
|
|
filter->multicast.nTable = 0;
|
|
|
|
filter->multicast.table = NULL;
|
|
|
|
|
|
|
|
if (virNetDevGetMcastList(ifname, &mcast) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (mcast.nentries > 0) {
|
2020-10-05 17:08:12 +00:00
|
|
|
filter->multicast.table = g_new0(virMacAddr, mcast.nentries);
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
for (i = 0; i < mcast.nentries; i++) {
|
|
|
|
virMacAddrSet(&filter->multicast.table[i],
|
|
|
|
&mcast.entries[i]->macaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
filter->multicast.nTable = mcast.nentries;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2015-07-19 10:11:07 +00:00
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
cleanup:
|
|
|
|
virNetDevMcastListClear(&mcast);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevRxFilter *
|
2014-09-20 18:39:44 +00:00
|
|
|
virNetDevRxFilterNew(void)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevRxFilter *filter;
|
2014-09-20 18:39:44 +00:00
|
|
|
|
2020-10-05 17:08:12 +00:00
|
|
|
filter = g_new0(virNetDevRxFilter, 1);
|
2014-09-20 18:39:44 +00:00
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevRxFilterFree(virNetDevRxFilter *filter)
|
2014-09-20 18:39:44 +00:00
|
|
|
{
|
|
|
|
if (filter) {
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(filter->name);
|
|
|
|
g_free(filter->unicast.table);
|
|
|
|
g_free(filter->multicast.table);
|
|
|
|
g_free(filter->vlan.table);
|
|
|
|
g_free(filter);
|
2014-09-20 18:39:44 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGetRxFilter:
|
|
|
|
* This function supplies the RX filter list for a given device interface
|
|
|
|
*
|
|
|
|
* @ifname: Name of the interface
|
|
|
|
* @filter: The RX filter list
|
|
|
|
*
|
|
|
|
* Returns 0 or -1 on failure.
|
|
|
|
*/
|
|
|
|
int virNetDevGetRxFilter(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevRxFilter **filter)
|
2014-10-10 17:55:42 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
2015-02-03 10:20:40 +00:00
|
|
|
bool receive = false;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevRxFilter *fil = virNetDevRxFilterNew();
|
2014-10-10 17:55:42 +00:00
|
|
|
|
|
|
|
if (!fil)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetDevGetMAC(ifname, &fil->mac))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetDevGetMulticastTable(ifname, fil))
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-01-22 19:47:02 +00:00
|
|
|
if (virNetDevGetPromiscuous(ifname, &fil->promiscuous))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetDevGetRcvAllMulti(ifname, &receive))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (receive) {
|
|
|
|
fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_ALL;
|
|
|
|
} else {
|
|
|
|
if (virNetDevGetRcvMulti(ifname, &receive))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (receive)
|
|
|
|
fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_NORMAL;
|
|
|
|
else
|
|
|
|
fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_NONE;
|
|
|
|
}
|
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (ret < 0) {
|
|
|
|
virNetDevRxFilterFree(fil);
|
|
|
|
fil = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*filter = fil;
|
|
|
|
return ret;
|
|
|
|
}
|
2015-02-23 15:38:29 +00:00
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#if defined(SIOCETHTOOL) && defined(WITH_STRUCT_IFREQ)
|
2015-07-19 10:11:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevRDMAFeature
|
|
|
|
* This function checks for the availability of RDMA feature
|
|
|
|
* and add it to bitmap
|
|
|
|
*
|
|
|
|
* @ifname: name of the interface
|
|
|
|
* @out: add RDMA feature if exist to bitmap
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetDevRDMAFeature(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap **out)
|
2015-07-19 10:11:07 +00:00
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *eth_devpath = NULL;
|
|
|
|
g_autofree char *eth_res_buf = NULL;
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) dirp = NULL;
|
2015-07-19 10:11:07 +00:00
|
|
|
struct dirent *dp;
|
|
|
|
|
2015-07-23 18:33:32 +00:00
|
|
|
if (!virFileExists(SYSFS_INFINIBAND_DIR))
|
|
|
|
return 0;
|
|
|
|
|
2016-06-21 14:34:08 +00:00
|
|
|
if (virDirOpen(&dirp, SYSFS_INFINIBAND_DIR) < 0)
|
2016-02-25 11:50:12 +00:00
|
|
|
return -1;
|
2015-07-19 10:11:07 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
eth_devpath = g_strdup_printf(SYSFS_NET_DIR "%s/device/resource", ifname);
|
2019-03-07 16:52:55 +00:00
|
|
|
|
|
|
|
/* If /sys/class/net/<ifname>/device/resource doesn't exist it is not a PCI
|
|
|
|
* device and therefore it will not have RDMA. */
|
|
|
|
if (!virFileExists(eth_devpath)) {
|
2020-10-27 21:49:11 +00:00
|
|
|
return 0;
|
2019-03-07 16:52:55 +00:00
|
|
|
}
|
|
|
|
|
2015-07-19 10:11:07 +00:00
|
|
|
if (virFileReadAll(eth_devpath, RESOURCE_FILE_LEN, ð_res_buf) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2015-07-19 10:11:07 +00:00
|
|
|
|
|
|
|
while (virDirRead(dirp, &dp, SYSFS_INFINIBAND_DIR) > 0) {
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *ib_res_buf = NULL;
|
|
|
|
g_autofree char *ib_devpath = g_strdup_printf(SYSFS_INFINIBAND_DIR "%s/device/resource",
|
|
|
|
dp->d_name);
|
|
|
|
|
2015-07-19 10:11:07 +00:00
|
|
|
if (virFileReadAll(ib_devpath, RESOURCE_FILE_LEN, &ib_res_buf) > 0 &&
|
|
|
|
STREQ(eth_res_buf, ib_res_buf)) {
|
|
|
|
ignore_value(virBitmapSetBit(*out, VIR_NET_DEV_FEAT_RDMA));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-27 21:49:11 +00:00
|
|
|
return 0;
|
2015-07-19 10:11:07 +00:00
|
|
|
}
|
|
|
|
|
2015-02-23 15:38:29 +00:00
|
|
|
|
|
|
|
/**
|
2015-07-19 10:11:07 +00:00
|
|
|
* virNetDevSendEthtoolIoctl
|
|
|
|
* This function sends ethtool ioctl request
|
2015-02-23 15:38:29 +00:00
|
|
|
*
|
2016-06-03 18:46:05 +00:00
|
|
|
* @fd: socket to operate on
|
|
|
|
* @ifr: struct ifreq with the command
|
2015-02-23 15:38:29 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
static int
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevSendEthtoolIoctl(const char *ifname, int fd, struct ifreq *ifr)
|
2015-02-23 15:38:29 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
2015-11-03 14:17:42 +00:00
|
|
|
|
2016-06-03 18:46:05 +00:00
|
|
|
ret = ioctl(fd, SIOCETHTOOL, ifr);
|
2015-11-03 14:17:42 +00:00
|
|
|
if (ret != 0) {
|
|
|
|
switch (errno) {
|
2016-06-07 12:00:22 +00:00
|
|
|
case EINVAL: /* kernel doesn't support SIOCETHTOOL */
|
2020-09-02 18:32:49 +00:00
|
|
|
VIR_DEBUG("ethtool ioctl: invalid request on %s", ifname);
|
2016-06-07 12:00:22 +00:00
|
|
|
break;
|
|
|
|
case EOPNOTSUPP: /* kernel doesn't support specific feature */
|
2020-09-02 18:32:49 +00:00
|
|
|
VIR_DEBUG("ethtool ioctl: request not supported on %s", ifname);
|
2016-06-07 12:00:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
2020-09-02 18:32:49 +00:00
|
|
|
virReportSystemError(errno, _("ethtool ioctl error on %s"), ifname);
|
2016-06-07 12:00:22 +00:00
|
|
|
break;
|
2015-11-03 14:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-23 15:38:29 +00:00
|
|
|
|
2015-07-19 10:11:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2015-02-23 15:38:29 +00:00
|
|
|
|
2016-06-03 18:01:44 +00:00
|
|
|
struct virNetDevEthtoolFeatureCmd {
|
|
|
|
const int cmd;
|
|
|
|
const virNetDevFeature feat;
|
|
|
|
};
|
|
|
|
|
2015-07-19 10:11:07 +00:00
|
|
|
|
|
|
|
/**
|
2016-06-07 12:06:24 +00:00
|
|
|
* virNetDevFeatureAvailable
|
|
|
|
* This function checks for the availability of a network device feature
|
|
|
|
*
|
2016-06-03 18:46:05 +00:00
|
|
|
* @fd: socket to operate on
|
|
|
|
* @ifr: struct ifreq with the command
|
2016-06-07 12:06:24 +00:00
|
|
|
* @cmd: reference to an ethtool command structure
|
|
|
|
*
|
2016-06-03 18:44:23 +00:00
|
|
|
* Returns true if the feature is available, false otherwise.
|
2016-06-07 12:06:24 +00:00
|
|
|
*/
|
2016-06-03 18:44:23 +00:00
|
|
|
static bool
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevFeatureAvailable(const char *ifname, int fd, struct ifreq *ifr, struct ethtool_value *cmd)
|
2015-07-19 10:11:07 +00:00
|
|
|
{
|
2016-06-03 18:46:05 +00:00
|
|
|
ifr->ifr_data = (void*)cmd;
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevSendEthtoolIoctl(ifname, fd, ifr) == 0 &&
|
2016-06-03 18:44:23 +00:00
|
|
|
cmd->data > 0)
|
|
|
|
return true;
|
|
|
|
return false;
|
2015-02-23 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-03 18:18:25 +00:00
|
|
|
static void
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevGetEthtoolFeatures(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *bitmap,
|
2016-06-03 18:46:05 +00:00
|
|
|
int fd,
|
|
|
|
struct ifreq *ifr)
|
2016-06-03 18:18:25 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
struct ethtool_value cmd = { 0 };
|
|
|
|
|
|
|
|
/* legacy ethtool getters */
|
|
|
|
struct virNetDevEthtoolFeatureCmd ethtool_cmds[] = {
|
|
|
|
{ETHTOOL_GRXCSUM, VIR_NET_DEV_FEAT_GRXCSUM},
|
|
|
|
{ETHTOOL_GTXCSUM, VIR_NET_DEV_FEAT_GTXCSUM},
|
|
|
|
{ETHTOOL_GSG, VIR_NET_DEV_FEAT_GSG},
|
|
|
|
{ETHTOOL_GTSO, VIR_NET_DEV_FEAT_GTSO},
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETHTOOL_GGSO
|
2016-06-03 18:18:25 +00:00
|
|
|
{ETHTOOL_GGSO, VIR_NET_DEV_FEAT_GGSO},
|
|
|
|
# endif
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETHTOOL_GGRO
|
2016-06-03 18:18:25 +00:00
|
|
|
{ETHTOOL_GGRO, VIR_NET_DEV_FEAT_GGRO},
|
|
|
|
# endif
|
|
|
|
};
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETHTOOL_GFLAGS
|
2016-06-03 18:18:25 +00:00
|
|
|
/* ethtool masks */
|
|
|
|
struct virNetDevEthtoolFeatureCmd flags[] = {
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETH_FLAG_LRO
|
2016-06-03 18:18:25 +00:00
|
|
|
{ETH_FLAG_LRO, VIR_NET_DEV_FEAT_LRO},
|
|
|
|
# endif
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETH_FLAG_TXVLAN
|
2016-06-03 18:18:25 +00:00
|
|
|
{ETH_FLAG_RXVLAN, VIR_NET_DEV_FEAT_RXVLAN},
|
|
|
|
{ETH_FLAG_TXVLAN, VIR_NET_DEV_FEAT_TXVLAN},
|
|
|
|
# endif
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETH_FLAG_NTUBLE
|
2016-06-03 18:18:25 +00:00
|
|
|
{ETH_FLAG_NTUPLE, VIR_NET_DEV_FEAT_NTUPLE},
|
|
|
|
# endif
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETH_FLAG_RXHASH
|
2016-06-03 18:18:25 +00:00
|
|
|
{ETH_FLAG_RXHASH, VIR_NET_DEV_FEAT_RXHASH},
|
|
|
|
# endif
|
|
|
|
};
|
|
|
|
# endif
|
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(ethtool_cmds); i++) {
|
2016-06-03 18:18:25 +00:00
|
|
|
cmd.cmd = ethtool_cmds[i].cmd;
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevFeatureAvailable(ifname, fd, ifr, &cmd))
|
2016-06-03 18:18:25 +00:00
|
|
|
ignore_value(virBitmapSetBit(bitmap, ethtool_cmds[i].feat));
|
|
|
|
}
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETHTOOL_GFLAGS
|
2016-06-03 18:18:25 +00:00
|
|
|
cmd.cmd = ETHTOOL_GFLAGS;
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevFeatureAvailable(ifname, fd, ifr, &cmd)) {
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(flags); i++) {
|
2016-06-03 18:18:25 +00:00
|
|
|
if (cmd.data & flags[i].cmd)
|
|
|
|
ignore_value(virBitmapSetBit(bitmap, flags[i].feat));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-30 20:36:52 +00:00
|
|
|
# if defined(WITH_LIBNL) && WITH_DECL_DEVLINK_CMD_ESWITCH_GET
|
2017-08-21 09:19:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGetFamilyId:
|
|
|
|
* This function supplies the devlink family id
|
|
|
|
*
|
|
|
|
* @family_name: the name of the family to query
|
2020-04-19 06:26:04 +00:00
|
|
|
* @family_id: family ID
|
2017-08-21 09:19:53 +00:00
|
|
|
*
|
2020-04-19 06:26:04 +00:00
|
|
|
* Returns: 0 if no family was found,
|
|
|
|
* 1 if family was found (@family_id is set),
|
|
|
|
* -1 otherwise
|
2017-08-21 09:19:53 +00:00
|
|
|
*/
|
2020-04-19 06:26:04 +00:00
|
|
|
static int
|
|
|
|
virNetDevGetFamilyId(const char *family_name,
|
|
|
|
uint32_t *family_id)
|
2017-08-21 09:19:53 +00:00
|
|
|
{
|
|
|
|
struct nl_msg *nl_msg = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree struct nlmsghdr *resp = NULL;
|
2018-09-07 08:14:46 +00:00
|
|
|
struct genlmsghdr gmsgh = {
|
|
|
|
.cmd = CTRL_CMD_GETFAMILY,
|
|
|
|
.version = DEVLINK_GENL_VERSION,
|
|
|
|
.reserved = 0,
|
|
|
|
};
|
2017-08-21 09:19:53 +00:00
|
|
|
struct nlattr *tb[CTRL_ATTR_MAX + 1] = {NULL, };
|
|
|
|
unsigned int recvbuflen;
|
2020-04-19 06:26:04 +00:00
|
|
|
int ret = -1;
|
2017-08-21 09:19:53 +00:00
|
|
|
|
2021-02-24 08:51:19 +00:00
|
|
|
nl_msg = virNetlinkMsgNew(GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK);
|
2017-08-21 09:19:53 +00:00
|
|
|
|
2018-09-07 08:14:46 +00:00
|
|
|
if (nlmsg_append(nl_msg, &gmsgh, sizeof(gmsgh), NLMSG_ALIGNTO) < 0)
|
2017-08-21 09:19:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (nla_put_string(nl_msg, CTRL_ATTR_FAMILY_NAME, family_name) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("allocated netlink buffer is too small"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0, NETLINK_GENERIC, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2017-09-21 17:57:30 +00:00
|
|
|
if (nlmsg_parse(resp, sizeof(struct nlmsghdr), tb, CTRL_ATTR_MAX, NULL) < 0) {
|
2017-08-21 09:19:53 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("malformed netlink response message"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-04-19 06:26:04 +00:00
|
|
|
if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
|
|
|
|
ret = 0;
|
2017-08-21 09:19:53 +00:00
|
|
|
goto cleanup;
|
2020-04-19 06:26:04 +00:00
|
|
|
}
|
2017-08-21 09:19:53 +00:00
|
|
|
|
2020-04-19 06:26:04 +00:00
|
|
|
*family_id = *(uint32_t *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
|
|
|
|
ret = 1;
|
2017-08-21 09:19:53 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
nlmsg_free(nl_msg);
|
2020-04-19 06:26:04 +00:00
|
|
|
return ret;
|
2017-08-21 09:19:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevSwitchdevFeature
|
|
|
|
* This function checks for the availability of Switchdev feature
|
|
|
|
* and add it to bitmap
|
|
|
|
*
|
|
|
|
* @ifname: name of the interface
|
|
|
|
* @out: add Switchdev feature if exist to bitmap
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetDevSwitchdevFeature(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap **out)
|
2017-08-21 09:19:53 +00:00
|
|
|
{
|
|
|
|
struct nl_msg *nl_msg = NULL;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree struct nlmsghdr *resp = NULL;
|
2017-08-21 09:19:53 +00:00
|
|
|
unsigned int recvbuflen;
|
|
|
|
struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {NULL, };
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autoptr(virPCIDevice) pci_device_ptr = NULL;
|
2018-09-07 08:14:46 +00:00
|
|
|
struct genlmsghdr gmsgh = {
|
|
|
|
.cmd = DEVLINK_CMD_ESWITCH_GET,
|
|
|
|
.version = DEVLINK_GENL_VERSION,
|
|
|
|
.reserved = 0,
|
|
|
|
};
|
2017-08-21 09:19:53 +00:00
|
|
|
const char *pci_name;
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree char *pfname = NULL;
|
2017-08-21 09:19:53 +00:00
|
|
|
int is_vf = -1;
|
|
|
|
int ret = -1;
|
|
|
|
uint32_t family_id;
|
2020-04-19 05:25:34 +00:00
|
|
|
int rv;
|
2017-08-21 09:19:53 +00:00
|
|
|
|
|
|
|
if ((is_vf = virNetDevIsVirtualFunction(ifname)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
util: don't log error if SRIOV PF has no associated netdev
Some SRIOV PFs don't have a netdev associated with them (the spec
apparently doesn't require it). In most cases when libvirt is dealing
with an SRIOV VF, that VF must have a PF, and the PF *must* have an
associated netdev (the only way to set the MAC address of a VF is by
sending a netlink message to the netdev of that VF's PF). But there
are times when we don't need for the PF to have a netdev; in
particular, when we're just getting the Switchdev Features for a VF,
we don't need the PF netdev - the netdev of the VF (apparently) works
just as well.
Commit 6452e2f5 (libvirt 5.1.0) *kind of* made libvirt work around PFs
with no netdevs in this case - if virNetDevGetPhysicalFunction
returned an error when setting up to retrieve Switchdev feature info,
it would ignore the error, and then check if the PF netdev name was
NULL and, if so it would reset the error object and continue on rather
than returning early with a failure. The problem is that by the time
this special handling occured, the error message about missing netdev
had already been logged, which was harmless to proper operation, but
confused the user.
Fortunately there are only 2 users of virNetDevGetPhysicalFunction, so
it is easy to redefine it's API to state that a missing netdev name is
*not* an error - in that case it will still return success, but the
caller must be prepared for the PF netdev name to be NULL. After
making this change, we can modify the two callers to behave properly
with the new semantics (for one of the callers it *is* still an error,
so the error message is moved there, but for the other it is okay to
continue), and our spurious error messages are a thing of the past.
Resolves: https://bugzilla.redhat.com/1924616
Fixes: 6452e2f5e1837bd753ee465e6607ed3c4f62b815
Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2021-02-24 03:19:56 +00:00
|
|
|
if (is_vf == 1 && virNetDevGetPhysicalFunction(ifname, &pfname) < 0)
|
|
|
|
return ret;
|
2017-08-21 09:19:53 +00:00
|
|
|
|
2017-10-10 13:04:54 +00:00
|
|
|
pci_device_ptr = pfname ? virNetDevGetPCIDevice(pfname) :
|
|
|
|
virNetDevGetPCIDevice(ifname);
|
|
|
|
/* No PCI device, then no feature bit to check/add */
|
2020-04-19 05:24:40 +00:00
|
|
|
if (pci_device_ptr == NULL)
|
|
|
|
return 0;
|
2017-10-10 13:04:54 +00:00
|
|
|
|
2020-04-19 05:25:34 +00:00
|
|
|
if ((rv = virNetDevGetFamilyId(DEVLINK_GENL_NAME, &family_id)) <= 0)
|
|
|
|
return rv;
|
|
|
|
|
2021-02-24 08:51:19 +00:00
|
|
|
nl_msg = virNetlinkMsgNew(family_id, NLM_F_REQUEST | NLM_F_ACK);
|
2017-08-21 09:19:53 +00:00
|
|
|
|
2018-09-07 08:14:46 +00:00
|
|
|
if (nlmsg_append(nl_msg, &gmsgh, sizeof(gmsgh), NLMSG_ALIGNTO) < 0)
|
2017-08-21 09:19:53 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
pci_name = virPCIDeviceGetName(pci_device_ptr);
|
|
|
|
|
|
|
|
if (nla_put(nl_msg, DEVLINK_ATTR_BUS_NAME, strlen("pci")+1, "pci") < 0 ||
|
|
|
|
nla_put(nl_msg, DEVLINK_ATTR_DEV_NAME, strlen(pci_name)+1, pci_name) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("allocated netlink buffer is too small"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0, NETLINK_GENERIC, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (nlmsg_parse(resp, sizeof(struct genlmsghdr), tb, DEVLINK_ATTR_MAX, NULL) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("malformed netlink response message"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[DEVLINK_ATTR_ESWITCH_MODE] &&
|
|
|
|
*(int *)RTA_DATA(tb[DEVLINK_ATTR_ESWITCH_MODE]) == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
|
|
|
|
ignore_value(virBitmapSetBit(*out, VIR_NET_DEV_FEAT_SWITCHDEV));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
nlmsg_free(nl_msg);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
# else
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevSwitchdevFeature(const char *ifname G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap **out G_GNUC_UNUSED)
|
2017-08-21 09:19:53 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETHTOOL_GFEATURES
|
2015-07-19 10:11:07 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGFeatureAvailable
|
|
|
|
* This function checks for the availability of a network device gfeature
|
|
|
|
*
|
2016-06-03 18:46:05 +00:00
|
|
|
* @fd: socket to operate on
|
|
|
|
* @ifr: struct ifreq with the command
|
|
|
|
* @cmd: reference to an ethtool command structure
|
2015-07-19 10:11:07 +00:00
|
|
|
*
|
2016-06-03 18:44:23 +00:00
|
|
|
* Returns true if the feature is available, false otherwise.
|
2015-07-19 10:11:07 +00:00
|
|
|
*/
|
2016-06-03 18:44:23 +00:00
|
|
|
static bool
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevGFeatureAvailable(const char *ifname,
|
|
|
|
int fd,
|
2016-06-03 18:46:05 +00:00
|
|
|
struct ifreq *ifr,
|
|
|
|
struct ethtool_gfeatures *cmd)
|
2015-07-19 10:11:07 +00:00
|
|
|
{
|
2016-06-03 18:46:05 +00:00
|
|
|
ifr->ifr_data = (void*)cmd;
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevSendEthtoolIoctl(ifname, fd, ifr) == 0)
|
2016-06-03 18:44:23 +00:00
|
|
|
return !!FEATURE_BIT_IS_SET(cmd->features, TX_UDP_TNL, active);
|
|
|
|
return false;
|
2015-07-19 10:11:07 +00:00
|
|
|
}
|
2016-06-03 18:25:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevGetEthtoolGFeatures(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *bitmap,
|
2016-06-03 18:46:05 +00:00
|
|
|
int fd,
|
|
|
|
struct ifreq *ifr)
|
2016-06-03 18:25:21 +00:00
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autofree struct ethtool_gfeatures *g_cmd = NULL;
|
2016-06-03 18:25:21 +00:00
|
|
|
|
2021-02-03 12:33:24 +00:00
|
|
|
g_cmd = g_malloc0(sizeof(struct ethtool_gfeatures) +
|
|
|
|
sizeof(struct ethtool_get_features_block) * GFEATURES_SIZE);
|
2016-06-03 18:25:21 +00:00
|
|
|
|
|
|
|
g_cmd->cmd = ETHTOOL_GFEATURES;
|
|
|
|
g_cmd->size = GFEATURES_SIZE;
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevGFeatureAvailable(ifname, fd, ifr, g_cmd))
|
2016-06-03 18:25:21 +00:00
|
|
|
ignore_value(virBitmapSetBit(bitmap, VIR_NET_DEV_FEAT_TXUDPTNL));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
# else
|
|
|
|
static int
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevGetEthtoolGFeatures(const char *ifname G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *bitmap G_GNUC_UNUSED,
|
2019-10-14 12:45:33 +00:00
|
|
|
int fd G_GNUC_UNUSED,
|
|
|
|
struct ifreq *ifr G_GNUC_UNUSED)
|
2016-06-03 18:25:21 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-19 10:11:07 +00:00
|
|
|
# endif
|
|
|
|
|
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
# if WITH_DECL_ETHTOOL_SCOALESCE && WITH_DECL_ETHTOOL_GCOALESCE
|
2017-04-07 15:38:06 +00:00
|
|
|
/**
|
|
|
|
* virNetDevSetCoalesce:
|
|
|
|
* @ifname: interface name to modify
|
2017-06-15 12:22:26 +00:00
|
|
|
* @coalesce: Coalesce settings to set or update
|
|
|
|
* @update: Whether this is an update for existing settings or not
|
2017-04-07 15:38:06 +00:00
|
|
|
*
|
|
|
|
* This function sets the various coalesce settings for a given interface
|
|
|
|
* @ifname and updates them back into @coalesce.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevSetCoalesce(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevCoalesce *coalesce,
|
2017-06-15 12:22:26 +00:00
|
|
|
bool update)
|
2017-04-07 15:38:06 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct ethtool_coalesce coal = {0};
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2017-04-07 15:38:06 +00:00
|
|
|
|
2017-06-15 12:22:26 +00:00
|
|
|
if (!coalesce && !update)
|
2017-04-07 15:38:06 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-06-15 12:22:26 +00:00
|
|
|
if (coalesce) {
|
|
|
|
coal = (struct ethtool_coalesce) {
|
|
|
|
.rx_max_coalesced_frames = coalesce->rx_max_coalesced_frames,
|
|
|
|
.rx_coalesce_usecs_irq = coalesce->rx_coalesce_usecs_irq,
|
|
|
|
.rx_max_coalesced_frames_irq = coalesce->rx_max_coalesced_frames_irq,
|
|
|
|
.tx_coalesce_usecs = coalesce->tx_coalesce_usecs,
|
|
|
|
.tx_max_coalesced_frames = coalesce->tx_max_coalesced_frames,
|
|
|
|
.tx_coalesce_usecs_irq = coalesce->tx_coalesce_usecs_irq,
|
|
|
|
.tx_max_coalesced_frames_irq = coalesce->tx_max_coalesced_frames_irq,
|
|
|
|
.stats_block_coalesce_usecs = coalesce->stats_block_coalesce_usecs,
|
|
|
|
.use_adaptive_rx_coalesce = coalesce->use_adaptive_rx_coalesce,
|
|
|
|
.use_adaptive_tx_coalesce = coalesce->use_adaptive_tx_coalesce,
|
|
|
|
.pkt_rate_low = coalesce->pkt_rate_low,
|
|
|
|
.rx_coalesce_usecs_low = coalesce->rx_coalesce_usecs_low,
|
|
|
|
.rx_max_coalesced_frames_low = coalesce->rx_max_coalesced_frames_low,
|
|
|
|
.tx_coalesce_usecs_low = coalesce->tx_coalesce_usecs_low,
|
|
|
|
.tx_max_coalesced_frames_low = coalesce->tx_max_coalesced_frames_low,
|
|
|
|
.pkt_rate_high = coalesce->pkt_rate_high,
|
|
|
|
.rx_coalesce_usecs_high = coalesce->rx_coalesce_usecs_high,
|
|
|
|
.rx_max_coalesced_frames_high = coalesce->rx_max_coalesced_frames_high,
|
|
|
|
.tx_coalesce_usecs_high = coalesce->tx_coalesce_usecs_high,
|
|
|
|
.tx_max_coalesced_frames_high = coalesce->tx_max_coalesced_frames_high,
|
|
|
|
.rate_sample_interval = coalesce->rate_sample_interval,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
coal.cmd = ETHTOOL_SCOALESCE;
|
2017-04-07 15:38:06 +00:00
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ifr.ifr_data = (void *) &coal;
|
|
|
|
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevSendEthtoolIoctl(ifname, fd, &ifr) < 0) {
|
2017-04-07 15:38:06 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set coalesce info on '%s'"),
|
|
|
|
ifname);
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2017-04-07 15:38:06 +00:00
|
|
|
}
|
|
|
|
|
2017-06-15 12:22:26 +00:00
|
|
|
if (coalesce) {
|
|
|
|
coal = (struct ethtool_coalesce) {
|
|
|
|
.cmd = ETHTOOL_GCOALESCE,
|
|
|
|
};
|
2017-04-07 15:38:06 +00:00
|
|
|
|
2017-06-15 12:22:26 +00:00
|
|
|
/* Don't fail if the update itself fails */
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevSendEthtoolIoctl(ifname, fd, &ifr) == 0) {
|
2017-06-15 12:22:26 +00:00
|
|
|
coalesce->rx_max_coalesced_frames = coal.rx_max_coalesced_frames;
|
|
|
|
coalesce->rx_coalesce_usecs_irq = coal.rx_coalesce_usecs_irq;
|
|
|
|
coalesce->rx_max_coalesced_frames_irq = coal.rx_max_coalesced_frames_irq;
|
|
|
|
coalesce->tx_coalesce_usecs = coal.tx_coalesce_usecs;
|
|
|
|
coalesce->tx_max_coalesced_frames = coal.tx_max_coalesced_frames;
|
|
|
|
coalesce->tx_coalesce_usecs_irq = coal.tx_coalesce_usecs_irq;
|
|
|
|
coalesce->tx_max_coalesced_frames_irq = coal.tx_max_coalesced_frames_irq;
|
|
|
|
coalesce->stats_block_coalesce_usecs = coal.stats_block_coalesce_usecs;
|
|
|
|
coalesce->use_adaptive_rx_coalesce = coal.use_adaptive_rx_coalesce;
|
|
|
|
coalesce->use_adaptive_tx_coalesce = coal.use_adaptive_tx_coalesce;
|
|
|
|
coalesce->pkt_rate_low = coal.pkt_rate_low;
|
|
|
|
coalesce->rx_coalesce_usecs_low = coal.rx_coalesce_usecs_low;
|
|
|
|
coalesce->rx_max_coalesced_frames_low = coal.rx_max_coalesced_frames_low;
|
|
|
|
coalesce->tx_coalesce_usecs_low = coal.tx_coalesce_usecs_low;
|
|
|
|
coalesce->tx_max_coalesced_frames_low = coal.tx_max_coalesced_frames_low;
|
|
|
|
coalesce->pkt_rate_high = coal.pkt_rate_high;
|
|
|
|
coalesce->rx_coalesce_usecs_high = coal.rx_coalesce_usecs_high;
|
|
|
|
coalesce->rx_max_coalesced_frames_high = coal.rx_max_coalesced_frames_high;
|
|
|
|
coalesce->tx_coalesce_usecs_high = coal.tx_coalesce_usecs_high;
|
|
|
|
coalesce->tx_max_coalesced_frames_high = coal.tx_max_coalesced_frames_high;
|
|
|
|
coalesce->rate_sample_interval = coal.rate_sample_interval;
|
|
|
|
}
|
|
|
|
}
|
2017-04-07 15:38:06 +00:00
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2017-04-07 15:38:06 +00:00
|
|
|
}
|
|
|
|
# else
|
|
|
|
int virNetDevSetCoalesce(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevCoalesce *coalesce,
|
2017-06-15 12:22:26 +00:00
|
|
|
bool update)
|
2017-04-07 15:38:06 +00:00
|
|
|
{
|
2017-06-15 12:22:26 +00:00
|
|
|
if (!coalesce && !update)
|
2017-04-23 14:53:37 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-04-07 15:38:06 +00:00
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot set coalesce info on interface '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
2015-02-23 15:38:29 +00:00
|
|
|
/**
|
|
|
|
* virNetDevGetFeatures:
|
|
|
|
* This function gets the nic offloads features available for ifname
|
|
|
|
*
|
|
|
|
* @ifname: name of the interface
|
2015-11-06 14:44:37 +00:00
|
|
|
* @out: bitmap of the available virNetDevFeature feature bits
|
2015-02-23 15:38:29 +00:00
|
|
|
*
|
2015-11-04 15:26:16 +00:00
|
|
|
* Returns 0 on success or if called from session mode, -1 on failure.
|
|
|
|
* If called from session mode, an empty bitmap is returned.
|
2015-02-23 15:38:29 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetFeatures(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap **out)
|
2015-02-23 15:38:29 +00:00
|
|
|
{
|
2016-06-03 18:46:05 +00:00
|
|
|
struct ifreq ifr;
|
2018-09-12 09:46:38 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2016-06-03 18:46:05 +00:00
|
|
|
|
2020-10-01 15:42:11 +00:00
|
|
|
*out = virBitmapNew(VIR_NET_DEV_FEAT_LAST);
|
2015-02-23 15:38:29 +00:00
|
|
|
|
2016-06-03 18:46:05 +00:00
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2015-02-23 15:38:29 +00:00
|
|
|
|
2020-09-02 18:32:49 +00:00
|
|
|
virNetDevGetEthtoolFeatures(ifname, *out, fd, &ifr);
|
2016-06-03 18:46:05 +00:00
|
|
|
|
2020-09-02 18:32:49 +00:00
|
|
|
if (virNetDevGetEthtoolGFeatures(ifname, *out, fd, &ifr) < 0)
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2015-07-19 10:11:07 +00:00
|
|
|
|
2015-07-23 18:33:32 +00:00
|
|
|
if (virNetDevRDMAFeature(ifname, out) < 0)
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2016-06-03 18:46:05 +00:00
|
|
|
|
2017-08-21 09:19:53 +00:00
|
|
|
if (virNetDevSwitchdevFeature(ifname, out) < 0)
|
2018-09-12 09:46:38 +00:00
|
|
|
return -1;
|
2017-08-21 09:19:53 +00:00
|
|
|
|
2018-09-12 09:46:38 +00:00
|
|
|
return 0;
|
2015-02-23 15:38:29 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetDevGetFeatures(const char *ifname G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap **out G_GNUC_UNUSED)
|
2015-02-23 15:38:29 +00:00
|
|
|
{
|
|
|
|
VIR_DEBUG("Getting network device features on %s is not implemented on this platform",
|
|
|
|
ifname);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 13:54:04 +00:00
|
|
|
|
|
|
|
int virNetDevSetCoalesce(const char *ifname,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevCoalesce *coalesce,
|
2017-06-15 12:22:26 +00:00
|
|
|
bool update)
|
2017-04-21 13:54:04 +00:00
|
|
|
{
|
2017-06-15 12:22:26 +00:00
|
|
|
if (!coalesce && !update)
|
2017-04-23 14:53:37 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-04-21 13:54:04 +00:00
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot set coalesce info on interface '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-23 15:38:29 +00:00
|
|
|
#endif
|
2016-04-13 08:33:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevRunEthernetScript:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @script: the script name
|
|
|
|
*
|
|
|
|
* This function executes script for new tap device created by libvirt.
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevRunEthernetScript(const char *ifname, const char *script)
|
|
|
|
{
|
2020-04-19 05:24:40 +00:00
|
|
|
g_autoptr(virCommand) cmd = NULL;
|
2016-04-13 08:33:36 +00:00
|
|
|
|
2017-02-02 13:16:20 +00:00
|
|
|
/* Not a bug! Previously we did accept script="" as a NO-OP. */
|
|
|
|
if (STREQ(script, ""))
|
|
|
|
return 0;
|
|
|
|
|
2016-04-13 08:33:36 +00:00
|
|
|
cmd = virCommandNew(script);
|
|
|
|
virCommandAddArgFormat(cmd, "%s", ifname);
|
|
|
|
virCommandClearCaps(cmd);
|
|
|
|
#ifdef CAP_NET_ADMIN
|
|
|
|
virCommandAllowCap(cmd, CAP_NET_ADMIN);
|
|
|
|
#endif
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
|
|
|
|
2020-04-19 05:24:40 +00:00
|
|
|
return virCommandRun(cmd, NULL);
|
2016-04-13 08:33:36 +00:00
|
|
|
}
|
2020-10-08 12:37:54 +00:00
|
|
|
|
|
|
|
|
2020-12-14 01:50:32 +00:00
|
|
|
/**
|
|
|
|
* virNetDevReserveName:
|
|
|
|
* @name: name of an existing network device
|
|
|
|
*
|
|
|
|
* Reserve a network device name, so that any new network device
|
|
|
|
* created with an autogenerated name will use a number higher
|
|
|
|
* than the number in the given device name.
|
|
|
|
*
|
|
|
|
* Returns nothing.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virNetDevReserveName(const char *name)
|
|
|
|
{
|
|
|
|
unsigned int id;
|
|
|
|
const char *idstr = NULL;
|
|
|
|
virNetDevGenNameType type;
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (STRPREFIX(name, VIR_NET_GENERATED_VNET_PREFIX))
|
|
|
|
type = VIR_NET_DEV_GEN_NAME_VNET;
|
|
|
|
else if (STRPREFIX(name, VIR_NET_GENERATED_MACVTAP_PREFIX))
|
|
|
|
type = VIR_NET_DEV_GEN_NAME_MACVTAP;
|
|
|
|
else if (STRPREFIX(name, VIR_NET_GENERATED_MACVLAN_PREFIX))
|
|
|
|
type = VIR_NET_DEV_GEN_NAME_MACVLAN;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_INFO("marking device in use: '%s'", name);
|
|
|
|
|
|
|
|
idstr = name + strlen(virNetDevGenNames[type].prefix);
|
|
|
|
|
|
|
|
if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
|
|
|
|
virMutexLock(&virNetDevGenNames[type].mutex);
|
|
|
|
|
|
|
|
if (virNetDevGenNames[type].lastID < (int)id)
|
|
|
|
virNetDevGenNames[type].lastID = id;
|
|
|
|
|
|
|
|
virMutexUnlock(&virNetDevGenNames[type].mutex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGenerateName:
|
|
|
|
* @ifname: pointer to pointer to string which can be a template,
|
|
|
|
* NULL or user-provided name.
|
|
|
|
* @type: type of the network device
|
|
|
|
*
|
|
|
|
* generate a new (currently unused) name for a new network device based
|
|
|
|
* on @ifname. If string pointed by @ifname is a template, replace %d
|
|
|
|
* with the reserved id; if that string is NULL, just generate a new
|
|
|
|
* name. 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.
|
|
|
|
*
|
|
|
|
* Note: if string pointed by @ifname is NOT a template or NULL, leave
|
|
|
|
* it unchanged and return it directly.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGenerateName(char **ifname, virNetDevGenNameType type)
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
const char *prefix = virNetDevGenNames[type].prefix;
|
|
|
|
double maxIDd = pow(10, IFNAMSIZ - 1 - strlen(prefix));
|
|
|
|
int maxID = INT_MAX;
|
|
|
|
int attempts = 0;
|
|
|
|
|
|
|
|
/* The @ifname is not a template, leave it unchanged. */
|
|
|
|
if (*ifname &&
|
|
|
|
(strchr(*ifname, '%') != strrchr(*ifname, '%') ||
|
|
|
|
strstr(*ifname, "%d") == NULL)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maxIDd <= (double)INT_MAX)
|
|
|
|
maxID = (int)maxIDd;
|
|
|
|
|
|
|
|
do {
|
|
|
|
g_autofree char *try = NULL;
|
|
|
|
|
|
|
|
virMutexLock(&virNetDevGenNames[type].mutex);
|
|
|
|
|
|
|
|
id = ++virNetDevGenNames[type].lastID;
|
|
|
|
|
|
|
|
/* reset before overflow */
|
|
|
|
if (virNetDevGenNames[type].lastID >= maxID)
|
|
|
|
virNetDevGenNames[type].lastID = -1;
|
|
|
|
|
|
|
|
virMutexUnlock(&virNetDevGenNames[type].mutex);
|
|
|
|
|
|
|
|
if (*ifname)
|
|
|
|
try = g_strdup_printf(*ifname, id);
|
|
|
|
else
|
|
|
|
try = g_strdup_printf("%s%d", prefix, id);
|
|
|
|
|
|
|
|
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"),
|
|
|
|
prefix);
|
|
|
|
return -1;
|
|
|
|
}
|