1 /************************************************************************
2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
3 * Copyright (C) 2001-2003 Optical Access
6 * This file is part of RSTP library.
8 * RSTP library is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; version 2.1
12 * RSTP library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
15 * General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with RSTP library; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 **********************************************************************/
23 /* Port Role Selection state machine : 17.22 */
29 CHOOSE(INIT_BRIDGE), \
30 CHOOSE(ROLE_SELECTION), \
33 #define GET_STATE_NAME STP_rolesel_get_state_name
37 void stp_dbg_break_point (PORT_T
* port
, STPM_T
* stpm
)
43 _is_backup_port (PORT_T
* port
, STPM_T
* this)
45 if (!STP_VECT_compare_bridge_id
46 (&port
->portPrio
.design_bridge
, &this->BrId
)) {
47 #if 0 /* def STP_DBG */
48 if (port
->info
->debug
) {
49 STP_VECT_br_id_print ("portPrio.design_bridge",
50 &port
->portPrio
.design_bridge
, True
);
51 STP_VECT_br_id_print (" this->BrId",
54 stp_dbg_break_point (port
, this);
63 setRoleSelected (char* reason
, STPM_T
* stpm
, PORT_T
* port
,
68 port
->selectedRole
= newRole
;
70 if (newRole
== port
->role
)
75 new_role_name
= "Disabled";
78 new_role_name
= "Alternate";
81 new_role_name
= "Backup";
84 new_role_name
= "Root";
87 new_role_name
= "Designated";
90 new_role_name
= "NonStp";
94 stp_trace ("%s-%s:port %s => Unknown (%d ?)",
95 reason
, stpm
->name
, port
->port_name
, (int) newRole
);
100 if (port
->roletrns
->debug
)
101 stp_trace ("%s(%s-%s) => %s",
102 reason
, stpm
->name
, port
->port_name
, new_role_name
);
107 updtRoleDisableBridge (STPM_T
* this)
109 register PORT_T
*port
;
111 for (port
= this->ports
; port
; port
= port
->next
) {
112 port
->selectedRole
= DisabledPort
;
117 clearReselectBridge (STPM_T
* this)
119 register PORT_T
*port
;
121 for (port
= this->ports
; port
; port
= port
->next
) {
122 port
->reselect
= False
;
127 updtRootPrio (STATE_MACH_T
* this)
129 PRIO_VECTOR_T rootPathPrio
; /* 17.4.2.2 */
130 register PORT_T
*port
;
131 register STPM_T
*stpm
;
132 register unsigned int dm
;
134 stpm
= this->owner
.stpm
;
136 for (port
= stpm
->ports
; port
; port
= port
->next
) {
137 if (port
->admin_non_stp
) {
141 if (Disabled
== port
->infoIs
)
143 if (Aged
== port
->infoIs
)
145 if (Mine
== port
->infoIs
) {
146 #if 0 /* def STP_DBG */
147 stp_dbg_break_point (port
); /* for debugger break point */
152 STP_VECT_copy (&rootPathPrio
, &port
->portPrio
);
153 rootPathPrio
.root_path_cost
+= port
->operPCost
;
155 if (STP_VECT_compare_vector (&rootPathPrio
, &stpm
->rootPrio
) < 0) {
156 STP_VECT_copy (&stpm
->rootPrio
, &rootPathPrio
);
157 STP_copy_times (&stpm
->rootTimes
, &port
->portTimes
);
158 dm
= (8 + stpm
->rootTimes
.MaxAge
) / 16;
161 stpm
->rootTimes
.MessageAge
+= dm
;
163 if (port
->roletrns
->debug
)
164 stp_trace ("updtRootPrio: dm=%d rootTimes.MessageAge=%d on port %s",
165 (int) dm
, (int) stpm
->rootTimes
.MessageAge
,
173 updtRolesBridge (STATE_MACH_T
* this)
175 register PORT_T
* port
;
176 register STPM_T
* stpm
;
177 PORT_ID old_root_port
; /* for tracing of root port changing */
179 stpm
= this->owner
.stpm
;
180 old_root_port
= stpm
->rootPortId
;
182 STP_VECT_create (&stpm
->rootPrio
, &stpm
->BrId
, 0, &stpm
->BrId
, 0, 0);
183 STP_copy_times (&stpm
->rootTimes
, &stpm
->BrTimes
);
184 stpm
->rootPortId
= 0;
188 for (port
= stpm
->ports
; port
; port
= port
->next
) {
189 if (port
->admin_non_stp
) {
192 STP_VECT_create (&port
->designPrio
,
193 &stpm
->rootPrio
.root_bridge
,
194 stpm
->rootPrio
.root_path_cost
,
195 &stpm
->BrId
, port
->port_id
, port
->port_id
);
196 STP_copy_times (&port
->designTimes
, &stpm
->rootTimes
);
200 if (port
->roletrns
->debug
) {
201 STP_VECT_br_id_print ("ch:designPrio.design_bridge",
202 &port
->designPrio
.design_bridge
, True
);
208 stpm
->rootPortId
= stpm
->rootPrio
.bridge_port
;
211 if (old_root_port
!= stpm
->rootPortId
) {
212 if (! stpm
->rootPortId
) {
213 stp_trace ("\nbrige %s became root", stpm
->name
);
215 stp_trace ("\nbrige %s new root port: %s",
217 STP_stpm_get_port_name_by_id (stpm
, stpm
->rootPortId
));
222 for (port
= stpm
->ports
; port
; port
= port
->next
) {
223 if (port
->admin_non_stp
) {
224 setRoleSelected ("Non", stpm
, port
, NonStpPort
);
225 port
->forward
= port
->learn
= True
;
229 switch (port
->infoIs
) {
231 setRoleSelected ("Dis", stpm
, port
, DisabledPort
);
234 setRoleSelected ("Age", stpm
, port
, DesignatedPort
);
235 port
->updtInfo
= True
;
238 setRoleSelected ("Mine", stpm
, port
, DesignatedPort
);
239 if (0 != STP_VECT_compare_vector (&port
->portPrio
,
240 &port
->designPrio
) ||
241 0 != STP_compare_times (&port
->portTimes
,
242 &port
->designTimes
)) {
243 port
->updtInfo
= True
;
247 if (stpm
->rootPortId
== port
->port_id
) {
248 setRoleSelected ("Rec", stpm
, port
, RootPort
);
249 } else if (STP_VECT_compare_vector (&port
->designPrio
, &port
->portPrio
) < 0) {
250 /* Note: this important piece has been inserted after
251 * discussion with Mick Sieman and reading 802.1y Z1 */
252 setRoleSelected ("Rec", stpm
, port
, DesignatedPort
);
253 port
->updtInfo
= True
;
256 if (_is_backup_port (port
, stpm
)) {
257 setRoleSelected ("rec", stpm
, port
, BackupPort
);
259 setRoleSelected ("rec", stpm
, port
, AlternatePort
);
262 port
->updtInfo
= False
;
265 stp_trace ("undef infoIs=%d", (int) port
->infoIs
);
274 setSelectedBridge (STPM_T
* this)
276 register PORT_T
* port
;
278 for (port
= this->ports
; port
; port
= port
->next
) {
279 if (port
->reselect
) {
281 stp_trace ("setSelectedBridge: TRUE=reselect on port %s", port
->port_name
);
287 for (port
= this->ports
; port
; port
= port
->next
) {
288 port
->selected
= True
;
295 STP_rolesel_enter_state (STATE_MACH_T
* this)
299 stpm
= this->owner
.stpm
;
301 switch (this->State
) {
304 updtRoleDisableBridge (stpm
);
307 clearReselectBridge (stpm
);
308 updtRolesBridge (this);
309 setSelectedBridge (stpm
);
315 STP_rolesel_check_conditions (STATE_MACH_T
* s
)
318 register PORT_T
* port
;
320 if (BEGIN
== s
->State
) {
321 STP_hop_2_state (s
, INIT_BRIDGE
);
326 return STP_hop_2_state (s
, INIT_BRIDGE
);
328 return STP_hop_2_state (s
, ROLE_SELECTION
);
330 stpm
= s
->owner
.stpm
;
331 for (port
= stpm
->ports
; port
; port
= port
->next
) {
332 if (port
->reselect
) {
333 /* stp_trace ("reselect on port %s", port->port_name); */
334 return STP_hop_2_state (s
, ROLE_SELECTION
);
344 STP_rolesel_update_stpm (STPM_T
* this)
346 register PORT_T
* port
;
347 PRIO_VECTOR_T rootPathPrio
; /* 17.4.2.2 */
349 stp_trace ("%s", "??? STP_rolesel_update_stpm ???");
350 STP_VECT_create (&rootPathPrio
, &this->BrId
, 0, &this->BrId
, 0, 0);
352 if (!this->rootPortId
||
353 STP_VECT_compare_vector (&rootPathPrio
, &this->rootPrio
) < 0) {
354 STP_VECT_copy (&this->rootPrio
, &rootPathPrio
);
357 for (port
= this->ports
; port
; port
= port
->next
) {
358 STP_VECT_create (&port
->designPrio
,
359 &this->rootPrio
.root_bridge
,
360 this->rootPrio
.root_path_cost
,
361 &this->BrId
, port
->port_id
, port
->port_id
);
362 if (Received
!= port
->infoIs
|| this->rootPortId
== port
->port_id
) {
363 STP_VECT_copy (&port
->portPrio
, &port
->designPrio
);
365 port
->reselect
= True
;
366 port
->selected
= False
;