diff options
author | thompsa <thompsa@FreeBSD.org> | 2006-08-02 02:47:27 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2006-08-02 02:47:27 +0000 |
commit | 1b5eb404f16c470940b710c07045e08bd5ffc18c (patch) | |
tree | 8521209ff51d7ce66b3baea955b4b4059dec1761 /sys | |
parent | 1c044fd132c6765720a3c35007a656a163e27fc7 (diff) | |
download | FreeBSD-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.c | 37 | ||||
-rw-r--r-- | sys/net/bridgestp.h | 10 |
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 *); |