Page MenuHomeFreeBSD

D59850.1794440392.diff
No OneTemporary

Authored By
Unknown
Size
4 KB
Referenced Files
None
Subscribers
None

D59850.1794440392.diff

diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c
--- a/sys/net/bridgestp.c
+++ b/sys/net/bridgestp.c
@@ -460,12 +460,9 @@
struct bstp_tbpdu tpdu;
uint16_t len;
- if (bp->bp_active == 0) {
- m_freem(m);
- return;
- }
-
BSTP_LOCK(bs);
+ if (bp->bp_active == 0)
+ goto out;
eh = mtod(m, struct ether_header *);
@@ -1697,8 +1694,8 @@
BSTP_LOCK(bs);
if (set) {
bp->bp_flags |= BSTP_PORT_AUTOPTP;
- if (bp->bp_role != BSTP_ROLE_DISABLED)
- taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
+ if (bp->bp_active && bp->bp_role != BSTP_ROLE_DISABLED)
+ taskqueue_enqueue(taskqueue_thread, &bp->bp_mediatask);
} else
bp->bp_flags &= ~BSTP_PORT_AUTOPTP;
BSTP_UNLOCK(bs);
@@ -1792,31 +1789,41 @@
{
struct bstp_state *bs = bp->bp_bs;
- if (!bp->bp_active)
- return;
+ NET_EPOCH_ASSERT();
- bstp_ifupdstatus(bp, 0);
+ /* The caller holds the network epoch; the media ioctl may sleep. */
BSTP_LOCK(bs);
- bstp_update_state(bs, bp);
+ if (bp->bp_active)
+ taskqueue_enqueue(taskqueue_thread, &bp->bp_mediatask);
BSTP_UNLOCK(bs);
}
static void
bstp_ifupdstatus(void *arg, int pending)
{
+ struct epoch_tracker et;
struct bstp_port *bp = (struct bstp_port *)arg;
struct bstp_state *bs = bp->bp_bs;
struct ifnet *ifp = bp->bp_ifp;
struct ifmediareq ifmr;
int error, changed;
- if (!bp->bp_active)
+ BSTP_LOCK(bs);
+ if (!bp->bp_active) {
+ BSTP_UNLOCK(bs);
return;
+ }
+ BSTP_UNLOCK(bs);
+ CURVNET_SET(ifp->if_vnet);
bzero((char *)&ifmr, sizeof(ifmr));
error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
+ /* Updating the STP state may transmit BPDUs. */
+ NET_EPOCH_ENTER(et);
BSTP_LOCK(bs);
+ if (!bp->bp_active)
+ goto out;
changed = 0;
if ((error == 0) && (ifp->if_flags & IFF_UP)) {
if (ifmr.ifm_status & IFM_ACTIVE) {
@@ -1862,7 +1869,11 @@
}
if (changed)
bstp_assign_roles(bs);
+ bstp_update_state(bs, bp);
+out:
BSTP_UNLOCK(bs);
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
}
static void
@@ -1896,7 +1907,7 @@
if (bstp_timer_dectest(&bs->bs_link_timer)) {
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
if (!(bp->bp_ifp->if_capabilities & IFCAP_LINKSTATE))
- taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
+ taskqueue_enqueue(taskqueue_thread, &bp->bp_mediatask);
}
bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER);
}
@@ -2109,7 +2120,7 @@
LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
bp->bp_port_id = (bp->bp_priority << 8) |
(bp->bp_ifp->if_index & 0xfff);
- taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask);
+ taskqueue_enqueue(taskqueue_thread, &bp->bp_mediatask);
}
bstp_assign_roles(bs);
@@ -2181,6 +2192,10 @@
mtx_unlock(&bstp_list_mtx);
}
+/*
+ * The caller must destroy bs_mtx after a network epoch grace period.
+ * Input and link-state callbacks may still be checking inactive ports.
+ */
void
bstp_detach(struct bstp_state *bs)
{
@@ -2190,7 +2205,6 @@
LIST_REMOVE(bs, bs_list);
mtx_unlock(&bstp_list_mtx);
callout_drain(&bs->bs_bstpcallout);
- BSTP_LOCK_DESTROY(bs);
}
void
@@ -2292,11 +2306,19 @@
void
bstp_destroy(struct bstp_port *bp)
{
+ struct epoch_tracker et;
+ struct bstp_state *bs = bp->bp_bs;
+
KASSERT(bp->bp_active == 0, ("port is still attached"));
+ /* Media updates can enqueue state and route-age notifications. */
+ taskqueue_drain(taskqueue_thread, &bp->bp_mediatask);
taskqueue_drain(taskqueue_swi, &bp->bp_statetask);
taskqueue_drain(taskqueue_swi, &bp->bp_rtagetask);
- taskqueue_drain(taskqueue_swi, &bp->bp_mediatask);
- if (bp->bp_bs->bs_root_port == bp)
- bstp_assign_roles(bp->bp_bs);
+ NET_EPOCH_ENTER(et);
+ BSTP_LOCK(bs);
+ if (bs->bs_root_port == bp)
+ bstp_assign_roles(bs);
+ BSTP_UNLOCK(bs);
+ NET_EPOCH_EXIT(et);
}
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -920,6 +920,7 @@
sc = __containerof(ctx, struct bridge_softc, sc_epoch_ctx);
+ BSTP_LOCK_DESTROY(&sc->sc_stp);
BRIDGE_LOCK_DESTROY(sc);
free(sc, M_DEVBUF);
}
@@ -1253,6 +1254,8 @@
if (bif->bif_flags & IFBIF_STP)
bstp_disable(&bif->bif_stp);
+ /* Notifications may still need the member's bridge pointer. */
+ bstp_destroy(&bif->bif_stp);
ifs->if_bridge = NULL;
CK_LIST_REMOVE(bif, bif_next);
@@ -1313,8 +1316,6 @@
/* Re-enable any interface capabilities */
bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
}
- bstp_destroy(&bif->bif_stp); /* prepare to free */
-
NET_EPOCH_CALL(bridge_delete_member_cb, &bif->bif_epoch_ctx);
}
@@ -1515,11 +1516,11 @@
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
}
+ bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
ifs->if_bridge = bif;
ifs->if_bridge_output = bridge_output;
ifs->if_bridge_input = bridge_input;
ifs->if_bridge_linkstate = bridge_linkstate;
- bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
/*
* XXX: XLOCK HERE!?!
*

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 11, 11:39 PM (8 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41667509
Default Alt Text
D59850.1794440392.diff (4 KB)

Event Timeline