Changeset View
Changeset View
Standalone View
Standalone View
head/sys/net/if_bridge.c
Show First 20 Lines • Show All 229 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
VNET_DEFINE_STATIC(struct mtx, bridge_list_mtx); | VNET_DEFINE_STATIC(struct mtx, bridge_list_mtx); | ||||
#define V_bridge_list_mtx VNET(bridge_list_mtx) | #define V_bridge_list_mtx VNET(bridge_list_mtx) | ||||
static eventhandler_tag bridge_detach_cookie; | static eventhandler_tag bridge_detach_cookie; | ||||
int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; | int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; | ||||
uma_zone_t bridge_rtnode_zone; | VNET_DEFINE_STATIC(uma_zone_t, bridge_rtnode_zone); | ||||
#define V_bridge_rtnode_zone VNET(bridge_rtnode_zone) | |||||
static int bridge_clone_create(struct if_clone *, int, caddr_t); | static int bridge_clone_create(struct if_clone *, int, caddr_t); | ||||
static void bridge_clone_destroy(struct ifnet *); | static void bridge_clone_destroy(struct ifnet *); | ||||
static int bridge_ioctl(struct ifnet *, u_long, caddr_t); | static int bridge_ioctl(struct ifnet *, u_long, caddr_t); | ||||
static void bridge_mutecaps(struct bridge_softc *); | static void bridge_mutecaps(struct bridge_softc *); | ||||
static void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *, | static void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *, | ||||
int); | int); | ||||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 Lines | |||||
#define V_bridge_cloner VNET(bridge_cloner) | #define V_bridge_cloner VNET(bridge_cloner) | ||||
static const char bridge_name[] = "bridge"; | static const char bridge_name[] = "bridge"; | ||||
static void | static void | ||||
vnet_bridge_init(const void *unused __unused) | vnet_bridge_init(const void *unused __unused) | ||||
{ | { | ||||
V_bridge_rtnode_zone = uma_zcreate("bridge_rtnode", | |||||
sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, | |||||
UMA_ALIGN_PTR, 0); | |||||
BRIDGE_LIST_LOCK_INIT(); | BRIDGE_LIST_LOCK_INIT(); | ||||
LIST_INIT(&V_bridge_list); | LIST_INIT(&V_bridge_list); | ||||
V_bridge_cloner = if_clone_simple(bridge_name, | V_bridge_cloner = if_clone_simple(bridge_name, | ||||
bridge_clone_create, bridge_clone_destroy, 0); | bridge_clone_create, bridge_clone_destroy, 0); | ||||
} | } | ||||
VNET_SYSINIT(vnet_bridge_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, | VNET_SYSINIT(vnet_bridge_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, | ||||
vnet_bridge_init, NULL); | vnet_bridge_init, NULL); | ||||
static void | static void | ||||
vnet_bridge_uninit(const void *unused __unused) | vnet_bridge_uninit(const void *unused __unused) | ||||
{ | { | ||||
if_clone_detach(V_bridge_cloner); | if_clone_detach(V_bridge_cloner); | ||||
V_bridge_cloner = NULL; | V_bridge_cloner = NULL; | ||||
BRIDGE_LIST_LOCK_DESTROY(); | BRIDGE_LIST_LOCK_DESTROY(); | ||||
uma_zdestroy(V_bridge_rtnode_zone); | |||||
} | } | ||||
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, | VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, | ||||
vnet_bridge_uninit, NULL); | vnet_bridge_uninit, NULL); | ||||
static int | static int | ||||
bridge_modevent(module_t mod, int type, void *data) | bridge_modevent(module_t mod, int type, void *data) | ||||
{ | { | ||||
switch (type) { | switch (type) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
bridge_rtnode_zone = uma_zcreate("bridge_rtnode", | |||||
sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, | |||||
UMA_ALIGN_PTR, 0); | |||||
bridge_dn_p = bridge_dummynet; | bridge_dn_p = bridge_dummynet; | ||||
bridge_detach_cookie = EVENTHANDLER_REGISTER( | bridge_detach_cookie = EVENTHANDLER_REGISTER( | ||||
ifnet_departure_event, bridge_ifdetach, NULL, | ifnet_departure_event, bridge_ifdetach, NULL, | ||||
EVENTHANDLER_PRI_ANY); | EVENTHANDLER_PRI_ANY); | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event, | EVENTHANDLER_DEREGISTER(ifnet_departure_event, | ||||
bridge_detach_cookie); | bridge_detach_cookie); | ||||
uma_zdestroy(bridge_rtnode_zone); | |||||
bridge_dn_p = NULL; | bridge_dn_p = NULL; | ||||
break; | break; | ||||
default: | default: | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | bridge_clone_destroy(struct ifnet *ifp) | ||||
while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) | while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) | ||||
bridge_delete_member(sc, bif, 0); | bridge_delete_member(sc, bif, 0); | ||||
while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) { | while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) { | ||||
bridge_delete_span(sc, bif); | bridge_delete_span(sc, bif); | ||||
} | } | ||||
/* Tear down the routing table. */ | |||||
bridge_rtable_fini(sc); | |||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
callout_drain(&sc->sc_brcallout); | callout_drain(&sc->sc_brcallout); | ||||
BRIDGE_LIST_LOCK(); | BRIDGE_LIST_LOCK(); | ||||
LIST_REMOVE(sc, sc_list); | LIST_REMOVE(sc, sc_list); | ||||
BRIDGE_LIST_UNLOCK(); | BRIDGE_LIST_UNLOCK(); | ||||
bstp_detach(&sc->sc_stp); | bstp_detach(&sc->sc_stp); | ||||
ether_ifdetach(ifp); | ether_ifdetach(ifp); | ||||
if_free(ifp); | if_free(ifp); | ||||
/* Tear down the routing table. */ | |||||
bridge_rtable_fini(sc); | |||||
BRIDGE_LOCK_DESTROY(sc); | BRIDGE_LOCK_DESTROY(sc); | ||||
free(sc, M_DEVBUF); | free(sc, M_DEVBUF); | ||||
} | } | ||||
/* | /* | ||||
* bridge_ioctl: | * bridge_ioctl: | ||||
* | * | ||||
* Handle a control request from the operator. | * Handle a control request from the operator. | ||||
▲ Show 20 Lines • Show All 1,908 Lines • ▼ Show 20 Lines | if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) { | ||||
return (ENOSPC); | return (ENOSPC); | ||||
} | } | ||||
/* | /* | ||||
* Allocate a new bridge forwarding node, and | * Allocate a new bridge forwarding node, and | ||||
* initialize the expiration time and Ethernet | * initialize the expiration time and Ethernet | ||||
* address. | * address. | ||||
*/ | */ | ||||
brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO); | brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO); | ||||
if (brt == NULL) | if (brt == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
if (bif->bif_flags & IFBIF_STICKY) | if (bif->bif_flags & IFBIF_STICKY) | ||||
brt->brt_flags = IFBAF_STICKY; | brt->brt_flags = IFBAF_STICKY; | ||||
else | else | ||||
brt->brt_flags = IFBAF_DYNAMIC; | brt->brt_flags = IFBAF_DYNAMIC; | ||||
memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); | memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); | ||||
brt->brt_vlan = vlan; | brt->brt_vlan = vlan; | ||||
if ((error = bridge_rtnode_insert(sc, brt)) != 0) { | if ((error = bridge_rtnode_insert(sc, brt)) != 0) { | ||||
uma_zfree(bridge_rtnode_zone, brt); | uma_zfree(V_bridge_rtnode_zone, brt); | ||||
return (error); | return (error); | ||||
} | } | ||||
brt->brt_dst = bif; | brt->brt_dst = bif; | ||||
bif->bif_addrcnt++; | bif->bif_addrcnt++; | ||||
} | } | ||||
if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && | ||||
brt->brt_dst != bif) { | brt->brt_dst != bif) { | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
bridge_timer(void *arg) | bridge_timer(void *arg) | ||||
{ | { | ||||
struct bridge_softc *sc = arg; | struct bridge_softc *sc = arg; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
/* Destruction of rtnodes requires a proper vnet context */ | |||||
CURVNET_SET(sc->sc_ifp->if_vnet); | |||||
bridge_rtage(sc); | bridge_rtage(sc); | ||||
if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) | if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
callout_reset(&sc->sc_brcallout, | callout_reset(&sc->sc_brcallout, | ||||
bridge_rtable_prune_period * hz, bridge_timer, sc); | bridge_rtable_prune_period * hz, bridge_timer, sc); | ||||
CURVNET_RESTORE(); | |||||
} | } | ||||
/* | /* | ||||
* bridge_rtage: | * bridge_rtage: | ||||
* | * | ||||
* Perform an aging cycle. | * Perform an aging cycle. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | |||||
* Deconstruct the route table for this bridge. | * Deconstruct the route table for this bridge. | ||||
*/ | */ | ||||
static void | static void | ||||
bridge_rtable_fini(struct bridge_softc *sc) | bridge_rtable_fini(struct bridge_softc *sc) | ||||
{ | { | ||||
KASSERT(sc->sc_brtcnt == 0, | KASSERT(sc->sc_brtcnt == 0, | ||||
("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt)); | ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt)); | ||||
bridge_rtflush(sc, 1); | |||||
free(sc->sc_rthash, M_DEVBUF); | free(sc->sc_rthash, M_DEVBUF); | ||||
} | } | ||||
/* | /* | ||||
* The following hash function is adapted from "Hash Functions" by Bob Jenkins | * The following hash function is adapted from "Hash Functions" by Bob Jenkins | ||||
* ("Algorithm Alley", Dr. Dobbs Journal, September 1997). | * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). | ||||
*/ | */ | ||||
#define mix(a, b, c) \ | #define mix(a, b, c) \ | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
LIST_REMOVE(brt, brt_hash); | LIST_REMOVE(brt, brt_hash); | ||||
LIST_REMOVE(brt, brt_list); | LIST_REMOVE(brt, brt_list); | ||||
sc->sc_brtcnt--; | sc->sc_brtcnt--; | ||||
brt->brt_dst->bif_addrcnt--; | brt->brt_dst->bif_addrcnt--; | ||||
uma_zfree(bridge_rtnode_zone, brt); | uma_zfree(V_bridge_rtnode_zone, brt); | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtable_expire: | * bridge_rtable_expire: | ||||
* | * | ||||
* Set the expiry time for all routes on an interface. | * Set the expiry time for all routes on an interface. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 565 Lines • Show Last 20 Lines |