Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_bridge.c
Show First 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | #define BRIDGE_XDROP(_sc) do { \ | ||||
mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \ | mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \ | ||||
(_sc)->sc_iflist_xcnt--; \ | (_sc)->sc_iflist_xcnt--; \ | ||||
} while (0) | } while (0) | ||||
/* | /* | ||||
* Bridge interface list entry. | * Bridge interface list entry. | ||||
*/ | */ | ||||
struct bridge_iflist { | struct bridge_iflist { | ||||
LIST_ENTRY(bridge_iflist) bif_next; | CK_LIST_ENTRY(bridge_iflist) bif_next; | ||||
struct ifnet *bif_ifp; /* member if */ | struct ifnet *bif_ifp; /* member if */ | ||||
struct bstp_port bif_stp; /* STP state */ | struct bstp_port bif_stp; /* STP state */ | ||||
uint32_t bif_flags; /* member if flags */ | uint32_t bif_flags; /* member if flags */ | ||||
int bif_savedcaps; /* saved capabilities */ | int bif_savedcaps; /* saved capabilities */ | ||||
uint32_t bif_addrmax; /* max # of addresses */ | uint32_t bif_addrmax; /* max # of addresses */ | ||||
uint32_t bif_addrcnt; /* cur. # of addresses */ | uint32_t bif_addrcnt; /* cur. # of addresses */ | ||||
uint32_t bif_addrexceeded;/* # of address violations */ | uint32_t bif_addrexceeded;/* # of address violations */ | ||||
}; | }; | ||||
/* | /* | ||||
* Bridge route node. | * Bridge route node. | ||||
*/ | */ | ||||
struct bridge_rtnode { | struct bridge_rtnode { | ||||
LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */ | CK_LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */ | ||||
LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */ | CK_LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */ | ||||
struct bridge_iflist *brt_dst; /* destination if */ | struct bridge_iflist *brt_dst; /* destination if */ | ||||
unsigned long brt_expire; /* expiration time */ | unsigned long brt_expire; /* expiration time */ | ||||
uint8_t brt_flags; /* address flags */ | uint8_t brt_flags; /* address flags */ | ||||
uint8_t brt_addr[ETHER_ADDR_LEN]; | uint8_t brt_addr[ETHER_ADDR_LEN]; | ||||
uint16_t brt_vlan; /* vlan id */ | uint16_t brt_vlan; /* vlan id */ | ||||
}; | }; | ||||
#define brt_ifp brt_dst->bif_ifp | #define brt_ifp brt_dst->bif_ifp | ||||
/* | /* | ||||
* Software state for each bridge. | * Software state for each bridge. | ||||
*/ | */ | ||||
struct bridge_softc { | struct bridge_softc { | ||||
struct ifnet *sc_ifp; /* make this an interface */ | struct ifnet *sc_ifp; /* make this an interface */ | ||||
LIST_ENTRY(bridge_softc) sc_list; | LIST_ENTRY(bridge_softc) sc_list; | ||||
struct mtx sc_mtx; | struct mtx sc_mtx; | ||||
struct cv sc_cv; | struct cv sc_cv; | ||||
uint32_t sc_brtmax; /* max # of addresses */ | uint32_t sc_brtmax; /* max # of addresses */ | ||||
uint32_t sc_brtcnt; /* cur. # of addresses */ | uint32_t sc_brtcnt; /* cur. # of addresses */ | ||||
uint32_t sc_brttimeout; /* rt timeout in seconds */ | uint32_t sc_brttimeout; /* rt timeout in seconds */ | ||||
struct callout sc_brcallout; /* bridge callout */ | struct callout sc_brcallout; /* bridge callout */ | ||||
uint32_t sc_iflist_ref; /* refcount for sc_iflist */ | uint32_t sc_iflist_ref; /* refcount for sc_iflist */ | ||||
uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */ | uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */ | ||||
LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */ | CK_LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */ | ||||
LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ | CK_LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ | ||||
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ | CK_LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ | ||||
uint32_t sc_rthash_key; /* key for hash */ | uint32_t sc_rthash_key; /* key for hash */ | ||||
LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ | CK_LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ | ||||
struct bstp_state sc_stp; /* STP state */ | struct bstp_state sc_stp; /* STP state */ | ||||
uint32_t sc_brtexceeded; /* # of cache drops */ | uint32_t sc_brtexceeded; /* # of cache drops */ | ||||
struct ifnet *sc_ifaddr; /* member mac copied from */ | struct ifnet *sc_ifaddr; /* member mac copied from */ | ||||
struct ether_addr sc_defaddr; /* Default MAC address */ | struct ether_addr sc_defaddr; /* Default MAC address */ | ||||
struct epoch_context sc_epoch_ctx; | |||||
philip: Does this belong in this review? It doesn't appear to be referenced by other changes in this… | |||||
kpAuthorUnsubmitted Done Inline ActionsIt does not. I've removed it. kp: It does not. I've removed it. | |||||
}; | }; | ||||
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; | ||||
▲ Show 20 Lines • Show All 405 Lines • ▼ Show 20 Lines | bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) | ||||
sc->sc_brtmax = BRIDGE_RTABLE_MAX; | sc->sc_brtmax = BRIDGE_RTABLE_MAX; | ||||
sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; | sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; | ||||
/* Initialize our routing table. */ | /* Initialize our routing table. */ | ||||
bridge_rtable_init(sc); | bridge_rtable_init(sc); | ||||
callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0); | ||||
LIST_INIT(&sc->sc_iflist); | CK_LIST_INIT(&sc->sc_iflist); | ||||
LIST_INIT(&sc->sc_spanlist); | CK_LIST_INIT(&sc->sc_spanlist); | ||||
ifp->if_softc = sc; | ifp->if_softc = sc; | ||||
if_initname(ifp, bridge_name, unit); | if_initname(ifp, bridge_name, unit); | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ||||
ifp->if_ioctl = bridge_ioctl; | ifp->if_ioctl = bridge_ioctl; | ||||
ifp->if_transmit = bridge_transmit; | ifp->if_transmit = bridge_transmit; | ||||
ifp->if_qflush = bridge_qflush; | ifp->if_qflush = bridge_qflush; | ||||
ifp->if_init = bridge_init; | ifp->if_init = bridge_init; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | bridge_clone_destroy(struct ifnet *ifp) | ||||
struct bridge_softc *sc = ifp->if_softc; | struct bridge_softc *sc = ifp->if_softc; | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
bridge_stop(ifp, 1); | bridge_stop(ifp, 1); | ||||
ifp->if_flags &= ~IFF_UP; | ifp->if_flags &= ~IFF_UP; | ||||
while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) | while ((bif = CK_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 = CK_LIST_FIRST(&sc->sc_spanlist)) != NULL) { | ||||
bridge_delete_span(sc, bif); | bridge_delete_span(sc, bif); | ||||
} | } | ||||
/* Tear down the routing table. */ | /* Tear down the routing table. */ | ||||
bridge_rtable_fini(sc); | bridge_rtable_fini(sc); | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | case SIOCSIFFLAGS: | ||||
} | } | ||||
break; | break; | ||||
case SIOCSIFMTU: | case SIOCSIFMTU: | ||||
if (ifr->ifr_mtu < 576) { | if (ifr->ifr_mtu < 576) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (LIST_EMPTY(&sc->sc_iflist)) { | if (CK_LIST_EMPTY(&sc->sc_iflist)) { | ||||
sc->sc_ifp->if_mtu = ifr->ifr_mtu; | sc->sc_ifp->if_mtu = ifr->ifr_mtu; | ||||
break; | break; | ||||
} | } | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if (bif->bif_ifp->if_mtu != ifr->ifr_mtu) { | if (bif->bif_ifp->if_mtu != ifr->ifr_mtu) { | ||||
log(LOG_NOTICE, "%s: invalid MTU: %u(%s)" | log(LOG_NOTICE, "%s: invalid MTU: %u(%s)" | ||||
" != %d\n", sc->sc_ifp->if_xname, | " != %d\n", sc->sc_ifp->if_xname, | ||||
bif->bif_ifp->if_mtu, | bif->bif_ifp->if_mtu, | ||||
bif->bif_ifp->if_xname, ifr->ifr_mtu); | bif->bif_ifp->if_xname, ifr->ifr_mtu); | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
Show All 23 Lines | |||||
bridge_mutecaps(struct bridge_softc *sc) | bridge_mutecaps(struct bridge_softc *sc) | ||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
int enabled, mask; | int enabled, mask; | ||||
/* Initial bitmask of capabilities to test */ | /* Initial bitmask of capabilities to test */ | ||||
mask = BRIDGE_IFCAPS_MASK; | mask = BRIDGE_IFCAPS_MASK; | ||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
/* Every member must support it or its disabled */ | /* Every member must support it or its disabled */ | ||||
mask &= bif->bif_savedcaps; | mask &= bif->bif_savedcaps; | ||||
} | } | ||||
BRIDGE_XLOCK(sc); | BRIDGE_XLOCK(sc); | ||||
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_UNLOCK(sc); | ||||
bridge_set_ifcap(sc, bif, enabled); | bridge_set_ifcap(sc, bif, enabled); | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
Show All 37 Lines | |||||
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; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
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; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
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); | ||||
} | } | ||||
/* | /* | ||||
Show All 10 Lines | bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
if (bif->bif_flags & IFBIF_STP) | if (bif->bif_flags & IFBIF_STP) | ||||
bstp_disable(&bif->bif_stp); | bstp_disable(&bif->bif_stp); | ||||
ifs->if_bridge = NULL; | ifs->if_bridge = NULL; | ||||
BRIDGE_XLOCK(sc); | BRIDGE_XLOCK(sc); | ||||
LIST_REMOVE(bif, bif_next); | CK_LIST_REMOVE(bif, bif_next); | ||||
BRIDGE_XDROP(sc); | BRIDGE_XDROP(sc); | ||||
/* | /* | ||||
* If removing the interface that gave the bridge its mac address, set | * If removing the interface that gave the bridge its mac address, set | ||||
* the mac address of the bridge to the address of the next member, or | * the mac address of the bridge to the address of the next member, or | ||||
* to its default address if no members are left. | * to its default address if no members are left. | ||||
*/ | */ | ||||
if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) { | if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) { | ||||
if (LIST_EMPTY(&sc->sc_iflist)) { | if (CK_LIST_EMPTY(&sc->sc_iflist)) { | ||||
bcopy(&sc->sc_defaddr, | bcopy(&sc->sc_defaddr, | ||||
IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | ||||
sc->sc_ifaddr = NULL; | sc->sc_ifaddr = NULL; | ||||
} else { | } else { | ||||
fif = LIST_FIRST(&sc->sc_iflist)->bif_ifp; | fif = ((struct bridge_iflist *)CK_LIST_FIRST(&sc->sc_iflist))->bif_ifp; | ||||
emasteUnsubmitted Done Inline Actions> 80 cols? emaste: > 80 cols? | |||||
bcopy(IF_LLADDR(fif), | bcopy(IF_LLADDR(fif), | ||||
IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | ||||
sc->sc_ifaddr = fif; | sc->sc_ifaddr = fif; | ||||
} | } | ||||
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | ||||
} | } | ||||
bridge_linkcheck(sc); | bridge_linkcheck(sc); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif) | bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif) | ||||
{ | { | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
KASSERT(bif->bif_ifp->if_bridge == NULL, | KASSERT(bif->bif_ifp->if_bridge == NULL, | ||||
("%s: not a span interface", __func__)); | ("%s: not a span interface", __func__)); | ||||
LIST_REMOVE(bif, bif_next); | CK_LIST_REMOVE(bif, bif_next); | ||||
free(bif, M_DEVBUF); | free(bif, M_DEVBUF); | ||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_add(struct bridge_softc *sc, void *arg) | bridge_ioctl_add(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct ifbreq *req = arg; | struct ifbreq *req = arg; | ||||
struct bridge_iflist *bif = NULL; | struct bridge_iflist *bif = NULL; | ||||
struct ifnet *ifs; | struct ifnet *ifs; | ||||
int error = 0; | int error = 0; | ||||
ifs = ifunit(req->ifbr_ifsname); | ifs = ifunit(req->ifbr_ifsname); | ||||
if (ifs == NULL) | if (ifs == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
if (ifs->if_ioctl == NULL) /* must be supported */ | if (ifs->if_ioctl == NULL) /* must be supported */ | ||||
return (EINVAL); | return (EINVAL); | ||||
/* If it's in the span list, it can't be a member. */ | /* If it's in the span list, it can't be a member. */ | ||||
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | ||||
if (ifs == bif->bif_ifp) | if (ifs == bif->bif_ifp) | ||||
return (EBUSY); | return (EBUSY); | ||||
if (ifs->if_bridge == sc) | if (ifs->if_bridge == sc) | ||||
return (EEXIST); | return (EEXIST); | ||||
if (ifs->if_bridge != NULL) | if (ifs->if_bridge != NULL) | ||||
return (EBUSY); | return (EBUSY); | ||||
Show All 22 Lines | #ifdef INET6 | ||||
/* Check if the parent interface has a link-local scope addr. */ | /* Check if the parent interface has a link-local scope addr. */ | ||||
if (V_allow_llz_overlap == 0 && | if (V_allow_llz_overlap == 0 && | ||||
in6ifa_llaonifp(sc->sc_ifp) != NULL) { | in6ifa_llaonifp(sc->sc_ifp) != NULL) { | ||||
/* | /* | ||||
* If any, remove all inet6 addresses from the member | * If any, remove all inet6 addresses from the member | ||||
* interfaces. | * interfaces. | ||||
*/ | */ | ||||
BRIDGE_XLOCK(sc); | BRIDGE_XLOCK(sc); | ||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if (in6ifa_llaonifp(bif->bif_ifp)) { | if (in6ifa_llaonifp(bif->bif_ifp)) { | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
in6_ifdetach(bif->bif_ifp); | in6_ifdetach(bif->bif_ifp); | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
if_printf(sc->sc_ifp, | if_printf(sc->sc_ifp, | ||||
"IPv6 addresses on %s have been removed " | "IPv6 addresses on %s have been removed " | ||||
"before adding it as a member to prevent " | "before adding it as a member to prevent " | ||||
"IPv6 address scope violation.\n", | "IPv6 address scope violation.\n", | ||||
Show All 9 Lines | if (in6ifa_llaonifp(ifs)) { | ||||
"IPv6 addresses on %s have been removed " | "IPv6 addresses on %s have been removed " | ||||
"before adding it as a member to prevent " | "before adding it as a member to prevent " | ||||
"IPv6 address scope violation.\n", | "IPv6 address scope violation.\n", | ||||
ifs->if_xname); | ifs->if_xname); | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
/* Allow the first Ethernet member to define the MTU */ | /* Allow the first Ethernet member to define the MTU */ | ||||
if (LIST_EMPTY(&sc->sc_iflist)) | if (CK_LIST_EMPTY(&sc->sc_iflist)) | ||||
sc->sc_ifp->if_mtu = ifs->if_mtu; | sc->sc_ifp->if_mtu = ifs->if_mtu; | ||||
else if (sc->sc_ifp->if_mtu != ifs->if_mtu) { | else if (sc->sc_ifp->if_mtu != ifs->if_mtu) { | ||||
if_printf(sc->sc_ifp, "invalid MTU: %u(%s) != %u\n", | if_printf(sc->sc_ifp, "invalid MTU: %u(%s) != %u\n", | ||||
ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu); | ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); | bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); | ||||
if (bif == NULL) | if (bif == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
bif->bif_ifp = ifs; | bif->bif_ifp = ifs; | ||||
bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; | bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; | ||||
bif->bif_savedcaps = ifs->if_capenable; | bif->bif_savedcaps = ifs->if_capenable; | ||||
/* | /* | ||||
* Assign the interface's MAC address to the bridge if it's the first | * Assign the interface's MAC address to the bridge if it's the first | ||||
* member and the MAC address of the bridge has not been changed from | * member and the MAC address of the bridge has not been changed from | ||||
* the default randomly generated one. | * the default randomly generated one. | ||||
*/ | */ | ||||
if (V_bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) && | if (V_bridge_inherit_mac && CK_LIST_EMPTY(&sc->sc_iflist) && | ||||
!memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr.octet, ETHER_ADDR_LEN)) { | !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr.octet, ETHER_ADDR_LEN)) { | ||||
bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | ||||
sc->sc_ifaddr = ifs; | sc->sc_ifaddr = ifs; | ||||
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | ||||
} | } | ||||
ifs->if_bridge = sc; | ifs->if_bridge = sc; | ||||
ifs->if_bridge_output = bridge_output; | ifs->if_bridge_output = bridge_output; | ||||
ifs->if_bridge_input = bridge_input; | ifs->if_bridge_input = bridge_input; | ||||
ifs->if_bridge_linkstate = bridge_linkstate; | ifs->if_bridge_linkstate = bridge_linkstate; | ||||
bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp); | bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp); | ||||
/* | /* | ||||
* XXX: XLOCK HERE!?! | * XXX: XLOCK HERE!?! | ||||
* | * | ||||
* NOTE: insert_***HEAD*** should be safe for the traversals. | * NOTE: insert_***HEAD*** should be safe for the traversals. | ||||
*/ | */ | ||||
LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next); | CK_LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next); | ||||
/* Set interface capabilities to the intersection set of all members */ | /* Set interface capabilities to the intersection set of all members */ | ||||
bridge_mutecaps(sc); | bridge_mutecaps(sc); | ||||
bridge_linkcheck(sc); | bridge_linkcheck(sc); | ||||
/* Place the interface into promiscuous mode */ | /* Place the interface into promiscuous mode */ | ||||
switch (ifs->if_type) { | switch (ifs->if_type) { | ||||
case IFT_ETHER: | case IFT_ETHER: | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct ifbifconf *bifc = arg; | struct ifbifconf *bifc = arg; | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
struct ifbreq breq; | struct ifbreq breq; | ||||
char *buf, *outbuf; | char *buf, *outbuf; | ||||
int count, buflen, len, error = 0; | int count, buflen, len, error = 0; | ||||
count = 0; | count = 0; | ||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) | ||||
count++; | count++; | ||||
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); | BRIDGE_UNLOCK(sc); | ||||
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
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)); | ||||
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; | ||||
strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, | strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, | ||||
sizeof(breq.ifbr_ifsname)); | sizeof(breq.ifbr_ifsname)); | ||||
/* Fill in the ifbreq structure */ | /* Fill in the ifbreq structure */ | ||||
error = bridge_ioctl_gifflags(sc, &breq); | error = bridge_ioctl_gifflags(sc, &breq); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
memcpy(buf, &breq, sizeof(breq)); | memcpy(buf, &breq, sizeof(breq)); | ||||
count++; | count++; | ||||
buf += sizeof(breq); | buf += sizeof(breq); | ||||
len -= sizeof(breq); | len -= sizeof(breq); | ||||
} | } | ||||
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { | ||||
if (len < sizeof(breq)) | if (len < sizeof(breq)) | ||||
break; | break; | ||||
strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, | strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, | ||||
sizeof(breq.ifbr_ifsname)); | sizeof(breq.ifbr_ifsname)); | ||||
breq.ifbr_ifsflags = bif->bif_flags; | breq.ifbr_ifsflags = bif->bif_flags; | ||||
breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff; | breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff; | ||||
memcpy(buf, &breq, sizeof(breq)); | memcpy(buf, &breq, sizeof(breq)); | ||||
Show All 18 Lines | bridge_ioctl_rts(struct bridge_softc *sc, void *arg) | ||||
struct ifbareq bareq; | struct ifbareq bareq; | ||||
char *buf, *outbuf; | char *buf, *outbuf; | ||||
int count, buflen, len, error = 0; | int count, buflen, len, error = 0; | ||||
if (bac->ifbac_len == 0) | if (bac->ifbac_len == 0) | ||||
return (0); | return (0); | ||||
count = 0; | count = 0; | ||||
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); | BRIDGE_UNLOCK(sc); | ||||
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
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)); | ||||
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; | ||||
strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, | strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, | ||||
sizeof(bareq.ifba_ifsname)); | sizeof(bareq.ifba_ifsname)); | ||||
memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); | memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); | ||||
bareq.ifba_vlan = brt->brt_vlan; | bareq.ifba_vlan = brt->brt_vlan; | ||||
if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && | ||||
time_uptime < brt->brt_expire) | time_uptime < brt->brt_expire) | ||||
▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | bridge_ioctl_addspan(struct bridge_softc *sc, void *arg) | ||||
struct ifbreq *req = arg; | struct ifbreq *req = arg; | ||||
struct bridge_iflist *bif = NULL; | struct bridge_iflist *bif = NULL; | ||||
struct ifnet *ifs; | struct ifnet *ifs; | ||||
ifs = ifunit(req->ifbr_ifsname); | ifs = ifunit(req->ifbr_ifsname); | ||||
if (ifs == NULL) | if (ifs == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | ||||
if (ifs == bif->bif_ifp) | if (ifs == bif->bif_ifp) | ||||
return (EBUSY); | return (EBUSY); | ||||
if (ifs->if_bridge != NULL) | if (ifs->if_bridge != NULL) | ||||
return (EBUSY); | return (EBUSY); | ||||
switch (ifs->if_type) { | switch (ifs->if_type) { | ||||
case IFT_ETHER: | case IFT_ETHER: | ||||
case IFT_GIF: | case IFT_GIF: | ||||
case IFT_L2VLAN: | case IFT_L2VLAN: | ||||
break; | break; | ||||
default: | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); | bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); | ||||
if (bif == NULL) | if (bif == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
bif->bif_ifp = ifs; | bif->bif_ifp = ifs; | ||||
bif->bif_flags = IFBIF_SPAN; | bif->bif_flags = IFBIF_SPAN; | ||||
LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next); | CK_LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
bridge_ioctl_delspan(struct bridge_softc *sc, void *arg) | bridge_ioctl_delspan(struct bridge_softc *sc, void *arg) | ||||
{ | { | ||||
struct ifbreq *req = arg; | struct ifbreq *req = arg; | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
struct ifnet *ifs; | struct ifnet *ifs; | ||||
ifs = ifunit(req->ifbr_ifsname); | ifs = ifunit(req->ifbr_ifsname); | ||||
if (ifs == NULL) | if (ifs == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | ||||
if (ifs == bif->bif_ifp) | if (ifs == bif->bif_ifp) | ||||
break; | break; | ||||
if (bif == NULL) | if (bif == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
bridge_delete_span(sc, bif); | bridge_delete_span(sc, bif); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | bridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg) | ||||
struct ifbpstpconf *bifstp = arg; | struct ifbpstpconf *bifstp = arg; | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
struct bstp_port *bp; | struct bstp_port *bp; | ||||
struct ifbpstpreq bpreq; | struct ifbpstpreq bpreq; | ||||
char *buf, *outbuf; | char *buf, *outbuf; | ||||
int count, buflen, len, error = 0; | int count, buflen, len, error = 0; | ||||
count = 0; | count = 0; | ||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
if ((bif->bif_flags & IFBIF_STP) != 0) | if ((bif->bif_flags & IFBIF_STP) != 0) | ||||
count++; | count++; | ||||
} | } | ||||
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); | BRIDGE_UNLOCK(sc); | ||||
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
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)); | ||||
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; | ||||
if ((bif->bif_flags & IFBIF_STP) == 0) | if ((bif->bif_flags & IFBIF_STP) == 0) | ||||
continue; | continue; | ||||
bp = &bif->bif_stp; | bp = &bif->bif_stp; | ||||
bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; | bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | if (sc != NULL) { | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
return; | return; | ||||
} | } | ||||
/* Check if the interface is a span port */ | /* Check if the interface is a span port */ | ||||
BRIDGE_LIST_LOCK(); | BRIDGE_LIST_LOCK(); | ||||
LIST_FOREACH(sc, &V_bridge_list, sc_list) { | LIST_FOREACH(sc, &V_bridge_list, sc_list) { | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) | ||||
if (ifp == bif->bif_ifp) { | if (ifp == bif->bif_ifp) { | ||||
bridge_delete_span(sc, bif); | bridge_delete_span(sc, bif); | ||||
break; | break; | ||||
} | } | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
} | } | ||||
BRIDGE_LIST_UNLOCK(); | BRIDGE_LIST_UNLOCK(); | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | if (dst_if == NULL) { | ||||
bridge_span(sc, m); | bridge_span(sc, m); | ||||
BRIDGE_LOCK2REF(sc, error); | BRIDGE_LOCK2REF(sc, error); | ||||
if (error) { | if (error) { | ||||
m_freem(m); | m_freem(m); | ||||
return (0); | return (0); | ||||
} | } | ||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { | ||||
dst_if = bif->bif_ifp; | dst_if = bif->bif_ifp; | ||||
if (dst_if->if_type == IFT_GIF) | if (dst_if->if_type == IFT_GIF) | ||||
continue; | continue; | ||||
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) | ||||
continue; | continue; | ||||
/* | /* | ||||
* If this is not the original output interface, | * If this is not the original output interface, | ||||
* and the interface is participating in spanning | * and the interface is participating in spanning | ||||
* tree, make sure the port is in a state that | * tree, make sure the port is in a state that | ||||
* allows forwarding. | * allows forwarding. | ||||
*/ | */ | ||||
if (dst_if != ifp && (bif->bif_flags & IFBIF_STP) && | if (dst_if != ifp && (bif->bif_flags & IFBIF_STP) && | ||||
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | ||||
continue; | continue; | ||||
if (LIST_NEXT(bif, bif_next) == NULL) { | if (CK_LIST_NEXT(bif, bif_next) == NULL) { | ||||
used = 1; | used = 1; | ||||
mc = m; | mc = m; | ||||
} else { | } else { | ||||
mc = m_copypacket(m, M_NOWAIT); | mc = m_copypacket(m, M_NOWAIT); | ||||
if (mc == NULL) { | if (mc == NULL) { | ||||
if_inc_counter(bifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(bifp, IFCOUNTER_OERRORS, 1); | ||||
continue; | continue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 398 Lines • ▼ Show 20 Lines | #define GRAB_OUR_PACKETS(iface) \ | ||||
* packet comes through the interface like VLAN's with the same MACs | * packet comes through the interface like VLAN's with the same MACs | ||||
* on several interfaces from the same bridge. This also will save | * on several interfaces from the same bridge. This also will save | ||||
* some CPU cycles in case the destination interface and the input | * some CPU cycles in case the destination interface and the input | ||||
* interface (eq ifp) are the same. | * interface (eq ifp) are the same. | ||||
*/ | */ | ||||
do { GRAB_OUR_PACKETS(ifp) } while (0); | do { GRAB_OUR_PACKETS(ifp) } while (0); | ||||
/* Now check the all bridge members. */ | /* Now check the all bridge members. */ | ||||
LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { | ||||
GRAB_OUR_PACKETS(bif2->bif_ifp) | GRAB_OUR_PACKETS(bif2->bif_ifp) | ||||
} | } | ||||
#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 | ||||
Show All 36 Lines | |||||
#endif | #endif | ||||
)) { | )) { | ||||
if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) | if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) | ||||
goto out; | goto out; | ||||
if (m == NULL) | if (m == NULL) | ||||
goto out; | goto out; | ||||
} | } | ||||
LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) { | ||||
dst_if = dbif->bif_ifp; | dst_if = dbif->bif_ifp; | ||||
if (dst_if == src_if) | if (dst_if == src_if) | ||||
continue; | continue; | ||||
/* Private segments can not talk to each other */ | /* Private segments can not talk to each other */ | ||||
if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)) | if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)) | ||||
continue; | continue; | ||||
if ((dbif->bif_flags & IFBIF_STP) && | if ((dbif->bif_flags & IFBIF_STP) && | ||||
dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | ||||
continue; | continue; | ||||
if ((dbif->bif_flags & IFBIF_DISCOVER) == 0 && | if ((dbif->bif_flags & IFBIF_DISCOVER) == 0 && | ||||
(m->m_flags & (M_BCAST|M_MCAST)) == 0) | (m->m_flags & (M_BCAST|M_MCAST)) == 0) | ||||
continue; | continue; | ||||
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) | ||||
continue; | continue; | ||||
if (LIST_NEXT(dbif, bif_next) == NULL) { | if (CK_LIST_NEXT(dbif, bif_next) == NULL) { | ||||
mc = m; | mc = m; | ||||
used = 1; | used = 1; | ||||
} else { | } else { | ||||
mc = m_dup(m, M_NOWAIT); | mc = m_dup(m, M_NOWAIT); | ||||
if (mc == NULL) { | if (mc == NULL) { | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | ||||
continue; | continue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
bridge_span(struct bridge_softc *sc, struct mbuf *m) | bridge_span(struct bridge_softc *sc, struct mbuf *m) | ||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
struct ifnet *dst_if; | struct ifnet *dst_if; | ||||
struct mbuf *mc; | struct mbuf *mc; | ||||
if (LIST_EMPTY(&sc->sc_spanlist)) | if (CK_LIST_EMPTY(&sc->sc_spanlist)) | ||||
return; | return; | ||||
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { | CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { | ||||
dst_if = bif->bif_ifp; | dst_if = bif->bif_ifp; | ||||
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) | ||||
continue; | continue; | ||||
mc = m_copypacket(m, M_NOWAIT); | mc = m_copypacket(m, M_NOWAIT); | ||||
if (mc == NULL) { | if (mc == NULL) { | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | bridge_rttrim(struct bridge_softc *sc) | ||||
if (sc->sc_brtcnt <= sc->sc_brtmax) | if (sc->sc_brtcnt <= sc->sc_brtmax) | ||||
return; | return; | ||||
/* Force an aging cycle; this might trim enough addresses. */ | /* Force an aging cycle; this might trim enough addresses. */ | ||||
bridge_rtage(sc); | bridge_rtage(sc); | ||||
if (sc->sc_brtcnt <= sc->sc_brtmax) | if (sc->sc_brtcnt <= sc->sc_brtmax) | ||||
return; | return; | ||||
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | CK_LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | ||||
if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { | ||||
bridge_rtnode_destroy(sc, brt); | bridge_rtnode_destroy(sc, brt); | ||||
if (sc->sc_brtcnt <= sc->sc_brtmax) | if (sc->sc_brtcnt <= sc->sc_brtmax) | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Show All 26 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
bridge_rtage(struct bridge_softc *sc) | bridge_rtage(struct bridge_softc *sc) | ||||
{ | { | ||||
struct bridge_rtnode *brt, *nbrt; | struct bridge_rtnode *brt, *nbrt; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | CK_LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | ||||
if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { | if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { | ||||
if (time_uptime >= brt->brt_expire) | if (time_uptime >= brt->brt_expire) | ||||
bridge_rtnode_destroy(sc, brt); | bridge_rtnode_destroy(sc, brt); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtflush: | * bridge_rtflush: | ||||
* | * | ||||
* Remove all dynamic addresses from the bridge. | * Remove all dynamic addresses from the bridge. | ||||
*/ | */ | ||||
static void | static void | ||||
bridge_rtflush(struct bridge_softc *sc, int full) | bridge_rtflush(struct bridge_softc *sc, int full) | ||||
{ | { | ||||
struct bridge_rtnode *brt, *nbrt; | struct bridge_rtnode *brt, *nbrt; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | CK_LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | ||||
if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) | if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) | ||||
bridge_rtnode_destroy(sc, brt); | bridge_rtnode_destroy(sc, brt); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtdaddr: | * bridge_rtdaddr: | ||||
* | * | ||||
Show All 26 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full) | bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full) | ||||
{ | { | ||||
struct bridge_rtnode *brt, *nbrt; | struct bridge_rtnode *brt, *nbrt; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | CK_LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { | ||||
if (brt->brt_ifp == ifp && (full || | if (brt->brt_ifp == ifp && (full || | ||||
(brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) | (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) | ||||
bridge_rtnode_destroy(sc, brt); | bridge_rtnode_destroy(sc, brt); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtable_init: | * bridge_rtable_init: | ||||
* | * | ||||
* Initialize the route table for this bridge. | * Initialize the route table for this bridge. | ||||
*/ | */ | ||||
static void | static void | ||||
bridge_rtable_init(struct bridge_softc *sc) | bridge_rtable_init(struct bridge_softc *sc) | ||||
{ | { | ||||
int i; | int i; | ||||
sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, | sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, | ||||
M_DEVBUF, M_WAITOK); | M_DEVBUF, M_WAITOK); | ||||
for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) | for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) | ||||
LIST_INIT(&sc->sc_rthash[i]); | CK_LIST_INIT(&sc->sc_rthash[i]); | ||||
sc->sc_rthash_key = arc4random(); | sc->sc_rthash_key = arc4random(); | ||||
LIST_INIT(&sc->sc_rtlist); | CK_LIST_INIT(&sc->sc_rtlist); | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtable_fini: | * bridge_rtable_fini: | ||||
* | * | ||||
* Deconstruct the route table for this bridge. | * Deconstruct the route table for this bridge. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct bridge_rtnode *brt; | struct bridge_rtnode *brt; | ||||
uint32_t hash; | uint32_t hash; | ||||
int dir; | int dir; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
hash = bridge_rthash(sc, addr); | hash = bridge_rthash(sc, addr); | ||||
LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) { | CK_LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) { | ||||
dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr); | dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr); | ||||
if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0)) | if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0)) | ||||
return (brt); | return (brt); | ||||
if (dir > 0) | if (dir > 0) | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
Show All 11 Lines | bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt) | ||||
struct bridge_rtnode *lbrt; | struct bridge_rtnode *lbrt; | ||||
uint32_t hash; | uint32_t hash; | ||||
int dir; | int dir; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
hash = bridge_rthash(sc, brt->brt_addr); | hash = bridge_rthash(sc, brt->brt_addr); | ||||
lbrt = LIST_FIRST(&sc->sc_rthash[hash]); | lbrt = CK_LIST_FIRST(&sc->sc_rthash[hash]); | ||||
if (lbrt == NULL) { | if (lbrt == NULL) { | ||||
LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash); | CK_LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash); | ||||
goto out; | goto out; | ||||
} | } | ||||
do { | do { | ||||
dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr); | dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr); | ||||
if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) | if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) | ||||
return (EEXIST); | return (EEXIST); | ||||
if (dir > 0) { | if (dir > 0) { | ||||
LIST_INSERT_BEFORE(lbrt, brt, brt_hash); | CK_LIST_INSERT_BEFORE(lbrt, brt, brt_hash); | ||||
goto out; | goto out; | ||||
} | } | ||||
if (LIST_NEXT(lbrt, brt_hash) == NULL) { | if (CK_LIST_NEXT(lbrt, brt_hash) == NULL) { | ||||
LIST_INSERT_AFTER(lbrt, brt, brt_hash); | CK_LIST_INSERT_AFTER(lbrt, brt, brt_hash); | ||||
goto out; | goto out; | ||||
} | } | ||||
lbrt = LIST_NEXT(lbrt, brt_hash); | lbrt = CK_LIST_NEXT(lbrt, brt_hash); | ||||
} while (lbrt != NULL); | } while (lbrt != NULL); | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
panic("bridge_rtnode_insert: impossible"); | panic("bridge_rtnode_insert: impossible"); | ||||
#endif | #endif | ||||
out: | out: | ||||
LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list); | CK_LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list); | ||||
sc->sc_brtcnt++; | sc->sc_brtcnt++; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtnode_destroy: | * bridge_rtnode_destroy: | ||||
* | * | ||||
* Destroy a bridge rtnode. | * Destroy a bridge rtnode. | ||||
*/ | */ | ||||
static void | static void | ||||
bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) | bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) | ||||
{ | { | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
LIST_REMOVE(brt, brt_hash); | CK_LIST_REMOVE(brt, brt_hash); | ||||
LIST_REMOVE(brt, brt_list); | CK_LIST_REMOVE(brt, brt_list); | ||||
sc->sc_brtcnt--; | sc->sc_brtcnt--; | ||||
brt->brt_dst->bif_addrcnt--; | brt->brt_dst->bif_addrcnt--; | ||||
uma_zfree(V_bridge_rtnode_zone, brt); | uma_zfree(V_bridge_rtnode_zone, brt); | ||||
} | } | ||||
/* | /* | ||||
* bridge_rtable_expire: | * bridge_rtable_expire: | ||||
* | * | ||||
Show All 10 Lines | bridge_rtable_expire(struct ifnet *ifp, int age) | ||||
/* | /* | ||||
* If the age is zero then flush, otherwise set all the expiry times to | * If the age is zero then flush, otherwise set all the expiry times to | ||||
* age for the interface | * age for the interface | ||||
*/ | */ | ||||
if (age == 0) | if (age == 0) | ||||
bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN); | bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN); | ||||
else { | else { | ||||
LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { | CK_LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { | ||||
/* Cap the expiry time to 'age' */ | /* Cap the expiry time to 'age' */ | ||||
if (brt->brt_ifp == ifp && | if (brt->brt_ifp == ifp && | ||||
brt->brt_expire > time_uptime + age && | brt->brt_expire > time_uptime + age && | ||||
(brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) | (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) | ||||
brt->brt_expire = time_uptime + age; | brt->brt_expire = time_uptime + age; | ||||
} | } | ||||
} | } | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
▲ Show 20 Lines • Show All 521 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
int new_link, hasls; | int new_link, hasls; | ||||
BRIDGE_LOCK_ASSERT(sc); | BRIDGE_LOCK_ASSERT(sc); | ||||
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 */ | ||||
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) { | ||||
new_link = LINK_STATE_UP; | new_link = LINK_STATE_UP; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) { | if (!CK_LIST_EMPTY(&sc->sc_iflist) && !hasls) { | ||||
/* If no interfaces support link-state then we default to up */ | /* If no interfaces support link-state then we default to up */ | ||||
new_link = LINK_STATE_UP; | new_link = LINK_STATE_UP; | ||||
} | } | ||||
if_link_state_change(sc->sc_ifp, new_link); | if_link_state_change(sc->sc_ifp, new_link); | ||||
} | } |
Does this belong in this review? It doesn't appear to be referenced by other changes in this diff.