2007-02-14 16:02:40 +00:00
|
|
|
/*
|
2009-02-05 16:03:11 +00:00
|
|
|
* Copyright (C) 2007, 2009 Red Hat, Inc.
|
2007-02-14 16:02:40 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2009-01-05 14:07:31 +00:00
|
|
|
#if defined(WITH_BRIDGE)
|
2007-11-26 11:50:16 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "bridge.h"
|
2010-11-09 20:48:48 +00:00
|
|
|
# include "files.h"
|
2010-03-09 18:22:22 +00:00
|
|
|
|
|
|
|
# include <stdlib.h>
|
|
|
|
# include <stdio.h>
|
|
|
|
# include <string.h>
|
|
|
|
# include <unistd.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <errno.h>
|
|
|
|
# include <arpa/inet.h>
|
|
|
|
# include <sys/types.h>
|
|
|
|
# include <sys/socket.h>
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
# include <paths.h>
|
|
|
|
# include <sys/wait.h>
|
|
|
|
|
|
|
|
# include <linux/param.h> /* HZ */
|
|
|
|
# include <linux/sockios.h> /* SIOCBRADDBR etc. */
|
|
|
|
# include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */
|
|
|
|
# include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */
|
|
|
|
# include <net/if_arp.h> /* ARPHRD_ETHER */
|
|
|
|
|
|
|
|
# include "internal.h"
|
2010-12-14 17:14:39 +00:00
|
|
|
# include "command.h"
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "memory.h"
|
|
|
|
# include "util.h"
|
|
|
|
# include "logging.h"
|
2010-10-21 10:13:05 +00:00
|
|
|
# include "network.h"
|
2010-03-09 18:22:22 +00:00
|
|
|
|
|
|
|
# define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
|
|
|
|
# define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
struct _brControl {
|
|
|
|
int fd;
|
|
|
|
};
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brInit:
|
|
|
|
* @ctlp: pointer to bridge control return value
|
|
|
|
*
|
|
|
|
* Initialize a new bridge layer. In case of success
|
|
|
|
* @ctlp will contain a pointer to the new bridge structure.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, an error code otherwise.
|
|
|
|
*/
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brInit(brControl **ctlp)
|
|
|
|
{
|
|
|
|
int fd;
|
2007-02-16 18:26:18 +00:00
|
|
|
int flags;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
if (!ctlp || *ctlp)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return errno;
|
|
|
|
|
2007-02-16 18:26:18 +00:00
|
|
|
if ((flags = fcntl(fd, F_GETFD)) < 0 ||
|
|
|
|
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
|
|
|
|
int err = errno;
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2007-02-16 18:26:18 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC(*ctlp) < 0) {
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2007-02-14 16:02:40 +00:00
|
|
|
return ENOMEM;
|
2007-06-29 13:23:13 +00:00
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
(*ctlp)->fd = fd;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brShutdown:
|
|
|
|
* @ctl: pointer to a bridge control
|
|
|
|
*
|
|
|
|
* Shutdown the bridge layer and deallocate the associated structures
|
|
|
|
*/
|
2007-02-14 16:02:40 +00:00
|
|
|
void
|
|
|
|
brShutdown(brControl *ctl)
|
|
|
|
{
|
|
|
|
if (!ctl)
|
|
|
|
return;
|
|
|
|
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(ctl->fd);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(ctl);
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brAddBridge:
|
|
|
|
* @ctl: bridge control pointer
|
2008-07-11 17:33:45 +00:00
|
|
|
* @name: the bridge name
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-07-11 17:33:45 +00:00
|
|
|
* This function register a new bridge
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef SIOCBRADDBR
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brAddBridge(brControl *ctl,
|
2009-03-02 17:37:03 +00:00
|
|
|
const char *name)
|
2007-02-14 16:02:40 +00:00
|
|
|
{
|
2008-07-11 17:33:45 +00:00
|
|
|
if (!ctl || !ctl->fd || !name)
|
2007-02-14 16:02:40 +00:00
|
|
|
return EINVAL;
|
|
|
|
|
2009-03-02 17:37:03 +00:00
|
|
|
if (ioctl(ctl->fd, SIOCBRADDBR, name) == 0)
|
|
|
|
return 0;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
return errno;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2007-08-07 13:02:35 +00:00
|
|
|
int brAddBridge (brControl *ctl ATTRIBUTE_UNUSED,
|
2009-04-20 09:18:26 +00:00
|
|
|
const char *name ATTRIBUTE_UNUSED)
|
2007-08-07 13:02:35 +00:00
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef SIOCBRDELBR
|
2009-01-20 22:36:10 +00:00
|
|
|
int
|
|
|
|
brHasBridge(brControl *ctl,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if (!ctl || !name) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
if (virStrcpyStatic(ifr.ifr_name, name) == NULL) {
|
2009-01-20 22:36:10 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2009-01-20 22:36:10 +00:00
|
|
|
int
|
2009-04-20 09:18:26 +00:00
|
|
|
brHasBridge(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *name ATTRIBUTE_UNUSED)
|
2009-01-20 22:36:10 +00:00
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brDeleteBridge:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @name: the bridge name
|
|
|
|
*
|
|
|
|
* Remove a bridge from the layer.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef SIOCBRDELBR
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brDeleteBridge(brControl *ctl,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
if (!ctl || !ctl->fd || !name)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
return ioctl(ctl->fd, SIOCBRDELBR, name) == 0 ? 0 : errno;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2007-08-07 13:02:35 +00:00
|
|
|
int
|
|
|
|
brDeleteBridge(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# if defined(SIOCBRADDIF) && defined(SIOCBRDELIF)
|
2007-02-14 16:02:40 +00:00
|
|
|
static int
|
|
|
|
brAddDelInterface(brControl *ctl,
|
|
|
|
int cmd,
|
|
|
|
const char *bridge,
|
|
|
|
const char *iface)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if (!ctl || !ctl->fd || !bridge || !iface)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_name, bridge) == NULL)
|
|
|
|
return EINVAL;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
if (!(ifr.ifr_ifindex = if_nametoindex(iface)))
|
|
|
|
return ENODEV;
|
|
|
|
|
|
|
|
return ioctl(ctl->fd, cmd, &ifr) == 0 ? 0 : errno;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brAddInterface:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @bridge: the bridge name
|
|
|
|
* @iface: the network interface name
|
2008-02-05 19:27:37 +00:00
|
|
|
*
|
2007-06-29 13:23:13 +00:00
|
|
|
* Adds an interface to a bridge
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef SIOCBRADDIF
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brAddInterface(brControl *ctl,
|
|
|
|
const char *bridge,
|
|
|
|
const char *iface)
|
|
|
|
{
|
|
|
|
return brAddDelInterface(ctl, SIOCBRADDIF, bridge, iface);
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2007-08-07 13:02:35 +00:00
|
|
|
int
|
|
|
|
brAddInterface(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *bridge ATTRIBUTE_UNUSED,
|
|
|
|
const char *iface ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brDeleteInterface:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @bridge: the bridge name
|
|
|
|
* @iface: the network interface name
|
2008-02-05 19:27:37 +00:00
|
|
|
*
|
2007-06-29 13:23:13 +00:00
|
|
|
* Removes an interface from a bridge
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef SIOCBRDELIF
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brDeleteInterface(brControl *ctl,
|
|
|
|
const char *bridge,
|
|
|
|
const char *iface)
|
|
|
|
{
|
|
|
|
return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface);
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2007-08-07 13:02:35 +00:00
|
|
|
int
|
|
|
|
brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *bridge ATTRIBUTE_UNUSED,
|
|
|
|
const char *iface ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2007-03-13 22:43:22 +00:00
|
|
|
|
2010-07-21 10:08:52 +00:00
|
|
|
/**
|
|
|
|
* ifSetInterfaceMac:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @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 an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
static int ifSetInterfaceMac(brControl *ctl, const char *ifname,
|
|
|
|
const unsigned char *macaddr)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if (!ctl || !ifname)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* To fill ifr.ifr_hdaddr.sa_family field */
|
|
|
|
if (ioctl(ctl->fd, SIOCGIFHWADDR, &ifr) != 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
memcpy(ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN);
|
|
|
|
|
|
|
|
return ioctl(ctl->fd, SIOCSIFHWADDR, &ifr) == 0 ? 0 : errno;
|
|
|
|
}
|
|
|
|
|
2008-12-04 14:38:31 +00:00
|
|
|
/**
|
|
|
|
* ifGetMtu
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @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.
|
|
|
|
* On error, returns -1 and sets errno accordingly
|
|
|
|
*/
|
|
|
|
static int ifGetMtu(brControl *ctl, const char *ifname)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if (!ctl || !ifname) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL) {
|
2008-12-04 14:38:31 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCGIFMTU, &ifr))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return ifr.ifr_mtu;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ifSetMtu:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @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 an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
static int ifSetMtu(brControl *ctl, const char *ifname, int mtu)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
if (!ctl || !ifname)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
|
|
|
|
return EINVAL;
|
2008-12-04 14:38:31 +00:00
|
|
|
ifr.ifr_mtu = mtu;
|
|
|
|
|
|
|
|
return ioctl(ctl->fd, SIOCSIFMTU, &ifr) == 0 ? 0 : errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* brSetInterfaceMtu
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @bridge: name of the bridge interface
|
|
|
|
* @ifname: name of the interface whose MTU we want to set
|
|
|
|
*
|
|
|
|
* Sets the interface mtu to the same MTU of the bridge
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
static int brSetInterfaceMtu(brControl *ctl,
|
|
|
|
const char *bridge,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
int mtu = ifGetMtu(ctl, bridge);
|
|
|
|
|
|
|
|
if (mtu < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
return ifSetMtu(ctl, ifname, mtu);
|
|
|
|
}
|
|
|
|
|
2009-01-27 11:12:05 +00:00
|
|
|
/**
|
|
|
|
* brProbeVnetHdr:
|
|
|
|
* @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 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef IFF_VNET_HDR
|
2009-01-27 11:12:05 +00:00
|
|
|
static int
|
|
|
|
brProbeVnetHdr(int tapfd)
|
|
|
|
{
|
2010-03-09 18:22:22 +00:00
|
|
|
# if defined(IFF_VNET_HDR) && defined(TUNGETFEATURES) && defined(TUNGETIFF)
|
2009-01-27 11:12:05 +00:00
|
|
|
unsigned int features;
|
|
|
|
struct ifreq dummy;
|
|
|
|
|
|
|
|
if (ioctl(tapfd, TUNGETFEATURES, &features) != 0) {
|
|
|
|
VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
|
|
|
|
"TUNGETFEATURES ioctl() not implemented"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(features & IFF_VNET_HDR)) {
|
|
|
|
VIR_INFO0(_("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_INFO0(_("Not enabling IFF_VNET_HDR; "
|
|
|
|
"TUNGETIFF ioctl() not implemented"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_INFO0(_("Enabling IFF_VNET_HDR"));
|
|
|
|
|
|
|
|
return 1;
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2009-02-17 10:26:43 +00:00
|
|
|
(void) tapfd;
|
2009-01-27 11:12:05 +00:00
|
|
|
VIR_INFO0(_("Not enabling IFF_VNET_HDR; disabled at build time"));
|
|
|
|
return 0;
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2009-01-27 11:12:05 +00:00
|
|
|
}
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2009-01-27 11:12:05 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brAddTap:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @bridge: the bridge name
|
|
|
|
* @ifname: the interface name (or name template)
|
2010-07-21 10:08:52 +00:00
|
|
|
* @macaddr: desired MAC address (VIR_MAC_BUFLEN long)
|
2009-01-27 11:12:05 +00:00
|
|
|
* @vnet_hdr: whether to try enabling IFF_VNET_HDR
|
2007-06-29 13:23:13 +00:00
|
|
|
* @tapfd: file descriptor return value for the new tap device
|
|
|
|
*
|
2008-03-14 15:31:08 +00:00
|
|
|
* This function creates a new tap device on a bridge. @ifname can be either
|
2007-06-29 13:23:13 +00:00
|
|
|
* a fixed name or a name template with '%d' for dynamic name allocation.
|
2009-06-03 11:13:33 +00:00
|
|
|
* 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.
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brAddTap(brControl *ctl,
|
|
|
|
const char *bridge,
|
2008-07-11 19:34:11 +00:00
|
|
|
char **ifname,
|
2010-07-21 10:08:52 +00:00
|
|
|
const unsigned char *macaddr,
|
2009-01-27 11:12:05 +00:00
|
|
|
int vnet_hdr,
|
2007-02-14 16:02:40 +00:00
|
|
|
int *tapfd)
|
|
|
|
{
|
2009-08-03 12:37:44 +00:00
|
|
|
int fd;
|
2009-07-30 07:14:47 +00:00
|
|
|
struct ifreq ifr;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2009-06-03 11:13:33 +00:00
|
|
|
if (!ctl || !ctl->fd || !bridge || !ifname)
|
2007-02-14 16:02:40 +00:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
|
|
|
|
return errno;
|
|
|
|
|
2009-07-30 07:14:47 +00:00
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
|
|
|
2009-07-29 21:23:23 +00:00
|
|
|
ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
|
2009-01-27 11:12:05 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef IFF_VNET_HDR
|
2009-07-29 21:23:23 +00:00
|
|
|
if (vnet_hdr && brProbeVnetHdr(fd))
|
|
|
|
ifr.ifr_flags |= IFF_VNET_HDR;
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2009-07-30 15:27:25 +00:00
|
|
|
(void) vnet_hdr;
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) {
|
2009-07-29 21:23:23 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
2009-01-27 11:12:05 +00:00
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (ioctl(fd, TUNSETIFF, &ifr) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-07-21 10:08:52 +00:00
|
|
|
/* 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 ((errno = ifSetInterfaceMac(ctl, ifr.ifr_name, macaddr)))
|
|
|
|
goto error;
|
2009-07-29 21:23:23 +00:00
|
|
|
/* 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 ((errno = brSetInterfaceMtu(ctl, bridge, ifr.ifr_name)))
|
|
|
|
goto error;
|
|
|
|
if ((errno = brAddInterface(ctl, bridge, ifr.ifr_name)))
|
|
|
|
goto error;
|
|
|
|
if ((errno = brSetInterfaceUp(ctl, ifr.ifr_name, 1)))
|
|
|
|
goto error;
|
|
|
|
if (!tapfd &&
|
|
|
|
(errno = ioctl(fd, TUNSETPERSIST, 1)))
|
|
|
|
goto error;
|
|
|
|
VIR_FREE(*ifname);
|
|
|
|
if (!(*ifname = strdup(ifr.ifr_name)))
|
|
|
|
goto error;
|
|
|
|
if (tapfd)
|
|
|
|
*tapfd = fd;
|
2010-08-11 21:51:41 +00:00
|
|
|
else
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2009-07-29 21:23:23 +00:00
|
|
|
return 0;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
error:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
2009-06-03 11:13:33 +00:00
|
|
|
int brDeleteTap(brControl *ctl,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
struct ifreq try;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (!ctl || !ctl->fd || !ifname)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
memset(&try, 0, sizeof(struct ifreq));
|
|
|
|
try.ifr_flags = IFF_TAP|IFF_NO_PI;
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (virStrcpyStatic(try.ifr_name, ifname) == NULL) {
|
2009-06-03 11:13:33 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, TUNSETIFF, &try) == 0) {
|
|
|
|
if ((errno = ioctl(fd, TUNSETPERSIST, 0)))
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2009-06-03 11:13:33 +00:00
|
|
|
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brSetInterfaceUp:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @up: 1 for up, 0 for down
|
|
|
|
*
|
|
|
|
* Function to control if an interface is activated (up, 1) or not (down, 0)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brSetInterfaceUp(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
int up)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
if (!ctl || !ifname)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
|
|
|
|
return EINVAL;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
flags = up ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP);
|
|
|
|
|
|
|
|
if (ifr.ifr_flags != flags) {
|
|
|
|
ifr.ifr_flags = flags;
|
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCSIFFLAGS, &ifr) < 0)
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brGetInterfaceUp:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @up: where to store the status
|
|
|
|
*
|
|
|
|
* Function to query if an interface is activated (1) or not (0)
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brGetInterfaceUp(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
int *up)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
if (!ctl || !ifname || !up)
|
2007-02-14 16:02:40 +00:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
2009-08-03 12:37:44 +00:00
|
|
|
if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
|
|
|
|
return EINVAL;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
*up = (ifr.ifr_flags & IFF_UP) ? 1 : 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
2010-12-14 17:14:39 +00:00
|
|
|
* brAddInetAddress:
|
2007-06-29 13:23:13 +00:00
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
2010-12-14 17:14:39 +00:00
|
|
|
* @addr: the IP address (IPv4 or IPv6)
|
|
|
|
* @prefix: number of 1 bits in the netmask
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2010-12-14 17:14:39 +00:00
|
|
|
* Add an IP address to an interface. This function *does not* remove
|
|
|
|
* any previously added IP addresses - that must be done separately with
|
|
|
|
* brDelInetAddress.
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2010-12-14 17:14:39 +00:00
|
|
|
* Returns 0 in case of success or -1 in case of error.
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
2010-12-14 17:14:39 +00:00
|
|
|
brAddInetAddress(brControl *ctl ATTRIBUTE_UNUSED,
|
2007-02-14 16:02:40 +00:00
|
|
|
const char *ifname,
|
2010-12-14 17:14:39 +00:00
|
|
|
virSocketAddr *addr,
|
|
|
|
unsigned int prefix)
|
2007-02-14 16:02:40 +00:00
|
|
|
{
|
2010-12-23 22:03:56 +00:00
|
|
|
virCommandPtr cmd = NULL;
|
2010-12-14 17:14:39 +00:00
|
|
|
char *addrstr;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!(addrstr = virSocketFormatAddr(addr)))
|
|
|
|
goto cleanup;
|
|
|
|
cmd = virCommandNew(IP_PATH);
|
|
|
|
virCommandAddArgList(cmd, "addr", "add", 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;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
2010-12-14 17:14:39 +00:00
|
|
|
* brDelInetAddress:
|
2007-06-29 13:23:13 +00:00
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
2010-12-14 17:14:39 +00:00
|
|
|
* @addr: the IP address (IPv4 or IPv6)
|
|
|
|
* @prefix: number of 1 bits in the netmask
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2010-12-14 17:14:39 +00:00
|
|
|
* Delete an IP address from an interface.
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2010-12-14 17:14:39 +00:00
|
|
|
* Returns 0 in case of success or -1 in case of error.
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
2010-12-14 17:14:39 +00:00
|
|
|
brDelInetAddress(brControl *ctl ATTRIBUTE_UNUSED,
|
2007-02-14 16:02:40 +00:00
|
|
|
const char *ifname,
|
2010-12-14 17:14:39 +00:00
|
|
|
virSocketAddr *addr,
|
|
|
|
unsigned int prefix)
|
2007-02-14 16:02:40 +00:00
|
|
|
{
|
2010-12-23 22:03:56 +00:00
|
|
|
virCommandPtr cmd = NULL;
|
2010-12-14 17:14:39 +00:00
|
|
|
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;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brSetForwardDelay:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @bridge: the bridge name
|
|
|
|
* @delay: delay in seconds
|
|
|
|
*
|
|
|
|
* Set the bridge forward delay
|
|
|
|
*
|
2008-08-29 07:11:15 +00:00
|
|
|
* Returns 0 in case of success or -1 on failure
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
2008-02-05 19:27:37 +00:00
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
2007-06-26 23:01:54 +00:00
|
|
|
brSetForwardDelay(brControl *ctl ATTRIBUTE_UNUSED,
|
2007-02-14 16:02:40 +00:00
|
|
|
const char *bridge,
|
|
|
|
int delay)
|
|
|
|
{
|
2010-12-14 17:14:39 +00:00
|
|
|
virCommandPtr cmd;
|
|
|
|
int ret = -1;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-12-14 17:14:39 +00:00
|
|
|
cmd = virCommandNew(BRCTL);
|
|
|
|
virCommandAddArgList(cmd, "setfd", bridge, NULL);
|
|
|
|
virCommandAddArgFormat(cmd, "%d", delay);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-12-14 17:14:39 +00:00
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-12-14 17:14:39 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brSetEnableSTP:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @bridge: 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.
|
|
|
|
*
|
2008-08-29 07:11:15 +00:00
|
|
|
* Returns 0 in case of success or -1 on failure
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
2007-06-26 23:01:54 +00:00
|
|
|
brSetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED,
|
2007-02-14 16:02:40 +00:00
|
|
|
const char *bridge,
|
|
|
|
int enable)
|
|
|
|
{
|
2010-12-14 17:14:39 +00:00
|
|
|
virCommandPtr cmd;
|
|
|
|
int ret = -1;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-12-14 17:14:39 +00:00
|
|
|
cmd = virCommandNew(BRCTL);
|
|
|
|
virCommandAddArgList(cmd, "stp", bridge,
|
|
|
|
enable ? "on" : "off",
|
|
|
|
NULL);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2010-12-14 17:14:39 +00:00
|
|
|
if (virCommandRun(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2009-01-05 14:07:31 +00:00
|
|
|
#endif /* WITH_BRIDGE */
|