Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_bridge.c
Show First 20 Lines • Show All 772 Lines • ▼ Show 20 Lines | union { | ||||
struct ifbareq ifbareq; | struct ifbareq ifbareq; | ||||
struct ifbaconf ifbaconf; | struct ifbaconf ifbaconf; | ||||
struct ifbrparam ifbrparam; | struct ifbrparam ifbrparam; | ||||
struct ifbropreq ifbropreq; | struct ifbropreq ifbropreq; | ||||
} args; | } args; | ||||
struct ifdrv *ifd = (struct ifdrv *) data; | struct ifdrv *ifd = (struct ifdrv *) data; | ||||
const struct bridge_control *bc; | const struct bridge_control *bc; | ||||
int error = 0, oldmtu; | int error = 0, oldmtu; | ||||
struct epoch_tracker et; | |||||
NET_EPOCH_ENTER(et); | |||||
switch (cmd) { | switch (cmd) { | ||||
case SIOCADDMULTI: | case SIOCADDMULTI: | ||||
case SIOCDELMULTI: | case SIOCDELMULTI: | ||||
break; | break; | ||||
case SIOCGDRVSPEC: | case SIOCGDRVSPEC: | ||||
case SIOCSDRVSPEC: | case SIOCSDRVSPEC: | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | default: | ||||
/* | /* | ||||
* drop the lock as ether_ioctl() will call bridge_start() and | * drop the lock as ether_ioctl() will call bridge_start() and | ||||
* cause the lock to be recursed. | * cause the lock to be recursed. | ||||
*/ | */ | ||||
error = ether_ioctl(ifp, cmd, data); | error = ether_ioctl(ifp, cmd, data); | ||||
break; | break; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* bridge_mutecaps: | * bridge_mutecaps: | ||||
* | * | ||||
* Clear or restore unwanted capabilities on the member interface | * Clear or restore unwanted capabilities on the member interface | ||||
Show All 15 Lines | bridge_mutecaps(struct bridge_softc *sc) | ||||
} | } | ||||
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
enabled = bif->bif_ifp->if_capenable; | enabled = bif->bif_ifp->if_capenable; | ||||
enabled &= ~BRIDGE_IFCAPS_STRIP; | enabled &= ~BRIDGE_IFCAPS_STRIP; | ||||
/* strip off mask bits and enable them again if allowed */ | /* strip off mask bits and enable them again if allowed */ | ||||
enabled &= ~BRIDGE_IFCAPS_MASK; | enabled &= ~BRIDGE_IFCAPS_MASK; | ||||
enabled |= mask; | enabled |= mask; | ||||
BRIDGE_UNLOCK(sc); | |||||
bridge_set_ifcap(sc, bif, enabled); | bridge_set_ifcap(sc, bif, enabled); | ||||
BRIDGE_LOCK(sc); | |||||
} | } | ||||
} | } | ||||
static void | static void | ||||
bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set) | bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set) | ||||
{ | { | ||||
struct ifnet *ifp = bif->bif_ifp; | struct ifnet *ifp = bif->bif_ifp; | ||||
struct ifreq ifr; | struct ifreq ifr; | ||||
int error, mask, stuck; | int error, mask, stuck; | ||||
BRIDGE_UNLOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
bzero(&ifr, sizeof(ifr)); | bzero(&ifr, sizeof(ifr)); | ||||
ifr.ifr_reqcap = set; | ifr.ifr_reqcap = set; | ||||
if (ifp->if_capenable != set) { | if (ifp->if_capenable != set) { | ||||
MPASS(! in_epoch(net_epoch_preempt)); | |||||
error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); | error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); | ||||
if (error) | if (error) | ||||
if_printf(sc->sc_ifp, | if_printf(sc->sc_ifp, | ||||
"error setting capabilities on %s: %d\n", | "error setting capabilities on %s: %d\n", | ||||
ifp->if_xname, error); | ifp->if_xname, error); | ||||
mask = BRIDGE_IFCAPS_MASK | BRIDGE_IFCAPS_STRIP; | mask = BRIDGE_IFCAPS_MASK | BRIDGE_IFCAPS_STRIP; | ||||
stuck = ifp->if_capenable & mask & ~set; | stuck = ifp->if_capenable & mask & ~set; | ||||
if (stuck != 0) | if (stuck != 0) | ||||
Show All 9 Lines | |||||
* Lookup a bridge member interface. | * Lookup a bridge member interface. | ||||
*/ | */ | ||||
static struct bridge_iflist * | static struct bridge_iflist * | ||||
bridge_lookup_member(struct bridge_softc *sc, const char *name) | bridge_lookup_member(struct bridge_softc *sc, const char *name) | ||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
NET_EPOCH_ASSERT(); | MPASS(in_epoch(net_epoch_preempt) || mtx_owned(&sc->sc_mtx)); | ||||
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
ifp = bif->bif_ifp; | ifp = bif->bif_ifp; | ||||
if (strcmp(ifp->if_xname, name) == 0) | if (strcmp(ifp->if_xname, name) == 0) | ||||
return (bif); | return (bif); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* bridge_lookup_member_if: | * bridge_lookup_member_if: | ||||
* | * | ||||
* Lookup a bridge member interface by ifnet*. | * Lookup a bridge member interface by ifnet*. | ||||
*/ | */ | ||||
static struct bridge_iflist * | static struct bridge_iflist * | ||||
bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) | bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) | ||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
NET_EPOCH_ASSERT(); | MPASS(in_epoch(net_epoch_preempt) || mtx_owned(&sc->sc_mtx)); | ||||
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if (bif->bif_ifp == member_ifp) | if (bif->bif_ifp == member_ifp) | ||||
return (bif); | return (bif); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static void | static void | ||||
bridge_delete_member_cb(struct epoch_context *ctx) | bridge_delete_member_cb(struct epoch_context *ctx) | ||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
bif = __containerof(ctx, struct bridge_iflist, bif_epoch_ctx); | bif = __containerof(ctx, struct bridge_iflist, bif_epoch_ctx); | ||||
if (bif->bif_flags & IFBIF_STP) | |||||
bstp_destroy(&bif->bif_stp); /* prepare to free */ | |||||
free(bif, M_DEVBUF); | free(bif, M_DEVBUF); | ||||
} | } | ||||
/* | /* | ||||
* bridge_delete_member: | * bridge_delete_member: | ||||
* | * | ||||
* Delete the specified member interface. | * Delete the specified member interface. | ||||
*/ | */ | ||||
Show All 37 Lines | bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, | ||||
bridge_mutecaps(sc); /* recalcuate now this interface is removed */ | bridge_mutecaps(sc); /* recalcuate now this interface is removed */ | ||||
bridge_rtdelete(sc, ifs, IFBF_FLUSHALL); | bridge_rtdelete(sc, ifs, IFBF_FLUSHALL); | ||||
KASSERT(bif->bif_addrcnt == 0, | KASSERT(bif->bif_addrcnt == 0, | ||||
("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt)); | ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt)); | ||||
ifs->if_bridge_output = NULL; | ifs->if_bridge_output = NULL; | ||||
ifs->if_bridge_input = NULL; | ifs->if_bridge_input = NULL; | ||||
ifs->if_bridge_linkstate = NULL; | ifs->if_bridge_linkstate = NULL; | ||||
BRIDGE_UNLOCK(sc); | |||||
if (!gone) { | if (!gone) { | ||||
switch (ifs->if_type) { | switch (ifs->if_type) { | ||||
case IFT_ETHER: | case IFT_ETHER: | ||||
case IFT_L2VLAN: | case IFT_L2VLAN: | ||||
/* | /* | ||||
* Take the interface out of promiscuous mode, but only | * Take the interface out of promiscuous mode, but only | ||||
* if it was promiscuous in the first place. It might | * if it was promiscuous in the first place. It might | ||||
* not be if we're in the bridge_ioctl_add() error path. | * not be if we're in the bridge_ioctl_add() error path. | ||||
Show All 9 Lines | |||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
panic("bridge_delete_member: impossible"); | panic("bridge_delete_member: impossible"); | ||||
#endif | #endif | ||||
break; | break; | ||||
} | } | ||||
/* reneable any interface capabilities */ | /* reneable any interface capabilities */ | ||||
bridge_set_ifcap(sc, bif, bif->bif_savedcaps); | bridge_set_ifcap(sc, bif, bif->bif_savedcaps); | ||||
} | } | ||||
bstp_destroy(&bif->bif_stp); /* prepare to free */ | |||||
BRIDGE_LOCK(sc); | |||||
NET_EPOCH_CALL(bridge_delete_member_cb, &bif->bif_epoch_ctx); | NET_EPOCH_CALL(bridge_delete_member_cb, &bif->bif_epoch_ctx); | ||||
} | } | ||||
/* | /* | ||||
* bridge_delete_span: | * bridge_delete_span: | ||||
* | * | ||||
* Delete the specified span interface. | * Delete the specified span interface. | ||||
▲ Show 20 Lines • Show All 380 Lines • ▼ Show 20 Lines | out: | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
free(outbuf, M_TEMP); | free(outbuf, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) | bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifbareq *req = arg; | struct ifbareq *req = arg; | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
int error; | int error; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ENTER(et); | ||||
BRIDGE_LOCK_ASSERT(sc); | |||||
bif = bridge_lookup_member(sc, req->ifba_ifsname); | bif = bridge_lookup_member(sc, req->ifba_ifsname); | ||||
if (bif == NULL) | if (bif == NULL) { | ||||
NET_EPOCH_EXIT(et); | |||||
return (ENOENT); | return (ENOENT); | ||||
} | |||||
/* bridge_rtupdate() may acquire the lock. */ | /* bridge_rtupdate() may acquire the lock. */ | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1, | error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1, | ||||
req->ifba_flags); | req->ifba_flags); | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
NET_EPOCH_EXIT(et); | |||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_sto(struct bridge_softc *sc, void *arg) | bridge_ioctl_sto(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct ifbrparam *param = arg; | struct ifbrparam *param = arg; | ||||
sc->sc_brttimeout = param->ifbrp_ctime; | sc->sc_brttimeout = param->ifbrp_ctime; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_gto(struct bridge_softc *sc, void *arg) | bridge_ioctl_gto(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct ifbrparam *param = arg; | struct ifbrparam *param = arg; | ||||
param->ifbrp_ctime = sc->sc_brttimeout; | param->ifbrp_ctime = sc->sc_brttimeout; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_daddr(struct bridge_softc *sc, void *arg) | bridge_ioctl_daddr(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifbareq *req = arg; | struct ifbareq *req = arg; | ||||
int ret; | |||||
return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan)); | NET_EPOCH_ENTER(et); | ||||
ret = bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan); | |||||
NET_EPOCH_EXIT(et); | |||||
return (ret); | |||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_flush(struct bridge_softc *sc, void *arg) | bridge_ioctl_flush(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct ifbreq *req = arg; | struct ifbreq *req = arg; | ||||
bridge_rtflush(sc, req->ifbr_ifsflags); | bridge_rtflush(sc, req->ifbr_ifsflags); | ||||
▲ Show 20 Lines • Show All 2,107 Lines • ▼ Show 20 Lines | bridge_linkstate(struct ifnet *ifp) | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
static void | static void | ||||
bridge_linkcheck(struct bridge_softc *sc) | bridge_linkcheck(struct bridge_softc *sc) | ||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
int new_link, hasls; | int new_link, hasls; | ||||
NET_EPOCH_ASSERT(); | |||||
new_link = LINK_STATE_DOWN; | new_link = LINK_STATE_DOWN; | ||||
hasls = 0; | hasls = 0; | ||||
/* Our link is considered up if at least one of our ports is active */ | /* Our link is considered up if at least one of our ports is active */ | ||||
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE) | if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE) | ||||
hasls++; | hasls++; | ||||
if (bif->bif_ifp->if_link_state == LINK_STATE_UP) { | if (bif->bif_ifp->if_link_state == LINK_STATE_UP) { | ||||
Show All 10 Lines |