diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-04 11:33:00 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-04 15:28:21 +0100 |
commit | af5333e0a02b2295304d4e029b15ee15a4fe2b3a (patch) | |
tree | c5c43680d374f58b487eeeaf18fb7ec6b84ba074 /freebsd/sys/net/bridgestp.c | |
parent | BUS_SPACE(9): Use simple memory model for ARM (diff) | |
download | rtems-libbsd-af5333e0a02b2295304d4e029b15ee15a4fe2b3a.tar.bz2 |
Update to FreeBSD 8.4
Diffstat (limited to 'freebsd/sys/net/bridgestp.c')
-rw-r--r-- | freebsd/sys/net/bridgestp.c | 174 |
1 files changed, 99 insertions, 75 deletions
diff --git a/freebsd/sys/net/bridgestp.c b/freebsd/sys/net/bridgestp.c index cc7f4e6f..1b2ef7cf 100644 --- a/freebsd/sys/net/bridgestp.c +++ b/freebsd/sys/net/bridgestp.c @@ -129,14 +129,14 @@ static int bstp_rerooted(struct bstp_state *, struct bstp_port *); static uint32_t bstp_calc_path_cost(struct bstp_port *); static void bstp_notify_state(void *, int); static void bstp_notify_rtage(void *, int); -static void bstp_ifupdstatus(struct bstp_state *, struct bstp_port *); +static void bstp_ifupdstatus(void *, int); static void bstp_enable_port(struct bstp_state *, struct bstp_port *); static void bstp_disable_port(struct bstp_state *, struct bstp_port *); static void bstp_tick(void *); static void bstp_timer_start(struct bstp_timer *, uint16_t); static void bstp_timer_stop(struct bstp_timer *); static void bstp_timer_latch(struct bstp_timer *); -static int bstp_timer_expired(struct bstp_timer *); +static int bstp_timer_dectest(struct bstp_timer *); static void bstp_hello_timer_expiry(struct bstp_state *, struct bstp_port *); static void bstp_message_age_expiry(struct bstp_state *, @@ -448,7 +448,7 @@ bstp_pdu_flags(struct bstp_port *bp) return (flags); } -struct mbuf * +void bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m) { struct bstp_state *bs = bp->bp_bs; @@ -458,7 +458,7 @@ bstp_input(struct bstp_port *bp, struct ifnet *ifp, struct mbuf *m) if (bp->bp_active == 0) { m_freem(m); - return (NULL); + return; } BSTP_LOCK(bs); @@ -523,7 +523,6 @@ out: BSTP_UNLOCK(bs); if (m) m_freem(m); - return (NULL); } static void @@ -1680,7 +1679,7 @@ bstp_set_autoptp(struct bstp_port *bp, int set) if (set) { bp->bp_flags |= BSTP_PORT_AUTOPTP; if (bp->bp_role != BSTP_ROLE_DISABLED) - bstp_ifupdstatus(bs, bp); + taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask); } else bp->bp_flags &= ~BSTP_PORT_AUTOPTP; BSTP_UNLOCK(bs); @@ -1770,85 +1769,93 @@ bstp_notify_rtage(void *arg, int pending) } void -bstp_linkstate(struct ifnet *ifp, int state) +bstp_linkstate(struct bstp_port *bp) { - struct bstp_state *bs; - struct bstp_port *bp; + struct bstp_state *bs = bp->bp_bs; - /* search for the stp port */ - mtx_lock(&bstp_list_mtx); - LIST_FOREACH(bs, &bstp_list, bs_list) { - BSTP_LOCK(bs); - LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { - if (bp->bp_ifp == ifp) { - bstp_ifupdstatus(bs, bp); - bstp_update_state(bs, bp); - /* it only exists once so return */ - BSTP_UNLOCK(bs); - mtx_unlock(&bstp_list_mtx); - return; - } - } - BSTP_UNLOCK(bs); - } - mtx_unlock(&bstp_list_mtx); + if (!bp->bp_active) + return; + + bstp_ifupdstatus(bp, 0); + BSTP_LOCK(bs); + bstp_update_state(bs, bp); + BSTP_UNLOCK(bs); } static void -bstp_ifupdstatus(struct bstp_state *bs, struct bstp_port *bp) +bstp_ifupdstatus(void *arg, int pending) { + struct bstp_port *bp = (struct bstp_port *)arg; + struct bstp_state *bs = bp->bp_bs; struct ifnet *ifp = bp->bp_ifp; struct ifmediareq ifmr; - int error = 0; + int error, changed; - BSTP_LOCK_ASSERT(bs); + if (!bp->bp_active) + return; bzero((char *)&ifmr, sizeof(ifmr)); error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); + BSTP_LOCK(bs); + changed = 0; if ((error == 0) && (ifp->if_flags & IFF_UP)) { if (ifmr.ifm_status & IFM_ACTIVE) { /* A full-duplex link is assumed to be point to point */ if (bp->bp_flags & BSTP_PORT_AUTOPTP) { - bp->bp_ptp_link = - ifmr.ifm_active & IFM_FDX ? 1 : 0; + int fdx; + + fdx = ifmr.ifm_active & IFM_FDX ? 1 : 0; + if (bp->bp_ptp_link ^ fdx) { + bp->bp_ptp_link = fdx; + changed = 1; + } } /* Calc the cost if the link was down previously */ if (bp->bp_flags & BSTP_PORT_PNDCOST) { - bp->bp_path_cost = bstp_calc_path_cost(bp); + uint32_t cost; + + cost = bstp_calc_path_cost(bp); + if (bp->bp_path_cost != cost) { + bp->bp_path_cost = cost; + changed = 1; + } bp->bp_flags &= ~BSTP_PORT_PNDCOST; } - if (bp->bp_role == BSTP_ROLE_DISABLED) + if (bp->bp_role == BSTP_ROLE_DISABLED) { bstp_enable_port(bs, bp); + changed = 1; + } } else { if (bp->bp_role != BSTP_ROLE_DISABLED) { bstp_disable_port(bs, bp); + changed = 1; if ((bp->bp_flags & BSTP_PORT_ADMEDGE) && bp->bp_protover == BSTP_PROTO_RSTP) bp->bp_operedge = 1; } } - return; - } - - if (bp->bp_infois != BSTP_INFO_DISABLED) + } else if (bp->bp_infois != BSTP_INFO_DISABLED) { bstp_disable_port(bs, bp); + changed = 1; + } + if (changed) + bstp_assign_roles(bs); + BSTP_UNLOCK(bs); } static void bstp_enable_port(struct bstp_state *bs, struct bstp_port *bp) { bp->bp_infois = BSTP_INFO_AGED; - bstp_assign_roles(bs); } static void bstp_disable_port(struct bstp_state *bs, struct bstp_port *bp) { bp->bp_infois = BSTP_INFO_DISABLED; - bstp_assign_roles(bs); } static void @@ -1862,30 +1869,34 @@ bstp_tick(void *arg) if (bs->bs_running == 0) return; - /* slow timer to catch missed link events */ - if (bstp_timer_expired(&bs->bs_link_timer)) { - LIST_FOREACH(bp, &bs->bs_bplist, bp_next) - bstp_ifupdstatus(bs, bp); + CURVNET_SET(bs->bs_vnet); + + /* poll link events on interfaces that do not support linkstate */ + if (bstp_timer_dectest(&bs->bs_link_timer)) { + LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { + if (!(bp->bp_ifp->if_capabilities & IFCAP_LINKSTATE)) + taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask); + } bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER); } LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { /* no events need to happen for these */ - bstp_timer_expired(&bp->bp_tc_timer); - bstp_timer_expired(&bp->bp_recent_root_timer); - bstp_timer_expired(&bp->bp_forward_delay_timer); - bstp_timer_expired(&bp->bp_recent_backup_timer); + bstp_timer_dectest(&bp->bp_tc_timer); + bstp_timer_dectest(&bp->bp_recent_root_timer); + bstp_timer_dectest(&bp->bp_forward_delay_timer); + bstp_timer_dectest(&bp->bp_recent_backup_timer); - if (bstp_timer_expired(&bp->bp_hello_timer)) + if (bstp_timer_dectest(&bp->bp_hello_timer)) bstp_hello_timer_expiry(bs, bp); - if (bstp_timer_expired(&bp->bp_message_age_timer)) + if (bstp_timer_dectest(&bp->bp_message_age_timer)) bstp_message_age_expiry(bs, bp); - if (bstp_timer_expired(&bp->bp_migrate_delay_timer)) + if (bstp_timer_dectest(&bp->bp_migrate_delay_timer)) bstp_migrate_delay_expiry(bs, bp); - if (bstp_timer_expired(&bp->bp_edge_delay_timer)) + if (bstp_timer_dectest(&bp->bp_edge_delay_timer)) bstp_edge_delay_expiry(bs, bp); /* update the various state machines for the port */ @@ -1895,6 +1906,8 @@ bstp_tick(void *arg) bp->bp_txcount--; } + CURVNET_RESTORE(); + callout_reset(&bs->bs_bstpcallout, hz, bstp_tick, bs); } @@ -1922,7 +1935,7 @@ bstp_timer_latch(struct bstp_timer *t) } static int -bstp_timer_expired(struct bstp_timer *t) +bstp_timer_dectest(struct bstp_timer *t) { if (t->active == 0 || t->latched) return (0); @@ -2010,24 +2023,33 @@ bstp_reinit(struct bstp_state *bs) struct bstp_port *bp; struct ifnet *ifp, *mif; u_char *e_addr; + void *bridgeptr; static const u_char llzero[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ BSTP_LOCK_ASSERT(bs); + if (LIST_EMPTY(&bs->bs_bplist)) + goto disablestp; + mif = NULL; + bridgeptr = LIST_FIRST(&bs->bs_bplist)->bp_ifp->if_bridge; + KASSERT(bridgeptr != NULL, ("Invalid bridge pointer")); /* * Search through the Ethernet adapters and find the one with the - * lowest value. The adapter which we take the MAC address from does - * not need to be part of the bridge, it just needs to be a unique - * value. + * lowest value. Make sure the adapter which we take the MAC address + * from is part of this bridge, so we can have more than one independent + * bridges in the same STP domain. */ IFNET_RLOCK_NOSLEEP(); TAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (ifp->if_type != IFT_ETHER) - continue; + continue; /* Not Ethernet */ + + if (ifp->if_bridge != bridgeptr) + continue; /* Not part of our bridge */ if (bstp_addr_cmp(IF_LLADDR(ifp), llzero) == 0) - continue; + continue; /* No mac address set */ if (mif == NULL) { mif = ifp; @@ -2039,21 +2061,8 @@ bstp_reinit(struct bstp_state *bs) } } IFNET_RUNLOCK_NOSLEEP(); - - if (LIST_EMPTY(&bs->bs_bplist) || mif == NULL) { - /* Set the bridge and root id (lower bits) to zero */ - bs->bs_bridge_pv.pv_dbridge_id = - ((uint64_t)bs->bs_bridge_priority) << 48; - bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id; - bs->bs_root_pv = bs->bs_bridge_pv; - /* Disable any remaining ports, they will have no MAC address */ - LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { - bp->bp_infois = BSTP_INFO_DISABLED; - bstp_set_port_role(bp, BSTP_ROLE_DISABLED); - } - callout_stop(&bs->bs_bstpcallout); - return; - } + if (mif == NULL) + goto disablestp; e_addr = IF_LLADDR(mif); bs->bs_bridge_pv.pv_dbridge_id = @@ -2076,11 +2085,25 @@ bstp_reinit(struct bstp_state *bs) LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { bp->bp_port_id = (bp->bp_priority << 8) | (bp->bp_ifp->if_index & 0xfff); - bstp_ifupdstatus(bs, bp); + taskqueue_enqueue(taskqueue_swi, &bp->bp_mediatask); } bstp_assign_roles(bs); bstp_timer_start(&bs->bs_link_timer, BSTP_LINK_TIMER); + return; + +disablestp: + /* Set the bridge and root id (lower bits) to zero */ + bs->bs_bridge_pv.pv_dbridge_id = + ((uint64_t)bs->bs_bridge_priority) << 48; + bs->bs_bridge_pv.pv_root_id = bs->bs_bridge_pv.pv_dbridge_id; + bs->bs_root_pv = bs->bs_bridge_pv; + /* Disable any remaining ports, they will have no MAC address */ + LIST_FOREACH(bp, &bs->bs_bplist, bp_next) { + bp->bp_infois = BSTP_INFO_DISABLED; + bstp_set_port_role(bp, BSTP_ROLE_DISABLED); + } + callout_stop(&bs->bs_bstpcallout); } static int @@ -2090,10 +2113,8 @@ bstp_modevent(module_t mod, int type, void *data) case MOD_LOAD: mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF); LIST_INIT(&bstp_list); - bstp_linkstate_p = bstp_linkstate; break; case MOD_UNLOAD: - bstp_linkstate_p = NULL; mtx_destroy(&bstp_list_mtx); break; default: @@ -2128,6 +2149,7 @@ bstp_attach(struct bstp_state *bs, struct bstp_cb_ops *cb) bs->bs_protover = BSTP_PROTO_RSTP; bs->bs_state_cb = cb->bcb_state; bs->bs_rtage_cb = cb->bcb_rtage; + bs->bs_vnet = curvnet; getmicrotime(&bs->bs_last_tc_time); @@ -2184,6 +2206,7 @@ bstp_create(struct bstp_state *bs, struct bstp_port *bp, struct ifnet *ifp) bp->bp_priority = BSTP_DEFAULT_PORT_PRIORITY; TASK_INIT(&bp->bp_statetask, 0, bstp_notify_state, bp); TASK_INIT(&bp->bp_rtagetask, 0, bstp_notify_rtage, bp); + TASK_INIT(&bp->bp_mediatask, 0, bstp_ifupdstatus, bp); /* Init state */ bp->bp_infois = BSTP_INFO_DISABLED; @@ -2247,4 +2270,5 @@ bstp_destroy(struct bstp_port *bp) KASSERT(bp->bp_active == 0, ("port is still attached")); taskqueue_drain(taskqueue_swi, &bp->bp_statetask); taskqueue_drain(taskqueue_swi, &bp->bp_rtagetask); + taskqueue_drain(taskqueue_swi, &bp->bp_mediatask); } |