summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2006-12-03 13:41:20 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2006-12-03 13:41:20 +0000
commitc3539f4fca699b326a362ae19444253885976af0 (patch)
treeee022dd19a1ee5c59a446ac90a40dbb39ededb15 /sbin
parentef660dffed30ce764d25a4ab3bbe8b3f8ff79108 (diff)
Add Rapid Spanning Tree Protocol support (802.1d-2004) based on work
by Andrew Thompson (thompsa@freebsd.org). The local changes include adoption to our bridge code, reduced stack usage and many other bits. If stp is enabled, RSTP will now be used by default. Thanks for help from Andrew. This code has been in snaps for while now, commit encouraged by deraadt@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/brconfig/brconfig.8102
-rw-r--r--sbin/brconfig/brconfig.c281
2 files changed, 329 insertions, 54 deletions
diff --git a/sbin/brconfig/brconfig.8 b/sbin/brconfig/brconfig.8
index a311492f5b5..6dd25727c40 100644
--- a/sbin/brconfig/brconfig.8
+++ b/sbin/brconfig/brconfig.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: brconfig.8,v 1.59 2006/10/23 07:05:49 jmc Exp $
+.\" $OpenBSD: brconfig.8,v 1.60 2006/12/03 13:41:19 reyk Exp $
.\"
.\" Copyright (c) 1999-2001 Jason L. Wright (jason@thought.net)
.\" All rights reserved.
@@ -32,7 +32,7 @@
.Nd manipulate bridge interfaces
.Sh SYNOPSIS
.Nm
-.Op Fl a
+.Op Fl Aa
.Nm
.Ar bridge-name
.Op Ar parameters
@@ -63,14 +63,19 @@ In the first synopsis, invoking
.Nm
with no arguments, or with the
.Fl a
+or
+.Fl A
flag, will list the status of all bridges in the system.
+The
+.Fl A
+flag will also list additional status information.
In the second, its command line consists
of the name of a bridge and a set of operations to be
performed on that bridge.
The commands are executed in the order they were specified.
If no command is specified in the second synopsis, the
.Nm
-will display status information about the bridge.
+will display full status information about the bridge.
With the third synopsis, rules for filtering Ethernet MAC addresses can
be added to a bridge.
.Pp
@@ -230,32 +235,89 @@ Enable spanning tree protocol on
Disable spanning tree protocol on
.Ar interface .
This is the default for interfaces added to the bridge.
+.It Cm proto Ar value
+Force the spanning tree protocol version.
+The available values are
+.Ar rstp
+to operate in the default Rapid Spanning Tree (RSTP) mode
+or
+.Ar stp
+to force operation in Spanning Tree (STP) mode with rapid transitions disabled.
.It Cm maxage Ar time
Set the time (in seconds) that a spanning tree protocol configuration is valid.
-Defaults to 20 seconds, minimum of 1, maximum of 255.
+Defaults to 20 seconds, minimum of 6, maximum of 40.
.It Cm fwddelay Ar time
Set the time (in seconds) before an interface begins forwarding packets.
-Defaults to 15 seconds, minimum of 1, maximum of 255.
+Defaults to 15 seconds, minimum of 4, maximum of 30.
.It Cm hellotime Ar time
Set the time (in seconds) between broadcasting spanning tree protocol
configuration packets.
-Defaults to 2 seconds, minimum of 1, maximum of 255.
+Defaults to 2 seconds, minimum of 1, maximum of 2.
+.It Cm holdcnt Ar time
+Set the transmit hold count, which is the number of spanning tree protocol
+packets transmitted before being rate limited.
+Defaults to 6, minimum of 1, maximum of 10.
.It Cm priority Ar num
Set the spanning priority of this bridge to
.Ar num .
-Defaults to 32768, minimum of 0, maximum of 65535.
+Defaults to 32768, minimum of 0, maximum of 61440.
.It Cm ifpriority Ar interface Ar num
Set the spanning tree priority of
.Ar interface
to
.Ar num .
-Defaults to 128, minimum of 0, maximum of 255.
+Defaults to 128, minimum of 0, maximum of 240.
.It Cm ifcost Ar interface Ar num
Set the spanning tree path cost of
.Ar interface
to
.Ar num .
-Defaults to 55, minimum of 1, maximum of 65535.
+Defaults to 55, minimum of 1, maximum of 200000000 in RSTP mode,
+and maximum of 65535 in STP mode.
+.It Cm -ifcost Ar interface
+Automatically calculate the spanning tree priority of
+.Ar interface
+based on the current link speed, interface status, and spanning tree mode.
+This is the default for interfaces added to the bridge.
+.It Cm edge Ar interface
+Set the
+.Ar interface
+as a spanning tree edge port.
+An edge port is a single connection to the network and cannot create
+bridge loops.
+This allows a straight transition to forwarding.
+.It Cm -edge Ar interface
+Disable edge port status on
+.Ar interface .
+.It Cm autoedge Ar interface
+Automatically detect the spanning tree edge port status on
+.Ar interface .
+This is the default for interfaces added to the bridge.
+.It Cm -autoedge Ar interface
+Disable automatic spanning tree edge port detection on
+.Ar interface .
+.It Cm p2p Ar interface
+Set the
+.Ar interface
+as a point to point link.
+This is required for straight transitions to forwarding and
+should be enabled for a full duplex link or a
+.Xr trunk 4
+with at least two physical links to the same network segment.
+.It Cm -p2p Ar interface
+Disable point to point link status on
+.Ar interface .
+This should be disabled for a half duplex link and for an interface
+connected to a shared network segment,
+like a hub or a wireless network.
+.It Cm autop2p Ar interface
+Automatically detect the point to point status on
+.Ar interface
+by checking the full duplex link status.
+This is the default for interfaces added to the bridge.
+.It Cm -autop2p Ar interface
+Disable automatic point to point link detection on
+.Ar interface .
.El
.Sh EXAMPLES
Create a bridge pseudo network device:
@@ -453,8 +515,8 @@ and
.Xr bridgename.if 5
files, using the ! operator.
.Sh SPANNING TREE
-The bridge has support for 802.1D Spanning Tree Protocol (STP), which can
-be used to detect and remove loops in a network topology.
+The bridge has support for 802.1D-2004 Spanning Tree Protocol (STP),
+which can be used to detect and remove loops in a network topology.
Using the
.Cm stp
or
@@ -463,6 +525,17 @@ commands
to
.Nm ,
STP can be enabled or disabled on each port.
+.Pp
+The bridge will use the Rapid Spanning Tree Protocol (RSTP) by default
+to allow rapid transitions to the forwarding state.
+The
+.Cm proto
+command to
+.Nm
+can be used to force operation in the common Spanning Tree Protocol
+without rapid state transitions.
+Note that RSTP will be compatible with remote bridges running common STP.
+.Pp
STP will not work on
.Xr gif 4
members because they lack a hardware MAC address.
@@ -501,6 +574,13 @@ kernel interface were 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
+Support for rapid spanning tree reconfigurations (RSTP) was added by
+.An Andrew Thompson Aq thompsa@freebsd.org
+and ported to
+.Ox
+by
+.An Reyk Floeter Aq reyk@openbsd.org .
.Sh BUGS
There are some rather special network interface chipsets which will
not work in a bridge configuration.
diff --git a/sbin/brconfig/brconfig.c b/sbin/brconfig/brconfig.c
index 69f38eb3dd7..4fffc195ffb 100644
--- a/sbin/brconfig/brconfig.c
+++ b/sbin/brconfig/brconfig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: brconfig.c,v 1.37 2006/07/25 00:26:42 djm Exp $ */
+/* $OpenBSD: brconfig.c,v 1.38 2006/12/03 13:41:19 reyk Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <sys/types.h>
+#include <sys/stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/param.h>
@@ -58,6 +59,7 @@ int bridge_deladdr(int, char *, char *);
int bridge_maxaddr(int, char *, char *);
int bridge_maxage(int, char *, char *);
int bridge_priority(int, char *, char *);
+int bridge_proto(int, char *, char *);
int bridge_fwddelay(int, char *, char *);
int bridge_hellotime(int, char *, char *);
int bridge_ifprio(int, char *, char *, char *);
@@ -69,6 +71,7 @@ int bridge_add(int, char *, char *);
int bridge_delete(int, char *, char *);
int bridge_addspan(int, char *, char *);
int bridge_delspan(int, char *, char *);
+int bridge_holdcnt(int, char *, char *);
int bridge_status(int, char *);
int is_bridge(int, char *);
int bridge_show_all(int);
@@ -80,13 +83,27 @@ void bridge_badrule(int, char **, int);
void bridge_showrule(struct ifbrlreq *, char *);
int bridge_rulefile(int, char *, char *);
+int aflag = 0;
+int Aflag = 0;
+
/* if_flags bits: borrowed from ifconfig.c */
#define IFFBITS \
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
#define IFBAFBITS "\020\1STATIC"
-#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\11SPAN"
+#define IFBIFBITS \
+"\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7P2P\10AUTOP2P\11SPAN"
+
+#define PV2ID(pv, epri, eaddr) do { \
+ epri = pv >> 48; \
+ eaddr[0] = pv >> 40; \
+ eaddr[1] = pv >> 32; \
+ eaddr[2] = pv >> 24; \
+ eaddr[3] = pv >> 16; \
+ eaddr[4] = pv >> 8; \
+ eaddr[5] = pv >> 0; \
+} while (0)
char *stpstates[] = {
"disabled",
@@ -94,6 +111,19 @@ char *stpstates[] = {
"learning",
"forwarding",
"blocking",
+ "discarding"
+};
+char *stpproto[] = {
+ "stp",
+ "(none)",
+ "rstp",
+};
+char *stproles[] = {
+ "disabled",
+ "root",
+ "designated",
+ "alternate",
+ "backup"
};
void
@@ -108,15 +138,17 @@ int
main(int argc, char *argv[])
{
int error = 0, ch, sock;
- int aflag = 0;
char *brdg;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
err(1, "socket");
- while ((ch = getopt(argc, argv, "ah")) != -1) {
+ while ((ch = getopt(argc, argv, "Aah")) != -1) {
switch (ch) {
+ case 'A':
+ Aflag = 1;
+ break;
case 'a':
aflag = 1;
break;
@@ -130,7 +162,9 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (aflag || argc < 1)
+ if (argc < 1)
+ aflag = 1;
+ if (aflag || Aflag)
return bridge_show_all(sock);
brdg = argv[0];
@@ -359,6 +393,15 @@ main(int argc, char *argv[])
error = bridge_priority(sock, brdg, argv[0]);
if (error)
return (error);
+ } else if (strcmp("proto", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("proto requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_proto(sock, brdg, argv[0]);
+ if (error)
+ return (error);
} else if (strcmp("ifpriority", argv[0]) == 0) {
argc--; argv++;
if (argc < 2) {
@@ -379,6 +422,15 @@ main(int argc, char *argv[])
if (error)
return (error);
argc--; argv++;
+ } else if (strcmp("-ifcost", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc < 1) {
+ warnx("-ifcost requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifcost(sock, brdg, argv[0], NULL);
+ if (error)
+ return (error);
} else if (strcmp("rules", argv[0]) == 0) {
argc--; argv++;
if (argc == 0) {
@@ -438,6 +490,95 @@ main(int argc, char *argv[])
IFBIF_STP);
if (error)
return (error);
+ } else if (strcmp("edge", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("edge requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_BSTP_EDGE);
+ if (error)
+ return (error);
+ } else if (strcmp("-edge", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-edge requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_BSTP_EDGE);
+ if (error)
+ return (error);
+ } else if (strcmp("autoedge", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("autoedge requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_BSTP_AUTOEDGE);
+ if (error)
+ return (error);
+ } else if (strcmp("-autoedge", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-autoedge requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_BSTP_AUTOEDGE);
+ if (error)
+ return (error);
+ } else if (strcmp("p2p", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("p2p requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_BSTP_P2P);
+ if (error)
+ return (error);
+ } else if (strcmp("-p2p", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-p2p requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_BSTP_P2P);
+ if (error)
+ return (error);
+ } else if (strcmp("autop2p", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("autop2p requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifsetflag(sock, brdg, argv[0],
+ IFBIF_BSTP_AUTOP2P);
+ if (error)
+ return (error);
+ } else if (strcmp("-autop2p", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("-autop2p requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_ifclrflag(sock, brdg, argv[0],
+ IFBIF_BSTP_P2P);
+ if (error)
+ return (error);
+ } else if (strcmp("holdcnt", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("holdcnt requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_holdcnt(sock, brdg, argv[0]);
+ if (error)
+ return (error);
} else {
warnx("unrecognized option: %s", argv[0]);
return (EX_USAGE);
@@ -459,7 +600,7 @@ bridge_ifsetflag(int s, char *brdg, char *ifsname, u_int32_t flag)
return (EX_IOERR);
}
- req.ifbr_ifsflags |= flag;
+ req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK;
if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) {
warn("%s: %s", brdg, ifsname);
@@ -481,7 +622,7 @@ bridge_ifclrflag(int s, char *brdg, char *ifsname, u_int32_t flag)
return (EX_IOERR);
}
- req.ifbr_ifsflags &= ~flag;
+ req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK);
if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) {
warn("%s: %s", brdg, ifsname);
@@ -610,37 +751,42 @@ bridge_flush(int s, char *brdg)
int
bridge_cfg(int s, char *brdg, char *delim)
{
- struct ifbrparam ifbp;
+ struct ifbropreq ifbp;
u_int16_t pri;
- u_int8_t ht, fd, ma;
+ u_int8_t ht, fd, ma, hc, proto;
+ u_int8_t lladdr[ETHER_ADDR_LEN];
+ u_int16_t bprio;
- strlcpy(ifbp.ifbrp_name, brdg, sizeof(ifbp.ifbrp_name));
- if (ioctl(s, SIOCBRDGGPRI, (caddr_t)&ifbp)) {
+ strlcpy(ifbp.ifbop_name, brdg, sizeof(ifbp.ifbop_name));
+ if (ioctl(s, SIOCBRDGGPARAM, (caddr_t)&ifbp)) {
warn("%s", brdg);
return (EX_IOERR);
}
- pri = ifbp.ifbrp_prio;
+ printf("%s", delim);
+ pri = ifbp.ifbop_priority;
+ ht = ifbp.ifbop_hellotime;
+ fd = ifbp.ifbop_fwddelay;
+ ma = ifbp.ifbop_maxage;
+ hc = ifbp.ifbop_holdcount;
+ proto = ifbp.ifbop_protocol;
- if (ioctl(s, SIOCBRDGGHT, (caddr_t)&ifbp)) {
- warn("%s", brdg);
- return (EX_IOERR);
- }
- ht = ifbp.ifbrp_hellotime;
+ printf("priority %u hellotime %u fwddelay %u maxage %u "
+ "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]);
- if (ioctl(s, SIOCBRDGGFD, (caddr_t)&ifbp)) {
- warn("%s", brdg);
- return (EX_IOERR);
- }
- fd = ifbp.ifbrp_fwddelay;
+ if (aflag && !Aflag)
+ return (0);
- if (ioctl(s, SIOCBRDGGMA, (caddr_t)&ifbp)) {
- warn("%s", brdg);
- return (EX_IOERR);
- }
- ma = ifbp.ifbrp_maxage;
+ PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr);
+ printf("\tdesignated: id %s priority %u\n",
+ ether_ntoa((struct ether_addr *)lladdr), bprio);
- printf("%spriority %u hellotime %u fwddelay %u maxage %u\n",
- delim, pri, ht, fd, ma);
+ if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge)
+ return (0);
+
+ PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr);
+ printf("\troot: id %s priority %u ifcost %u port %u\n",
+ ether_ntoa((struct ether_addr *)lladdr), bprio,
+ ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
return (0);
}
@@ -674,12 +820,14 @@ bridge_list(int s, char *brdg, char *delim)
printf("\n");
if (reqp->ifbr_ifsflags & IFBIF_SPAN)
continue;
- printf("\t\t\t");
+ printf("\t\t");
printf("port %u ifpriority %u ifcost %u",
reqp->ifbr_portno, reqp->ifbr_priority,
reqp->ifbr_path_cost);
if (reqp->ifbr_ifsflags & IFBIF_STP)
- printf(" %s", stpstates[reqp->ifbr_state]);
+ printf(" %s role %s",
+ stpstates[reqp->ifbr_state],
+ stproles[reqp->ifbr_role]);
printf("\n");
bridge_rules(s, brdg, buf, delim);
}
@@ -825,6 +973,31 @@ bridge_priority(int s, char *brdg, char *arg)
}
int
+bridge_proto(int s, char *brdg, char *arg)
+{
+ struct ifbrparam bp;
+ int i, proto = -1;
+
+ for (i = 0; i <= BSTP_PROTO_MAX; i++)
+ if (strcmp(arg, stpproto[i]) == 0) {
+ proto = i;
+ break;
+ }
+ if (proto == -1) {
+ printf("invalid arg for proto: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ bp.ifbrp_prio = proto;
+ if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
bridge_fwddelay(int s, char *brdg, char *arg)
{
struct ifbrparam bp;
@@ -954,13 +1127,17 @@ bridge_ifcost(int s, char *brdg, char *ifname, char *val)
strlcpy(breq.ifbr_name, brdg, sizeof(breq.ifbr_name));
strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
- errno = 0;
- v = strtoul(val, &endptr, 0);
- if (val[0] == '\0' || endptr[0] != '\0' ||
- v < 1 || v > 0xffffffffUL ||
- (errno == ERANGE && v == ULONG_MAX)) {
- printf("invalid arg for ifcost: %s\n", val);
- return (EX_USAGE);
+ if (val == NULL)
+ v = 0;
+ else {
+ errno = 0;
+ v = strtoul(val, &endptr, 0);
+ if (val[0] == '\0' || endptr[0] != '\0' ||
+ v < 0 || v > 0xffffffffUL ||
+ (errno == ERANGE && v == ULONG_MAX)) {
+ printf("invalid arg for ifcost: %s\n", val);
+ return (EX_USAGE);
+ }
}
breq.ifbr_path_cost = v;
@@ -1033,6 +1210,26 @@ bridge_addrs(int s, char *brdg, char *delim)
return (0);
}
+int
+bridge_holdcnt(int s, char *brdg, char *value)
+{
+ struct ifbrparam bp;
+ const char *errstr;
+
+ bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr);
+ if (errstr) {
+ warn("holdcnt %s %s", value, errstr);
+ return (EX_IOERR);
+ }
+
+ strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
+ if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0) {
+ warn("%s", brdg);
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
/*
* Check to make sure 'brdg' is really a bridge interface.
*/
@@ -1076,13 +1273,11 @@ bridge_status(int s, char *brdg)
printb("flags", ifr.ifr_flags, IFFBITS);
printf("\n");
- printf("\tConfiguration:\n");
- err = bridge_cfg(s, brdg, "\t\t");
+ err = bridge_cfg(s, brdg, "\t");
if (err)
return (err);
- printf("\tInterfaces:\n");
- err = bridge_list(s, brdg, "\t\t");
+ err = bridge_list(s, brdg, "\t");
if (err)
return (err);
@@ -1364,7 +1559,7 @@ printb(char *s, unsigned short v, char *bits)
printf("%s=%o", s, v);
else
printf("%s=%x", s, v);
-
+
if (bits) {
bits++;
putchar('<');