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.
This commit is contained in:
parent
1c044fd132
commit
1b5eb404f1
@ -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);
|
||||
}
|
||||
|
@ -109,6 +109,11 @@
|
||||
#define BSTP_TICK_VAL (1 * 256) /* in 256ths of a second */
|
||||
#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
|
||||
@ -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 *);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user