2007-02-14 16:02:40 +00:00
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2007-11-26 11:50:16 +00:00
|
|
|
#ifdef WITH_QEMU
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
#include "bridge.h"
|
|
|
|
|
|
|
|
#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>
|
2007-06-26 23:01:54 +00:00
|
|
|
#include <paths.h>
|
|
|
|
#include <sys/wait.h>
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
#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 */
|
2008-02-28 01:23:14 +00:00
|
|
|
#include <net/if_arp.h> /* ARPHRD_ETHER */
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
#include "internal.h"
|
2008-06-06 11:09:57 +00:00
|
|
|
#include "memory.h"
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
#define MAX_BRIDGE_ID 256
|
|
|
|
|
|
|
|
#define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
|
|
|
|
#define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
|
|
|
|
|
|
|
|
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;
|
|
|
|
close(fd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC(*ctlp) < 0) {
|
2007-06-29 13:23:13 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
close(ctl->fd);
|
|
|
|
ctl->fd = 0;
|
|
|
|
|
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.
|
|
|
|
*/
|
2007-08-07 13:02:35 +00:00
|
|
|
#ifdef SIOCBRADDBR
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brAddBridge(brControl *ctl,
|
2008-07-11 17:33:45 +00:00
|
|
|
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;
|
|
|
|
|
2008-07-11 17:33:45 +00:00
|
|
|
if (*name) {
|
|
|
|
if (ioctl(ctl->fd, SIOCBRADDBR, *name) == 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
return 0;
|
2008-07-11 17:33:45 +00:00
|
|
|
} else {
|
|
|
|
int id = 0;
|
|
|
|
do {
|
|
|
|
char try[50];
|
|
|
|
|
|
|
|
snprintf(try, sizeof(try), "virbr%d", id);
|
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCBRADDBR, try) == 0) {
|
|
|
|
if (!(*name = strdup(try))) {
|
|
|
|
ioctl(ctl->fd, SIOCBRDELBR, name);
|
|
|
|
return ENOMEM;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
id++;
|
|
|
|
} while (id < MAX_BRIDGE_ID);
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
return errno;
|
|
|
|
}
|
2007-08-07 13:02:35 +00:00
|
|
|
#else
|
|
|
|
int brAddBridge (brControl *ctl ATTRIBUTE_UNUSED,
|
2008-08-07 10:22:52 +00:00
|
|
|
char **name ATTRIBUTE_UNUSED)
|
2007-08-07 13:02:35 +00:00
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
2007-02-14 16:02:40 +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.
|
|
|
|
*/
|
2007-08-07 13:02:35 +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;
|
|
|
|
}
|
2007-08-07 13:02:35 +00:00
|
|
|
#else
|
|
|
|
int
|
|
|
|
brDeleteBridge(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-08-07 13:02:35 +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;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (!ctl || !ctl->fd || !bridge || !iface)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((len = strlen(bridge)) >= BR_IFNAME_MAXLEN)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
strncpy(ifr.ifr_name, bridge, len);
|
|
|
|
ifr.ifr_name[len] = '\0';
|
|
|
|
|
|
|
|
if (!(ifr.ifr_ifindex = if_nametoindex(iface)))
|
|
|
|
return ENODEV;
|
|
|
|
|
|
|
|
return ioctl(ctl->fd, cmd, &ifr) == 0 ? 0 : errno;
|
|
|
|
}
|
2007-08-07 13:02:35 +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.
|
|
|
|
*/
|
2007-08-07 13:02:35 +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);
|
|
|
|
}
|
2007-08-07 13:02:35 +00:00
|
|
|
#else
|
|
|
|
int
|
|
|
|
brAddInterface(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *bridge ATTRIBUTE_UNUSED,
|
|
|
|
const char *iface ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#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.
|
|
|
|
*/
|
2007-08-07 13:02:35 +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);
|
|
|
|
}
|
2007-08-07 13:02:35 +00:00
|
|
|
#else
|
|
|
|
int
|
|
|
|
brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED,
|
|
|
|
const char *bridge ATTRIBUTE_UNUSED,
|
|
|
|
const char *iface ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
2007-03-13 22:43:22 +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)
|
|
|
|
* @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.
|
|
|
|
* in either case the final name for the bridge will be stored in @ifname
|
|
|
|
* and the associated file descriptor in @tapfd.
|
|
|
|
*
|
|
|
|
* 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,
|
2007-02-14 16:02:40 +00:00
|
|
|
int *tapfd)
|
|
|
|
{
|
|
|
|
int id, subst, fd;
|
|
|
|
|
2007-03-13 22:43:22 +00:00
|
|
|
if (!ctl || !ctl->fd || !bridge || !ifname || !tapfd)
|
2007-02-14 16:02:40 +00:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
subst = id = 0;
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
if (strstr(*ifname, "%d"))
|
2007-02-14 16:02:40 +00:00
|
|
|
subst = 1;
|
|
|
|
|
|
|
|
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
do {
|
|
|
|
struct ifreq try;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
memset(&try, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
try.ifr_flags = IFF_TAP|IFF_NO_PI;
|
|
|
|
|
|
|
|
if (subst) {
|
2008-07-11 19:34:11 +00:00
|
|
|
len = snprintf(try.ifr_name, BR_IFNAME_MAXLEN, *ifname, id);
|
|
|
|
if (len >= BR_IFNAME_MAXLEN) {
|
2007-02-14 16:02:40 +00:00
|
|
|
errno = EADDRINUSE;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
2008-07-11 19:34:11 +00:00
|
|
|
len = strlen(*ifname);
|
|
|
|
if (len >= BR_IFNAME_MAXLEN - 1) {
|
2007-02-14 16:02:40 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-11 19:34:11 +00:00
|
|
|
strncpy(try.ifr_name, *ifname, len);
|
2007-02-14 16:02:40 +00:00
|
|
|
try.ifr_name[len] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, TUNSETIFF, &try) == 0) {
|
|
|
|
if ((errno = brAddInterface(ctl, bridge, try.ifr_name)))
|
|
|
|
goto error;
|
|
|
|
if ((errno = brSetInterfaceUp(ctl, try.ifr_name, 1)))
|
|
|
|
goto error;
|
2008-07-11 19:34:11 +00:00
|
|
|
VIR_FREE(*ifname);
|
|
|
|
if (!(*ifname = strdup(try.ifr_name))) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
*tapfd = fd;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
id++;
|
|
|
|
} while (subst && id <= MAX_BRIDGE_ID);
|
|
|
|
|
|
|
|
error:
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
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 len;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
if (!ctl || !ifname)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
strncpy(ifr.ifr_name, ifname, len);
|
|
|
|
ifr.ifr_name[len] = '\0';
|
|
|
|
|
|
|
|
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;
|
|
|
|
int len;
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
if (!ctl || !ifname || !up)
|
2007-02-14 16:02:40 +00:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
strncpy(ifr.ifr_name, ifname, len);
|
|
|
|
ifr.ifr_name[len] = '\0';
|
|
|
|
|
|
|
|
if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
*up = (ifr.ifr_flags & IFF_UP) ? 1 : 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
brSetInetAddr(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
int cmd,
|
|
|
|
const char *addr)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct in_addr inaddr;
|
|
|
|
int len, ret;
|
|
|
|
|
|
|
|
if (!ctl || !ctl->fd || !ifname || !addr)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
strncpy(ifr.ifr_name, ifname, len);
|
|
|
|
ifr.ifr_name[len] = '\0';
|
|
|
|
|
|
|
|
if ((ret = inet_pton(AF_INET, addr, &inaddr)) < 0)
|
|
|
|
return errno;
|
|
|
|
else if (ret == 0)
|
|
|
|
return EINVAL;
|
|
|
|
|
2007-02-20 09:57:47 +00:00
|
|
|
((struct sockaddr_in *)&ifr.ifr_data)->sin_family = AF_INET;
|
|
|
|
((struct sockaddr_in *)&ifr.ifr_data)->sin_addr = inaddr;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
if (ioctl(ctl->fd, cmd, &ifr) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
brGetInetAddr(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
int cmd,
|
|
|
|
char *addr,
|
|
|
|
int maxlen)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct in_addr *inaddr;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (!ctl || !ctl->fd || !ifname || !addr)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
memset(&ifr, 0, sizeof(struct ifreq));
|
|
|
|
|
|
|
|
strncpy(ifr.ifr_name, ifname, len);
|
|
|
|
ifr.ifr_name[len] = '\0';
|
|
|
|
|
|
|
|
if (ioctl(ctl->fd, cmd, &ifr) < 0)
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
if (maxlen < BR_INET_ADDR_MAXLEN || ifr.ifr_addr.sa_family != AF_INET)
|
|
|
|
return EFAULT;
|
|
|
|
|
2007-02-20 09:57:47 +00:00
|
|
|
inaddr = &((struct sockaddr_in *)&ifr.ifr_data)->sin_addr;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
|
|
|
if (!inet_ntop(AF_INET, inaddr, addr, maxlen))
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brSetInetAddress:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
2008-03-13 09:21:41 +00:00
|
|
|
* @addr: the string representation of the IP address
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
|
|
|
* Function to bind the interface to an IP address, it should handle
|
|
|
|
* IPV4 and IPv6. The string for addr would be of the form
|
|
|
|
* "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brSetInetAddress(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
const char *addr)
|
|
|
|
{
|
|
|
|
return brSetInetAddr(ctl, ifname, SIOCSIFADDR, addr);
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brGetInetAddress:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
2008-03-13 09:21:41 +00:00
|
|
|
* @addr: the array for the string representation of the IP address
|
2007-06-29 13:23:13 +00:00
|
|
|
* @maxlen: size of @addr in bytes
|
|
|
|
*
|
|
|
|
* Function to get the IP address of an interface, it should handle
|
|
|
|
* IPV4 and IPv6. The returned string for addr would be of the form
|
|
|
|
* "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brGetInetAddress(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
char *addr,
|
|
|
|
int maxlen)
|
|
|
|
{
|
|
|
|
return brGetInetAddr(ctl, ifname, SIOCGIFADDR, addr, maxlen);
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brSetInetNetmask:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @addr: the string representation of the netmask
|
|
|
|
*
|
|
|
|
* Function to set the netmask of an interface, it should handle
|
|
|
|
* IPV4 and IPv6 forms. The string for addr would be of the form
|
|
|
|
* "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brSetInetNetmask(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
const char *addr)
|
|
|
|
{
|
|
|
|
return brSetInetAddr(ctl, ifname, SIOCSIFNETMASK, addr);
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
|
|
|
* brGetInetNetmask:
|
|
|
|
* @ctl: bridge control pointer
|
|
|
|
* @ifname: the interface name
|
|
|
|
* @addr: the array for the string representation of the netmask
|
|
|
|
* @maxlen: size of @addr in bytes
|
|
|
|
*
|
|
|
|
* Function to get the netmask of an interface, it should handle
|
|
|
|
* IPV4 and IPv6. The returned string for addr would be of the form
|
|
|
|
* "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
|
|
|
|
2007-02-14 16:02:40 +00:00
|
|
|
int
|
|
|
|
brGetInetNetmask(brControl *ctl,
|
|
|
|
const char *ifname,
|
|
|
|
char *addr,
|
|
|
|
int maxlen)
|
|
|
|
{
|
|
|
|
return brGetInetAddr(ctl, ifname, SIOCGIFNETMASK, addr, maxlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2007-06-26 23:01:54 +00:00
|
|
|
brctlSpawn(char * const *argv)
|
2007-02-14 16:02:40 +00:00
|
|
|
{
|
2007-06-26 23:01:54 +00:00
|
|
|
pid_t pid, ret;
|
|
|
|
int status;
|
|
|
|
int null = -1;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0)
|
2007-02-14 16:02:40 +00:00
|
|
|
return errno;
|
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
pid = fork();
|
|
|
|
if (pid == -1) {
|
|
|
|
int saved_errno = errno;
|
|
|
|
close(null);
|
|
|
|
return saved_errno;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if (pid == 0) { /* child */
|
|
|
|
dup2(null, STDIN_FILENO);
|
|
|
|
dup2(null, STDOUT_FILENO);
|
|
|
|
dup2(null, STDERR_FILENO);
|
|
|
|
close(null);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
execvp(argv[0], argv);
|
|
|
|
|
|
|
|
_exit (1);
|
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
close(null);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
while ((ret = waitpid(pid, &status, 0) == -1) && errno == EINTR);
|
|
|
|
if (ret == -1)
|
|
|
|
return errno;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : EINVAL;
|
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
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
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)
|
|
|
|
{
|
2007-06-26 23:01:54 +00:00
|
|
|
char **argv;
|
|
|
|
int retval = ENOMEM;
|
|
|
|
int n;
|
|
|
|
char delayStr[30];
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
n = 1 + /* brctl */
|
|
|
|
1 + /* setfd */
|
|
|
|
1 + /* brige name */
|
|
|
|
1; /* value */
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
snprintf(delayStr, sizeof(delayStr), "%d", delay);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC_N(argv, n + 1) < 0)
|
2007-06-26 23:01:54 +00:00
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
n = 0;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-09-20 18:40:36 +00:00
|
|
|
if (!(argv[n++] = strdup(BRCTL)))
|
2007-06-26 23:01:54 +00:00
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if (!(argv[n++] = strdup("setfd")))
|
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if (!(argv[n++] = strdup(bridge)))
|
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if (!(argv[n++] = strdup(delayStr)))
|
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
argv[n++] = NULL;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
retval = brctlSpawn(argv);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
error:
|
|
|
|
if (argv) {
|
|
|
|
n = 0;
|
|
|
|
while (argv[n])
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(argv[n++]);
|
|
|
|
VIR_FREE(argv);
|
2007-06-26 23:01:54 +00:00
|
|
|
}
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
return retval;
|
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.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an errno code in case of failure.
|
|
|
|
*/
|
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)
|
|
|
|
{
|
2007-06-26 23:01:54 +00:00
|
|
|
char **argv;
|
|
|
|
int retval = ENOMEM;
|
|
|
|
int n;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
n = 1 + /* brctl */
|
2007-11-21 11:46:05 +00:00
|
|
|
1 + /* stp */
|
2007-06-26 23:01:54 +00:00
|
|
|
1 + /* brige name */
|
|
|
|
1; /* value */
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC_N(argv, n + 1) < 0)
|
2007-06-26 23:01:54 +00:00
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
n = 0;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-09-20 18:40:36 +00:00
|
|
|
if (!(argv[n++] = strdup(BRCTL)))
|
2007-06-26 23:01:54 +00:00
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
if (!(argv[n++] = strdup("stp")))
|
2007-06-26 23:01:54 +00:00
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if (!(argv[n++] = strdup(bridge)))
|
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
if (!(argv[n++] = strdup(enable ? "on" : "off")))
|
|
|
|
goto error;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
argv[n++] = NULL;
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
retval = brctlSpawn(argv);
|
2007-02-14 16:02:40 +00:00
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
error:
|
|
|
|
if (argv) {
|
|
|
|
n = 0;
|
|
|
|
while (argv[n])
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(argv[n++]);
|
|
|
|
VIR_FREE(argv);
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 23:01:54 +00:00
|
|
|
return retval;
|
2007-02-14 16:02:40 +00:00
|
|
|
}
|
|
|
|
|
2007-11-26 11:50:16 +00:00
|
|
|
#endif /* WITH_QEMU */
|