mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +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
This commit is contained in:
parent
c1df2c14b5
commit
e49c9bf25c
@ -150,7 +150,8 @@ LIBS=$old_libs
|
|||||||
dnl Availability of various common headers (non-fatal if missing).
|
dnl Availability of various common headers (non-fatal if missing).
|
||||||
AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/un.h \
|
AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/un.h \
|
||||||
sys/poll.h syslog.h mntent.h net/ethernet.h linux/magic.h \
|
sys/poll.h syslog.h mntent.h net/ethernet.h linux/magic.h \
|
||||||
sys/un.h sys/syscall.h netinet/tcp.h ifaddrs.h libtasn1.h])
|
sys/un.h sys/syscall.h netinet/tcp.h ifaddrs.h libtasn1.h \
|
||||||
|
net/if.h])
|
||||||
|
|
||||||
dnl Our only use of libtasn1.h is in the testsuite, and can be skipped
|
dnl Our only use of libtasn1.h is in the testsuite, and can be skipped
|
||||||
dnl if the header is not present. Assume -ltasn1 is present if the
|
dnl if the header is not present. Assume -ltasn1 is present if the
|
||||||
|
@ -102,7 +102,6 @@ src/test/test_driver.c
|
|||||||
src/uml/uml_conf.c
|
src/uml/uml_conf.c
|
||||||
src/uml/uml_driver.c
|
src/uml/uml_driver.c
|
||||||
src/util/authhelper.c
|
src/util/authhelper.c
|
||||||
src/util/bridge.c
|
|
||||||
src/util/cgroup.c
|
src/util/cgroup.c
|
||||||
src/util/command.c
|
src/util/command.c
|
||||||
src/util/conf.c
|
src/util/conf.c
|
||||||
@ -127,6 +126,9 @@ src/util/sysinfo.c
|
|||||||
src/util/util.c
|
src/util/util.c
|
||||||
src/util/viraudit.c
|
src/util/viraudit.c
|
||||||
src/util/virfile.c
|
src/util/virfile.c
|
||||||
|
src/util/virnetdev.c
|
||||||
|
src/util/virnetdevbridge.c
|
||||||
|
src/util/virnetdevtap.c
|
||||||
src/util/virpidfile.c
|
src/util/virpidfile.c
|
||||||
src/util/virterror.c
|
src/util/virterror.c
|
||||||
src/util/xml.c
|
src/util/xml.c
|
||||||
|
@ -54,7 +54,6 @@ augeastest_DATA =
|
|||||||
UTIL_SOURCES = \
|
UTIL_SOURCES = \
|
||||||
util/authhelper.c util/authhelper.h \
|
util/authhelper.c util/authhelper.h \
|
||||||
util/bitmap.c util/bitmap.h \
|
util/bitmap.c util/bitmap.h \
|
||||||
util/bridge.c util/bridge.h \
|
|
||||||
util/buf.c util/buf.h \
|
util/buf.c util/buf.h \
|
||||||
util/command.c util/command.h \
|
util/command.c util/command.h \
|
||||||
util/conf.c util/conf.h \
|
util/conf.c util/conf.h \
|
||||||
@ -93,7 +92,10 @@ UTIL_SOURCES = \
|
|||||||
util/xml.c util/xml.h \
|
util/xml.c util/xml.h \
|
||||||
util/virterror.c util/virterror_internal.h \
|
util/virterror.c util/virterror_internal.h \
|
||||||
util/virkeycode.c util/virkeycode.h \
|
util/virkeycode.c util/virkeycode.h \
|
||||||
util/virkeymaps.h
|
util/virkeymaps.h \
|
||||||
|
util/virnetdev.h util/virnetdev.c \
|
||||||
|
util/virnetdevbridge.h util/virnetdevbridge.c \
|
||||||
|
util/virnetdevtap.h util/virnetdevtap.c
|
||||||
|
|
||||||
EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \
|
EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \
|
||||||
$(srcdir)/util/virkeycode-mapgen.py
|
$(srcdir)/util/virkeycode-mapgen.py
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
#include "lxc_driver.h"
|
#include "lxc_driver.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "bridge.h"
|
#include "virnetdevbridge.h"
|
||||||
#include "veth.h"
|
#include "veth.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
@ -55,13 +56,15 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "iptables.h"
|
#include "iptables.h"
|
||||||
#include "bridge.h"
|
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
#include "util/network.h"
|
#include "util/network.h"
|
||||||
#include "configmake.h"
|
#include "configmake.h"
|
||||||
#include "ignore-value.h"
|
#include "ignore-value.h"
|
||||||
|
#include "virnetdev.h"
|
||||||
|
#include "virnetdevbridge.h"
|
||||||
|
#include "virnetdevtap.h"
|
||||||
|
|
||||||
#define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
|
#define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
|
||||||
#define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"
|
#define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"
|
||||||
|
@ -54,7 +54,6 @@
|
|||||||
#include "openvz_conf.h"
|
#include "openvz_conf.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "bridge.h"
|
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "domain_audit.h"
|
#include "domain_audit.h"
|
||||||
#include "domain_conf.h"
|
#include "domain_conf.h"
|
||||||
#include "network/bridge_driver.h"
|
#include "network/bridge_driver.h"
|
||||||
|
#include "virnetdevtap.h"
|
||||||
|
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
# include "ebtables.h"
|
# include "ebtables.h"
|
||||||
# include "internal.h"
|
# include "internal.h"
|
||||||
# include "bridge.h"
|
|
||||||
# include "capabilities.h"
|
# include "capabilities.h"
|
||||||
# include "network_conf.h"
|
# include "network_conf.h"
|
||||||
# include "domain_conf.h"
|
# include "domain_conf.h"
|
||||||
|
@ -43,11 +43,11 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "bridge.h"
|
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "domain_nwfilter.h"
|
#include "domain_nwfilter.h"
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "virnetdevtap.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_UML
|
#define VIR_FROM_THIS VIR_FROM_UML
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
# define __UML_CONF_H
|
# define __UML_CONF_H
|
||||||
|
|
||||||
# include "internal.h"
|
# include "internal.h"
|
||||||
# include "bridge.h"
|
|
||||||
# include "capabilities.h"
|
# include "capabilities.h"
|
||||||
# include "network_conf.h"
|
# include "network_conf.h"
|
||||||
# include "domain_conf.h"
|
# include "domain_conf.h"
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "fdstream.h"
|
#include "fdstream.h"
|
||||||
#include "configmake.h"
|
#include "configmake.h"
|
||||||
|
#include "virnetdevtap.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_UML
|
#define VIR_FROM_THIS VIR_FROM_UML
|
||||||
|
|
||||||
|
1115
src/util/bridge.c
1115
src/util/bridge.c
File diff suppressed because it is too large
Load Diff
@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2007 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Mark McLoughlin <markmc@redhat.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __QEMUD_BRIDGE_H__
|
|
||||||
# define __QEMUD_BRIDGE_H__
|
|
||||||
|
|
||||||
# include <config.h>
|
|
||||||
|
|
||||||
# if defined(WITH_BRIDGE)
|
|
||||||
|
|
||||||
# include <net/if.h>
|
|
||||||
# include <netinet/in.h>
|
|
||||||
# include "network.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BR_IFNAME_MAXLEN:
|
|
||||||
* maximum size in byte of the name for an interface
|
|
||||||
*/
|
|
||||||
# define BR_IFNAME_MAXLEN IF_NAMESIZE
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BR_INET_ADDR_MAXLEN:
|
|
||||||
* maximum size in bytes for an inet addess name
|
|
||||||
*/
|
|
||||||
# define BR_INET_ADDR_MAXLEN INET_ADDRSTRLEN
|
|
||||||
|
|
||||||
int virNetDevBridgeCreate(const char *brname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevBridgeDelete(const char *brname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevExists(const char *brname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevBridgeAddPort(const char *brname,
|
|
||||||
const char *ifname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevBridgeRemovePort(const char *brname,
|
|
||||||
const char *ifname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BR_TAP_VNET_HDR = (1 << 0),
|
|
||||||
BR_TAP_PERSIST = (1 << 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
int virNetDevTapCreateInBridgePort(const char *brname,
|
|
||||||
char **ifname,
|
|
||||||
const unsigned char *macaddr,
|
|
||||||
int vnet_hdr,
|
|
||||||
bool up,
|
|
||||||
int *tapfd)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
|
||||||
ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
|
|
||||||
int virNetDevTapDelete(const char *ifname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevSetOnline(const char *ifname,
|
|
||||||
bool online)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevIsOnline(const char *ifname,
|
|
||||||
bool *online)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevSetIPv4Address(const char *ifname,
|
|
||||||
virSocketAddr *addr,
|
|
||||||
unsigned int prefix)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevClearIPv4Address(const char *ifname,
|
|
||||||
virSocketAddr *addr,
|
|
||||||
unsigned int prefix)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevBridgeSetSTPDelay(const char *brname,
|
|
||||||
int delay)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevBridgeGetSTPDelay(const char *brname,
|
|
||||||
int *delay)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevBridgeSetSTP(const char *brname,
|
|
||||||
bool enable)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevBridgeGetSTP(const char *brname,
|
|
||||||
bool *enable)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevTapCreate(char **ifname,
|
|
||||||
int vnet_hdr,
|
|
||||||
int *tapfd)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
int virNetDevSetMAC(const char *ifname,
|
|
||||||
const unsigned char *macaddr)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevGetMAC(const char *ifname,
|
|
||||||
unsigned char *macaddr)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevSetMTU(const char *ifname,
|
|
||||||
int mtu)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevSetMTUFromDevice(const char *ifname,
|
|
||||||
const char *otherifname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
int virNetDevGetMTU(const char *ifname)
|
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
|
||||||
|
|
||||||
# endif /* WITH_BRIDGE */
|
|
||||||
|
|
||||||
#endif /* __QEMUD_BRIDGE_H__ */
|
|
524
src/util/virnetdev.c
Normal file
524
src/util/virnetdev.c
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark McLoughlin <markmc@redhat.com>
|
||||||
|
* Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "virnetdev.h"
|
||||||
|
#include "virfile.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef HAVE_NET_IF_H
|
||||||
|
# include <net/if.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
|
#ifdef HAVE_NET_IF_H
|
||||||
|
static int virNetDevSetupControlFull(const char *ifname,
|
||||||
|
struct ifreq *ifr,
|
||||||
|
int domain,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
memset(ifr, 0, sizeof(*ifr));
|
||||||
|
|
||||||
|
if (virStrcpyStatic(ifr->ifr_name, ifname) == NULL) {
|
||||||
|
virReportSystemError(ERANGE,
|
||||||
|
_("Network interface name '%s' is too long"),
|
||||||
|
ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int virNetDevSetupControl(const char *ifname,
|
||||||
|
struct ifreq *ifr)
|
||||||
|
{
|
||||||
|
return virNetDevSetupControlFull(ifname, ifr, AF_PACKET, SOCK_DGRAM);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCGIFFLAGS
|
||||||
|
/**
|
||||||
|
* 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)) {
|
||||||
|
if (errno == ENODEV)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to check interface flags for %s"), ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevExists(const char *ifname)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to check interface %s"), ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCGIFHWADDR
|
||||||
|
/**
|
||||||
|
* virNetDevSetMAC:
|
||||||
|
* @ifname: interface name to set MTU for
|
||||||
|
* @macaddr: MAC address (VIR_MAC_BUFLEN in size)
|
||||||
|
*
|
||||||
|
* 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,
|
||||||
|
const unsigned char *macaddr)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN);
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Cannot set interface MAC on '%s'"),
|
||||||
|
ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevSetMAC(const char *ifname,
|
||||||
|
const unsigned char *macaddr ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Cannot set interface MAC on '%s'"),
|
||||||
|
ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCGIFHWADDR
|
||||||
|
/**
|
||||||
|
* virNetDevGetMAC:
|
||||||
|
* @ifname: interface name to set MTU for
|
||||||
|
* @macaddr: MAC address (VIR_MAC_BUFLEN in size)
|
||||||
|
*
|
||||||
|
* 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,
|
||||||
|
unsigned char *macaddr)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(macaddr, ifr.ifr_hwaddr.sa_data, VIR_MAC_BUFLEN);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevGetMAC(const char *ifname,
|
||||||
|
unsigned char *macaddr ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Cannot get interface MAC on '%s'"),
|
||||||
|
ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCGIFMTU
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevGetMTU(const char *ifname)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Cannot get interface MTU on '%s'"),
|
||||||
|
ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCSIFMTU
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCSIFFLAGS
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SIOCGIFFLAGS
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
if (!(addrstr = virSocketFormatAddr(addr)))
|
||||||
|
goto cleanup;
|
||||||
|
/* format up a broadcast address if this is IPv4 */
|
||||||
|
if ((VIR_SOCKET_IS_FAMILY(addr, AF_INET)) &&
|
||||||
|
((virSocketAddrBroadcastByPrefix(addr, prefix, &broadcast) < 0) ||
|
||||||
|
!(bcaststr = virSocketFormatAddr(&broadcast)))) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(addrstr);
|
||||||
|
VIR_FREE(bcaststr);
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
if (!(addrstr = virSocketFormatAddr(addr)))
|
||||||
|
goto cleanup;
|
||||||
|
cmd = virCommandNew(IP_PATH);
|
||||||
|
virCommandAddArgList(cmd, "addr", "del", NULL);
|
||||||
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
||||||
|
virCommandAddArgList(cmd, "dev", ifname, NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(addrstr);
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
63
src/util/virnetdev.h
Normal file
63
src/util/virnetdev.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark McLoughlin <markmc@redhat.com>
|
||||||
|
* Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_NETDEV_H__
|
||||||
|
# define __VIR_NETDEV_H__
|
||||||
|
|
||||||
|
# include "network.h"
|
||||||
|
|
||||||
|
int virNetDevExists(const char *brname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevSetOnline(const char *ifname,
|
||||||
|
bool online)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevIsOnline(const char *ifname,
|
||||||
|
bool *online)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevSetIPv4Address(const char *ifname,
|
||||||
|
virSocketAddr *addr,
|
||||||
|
unsigned int prefix)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevClearIPv4Address(const char *ifname,
|
||||||
|
virSocketAddr *addr,
|
||||||
|
unsigned int prefix)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
|
||||||
|
int virNetDevSetMAC(const char *ifname,
|
||||||
|
const unsigned char *macaddr)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevGetMAC(const char *ifname,
|
||||||
|
unsigned char *macaddr)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevSetMTU(const char *ifname,
|
||||||
|
int mtu)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevSetMTUFromDevice(const char *ifname,
|
||||||
|
const char *otherifname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevGetMTU(const char *ifname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
#endif /* __VIR_NETDEV_H__ */
|
527
src/util/virnetdevbridge.c
Normal file
527
src/util/virnetdevbridge.c
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark McLoughlin <markmc@redhat.com>
|
||||||
|
* Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "virnetdevbridge.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "virfile.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "intprops.h"
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef HAVE_NET_IF_H
|
||||||
|
# include <net/if.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __linux__
|
||||||
|
# include <linux/sockios.h>
|
||||||
|
# include <linux/param.h> /* HZ */
|
||||||
|
# include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */
|
||||||
|
|
||||||
|
# define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
|
||||||
|
# define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_NET_IF_H
|
||||||
|
static int virNetDevSetupControlFull(const char *ifname,
|
||||||
|
struct ifreq *ifr,
|
||||||
|
int domain,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (ifname && ifr) {
|
||||||
|
memset(ifr, 0, sizeof(*ifr));
|
||||||
|
|
||||||
|
if (virStrcpyStatic(ifr->ifr_name, ifname) == NULL) {
|
||||||
|
virReportSystemError(ERANGE,
|
||||||
|
_("Network interface name '%s' is too long"),
|
||||||
|
ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int virNetDevSetupControl(const char *ifname,
|
||||||
|
struct ifreq *ifr)
|
||||||
|
{
|
||||||
|
return virNetDevSetupControlFull(ifname, ifr, AF_PACKET, SOCK_DGRAM);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
# define SYSFS_NET_DIR "/sys/class/net"
|
||||||
|
/*
|
||||||
|
* Bridge parameters can be set via sysfs on newish kernels,
|
||||||
|
* or by ioctl on older kernels. Perhaps we could just use
|
||||||
|
* ioctl for every kernel, but its not clear what the long
|
||||||
|
* term lifespan of the ioctl interface is...
|
||||||
|
*/
|
||||||
|
static int virNetDevBridgeSet(const char *brname,
|
||||||
|
const char *paramname, /* sysfs param name */
|
||||||
|
unsigned long value, /* new value */
|
||||||
|
int fd, /* control socket */
|
||||||
|
struct ifreq *ifr) /* pre-filled bridge name */
|
||||||
|
{
|
||||||
|
char *path = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (virAsprintf(&path, "%s/%s/bridge/%s", SYSFS_NET_DIR, brname, paramname) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virFileExists(path)) {
|
||||||
|
char valuestr[INT_BUFSIZE_BOUND(value)];
|
||||||
|
snprintf(valuestr, sizeof(valuestr), "%lu", value);
|
||||||
|
if (virFileWriteStr(path, valuestr, 0) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to set bridge %s %s"), brname, paramname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned long paramid;
|
||||||
|
if (STREQ(paramname, "stp_state")) {
|
||||||
|
paramid = BRCTL_SET_BRIDGE_STP_STATE;
|
||||||
|
} else if (STREQ(paramname, "forward_delay")) {
|
||||||
|
paramid = BRCTL_SET_BRIDGE_FORWARD_DELAY;
|
||||||
|
} else {
|
||||||
|
virReportSystemError(EINVAL,
|
||||||
|
_("Unable to set bridge %s %s"), brname, paramname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
unsigned long args[] = { paramid, value, 0, 0 };
|
||||||
|
ifr->ifr_data = (char*)&args;
|
||||||
|
if (ioctl(fd, SIOCDEVPRIVATE, ifr) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to set bridge %s %s"), brname, paramname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int virNetDevBridgeGet(const char *brname,
|
||||||
|
const char *paramname, /* sysfs param name */
|
||||||
|
unsigned long *value, /* current value */
|
||||||
|
int fd, /* control socket */
|
||||||
|
struct ifreq *ifr) /* pre-filled bridge name */
|
||||||
|
{
|
||||||
|
char *path = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (virAsprintf(&path, "%s/%s/bridge/%s", SYSFS_NET_DIR, brname, paramname) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virFileExists(path)) {
|
||||||
|
char *valuestr;
|
||||||
|
if (virFileReadAll(path, INT_BUFSIZE_BOUND(unsigned long), &valuestr) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virStrToLong_ul(valuestr, NULL, 10, value) < 0) {
|
||||||
|
virReportSystemError(EINVAL,
|
||||||
|
_("Unable to get bridge %s %s"), brname, paramname);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct __bridge_info info;
|
||||||
|
unsigned long args[] = { BRCTL_GET_BRIDGE_INFO, (unsigned long)&info, 0, 0 };
|
||||||
|
ifr->ifr_data = (char*)&args;
|
||||||
|
if (ioctl(fd, SIOCDEVPRIVATE, ifr) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to get bridge %s %s"), brname, paramname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STREQ(paramname, "stp_state")) {
|
||||||
|
*value = info.stp_enabled;
|
||||||
|
} else if (STREQ(paramname, "forward_delay")) {
|
||||||
|
*value = info.forward_delay;
|
||||||
|
} else {
|
||||||
|
virReportSystemError(EINVAL,
|
||||||
|
_("Unable to get bridge %s %s"), brname, paramname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeCreate:
|
||||||
|
* @brname: the bridge name
|
||||||
|
*
|
||||||
|
* This function register a new bridge
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or -1 on failure
|
||||||
|
*/
|
||||||
|
#ifdef SIOCBRADDBR
|
||||||
|
int virNetDevBridgeCreate(const char *brname)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCBRADDBR, brname) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to create bridge %s"), brname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevBridgeCreate(const char *brname)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to create bridge %s"), brname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeDelete:
|
||||||
|
* @brname: the bridge name
|
||||||
|
*
|
||||||
|
* Remove a bridge from the layer.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or an errno code in case of failure.
|
||||||
|
*/
|
||||||
|
#ifdef SIOCBRDELBR
|
||||||
|
int virNetDevBridgeDelete(const char *brname)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCBRDELBR, brname) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to delete bridge %s"), brname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevBridgeDelete(const char *brname ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to delete bridge %s"), brname);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeAddPort:
|
||||||
|
* @brname: the bridge name
|
||||||
|
* @ifname: the network interface name
|
||||||
|
*
|
||||||
|
* Adds an interface to a bridge
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or an errno code in case of failure.
|
||||||
|
*/
|
||||||
|
#ifdef SIOCBRADDIF
|
||||||
|
int virNetDevBridgeAddPort(const char *brname,
|
||||||
|
const char *ifname)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(ifr.ifr_ifindex = if_nametoindex(ifname))) {
|
||||||
|
virReportSystemError(ENODEV,
|
||||||
|
_("Unable to get interface index for %s"), ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to add bridge %s port %s"), brname, ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevBridgeAddPort(const char *brname,
|
||||||
|
const char *ifname)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to add bridge %s port %s"), brname, ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeRemovePort:
|
||||||
|
* @brname: the bridge name
|
||||||
|
* @ifname: the network interface name
|
||||||
|
*
|
||||||
|
* Removes an interface from a bridge
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or an errno code in case of failure.
|
||||||
|
*/
|
||||||
|
#ifdef SIOCBRDELIF
|
||||||
|
int virNetDevBridgeRemovePort(const char *brname,
|
||||||
|
const char *ifname)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(ifr.ifr_ifindex = if_nametoindex(ifname))) {
|
||||||
|
virReportSystemError(ENODEV,
|
||||||
|
_("Unable to get interface index for %s"), ifname);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCBRDELIF, &ifr) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to remove bridge %s port %s"), brname, ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virNetDevBridgeRemovePort(const char *brname,
|
||||||
|
const char *ifname)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to remove bridge %s port %s"), brname, ifname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeSetSTPDelay:
|
||||||
|
* @brname: the bridge name
|
||||||
|
* @delay: delay in seconds
|
||||||
|
*
|
||||||
|
* Set the bridge forward delay
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or -1 on failure
|
||||||
|
*/
|
||||||
|
|
||||||
|
int virNetDevBridgeSetSTPDelay(const char *brname,
|
||||||
|
int delay)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = virNetDevBridgeSet(brname, "stp_state", MS_TO_JIFFIES(delay),
|
||||||
|
fd, &ifr);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeGetSTPDelay:
|
||||||
|
* @brname: the bridge device name
|
||||||
|
* @delayms: the forward delay in milliseconds
|
||||||
|
*
|
||||||
|
* Retrives the forward delay for the bridge device @brname
|
||||||
|
* storing it in @delayms. The forward delay is only meaningful
|
||||||
|
* if STP is enabled
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 on error+
|
||||||
|
*/
|
||||||
|
int virNetDevBridgeGetSTPDelay(const char *brname,
|
||||||
|
int *delayms)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = virNetDevBridgeGet(brname, "stp_state", &i,
|
||||||
|
fd, &ifr);
|
||||||
|
*delayms = JIFFIES_TO_MS(i);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeSetSTP:
|
||||||
|
* @brname: the bridge name
|
||||||
|
* @enable: 1 to enable, 0 to disable
|
||||||
|
*
|
||||||
|
* Control whether the bridge participates in the spanning tree protocol,
|
||||||
|
* in general don't disable it without good reasons.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or -1 on failure
|
||||||
|
*/
|
||||||
|
int virNetDevBridgeSetSTP(const char *brname,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = virNetDevBridgeSet(brname, "stp_state", enable ? 1 : 0,
|
||||||
|
fd, &ifr);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevBridgeGetSTP:
|
||||||
|
* @brname: the bridge device name
|
||||||
|
* @enabled: returns the STP state
|
||||||
|
*
|
||||||
|
* Determine the state of the spanning tree protocol on
|
||||||
|
* the device @brname, returning the state in @enabled
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int virNetDevBridgeGetSTP(const char *brname,
|
||||||
|
bool *enabled)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
struct ifreq ifr;
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = virNetDevBridgeGet(brname, "stp_state", &i,
|
||||||
|
fd, &ifr);
|
||||||
|
*enabled = i ? true : false;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else /* !__linux__ */
|
||||||
|
int virNetDevBridgeSetSTPDelay(const char *brname,
|
||||||
|
int delay ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to set STP delay on %s on this platform"),
|
||||||
|
brname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int virNetDevBridgeGetSTPDelay(const char *brname,
|
||||||
|
int *delay ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to get STP delay on %s on this platform"),
|
||||||
|
brname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int virNetDevBridgeSetSTP(const char *brname,
|
||||||
|
bool enable ATTRIBUTE_UNUSED)
|
||||||
|
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to set STP on %s on this platform"),
|
||||||
|
brname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int virNetDevBridgeGetSTP(const char *brname,
|
||||||
|
bool *enable ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS,
|
||||||
|
_("Unable to get STP on %s on this platform"),
|
||||||
|
brname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* __linux__ */
|
54
src/util/virnetdevbridge.h
Normal file
54
src/util/virnetdevbridge.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark McLoughlin <markmc@redhat.com>
|
||||||
|
* Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_NETDEV_BRIDGE_H__
|
||||||
|
# define __VIR_NETDEV_BRIDGE_H__
|
||||||
|
|
||||||
|
# include "internal.h"
|
||||||
|
|
||||||
|
int virNetDevBridgeCreate(const char *brname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevBridgeDelete(const char *brname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevBridgeAddPort(const char *brname,
|
||||||
|
const char *ifname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevBridgeRemovePort(const char *brname,
|
||||||
|
const char *ifname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevBridgeSetSTPDelay(const char *brname,
|
||||||
|
int delay)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevBridgeGetSTPDelay(const char *brname,
|
||||||
|
int *delay)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevBridgeSetSTP(const char *brname,
|
||||||
|
bool enable)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
int virNetDevBridgeGetSTP(const char *brname,
|
||||||
|
bool *enable)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
#endif /* __VIR_NETDEV_BRIDGE_H__ */
|
300
src/util/virnetdevtap.c
Normal file
300
src/util/virnetdevtap.c
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark McLoughlin <markmc@redhat.com>
|
||||||
|
* Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "virnetdevtap.h"
|
||||||
|
#include "virnetdev.h"
|
||||||
|
#include "virnetdevbridge.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "virfile.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef HAVE_NET_IF_H
|
||||||
|
# include <net/if.h>
|
||||||
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
#ifdef __linux__
|
||||||
|
# include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevProbeVnetHdr:
|
||||||
|
* @tapfd: a tun/tap file descriptor
|
||||||
|
*
|
||||||
|
* Check whether it is safe to enable the IFF_VNET_HDR flag on the
|
||||||
|
* tap interface.
|
||||||
|
*
|
||||||
|
* Setting IFF_VNET_HDR enables QEMU's virtio_net driver to allow
|
||||||
|
* guests to pass larger (GSO) packets, with partial checksums, to
|
||||||
|
* the host. This greatly increases the achievable throughput.
|
||||||
|
*
|
||||||
|
* It is only useful to enable this when we're setting up a virtio
|
||||||
|
* interface. And it is only *safe* to enable it when we know for
|
||||||
|
* sure that a) qemu has support for IFF_VNET_HDR and b) the running
|
||||||
|
* kernel implements the TUNGETIFF ioctl(), which qemu needs to query
|
||||||
|
* the supplied tapfd.
|
||||||
|
*
|
||||||
|
* Returns 1 if VnetHdr is supported, 0 if not supported
|
||||||
|
*/
|
||||||
|
#ifdef IFF_VNET_HDR
|
||||||
|
static int
|
||||||
|
virNetDevProbeVnetHdr(int tapfd)
|
||||||
|
{
|
||||||
|
# if defined(IFF_VNET_HDR) && defined(TUNGETFEATURES) && defined(TUNGETIFF)
|
||||||
|
unsigned int features;
|
||||||
|
struct ifreq dummy;
|
||||||
|
|
||||||
|
if (ioctl(tapfd, TUNGETFEATURES, &features) != 0) {
|
||||||
|
VIR_INFO("Not enabling IFF_VNET_HDR; "
|
||||||
|
"TUNGETFEATURES ioctl() not implemented");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(features & IFF_VNET_HDR)) {
|
||||||
|
VIR_INFO("Not enabling IFF_VNET_HDR; "
|
||||||
|
"TUNGETFEATURES ioctl() reports no IFF_VNET_HDR");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The kernel will always return -1 at this point.
|
||||||
|
* If TUNGETIFF is not implemented then errno == EBADFD.
|
||||||
|
*/
|
||||||
|
if (ioctl(tapfd, TUNGETIFF, &dummy) != -1 || errno != EBADFD) {
|
||||||
|
VIR_INFO("Not enabling IFF_VNET_HDR; "
|
||||||
|
"TUNGETIFF ioctl() not implemented");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_INFO("Enabling IFF_VNET_HDR");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
# else
|
||||||
|
(void) tapfd;
|
||||||
|
VIR_INFO("Not enabling IFF_VNET_HDR; disabled at build time");
|
||||||
|
return 0;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TUNSETIFF
|
||||||
|
/**
|
||||||
|
* brCreateTap:
|
||||||
|
* @ifname: the interface name
|
||||||
|
* @vnet_hr: whether to try enabling IFF_VNET_HDR
|
||||||
|
* @tapfd: file descriptor return value for the new tap device
|
||||||
|
*
|
||||||
|
* Creates a tap interface.
|
||||||
|
* If the @tapfd parameter is supplied, the open tap device file
|
||||||
|
* descriptor will be returned, otherwise the TAP device will be made
|
||||||
|
* persistent and closed. The caller must use brDeleteTap to remove
|
||||||
|
* a persistent TAP devices when it is no longer needed.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or an errno code in case of failure.
|
||||||
|
*/
|
||||||
|
int virNetDevTapCreate(char **ifname,
|
||||||
|
int vnet_hdr ATTRIBUTE_UNUSED,
|
||||||
|
int *tapfd)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct ifreq ifr;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||||
|
virReportSystemError(errno, "%s",
|
||||||
|
_("Unable to open /dev/net/tun, is tun module loaded?"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
|
||||||
|
ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
|
||||||
|
|
||||||
|
# ifdef IFF_VNET_HDR
|
||||||
|
if (vnet_hdr && virNetDevProbeVnetHdr(fd))
|
||||||
|
ifr.ifr_flags |= IFF_VNET_HDR;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) {
|
||||||
|
virReportSystemError(ERANGE,
|
||||||
|
_("Network interface name '%s' is too long"),
|
||||||
|
*ifname);
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to create tap device %s"),
|
||||||
|
NULLSTR(*ifname));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tapfd &&
|
||||||
|
(errno = ioctl(fd, TUNSETPERSIST, 1))) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to set tap device %s to persistent"),
|
||||||
|
NULLSTR(*ifname));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_FREE(*ifname);
|
||||||
|
if (!(*ifname = strdup(ifr.ifr_name))) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (tapfd)
|
||||||
|
*tapfd = fd;
|
||||||
|
else
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (ret < 0)
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int virNetDevTapDelete(const char *ifname)
|
||||||
|
{
|
||||||
|
struct ifreq try;
|
||||||
|
int fd;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||||
|
virReportSystemError(errno, "%s",
|
||||||
|
_("Unable to open /dev/net/tun, is tun module loaded?"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&try, 0, sizeof(struct ifreq));
|
||||||
|
try.ifr_flags = IFF_TAP|IFF_NO_PI;
|
||||||
|
|
||||||
|
if (virStrcpyStatic(try.ifr_name, ifname) == NULL) {
|
||||||
|
virReportSystemError(ERANGE,
|
||||||
|
_("Network interface name '%s' is too long"),
|
||||||
|
ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, TUNSETIFF, &try) < 0) {
|
||||||
|
virReportSystemError(errno, "%s",
|
||||||
|
_("Unable to associate TAP device"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, TUNSETPERSIST, 0) < 0) {
|
||||||
|
virReportSystemError(errno, "%s",
|
||||||
|
_("Unable to make TAP device non-persistent"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else /* ! TUNSETIFF */
|
||||||
|
int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED,
|
||||||
|
int vnet_hdr ATTRIBUTE_UNUSED,
|
||||||
|
int *tapfd ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS, "%s",
|
||||||
|
_("Unable to create TAP devices on this platform"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virReportSystemError(ENOSYS, "%s",
|
||||||
|
_("Unable to delete TAP devices on this platform"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* ! TUNSETIFF */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevTapCreateInBridgePort:
|
||||||
|
* @brname: the bridge name
|
||||||
|
* @ifname: the interface name (or name template)
|
||||||
|
* @macaddr: desired MAC address (VIR_MAC_BUFLEN long)
|
||||||
|
* @vnet_hdr: whether to try enabling IFF_VNET_HDR
|
||||||
|
* @tapfd: file descriptor return value for the new tap device
|
||||||
|
*
|
||||||
|
* This function creates a new tap device on a bridge. @ifname can be either
|
||||||
|
* a fixed name or a name template with '%d' for dynamic name allocation.
|
||||||
|
* in either case the final name for the bridge will be stored in @ifname.
|
||||||
|
* If the @tapfd parameter is supplied, the open tap device file
|
||||||
|
* descriptor will be returned, otherwise the TAP device will be made
|
||||||
|
* persistent and closed. The caller must use brDeleteTap to remove
|
||||||
|
* a persistent TAP devices when it is no longer needed.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or -1 on failure
|
||||||
|
*/
|
||||||
|
int virNetDevTapCreateInBridgePort(const char *brname,
|
||||||
|
char **ifname,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
int vnet_hdr,
|
||||||
|
bool up,
|
||||||
|
int *tapfd)
|
||||||
|
{
|
||||||
|
if (virNetDevTapCreate(ifname, vnet_hdr, tapfd) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* We need to set the interface MAC before adding it
|
||||||
|
* to the bridge, because the bridge assumes the lowest
|
||||||
|
* MAC of all enslaved interfaces & we don't want it
|
||||||
|
* seeing the kernel allocate random MAC for the TAP
|
||||||
|
* device before we set our static MAC.
|
||||||
|
*/
|
||||||
|
if (virNetDevSetMAC(*ifname, macaddr) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* We need to set the interface MTU before adding it
|
||||||
|
* to the bridge, because the bridge will have its
|
||||||
|
* MTU adjusted automatically when we add the new interface.
|
||||||
|
*/
|
||||||
|
if (virNetDevSetMTUFromDevice(*ifname, brname) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virNetDevBridgeAddPort(brname, *ifname) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virNetDevSetOnline(*ifname, up) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
VIR_FORCE_CLOSE(*tapfd);
|
||||||
|
|
||||||
|
return errno;
|
||||||
|
}
|
45
src/util/virnetdevtap.h
Normal file
45
src/util/virnetdevtap.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2011 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark McLoughlin <markmc@redhat.com>
|
||||||
|
* Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_NETDEV_TAP_H__
|
||||||
|
# define __VIR_NETDEV_TAP_H__
|
||||||
|
|
||||||
|
# include "internal.h"
|
||||||
|
|
||||||
|
int virNetDevTapCreate(char **ifname,
|
||||||
|
int vnet_hdr,
|
||||||
|
int *tapfd)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevTapDelete(const char *ifname)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
int virNetDevTapCreateInBridgePort(const char *brname,
|
||||||
|
char **ifname,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
int vnet_hdr,
|
||||||
|
bool up,
|
||||||
|
int *tapfd)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
||||||
|
ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
|
#endif /* __VIR_NETDEV_TAP_H__ */
|
Loading…
Reference in New Issue
Block a user