Add if_bridge, which provides more advanced Ethernet bridging and 802.1d

spanning tree support.

Based on Jason Wright's bridge driver from OpenBSD, and modified by Jason R.
Thorpe in NetBSD.

Reviewed by:	mlaier, bms, green
Silence from:	-net
Approved by:	mlaier (mentor)
Obtained from:	NetBSD
This commit is contained in:
Andrew Thompson 2005-06-05 02:59:26 +00:00
parent 181fc3c6ea
commit 31997bf223
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=146985
5 changed files with 4641 additions and 0 deletions

533
sbin/ifconfig/ifbridge.c Normal file
View File

@ -0,0 +1,533 @@
/*-
* Copyright 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_bridgevar.h>
#include <net/route.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#include "ifconfig.h"
static int
get_val(const char *cp, u_long *valp)
{
char *endptr;
u_long val;
errno = 0;
val = strtoul(cp, &endptr, 0);
if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
return (-1);
*valp = val;
return (0);
}
static int
do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
{
struct ifdrv ifd;
memset(&ifd, 0, sizeof(ifd));
strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
ifd.ifd_cmd = op;
ifd.ifd_len = argsize;
ifd.ifd_data = arg;
return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
}
static void
do_bridgeflag(int sock, const char *ifs, int flag, int set)
{
struct ifbreq req;
strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
err(1, "unable to get bridge flags");
if (set)
req.ifbr_ifsflags |= flag;
else
req.ifbr_ifsflags &= ~flag;
if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
err(1, "unable to set bridge flags");
}
static void
bridge_interfaces(int s, const char *prefix, int flags)
{
static const char *stpstates[] = {
"disabled",
"listening",
"learning",
"forwarding",
"blocking",
};
struct ifbifconf bifc;
struct ifbreq *req;
char *inbuf = NULL, *ninbuf;
int i, len = 8192;
for (;;) {
ninbuf = realloc(inbuf, len);
if (ninbuf == NULL)
err(1, "unable to allocate interface buffer");
bifc.ifbic_len = len;
bifc.ifbic_buf = inbuf = ninbuf;
if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
err(1, "unable to get interface list");
if ((bifc.ifbic_len + sizeof(*req)) < len)
break;
len *= 2;
}
for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
req = bifc.ifbic_req + i;
printf("%s%s ", prefix, req->ifbr_ifsname);
printb("flags", req->ifbr_ifsflags, IFBIFBITS);
printf("\n");
if (!flags) continue;
printf("%s\t", prefix);
printf("port %u priority %u",
req->ifbr_portno, req->ifbr_priority);
if (req->ifbr_ifsflags & IFBIF_STP) {
printf(" path cost %u", req->ifbr_path_cost);
if (req->ifbr_state <
sizeof(stpstates) / sizeof(stpstates[0]))
printf(" %s", stpstates[req->ifbr_state]);
else
printf(" <unknown state %d>",
req->ifbr_state);
}
printf("\n");
}
free(inbuf);
}
static void
bridge_addresses(int s, const char *prefix)
{
struct ifbaconf ifbac;
struct ifbareq *ifba;
char *inbuf = NULL, *ninbuf;
int i, len = 8192;
struct ether_addr ea;
for (;;) {
ninbuf = realloc(inbuf, len);
if (ninbuf == NULL)
err(1, "unable to allocate address buffer");
ifbac.ifbac_len = len;
ifbac.ifbac_buf = inbuf = ninbuf;
if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
err(1, "unable to get address cache");
if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
break;
len *= 2;
}
for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
ifba = ifbac.ifbac_req + i;
memcpy(ea.octet, ifba->ifba_dst,
sizeof(ea.octet));
printf("%s%s %s %lu ", prefix, ether_ntoa(&ea),
ifba->ifba_ifsname, ifba->ifba_expire);
printb("flags", ifba->ifba_flags, IFBAFBITS);
printf("\n");
}
free(inbuf);
}
static void
bridge_status(int s)
{
struct ifbrparam param;
u_int16_t pri;
u_int8_t ht, fd, ma;
if (do_cmd(s, BRDGGPRI, &param, sizeof(param), 0) < 0)
return;
pri = param.ifbrp_prio;
if (do_cmd(s, BRDGGHT, &param, sizeof(param), 0) < 0)
return;
ht = param.ifbrp_hellotime;
if (do_cmd(s, BRDGGFD, &param, sizeof(param), 0) < 0)
return;
fd = param.ifbrp_fwddelay;
if (do_cmd(s, BRDGGMA, &param, sizeof(param), 0) < 0)
return;
ma = param.ifbrp_maxage;
printf("\tpriority %u hellotime %u fwddelay %u maxage %u\n",
pri, ht, fd, ma);
bridge_interfaces(s, "\tmember: ", 0);
return;
}
static void
setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
err(1, "BRDGADD %s", val);
}
static void
setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
err(1, "BRDGDEL %s", val);
}
static void
setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
{
do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
}
static void
unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
{
do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
}
static void
setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
{
do_bridgeflag(s, val, IFBIF_LEARNING, 1);
}
static void
unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
{
do_bridgeflag(s, val, IFBIF_LEARNING, 0);
}
static void
setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
{
do_bridgeflag(s, val, IFBIF_STP, 1);
}
static void
unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
{
do_bridgeflag(s, val, IFBIF_STP, 0);
}
static void
setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
req.ifbr_ifsflags = IFBF_FLUSHDYN;
if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
err(1, "BRDGFLUSH");
}
static void
setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
req.ifbr_ifsflags = IFBF_FLUSHALL;
if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
err(1, "BRDGFLUSH");
}
static void
setbridge_static(const char *val, const char *mac, int s,
const struct afswtch *afp)
{
struct ifbareq req;
struct ether_addr *ea;
memset(&req, 0, sizeof(req));
strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
ea = ether_aton(mac);
if (ea == NULL)
errx(1, "%s: invalid address: %s", val, mac);
memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
req.ifba_flags = IFBAF_STATIC;
if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
err(1, "BRDGSADDR %s", val);
}
static void
setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbareq req;
struct ether_addr *ea;
memset(&req, 0, sizeof(req));
ea = ether_aton(val);
if (ea == NULL)
errx(1, "invalid address: %s", val);
memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
err(1, "BRDGDADDR %s", val);
}
static void
setbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
{
bridge_addresses(s, "");
}
static void
setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
{
struct ifbrparam param;
u_long val;
if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
errx(1, "invalid value: %s", arg);
param.ifbrp_csize = val & 0xffffffff;
if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
err(1, "BRDGSCACHE %s", arg);
}
static void
setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
{
struct ifbrparam param;
u_long val;
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
errx(1, "invalid value: %s", arg);
param.ifbrp_hellotime = val & 0xff;
if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
err(1, "BRDGSHT %s", arg);
}
static void
setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
{
struct ifbrparam param;
u_long val;
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
errx(1, "invalid value: %s", arg);
param.ifbrp_fwddelay = val & 0xff;
if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
err(1, "BRDGSFD %s", arg);
}
static void
setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
{
struct ifbrparam param;
u_long val;
if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
errx(1, "invalid value: %s", arg);
param.ifbrp_maxage = val & 0xff;
if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
err(1, "BRDGSMA %s", arg);
}
static void
setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
{
struct ifbrparam param;
u_long val;
if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
errx(1, "invalid value: %s", arg);
param.ifbrp_prio = val & 0xffff;
if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
err(1, "BRDGSPRI %s", arg);
}
static void
setbridge_ifpriority(const char *ifn, const char *pri, int s,
const struct afswtch *afp)
{
struct ifbreq req;
u_long val;
memset(&req, 0, sizeof(req));
if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
errx(1, "invalid value: %s", pri);
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
req.ifbr_priority = val & 0xff;
if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
err(1, "BRDGSIFPRIO %s", pri);
}
static void
setbridge_ifpathcost(const char *ifn, const char *cost, int s,
const struct afswtch *afp)
{
struct ifbreq req;
u_long val;
memset(&req, 0, sizeof(req));
if (get_val(cost, &val) < 0 || (val & ~0xff) != 0)
errx(1, "invalid value: %s", cost);
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
req.ifbr_path_cost = val & 0xffff;
if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
err(1, "BRDGSIFCOST %s", cost);
}
static void
setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
{
struct ifbrparam param;
u_long val;
if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
errx(1, "invalid value: %s", arg);
param.ifbrp_ctime = val & 0xffffffff;
if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
err(1, "BRDGSTO %s", arg);
}
static struct cmd bridge_cmds[] = {
DEF_CMD_ARG("addm", setbridge_add),
DEF_CMD_ARG("deletem", setbridge_delete),
DEF_CMD_ARG("discover", setbridge_discover),
DEF_CMD_ARG("-discover", unsetbridge_discover),
DEF_CMD_ARG("learn", setbridge_learn),
DEF_CMD_ARG("-learn", unsetbridge_learn),
DEF_CMD_ARG("stp", setbridge_stp),
DEF_CMD_ARG("-stp", unsetbridge_stp),
DEF_CMD("flush", 0, setbridge_flush),
DEF_CMD("flushall", 0, setbridge_flushall),
DEF_CMD_ARG2("static", setbridge_static),
DEF_CMD_ARG("deladdr", setbridge_deladdr),
DEF_CMD("addr", 1, setbridge_addr),
DEF_CMD_ARG("maxaddr", setbridge_maxaddr),
DEF_CMD_ARG("hellotime", setbridge_hellotime),
DEF_CMD_ARG("fwddelay", setbridge_fwddelay),
DEF_CMD_ARG("maxage", setbridge_maxage),
DEF_CMD_ARG("priority", setbridge_priority),
DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
DEF_CMD_ARG("timeout", setbridge_timeout),
};
static struct afswtch af_bridge = {
.af_name = "af_bridge",
.af_af = AF_UNSPEC,
.af_other_status = bridge_status,
};
static __constructor void
bridge_ctor(void)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
for (i = 0; i < N(bridge_cmds); i++)
cmd_register(&bridge_cmds[i]);
af_register(&af_bridge);
#undef N
}

169
share/man/man4/if_bridge.4 Normal file
View File

@ -0,0 +1,169 @@
.\" $NetBSD: bridge.4,v 1.5 2004/01/31 20:14:11 jdc Exp $
.\"
.\" Copyright 2001 Wasabi Systems, Inc.
.\" All rights reserved.
.\"
.\" Written by Jason R. Thorpe for Wasabi Systems, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed for the NetBSD Project by
.\" Wasabi Systems, Inc.
.\" 4. The name of Wasabi Systems, Inc. may not be used to endorse
.\" or promote products derived from this software without specific prior
.\" written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD$
.Dd January 4, 2004
.Dt IF_BRIDGE 4
.Os
.Sh NAME
.Nm if_bridge
.Nd network bridge device
.Sh SYNOPSIS
.Cd device if_bridge
.Sh DESCRIPTION
The
.Nm
driver creates a logical link between two or more IEEE 802 networks
that use the same (or
.Dq similar enough )
framing format.
For example, it is possible to bridge Ethernet and 802.11 networks together,
but it is not possible to bridge Ethernet and Token Ring together.
.Pp
Each
.Nm
interface is created at runtime using interface cloning.
This is
most easily done with the
.Xr ifconfig 8
.Cm create
command or using the
.Va cloned_interfaces
variable in
.Xr rc.conf 5 .
.Pp
A bridge can be used to provide several services, such as a simple
802.11-to-Ethernet bridge for wireless hosts, and traffic isolation.
.Pp
A bridge works like a hub, forwarding traffic from one interface
to another.
Multicast and broadcast packets are always forwarded to all
interfaces that are part of the bridge.
For unicast traffic, the bridge learns which MAC addresses are associated
with which interfaces and will forward the traffic selectively.
.Pp
The
.Nm
driver implements the IEEE 802.1D Spanning Tree protocol (STP).
Spanning Tree is used to detect and remove loops in a network topology.
.Pp
When filtering is enabled, bridged packets will pass through the filter
inbound on the originating interface, on the bridge interface and outbound on
the appropriate interfaces. This behaviour can be controlled using
.Xr sysctl 8 :
.Bl -tag -width ".Va net.link.bridge.pfil_member"
.It Va net.link.bridge.pfil_member
Set to
.Li 1
to enable enable filtering on the incoming and outgoing member interfaces, set
to
.Li 0
to disable it.
.It Va net.link.bridge.pfil_bridge
Set to
.Li 1
to enable enable filtering on the bridge interface, set
to
.Li 0
to disable it.
.El
.Pp
ARP and REVARP packets are forwarded without being filtered and others
that are not IP nor IPv6 packets are not forwarded when filtering is
enabled.
.Pp
Note that packets to and from the bridging host will be seen by the
filter on the interface with the appropriate address configured as well
as on the interface on which the packet arrives or departs.
.Sh EXAMPLES
The following then placed in the file
.Pa /etc/rc.conf
will cause the a bridge called
.Sq bridge0
to be created, and will add the interfaces
.Sq wi0
and
.Sq fxp0
to the bridge, and then enable packet forwarding.
Such a configuration could be used to implement a simple
802.11-to-Ethernet bridge (assuming the 802.11 interface is
in ad-hoc mode).
.Bd -literal -offset indent
cloned_interfaces="bridge0"
ifconfig_bridge0="addm wi0 addm fxp0 up"
.Ed
.Pp
Consider a system with two 4-port Ethernet boards.
The following will cause a bridge consisting of all 8 ports with Spanning Tree
enabled to be created:
.Bd -literal -offset indent
iconfig bridge0 create
ifconfig bridge0 \e
addm fxp0 stp fxp0 \e
addm fxp1 stp fxp1 \e
addm fxp2 stp fxp2 \e
addm fxp3 stp fxp3 \e
addm fxp4 stp fxp4 \e
addm fxp5 stp fxp5 \e
addm fxp6 stp fxp6 \e
addm fxp7 stp fxp7 \e
up
.Ed
.Sh SEE ALSO
.Xr ifconfig 8
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 6.0 .
.Sh AUTHORS
The
.Nm bridge
driver was originally written by
.An Jason L. Wright
.Aq jason@thought.net
as part of an undergraduate independent study at the University of
North Carolina at Greensboro.
.Pp
This version of the
.Nm
driver has been heavily modified from the original version by
.An Jason R. Thorpe
.Aq thorpej@wasabisystems.com .
.Sh BUGS
The
.Nm
driver currently supports only Ethernet and Ethernet-like (e.g. 802.11)
network devices, with exactly the same interface MTU size as the bridge device.

1174
sys/net/bridgestp.c Normal file

File diff suppressed because it is too large Load Diff

2408
sys/net/if_bridge.c Normal file

File diff suppressed because it is too large Load Diff

357
sys/net/if_bridgevar.h Normal file
View File

@ -0,0 +1,357 @@
/* $NetBSD: if_bridgevar.h,v 1.4 2003/07/08 07:13:50 itojun Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Jason L. Wright
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* OpenBSD: if_bridge.h,v 1.14 2001/03/22 03:48:29 jason Exp
*
* $FreeBSD$
*/
/*
* Data structure and control definitions for bridge interfaces.
*/
#include <sys/callout.h>
#include <sys/queue.h>
/*
* Commands used in the SIOCSDRVSPEC ioctl. Note the lookup of the
* bridge interface itself is keyed off the ifdrv structure.
*/
#define BRDGADD 0 /* add bridge member (ifbreq) */
#define BRDGDEL 1 /* delete bridge member (ifbreq) */
#define BRDGGIFFLGS 2 /* get member if flags (ifbreq) */
#define BRDGSIFFLGS 3 /* set member if flags (ifbreq) */
#define BRDGSCACHE 4 /* set cache size (ifbrparam) */
#define BRDGGCACHE 5 /* get cache size (ifbrparam) */
#define BRDGGIFS 6 /* get member list (ifbifconf) */
#define BRDGRTS 7 /* get address list (ifbaconf) */
#define BRDGSADDR 8 /* set static address (ifbareq) */
#define BRDGSTO 9 /* set cache timeout (ifbrparam) */
#define BRDGGTO 10 /* get cache timeout (ifbrparam) */
#define BRDGDADDR 11 /* delete address (ifbareq) */
#define BRDGFLUSH 12 /* flush address cache (ifbreq) */
#define BRDGGPRI 13 /* get priority (ifbrparam) */
#define BRDGSPRI 14 /* set priority (ifbrparam) */
#define BRDGGHT 15 /* get hello time (ifbrparam) */
#define BRDGSHT 16 /* set hello time (ifbrparam) */
#define BRDGGFD 17 /* get forward delay (ifbrparam) */
#define BRDGSFD 18 /* set forward delay (ifbrparam) */
#define BRDGGMA 19 /* get max age (ifbrparam) */
#define BRDGSMA 20 /* set max age (ifbrparam) */
#define BRDGSIFPRIO 21 /* set if priority (ifbreq) */
#define BRDGSIFCOST 22 /* set if path cost (ifbreq) */
/*
* Generic bridge control request.
*/
struct ifbreq {
char ifbr_ifsname[IFNAMSIZ]; /* member if name */
uint32_t ifbr_ifsflags; /* member if flags */
uint8_t ifbr_state; /* member if STP state */
uint8_t ifbr_priority; /* member if STP priority */
uint8_t ifbr_path_cost; /* member if STP cost */
uint8_t ifbr_portno; /* member if port number */
};
/* BRDGGIFFLAGS, BRDGSIFFLAGS */
#define IFBIF_LEARNING 0x01 /* if can learn */
#define IFBIF_DISCOVER 0x02 /* if sends packets w/ unknown dest. */
#define IFBIF_STP 0x04 /* if participates in spanning tree */
#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3STP"
/* BRDGFLUSH */
#define IFBF_FLUSHDYN 0x00 /* flush learned addresses only */
#define IFBF_FLUSHALL 0x01 /* flush all addresses */
/* STP port states */
#define BSTP_IFSTATE_DISABLED 0
#define BSTP_IFSTATE_LISTENING 1
#define BSTP_IFSTATE_LEARNING 2
#define BSTP_IFSTATE_FORWARDING 3
#define BSTP_IFSTATE_BLOCKING 4
/*
* Interface list structure.
*/
struct ifbifconf {
uint32_t ifbic_len; /* buffer size */
union {
caddr_t ifbicu_buf;
struct ifbreq *ifbicu_req;
} ifbic_ifbicu;
#define ifbic_buf ifbic_ifbicu.ifbicu_buf
#define ifbic_req ifbic_ifbicu.ifbicu_req
};
/*
* Bridge address request.
*/
struct ifbareq {
char ifba_ifsname[IFNAMSIZ]; /* member if name */
unsigned long ifba_expire; /* address expire time */
uint8_t ifba_flags; /* address flags */
uint8_t ifba_dst[ETHER_ADDR_LEN];/* destination address */
};
#define IFBAF_TYPEMASK 0x03 /* address type mask */
#define IFBAF_DYNAMIC 0x00 /* dynamically learned address */
#define IFBAF_STATIC 0x01 /* static address */
#define IFBAFBITS "\020\1STATIC"
/*
* Address list structure.
*/
struct ifbaconf {
uint32_t ifbac_len; /* buffer size */
union {
caddr_t ifbacu_buf;
struct ifbareq *ifbacu_req;
} ifbac_ifbacu;
#define ifbac_buf ifbac_ifbacu.ifbacu_buf
#define ifbac_req ifbac_ifbacu.ifbacu_req
};
/*
* Bridge parameter structure.
*/
struct ifbrparam {
union {
uint32_t ifbrpu_int32;
uint16_t ifbrpu_int16;
uint8_t ifbrpu_int8;
} ifbrp_ifbrpu;
};
#define ifbrp_csize ifbrp_ifbrpu.ifbrpu_int32 /* cache size */
#define ifbrp_ctime ifbrp_ifbrpu.ifbrpu_int32 /* cache time (sec) */
#define ifbrp_prio ifbrp_ifbrpu.ifbrpu_int16 /* bridge priority */
#define ifbrp_hellotime ifbrp_ifbrpu.ifbrpu_int8 /* hello time (sec) */
#define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_int8 /* fwd time (sec) */
#define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_int8 /* max age (sec) */
#ifdef _KERNEL
/*
* Timekeeping structure used in spanning tree code.
*/
struct bridge_timer {
uint16_t active;
uint16_t value;
};
struct bstp_config_unit {
uint64_t cu_rootid;
uint64_t cu_bridge_id;
uint32_t cu_root_path_cost;
uint16_t cu_message_age;
uint16_t cu_max_age;
uint16_t cu_hello_time;
uint16_t cu_forward_delay;
uint16_t cu_port_id;
uint8_t cu_message_type;
uint8_t cu_topology_change_acknowledgment;
uint8_t cu_topology_change;
};
struct bstp_tcn_unit {
uint8_t tu_message_type;
};
/*
* Bridge interface list entry.
*/
struct bridge_iflist {
LIST_ENTRY(bridge_iflist) bif_next;
uint64_t bif_designated_root;
uint64_t bif_designated_bridge;
uint32_t bif_path_cost;
uint32_t bif_designated_cost;
struct bridge_timer bif_hold_timer;
struct bridge_timer bif_message_age_timer;
struct bridge_timer bif_forward_delay_timer;
struct bstp_config_unit bif_config_bpdu;
uint16_t bif_port_id;
uint16_t bif_designated_port;
uint8_t bif_state;
uint8_t bif_topology_change_acknowledge;
uint8_t bif_config_pending;
uint8_t bif_change_detection_enabled;
uint8_t bif_priority;
struct ifnet *bif_ifp; /* member if */
uint32_t bif_flags; /* member if flags */
};
/*
* Bridge route node.
*/
struct bridge_rtnode {
LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */
LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */
struct ifnet *brt_ifp; /* destination if */
unsigned long brt_expire; /* expiration time */
uint8_t brt_flags; /* address flags */
uint8_t brt_addr[ETHER_ADDR_LEN];
};
/*
* Software state for each bridge.
*/
struct bridge_softc {
struct arpcom ifb_ac; /* make this an interface */
LIST_ENTRY(bridge_softc) sc_list;
struct mtx sc_mtx;
struct cv sc_cv;
uint64_t sc_designated_root;
uint64_t sc_bridge_id;
struct bridge_iflist *sc_root_port;
uint32_t sc_root_path_cost;
uint16_t sc_max_age;
uint16_t sc_hello_time;
uint16_t sc_forward_delay;
uint16_t sc_bridge_max_age;
uint16_t sc_bridge_hello_time;
uint16_t sc_bridge_forward_delay;
uint16_t sc_topology_change_time;
uint16_t sc_hold_time;
uint16_t sc_bridge_priority;
uint8_t sc_topology_change_detected;
uint8_t sc_topology_change;
struct bridge_timer sc_hello_timer;
struct bridge_timer sc_topology_change_timer;
struct bridge_timer sc_tcn_timer;
uint32_t sc_brtmax; /* max # of addresses */
uint32_t sc_brtcnt; /* cur. # of addresses */
uint32_t sc_brttimeout; /* rt timeout in seconds */
struct callout sc_brcallout; /* bridge callout */
struct callout sc_bstpcallout; /* STP callout */
uint32_t sc_iflist_ref; /* refcount for sc_iflist */
uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */
LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */
LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
uint32_t sc_rthash_key; /* key for hash */
};
#define BRIDGE_LOCK_INIT(_sc) do { \
mtx_init(&(_sc)->sc_mtx, "if_bridge", NULL, MTX_DEF); \
cv_init(&(_sc)->sc_cv, "if_bridge_cv"); \
} while (0)
#define BRIDGE_LOCK_DESTROY(_sc) do { \
mtx_destroy(&(_sc)->sc_mtx); \
cv_destroy(&(_sc)->sc_cv); \
} while (0)
#define BRIDGE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define BRIDGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define BRIDGE_LOCKED(_sc) mtx_owned(&(_sc)->sc_mtx)
#define BRIDGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
#define BRIDGE_LOCK2REF(_sc, _err) do { \
mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
if ((_sc)->sc_iflist_xcnt > 0) \
(_err) = EBUSY; \
else \
(_sc)->sc_iflist_ref++; \
mtx_unlock(&(_sc)->sc_mtx); \
} while (0)
#define BRIDGE_UNREF(_sc) do { \
mtx_lock(&(_sc)->sc_mtx); \
(_sc)->sc_iflist_ref--; \
if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) \
cv_broadcast(&(_sc)->sc_cv); \
mtx_unlock(&(_sc)->sc_mtx); \
} while (0)
#define BRIDGE_XLOCK(_sc) do { \
mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
(_sc)->sc_iflist_xcnt++; \
while ((_sc)->sc_iflist_ref > 0) \
cv_wait(&(_sc)->sc_cv, &(_sc)->sc_mtx); \
} while (0)
#define BRIDGE_XDROP(_sc) do { \
mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \
(_sc)->sc_iflist_xcnt--; \
} while (0)
extern const uint8_t bstp_etheraddr[];
void bridge_ifdetach(struct ifnet *);
void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
struct mbuf *bridge_input(struct ifnet *, struct mbuf *);
extern void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
void bstp_initialization(struct bridge_softc *);
void bstp_linkstate(struct ifnet *, int);
void bstp_stop(struct bridge_softc *);
struct mbuf *bstp_input(struct ifnet *, struct mbuf *);
void bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *,
int);
#endif /* _KERNEL */