| Summary: | [if_bridge] [patch] two STP bridges have the same id | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | nvass | ||||||
| Component: | kern | Assignee: | Adrian Chadd <adrian> | ||||||
| Status: | Closed FIXED | ||||||||
| Severity: | Affects Only Me | ||||||||
| Priority: | Normal | ||||||||
| Version: | 10.0-CURRENT | ||||||||
| Hardware: | Any | ||||||||
| OS: | Any | ||||||||
| Attachments: |
|
||||||||
Responsible Changed From-To: freebsd-bugs->freebsd-net Responsible Changed From-To: freebsd-net->adrian I'll poke this. Hi Nikos, I have had a look at this patch. I originally ended up with the same change as OpenBSD made but I realised why you did it differently, to include all bridge ports and not just those with stp enabled. Here is a different version of your change, while it is more churn I think it ends up with more readable code. If the bridge port list is empty we jump straight out and avoid looping when 'bp' is always null. regards, Andrew On 2/23/2012 1:43 AM, Andrew Thompson wrote: > Hi Nikos, Hi Andrew, > I have had a look at this patch. I originally ended up with the same > change as OpenBSD made but I realised why you did it differently, to > include all bridge ports and not just those with stp enabled. > > Here is a different version of your change, while it is more churn I > think it ends up with more readable code. If the bridge port list is > empty we jump straight out and avoid looping when 'bp' is always null. I just tested your patch and it works as wanted. Could you please commit it? I would prefer the bridge id to be sticky, that is: Get the bridge id from the first ethernet added to the bridge and stick to it while it is a member of the bridge. This way there is going to be one topology change when the bridge enters the STP domain. If the said interface leaves the bridge(unlikely), the bridge will have to change its ID to another one. But I don't have time to look at it at the moment:( Plus the new behavior is good enough for me... Thanks, Nikos Author: thompsa Date: Fri Feb 24 17:50:36 2012 New Revision: 232118 URL: http://svn.freebsd.org/changeset/base/232118 Log: Only look for a usable MAC address for the bridge ID from ports within our bridge, this allows us to have more than one independent bridge in the same STP domain. PR: kern/164369 Submitted by: Nikos Vassiliadis (earlier version) MFC after: 2 weeks Modified: head/sys/net/bridgestp.c Modified: head/sys/net/bridgestp.c ============================================================================== --- head/sys/net/bridgestp.c Fri Feb 24 17:50:23 2012 (r232117) +++ head/sys/net/bridgestp.c Fri Feb 24 17:50:36 2012 (r232118) @@ -2013,24 +2013,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; @@ -2042,21 +2051,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 = @@ -2084,6 +2080,20 @@ bstp_reinit(struct bstp_state *bs) 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 _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" Could you close this PR? Author: thompsa Date: Sat May 26 07:35:44 2012 New Revision: 236048 URL: http://svn.freebsd.org/changeset/base/236048 Log: MFC r232118 Only look for a usable MAC address for the bridge ID from ports within our bridge, this allows us to have more than one independent bridge in the same STP domain. PR: kern/164369 Submitted by: Nikos Vassiliadis (earlier version) Modified: stable/9/sys/net/bridgestp.c Directory Properties: stable/9/sys/ (props changed) stable/9/sys/amd64/include/xen/ (props changed) stable/9/sys/boot/ (props changed) stable/9/sys/boot/i386/efi/ (props changed) stable/9/sys/boot/ia64/efi/ (props changed) stable/9/sys/boot/ia64/ski/ (props changed) stable/9/sys/boot/powerpc/boot1.chrp/ (props changed) stable/9/sys/boot/powerpc/ofw/ (props changed) stable/9/sys/cddl/contrib/opensolaris/ (props changed) stable/9/sys/conf/ (props changed) stable/9/sys/contrib/dev/acpica/ (props changed) stable/9/sys/contrib/octeon-sdk/ (props changed) stable/9/sys/contrib/pf/ (props changed) stable/9/sys/contrib/x86emu/ (props changed) stable/9/sys/dev/ (props changed) stable/9/sys/dev/e1000/ (props changed) stable/9/sys/dev/ixgbe/ (props changed) stable/9/sys/fs/ (props changed) stable/9/sys/fs/ntfs/ (props changed) stable/9/sys/modules/ (props changed) Modified: stable/9/sys/net/bridgestp.c ============================================================================== --- stable/9/sys/net/bridgestp.c Sat May 26 07:34:46 2012 (r236047) +++ stable/9/sys/net/bridgestp.c Sat May 26 07:35:44 2012 (r236048) @@ -2013,24 +2013,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; @@ -2042,21 +2051,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 = @@ -2084,6 +2080,20 @@ bstp_reinit(struct bstp_state *bs) 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 _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" Author: thompsa Date: Sat May 26 07:58:58 2012 New Revision: 236056 URL: http://svn.freebsd.org/changeset/base/236056 Log: MFC r232118 Only look for a usable MAC address for the bridge ID from ports within our bridge, this allows us to have more than one independent bridge in the same STP domain. PR: kern/164369 Submitted by: Nikos Vassiliadis (earlier version) Modified: stable/8/sys/net/bridgestp.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/boot/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/e1000/ (props changed) Modified: stable/8/sys/net/bridgestp.c ============================================================================== --- stable/8/sys/net/bridgestp.c Sat May 26 07:58:12 2012 (r236055) +++ stable/8/sys/net/bridgestp.c Sat May 26 07:58:58 2012 (r236056) @@ -2013,24 +2013,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; @@ -2042,21 +2051,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 = @@ -2084,6 +2080,20 @@ bstp_reinit(struct bstp_state *bs) 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 _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" This was fixed a long time ago |
The current code in STP selects the id of a bridge from all available ethernet ifnets regardless if they are part of the said bridge. This is problematic when more than one STP bridges exist, that is, more than one bridges will have the same bridge id. Fix: The MAC address candidates for the bridge id should be only from the bridge's members Patch attached with submission follows: How-To-Repeat: ifconfig bridge0 create ifconfig bridge1 create ifconfig bridge0 addm em0 addm em1 stp em0 stp em1 ifconfig bridge1 addm em2 addm em3 stp em2 stp em3 The resulting bridges are: bridge0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 02:46:61:bb:95:00 nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> id 08:00:27:0f:88:a5 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 08:00:27:0f:88:a5 priority 32768 ifcost 0 port 0 member: em1 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> ifmaxaddr 0 port 3 priority 128 path cost 20000 proto rstp role designated state discarding member: em0 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> ifmaxaddr 0 port 1 priority 128 path cost 20000 proto rstp role designated state discarding bridge1: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 02:46:61:bb:95:01 nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> id 08:00:27:0f:88:a5 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 08:00:27:0f:88:a5 priority 32768 ifcost 0 port 0 member: em3 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> ifmaxaddr 0 port 5 priority 128 path cost 20000 proto rstp role designated state discarding member: em2 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> ifmaxaddr 0 port 4 priority 128 path cost 20000 proto rstp role designated state discarding Both have the same id