From 3da0e4ba1fe984e45960cc020f02c1812058663e Mon Sep 17 00:00:00 2001 From: thompsa Date: Sat, 17 Dec 2005 06:33:51 +0000 Subject: Change from a callback in if_ethersubr to using EVENTHANDLER in order to detach span ports when they disappear. The span port does not have a pointer to the softc so revert r1.31 and bring back the softc linked-list. MFC after: 2 weeks --- sys/net/if_bridge.c | 79 +++++++++++++++++++++++++++++++++++++++++--------- sys/net/if_bridgevar.h | 2 +- sys/net/if_ethersubr.c | 7 ----- 3 files changed, 67 insertions(+), 21 deletions(-) (limited to 'sys/net') diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index c063b91..e82cfd1 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -170,6 +170,9 @@ __FBSDID("$FreeBSD$"); #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) #endif +static struct mtx bridge_list_mtx; +eventhandler_tag bridge_detach_cookie = NULL; + int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; uma_zone_t bridge_rtnode_zone; @@ -178,7 +181,7 @@ static int bridge_clone_create(struct if_clone *, int); static void bridge_clone_destroy(struct ifnet *); static int bridge_ioctl(struct ifnet *, u_long, caddr_t); -static void bridge_ifdetach(struct ifnet *); +static void bridge_ifdetach(void *arg __unused, struct ifnet *); static void bridge_init(void *); static void bridge_dummynet(struct mbuf *, struct ifnet *); static void bridge_stop(struct ifnet *, int); @@ -219,6 +222,8 @@ static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, struct ifnet *ifp); static void bridge_delete_member(struct bridge_softc *, struct bridge_iflist *, int); +static void bridge_delete_span(struct bridge_softc *, + struct bridge_iflist *); static int bridge_ioctl_add(struct bridge_softc *, void *); static int bridge_ioctl_del(struct bridge_softc *, void *); @@ -345,6 +350,8 @@ const int bridge_control_table_size = static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +LIST_HEAD(, bridge_softc) bridge_list; + IFC_SIMPLE_DECLARE(bridge, 0); static int @@ -353,24 +360,30 @@ bridge_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: + mtx_init(&bridge_list_mtx, "if_bridge list", NULL, MTX_DEF); if_clone_attach(&bridge_cloner); bridge_rtnode_zone = uma_zcreate("bridge_rtnode", sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + LIST_INIT(&bridge_list); bridge_input_p = bridge_input; bridge_output_p = bridge_output; bridge_dn_p = bridge_dummynet; - bridge_detach_p = bridge_ifdetach; bstp_linkstate_p = bstp_linkstate; + bridge_detach_cookie = EVENTHANDLER_REGISTER( + ifnet_departure_event, bridge_ifdetach, NULL, + EVENTHANDLER_PRI_ANY); break; case MOD_UNLOAD: + EVENTHANDLER_DEREGISTER(ifnet_departure_event, + bridge_detach_cookie); if_clone_detach(&bridge_cloner); uma_zdestroy(bridge_rtnode_zone); bridge_input_p = NULL; bridge_output_p = NULL; bridge_dn_p = NULL; - bridge_detach_p = NULL; bstp_linkstate_p = NULL; + mtx_destroy(&bridge_list_mtx); break; default: return EOPNOTSUPP; @@ -481,6 +494,10 @@ bridge_clone_create(struct if_clone *ifc, int unit) ifp->if_baudrate = 0; ifp->if_type = IFT_BRIDGE; + mtx_lock(&bridge_list_mtx); + LIST_INSERT_HEAD(&bridge_list, sc, sc_list); + mtx_unlock(&bridge_list_mtx); + return (0); } @@ -504,8 +521,7 @@ bridge_clone_destroy(struct ifnet *ifp) bridge_delete_member(sc, bif, 0); while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) { - LIST_REMOVE(bif, bif_next); - free(bif, M_DEVBUF); + bridge_delete_span(sc, bif); } BRIDGE_UNLOCK(sc); @@ -513,6 +529,10 @@ bridge_clone_destroy(struct ifnet *ifp) callout_drain(&sc->sc_brcallout); callout_drain(&sc->sc_bstpcallout); + mtx_lock(&bridge_list_mtx); + LIST_REMOVE(sc, sc_list); + mtx_unlock(&bridge_list_mtx); + ether_ifdetach(ifp); if_free_type(ifp, IFT_ETHER); @@ -724,6 +744,23 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, bstp_initialization(sc); } +/* + * bridge_delete_span: + * + * Delete the specified span interface. + */ +static void +bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif) +{ + BRIDGE_LOCK_ASSERT(sc); + + KASSERT(bif->bif_ifp->if_bridge == NULL, + ("%s: not a span interface", __func__)); + + LIST_REMOVE(bif, bif_next); + free(bif, M_DEVBUF); +} + static int bridge_ioctl_add(struct bridge_softc *sc, void *arg) { @@ -1285,8 +1322,7 @@ bridge_ioctl_delspan(struct bridge_softc *sc, void *arg) if (bif == NULL) return (ENOENT); - LIST_REMOVE(bif, bif_next); - free(bif, M_DEVBUF); + bridge_delete_span(sc, bif); return (0); } @@ -1298,20 +1334,37 @@ bridge_ioctl_delspan(struct bridge_softc *sc, void *arg) * interface is detaching. */ static void -bridge_ifdetach(struct ifnet *ifp) +bridge_ifdetach(void *arg __unused, struct ifnet *ifp) { struct bridge_softc *sc = ifp->if_bridge; struct bridge_iflist *bif; - BRIDGE_LOCK(sc); + /* Check if the interface is a bridge member */ + if (sc != NULL) { + BRIDGE_LOCK(sc); - bif = bridge_lookup_member_if(sc, ifp); - if (bif == NULL) + bif = bridge_lookup_member_if(sc, ifp); + if (bif != NULL) + bridge_delete_member(sc, bif, 1); + + + BRIDGE_UNLOCK(sc); return; + } - bridge_delete_member(sc, bif, 1); + /* Check if the interface is a span port */ + mtx_lock(&bridge_list_mtx); + LIST_FOREACH(sc, &bridge_list, sc_list) { + BRIDGE_LOCK(sc); + LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) + if (ifp == bif->bif_ifp) { + bridge_delete_span(sc, bif); + break; + } - BRIDGE_UNLOCK(sc); + BRIDGE_UNLOCK(sc); + } + mtx_unlock(&bridge_list_mtx); } /* diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h index 7ec672a..7d07b01 100644 --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -267,6 +267,7 @@ struct bridge_rtnode { */ struct bridge_softc { struct ifnet *sc_ifp; /* make this an interface */ + LIST_ENTRY(bridge_softc) sc_list; struct mtx sc_mtx; struct cv sc_cv; uint64_t sc_designated_root; @@ -362,7 +363,6 @@ extern struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); extern int (*bridge_output_p)(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *); -extern void (*bridge_detach_p)(struct ifnet *); extern void (*bstp_linkstate_p)(struct ifnet *ifp, int state); void bstp_initialization(struct bridge_softc *); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index f7f1e84..2d89cee 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -111,7 +111,6 @@ struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); int (*bridge_output_p)(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); void (*bridge_dn_p)(struct mbuf *, struct ifnet *); -void (*bridge_detach_p)(struct ifnet *ifp); static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -899,12 +898,6 @@ ether_ifdetach(struct ifnet *ifp) (*ng_ether_detach_p)(ifp); } - if (ifp->if_bridge) { - KASSERT(bridge_detach_p != NULL, - ("bridge_detach_p is NULL")); - (*bridge_detach_p)(ifp); - } - bpfdetach(ifp); if_detach(ifp); } -- cgit v1.1