aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorAndrew Thompson <thompsa@FreeBSD.org>2006-07-26 10:43:02 +0000
committerAndrew Thompson <thompsa@FreeBSD.org>2006-07-26 10:43:02 +0000
commit96e47153ea6f7bdcb9d545c2c615b18af5b8c256 (patch)
treed889157d90bbdf6d617e7a68191cd316ae8726c4 /sys/net
parente61a82f3e3472e6a9339161002e3160e9d5129e9 (diff)
downloadsrc-96e47153ea6f7bdcb9d545c2c615b18af5b8c256.tar.gz
src-96e47153ea6f7bdcb9d545c2c615b18af5b8c256.zip
/tmp/cvsuusTrc
Notes
Notes: svn path=/head/; revision=160703
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bridgestp.c1192
-rw-r--r--sys/net/bridgestp.h256
-rw-r--r--sys/net/if_bridge.c150
-rw-r--r--sys/net/if_bridgevar.h78
4 files changed, 953 insertions, 723 deletions
diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c
index 251a730eac3b..d57b1737cdbb 100644
--- a/sys/net/bridgestp.c
+++ b/sys/net/bridgestp.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sockio.h>
#include <sys/kernel.h>
#include <sys/callout.h>
+#include <sys/module.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -63,172 +64,123 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
-#include <net/if_bridgevar.h>
-
-/* BPDU message types */
-#define BSTP_MSGTYPE_CFG 0x00 /* Configuration */
-#define BSTP_MSGTYPE_TCN 0x80 /* Topology chg notification */
-
-/* BPDU flags */
-#define BSTP_FLAG_TC 0x01 /* Topology change */
-#define BSTP_FLAG_TCA 0x80 /* Topology change ack */
-
-#define BSTP_MESSAGE_AGE_INCR (1 * 256) /* in 256ths of a second */
-#define BSTP_TICK_VAL (1 * 256) /* in 256ths of a second */
-#define BSTP_LINK_TIMER (BSTP_TICK_VAL * 15)
-
-/*
- * Because BPDU's do not make nicely aligned structures, two different
- * declarations are used: bstp_?bpdu (wire representation, packed) and
- * bstp_*_unit (internal, nicely aligned version).
- */
-
-/* configuration bridge protocol data unit */
-struct bstp_cbpdu {
- uint8_t cbu_dsap; /* LLC: destination sap */
- uint8_t cbu_ssap; /* LLC: source sap */
- uint8_t cbu_ctl; /* LLC: control */
- uint16_t cbu_protoid; /* protocol id */
- uint8_t cbu_protover; /* protocol version */
- uint8_t cbu_bpdutype; /* message type */
- uint8_t cbu_flags; /* flags (below) */
-
- /* root id */
- uint16_t cbu_rootpri; /* root priority */
- uint8_t cbu_rootaddr[6]; /* root address */
-
- uint32_t cbu_rootpathcost; /* root path cost */
-
- /* bridge id */
- uint16_t cbu_bridgepri; /* bridge priority */
- uint8_t cbu_bridgeaddr[6]; /* bridge address */
-
- uint16_t cbu_portid; /* port id */
- uint16_t cbu_messageage; /* current message age */
- uint16_t cbu_maxage; /* maximum age */
- uint16_t cbu_hellotime; /* hello time */
- uint16_t cbu_forwarddelay; /* forwarding delay */
-} __attribute__((__packed__));
-
-/* topology change notification bridge protocol data unit */
-struct bstp_tbpdu {
- uint8_t tbu_dsap; /* LLC: destination sap */
- uint8_t tbu_ssap; /* LLC: source sap */
- uint8_t tbu_ctl; /* LLC: control */
- uint16_t tbu_protoid; /* protocol id */
- uint8_t tbu_protover; /* protocol version */
- uint8_t tbu_bpdutype; /* message type */
-} __attribute__((__packed__));
+#include <net/bridgestp.h>
const uint8_t bstp_etheraddr[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-static void bstp_initialize_port(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_ifupdstatus(struct bridge_softc *, struct bridge_iflist *);
-static void bstp_enable_port(struct bridge_softc *, struct bridge_iflist *);
-static void bstp_disable_port(struct bridge_softc *,
- struct bridge_iflist *);
+LIST_HEAD(, bstp_state) bstp_list;
+static struct mtx bstp_list_mtx;
+
+static void bstp_initialize_port(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_ifupdstatus(struct bstp_state *, struct bstp_port *);
+static void bstp_enable_port(struct bstp_state *, struct bstp_port *);
+static void bstp_disable_port(struct bstp_state *,
+ struct bstp_port *);
#ifdef notused
-static void bstp_enable_change_detection(struct bridge_iflist *);
-static void bstp_disable_change_detection(struct bridge_iflist *);
+static void bstp_enable_change_detection(struct bstp_port *);
+static void bstp_disable_change_detection(struct bstp_port *);
#endif /* notused */
-static int bstp_root_bridge(struct bridge_softc *sc);
-static int bstp_supersedes_port_info(struct bridge_softc *,
- struct bridge_iflist *, struct bstp_config_unit *);
-static int bstp_designated_port(struct bridge_softc *,
- struct bridge_iflist *);
-static int bstp_designated_for_some_port(struct bridge_softc *);
-static void bstp_transmit_config(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_transmit_tcn(struct bridge_softc *);
-static void bstp_received_config_bpdu(struct bridge_softc *,
- struct bridge_iflist *, struct bstp_config_unit *);
-static void bstp_received_tcn_bpdu(struct bridge_softc *,
- struct bridge_iflist *, struct bstp_tcn_unit *);
-static void bstp_record_config_information(struct bridge_softc *,
- struct bridge_iflist *, struct bstp_config_unit *);
-static void bstp_record_config_timeout_values(struct bridge_softc *,
+static int bstp_root_bridge(struct bstp_state *bs);
+static int bstp_supersedes_port_info(struct bstp_state *,
+ struct bstp_port *, struct bstp_config_unit *);
+static int bstp_designated_port(struct bstp_state *,
+ struct bstp_port *);
+static int bstp_designated_for_some_port(struct bstp_state *);
+static void bstp_transmit_config(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_transmit_tcn(struct bstp_state *);
+static void bstp_received_config_bpdu(struct bstp_state *,
+ struct bstp_port *, struct bstp_config_unit *);
+static void bstp_received_tcn_bpdu(struct bstp_state *,
+ struct bstp_port *, struct bstp_tcn_unit *);
+static void bstp_record_config_information(struct bstp_state *,
+ struct bstp_port *, struct bstp_config_unit *);
+static void bstp_record_config_timeout_values(struct bstp_state *,
struct bstp_config_unit *);
-static void bstp_config_bpdu_generation(struct bridge_softc *);
-static void bstp_send_config_bpdu(struct bridge_softc *,
- struct bridge_iflist *, struct bstp_config_unit *);
-static void bstp_configuration_update(struct bridge_softc *);
-static void bstp_root_selection(struct bridge_softc *);
-static void bstp_designated_port_selection(struct bridge_softc *);
-static void bstp_become_designated_port(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_port_state_selection(struct bridge_softc *);
-static void bstp_make_forwarding(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_make_blocking(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_set_port_state(struct bridge_iflist *, uint8_t);
+static void bstp_config_bpdu_generation(struct bstp_state *);
+static void bstp_send_config_bpdu(struct bstp_state *,
+ struct bstp_port *, struct bstp_config_unit *);
+static void bstp_configuration_update(struct bstp_state *);
+static void bstp_root_selection(struct bstp_state *);
+static void bstp_designated_port_selection(struct bstp_state *);
+static void bstp_become_designated_port(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_port_state_selection(struct bstp_state *);
+static void bstp_make_forwarding(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_make_blocking(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_set_port_state(struct bstp_port *, uint8_t);
#ifdef notused
-static void bstp_set_bridge_priority(struct bridge_softc *, uint64_t);
-static void bstp_set_port_priority(struct bridge_softc *,
- struct bridge_iflist *, uint16_t);
-static void bstp_set_path_cost(struct bridge_softc *,
- struct bridge_iflist *, uint32_t);
+static void bstp_set_bridge_priority(struct bstp_state *, uint64_t);
+static void bstp_set_port_priority(struct bstp_state *,
+ struct bstp_port *, uint16_t);
+static void bstp_set_path_cost(struct bstp_state *,
+ struct bstp_port *, uint32_t);
#endif /* notused */
-static void bstp_topology_change_detection(struct bridge_softc *);
-static void bstp_topology_change_acknowledged(struct bridge_softc *);
-static void bstp_acknowledge_topology_change(struct bridge_softc *,
- struct bridge_iflist *);
+static void bstp_topology_change_detection(struct bstp_state *);
+static void bstp_topology_change_acknowledged(struct bstp_state *);
+static void bstp_acknowledge_topology_change(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_enqueue(struct ifnet *, struct mbuf *);
static void bstp_tick(void *);
-static void bstp_timer_start(struct bridge_timer *, uint16_t);
-static void bstp_timer_stop(struct bridge_timer *);
-static int bstp_timer_expired(struct bridge_timer *, uint16_t);
-
-static void bstp_hold_timer_expiry(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_message_age_timer_expiry(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_forward_delay_timer_expiry(struct bridge_softc *,
- struct bridge_iflist *);
-static void bstp_topology_change_timer_expiry(struct bridge_softc *);
-static void bstp_tcn_timer_expiry(struct bridge_softc *);
-static void bstp_hello_timer_expiry(struct bridge_softc *);
+static void bstp_timer_start(struct bstp_timer *, uint16_t);
+static void bstp_timer_stop(struct bstp_timer *);
+static int bstp_timer_expired(struct bstp_timer *, uint16_t);
+
+static void bstp_hold_timer_expiry(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_message_age_timer_expiry(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_forward_delay_timer_expiry(struct bstp_state *,
+ struct bstp_port *);
+static void bstp_topology_change_timer_expiry(struct bstp_state *);
+static void bstp_tcn_timer_expiry(struct bstp_state *);
+static void bstp_hello_timer_expiry(struct bstp_state *);
static int bstp_addr_cmp(const uint8_t *, const uint8_t *);
static void
-bstp_transmit_config(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_transmit_config(struct bstp_state *bs, struct bstp_port *bp)
{
- if (bif->bif_hold_timer.active) {
- bif->bif_config_pending = 1;
+ BSTP_LOCK_ASSERT(bs);
+
+ if (bp->bp_hold_timer.active) {
+ bp->bp_config_pending = 1;
return;
}
- bif->bif_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
- bif->bif_config_bpdu.cu_rootid = sc->sc_designated_root;
- bif->bif_config_bpdu.cu_root_path_cost = sc->sc_root_path_cost;
- bif->bif_config_bpdu.cu_bridge_id = sc->sc_bridge_id;
- bif->bif_config_bpdu.cu_port_id = bif->bif_port_id;
+ bp->bp_config_bpdu.cu_message_type = BSTP_MSGTYPE_CFG;
+ bp->bp_config_bpdu.cu_rootid = bs->bs_designated_root;
+ bp->bp_config_bpdu.cu_root_path_cost = bs->bs_root_path_cost;
+ bp->bp_config_bpdu.cu_bridge_id = bs->bs_bridge_id;
+ bp->bp_config_bpdu.cu_port_id = bp->bp_port_id;
- if (bstp_root_bridge(sc))
- bif->bif_config_bpdu.cu_message_age = 0;
+ if (bstp_root_bridge(bs))
+ bp->bp_config_bpdu.cu_message_age = 0;
else
- bif->bif_config_bpdu.cu_message_age =
- sc->sc_root_port->bif_message_age_timer.value +
+ bp->bp_config_bpdu.cu_message_age =
+ bs->bs_root_port->bp_message_age_timer.value +
BSTP_MESSAGE_AGE_INCR;
- bif->bif_config_bpdu.cu_max_age = sc->sc_max_age;
- bif->bif_config_bpdu.cu_hello_time = sc->sc_hello_time;
- bif->bif_config_bpdu.cu_forward_delay = sc->sc_forward_delay;
- bif->bif_config_bpdu.cu_topology_change_acknowledgment
- = bif->bif_topology_change_acknowledge;
- bif->bif_config_bpdu.cu_topology_change = sc->sc_topology_change;
-
- if (bif->bif_config_bpdu.cu_message_age < sc->sc_max_age) {
- bif->bif_topology_change_acknowledge = 0;
- bif->bif_config_pending = 0;
- bstp_send_config_bpdu(sc, bif, &bif->bif_config_bpdu);
- bstp_timer_start(&bif->bif_hold_timer, 0);
+ bp->bp_config_bpdu.cu_max_age = bs->bs_max_age;
+ bp->bp_config_bpdu.cu_hello_time = bs->bs_hello_time;
+ bp->bp_config_bpdu.cu_forward_delay = bs->bs_forward_delay;
+ bp->bp_config_bpdu.cu_topology_change_acknowledgment
+ = bp->bp_topology_change_acknowledge;
+ bp->bp_config_bpdu.cu_topology_change = bs->bs_topology_change;
+
+ if (bp->bp_config_bpdu.cu_message_age < bs->bs_max_age) {
+ bp->bp_topology_change_acknowledge = 0;
+ bp->bp_config_pending = 0;
+ bstp_send_config_bpdu(bs, bp, &bp->bp_config_bpdu);
+ bstp_timer_start(&bp->bp_hold_timer, 0);
}
}
static void
-bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
+bstp_send_config_bpdu(struct bstp_state *bs, struct bstp_port *bp,
struct bstp_config_unit *cu)
{
struct ifnet *ifp;
@@ -236,9 +188,9 @@ bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
struct ether_header *eh;
struct bstp_cbpdu bpdu;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
- ifp = bif->bif_ifp;
+ ifp = bp->bp_ifp;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
@@ -291,96 +243,97 @@ bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
- /* XXX: safe here?!? */
- BRIDGE_UNLOCK(sc);
- bridge_enqueue(sc, ifp, m);
- BRIDGE_LOCK(sc);
+ bstp_enqueue(ifp, m);
}
static int
-bstp_root_bridge(struct bridge_softc *sc)
+bstp_root_bridge(struct bstp_state *bs)
{
- return (sc->sc_designated_root == sc->sc_bridge_id);
+ return (bs->bs_designated_root == bs->bs_bridge_id);
}
static int
-bstp_supersedes_port_info(struct bridge_softc *sc, struct bridge_iflist *bif,
+bstp_supersedes_port_info(struct bstp_state *bs, struct bstp_port *bp,
struct bstp_config_unit *cu)
{
- if (cu->cu_rootid < bif->bif_designated_root)
+ if (cu->cu_rootid < bp->bp_designated_root)
return (1);
- if (cu->cu_rootid > bif->bif_designated_root)
+ if (cu->cu_rootid > bp->bp_designated_root)
return (0);
- if (cu->cu_root_path_cost < bif->bif_designated_cost)
+ if (cu->cu_root_path_cost < bp->bp_designated_cost)
return (1);
- if (cu->cu_root_path_cost > bif->bif_designated_cost)
+ if (cu->cu_root_path_cost > bp->bp_designated_cost)
return (0);
- if (cu->cu_bridge_id < bif->bif_designated_bridge)
+ if (cu->cu_bridge_id < bp->bp_designated_bridge)
return (1);
- if (cu->cu_bridge_id > bif->bif_designated_bridge)
+ if (cu->cu_bridge_id > bp->bp_designated_bridge)
return (0);
- if (sc->sc_bridge_id != cu->cu_bridge_id)
+ if (bs->bs_bridge_id != cu->cu_bridge_id)
return (1);
- if (cu->cu_port_id <= bif->bif_designated_port)
+ if (cu->cu_port_id <= bp->bp_designated_port)
return (1);
return (0);
}
static void
-bstp_record_config_information(struct bridge_softc *sc,
- struct bridge_iflist *bif, struct bstp_config_unit *cu)
+bstp_record_config_information(struct bstp_state *bs,
+ struct bstp_port *bp, struct bstp_config_unit *cu)
{
- bif->bif_designated_root = cu->cu_rootid;
- bif->bif_designated_cost = cu->cu_root_path_cost;
- bif->bif_designated_bridge = cu->cu_bridge_id;
- bif->bif_designated_port = cu->cu_port_id;
- bstp_timer_start(&bif->bif_message_age_timer, cu->cu_message_age);
+ BSTP_LOCK_ASSERT(bs);
+
+ bp->bp_designated_root = cu->cu_rootid;
+ bp->bp_designated_cost = cu->cu_root_path_cost;
+ bp->bp_designated_bridge = cu->cu_bridge_id;
+ bp->bp_designated_port = cu->cu_port_id;
+ bstp_timer_start(&bp->bp_message_age_timer, cu->cu_message_age);
}
static void
-bstp_record_config_timeout_values(struct bridge_softc *sc,
+bstp_record_config_timeout_values(struct bstp_state *bs,
struct bstp_config_unit *config)
{
- sc->sc_max_age = config->cu_max_age;
- sc->sc_hello_time = config->cu_hello_time;
- sc->sc_forward_delay = config->cu_forward_delay;
- sc->sc_topology_change = config->cu_topology_change;
+ BSTP_LOCK_ASSERT(bs);
+
+ bs->bs_max_age = config->cu_max_age;
+ bs->bs_hello_time = config->cu_hello_time;
+ bs->bs_forward_delay = config->cu_forward_delay;
+ bs->bs_topology_change = config->cu_topology_change;
}
static void
-bstp_config_bpdu_generation(struct bridge_softc *sc)
+bstp_config_bpdu_generation(struct bstp_state *bs)
{
- struct bridge_iflist *bif;
+ struct bstp_port *bp;
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bstp_designated_port(sc, bif) &&
- (bif->bif_state != BSTP_IFSTATE_DISABLED))
- bstp_transmit_config(sc, bif);
+ BSTP_LOCK_ASSERT(bs);
+
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bstp_designated_port(bs, bp) &&
+ (bp->bp_state != BSTP_IFSTATE_DISABLED))
+ bstp_transmit_config(bs, bp);
}
}
static int
-bstp_designated_port(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_designated_port(struct bstp_state *bs, struct bstp_port *bp)
{
- return ((bif->bif_designated_bridge == sc->sc_bridge_id)
- && (bif->bif_designated_port == bif->bif_port_id));
+ return ((bp->bp_designated_bridge == bs->bs_bridge_id)
+ && (bp->bp_designated_port == bp->bp_port_id));
}
static void
-bstp_transmit_tcn(struct bridge_softc *sc)
+bstp_transmit_tcn(struct bstp_state *bs)
{
struct bstp_tbpdu bpdu;
- struct bridge_iflist *bif = sc->sc_root_port;
- struct ifnet *ifp = bif->bif_ifp;
+ struct bstp_port *bp = bs->bs_root_port;
+ struct ifnet *ifp = bp->bp_ifp;
struct ether_header *eh;
struct mbuf *m;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
@@ -407,212 +360,214 @@ bstp_transmit_tcn(struct bridge_softc *sc)
memcpy(mtod(m, caddr_t) + sizeof(*eh), &bpdu, sizeof(bpdu));
- /* XXX: safe here?!? */
- BRIDGE_UNLOCK(sc);
- bridge_enqueue(sc, ifp, m);
- BRIDGE_LOCK(sc);
+ bstp_enqueue(ifp, m);
}
static void
-bstp_configuration_update(struct bridge_softc *sc)
+bstp_configuration_update(struct bstp_state *bs)
{
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
- bstp_root_selection(sc);
- bstp_designated_port_selection(sc);
+ bstp_root_selection(bs);
+ bstp_designated_port_selection(bs);
}
static void
-bstp_root_selection(struct bridge_softc *sc)
+bstp_root_selection(struct bstp_state *bs)
{
- struct bridge_iflist *root_port = NULL, *bif;
+ struct bstp_port *root_port = NULL, *bp;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bstp_designated_port(sc, bif))
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bstp_designated_port(bs, bp))
continue;
- if (bif->bif_state == BSTP_IFSTATE_DISABLED)
+ if (bp->bp_state == BSTP_IFSTATE_DISABLED)
continue;
- if (bif->bif_designated_root >= sc->sc_bridge_id)
+ if (bp->bp_designated_root >= bs->bs_bridge_id)
continue;
if (root_port == NULL)
goto set_port;
- if (bif->bif_designated_root < root_port->bif_designated_root)
+ if (bp->bp_designated_root < root_port->bp_designated_root)
goto set_port;
- if (bif->bif_designated_root > root_port->bif_designated_root)
+ if (bp->bp_designated_root > root_port->bp_designated_root)
continue;
- if ((bif->bif_designated_cost + bif->bif_path_cost) <
- (root_port->bif_designated_cost + root_port->bif_path_cost))
+ if ((bp->bp_designated_cost + bp->bp_path_cost) <
+ (root_port->bp_designated_cost + root_port->bp_path_cost))
goto set_port;
- if ((bif->bif_designated_cost + bif->bif_path_cost) >
- (root_port->bif_designated_cost + root_port->bif_path_cost))
+ if ((bp->bp_designated_cost + bp->bp_path_cost) >
+ (root_port->bp_designated_cost + root_port->bp_path_cost))
continue;
- if (bif->bif_designated_bridge <
- root_port->bif_designated_bridge)
+ if (bp->bp_designated_bridge <
+ root_port->bp_designated_bridge)
goto set_port;
- if (bif->bif_designated_bridge >
- root_port->bif_designated_bridge)
+ if (bp->bp_designated_bridge >
+ root_port->bp_designated_bridge)
continue;
- if (bif->bif_designated_port < root_port->bif_designated_port)
+ if (bp->bp_designated_port < root_port->bp_designated_port)
goto set_port;
- if (bif->bif_designated_port > root_port->bif_designated_port)
+ if (bp->bp_designated_port > root_port->bp_designated_port)
continue;
- if (bif->bif_port_id >= root_port->bif_port_id)
+ if (bp->bp_port_id >= root_port->bp_port_id)
continue;
set_port:
- root_port = bif;
+ root_port = bp;
}
- sc->sc_root_port = root_port;
+ bs->bs_root_port = root_port;
if (root_port == NULL) {
- sc->sc_designated_root = sc->sc_bridge_id;
- sc->sc_root_path_cost = 0;
+ bs->bs_designated_root = bs->bs_bridge_id;
+ bs->bs_root_path_cost = 0;
} else {
- sc->sc_designated_root = root_port->bif_designated_root;
- sc->sc_root_path_cost = root_port->bif_designated_cost +
- root_port->bif_path_cost;
+ bs->bs_designated_root = root_port->bp_designated_root;
+ bs->bs_root_path_cost = root_port->bp_designated_cost +
+ root_port->bp_path_cost;
}
}
static void
-bstp_designated_port_selection(struct bridge_softc *sc)
+bstp_designated_port_selection(struct bstp_state *bs)
{
- struct bridge_iflist *bif;
+ struct bstp_port *bp;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bstp_designated_port(sc, bif))
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bstp_designated_port(bs, bp))
goto designated;
- if (bif->bif_designated_root != sc->sc_designated_root)
+ if (bp->bp_designated_root != bs->bs_designated_root)
goto designated;
- if (sc->sc_root_path_cost < bif->bif_designated_cost)
+ if (bs->bs_root_path_cost < bp->bp_designated_cost)
goto designated;
- if (sc->sc_root_path_cost > bif->bif_designated_cost)
+ if (bs->bs_root_path_cost > bp->bp_designated_cost)
continue;
- if (sc->sc_bridge_id < bif->bif_designated_bridge)
+ if (bs->bs_bridge_id < bp->bp_designated_bridge)
goto designated;
- if (sc->sc_bridge_id > bif->bif_designated_bridge)
+ if (bs->bs_bridge_id > bp->bp_designated_bridge)
continue;
- if (bif->bif_port_id > bif->bif_designated_port)
+ if (bp->bp_port_id > bp->bp_designated_port)
continue;
designated:
- bstp_become_designated_port(sc, bif);
+ bstp_become_designated_port(bs, bp);
}
}
static void
-bstp_become_designated_port(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_become_designated_port(struct bstp_state *bs, struct bstp_port *bp)
{
- bif->bif_designated_root = sc->sc_designated_root;
- bif->bif_designated_cost = sc->sc_root_path_cost;
- bif->bif_designated_bridge = sc->sc_bridge_id;
- bif->bif_designated_port = bif->bif_port_id;
+ BSTP_LOCK_ASSERT(bs);
+
+ bp->bp_designated_root = bs->bs_designated_root;
+ bp->bp_designated_cost = bs->bs_root_path_cost;
+ bp->bp_designated_bridge = bs->bs_bridge_id;
+ bp->bp_designated_port = bp->bp_port_id;
}
static void
-bstp_port_state_selection(struct bridge_softc *sc)
+bstp_port_state_selection(struct bstp_state *bs)
{
- struct bridge_iflist *bif;
-
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bif == sc->sc_root_port) {
- bif->bif_config_pending = 0;
- bif->bif_topology_change_acknowledge = 0;
- bstp_make_forwarding(sc, bif);
- } else if (bstp_designated_port(sc, bif)) {
- bstp_timer_stop(&bif->bif_message_age_timer);
- bstp_make_forwarding(sc, bif);
+ struct bstp_port *bp;
+
+ BSTP_LOCK_ASSERT(bs);
+
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bp == bs->bs_root_port) {
+ bp->bp_config_pending = 0;
+ bp->bp_topology_change_acknowledge = 0;
+ bstp_make_forwarding(bs, bp);
+ } else if (bstp_designated_port(bs, bp)) {
+ bstp_timer_stop(&bp->bp_message_age_timer);
+ bstp_make_forwarding(bs, bp);
} else {
- bif->bif_config_pending = 0;
- bif->bif_topology_change_acknowledge = 0;
- bstp_make_blocking(sc, bif);
+ bp->bp_config_pending = 0;
+ bp->bp_topology_change_acknowledge = 0;
+ bstp_make_blocking(bs, bp);
}
}
}
static void
-bstp_make_forwarding(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_make_forwarding(struct bstp_state *bs, struct bstp_port *bp)
{
- if (bif->bif_state == BSTP_IFSTATE_BLOCKING) {
- bstp_set_port_state(bif, BSTP_IFSTATE_LISTENING);
- bstp_timer_start(&bif->bif_forward_delay_timer, 0);
+ BSTP_LOCK_ASSERT(bs);
+
+ if (bp->bp_state == BSTP_IFSTATE_BLOCKING) {
+ bstp_set_port_state(bp, BSTP_IFSTATE_LISTENING);
+ bstp_timer_start(&bp->bp_forward_delay_timer, 0);
}
}
static void
-bstp_make_blocking(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_make_blocking(struct bstp_state *bs, struct bstp_port *bp)
{
- BRIDGE_LOCK_ASSERT(sc);
-
- if ((bif->bif_state != BSTP_IFSTATE_DISABLED) &&
- (bif->bif_state != BSTP_IFSTATE_BLOCKING)) {
- if ((bif->bif_state == BSTP_IFSTATE_FORWARDING) ||
- (bif->bif_state == BSTP_IFSTATE_LEARNING)) {
- if (bif->bif_change_detection_enabled) {
- bstp_topology_change_detection(sc);
+ BSTP_LOCK_ASSERT(bs);
+
+ if ((bp->bp_state != BSTP_IFSTATE_DISABLED) &&
+ (bp->bp_state != BSTP_IFSTATE_BLOCKING)) {
+ if ((bp->bp_state == BSTP_IFSTATE_FORWARDING) ||
+ (bp->bp_state == BSTP_IFSTATE_LEARNING)) {
+ if (bp->bp_change_detection_enabled) {
+ bstp_topology_change_detection(bs);
}
}
- bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
- bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
- bstp_timer_stop(&bif->bif_forward_delay_timer);
+ bstp_set_port_state(bp, BSTP_IFSTATE_BLOCKING);
+ /* XXX bridge_rtdelete(bs, bp->bp_ifp, IFBF_FLUSHDYN); */
+ bstp_timer_stop(&bp->bp_forward_delay_timer);
}
}
static void
-bstp_set_port_state(struct bridge_iflist *bif, uint8_t state)
+bstp_set_port_state(struct bstp_port *bp, uint8_t state)
{
- bif->bif_state = state;
+ bp->bp_state = state;
}
static void
-bstp_topology_change_detection(struct bridge_softc *sc)
+bstp_topology_change_detection(struct bstp_state *bs)
{
- if (bstp_root_bridge(sc)) {
- sc->sc_topology_change = 1;
- bstp_timer_start(&sc->sc_topology_change_timer, 0);
- } else if (!sc->sc_topology_change_detected) {
- bstp_transmit_tcn(sc);
- bstp_timer_start(&sc->sc_tcn_timer, 0);
+ BSTP_LOCK_ASSERT(bs);
+
+ if (bstp_root_bridge(bs)) {
+ bs->bs_topology_change = 1;
+ bstp_timer_start(&bs->bs_topology_change_timer, 0);
+ } else if (!bs->bs_topology_change_detected) {
+ bstp_transmit_tcn(bs);
+ bstp_timer_start(&bs->bs_tcn_timer, 0);
}
- sc->sc_topology_change_detected = 1;
+ bs->bs_topology_change_detected = 1;
}
static void
-bstp_topology_change_acknowledged(struct bridge_softc *sc)
+bstp_topology_change_acknowledged(struct bstp_state *bs)
{
- sc->sc_topology_change_detected = 0;
- bstp_timer_stop(&sc->sc_tcn_timer);
+ BSTP_LOCK_ASSERT(bs);
+
+ bs->bs_topology_change_detected = 0;
+ bstp_timer_stop(&bs->bs_tcn_timer);
}
static void
-bstp_acknowledge_topology_change(struct bridge_softc *sc,
- struct bridge_iflist *bif)
+bstp_acknowledge_topology_change(struct bstp_state *bs,
+ struct bstp_port *bp)
{
- bif->bif_topology_change_acknowledge = 1;
- bstp_transmit_config(sc, bif);
+ BSTP_LOCK_ASSERT(bs);
+
+ bp->bp_topology_change_acknowledge = 1;
+ bstp_transmit_config(bs, bp);
}
struct mbuf *
-bstp_input(struct ifnet *ifp, struct mbuf *m)
+bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m)
{
- struct bridge_softc *sc = ifp->if_bridge;
- struct bridge_iflist *bif = NULL;
+ struct bstp_state *bs = bp->bp_bs;
struct ether_header *eh;
struct bstp_tbpdu tpdu;
struct bstp_cbpdu cpdu;
@@ -620,18 +575,14 @@ bstp_input(struct ifnet *ifp, struct mbuf *m)
struct bstp_tcn_unit tu;
uint16_t len;
- BRIDGE_LOCK_ASSERT(sc);
+ if (bp->bp_active == 0) {
+ m_freem(m);
+ return (NULL);
+ }
- eh = mtod(m, struct ether_header *);
+ BSTP_LOCK(bs);
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bif->bif_ifp == ifp)
- break;
- }
- if (bif == NULL)
- goto out;
+ eh = mtod(m, struct ether_header *);
len = ntohs(eh->ether_type);
if (len < sizeof(tpdu))
@@ -657,7 +608,7 @@ bstp_input(struct ifnet *ifp, struct mbuf *m)
switch (tpdu.tbu_bpdutype) {
case BSTP_MSGTYPE_TCN:
tu.tu_message_type = tpdu.tbu_bpdutype;
- bstp_received_tcn_bpdu(sc, bif, &tu);
+ bstp_received_tcn_bpdu(bs, bp, &tu);
break;
case BSTP_MSGTYPE_CFG:
if (m->m_len < sizeof(cpdu) &&
@@ -694,147 +645,154 @@ bstp_input(struct ifnet *ifp, struct mbuf *m)
(cpdu.cbu_flags & BSTP_FLAG_TCA) ? 1 : 0;
cu.cu_topology_change =
(cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0;
- bstp_received_config_bpdu(sc, bif, &cu);
+ bstp_received_config_bpdu(bs, bp, &cu);
break;
default:
goto out;
}
out:
+ BSTP_UNLOCK(bs);
if (m)
m_freem(m);
return (NULL);
}
static void
-bstp_received_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
+bstp_received_config_bpdu(struct bstp_state *bs, struct bstp_port *bp,
struct bstp_config_unit *cu)
{
int root;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
- root = bstp_root_bridge(sc);
+ root = bstp_root_bridge(bs);
- if (bif->bif_state != BSTP_IFSTATE_DISABLED) {
- if (bstp_supersedes_port_info(sc, bif, cu)) {
- bstp_record_config_information(sc, bif, cu);
- bstp_configuration_update(sc);
- bstp_port_state_selection(sc);
+ if (bp->bp_state != BSTP_IFSTATE_DISABLED) {
+ if (bstp_supersedes_port_info(bs, bp, cu)) {
+ bstp_record_config_information(bs, bp, cu);
+ bstp_configuration_update(bs);
+ bstp_port_state_selection(bs);
- if ((bstp_root_bridge(sc) == 0) && root) {
- bstp_timer_stop(&sc->sc_hello_timer);
+ if ((bstp_root_bridge(bs) == 0) && root) {
+ bstp_timer_stop(&bs->bs_hello_timer);
- if (sc->sc_topology_change_detected) {
+ if (bs->bs_topology_change_detected) {
bstp_timer_stop(
- &sc->sc_topology_change_timer);
- bstp_transmit_tcn(sc);
- bstp_timer_start(&sc->sc_tcn_timer, 0);
+ &bs->bs_topology_change_timer);
+ bstp_transmit_tcn(bs);
+ bstp_timer_start(&bs->bs_tcn_timer, 0);
}
}
- if (bif == sc->sc_root_port) {
- bstp_record_config_timeout_values(sc, cu);
- bstp_config_bpdu_generation(sc);
+ if (bp == bs->bs_root_port) {
+ bstp_record_config_timeout_values(bs, cu);
+ bstp_config_bpdu_generation(bs);
if (cu->cu_topology_change_acknowledgment)
- bstp_topology_change_acknowledged(sc);
+ bstp_topology_change_acknowledged(bs);
}
- } else if (bstp_designated_port(sc, bif))
- bstp_transmit_config(sc, bif);
+ } else if (bstp_designated_port(bs, bp))
+ bstp_transmit_config(bs, bp);
}
}
static void
-bstp_received_tcn_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif,
+bstp_received_tcn_bpdu(struct bstp_state *bs, struct bstp_port *bp,
struct bstp_tcn_unit *tcn)
{
- if (bif->bif_state != BSTP_IFSTATE_DISABLED &&
- bstp_designated_port(sc, bif)) {
- bstp_topology_change_detection(sc);
- bstp_acknowledge_topology_change(sc, bif);
+ if (bp->bp_state != BSTP_IFSTATE_DISABLED &&
+ bstp_designated_port(bs, bp)) {
+ bstp_topology_change_detection(bs);
+ bstp_acknowledge_topology_change(bs, bp);
}
}
static void
-bstp_hello_timer_expiry(struct bridge_softc *sc)
+bstp_hello_timer_expiry(struct bstp_state *bs)
{
- bstp_config_bpdu_generation(sc);
- bstp_timer_start(&sc->sc_hello_timer, 0);
+ bstp_config_bpdu_generation(bs);
+ bstp_timer_start(&bs->bs_hello_timer, 0);
}
static void
-bstp_message_age_timer_expiry(struct bridge_softc *sc,
- struct bridge_iflist *bif)
+bstp_message_age_timer_expiry(struct bstp_state *bs,
+ struct bstp_port *bp)
{
int root;
- root = bstp_root_bridge(sc);
- bstp_become_designated_port(sc, bif);
- bstp_configuration_update(sc);
- bstp_port_state_selection(sc);
+ BSTP_LOCK_ASSERT(bs);
- if ((bstp_root_bridge(sc)) && (root == 0)) {
- sc->sc_max_age = sc->sc_bridge_max_age;
- sc->sc_hello_time = sc->sc_bridge_hello_time;
- sc->sc_forward_delay = sc->sc_bridge_forward_delay;
+ root = bstp_root_bridge(bs);
+ bstp_become_designated_port(bs, bp);
+ bstp_configuration_update(bs);
+ bstp_port_state_selection(bs);
- bstp_topology_change_detection(sc);
- bstp_timer_stop(&sc->sc_tcn_timer);
- bstp_config_bpdu_generation(sc);
- bstp_timer_start(&sc->sc_hello_timer, 0);
+ if ((bstp_root_bridge(bs)) && (root == 0)) {
+ bs->bs_max_age = bs->bs_bridge_max_age;
+ bs->bs_hello_time = bs->bs_bridge_hello_time;
+ bs->bs_forward_delay = bs->bs_bridge_forward_delay;
+
+ bstp_topology_change_detection(bs);
+ bstp_timer_stop(&bs->bs_tcn_timer);
+ bstp_config_bpdu_generation(bs);
+ bstp_timer_start(&bs->bs_hello_timer, 0);
}
}
static void
-bstp_forward_delay_timer_expiry(struct bridge_softc *sc,
- struct bridge_iflist *bif)
+bstp_forward_delay_timer_expiry(struct bstp_state *bs,
+ struct bstp_port *bp)
{
- if (bif->bif_state == BSTP_IFSTATE_LISTENING) {
- bstp_set_port_state(bif, BSTP_IFSTATE_LEARNING);
- bstp_timer_start(&bif->bif_forward_delay_timer, 0);
- } else if (bif->bif_state == BSTP_IFSTATE_LEARNING) {
- bstp_set_port_state(bif, BSTP_IFSTATE_FORWARDING);
- if (bstp_designated_for_some_port(sc) &&
- bif->bif_change_detection_enabled)
- bstp_topology_change_detection(sc);
+ if (bp->bp_state == BSTP_IFSTATE_LISTENING) {
+ bstp_set_port_state(bp, BSTP_IFSTATE_LEARNING);
+ bstp_timer_start(&bp->bp_forward_delay_timer, 0);
+ } else if (bp->bp_state == BSTP_IFSTATE_LEARNING) {
+ bstp_set_port_state(bp, BSTP_IFSTATE_FORWARDING);
+ if (bstp_designated_for_some_port(bs) &&
+ bp->bp_change_detection_enabled)
+ bstp_topology_change_detection(bs);
}
}
static int
-bstp_designated_for_some_port(struct bridge_softc *sc)
+bstp_designated_for_some_port(struct bstp_state *bs)
{
- struct bridge_iflist *bif;
+ struct bstp_port *bp;
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bif->bif_designated_bridge == sc->sc_bridge_id)
+ BSTP_LOCK_ASSERT(bs);
+
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bp->bp_designated_bridge == bs->bs_bridge_id)
return (1);
}
return (0);
}
static void
-bstp_tcn_timer_expiry(struct bridge_softc *sc)
+bstp_tcn_timer_expiry(struct bstp_state *bs)
{
- bstp_transmit_tcn(sc);
- bstp_timer_start(&sc->sc_tcn_timer, 0);
+ BSTP_LOCK_ASSERT(bs);
+
+ bstp_transmit_tcn(bs);
+ bstp_timer_start(&bs->bs_tcn_timer, 0);
}
static void
-bstp_topology_change_timer_expiry(struct bridge_softc *sc)
+bstp_topology_change_timer_expiry(struct bstp_state *bs)
{
- sc->sc_topology_change_detected = 0;
- sc->sc_topology_change = 0;
+ BSTP_LOCK_ASSERT(bs);
+
+ bs->bs_topology_change_detected = 0;
+ bs->bs_topology_change = 0;
}
static void
-bstp_hold_timer_expiry(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_hold_timer_expiry(struct bstp_state *bs, struct bstp_port *bp)
{
- if (bif->bif_config_pending)
- bstp_transmit_config(sc, bif);
+ if (bp->bp_config_pending)
+ bstp_transmit_config(bs, bp);
}
static int
@@ -850,40 +808,37 @@ bstp_addr_cmp(const uint8_t *a, const uint8_t *b)
}
void
-bstp_initialization(struct bridge_softc *sc)
+bstp_reinit(struct bstp_state *bs)
{
- struct bridge_iflist *bif, *mif;
+ struct bstp_port *bp, *mbp;
u_char *e_addr;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK(bs);
- mif = NULL;
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bif->bif_ifp->if_type != IFT_ETHER)
- continue;
- bif->bif_port_id = (bif->bif_priority << 8) |
- (bif->bif_ifp->if_index & 0xff);
+ mbp = NULL;
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ bp->bp_port_id = (bp->bp_priority << 8) |
+ (bp->bp_ifp->if_index & 0xff);
- if (mif == NULL) {
- mif = bif;
+ if (mbp == NULL) {
+ mbp = bp;
continue;
}
- if (bstp_addr_cmp(IF_LLADDR(bif->bif_ifp),
- IF_LLADDR(mif->bif_ifp)) < 0) {
- mif = bif;
+ if (bstp_addr_cmp(IF_LLADDR(bp->bp_ifp),
+ IF_LLADDR(mbp->bp_ifp)) < 0) {
+ mbp = bp;
continue;
}
}
- if (mif == NULL) {
- bstp_stop(sc);
+ if (mbp == NULL) {
+ BSTP_UNLOCK(bs);
+ bstp_stop(bs);
return;
}
- e_addr = IF_LLADDR(mif->bif_ifp);
- sc->sc_bridge_id =
- (((uint64_t)sc->sc_bridge_priority) << 48) |
+ e_addr = IF_LLADDR(mbp->bp_ifp);
+ bs->bs_bridge_id =
+ (((uint64_t)bs->bs_bridge_priority) << 48) |
(((uint64_t)e_addr[0]) << 40) |
(((uint64_t)e_addr[1]) << 32) |
(((uint64_t)e_addr[2]) << 24) |
@@ -891,298 +846,370 @@ bstp_initialization(struct bridge_softc *sc)
(((uint64_t)e_addr[4]) << 8) |
(((uint64_t)e_addr[5]));
- sc->sc_designated_root = sc->sc_bridge_id;
- sc->sc_root_path_cost = 0;
- sc->sc_root_port = NULL;
-
- sc->sc_max_age = sc->sc_bridge_max_age;
- sc->sc_hello_time = sc->sc_bridge_hello_time;
- sc->sc_forward_delay = sc->sc_bridge_forward_delay;
- sc->sc_topology_change_detected = 0;
- sc->sc_topology_change = 0;
- bstp_timer_stop(&sc->sc_tcn_timer);
- bstp_timer_stop(&sc->sc_topology_change_timer);
-
- if (callout_pending(&sc->sc_bstpcallout) == 0)
- callout_reset(&sc->sc_bstpcallout, hz,
- bstp_tick, sc);
-
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if (bif->bif_flags & IFBIF_STP)
- bstp_ifupdstatus(sc, bif);
- else
- bstp_disable_port(sc, bif);
+ bs->bs_designated_root = bs->bs_bridge_id;
+ bs->bs_root_path_cost = 0;
+ bs->bs_root_port = NULL;
+
+ bs->bs_max_age = bs->bs_bridge_max_age;
+ bs->bs_hello_time = bs->bs_bridge_hello_time;
+ bs->bs_forward_delay = bs->bs_bridge_forward_delay;
+ bs->bs_topology_change_detected = 0;
+ bs->bs_topology_change = 0;
+ bstp_timer_stop(&bs->bs_tcn_timer);
+ bstp_timer_stop(&bs->bs_topology_change_timer);
+
+ if (callout_pending(&bs->bs_bstpcallout) == 0)
+ callout_reset(&bs->bs_bstpcallout, hz,
+ bstp_tick, bs);
+
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next)
+ bstp_ifupdstatus(bs, bp);
+
+ bstp_port_state_selection(bs);
+ bstp_config_bpdu_generation(bs);
+ bstp_timer_start(&bs->bs_hello_timer, 0);
+ bstp_timer_start(&bs->bs_link_timer, 0);
+ BSTP_UNLOCK(bs);
+}
+
+static int
+bstp_modevent(module_t mod, int type, void *data)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF);
+ LIST_INIT(&bstp_list);
+ bstp_linkstate_p = bstp_linkstate;
+ break;
+ case MOD_UNLOAD:
+ mtx_destroy(&bstp_list_mtx);
+ break;
+ default:
+ return (EOPNOTSUPP);
}
+ return (0);
+}
+
+static moduledata_t bstp_mod = {
+ "bridgestp",
+ bstp_modevent,
+ 0
+};
+
+DECLARE_MODULE(bridgestp, bstp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
- bstp_port_state_selection(sc);
- bstp_config_bpdu_generation(sc);
- bstp_timer_start(&sc->sc_hello_timer, 0);
- bstp_timer_start(&sc->sc_link_timer, 0);
+void
+bstp_attach(struct bstp_state *bs)
+{
+ BSTP_LOCK_INIT(bs);
+ callout_init_mtx(&bs->bs_bstpcallout, &bs->bs_mtx, 0);
+ LIST_INIT(&bs->bs_bplist);
+
+ bs->bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
+ bs->bs_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
+ bs->bs_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY;
+ bs->bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
+ bs->bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
+
+ mtx_lock(&bstp_list_mtx);
+ LIST_INSERT_HEAD(&bstp_list, bs, bs_list);
+ mtx_unlock(&bstp_list_mtx);
}
void
-bstp_stop(struct bridge_softc *sc)
+bstp_detach(struct bstp_state *bs)
{
- struct bridge_iflist *bif;
+ KASSERT(LIST_EMPTY(&bs->bs_bplist), ("bstp still active"));
+
+ mtx_lock(&bstp_list_mtx);
+ LIST_REMOVE(bs, bs_list);
+ mtx_unlock(&bstp_list_mtx);
+ BSTP_LOCK_DESTROY(bs);
+}
- BRIDGE_LOCK_ASSERT(sc);
+void
+bstp_init(struct bstp_state *bs)
+{
+ callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
+ bstp_reinit(bs);
+}
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
- bstp_timer_stop(&bif->bif_hold_timer);
- bstp_timer_stop(&bif->bif_message_age_timer);
- bstp_timer_stop(&bif->bif_forward_delay_timer);
+void
+bstp_stop(struct bstp_state *bs)
+{
+ struct bstp_port *bp;
+
+ BSTP_LOCK(bs);
+
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ bstp_set_port_state(bp, BSTP_IFSTATE_DISABLED);
+ bstp_timer_stop(&bp->bp_hold_timer);
+ bstp_timer_stop(&bp->bp_message_age_timer);
+ bstp_timer_stop(&bp->bp_forward_delay_timer);
}
- callout_stop(&sc->sc_bstpcallout);
+ callout_drain(&bs->bs_bstpcallout);
+ callout_stop(&bs->bs_bstpcallout);
- bstp_timer_stop(&sc->sc_topology_change_timer);
- bstp_timer_stop(&sc->sc_tcn_timer);
- bstp_timer_stop(&sc->sc_hello_timer);
+ bstp_timer_stop(&bs->bs_topology_change_timer);
+ bstp_timer_stop(&bs->bs_tcn_timer);
+ bstp_timer_stop(&bs->bs_hello_timer);
+ BSTP_UNLOCK(bs);
}
static void
-bstp_initialize_port(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_initialize_port(struct bstp_state *bs, struct bstp_port *bp)
{
- bstp_become_designated_port(sc, bif);
- bstp_set_port_state(bif, BSTP_IFSTATE_BLOCKING);
- bif->bif_topology_change_acknowledge = 0;
- bif->bif_config_pending = 0;
- bif->bif_change_detection_enabled = 1;
- bstp_timer_stop(&bif->bif_message_age_timer);
- bstp_timer_stop(&bif->bif_forward_delay_timer);
- bstp_timer_stop(&bif->bif_hold_timer);
+ BSTP_LOCK_ASSERT(bs);
+
+ bstp_become_designated_port(bs, bp);
+ bstp_set_port_state(bp, BSTP_IFSTATE_BLOCKING);
+ bp->bp_topology_change_acknowledge = 0;
+ bp->bp_config_pending = 0;
+ bp->bp_change_detection_enabled = 1;
+ bstp_timer_stop(&bp->bp_message_age_timer);
+ bstp_timer_stop(&bp->bp_forward_delay_timer);
+ bstp_timer_stop(&bp->bp_hold_timer);
}
static void
-bstp_enable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp)
{
- bstp_initialize_port(sc, bif);
- bstp_port_state_selection(sc);
+ bstp_initialize_port(bs, bp);
+ bstp_port_state_selection(bs);
}
static void
-bstp_disable_port(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
{
int root;
- BRIDGE_LOCK_ASSERT(sc);
-
- root = bstp_root_bridge(sc);
- bstp_become_designated_port(sc, bif);
- bstp_set_port_state(bif, BSTP_IFSTATE_DISABLED);
- bif->bif_topology_change_acknowledge = 0;
- bif->bif_config_pending = 0;
- bstp_timer_stop(&bif->bif_message_age_timer);
- bstp_timer_stop(&bif->bif_forward_delay_timer);
- bstp_configuration_update(sc);
- bstp_port_state_selection(sc);
- bridge_rtdelete(sc, bif->bif_ifp, IFBF_FLUSHDYN);
-
- if (bstp_root_bridge(sc) && (root == 0)) {
- sc->sc_max_age = sc->sc_bridge_max_age;
- sc->sc_hello_time = sc->sc_bridge_hello_time;
- sc->sc_forward_delay = sc->sc_bridge_forward_delay;
-
- bstp_topology_change_detection(sc);
- bstp_timer_stop(&sc->sc_tcn_timer);
- bstp_config_bpdu_generation(sc);
- bstp_timer_start(&sc->sc_hello_timer, 0);
+ BSTP_LOCK_ASSERT(bs);
+
+ root = bstp_root_bridge(bs);
+ bstp_become_designated_port(bs, bp);
+ bstp_set_port_state(bp, BSTP_IFSTATE_DISABLED);
+ bp->bp_topology_change_acknowledge = 0;
+ bp->bp_config_pending = 0;
+ bstp_timer_stop(&bp->bp_message_age_timer);
+ bstp_timer_stop(&bp->bp_forward_delay_timer);
+ bstp_configuration_update(bs);
+ bstp_port_state_selection(bs);
+ /* XXX bridge_rtdelete(bs, bp->bp_ifp, IFBF_FLUSHDYN); */
+
+ if (bstp_root_bridge(bs) && (root == 0)) {
+ bs->bs_max_age = bs->bs_bridge_max_age;
+ bs->bs_hello_time = bs->bs_bridge_hello_time;
+ bs->bs_forward_delay = bs->bs_bridge_forward_delay;
+
+ bstp_topology_change_detection(bs);
+ bstp_timer_stop(&bs->bs_tcn_timer);
+ bstp_config_bpdu_generation(bs);
+ bstp_timer_start(&bs->bs_hello_timer, 0);
}
}
#ifdef notused
static void
-bstp_set_bridge_priority(struct bridge_softc *sc, uint64_t new_bridge_id)
+bstp_set_bridge_priority(struct bstp_state *bs, uint64_t new_bridge_id)
{
- struct bridge_iflist *bif;
+ struct bstp_port *bp;
int root;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
- root = bstp_root_bridge(sc);
+ root = bstp_root_bridge(bs);
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bstp_designated_port(sc, bif))
- bif->bif_designated_bridge = new_bridge_id;
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bstp_designated_port(bs, bp))
+ bp->bp_designated_bridge = new_bridge_id;
}
- sc->sc_bridge_id = new_bridge_id;
+ bs->bs_bridge_id = new_bridge_id;
- bstp_configuration_update(sc);
- bstp_port_state_selection(sc);
+ bstp_configuration_update(bs);
+ bstp_port_state_selection(bs);
- if (bstp_root_bridge(sc) && (root == 0)) {
- sc->sc_max_age = sc->sc_bridge_max_age;
- sc->sc_hello_time = sc->sc_bridge_hello_time;
- sc->sc_forward_delay = sc->sc_bridge_forward_delay;
+ if (bstp_root_bridge(bs) && (root == 0)) {
+ bs->bs_max_age = bs->bs_bridge_max_age;
+ bs->bs_hello_time = bs->bs_bridge_hello_time;
+ bs->bs_forward_delay = bs->bs_bridge_forward_delay;
- bstp_topology_change_detection(sc);
- bstp_timer_stop(&sc->sc_tcn_timer);
- bstp_config_bpdu_generation(sc);
- bstp_timer_start(&sc->sc_hello_timer, 0);
+ bstp_topology_change_detection(bs);
+ bstp_timer_stop(&bs->bs_tcn_timer);
+ bstp_config_bpdu_generation(bs);
+ bstp_timer_start(&bs->bs_hello_timer, 0);
}
}
static void
-bstp_set_port_priority(struct bridge_softc *sc, struct bridge_iflist *bif,
+bstp_set_port_priority(struct bstp_state *bs, struct bstp_port *bp,
uint16_t new_port_id)
{
- if (bstp_designated_port(sc, bif))
- bif->bif_designated_port = new_port_id;
+ if (bstp_designated_port(bs, bp))
+ bp->bp_designated_port = new_port_id;
- bif->bif_port_id = new_port_id;
+ bp->bp_port_id = new_port_id;
- if ((sc->sc_bridge_id == bif->bif_designated_bridge) &&
- (bif->bif_port_id < bif->bif_designated_port)) {
- bstp_become_designated_port(sc, bif);
- bstp_port_state_selection(sc);
+ if ((bs->bs_bridge_id == bp->bp_designated_bridge) &&
+ (bp->bp_port_id < bp->bp_designated_port)) {
+ bstp_become_designated_port(bs, bp);
+ bstp_port_state_selection(bs);
}
}
static void
-bstp_set_path_cost(struct bridge_softc *sc, struct bridge_iflist *bif,
+bstp_set_path_cost(struct bstp_state *bs, struct bstp_port *bp,
uint32_t path_cost)
{
- bif->bif_path_cost = path_cost;
- bstp_configuration_update(sc);
- bstp_port_state_selection(sc);
+ bp->bp_path_cost = path_cost;
+ bstp_configuration_update(bs);
+ bstp_port_state_selection(bs);
}
static void
-bstp_enable_change_detection(struct bridge_iflist *bif)
+bstp_enable_change_detection(struct bstp_port *bp)
{
- bif->bif_change_detection_enabled = 1;
+ bp->bp_change_detection_enabled = 1;
}
static void
-bstp_disable_change_detection(struct bridge_iflist *bif)
+bstp_disable_change_detection(struct bstp_port *bp)
{
- bif->bif_change_detection_enabled = 0;
+ bp->bp_change_detection_enabled = 0;
}
#endif /* notused */
-void
-bstp_linkstate(struct ifnet *ifp, int state)
+static void
+bstp_enqueue(struct ifnet *dst_ifp, struct mbuf *m)
{
- struct bridge_softc *sc;
- struct bridge_iflist *bif;
+ int err = 0;
- sc = ifp->if_bridge;
- BRIDGE_LOCK(sc);
+ IFQ_ENQUEUE(&dst_ifp->if_snd, m, err);
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
+ if ((dst_ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0)
+ (*dst_ifp->if_start)(dst_ifp);
+}
- if (bif->bif_ifp == ifp) {
- bstp_ifupdstatus(sc, bif);
- break;
+void
+bstp_linkstate(struct ifnet *ifp, int state)
+{
+ struct bstp_state *bs;
+ struct bstp_port *bp;
+
+ /*
+ * It would be nice if the ifnet had a pointer to the bstp_port so we
+ * didnt need to search for it, but that may be an overkill. In reality
+ * this is fast and doesnt get called often.
+ */
+ mtx_lock(&bstp_list_mtx);
+ LIST_FOREACH(bs, &bstp_list, bs_list) {
+ BSTP_LOCK(bs);
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bp->bp_ifp == ifp) {
+ bstp_ifupdstatus(bs, bp);
+ /* it only exists once so return */
+ BSTP_UNLOCK(bs);
+ mtx_unlock(&bstp_list_mtx);
+ return;
+ }
}
+ BSTP_UNLOCK(bs);
}
-
- BRIDGE_UNLOCK(sc);
+ mtx_unlock(&bstp_list_mtx);
}
static void
-bstp_ifupdstatus(struct bridge_softc *sc, struct bridge_iflist *bif)
+bstp_ifupdstatus(struct bstp_state *bs, struct bstp_port *bp)
{
- struct ifnet *ifp = bif->bif_ifp;
+ struct ifnet *ifp = bp->bp_ifp;
struct ifmediareq ifmr;
int error = 0;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
bzero((char *)&ifmr, sizeof(ifmr));
error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
if ((error == 0) && (ifp->if_flags & IFF_UP)) {
- if (ifmr.ifm_status & IFM_ACTIVE) {
- if (bif->bif_state == BSTP_IFSTATE_DISABLED)
- bstp_enable_port(sc, bif);
+ if (ifmr.ifm_status & IFM_ACTIVE) {
+ if (bp->bp_state == BSTP_IFSTATE_DISABLED)
+ bstp_enable_port(bs, bp);
} else {
- if (bif->bif_state != BSTP_IFSTATE_DISABLED)
- bstp_disable_port(sc, bif);
+ if (bp->bp_state != BSTP_IFSTATE_DISABLED)
+ bstp_disable_port(bs, bp);
}
return;
}
- if (bif->bif_state != BSTP_IFSTATE_DISABLED)
- bstp_disable_port(sc, bif);
+ if (bp->bp_state != BSTP_IFSTATE_DISABLED)
+ bstp_disable_port(bs, bp);
}
static void
bstp_tick(void *arg)
{
- struct bridge_softc *sc = arg;
- struct bridge_iflist *bif;
+ struct bstp_state *bs = arg;
+ struct bstp_port *bp;
- BRIDGE_LOCK_ASSERT(sc);
+ BSTP_LOCK_ASSERT(bs);
/* slow timer to catch missed link events */
- if (bstp_timer_expired(&sc->sc_link_timer, BSTP_LINK_TIMER)) {
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- bstp_ifupdstatus(sc, bif);
+ if (bstp_timer_expired(&bs->bs_link_timer, BSTP_LINK_TIMER)) {
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ bstp_ifupdstatus(bs, bp);
}
- bstp_timer_start(&sc->sc_link_timer, 0);
+ bstp_timer_start(&bs->bs_link_timer, 0);
}
- if (bstp_timer_expired(&sc->sc_hello_timer, sc->sc_hello_time))
- bstp_hello_timer_expiry(sc);
+ if (bstp_timer_expired(&bs->bs_hello_timer, bs->bs_hello_time))
+ bstp_hello_timer_expiry(bs);
- if (bstp_timer_expired(&sc->sc_tcn_timer, sc->sc_bridge_hello_time))
- bstp_tcn_timer_expiry(sc);
+ if (bstp_timer_expired(&bs->bs_tcn_timer, bs->bs_bridge_hello_time))
+ bstp_tcn_timer_expiry(bs);
- if (bstp_timer_expired(&sc->sc_topology_change_timer,
- sc->sc_topology_change_time))
- bstp_topology_change_timer_expiry(sc);
+ if (bstp_timer_expired(&bs->bs_topology_change_timer,
+ bs->bs_topology_change_time))
+ bstp_topology_change_timer_expiry(bs);
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bstp_timer_expired(&bif->bif_message_age_timer,
- sc->sc_max_age))
- bstp_message_age_timer_expiry(sc, bif);
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bstp_timer_expired(&bp->bp_message_age_timer,
+ bs->bs_max_age))
+ bstp_message_age_timer_expiry(bs, bp);
}
- LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- if ((bif->bif_flags & IFBIF_STP) == 0)
- continue;
- if (bstp_timer_expired(&bif->bif_forward_delay_timer,
- sc->sc_forward_delay))
- bstp_forward_delay_timer_expiry(sc, bif);
+ LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
+ if (bstp_timer_expired(&bp->bp_forward_delay_timer,
+ bs->bs_forward_delay))
+ bstp_forward_delay_timer_expiry(bs, bp);
- if (bstp_timer_expired(&bif->bif_hold_timer,
- sc->sc_hold_time))
- bstp_hold_timer_expiry(sc, bif);
+ if (bstp_timer_expired(&bp->bp_hold_timer,
+ bs->bs_hold_time))
+ bstp_hold_timer_expiry(bs, bp);
}
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- callout_reset(&sc->sc_bstpcallout, hz, bstp_tick, sc);
+ callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs);
}
static void
-bstp_timer_start(struct bridge_timer *t, uint16_t v)
+bstp_timer_start(struct bstp_timer *t, uint16_t v)
{
t->value = v;
t->active = 1;
}
static void
-bstp_timer_stop(struct bridge_timer *t)
+bstp_timer_stop(struct bstp_timer *t)
{
t->value = 0;
t->active = 0;
}
static int
-bstp_timer_expired(struct bridge_timer *t, uint16_t v)
+bstp_timer_expired(struct bstp_timer *t, uint16_t v)
{
if (t->active == 0)
return (0);
@@ -1194,3 +1221,46 @@ bstp_timer_expired(struct bridge_timer *t, uint16_t v)
return (0);
}
+
+int
+bstp_add(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp)
+{
+ KASSERT(bp->bp_active == 0, ("already a bstp member"));
+
+ switch (ifp->if_type) {
+ case IFT_ETHER: /* These can do spanning tree. */
+ break;
+ default:
+ /* Nothing else can. */
+ return (EINVAL);
+ }
+
+ BSTP_LOCK(bs);
+ bp->bp_ifp = ifp;
+ bp->bp_bs = bs;
+ bp->bp_active = 1;
+ bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY;
+ bp->bp_path_cost = BSTP_DEFAULT_PATH_COST;
+
+ LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
+ BSTP_UNLOCK(bs);
+ bstp_reinit(bs);
+
+ return (0);
+}
+
+void
+bstp_delete(struct bstp_port *bp)
+{
+ struct bstp_state *bs = bp->bp_bs;
+
+ KASSERT(bp->bp_active == 1, ("not a bstp member"));
+
+ BSTP_LOCK(bs);
+ LIST_REMOVE(bp, bp_next);
+ BSTP_UNLOCK(bs);
+ bp->bp_bs = NULL;
+ bp->bp_active = 0;
+
+ bstp_reinit(bs);
+}
diff --git a/sys/net/bridgestp.h b/sys/net/bridgestp.h
new file mode 100644
index 000000000000..61f2317a2777
--- /dev/null
+++ b/sys/net/bridgestp.h
@@ -0,0 +1,256 @@
+/* $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 STP interfaces.
+ */
+
+#include <sys/callout.h>
+#include <sys/queue.h>
+
+/* 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
+
+#ifdef _KERNEL
+
+/*
+ * Spanning tree defaults.
+ */
+#define BSTP_DEFAULT_MAX_AGE (20 * 256)
+#define BSTP_DEFAULT_HELLO_TIME (2 * 256)
+#define BSTP_DEFAULT_FORWARD_DELAY (15 * 256)
+#define BSTP_DEFAULT_HOLD_TIME (1 * 256)
+#define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000
+#define BSTP_DEFAULT_PORT_PRIORITY 0x80
+#define BSTP_DEFAULT_PATH_COST 55
+
+/* BPDU message types */
+#define BSTP_MSGTYPE_CFG 0x00 /* Configuration */
+#define BSTP_MSGTYPE_TCN 0x80 /* Topology chg notification */
+
+/* BPDU flags */
+#define BSTP_FLAG_TC 0x01 /* Topology change */
+#define BSTP_FLAG_TCA 0x80 /* Topology change ack */
+
+#define BSTP_MESSAGE_AGE_INCR (1 * 256) /* in 256ths of a second */
+#define BSTP_TICK_VAL (1 * 256) /* in 256ths of a second */
+#define BSTP_LINK_TIMER (BSTP_TICK_VAL * 30)
+
+/*
+ * Because BPDU's do not make nicely aligned structures, two different
+ * declarations are used: bstp_?bpdu (wire representation, packed) and
+ * bstp_*_unit (internal, nicely aligned version).
+ */
+
+/* configuration bridge protocol data unit */
+struct bstp_cbpdu {
+ uint8_t cbu_dsap; /* LLC: destination sap */
+ uint8_t cbu_ssap; /* LLC: source sap */
+ uint8_t cbu_ctl; /* LLC: control */
+ uint16_t cbu_protoid; /* protocol id */
+ uint8_t cbu_protover; /* protocol version */
+ uint8_t cbu_bpdutype; /* message type */
+ uint8_t cbu_flags; /* flags (below) */
+
+ /* root id */
+ uint16_t cbu_rootpri; /* root priority */
+ uint8_t cbu_rootaddr[6]; /* root address */
+
+ uint32_t cbu_rootpathcost; /* root path cost */
+
+ /* bridge id */
+ uint16_t cbu_bridgepri; /* bridge priority */
+ uint8_t cbu_bridgeaddr[6]; /* bridge address */
+
+ uint16_t cbu_portid; /* port id */
+ uint16_t cbu_messageage; /* current message age */
+ uint16_t cbu_maxage; /* maximum age */
+ uint16_t cbu_hellotime; /* hello time */
+ uint16_t cbu_forwarddelay; /* forwarding delay */
+} __attribute__((__packed__));
+
+/* topology change notification bridge protocol data unit */
+struct bstp_tbpdu {
+ uint8_t tbu_dsap; /* LLC: destination sap */
+ uint8_t tbu_ssap; /* LLC: source sap */
+ uint8_t tbu_ctl; /* LLC: control */
+ uint16_t tbu_protoid; /* protocol id */
+ uint8_t tbu_protover; /* protocol version */
+ uint8_t tbu_bpdutype; /* message type */
+} __attribute__((__packed__));
+
+/*
+ * Timekeeping structure used in spanning tree code.
+ */
+struct bstp_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 bstp_port {
+ LIST_ENTRY(bstp_port) bp_next;
+ struct ifnet *bp_ifp; /* parent if */
+ struct bstp_state *bp_bs;
+ int bp_active;
+ uint64_t bp_designated_root;
+ uint64_t bp_designated_bridge;
+ uint32_t bp_path_cost;
+ uint32_t bp_designated_cost;
+ struct bstp_timer bp_hold_timer;
+ struct bstp_timer bp_message_age_timer;
+ struct bstp_timer bp_forward_delay_timer;
+ struct bstp_config_unit bp_config_bpdu;
+ uint16_t bp_port_id;
+ uint16_t bp_designated_port;
+ uint8_t bp_state;
+ uint8_t bp_topology_change_acknowledge;
+ uint8_t bp_config_pending;
+ uint8_t bp_change_detection_enabled;
+ uint8_t bp_priority;
+};
+
+/*
+ * Software state for each bridge STP.
+ */
+struct bstp_state {
+ LIST_ENTRY(bstp_state) bs_list;
+ struct mtx bs_mtx;
+ uint64_t bs_designated_root;
+ uint64_t bs_bridge_id;
+ struct bstp_port *bs_root_port;
+ uint32_t bs_root_path_cost;
+ uint16_t bs_max_age;
+ uint16_t bs_hello_time;
+ uint16_t bs_forward_delay;
+ uint16_t bs_bridge_max_age;
+ uint16_t bs_bridge_hello_time;
+ uint16_t bs_bridge_forward_delay;
+ uint16_t bs_topology_change_time;
+ uint16_t bs_hold_time;
+ uint16_t bs_bridge_priority;
+ uint8_t bs_topology_change_detected;
+ uint8_t bs_topology_change;
+ struct bstp_timer bs_hello_timer;
+ struct bstp_timer bs_topology_change_timer;
+ struct bstp_timer bs_tcn_timer;
+ struct callout bs_bstpcallout; /* STP callout */
+ struct bstp_timer bs_link_timer;
+ LIST_HEAD(, bstp_port) bs_bplist;
+};
+
+#define BSTP_LOCK_INIT(_bs) mtx_init(&(_bs)->bs_mtx, "bstp", \
+ NULL, MTX_DEF)
+#define BSTP_LOCK_DESTROY(_bs) mtx_destroy(&(_bs)->bs_mtx)
+#define BSTP_LOCK(_bs) mtx_lock(&(_bs)->bs_mtx)
+#define BSTP_UNLOCK(_bs) mtx_unlock(&(_bs)->bs_mtx)
+#define BSTP_LOCK_ASSERT(_bs) mtx_assert(&(_bs)->bs_mtx, MA_OWNED)
+
+extern const uint8_t bstp_etheraddr[];
+
+extern void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
+
+void bstp_attach(struct bstp_state *);
+void bstp_detach(struct bstp_state *);
+void bstp_init(struct bstp_state *);
+void bstp_reinit(struct bstp_state *);
+void bstp_stop(struct bstp_state *);
+int bstp_add(struct bstp_state *, struct bstp_port *, struct ifnet *);
+void bstp_delete(struct bstp_port *);
+void bstp_linkstate(struct ifnet *, int);
+struct mbuf *bstp_input(struct bstp_port *, struct ifnet *, struct mbuf *);
+
+#endif /* _KERNEL */
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 62f896c75ec6..65393f81492f 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -126,6 +126,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <machine/in_cksum.h>
#include <netinet/if_ether.h> /* for struct arpcom */
+#include <net/bridgestp.h>
#include <net/if_bridgevar.h>
#include <net/if_llc.h>
@@ -150,17 +151,6 @@ __FBSDID("$FreeBSD$");
#endif
/*
- * Spanning tree defaults.
- */
-#define BSTP_DEFAULT_MAX_AGE (20 * 256)
-#define BSTP_DEFAULT_HELLO_TIME (2 * 256)
-#define BSTP_DEFAULT_FORWARD_DELAY (15 * 256)
-#define BSTP_DEFAULT_HOLD_TIME (1 * 256)
-#define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000
-#define BSTP_DEFAULT_PORT_PRIORITY 0x80
-#define BSTP_DEFAULT_PATH_COST 55
-
-/*
* Timeout (in seconds) for entries learned dynamically.
*/
#ifndef BRIDGE_RTABLE_TIMEOUT
@@ -471,17 +461,16 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
sc->sc_brtmax = BRIDGE_RTABLE_MAX;
sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
- sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
- sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
- sc->sc_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY;
- sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
- sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME;
+ sc->sc_stp.bs_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
+ sc->sc_stp.bs_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
+ sc->sc_stp.bs_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY;
+ sc->sc_stp.bs_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
+ sc->sc_stp.bs_hold_time = BSTP_DEFAULT_HOLD_TIME;
/* Initialize our routing table. */
bridge_rtable_init(sc);
callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0);
- callout_init_mtx(&sc->sc_bstpcallout, &sc->sc_mtx, 0);
LIST_INIT(&sc->sc_iflist);
LIST_INIT(&sc->sc_spanlist);
@@ -519,6 +508,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
mtx_unlock(&bridge_list_mtx);
}
+ bstp_attach(&sc->sc_stp);
ether_ifattach(ifp, eaddr);
/* Now undo some of the damage... */
ifp->if_baudrate = 0;
@@ -557,12 +547,12 @@ bridge_clone_destroy(struct ifnet *ifp)
BRIDGE_UNLOCK(sc);
callout_drain(&sc->sc_brcallout);
- callout_drain(&sc->sc_bstpcallout);
mtx_lock(&bridge_list_mtx);
LIST_REMOVE(sc, sc_list);
mtx_unlock(&bridge_list_mtx);
+ bstp_detach(&sc->sc_stp);
ether_ifdetach(ifp);
if_free_type(ifp, IFT_ETHER);
@@ -801,6 +791,9 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
}
}
+ if (bif->bif_flags & IFBIF_STP)
+ bstp_delete(&bif->bif_stp);
+
ifs->if_bridge = NULL;
BRIDGE_XLOCK(sc);
LIST_REMOVE(bif, bif_next);
@@ -809,9 +802,6 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
free(bif, M_DEVBUF);
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
}
/*
@@ -873,8 +863,6 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
bif->bif_ifp = ifs;
bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
- bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY;
- bif->bif_path_cost = BSTP_DEFAULT_PATH_COST;
switch (ifs->if_type) {
case IFT_ETHER:
@@ -905,11 +893,6 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
*/
LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next);
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
- else
- bstp_stop(sc);
-
out:
if (error) {
if (bif != NULL)
@@ -948,9 +931,9 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
return (ENOENT);
req->ifbr_ifsflags = bif->bif_flags;
- req->ifbr_state = bif->bif_state;
- req->ifbr_priority = bif->bif_priority;
- req->ifbr_path_cost = bif->bif_path_cost;
+ req->ifbr_state = bif->bif_stp.bp_state;
+ req->ifbr_priority = bif->bif_stp.bp_priority;
+ req->ifbr_path_cost = bif->bif_stp.bp_path_cost;
req->ifbr_portno = bif->bif_ifp->if_index & 0xff;
return (0);
@@ -961,6 +944,7 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
{
struct ifbreq *req = arg;
struct bridge_iflist *bif;
+ int error;
BRIDGE_LOCK_ASSERT(sc);
@@ -973,22 +957,19 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
return (EINVAL);
if (req->ifbr_ifsflags & IFBIF_STP) {
- switch (bif->bif_ifp->if_type) {
- case IFT_ETHER:
- /* These can do spanning tree. */
- break;
-
- default:
- /* Nothing else can. */
- return (EINVAL);
+ if ((bif->bif_flags & IFBIF_STP) == 0) {
+ error = bstp_add(&sc->sc_stp, &bif->bif_stp,
+ bif->bif_ifp);
+ if (error)
+ return (error);
}
+ } else {
+ if ((bif->bif_flags & IFBIF_STP) != 0)
+ bstp_delete(&bif->bif_stp);
}
bif->bif_flags = req->ifbr_ifsflags;
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
-
return (0);
}
@@ -1048,9 +1029,9 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname,
sizeof(breq.ifbr_ifsname));
breq.ifbr_ifsflags = bif->bif_flags;
- breq.ifbr_state = bif->bif_state;
- breq.ifbr_priority = bif->bif_priority;
- breq.ifbr_path_cost = bif->bif_path_cost;
+ breq.ifbr_state = bif->bif_stp.bp_state;
+ breq.ifbr_priority = bif->bif_stp.bp_priority;
+ breq.ifbr_path_cost = bif->bif_stp.bp_path_cost;
breq.ifbr_portno = bif->bif_ifp->if_index & 0xff;
error = copyout(&breq, bifc->ifbic_req + count, sizeof(breq));
if (error)
@@ -1065,9 +1046,9 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname,
sizeof(breq.ifbr_ifsname));
breq.ifbr_ifsflags = bif->bif_flags;
- breq.ifbr_state = bif->bif_state;
- breq.ifbr_priority = bif->bif_priority;
- breq.ifbr_path_cost = bif->bif_path_cost;
+ breq.ifbr_state = bif->bif_stp.bp_state;
+ breq.ifbr_priority = bif->bif_stp.bp_priority;
+ breq.ifbr_path_cost = bif->bif_stp.bp_path_cost;
breq.ifbr_portno = bif->bif_ifp->if_index & 0xff;
error = copyout(&breq, bifc->ifbic_req + count, sizeof(breq));
if (error)
@@ -1188,10 +1169,11 @@ static int
bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
- param->ifbrp_prio = sc->sc_bridge_priority;
+ param->ifbrp_prio = bs->bs_bridge_priority;
return (0);
}
@@ -1200,13 +1182,12 @@ static int
bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
- sc->sc_bridge_priority = param->ifbrp_prio;
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
+ bs->bs_bridge_priority = param->ifbrp_prio;
+ bstp_reinit(bs);
return (0);
}
@@ -1215,10 +1196,11 @@ static int
bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
- param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8;
+ param->ifbrp_hellotime = bs->bs_bridge_hello_time >> 8;
return (0);
}
@@ -1227,15 +1209,14 @@ static int
bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
if (param->ifbrp_hellotime == 0)
return (EINVAL);
- sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8;
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
+ bs->bs_bridge_hello_time = param->ifbrp_hellotime << 8;
+ bstp_reinit(bs);
return (0);
}
@@ -1244,10 +1225,11 @@ static int
bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
- param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8;
+ param->ifbrp_fwddelay = bs->bs_bridge_forward_delay >> 8;
return (0);
}
@@ -1256,15 +1238,14 @@ static int
bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
if (param->ifbrp_fwddelay == 0)
return (EINVAL);
- sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8;
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
+ bs->bs_bridge_forward_delay = param->ifbrp_fwddelay << 8;
+ bstp_reinit(bs);
return (0);
}
@@ -1273,10 +1254,11 @@ static int
bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
- param->ifbrp_maxage = sc->sc_bridge_max_age >> 8;
+ param->ifbrp_maxage = bs->bs_bridge_max_age >> 8;
return (0);
}
@@ -1285,15 +1267,14 @@ static int
bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
{
struct ifbrparam *param = arg;
+ struct bstp_state *bs = &sc->sc_stp;
BRIDGE_LOCK_ASSERT(sc);
if (param->ifbrp_maxage == 0)
return (EINVAL);
- sc->sc_bridge_max_age = param->ifbrp_maxage << 8;
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
+ bs->bs_bridge_max_age = param->ifbrp_maxage << 8;
+ bstp_reinit(bs);
return (0);
}
@@ -1310,10 +1291,8 @@ bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
if (bif == NULL)
return (ENOENT);
- bif->bif_priority = req->ifbr_priority;
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
+ bif->bif_stp.bp_priority = req->ifbr_priority;
+ bstp_reinit(&sc->sc_stp);
return (0);
}
@@ -1330,10 +1309,8 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
if (bif == NULL)
return (ENOENT);
- bif->bif_path_cost = req->ifbr_path_cost;
-
- if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- bstp_initialization(sc);
+ bif->bif_stp.bp_path_cost = req->ifbr_path_cost;
+ bstp_reinit(&sc->sc_stp);
return (0);
}
@@ -1462,7 +1439,8 @@ bridge_init(void *xsc)
bridge_timer, sc);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
- bstp_initialization(sc);
+ bstp_init(&sc->sc_stp); /* Initialize Spanning Tree */
+
BRIDGE_UNLOCK(sc);
}
@@ -1482,7 +1460,7 @@ bridge_stop(struct ifnet *ifp, int disable)
return;
callout_stop(&sc->sc_brcallout);
- bstp_stop(sc);
+ bstp_stop(&sc->sc_stp);
bridge_rtflush(sc, IFBF_FLUSHDYN);
@@ -1646,7 +1624,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
*/
if (dst_if != ifp &&
(bif->bif_flags & IFBIF_STP) != 0) {
- switch (bif->bif_state) {
+ switch (bif->bif_stp.bp_state) {
case BSTP_IFSTATE_BLOCKING:
case BSTP_IFSTATE_LISTENING:
case BSTP_IFSTATE_DISABLED:
@@ -1764,7 +1742,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
}
if (bif->bif_flags & IFBIF_STP) {
- switch (bif->bif_state) {
+ switch (bif->bif_stp.bp_state) {
case BSTP_IFSTATE_BLOCKING:
case BSTP_IFSTATE_LISTENING:
case BSTP_IFSTATE_DISABLED:
@@ -1794,7 +1772,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
}
if ((bif->bif_flags & IFBIF_STP) != 0 &&
- bif->bif_state == BSTP_IFSTATE_LEARNING) {
+ bif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) {
m_freem(m);
BRIDGE_UNLOCK(sc);
return;
@@ -1871,7 +1849,7 @@ bridge_forward(struct bridge_softc *sc, struct mbuf *m)
}
if (bif->bif_flags & IFBIF_STP) {
- switch (bif->bif_state) {
+ switch (bif->bif_stp.bp_state) {
case BSTP_IFSTATE_DISABLED:
case BSTP_IFSTATE_BLOCKING:
BRIDGE_UNLOCK(sc);
@@ -1962,7 +1940,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
/* Tap off 802.1D packets; they do not get forwarded. */
if (memcmp(eh->ether_dhost, bstp_etheraddr,
ETHER_ADDR_LEN) == 0) {
- m = bstp_input(ifp, m);
+ m = bstp_input(&bif->bif_stp, ifp, m);
if (m == NULL) {
BRIDGE_UNLOCK(sc);
return (NULL);
@@ -1970,7 +1948,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
}
if (bif->bif_flags & IFBIF_STP) {
- switch (bif->bif_state) {
+ switch (bif->bif_stp.bp_state) {
case BSTP_IFSTATE_BLOCKING:
case BSTP_IFSTATE_LISTENING:
case BSTP_IFSTATE_DISABLED:
@@ -2023,7 +2001,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
}
if (bif->bif_flags & IFBIF_STP) {
- switch (bif->bif_state) {
+ switch (bif->bif_stp.bp_state) {
case BSTP_IFSTATE_BLOCKING:
case BSTP_IFSTATE_LISTENING:
case BSTP_IFSTATE_DISABLED:
@@ -2117,7 +2095,7 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
continue;
if (bif->bif_flags & IFBIF_STP) {
- switch (bif->bif_state) {
+ switch (bif->bif_stp.bp_state) {
case BSTP_IFSTATE_BLOCKING:
case BSTP_IFSTATE_DISABLED:
continue;
diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h
index 4ac7307e3387..b8a4265cf943 100644
--- a/sys/net/if_bridgevar.h
+++ b/sys/net/if_bridgevar.h
@@ -133,13 +133,6 @@ struct ifbreq {
#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.
*/
@@ -200,53 +193,14 @@ struct ifbrparam {
#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 */
+ struct bstp_port bif_stp; /* STP state */
uint32_t bif_flags; /* member if flags */
int bif_mutecap; /* member muted caps */
};
@@ -271,29 +225,10 @@ struct bridge_softc {
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 */
@@ -301,7 +236,7 @@ struct bridge_softc {
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
uint32_t sc_rthash_key; /* key for hash */
LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */
- struct bridge_timer sc_link_timer;
+ struct bstp_state sc_stp; /* STP state */
};
#define BRIDGE_LOCK_INIT(_sc) do { \
@@ -356,8 +291,6 @@ struct bridge_softc {
_err = (*bridge_output_p)(_ifp, _m, NULL, NULL); \
} while (0)
-extern const uint8_t bstp_etheraddr[];
-
void bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *);
void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
@@ -365,12 +298,5 @@ extern struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *);
extern int (*bridge_output_p)(struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *);
extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
-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 *);
-
#endif /* _KERNEL */