summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2006-08-02 02:47:27 +0000
committerthompsa <thompsa@FreeBSD.org>2006-08-02 02:47:27 +0000
commit1b5eb404f16c470940b710c07045e08bd5ffc18c (patch)
tree8521209ff51d7ce66b3baea955b4b4059dec1761 /sys
parent1c044fd132c6765720a3c35007a656a163e27fc7 (diff)
downloadFreeBSD-src-1b5eb404f16c470940b710c07045e08bd5ffc18c.zip
FreeBSD-src-1b5eb404f16c470940b710c07045e08bd5ffc18c.tar.gz
Add a callback so we can notify the parent bridge that a port state change has
occured, we need to do this from a taskqueue to avoid a LOR with the if_bridge mutex.
Diffstat (limited to 'sys')
-rw-r--r--sys/net/bridgestp.c37
-rw-r--r--sys/net/bridgestp.h10
2 files changed, 43 insertions, 4 deletions
diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c
index 86e79e9..fc59ea8 100644
--- a/sys/net/bridgestp.c
+++ b/sys/net/bridgestp.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -112,6 +113,7 @@ static void bstp_make_forwarding(struct bstp_state *,
static void bstp_make_blocking(struct bstp_state *,
struct bstp_port *);
static void bstp_set_port_state(struct bstp_port *, uint8_t);
+static void bstp_state_change(void *, int);
static void bstp_update_forward_transitions(struct bstp_port *);
#ifdef notused
static void bstp_set_bridge_priority(struct bstp_state *, uint64_t);
@@ -520,7 +522,6 @@ bstp_make_blocking(struct bstp_state *bs, struct bstp_port *bp)
}
}
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);
}
}
@@ -529,6 +530,25 @@ static void
bstp_set_port_state(struct bstp_port *bp, uint8_t state)
{
bp->bp_state = state;
+ struct bstp_state *bs = bp->bp_bs;
+
+ /* notify the parent bridge */
+ if (bs->bs_state_cb != NULL)
+ taskqueue_enqueue(taskqueue_swi, &bp->bp_statetask);
+}
+
+/*
+ * Notify the bridge that a port state has changed, we need to do this from a
+ * taskqueue to avoid a LOR.
+ */
+static void
+bstp_state_change(void *arg, int pending)
+{
+ struct bstp_port *bp = (struct bstp_port *)arg;
+ struct bstp_state *bs = bp->bp_bs;
+
+ if (bp->bp_active == 1)
+ (*bs->bs_state_cb)(bp->bp_ifp, bp->bp_state);
}
static void
@@ -910,7 +930,7 @@ static moduledata_t bstp_mod = {
DECLARE_MODULE(bridgestp, bstp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
void
-bstp_attach(struct bstp_state *bs)
+bstp_attach(struct bstp_state *bs, bstp_state_cb_t state_callback)
{
BSTP_LOCK_INIT(bs);
callout_init_mtx(&bs->bs_bstpcallout, &bs->bs_mtx, 0);
@@ -921,6 +941,7 @@ bstp_attach(struct bstp_state *bs)
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;
+ bs->bs_state_cb = state_callback;
mtx_lock(&bstp_list_mtx);
LIST_INSERT_HEAD(&bstp_list, bs, bs_list);
@@ -1007,7 +1028,6 @@ bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp)
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;
@@ -1253,6 +1273,7 @@ bstp_add(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp)
bp->bp_path_cost = BSTP_DEFAULT_PATH_COST;
LIST_INSERT_HEAD(&bs->bs_bplist, bp, bp_next);
+ TASK_INIT(&bp->bp_statetask, 0, bstp_state_change, bp);
BSTP_UNLOCK(bs);
bstp_reinit(bs);
@@ -1276,3 +1297,13 @@ bstp_delete(struct bstp_port *bp)
bstp_reinit(bs);
}
+
+/*
+ * The bstp_port structure is about to be freed by the parent bridge.
+ */
+void
+bstp_drain(struct bstp_port *bp)
+{
+ KASSERT(bp->bp_active == 0, ("port is still attached"));
+ taskqueue_drain(taskqueue_swi, &bp->bp_statetask);
+}
diff --git a/sys/net/bridgestp.h b/sys/net/bridgestp.h
index 0905653..6e3f50a 100644
--- a/sys/net/bridgestp.h
+++ b/sys/net/bridgestp.h
@@ -110,6 +110,11 @@
#define BSTP_LINK_TIMER (BSTP_TICK_VAL * 30)
/*
+ * * Driver callbacks for STP state changes
+ * */
+typedef void (*bstp_state_cb_t)(struct ifnet *, int);
+
+/*
* 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).
@@ -202,6 +207,7 @@ struct bstp_port {
uint8_t bp_change_detection_enabled;
uint8_t bp_priority;
uint32_t bp_forward_transitions;
+ struct task bp_statetask;
};
/*
@@ -232,6 +238,7 @@ struct bstp_state {
struct bstp_timer bs_link_timer;
struct timeval bs_last_tc_time;
LIST_HEAD(, bstp_port) bs_bplist;
+ bstp_state_cb_t bs_state_cb;
};
#define BSTP_LOCK_INIT(_bs) mtx_init(&(_bs)->bs_mtx, "bstp", \
@@ -245,13 +252,14 @@ extern const uint8_t bstp_etheraddr[];
extern void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
-void bstp_attach(struct bstp_state *);
+void bstp_attach(struct bstp_state *, bstp_state_cb_t);
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_drain(struct bstp_port *);
void bstp_linkstate(struct ifnet *, int);
struct mbuf *bstp_input(struct bstp_port *, struct ifnet *, struct mbuf *);
OpenPOWER on IntegriCloud