Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_bridge.c
Show First 20 Lines • Show All 599 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
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(); | ||||
/* Before we can destroy the uma zone, because there are callbacks that | /* Before we can destroy the uma zone, because there are callbacks that | ||||
* use it. */ | * use it. */ | ||||
NET_EPOCH_WAIT(); | epoch_drain_callbacks(net_epoch_preempt); | ||||
uma_zdestroy(V_bridge_rtnode_zone); | 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) | ||||
▲ Show 20 Lines • Show All 845 Lines • ▼ Show 20 Lines | bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) | ||||
CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | ||||
count++; | count++; | ||||
buflen = sizeof(breq) * count; | buflen = sizeof(breq) * count; | ||||
if (bifc->ifbic_len == 0) { | if (bifc->ifbic_len == 0) { | ||||
bifc->ifbic_len = buflen; | bifc->ifbic_len = buflen; | ||||
return (0); | return (0); | ||||
} | } | ||||
BRIDGE_UNLOCK(sc); | outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); | ||||
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | if (outbuf == NULL) | ||||
BRIDGE_LOCK(sc); | return (ENOMEM); | ||||
count = 0; | count = 0; | ||||
buf = outbuf; | buf = outbuf; | ||||
len = min(bifc->ifbic_len, buflen); | len = min(bifc->ifbic_len, buflen); | ||||
bzero(&breq, sizeof(breq)); | bzero(&breq, sizeof(breq)); | ||||
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if (len < sizeof(breq)) | if (len < sizeof(breq)) | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | bridge_ioctl_rts(struct bridge_softc *sc, void *arg) | ||||
if (bac->ifbac_len == 0) | if (bac->ifbac_len == 0) | ||||
return (0); | return (0); | ||||
count = 0; | count = 0; | ||||
CK_LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) | CK_LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) | ||||
count++; | count++; | ||||
buflen = sizeof(bareq) * count; | buflen = sizeof(bareq) * count; | ||||
BRIDGE_UNLOCK(sc); | outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); | ||||
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | if (outbuf == NULL) | ||||
BRIDGE_LOCK(sc); | return (ENOMEM); | ||||
count = 0; | count = 0; | ||||
buf = outbuf; | buf = outbuf; | ||||
len = min(bac->ifbac_len, buflen); | len = min(bac->ifbac_len, buflen); | ||||
bzero(&bareq, sizeof(bareq)); | bzero(&bareq, sizeof(bareq)); | ||||
CK_LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { | CK_LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { | ||||
if (len < sizeof(bareq)) | if (len < sizeof(bareq)) | ||||
goto out; | goto out; | ||||
▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | bridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg) | ||||
} | } | ||||
buflen = sizeof(bpreq) * count; | buflen = sizeof(bpreq) * count; | ||||
if (bifstp->ifbpstp_len == 0) { | if (bifstp->ifbpstp_len == 0) { | ||||
bifstp->ifbpstp_len = buflen; | bifstp->ifbpstp_len = buflen; | ||||
return (0); | return (0); | ||||
} | } | ||||
BRIDGE_UNLOCK(sc); | outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); | ||||
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | if (outbuf == NULL) | ||||
BRIDGE_LOCK(sc); | return (ENOMEM); | ||||
count = 0; | count = 0; | ||||
buf = outbuf; | buf = outbuf; | ||||
len = min(bifstp->ifbpstp_len, buflen); | len = min(bifstp->ifbpstp_len, buflen); | ||||
bzero(&bpreq, sizeof(bpreq)); | bzero(&bpreq, sizeof(bpreq)); | ||||
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if (len < sizeof(bpreq)) | if (len < sizeof(bpreq)) | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* The mbuf has the Ethernet header already attached. We must | * The mbuf has the Ethernet header already attached. We must | ||||
* enqueue or free the mbuf before returning. | * enqueue or free the mbuf before returning. | ||||
*/ | */ | ||||
static int | static int | ||||
bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, | bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, | ||||
struct rtentry *rt) | struct rtentry *rt) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ether_header *eh; | struct ether_header *eh; | ||||
struct ifnet *dst_if; | struct ifnet *dst_if; | ||||
struct bridge_softc *sc; | struct bridge_softc *sc; | ||||
uint16_t vlan; | uint16_t vlan; | ||||
MPASS(in_epoch(net_epoch_preempt)); | NET_EPOCH_ENTER_ET(et); | ||||
if (m->m_len < ETHER_HDR_LEN) { | if (m->m_len < ETHER_HDR_LEN) { | ||||
m = m_pullup(m, ETHER_HDR_LEN); | m = m_pullup(m, ETHER_HDR_LEN); | ||||
if (m == NULL) | if (m == NULL) { | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (0); | return (0); | ||||
} | } | ||||
} | |||||
eh = mtod(m, struct ether_header *); | eh = mtod(m, struct ether_header *); | ||||
sc = ifp->if_bridge; | sc = ifp->if_bridge; | ||||
vlan = VLANTAGOF(m); | vlan = VLANTAGOF(m); | ||||
/* | /* | ||||
* If bridge is down, but the original output interface is up, | * If bridge is down, but the original output interface is up, | ||||
* go ahead and send out that interface. Otherwise, the packet | * go ahead and send out that interface. Otherwise, the packet | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
bridge_enqueue(sc, dst_if, mc); | bridge_enqueue(sc, dst_if, mc); | ||||
} | } | ||||
if (used == 0) | if (used == 0) | ||||
m_freem(m); | m_freem(m); | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (0); | return (0); | ||||
} | } | ||||
sendunicast: | sendunicast: | ||||
/* | /* | ||||
* XXX Spanning tree consideration here? | * XXX Spanning tree consideration here? | ||||
*/ | */ | ||||
bridge_span(sc, m); | bridge_span(sc, m); | ||||
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) { | ||||
m_freem(m); | m_freem(m); | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (0); | return (0); | ||||
} | } | ||||
bridge_enqueue(sc, dst_if, m); | bridge_enqueue(sc, dst_if, m); | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* bridge_transmit: | * bridge_transmit: | ||||
* | * | ||||
* Do output on a bridge. | * Do output on a bridge. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 180 Lines • ▼ Show 20 Lines | |||||
* bridge_input: | * bridge_input: | ||||
* | * | ||||
* Receive input from a member interface. Queue the packet for | * Receive input from a member interface. Queue the packet for | ||||
* bridging if it is not for us. | * bridging if it is not for us. | ||||
*/ | */ | ||||
static struct mbuf * | static struct mbuf * | ||||
bridge_input(struct ifnet *ifp, struct mbuf *m) | bridge_input(struct ifnet *ifp, struct mbuf *m) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct bridge_softc *sc = ifp->if_bridge; | struct bridge_softc *sc = ifp->if_bridge; | ||||
struct bridge_iflist *bif, *bif2; | struct bridge_iflist *bif, *bif2; | ||||
struct ifnet *bifp; | struct ifnet *bifp; | ||||
struct ether_header *eh; | struct ether_header *eh; | ||||
struct mbuf *mc, *mc2; | struct mbuf *mc, *mc2; | ||||
uint16_t vlan; | uint16_t vlan; | ||||
int error; | int error; | ||||
MPASS(in_epoch(net_epoch_preempt)); | NET_EPOCH_ENTER_ET(et); | ||||
if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (m); | return (m); | ||||
} | |||||
bifp = sc->sc_ifp; | bifp = sc->sc_ifp; | ||||
vlan = VLANTAGOF(m); | vlan = VLANTAGOF(m); | ||||
/* | /* | ||||
* Implement support for bridge monitoring. If this flag has been | * Implement support for bridge monitoring. If this flag has been | ||||
* set on this interface, discard the packet once we push it through | * set on this interface, discard the packet once we push it through | ||||
* the bpf(4) machinery, but before we do, increment the byte and | * the bpf(4) machinery, but before we do, increment the byte and | ||||
* packet counters associated with this interface. | * packet counters associated with this interface. | ||||
*/ | */ | ||||
if ((bifp->if_flags & IFF_MONITOR) != 0) { | if ((bifp->if_flags & IFF_MONITOR) != 0) { | ||||
m->m_pkthdr.rcvif = bifp; | m->m_pkthdr.rcvif = bifp; | ||||
ETHER_BPF_MTAP(bifp, m); | ETHER_BPF_MTAP(bifp, m); | ||||
if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); | ||||
if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); | if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); | ||||
m_freem(m); | m_freem(m); | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (NULL); | return (NULL); | ||||
} | } | ||||
bif = bridge_lookup_member_if(sc, ifp); | bif = bridge_lookup_member_if(sc, ifp); | ||||
if (bif == NULL) { | if (bif == NULL) { | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (m); | return (m); | ||||
} | } | ||||
eh = mtod(m, struct ether_header *); | eh = mtod(m, struct ether_header *); | ||||
bridge_span(sc, m); | bridge_span(sc, m); | ||||
if (m->m_flags & (M_BCAST|M_MCAST)) { | if (m->m_flags & (M_BCAST|M_MCAST)) { | ||||
/* Tap off 802.1D packets; they do not get forwarded. */ | /* Tap off 802.1D packets; they do not get forwarded. */ | ||||
if (memcmp(eh->ether_dhost, bstp_etheraddr, | if (memcmp(eh->ether_dhost, bstp_etheraddr, | ||||
ETHER_ADDR_LEN) == 0) { | ETHER_ADDR_LEN) == 0) { | ||||
bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */ | bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */ | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if ((bif->bif_flags & IFBIF_STP) && | if ((bif->bif_flags & IFBIF_STP) && | ||||
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { | bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (m); | return (m); | ||||
} | } | ||||
/* | /* | ||||
* Make a deep copy of the packet and enqueue the copy | * Make a deep copy of the packet and enqueue the copy | ||||
* for bridge processing; return the original packet for | * for bridge processing; return the original packet for | ||||
* local processing. | * local processing. | ||||
*/ | */ | ||||
mc = m_dup(m, M_NOWAIT); | mc = m_dup(m, M_NOWAIT); | ||||
if (mc == NULL) { | if (mc == NULL) { | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (m); | return (m); | ||||
} | } | ||||
/* Perform the bridge forwarding function with the copy. */ | /* Perform the bridge forwarding function with the copy. */ | ||||
bridge_forward(sc, bif, mc); | bridge_forward(sc, bif, mc); | ||||
/* | /* | ||||
* Reinject the mbuf as arriving on the bridge so we have a | * Reinject the mbuf as arriving on the bridge so we have a | ||||
Show All 10 Lines | if (mc2 != NULL) { | ||||
mc2 = m_copyup(mc2, i, ETHER_ALIGN); | mc2 = m_copyup(mc2, i, ETHER_ALIGN); | ||||
} | } | ||||
if (mc2 != NULL) { | if (mc2 != NULL) { | ||||
mc2->m_pkthdr.rcvif = bifp; | mc2->m_pkthdr.rcvif = bifp; | ||||
(*bifp->if_input)(bifp, mc2); | (*bifp->if_input)(bifp, mc2); | ||||
} | } | ||||
/* Return the original packet for local processing. */ | /* Return the original packet for local processing. */ | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (m); | return (m); | ||||
} | } | ||||
if ((bif->bif_flags & IFBIF_STP) && | if ((bif->bif_flags & IFBIF_STP) && | ||||
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { | bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (m); | return (m); | ||||
} | } | ||||
#if (defined(INET) || defined(INET6)) | #if (defined(INET) || defined(INET6)) | ||||
# define OR_CARP_CHECK_WE_ARE_DST(iface) \ | # define OR_CARP_CHECK_WE_ARE_DST(iface) \ | ||||
|| ((iface)->if_carp \ | || ((iface)->if_carp \ | ||||
&& (*carp_forus_p)((iface), eh->ether_dhost)) | && (*carp_forus_p)((iface), eh->ether_dhost)) | ||||
# define OR_CARP_CHECK_WE_ARE_SRC(iface) \ | # define OR_CARP_CHECK_WE_ARE_SRC(iface) \ | ||||
Show All 33 Lines | if ((iface)->if_type == IFT_BRIDGE) { \ | ||||
eh = mtod(m, struct ether_header *); \ | eh = mtod(m, struct ether_header *); \ | ||||
} \ | } \ | ||||
} \ | } \ | ||||
if (bif->bif_flags & IFBIF_LEARNING) { \ | if (bif->bif_flags & IFBIF_LEARNING) { \ | ||||
error = bridge_rtupdate(sc, eh->ether_shost, \ | error = bridge_rtupdate(sc, eh->ether_shost, \ | ||||
vlan, bif, 0, IFBAF_DYNAMIC); \ | vlan, bif, 0, IFBAF_DYNAMIC); \ | ||||
if (error && bif->bif_addrmax) { \ | if (error && bif->bif_addrmax) { \ | ||||
m_freem(m); \ | m_freem(m); \ | ||||
NET_EPOCH_EXIT_ET(et); \ | |||||
return (NULL); \ | return (NULL); \ | ||||
} \ | } \ | ||||
} \ | } \ | ||||
m->m_pkthdr.rcvif = iface; \ | m->m_pkthdr.rcvif = iface; \ | ||||
NET_EPOCH_EXIT_ET(et); \ | |||||
return (m); \ | return (m); \ | ||||
} \ | } \ | ||||
\ | \ | ||||
/* We just received a packet that we sent out. */ \ | /* We just received a packet that we sent out. */ \ | ||||
if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \ | if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \ | ||||
OR_CARP_CHECK_WE_ARE_SRC((iface)) \ | OR_CARP_CHECK_WE_ARE_SRC((iface)) \ | ||||
) { \ | ) { \ | ||||
m_freem(m); \ | m_freem(m); \ | ||||
NET_EPOCH_EXIT_ET(et); \ | |||||
return (NULL); \ | return (NULL); \ | ||||
} | } | ||||
/* | /* | ||||
* Unicast. Make sure it's not for the bridge. | * Unicast. Make sure it's not for the bridge. | ||||
*/ | */ | ||||
do { GRAB_OUR_PACKETS(bifp) } while (0); | do { GRAB_OUR_PACKETS(bifp) } while (0); | ||||
Show All 14 Lines | |||||
#undef OR_CARP_CHECK_WE_ARE_DST | #undef OR_CARP_CHECK_WE_ARE_DST | ||||
#undef OR_CARP_CHECK_WE_ARE_SRC | #undef OR_CARP_CHECK_WE_ARE_SRC | ||||
#undef OR_PFIL_HOOKED_INET6 | #undef OR_PFIL_HOOKED_INET6 | ||||
#undef GRAB_OUR_PACKETS | #undef GRAB_OUR_PACKETS | ||||
/* Perform the bridge forwarding function. */ | /* Perform the bridge forwarding function. */ | ||||
bridge_forward(sc, bif, m); | bridge_forward(sc, bif, m); | ||||
NET_EPOCH_EXIT_ET(et); | |||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* bridge_broadcast: | * bridge_broadcast: | ||||
* | * | ||||
* Send a frame to all interfaces that are members of | * Send a frame to all interfaces that are members of | ||||
* the bridge, except for the one on which the packet | * the bridge, except for the one on which the packet | ||||
▲ Show 20 Lines • Show All 1,151 Lines • Show Last 20 Lines |