commit 7a9b562073c053dc050bf0ccdb5416200cb0ea23 Author: Ryota Ozaki Date: Thu Dec 4 11:57:00 2014 +0900 psz bridge diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c index bcad84c..95208ce 100644 --- a/sys/net/bridgestp.c +++ b/sys/net/bridgestp.c @@ -221,7 +221,7 @@ bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif, struct bstp_cbpdu bpdu; int s; - KASSERT(BRIDGE_LOCKED(sc)); + KASSERT(BRIDGE_INTR_LOCKED(sc)); ifp = bif->bif_ifp; @@ -276,11 +276,11 @@ bstp_send_config_bpdu(struct bridge_softc *sc, struct bridge_iflist *bif, memcpy(mtod(m, char *) + sizeof(*eh), &bpdu, sizeof(bpdu)); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); s = splnet(); bridge_enqueue(sc, ifp, m, 0); splx(s); - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); } static int @@ -367,7 +367,7 @@ bstp_transmit_tcn(struct bridge_softc *sc) struct mbuf *m; int s; - KASSERT(BRIDGE_LOCKED(sc)); + KASSERT(BRIDGE_INTR_LOCKED(sc)); KASSERT(bif != NULL); ifp = bif->bif_ifp; @@ -396,11 +396,11 @@ bstp_transmit_tcn(struct bridge_softc *sc) memcpy(mtod(m, char *) + sizeof(*eh), &bpdu, sizeof(bpdu)); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); s = splnet(); bridge_enqueue(sc, ifp, m, 0); splx(s); - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); } static void @@ -634,9 +634,9 @@ bstp_input(struct bridge_softc *sc, struct bridge_iflist *bif, struct mbuf *m) case BSTP_MSGTYPE_TCN: tu.tu_message_type = tpdu.tbu_bpdutype; - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); bstp_received_tcn_bpdu(sc, bif, &tu); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); break; case BSTP_MSGTYPE_CFG: @@ -675,9 +675,9 @@ bstp_input(struct bridge_softc *sc, struct bridge_iflist *bif, struct mbuf *m) cu.cu_topology_change = (cpdu.cbu_flags & BSTP_FLAG_TC) ? 1 : 0; - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); bstp_received_config_bpdu(sc, bif, &cu); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); break; default: @@ -826,7 +826,7 @@ bstp_initialization(struct bridge_softc *sc) mif = NULL; - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if ((bif->bif_flags & IFBIF_STP) == 0) @@ -848,7 +848,7 @@ bstp_initialization(struct bridge_softc *sc) } if (mif == NULL) { - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); bstp_stop(sc); return; } @@ -862,7 +862,7 @@ bstp_initialization(struct bridge_softc *sc) (((uint64_t)(uint8_t)CLLADDR(mif->bif_ifp->if_sadl)[4]) << 8) | (((uint64_t)(uint8_t)CLLADDR(mif->bif_ifp->if_sadl)[5]) << 0); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); sc->sc_designated_root = sc->sc_bridge_id; sc->sc_root_path_cost = 0; @@ -880,7 +880,7 @@ bstp_initialization(struct bridge_softc *sc) callout_reset(&sc->sc_bstpcallout, hz, bstp_tick, sc); - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if (bif->bif_flags & IFBIF_STP) @@ -893,7 +893,7 @@ bstp_initialization(struct bridge_softc *sc) bstp_config_bpdu_generation(sc); bstp_timer_start(&sc->sc_hello_timer, 0); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); } void @@ -901,14 +901,14 @@ bstp_stop(struct bridge_softc *sc) { struct bridge_iflist *bif; - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); 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); } - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); callout_stop(&sc->sc_bstpcallout); @@ -1065,7 +1065,7 @@ bstp_tick(void *arg) int s; s = splnet(); - BRIDGE_LOCK(sc); + BRIDGE_INTR_LOCK(sc); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if ((bif->bif_flags & IFBIF_STP) == 0) @@ -1113,7 +1113,7 @@ bstp_tick(void *arg) if (sc->sc_if.if_flags & IFF_RUNNING) callout_reset(&sc->sc_bstpcallout, hz, bstp_tick, sc); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); splx(s); } diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 3909c00..2b4eb63 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -223,6 +223,7 @@ static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, static void bridge_release_member(struct bridge_softc *, struct bridge_iflist *); static void bridge_delete_member(struct bridge_softc *, struct bridge_iflist *); +static struct bridge_iflist *bridge_try_hold_bif(struct bridge_iflist *); static int bridge_ioctl_add(struct bridge_softc *, void *); static int bridge_ioctl_del(struct bridge_softc *, void *); @@ -369,8 +370,12 @@ bridge_clone_create(struct if_clone *ifc, int unit) LIST_INIT(&sc->sc_iflist); #ifdef BRIDGE_MPSAFE sc->sc_iflist_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); + sc->sc_iflist_psz = pserialize_create(); + sc->sc_iflist_psz_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET); #else sc->sc_iflist_lock = NULL; + sc->sc_iflist_psz = NULL; + sc->sc_iflist_psz_lock = NULL; #endif cv_init(&sc->sc_iflist_cv, "if_bridge_cv"); @@ -422,10 +427,8 @@ bridge_clone_destroy(struct ifnet *ifp) bridge_stop(ifp, 1); - BRIDGE_LOCK(sc); while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) bridge_delete_member(sc, bif); - BRIDGE_UNLOCK(sc); mutex_enter(&bridge_list_lock); LIST_REMOVE(sc, sc_list); @@ -446,6 +449,11 @@ bridge_clone_destroy(struct ifnet *ifp) if (sc->sc_iflist_lock) mutex_obj_free(sc->sc_iflist_lock); + if (sc->sc_iflist_psz) + pserialize_destroy(sc->sc_iflist_psz); + if (sc->sc_iflist_psz_lock) + mutex_obj_free(sc->sc_iflist_psz_lock); + kmem_free(sc, sizeof(*sc)); return (0); @@ -674,25 +682,18 @@ bridge_lookup_member(struct bridge_softc *sc, const char *name) { struct bridge_iflist *bif; struct ifnet *ifp; + int s; - BRIDGE_LOCK(sc); + BRIDGE_RENTER(s); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { ifp = bif->bif_ifp; if (strcmp(ifp->if_xname, name) == 0) break; } + bif = bridge_try_hold_bif(bif); -#ifdef BRIDGE_MPSAFE - if (bif != NULL) { - if (bif->bif_waiting) - bif = NULL; - else - atomic_inc_32(&bif->bif_refs); - } -#endif - - BRIDGE_UNLOCK(sc); + BRIDGE_REXIT(s); return bif; } @@ -706,11 +707,21 @@ static struct bridge_iflist * bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) { struct bridge_iflist *bif; + int s; - BRIDGE_LOCK(sc); + BRIDGE_RENTER(s); bif = member_ifp->if_bridgeif; + bif = bridge_try_hold_bif(bif); + BRIDGE_REXIT(s); + + return bif; +} + +static struct bridge_iflist * +bridge_try_hold_bif(struct bridge_iflist *bif) +{ #ifdef BRIDGE_MPSAFE if (bif != NULL) { if (bif->bif_waiting) @@ -719,9 +730,6 @@ bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) atomic_inc_32(&bif->bif_refs); } #endif - - BRIDGE_UNLOCK(sc); - return bif; } @@ -734,12 +742,13 @@ static void bridge_release_member(struct bridge_softc *sc, struct bridge_iflist *bif) { #ifdef BRIDGE_MPSAFE - atomic_dec_32(&bif->bif_refs); - membar_sync(); - if (__predict_false(bif->bif_waiting && bif->bif_refs == 0)) { - BRIDGE_LOCK(sc); + uint32_t refs; + + refs = atomic_dec_uint_nv(&bif->bif_refs); + if (__predict_false(refs == 0 && bif->bif_waiting)) { + BRIDGE_INTR_LOCK(sc); cv_broadcast(&sc->sc_iflist_cv); - BRIDGE_UNLOCK(sc); + BRIDGE_INTR_UNLOCK(sc); } #else (void)sc; @@ -757,7 +766,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) { struct ifnet *ifs = bif->bif_ifp; - KASSERT(BRIDGE_LOCKED(sc)); + BRIDGE_LOCK(sc); ifs->if_input = ether_input; ifs->if_bridge = NULL; @@ -765,13 +774,21 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) LIST_REMOVE(bif, bif_next); + if (sc->sc_iflist_psz != NULL) + pserialize_perform(sc->sc_iflist_psz); + + BRIDGE_UNLOCK(sc); + #ifdef BRIDGE_MPSAFE + BRIDGE_INTR_LOCK(sc); bif->bif_waiting = true; membar_sync(); while (bif->bif_refs > 0) { aprint_debug("%s: cv_wait on iflist\n", __func__); cv_wait(&sc->sc_iflist_cv, sc->sc_iflist_lock); } + bif->bif_waiting = false; + BRIDGE_INTR_UNLOCK(sc); #endif kmem_free(bif, sizeof(*bif)); @@ -875,9 +892,10 @@ bridge_ioctl_del(struct bridge_softc *sc, void *arg) return ENOENT; } + BRIDGE_UNLOCK(sc); + bridge_delete_member(sc, bif); - BRIDGE_UNLOCK(sc); switch (ifs->if_type) { case IFT_ETHER: @@ -1510,13 +1528,18 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, struct bridge_iflist *bif; struct mbuf *mc; int used = 0; + int ss; - BRIDGE_LOCK(sc); - + BRIDGE_RENTER(ss); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { + bif = bridge_try_hold_bif(bif); + if (bif == NULL) + continue; + BRIDGE_REXIT(ss); + dst_if = bif->bif_ifp; if ((dst_if->if_flags & IFF_RUNNING) == 0) - continue; + goto next; /* * If this is not the original output interface, @@ -1530,7 +1553,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, case BSTP_IFSTATE_BLOCKING: case BSTP_IFSTATE_LISTENING: case BSTP_IFSTATE_DISABLED: - continue; + goto next; } } @@ -1541,14 +1564,16 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, mc = m_copym(m, 0, M_COPYALL, M_NOWAIT); if (mc == NULL) { sc->sc_if.if_oerrors++; - continue; + goto next; } } bridge_enqueue(sc, dst_if, mc, 0); +next: + bridge_release_member(sc, bif); + BRIDGE_RENTER(ss); } - - BRIDGE_UNLOCK(sc); + BRIDGE_REXIT(ss); if (used == 0) m_freem(m); @@ -1824,23 +1849,30 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) !bstp_state_before_learning(bif)) { struct bridge_iflist *_bif; struct ifnet *_ifp = NULL; + int s; - BRIDGE_LOCK(sc); + BRIDGE_RENTER(s); LIST_FOREACH(_bif, &sc->sc_iflist, bif_next) { /* It is destined for us. */ if (bridge_ourether(_bif, eh, 0)) { + _bif = bridge_try_hold_bif(_bif); + BRIDGE_REXIT(s); + if (_bif == NULL) + goto out; if (_bif->bif_flags & IFBIF_LEARNING) (void) bridge_rtupdate(sc, eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); _ifp = m->m_pkthdr.rcvif = _bif->bif_ifp; - break; + bridge_release_member(sc, _bif); + goto out; } /* We just received a packet that we sent out. */ if (bridge_ourether(_bif, eh, 1)) break; } - BRIDGE_UNLOCK(sc); + BRIDGE_REXIT(s); +out: if (_bif != NULL) { bridge_release_member(sc, bif); @@ -1892,29 +1924,34 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *mc; struct ifnet *dst_if; bool used, bmcast; + int s; used = bmcast = m->m_flags & (M_BCAST|M_MCAST); - BRIDGE_LOCK(sc); - + BRIDGE_RENTER(s); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { + bif = bridge_try_hold_bif(bif); + if (bif == NULL) + continue; + BRIDGE_REXIT(s); + dst_if = bif->bif_ifp; if (dst_if == src_if) - continue; + goto next; if (bif->bif_flags & IFBIF_STP) { switch (bif->bif_state) { case BSTP_IFSTATE_BLOCKING: case BSTP_IFSTATE_DISABLED: - continue; + goto next; } } if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && !bmcast) - continue; + goto next; if ((dst_if->if_flags & IFF_RUNNING) == 0) - continue; + goto next; if (!used && LIST_NEXT(bif, bif_next) == NULL) { mc = m; @@ -1923,13 +1960,16 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT); if (mc == NULL) { sc->sc_if.if_oerrors++; - continue; + goto next; } } bridge_enqueue(sc, dst_if, mc, 1); +next: + bridge_release_member(sc, bif); + BRIDGE_RENTER(s); } - BRIDGE_UNLOCK(sc); + BRIDGE_REXIT(s); if (bmcast) ether_input(src_if, m); diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h index 46d5b9b..1d3a291 100644 --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -80,6 +80,7 @@ #include #include + /* * Commands used in the SIOCSDRVSPEC ioctl. Note the lookup of the * bridge interface itself is keyed off the ifdrv structure. @@ -207,6 +208,8 @@ struct ifbrparam { #define ifbrp_filter ifbrp_ifbrpu.ifbrpu_int32 /* filtering flags */ #ifdef _KERNEL +#include + #include /* @@ -305,6 +308,8 @@ struct bridge_softc { LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */ kmutex_t *sc_iflist_lock; kcondvar_t sc_iflist_cv; + pserialize_t sc_iflist_psz; + kmutex_t *sc_iflist_psz_lock; LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ kmutex_t *sc_rtlist_lock; @@ -331,12 +336,37 @@ void bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *, #define BRIDGE_MPSAFE 1 #endif -#define BRIDGE_LOCK(_sc) if ((_sc)->sc_iflist_lock) \ +#define BRIDGE_LOCK(_sc) if ((_sc)->sc_iflist_psz_lock) \ + mutex_enter((_sc)->sc_iflist_psz_lock) +#define BRIDGE_UNLOCK(_sc) if ((_sc)->sc_iflist_psz_lock) \ + mutex_exit((_sc)->sc_iflist_psz_lock) +#define BRIDGE_LOCKED(_sc) (!(_sc)->sc_iflist_psz_lock || \ + mutex_owned((_sc)->sc_iflist_psz_lock)) + +#define BRIDGE_INTR_LOCK(_sc) if ((_sc)->sc_iflist_lock) \ mutex_enter((_sc)->sc_iflist_lock) -#define BRIDGE_UNLOCK(_sc) if ((_sc)->sc_iflist_lock) \ +#define BRIDGE_INTR_UNLOCK(_sc) if ((_sc)->sc_iflist_lock) \ mutex_exit((_sc)->sc_iflist_lock) -#define BRIDGE_LOCKED(_sc) (!(_sc)->sc_iflist_lock || \ +#define BRIDGE_INTR_LOCKED(_sc) (!(_sc)->sc_iflist_lock || \ mutex_owned((_sc)->sc_iflist_lock)) +#ifdef BRIDGE_MPSAFE +#define BRIDGE_RENTER(__s) do { \ + if (!cpu_intr_p()) \ + __s = pserialize_read_enter(); \ + else \ + __s = splhigh(); \ + } while (0) +#define BRIDGE_REXIT(__s) do { \ + if (!cpu_intr_p()) \ + pserialize_read_exit(__s); \ + else \ + splx(__s); \ + } while (0) +#else /* BRIDGE_MPSAFE */ +#define BRIDGE_RENTER(__s) do { __s = 0; } while (0) +#define BRIDGE_REXIT(__s) do { (void)__s; } while (0) +#endif /* BRIDGE_MPSAFE */ + #endif /* _KERNEL */ #endif /* !_NET_IF_BRIDGEVAR_H_ */