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
|
|
|
/*
|
2014-02-10 14:08:26 +00:00
|
|
|
* Copyright (C) 2007-2014 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
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Mark McLoughlin <markmc@redhat.com>
|
|
|
|
* Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "virnetdev.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-12 18:06:53 +00:00
|
|
|
#include "viralloc.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"
|
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 <sys/ioctl.h>
|
2012-09-05 22:27:42 +00:00
|
|
|
#include <net/if.h>
|
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>
|
2013-04-27 15:50:19 +00:00
|
|
|
# define VIR_NETDEV_FAMILY AF_PACKET
|
|
|
|
#elif defined(HAVE_STRUCT_IFREQ) && defined(AF_LOCAL)
|
|
|
|
# define VIR_NETDEV_FAMILY AF_LOCAL
|
|
|
|
#else
|
2011-06-13 23:50:09 +00:00
|
|
|
# undef HAVE_STRUCT_IFREQ
|
2011-11-03 09:27:45 +00:00
|
|
|
#endif
|
|
|
|
|
2013-05-03 13:35:20 +00:00
|
|
|
#if HAVE_DECL_LINK_ADDR
|
|
|
|
# include <sys/sockio.h>
|
|
|
|
# include <net/if_dl.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"
|
|
|
|
#define VIR_MCAST_ADDR_LEN (VIR_MAC_HEXLEN + 1)
|
|
|
|
|
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;
|
|
|
|
typedef virNetDevMcastEntry *virNetDevMcastEntryPtr;
|
|
|
|
struct _virNetDevMcastEntry {
|
|
|
|
int index;
|
|
|
|
char name[VIR_MCAST_NAME_LEN];
|
|
|
|
int users;
|
|
|
|
bool global;
|
|
|
|
virMacAddr macaddr;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virNetDevMcastList virNetDevMcastList;
|
|
|
|
typedef virNetDevMcastList *virNetDevMcastListPtr;
|
|
|
|
struct _virNetDevMcastList {
|
|
|
|
size_t nentries;
|
|
|
|
virNetDevMcastEntryPtr *entries;
|
|
|
|
};
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(HAVE_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
|
|
|
|
2013-06-21 16:57:12 +00:00
|
|
|
if (virStrcpyStatic(ifr->ifr_name, ifname) == NULL) {
|
|
|
|
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
|
|
|
}
|
2013-06-13 06:26:20 +00:00
|
|
|
#else /* !HAVE_STRUCT_IFREQ */
|
|
|
|
int
|
|
|
|
virNetDevSetupControl(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
void *ifr ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Network device configuration is not supported "
|
|
|
|
"on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_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
|
|
|
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCGIFFLAGS) && defined(HAVE_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)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
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)
|
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
|
|
|
ret = 0;
|
|
|
|
else
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to check interface flags for %s"), ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#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) && \
|
|
|
|
defined(HAVE_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
|
|
|
/**
|
|
|
|
* virNetDevSetMAC:
|
|
|
|
* @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 sets the @macaddr for a given interface @ifname. This
|
|
|
|
* gets rid of the kernel's automatically assigned random MAC.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on failure
|
|
|
|
*/
|
|
|
|
int virNetDevSetMAC(const char *ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const 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
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* To fill ifr.ifr_hdaddr.sa_family field */
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface MAC on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set interface MAC on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-05-03 13:35:20 +00:00
|
|
|
#elif defined(SIOCSIFLLADDR) && defined(HAVE_STRUCT_IFREQ) && \
|
|
|
|
HAVE_DECL_LINK_ADDR
|
|
|
|
int virNetDevSetMAC(const char *ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr)
|
2013-05-03 13:35:20 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct sockaddr_dl sdl;
|
|
|
|
char mac[VIR_MAC_STRING_BUFLEN + 1] = ":";
|
|
|
|
int s;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if ((s = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virMacAddrFormat(macaddr, mac + 1);
|
|
|
|
sdl.sdl_len = sizeof(sdl);
|
|
|
|
link_addr(mac, &sdl);
|
|
|
|
|
|
|
|
memcpy(ifr.ifr_addr.sa_data, sdl.sdl_data, VIR_MAC_BUFLEN);
|
|
|
|
ifr.ifr_addr.sa_len = VIR_MAC_BUFLEN;
|
|
|
|
|
|
|
|
if (ioctl(s, SIOCSIFLLADDR, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set interface MAC on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2013-05-03 13:35:20 +00:00
|
|
|
VIR_FORCE_CLOSE(s);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
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 virNetDevSetMAC(const char *ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr ATTRIBUTE_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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCGIFHWADDR) && defined(HAVE_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,
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrPtr 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
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface MAC on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevGetMAC(const char *ifname,
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrPtr macaddr ATTRIBUTE_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
|
|
|
|
|
|
|
|
|
2011-11-02 17:40:50 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevReplaceMacAddress:
|
|
|
|
* @macaddress: new MAC address for interface
|
|
|
|
* @linkdev: name of interface
|
|
|
|
* @stateDir: directory to store old MAC address
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevReplaceMacAddress(const char *linkdev,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddress,
|
2011-11-02 17:40:50 +00:00
|
|
|
const char *stateDir)
|
|
|
|
{
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddr oldmac;
|
2011-11-02 17:40:50 +00:00
|
|
|
char *path = NULL;
|
|
|
|
char macstr[VIR_MAC_STRING_BUFLEN];
|
2014-04-08 04:25:31 +00:00
|
|
|
int ret = -1;
|
2011-11-02 17:40:50 +00:00
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
if (virNetDevGetMAC(linkdev, &oldmac) < 0)
|
2011-11-02 17:40:50 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "%s/%s",
|
|
|
|
stateDir,
|
2013-07-04 10:17:18 +00:00
|
|
|
linkdev) < 0)
|
2011-11-02 17:40:50 +00:00
|
|
|
return -1;
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrFormat(&oldmac, macstr);
|
2011-11-02 17:40:50 +00:00
|
|
|
if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to preserve mac for %s"),
|
|
|
|
linkdev);
|
2014-04-08 04:25:31 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetDevSetMAC(linkdev, macaddress) < 0)
|
2014-04-08 04:25:31 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
2011-11-02 17:40:50 +00:00
|
|
|
|
2014-04-08 04:25:31 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(path);
|
|
|
|
return ret;
|
2011-11-02 17:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevRestoreMacAddress:
|
|
|
|
* @linkdev: name of interface
|
|
|
|
* @stateDir: directory containing old MAC address
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -errno on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevRestoreMacAddress(const char *linkdev,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
2014-04-08 04:25:31 +00:00
|
|
|
int rc = -1;
|
2011-11-02 17:40:50 +00:00
|
|
|
char *oldmacname = NULL;
|
|
|
|
char *macstr = NULL;
|
|
|
|
char *path = NULL;
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddr oldmac;
|
2011-11-02 17:40:50 +00:00
|
|
|
|
|
|
|
if (virAsprintf(&path, "%s/%s",
|
|
|
|
stateDir,
|
2013-07-04 10:17:18 +00:00
|
|
|
linkdev) < 0)
|
2011-11-02 17:40:50 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0)
|
2014-04-08 04:25:31 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:40:50 +00:00
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
if (virMacAddrParse(macstr, &oldmac) != 0) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-11-02 17:40:50 +00:00
|
|
|
_("Cannot parse MAC address from '%s'"),
|
|
|
|
oldmacname);
|
2014-04-08 04:25:31 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*reset mac and remove file-ignore results*/
|
2012-07-17 12:07:59 +00:00
|
|
|
rc = virNetDevSetMAC(linkdev, &oldmac);
|
2011-11-02 17:40:50 +00:00
|
|
|
ignore_value(unlink(path));
|
|
|
|
|
2014-04-08 04:25:31 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(macstr);
|
|
|
|
VIR_FREE(path);
|
2011-11-02 17:40:50 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCGIFMTU) && defined(HAVE_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)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface MTU on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ifr.ifr_mtu;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevGetMTU(const char *ifname)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot get interface MTU on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCSIFMTU) && defined(HAVE_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)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
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);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevSetMTU(const char *ifname, int mtu ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
char *pid = NULL;
|
|
|
|
const char *argv[] = {
|
|
|
|
"ip", "link", "set", ifname, "netns", NULL, NULL
|
|
|
|
};
|
|
|
|
|
2013-07-04 10:17:18 +00:00
|
|
|
if (virAsprintf(&pid, "%lld", (long long) pidInNs) == -1)
|
2011-11-02 16:03:09 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
argv[5] = pid;
|
|
|
|
rc = virRun(argv, NULL);
|
|
|
|
|
|
|
|
VIR_FREE(pid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCSIFNAME) && defined(HAVE_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)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-27 15:50:19 +00:00
|
|
|
# ifdef HAVE_STRUCT_IFREQ_IFR_NEWNAME
|
2011-11-02 16:03:09 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_newname, newifname) == NULL) {
|
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("Network interface name '%s' is too long"),
|
|
|
|
newifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
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);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2011-11-02 16:03:09 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCSIFFLAGS) && defined(HAVE_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
|
|
|
/**
|
|
|
|
* virNetDevSetOnline:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @online: true for up, false for down
|
|
|
|
*
|
|
|
|
* Function to control if an interface is activated (up, true) or not (down, false)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 on error.
|
|
|
|
*/
|
|
|
|
int virNetDevSetOnline(const char *ifname,
|
|
|
|
bool online)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
int ifflags;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (online)
|
|
|
|
ifflags = ifr.ifr_flags | IFF_UP;
|
|
|
|
else
|
|
|
|
ifflags = ifr.ifr_flags & ~IFF_UP;
|
|
|
|
|
|
|
|
if (ifr.ifr_flags != ifflags) {
|
|
|
|
ifr.ifr_flags = ifflags;
|
|
|
|
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot set interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevSetOnline(const char *ifname,
|
|
|
|
bool online ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot set interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCGIFFLAGS) && defined(HAVE_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
|
|
|
/**
|
|
|
|
* virNetDevIsOnline:
|
|
|
|
* @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.
|
|
|
|
*/
|
|
|
|
int virNetDevIsOnline(const char *ifname,
|
|
|
|
bool *online)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot get interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
*online = (ifr.ifr_flags & IFF_UP) ? true : false;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevIsOnline(const char *ifname,
|
|
|
|
bool *online ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS,
|
|
|
|
_("Cannot get interface flags on '%s'"),
|
|
|
|
ifname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCGIFINDEX) && defined(HAVE_STRUCT_IFREQ)
|
2011-11-03 09:27:45 +00:00
|
|
|
int virNetDevGetIndex(const char *ifname, int *ifindex)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifreq;
|
2013-04-27 15:50:19 +00:00
|
|
|
int 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));
|
|
|
|
|
|
|
|
if (virStrncpy(ifreq.ifr_name, ifname, strlen(ifname),
|
|
|
|
sizeof(ifreq.ifr_name)) == NULL) {
|
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("invalid interface name %s"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFINDEX, &ifreq) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to get index for interface %s"), ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-04-27 15:50:19 +00:00
|
|
|
# ifdef HAVE_STRUCT_IFREQ_IFR_INDEX
|
|
|
|
*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
|
2011-11-03 09:27:45 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2011-11-03 09:27:45 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
2011-12-01 13:31:18 +00:00
|
|
|
#else /* ! SIOCGIFINDEX */
|
2011-11-03 09:27:45 +00:00
|
|
|
int virNetDevGetIndex(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
int *ifindex ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
|
|
|
|
2014-02-10 14:08:26 +00:00
|
|
|
#if defined(SIOCGIFVLAN) && defined(HAVE_STRUCT_IFREQ) && HAVE_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,
|
|
|
|
};
|
|
|
|
int ret = -1;
|
|
|
|
int fd = socket(PF_PACKET, SOCK_DGRAM, 0);
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to open control socket"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrcpyStatic(vlanargs.device1, ifname) == NULL) {
|
|
|
|
virReportSystemError(ERANGE,
|
|
|
|
_("invalid interface name %s"),
|
|
|
|
ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFVLAN, &vlanargs) != 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to get VLAN for interface %s"), ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vlanid = vlanargs.u.VID;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2011-12-01 13:31:18 +00:00
|
|
|
#else /* ! SIOCGIFVLAN */
|
2011-11-03 09:27:45 +00:00
|
|
|
int virNetDevGetVLanID(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
int *vlanid ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
* virNetDevSetIPv4Address:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @addr: the IP address (IPv4 or IPv6)
|
|
|
|
* @prefix: number of 1 bits in the netmask
|
|
|
|
*
|
|
|
|
* Add an IP address to an interface. This function *does not* remove
|
|
|
|
* any previously added IP addresses - that must be done separately with
|
|
|
|
* brDelInetAddress.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 in case of error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int virNetDevSetIPv4Address(const char *ifname,
|
|
|
|
virSocketAddr *addr,
|
|
|
|
unsigned int prefix)
|
|
|
|
{
|
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
char *addrstr = NULL, *bcaststr = NULL;
|
|
|
|
virSocketAddr broadcast;
|
|
|
|
int ret = -1;
|
|
|
|
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (!(addrstr = virSocketAddrFormat(addr)))
|
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
|
|
|
goto cleanup;
|
|
|
|
/* format up a broadcast address if this is IPv4 */
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if ((VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) &&
|
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
|
|
|
((virSocketAddrBroadcastByPrefix(addr, prefix, &broadcast) < 0) ||
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
!(bcaststr = virSocketAddrFormat(&broadcast)))) {
|
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
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-08-11 13:54:48 +00:00
|
|
|
#ifdef IFCONFIG_PATH
|
|
|
|
cmd = virCommandNew(IFCONFIG_PATH);
|
|
|
|
virCommandAddArg(cmd, ifname);
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6))
|
|
|
|
virCommandAddArg(cmd, "inet6");
|
|
|
|
else
|
|
|
|
virCommandAddArg(cmd, "inet");
|
|
|
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
|
|
|
if (bcaststr)
|
|
|
|
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
|
|
|
|
virCommandAddArg(cmd, "alias");
|
|
|
|
#else
|
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
|
|
|
cmd = virCommandNew(IP_PATH);
|
|
|
|
virCommandAddArgList(cmd, "addr", "add", NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
|
|
|
if (bcaststr)
|
|
|
|
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
|
|
|
|
virCommandAddArgList(cmd, "dev", ifname, NULL);
|
2013-08-11 13:54:48 +00:00
|
|
|
#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
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FREE(addrstr);
|
|
|
|
VIR_FREE(bcaststr);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
Support for static routes on a virtual bridge
network: static route support for <network>
This patch adds the <route> subelement of <network> to define a static
route. the address and prefix (or netmask) attribute identify the
destination network, and the gateway attribute specifies the next hop
address (which must be directly reachable from the containing
<network>) which is to receive the packets destined for
"address/(prefix|netmask)".
These attributes are translated into an "ip route add" command that is
executed when the network is started. The command used is of the
following form:
ip route add <address>/<prefix> via <gateway> \
dev <virbr-bridge> proto static metric <metric>
Tests are done to validate that the input data are correct. For
example, for a static route ip definition, the address must be a
network address and not a host address. Additional checks are added
to ensure that the specified gateway is directly reachable via this
network (i.e. that the gateway IP address is in the same subnet as one
of the IP's defined for the network).
prefix='0' is supported for both family='ipv4' address='0.0.0.0'
netmask='0.0.0.0' or prefix='0', and for family='ipv6' address='::',
prefix=0', although care should be taken to not override a desired
system default route.
Anytime an attempt is made to define a static route which *exactly*
duplicates an existing static route (for example, address=::,
prefix=0, metric=1), the following error message will be sent to
syslog:
RTNETLINK answers: File exists
This can be overridden by decreasing the metric value for the route
that should be preferred, or increasing the metric for the route that
shouldn't be preferred (and is thus in place only in anticipation that
the preferred route may be removed in the future). Caution should be
used when manipulating route metrics, especially for a default route.
Note: The use of the command-line interface should be replaced by
direct use of libnl so that error conditions can be handled better. But,
that is being left as an exercise for another day.
Signed-off-by: Gene Czarcinski <gene@czarc.net>
Signed-off-by: Laine Stump <laine@laine.org>
2013-05-07 17:42:55 +00:00
|
|
|
/**
|
|
|
|
* virNetDevAddRoute:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @addr: the IP network address (IPv4 or IPv6)
|
|
|
|
* @prefix: number of 1 bits in the netmask
|
|
|
|
* @gateway: via address for route (same as @addr)
|
|
|
|
*
|
|
|
|
* Add a route for a network IP address to an interface. This function
|
|
|
|
* *does not* remove any previously added IP static routes.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 in case of error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetDevAddRoute(const char *ifname,
|
|
|
|
virSocketAddrPtr addr,
|
|
|
|
unsigned int prefix,
|
|
|
|
virSocketAddrPtr gateway,
|
|
|
|
unsigned int metric)
|
|
|
|
{
|
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
char *addrstr = NULL, *gatewaystr = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!(addrstr = virSocketAddrFormat(addr)))
|
|
|
|
goto cleanup;
|
|
|
|
if (!(gatewaystr = virSocketAddrFormat(gateway)))
|
|
|
|
goto cleanup;
|
|
|
|
cmd = virCommandNew(IP_PATH);
|
|
|
|
virCommandAddArgList(cmd, "route", "add", NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
|
|
|
virCommandAddArgList(cmd, "via", gatewaystr, "dev", ifname,
|
|
|
|
"proto", "static", "metric", NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%u", metric);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
Support for static routes on a virtual bridge
network: static route support for <network>
This patch adds the <route> subelement of <network> to define a static
route. the address and prefix (or netmask) attribute identify the
destination network, and the gateway attribute specifies the next hop
address (which must be directly reachable from the containing
<network>) which is to receive the packets destined for
"address/(prefix|netmask)".
These attributes are translated into an "ip route add" command that is
executed when the network is started. The command used is of the
following form:
ip route add <address>/<prefix> via <gateway> \
dev <virbr-bridge> proto static metric <metric>
Tests are done to validate that the input data are correct. For
example, for a static route ip definition, the address must be a
network address and not a host address. Additional checks are added
to ensure that the specified gateway is directly reachable via this
network (i.e. that the gateway IP address is in the same subnet as one
of the IP's defined for the network).
prefix='0' is supported for both family='ipv4' address='0.0.0.0'
netmask='0.0.0.0' or prefix='0', and for family='ipv6' address='::',
prefix=0', although care should be taken to not override a desired
system default route.
Anytime an attempt is made to define a static route which *exactly*
duplicates an existing static route (for example, address=::,
prefix=0, metric=1), the following error message will be sent to
syslog:
RTNETLINK answers: File exists
This can be overridden by decreasing the metric value for the route
that should be preferred, or increasing the metric for the route that
shouldn't be preferred (and is thus in place only in anticipation that
the preferred route may be removed in the future). Caution should be
used when manipulating route metrics, especially for a default route.
Note: The use of the command-line interface should be replaced by
direct use of libnl so that error conditions can be handled better. But,
that is being left as an exercise for another day.
Signed-off-by: Gene Czarcinski <gene@czarc.net>
Signed-off-by: Laine Stump <laine@laine.org>
2013-05-07 17:42:55 +00:00
|
|
|
VIR_FREE(addrstr);
|
|
|
|
VIR_FREE(gatewaystr);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
* virNetDevClearIPv4Address:
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @addr: the IP address (IPv4 or IPv6)
|
|
|
|
* @prefix: number of 1 bits in the netmask
|
|
|
|
*
|
|
|
|
* Delete an IP address from an interface.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or -1 in case of error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int virNetDevClearIPv4Address(const char *ifname,
|
|
|
|
virSocketAddr *addr,
|
|
|
|
unsigned int prefix)
|
|
|
|
{
|
|
|
|
virCommandPtr cmd = NULL;
|
|
|
|
char *addrstr;
|
|
|
|
int ret = -1;
|
|
|
|
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
if (!(addrstr = virSocketAddrFormat(addr)))
|
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
|
|
|
goto cleanup;
|
2013-08-11 13:54:48 +00:00
|
|
|
#ifdef IFCONFIG_PATH
|
|
|
|
cmd = virCommandNew(IFCONFIG_PATH);
|
|
|
|
virCommandAddArg(cmd, ifname);
|
|
|
|
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6))
|
|
|
|
virCommandAddArg(cmd, "inet6");
|
|
|
|
else
|
|
|
|
virCommandAddArg(cmd, "inet");
|
|
|
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
|
|
|
virCommandAddArg(cmd, "-alias");
|
|
|
|
#else
|
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
|
|
|
cmd = virCommandNew(IP_PATH);
|
|
|
|
virCommandAddArgList(cmd, "addr", "del", NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
|
|
|
virCommandAddArgList(cmd, "dev", ifname, NULL);
|
2013-08-11 13:54:48 +00:00
|
|
|
#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
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
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
|
|
|
VIR_FREE(addrstr);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
2011-11-03 10:35:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGetIPv4Address:
|
|
|
|
* @ifname: name of the interface whose IP address we want
|
|
|
|
* @addr: filled with the IPv4 address
|
|
|
|
*
|
|
|
|
* This function gets the IPv4 address for the interface @ifname
|
|
|
|
* and stores it in @addr
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -errno on failure.
|
|
|
|
*/
|
2011-12-01 13:31:18 +00:00
|
|
|
#if defined(SIOCGIFADDR) && defined(HAVE_STRUCT_IFREQ)
|
2011-11-03 10:35:17 +00:00
|
|
|
int virNetDevGetIPv4Address(const char *ifname,
|
|
|
|
virSocketAddrPtr addr)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
addr->data.stor.ss_family = AF_UNSPEC;
|
|
|
|
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to get IPv4 address for interface %s"), ifname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr->data.stor.ss_family = AF_INET;
|
|
|
|
addr->len = sizeof(addr->data.inet4);
|
|
|
|
memcpy(&addr->data.inet4, &ifr.ifr_addr, addr->len);
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2011-11-03 10:35:17 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#else /* ! SIOCGIFADDR */
|
2011-11-03 10:35:17 +00:00
|
|
|
|
|
|
|
int virNetDevGetIPv4Address(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
virSocketAddrPtr addr ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get IPv4 address on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-12-01 13:31:18 +00:00
|
|
|
#endif /* ! SIOCGIFADDR */
|
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
|
|
|
|
*/
|
2013-04-27 15:50:19 +00:00
|
|
|
#if defined(SIOCGIFHWADDR) && defined(HAVE_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
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
int idx;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virNetDevExists(ifname)) < 0)
|
|
|
|
return -1;
|
|
|
|
if (rc == 0) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (macaddr != NULL) {
|
|
|
|
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
|
|
|
if (errno == ENODEV) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
if (virMacAddrCmpRaw(macaddr,
|
|
|
|
(unsigned char *)ifr.ifr_hwaddr.sa_data) != 0) {
|
2011-11-03 12:32:38 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifindex != -1) {
|
|
|
|
if (virNetDevGetIndex(ifname, &idx) < 0)
|
|
|
|
goto cleanup;
|
2014-09-03 19:39:21 +00:00
|
|
|
if (idx != ifindex) {
|
2011-11-03 12:32:38 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-04-27 15:50:19 +00:00
|
|
|
#else
|
2011-11-03 12:32:38 +00:00
|
|
|
int virNetDevValidateConfig(const char *ifname ATTRIBUTE_UNUSED,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr ATTRIBUTE_UNUSED,
|
2011-11-03 12:32:38 +00:00
|
|
|
int ifindex ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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__
|
|
|
|
# define NET_SYSFS "/sys/class/net/"
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevSysfsFile(char **pf_sysfs_device_link, const char *ifname,
|
|
|
|
const char *file)
|
|
|
|
{
|
|
|
|
|
2013-07-18 10:13:46 +00:00
|
|
|
if (virAsprintf(pf_sysfs_device_link, NET_SYSFS "%s/%s", ifname, file) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2011-11-03 12:40:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname,
|
|
|
|
const char *file)
|
|
|
|
{
|
|
|
|
|
2013-07-18 10:13:46 +00:00
|
|
|
if (virAsprintf(pf_sysfs_device_link, NET_SYSFS "%s/device/%s", ifname,
|
|
|
|
file) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2011-11-03 12:40:33 +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,
|
2013-01-14 22:11:44 +00:00
|
|
|
virPCIDeviceAddressPtr **virt_fns,
|
2013-11-08 10:39:08 +00:00
|
|
|
size_t *n_vfname)
|
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;
|
2011-12-14 10:50:14 +00:00
|
|
|
char *pf_sysfs_device_link = NULL;
|
|
|
|
char *pci_sysfs_device_link = NULL;
|
2013-01-22 14:15:41 +00:00
|
|
|
char *pciConfigAddr = NULL;
|
2011-12-14 10:50:14 +00:00
|
|
|
|
2013-07-01 03:52:43 +00:00
|
|
|
*virt_fns = NULL;
|
|
|
|
*n_vfname = 0;
|
|
|
|
|
2011-12-14 10:50:14 +00:00
|
|
|
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0)
|
|
|
|
return ret;
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virPCIGetVirtualFunctions(pf_sysfs_device_link, virt_fns,
|
|
|
|
n_vfname) < 0)
|
2011-12-14 10:50:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:17:18 +00:00
|
|
|
if (VIR_ALLOC_N(*vfname, *n_vfname) < 0)
|
2011-12-14 10:50:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-09-03 22:24:43 +00:00
|
|
|
for (i = 0; i < *n_vfname; i++) {
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virPCIGetAddrString((*virt_fns)[i]->domain,
|
|
|
|
(*virt_fns)[i]->bus,
|
|
|
|
(*virt_fns)[i]->slot,
|
|
|
|
(*virt_fns)[i]->function,
|
|
|
|
&pciConfigAddr) < 0) {
|
2011-12-14 10:50:14 +00:00
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Failed to get PCI Config Address String"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virPCIGetSysfsFile(pciConfigAddr, &pci_sysfs_device_link) < 0) {
|
2011-12-14 10:50:14 +00:00
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Failed to get PCI SYSFS file"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
if (virPCIGetNetName(pci_sysfs_device_link, &((*vfname)[i])) < 0) {
|
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) {
|
2011-12-14 10:50:14 +00:00
|
|
|
VIR_FREE(*vfname);
|
2012-08-16 15:41:58 +00:00
|
|
|
VIR_FREE(*virt_fns);
|
|
|
|
}
|
2011-12-14 10:50:14 +00:00
|
|
|
VIR_FREE(pf_sysfs_device_link);
|
|
|
|
VIR_FREE(pci_sysfs_device_link);
|
|
|
|
VIR_FREE(pciConfigAddr);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
char *if_sysfs_device_link = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&if_sysfs_device_link, ifname, "device") < 0)
|
|
|
|
return ret;
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
ret = virPCIIsVirtualFunction(if_sysfs_device_link);
|
2011-11-03 12:40:33 +00:00
|
|
|
|
|
|
|
VIR_FREE(if_sysfs_device_link);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
char *pf_sysfs_device_link = NULL, *vf_sysfs_device_link = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&pf_sysfs_device_link, pfname, "device") < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&vf_sysfs_device_link, vfname, "device") < 0) {
|
|
|
|
VIR_FREE(pf_sysfs_device_link);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
ret = virPCIGetVirtualFunctionIndex(pf_sysfs_device_link,
|
|
|
|
vf_sysfs_device_link,
|
|
|
|
vf_index);
|
2011-11-03 12:40:33 +00:00
|
|
|
|
|
|
|
VIR_FREE(pf_sysfs_device_link);
|
|
|
|
VIR_FREE(vf_sysfs_device_link);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevGetPhysicalFunction
|
|
|
|
*
|
|
|
|
* @ifname : name of the physical function interface name
|
|
|
|
* @pfname : Contains sriov physical function for interface ifname
|
|
|
|
* upon successful return
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
|
|
|
|
{
|
|
|
|
char *physfn_sysfs_path = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virNetDevSysfsDeviceFile(&physfn_sysfs_path, ifname, "physfn") < 0)
|
|
|
|
return ret;
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
ret = virPCIGetNetName(physfn_sysfs_path, pfname);
|
2011-11-03 12:40:33 +00:00
|
|
|
|
|
|
|
VIR_FREE(physfn_sysfs_path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2011-12-14 10:50:14 +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)
|
|
|
|
{
|
|
|
|
char *pf_sysfs_path = NULL, *vf_sysfs_path = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*pfname = NULL;
|
|
|
|
|
|
|
|
if (virNetDevGetPhysicalFunction(vfname, pfname) < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&pf_sysfs_path, *pfname, "device") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&vf_sysfs_path, vfname, "device") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-01-14 22:11:44 +00:00
|
|
|
ret = virPCIGetVirtualFunctionIndex(pf_sysfs_path, vf_sysfs_path, vf);
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-03-06 01:12:34 +00:00
|
|
|
if (ret < 0)
|
|
|
|
VIR_FREE(*pfname);
|
|
|
|
|
|
|
|
VIR_FREE(vf_sysfs_path);
|
|
|
|
VIR_FREE(pf_sysfs_path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !__linux__ */
|
2011-12-14 10:50:14 +00:00
|
|
|
int
|
|
|
|
virNetDevGetVirtualFunctions(const char *pfname ATTRIBUTE_UNUSED,
|
|
|
|
char ***vfname ATTRIBUTE_UNUSED,
|
2013-01-14 22:11:44 +00:00
|
|
|
virPCIDeviceAddressPtr **virt_fns ATTRIBUTE_UNUSED,
|
2013-11-08 10:39:08 +00:00
|
|
|
size_t *n_vfname ATTRIBUTE_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
|
|
|
|
virNetDevIsVirtualFunction(const char *ifname ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
virNetDevGetVirtualFunctionIndex(const char *pfname ATTRIBUTE_UNUSED,
|
|
|
|
const char *vfname ATTRIBUTE_UNUSED,
|
|
|
|
int *vf_index ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
virNetDevGetPhysicalFunction(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
char **pfname ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
|
|
|
int
|
|
|
|
virNetDevGetVirtualFunctionInfo(const char *vfname ATTRIBUTE_UNUSED,
|
|
|
|
char **pfname ATTRIBUTE_UNUSED,
|
|
|
|
int *vf ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to get virtual function info on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2011-11-03 12:40:33 +00:00
|
|
|
#endif /* !__linux__ */
|
2012-04-13 13:43:58 +00:00
|
|
|
#if defined(__linux__) && defined(HAVE_LIBNL) && defined(IFLA_VF_MAX)
|
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) },
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevLinkDump:
|
|
|
|
*
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
* @ifname: The name of the interface; only use if ifindex <= 0
|
|
|
|
* @ifindex: The interface index; may be <= 0 if ifname is given
|
|
|
|
* @data: Gets a pointer to the raw data from netlink.
|
|
|
|
MUST BE FREED BY CALLER!
|
|
|
|
* @nlattr: Pointer to a pointer of netlink attributes that will contain
|
|
|
|
* the results
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
* @src_pid: pid used for nl_pid of the local end of the netlink message
|
|
|
|
* (0 == "use getpid()")
|
|
|
|
* @dst_pid: pid of destination nl_pid if the kernel
|
|
|
|
* is not the target of the netlink message but it is to be
|
|
|
|
* sent to another process (0 if sending to the kernel)
|
2012-03-06 01:12:34 +00:00
|
|
|
*
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
* Get information from netlink about an interface given its name or index.
|
2012-03-06 01:12:34 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on fatal error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevLinkDump(const char *ifname, int ifindex,
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
void **nlData, struct nlattr **tb,
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
uint32_t src_pid, uint32_t dst_pid)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
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
|
|
|
int rc = -1;
|
2013-04-03 13:09:19 +00:00
|
|
|
struct nlmsghdr *resp = NULL;
|
2012-03-06 01:12:34 +00:00
|
|
|
struct nlmsgerr *err;
|
|
|
|
struct ifinfomsg ifinfo = {
|
|
|
|
.ifi_family = AF_UNSPEC,
|
|
|
|
.ifi_index = ifindex
|
|
|
|
};
|
|
|
|
unsigned int recvbuflen;
|
|
|
|
struct nl_msg *nl_msg;
|
|
|
|
|
|
|
|
if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ifinfo.ifi_index = ifindex;
|
|
|
|
|
|
|
|
nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
|
|
|
|
if (!nl_msg) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (ifname) {
|
|
|
|
if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
util: fix botched check for new netlink request filters
This is an adjustment to the fix for
https://bugzilla.redhat.com/show_bug.cgi?id=889319
to account for two bonehead mistakes I made.
commit ac2797cf2af2fd0e64c58a48409a8175d24d6f86 attempted to fix a
problem with netlink in newer kernels requiring an extra attribute
with a filter flag set in order to receive an IFLA_VFINFO_LIST from
netlink. Unfortunately, the #ifdef that protected against compiling it
in on systems without the new flag went a bit too far, assuring that
the new code would *never* be compiled, and even if it had, the code
was incorrect.
The first problem was that, while some IFLA_* enum values are also
their existence at compile time, IFLA_EXT_MASK *isn't* #defined, so
checking to see if it's #defined is not a valid method of determining
whether or not to add the attribute. Fortunately, the flag that is
being set (RTEXT_FILTER_VF) *is* #defined, and it is never present if
IFLA_EXT_MASK isn't, so it's sufficient to just check for that flag.
And to top it off, due to the code not actually compiling when I
thought it did, I didn't realize that I'd been given the wrong arglist
to nla_put() - you can't just send a const value to nla_put, you have
to send it a pointer to memory containing what you want to add to the
message, along with the length of that memory.
This time I've actually sent the patch over to the other machine
that's experiencing the problem, applied it to the branch being used
(0.10.2) and verified that it works properly, i.e. it does fix the
problem it's supposed to fix. :-/
2012-12-21 20:09:33 +00:00
|
|
|
# ifdef RTEXT_FILTER_VF
|
util: fix functions that retrieve SRIOV VF info
This patch resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=889319
When assigning an SRIOV virtual function to a guest using "intelligent
PCI passthrough" (<interface type='hostdev'>, which sets the MAC
address and vlan tag of the VF before passing its info to qemu),
libvirt first learns the current MAC address and vlan tag by sending
an NLM_F_REQUEST message for the VF's PF (physical function) to the
kernel via a NETLINK_ROUTE socket (see virNetDevLinkDump()); the
response message's IFLA_VFINFO_LIST section is examined to extract the
info for the particular VF being assigned.
This worked fine with kernels up until kernel commit
115c9b81928360d769a76c632bae62d15206a94a (first appearing in upstream
kernel 3.3) which changed the ABI to not return IFLA_VFINFO_LIST in
the response until a newly introduced IFLA_EXT_MASK field was included
in the request, with the (newly introduced, of course) RTEXT_FILTER_VF
flag set.
The justification for this ABI change was that new fields had been
added to the VFINFO, causing NLM_F_REQUEST messages to fail on systems
with large numbers of VFs if the requesting application didn't have a
large enough buffer for all the info. The idea is that most
applications doing an NLM_F_REQUEST don't care about VFINFO anyway, so
eliminating it from the response would lower the requirements on
buffer size. Apparently, the people who pushed this patch made the
mistaken assumption that iproute2 (the "ip" command) was the only
package that used IFLA_VFINFO_LIST, so it wouldn't break anything else
(and they made sure that iproute2 was fixed.
The logic of this "fix" is debatable at best (one could claim that the
proper fix would be for the applications in question to be fixed so
that they properly sized the buffer, which is what libvirt does
(purely by virtue of using libnl), but it is what it is and we have to
deal with it.
In order for <interface type='hostdev'> to work properly on systems
with a kernel 3.3 or later, libvirt needs to add the afore-mentioned
IFLA_EXT_MASK field with RTEXT_FILTER_VF set.
Of course we also need to continue working on systems with older
kernels, so that one bit of code is compiled conditionally. The one
time this could cause problems is if the libvirt binary was built on a
system without IFLA_EXT_MASK which was subsequently updated to a
kernel that *did* have it. That could be solved by manually providing
the values of IFLA_EXT_MASK and RTEXT_FILTER_VF and adding it to the
message anyway, but I'm uncertain what that might actually do on a
system that didn't support the message, so for the time being we'll
just fail in that case (which will very likely never happen anyway).
2012-12-20 18:22:17 +00:00
|
|
|
/* if this filter exists in the kernel's netlink implementation,
|
|
|
|
* we need to set it, otherwise the response message will not
|
|
|
|
* contain the IFLA_VFINFO_LIST that we're looking for.
|
|
|
|
*/
|
util: fix botched check for new netlink request filters
This is an adjustment to the fix for
https://bugzilla.redhat.com/show_bug.cgi?id=889319
to account for two bonehead mistakes I made.
commit ac2797cf2af2fd0e64c58a48409a8175d24d6f86 attempted to fix a
problem with netlink in newer kernels requiring an extra attribute
with a filter flag set in order to receive an IFLA_VFINFO_LIST from
netlink. Unfortunately, the #ifdef that protected against compiling it
in on systems without the new flag went a bit too far, assuring that
the new code would *never* be compiled, and even if it had, the code
was incorrect.
The first problem was that, while some IFLA_* enum values are also
their existence at compile time, IFLA_EXT_MASK *isn't* #defined, so
checking to see if it's #defined is not a valid method of determining
whether or not to add the attribute. Fortunately, the flag that is
being set (RTEXT_FILTER_VF) *is* #defined, and it is never present if
IFLA_EXT_MASK isn't, so it's sufficient to just check for that flag.
And to top it off, due to the code not actually compiling when I
thought it did, I didn't realize that I'd been given the wrong arglist
to nla_put() - you can't just send a const value to nla_put, you have
to send it a pointer to memory containing what you want to add to the
message, along with the length of that memory.
This time I've actually sent the patch over to the other machine
that's experiencing the problem, applied it to the branch being used
(0.10.2) and verified that it works properly, i.e. it does fix the
problem it's supposed to fix. :-/
2012-12-21 20:09:33 +00:00
|
|
|
{
|
|
|
|
uint32_t ifla_ext_mask = RTEXT_FILTER_VF;
|
|
|
|
|
|
|
|
if (nla_put(nl_msg, IFLA_EXT_MASK,
|
|
|
|
sizeof(ifla_ext_mask), &ifla_ext_mask) < 0) {
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
}
|
util: fix functions that retrieve SRIOV VF info
This patch resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=889319
When assigning an SRIOV virtual function to a guest using "intelligent
PCI passthrough" (<interface type='hostdev'>, which sets the MAC
address and vlan tag of the VF before passing its info to qemu),
libvirt first learns the current MAC address and vlan tag by sending
an NLM_F_REQUEST message for the VF's PF (physical function) to the
kernel via a NETLINK_ROUTE socket (see virNetDevLinkDump()); the
response message's IFLA_VFINFO_LIST section is examined to extract the
info for the particular VF being assigned.
This worked fine with kernels up until kernel commit
115c9b81928360d769a76c632bae62d15206a94a (first appearing in upstream
kernel 3.3) which changed the ABI to not return IFLA_VFINFO_LIST in
the response until a newly introduced IFLA_EXT_MASK field was included
in the request, with the (newly introduced, of course) RTEXT_FILTER_VF
flag set.
The justification for this ABI change was that new fields had been
added to the VFINFO, causing NLM_F_REQUEST messages to fail on systems
with large numbers of VFs if the requesting application didn't have a
large enough buffer for all the info. The idea is that most
applications doing an NLM_F_REQUEST don't care about VFINFO anyway, so
eliminating it from the response would lower the requirements on
buffer size. Apparently, the people who pushed this patch made the
mistaken assumption that iproute2 (the "ip" command) was the only
package that used IFLA_VFINFO_LIST, so it wouldn't break anything else
(and they made sure that iproute2 was fixed.
The logic of this "fix" is debatable at best (one could claim that the
proper fix would be for the applications in question to be fixed so
that they properly sized the buffer, which is what libvirt does
(purely by virtue of using libnl), but it is what it is and we have to
deal with it.
In order for <interface type='hostdev'> to work properly on systems
with a kernel 3.3 or later, libvirt needs to add the afore-mentioned
IFLA_EXT_MASK field with RTEXT_FILTER_VF set.
Of course we also need to continue working on systems with older
kernels, so that one bit of code is compiled conditionally. The one
time this could cause problems is if the libvirt binary was built on a
system without IFLA_EXT_MASK which was subsequently updated to a
kernel that *did* have it. That could be solved by manually providing
the values of IFLA_EXT_MASK and RTEXT_FILTER_VF and adding it to the
message anyway, but I'm uncertain what that might actually do on a
system that didn't support the message, so for the time being we'll
just fail in that case (which will very likely never happen anyway).
2012-12-20 18:22:17 +00:00
|
|
|
# endif
|
|
|
|
|
2013-04-03 13:09:19 +00:00
|
|
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen,
|
2012-08-22 04:10:23 +00:00
|
|
|
src_pid, dst_pid, 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;
|
|
|
|
|
|
|
|
if (err->error) {
|
|
|
|
virReportSystemError(-err->error,
|
|
|
|
_("error dumping %s (%d) interface"),
|
|
|
|
ifname, ifindex);
|
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
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GENL_ID_CTRL:
|
|
|
|
case NLMSG_DONE:
|
|
|
|
rc = nlmsg_parse(resp, sizeof(struct ifinfomsg),
|
|
|
|
tb, IFLA_MAX, NULL);
|
|
|
|
if (rc < 0)
|
|
|
|
goto malformed_resp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto malformed_resp;
|
|
|
|
}
|
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
|
|
|
rc = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-03-06 01:12:34 +00:00
|
|
|
nlmsg_free(nl_msg);
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
if (rc < 0)
|
|
|
|
VIR_FREE(resp);
|
|
|
|
*nlData = resp;
|
2012-03-06 01:12:34 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevSetVfConfig(const char *ifname, int ifindex, int vf,
|
2013-10-05 19:41:44 +00:00
|
|
|
bool nltarget_kernel, const virMacAddr *macaddr,
|
2012-03-06 01:12:34 +00:00
|
|
|
int vlanid, uint32_t (*getPidFunc)(void))
|
|
|
|
{
|
|
|
|
int rc = -1;
|
2013-04-03 13:09:19 +00:00
|
|
|
struct nlmsghdr *resp = NULL;
|
2012-03-06 01:12:34 +00:00
|
|
|
struct nlmsgerr *err;
|
|
|
|
unsigned int recvbuflen = 0;
|
|
|
|
uint32_t pid = 0;
|
|
|
|
struct nl_msg *nl_msg;
|
|
|
|
struct nlattr *vfinfolist, *vfinfo;
|
|
|
|
struct ifinfomsg ifinfo = {
|
|
|
|
.ifi_family = AF_UNSPEC,
|
|
|
|
.ifi_index = ifindex
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!macaddr && vlanid < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nl_msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_REQUEST);
|
|
|
|
if (!nl_msg) {
|
|
|
|
virReportOOMError();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (!nltarget_kernel) {
|
|
|
|
pid = getPidFunc();
|
|
|
|
if (pid == 0) {
|
|
|
|
rc = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-03 13:09:19 +00:00
|
|
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, pid,
|
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;
|
|
|
|
|
|
|
|
if (err->error) {
|
|
|
|
virReportSystemError(-err->error,
|
|
|
|
_("error during set %s of ifindex %d"),
|
|
|
|
(macaddr ? (vlanid >= 0 ? "mac/vlan" : "mac") : "vlanid"),
|
|
|
|
ifindex);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NLMSG_DONE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto malformed_resp;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-03-06 01:12:34 +00:00
|
|
|
nlmsg_free(nl_msg);
|
2013-04-03 13:09:19 +00:00
|
|
|
VIR_FREE(resp);
|
2012-03-06 01:12:34 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-07-17 12:07:59 +00:00
|
|
|
virNetDevParseVfConfig(struct nlattr **tb, int32_t vf, virMacAddrPtr mac,
|
2012-03-06 01:12:34 +00:00
|
|
|
int *vlanid)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
int rem;
|
|
|
|
|
|
|
|
if (!tb[IFLA_VFINFO_LIST]) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing IFLA_VF_INFO in netlink response"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
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"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2012-12-20 19:52:41 +00:00
|
|
|
if (tb[IFLA_VF_MAC]) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_VF_VLAN]) {
|
|
|
|
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
|
|
|
|
|
|
|
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);
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-03-06 01:12:34 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-07-17 12:07:59 +00:00
|
|
|
virNetDevGetVfConfig(const char *ifname, int vf, virMacAddrPtr mac,
|
2012-03-06 01:12:34 +00:00
|
|
|
int *vlanid)
|
|
|
|
{
|
|
|
|
int rc = -1;
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
void *nlData = NULL;
|
2012-03-06 01:12:34 +00:00
|
|
|
struct nlattr *tb[IFLA_MAX + 1] = {NULL, };
|
|
|
|
int ifindex = -1;
|
|
|
|
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
rc = virNetDevLinkDump(ifname, ifindex, &nlData, tb, 0, 0);
|
2012-03-06 01:12:34 +00:00
|
|
|
if (rc < 0)
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
goto cleanup;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
|
|
|
rc = virNetDevParseVfConfig(tb, vf, mac, vlanid);
|
|
|
|
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(nlData);
|
2012-03-06 01:12:34 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevReplaceVfConfig(const char *pflinkdev, int vf,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddress,
|
2012-03-06 01:12:34 +00:00
|
|
|
int vlanid,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
2012-08-16 04:06:39 +00:00
|
|
|
int ret = -1;
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddr oldmac;
|
2012-03-06 01:12:34 +00:00
|
|
|
int oldvlanid = -1;
|
|
|
|
char *path = NULL;
|
|
|
|
char macstr[VIR_MAC_STRING_BUFLEN];
|
2012-08-16 04:06:39 +00:00
|
|
|
char *fileData = NULL;
|
2012-03-06 01:12:34 +00:00
|
|
|
int ifindex = -1;
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
if (virNetDevGetVfConfig(pflinkdev, vf, &oldmac, &oldvlanid) < 0)
|
2012-08-16 04:06:39 +00:00
|
|
|
goto cleanup;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
|
|
|
if (virAsprintf(&path, "%s/%s_vf%d",
|
2013-07-04 10:17:18 +00:00
|
|
|
stateDir, pflinkdev, vf) < 0)
|
2012-08-16 04:06:39 +00:00
|
|
|
goto cleanup;
|
2012-03-06 01:12:34 +00:00
|
|
|
|
2012-08-16 04:06:39 +00:00
|
|
|
if (virAsprintf(&fileData, "%s\n%d\n",
|
2013-07-04 10:17:18 +00:00
|
|
|
virMacAddrFormat(&oldmac, macstr), oldvlanid) < 0)
|
2012-08-16 04:06:39 +00:00
|
|
|
goto cleanup;
|
|
|
|
if (virFileWriteStr(path, fileData, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to preserve mac/vlan tag "
|
|
|
|
"for pf = %s, vf = %d"), pflinkdev, vf);
|
|
|
|
goto cleanup;
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
|
|
|
|
2012-08-16 04:06:39 +00:00
|
|
|
ret = virNetDevSetVfConfig(pflinkdev, ifindex, vf, true,
|
2012-03-06 01:12:34 +00:00
|
|
|
macaddress, vlanid, NULL);
|
2012-08-16 04:06:39 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-08-16 04:06:39 +00:00
|
|
|
VIR_FREE(path);
|
|
|
|
VIR_FREE(fileData);
|
|
|
|
return ret;
|
2012-03-06 01:12:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevRestoreVfConfig(const char *pflinkdev, int vf,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
int rc = -1;
|
|
|
|
char *path = NULL;
|
2012-08-16 04:06:39 +00:00
|
|
|
char *fileData = NULL;
|
|
|
|
char *vlan = NULL;
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddr oldmac;
|
2012-03-06 01:12:34 +00:00
|
|
|
int vlanid = -1;
|
|
|
|
int ifindex = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "%s/%s_vf%d",
|
2013-07-04 10:17:18 +00:00
|
|
|
stateDir, pflinkdev, vf) < 0)
|
2012-03-06 01:12:34 +00:00
|
|
|
return rc;
|
|
|
|
|
2012-08-16 04:06:39 +00:00
|
|
|
if (virFileReadAll(path, 128, &fileData) < 0) {
|
2012-03-06 01:12:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-08-16 04:06:39 +00:00
|
|
|
if ((vlan = strchr(fileData, '\n'))) {
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
*vlan++ = 0; /* NULL terminate the mac address */
|
|
|
|
if (*vlan) {
|
|
|
|
if ((virStrToLong_i(vlan, &endptr, 10, &vlanid) < 0) ||
|
|
|
|
(endptr && *endptr != '\n' && *endptr != 0)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot parse vlan tag from '%s'"),
|
|
|
|
vlan);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virMacAddrParse(fileData, &oldmac) != 0) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-03-06 01:12:34 +00:00
|
|
|
_("Cannot parse MAC address from '%s'"),
|
2012-08-16 04:06:39 +00:00
|
|
|
fileData);
|
2012-03-06 01:12:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*reset mac and remove file-ignore results*/
|
|
|
|
rc = virNetDevSetVfConfig(pflinkdev, ifindex, vf, true,
|
2012-07-17 12:07:59 +00:00
|
|
|
&oldmac, vlanid, NULL);
|
2012-03-06 01:12:34 +00:00
|
|
|
ignore_value(unlink(path));
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-03-06 01:12:34 +00:00
|
|
|
VIR_FREE(path);
|
2012-08-16 04:06:39 +00:00
|
|
|
VIR_FREE(fileData);
|
2012-03-06 01:12:34 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevReplaceNetConfig:
|
|
|
|
* @linkdev: name of the interface
|
|
|
|
* @vf: vf index if linkdev is a pf
|
|
|
|
* @macaddress: new MAC address for interface
|
|
|
|
* @vlanid: new vlanid
|
|
|
|
* @stateDir: directory to store old net config
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
2014-03-12 16:01:39 +00:00
|
|
|
virNetDevReplaceNetConfig(const char *linkdev, int vf,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddress, int vlanid,
|
2014-03-12 16:01:39 +00:00
|
|
|
const char *stateDir)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
if (vf == -1)
|
|
|
|
return virNetDevReplaceMacAddress(linkdev, macaddress, stateDir);
|
|
|
|
else
|
|
|
|
return virNetDevReplaceVfConfig(linkdev, vf, macaddress, vlanid,
|
|
|
|
stateDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevRestoreNetConfig:
|
|
|
|
* @linkdev: name of the interface
|
|
|
|
* @vf: vf index if linkdev is a pf
|
|
|
|
* @stateDir: directory containing old net config
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -errno on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
2014-03-12 16:01:39 +00:00
|
|
|
virNetDevRestoreNetConfig(const char *linkdev, int vf, const char *stateDir)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
if (vf == -1)
|
|
|
|
return virNetDevRestoreMacAddress(linkdev, stateDir);
|
|
|
|
else
|
|
|
|
return virNetDevRestoreVfConfig(linkdev, vf, stateDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* defined(__linux__) && defined(HAVE_LIBNL) */
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetDevLinkDump(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
int ifindex ATTRIBUTE_UNUSED,
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
void **nlData ATTRIBUTE_UNUSED,
|
2012-03-06 01:12:34 +00:00
|
|
|
struct nlattr **tb ATTRIBUTE_UNUSED,
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
uint32_t src_pid ATTRIBUTE_UNUSED,
|
|
|
|
uint32_t dst_pid ATTRIBUTE_UNUSED)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to dump link info on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2014-03-12 17:17:39 +00:00
|
|
|
virNetDevReplaceNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
2012-03-06 01:12:34 +00:00
|
|
|
int vf ATTRIBUTE_UNUSED,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddress ATTRIBUTE_UNUSED,
|
2012-03-06 01:12:34 +00:00
|
|
|
int vlanid ATTRIBUTE_UNUSED,
|
2014-03-12 17:17:39 +00:00
|
|
|
const char *stateDir ATTRIBUTE_UNUSED)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to replace net config on this platform"));
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2014-03-12 17:17:39 +00:00
|
|
|
virNetDevRestoreNetConfig(const char *linkdev ATTRIBUTE_UNUSED,
|
2012-03-06 01:12:34 +00:00
|
|
|
int vf ATTRIBUTE_UNUSED,
|
2014-03-12 17:17:39 +00:00
|
|
|
const char *stateDir ATTRIBUTE_UNUSED)
|
2012-03-06 01:12:34 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to restore net config on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* defined(__linux__) && defined(HAVE_LIBNL) */
|
2014-06-05 14:14:49 +00:00
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
int
|
|
|
|
virNetDevGetLinkInfo(const char *ifname,
|
|
|
|
virInterfaceLinkPtr lnk)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *path = NULL;
|
|
|
|
char *buf = NULL;
|
|
|
|
char *tmp;
|
|
|
|
int tmp_state;
|
|
|
|
unsigned int tmp_speed;
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&path, ifname, "operstate") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virFileReadAll(path, 1024, &buf) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("unable to read: %s"),
|
|
|
|
path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(tmp = strchr(buf, '\n'))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse: %s"),
|
|
|
|
buf);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
*tmp = '\0';
|
|
|
|
|
|
|
|
/* We shouldn't allow 0 here, because
|
|
|
|
* virInterfaceState enum starts from 1. */
|
|
|
|
if ((tmp_state = virInterfaceStateTypeFromString(buf)) <= 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse: %s"),
|
|
|
|
buf);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
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. */
|
|
|
|
if (lnk->state != VIR_INTERFACE_STATE_UP) {
|
|
|
|
lnk->speed = 0;
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-06-05 14:14:49 +00:00
|
|
|
VIR_FREE(path);
|
|
|
|
VIR_FREE(buf);
|
|
|
|
|
|
|
|
if (virNetDevSysfsFile(&path, ifname, "speed") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
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 */
|
|
|
|
if (errno == EINVAL) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("unable to read: %s"),
|
|
|
|
path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrToLong_ui(buf, &tmp, 10, &tmp_speed) < 0 ||
|
|
|
|
*tmp != '\n') {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse: %s"),
|
|
|
|
buf);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-06-13 09:29:48 +00:00
|
|
|
lnk->speed = tmp_speed;
|
2014-06-05 14:14:49 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(buf);
|
|
|
|
VIR_FREE(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetDevGetLinkInfo(const char *ifname,
|
|
|
|
virInterfaceLinkPtr lnk)
|
|
|
|
{
|
|
|
|
/* 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
|
|
|
|
|
|
|
|
2014-10-29 18:20:47 +00:00
|
|
|
#if defined(SIOCADDMULTI) && defined(HAVE_STRUCT_IFREQ) && \
|
|
|
|
defined(HAVE_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,
|
|
|
|
virMacAddrPtr macaddr)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
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);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevAddMulti(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
virMacAddrPtr macaddr ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to add address to interface "
|
|
|
|
"multicast list on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-10-29 18:20:47 +00:00
|
|
|
#if defined(SIOCDELMULTI) && defined(HAVE_STRUCT_IFREQ) && \
|
|
|
|
defined(HAVE_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,
|
|
|
|
virMacAddrPtr macaddr)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret = -1;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
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);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetDevDelMulti(const char *ifname ATTRIBUTE_UNUSED,
|
|
|
|
virMacAddrPtr macaddr ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Unable to delete address from interface "
|
|
|
|
"multicast list on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast)
|
|
|
|
{
|
|
|
|
int ifindex;
|
|
|
|
int num;
|
|
|
|
char *next;
|
|
|
|
char *token;
|
|
|
|
char *saveptr;
|
|
|
|
char *endptr;
|
|
|
|
|
2014-10-29 20:57:58 +00:00
|
|
|
for (ifindex = 0, 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;
|
|
|
|
|
|
|
|
}
|
|
|
|
mcast->index = num;
|
|
|
|
break;
|
2014-10-29 20:57:58 +00:00
|
|
|
case VIR_MCAST_TYPE_NAME_TOKEN:
|
2014-10-10 17:55:42 +00:00
|
|
|
if (virStrncpy(mcast->name, token, strlen(token),
|
|
|
|
VIR_MCAST_NAME_LEN) == NULL) {
|
|
|
|
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,
|
|
|
|
&mcast->macaddr) < 0) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void virNetDevMcastListClear(virNetDevMcastListPtr mcast)
|
|
|
|
{
|
|
|
|
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,
|
|
|
|
virNetDevMcastListPtr mcast)
|
|
|
|
{
|
|
|
|
char *cur = NULL;
|
|
|
|
char *buf = NULL;
|
|
|
|
char *next = NULL;
|
|
|
|
int ret = -1, len;
|
|
|
|
virNetDevMcastEntryPtr entry = NULL;
|
|
|
|
|
|
|
|
mcast->entries = NULL;
|
|
|
|
mcast->nentries = 0;
|
|
|
|
|
|
|
|
/* Read entire multicast table into memory */
|
|
|
|
if ((len = virFileReadAll(PROC_NET_DEV_MCAST, MAX_MCAST_SIZE, &buf)) <= 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
cur = buf;
|
|
|
|
while (cur) {
|
|
|
|
if (!entry && VIR_ALLOC(entry) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
next = strchr(cur, '\n');
|
|
|
|
if (next)
|
|
|
|
next++;
|
|
|
|
if (virNetDevParseMcast(cur, entry))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* 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))
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
memset(entry, 0, sizeof(virNetDevMcastEntry));
|
|
|
|
}
|
|
|
|
cur = next && ((next - buf) < len) ? next : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2014-10-29 22:29:43 +00:00
|
|
|
VIR_FREE(buf);
|
2014-10-10 17:55:42 +00:00
|
|
|
VIR_FREE(entry);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-20 18:39:44 +00:00
|
|
|
VIR_ENUM_IMPL(virNetDevRxFilterMode,
|
|
|
|
VIR_NETDEV_RX_FILTER_MODE_LAST,
|
|
|
|
"none",
|
|
|
|
"normal",
|
|
|
|
"all");
|
|
|
|
|
|
|
|
|
2014-10-10 17:55:42 +00:00
|
|
|
static int virNetDevGetMulticastTable(const char *ifname,
|
|
|
|
virNetDevRxFilterPtr filter)
|
|
|
|
{
|
|
|
|
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) {
|
|
|
|
if (VIR_ALLOC_N(filter->multicast.table, mcast.nentries) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < mcast.nentries; i++) {
|
|
|
|
virMacAddrSet(&filter->multicast.table[i],
|
|
|
|
&mcast.entries[i]->macaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
filter->multicast.nTable = mcast.nentries;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virNetDevMcastListClear(&mcast);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-20 18:39:44 +00:00
|
|
|
virNetDevRxFilterPtr
|
|
|
|
virNetDevRxFilterNew(void)
|
|
|
|
{
|
|
|
|
virNetDevRxFilterPtr filter;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(filter) < 0)
|
|
|
|
return NULL;
|
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetDevRxFilterFree(virNetDevRxFilterPtr filter)
|
|
|
|
{
|
|
|
|
if (filter) {
|
|
|
|
VIR_FREE(filter->name);
|
|
|
|
VIR_FREE(filter->unicast.table);
|
|
|
|
VIR_FREE(filter->multicast.table);
|
|
|
|
VIR_FREE(filter->vlan.table);
|
|
|
|
VIR_FREE(filter);
|
|
|
|
}
|
|
|
|
}
|
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,
|
|
|
|
virNetDevRxFilterPtr *filter)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
virNetDevRxFilterPtr fil = virNetDevRxFilterNew();
|
|
|
|
|
|
|
|
if (!fil)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetDevGetMAC(ifname, &fil->mac))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virNetDevGetMulticastTable(ifname, fil))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (ret < 0) {
|
|
|
|
virNetDevRxFilterFree(fil);
|
|
|
|
fil = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*filter = fil;
|
|
|
|
return ret;
|
|
|
|
}
|