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:
Daniel P. Berrange 2011-11-02 13:41:58 +00:00
parent c1df2c14b5
commit e49c9bf25c
19 changed files with 1530 additions and 1254 deletions

View File

@ -150,7 +150,8 @@ LIBS=$old_libs
dnl Availability of various common headers (non-fatal if missing).
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/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 if the header is not present. Assume -ltasn1 is present if the

View File

@ -102,7 +102,6 @@ src/test/test_driver.c
src/uml/uml_conf.c
src/uml/uml_driver.c
src/util/authhelper.c
src/util/bridge.c
src/util/cgroup.c
src/util/command.c
src/util/conf.c
@ -127,6 +126,9 @@ src/util/sysinfo.c
src/util/util.c
src/util/viraudit.c
src/util/virfile.c
src/util/virnetdev.c
src/util/virnetdevbridge.c
src/util/virnetdevtap.c
src/util/virpidfile.c
src/util/virterror.c
src/util/xml.c

View File

@ -54,7 +54,6 @@ augeastest_DATA =
UTIL_SOURCES = \
util/authhelper.c util/authhelper.h \
util/bitmap.c util/bitmap.h \
util/bridge.c util/bridge.h \
util/buf.c util/buf.h \
util/command.c util/command.h \
util/conf.c util/conf.h \
@ -93,7 +92,10 @@ UTIL_SOURCES = \
util/xml.c util/xml.h \
util/virterror.c util/virterror_internal.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 \
$(srcdir)/util/virkeycode-mapgen.py

View File

@ -43,7 +43,7 @@
#include "lxc_driver.h"
#include "memory.h"
#include "util.h"
#include "bridge.h"
#include "virnetdevbridge.h"
#include "veth.h"
#include "nodeinfo.h"
#include "uuid.h"

View File

@ -42,6 +42,7 @@
#include <stdio.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include "virterror_internal.h"
#include "datatypes.h"
@ -55,13 +56,15 @@
#include "memory.h"
#include "uuid.h"
#include "iptables.h"
#include "bridge.h"
#include "interface.h"
#include "logging.h"
#include "dnsmasq.h"
#include "util/network.h"
#include "configmake.h"
#include "ignore-value.h"
#include "virnetdev.h"
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
#define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
#define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"

View File

@ -54,7 +54,6 @@
#include "openvz_conf.h"
#include "nodeinfo.h"
#include "memory.h"
#include "bridge.h"
#include "virfile.h"
#include "logging.h"
#include "command.h"

View File

@ -38,6 +38,7 @@
#include "domain_audit.h"
#include "domain_conf.h"
#include "network/bridge_driver.h"
#include "virnetdevtap.h"
#include <sys/utsname.h>
#include <sys/stat.h>

View File

@ -28,7 +28,6 @@
# include "ebtables.h"
# include "internal.h"
# include "bridge.h"
# include "capabilities.h"
# include "network_conf.h"
# include "domain_conf.h"

View File

@ -43,11 +43,11 @@
#include "util.h"
#include "memory.h"
#include "nodeinfo.h"
#include "bridge.h"
#include "logging.h"
#include "domain_nwfilter.h"
#include "virfile.h"
#include "command.h"
#include "virnetdevtap.h"
#define VIR_FROM_THIS VIR_FROM_UML

View File

@ -25,7 +25,6 @@
# define __UML_CONF_H
# include "internal.h"
# include "bridge.h"
# include "capabilities.h"
# include "network_conf.h"
# include "domain_conf.h"

View File

@ -62,6 +62,7 @@
#include "virfile.h"
#include "fdstream.h"
#include "configmake.h"
#include "virnetdevtap.h"
#define VIR_FROM_THIS VIR_FROM_UML

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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
View 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
View 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__ */

View 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
View 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
View 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__ */