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 */
27 #include "stp_vectors.h"
30 CHOOSE(INIT_BRIDGE), \
31 CHOOSE(ROLE_SELECTION) \
34 #define GET_STATE_NAME STP_rolesel_get_state_name
38 void stp_dbg_break_point (PORT_T
* port
, STPM_T
* stpm
)
44 _is_backup_port (PORT_T
* port
, STPM_T
* this)
46 if (!STP_VECT_compare_bridge_id
47 (&port
->portPrio
.design_bridge
, &this->BrId
)) {
48 #if 0 /* def STP_DBG */
49 if (port
->info
->debug
) {
50 STP_VECT_br_id_print ("portPrio.design_bridge",
51 &port
->portPrio
.design_bridge
, True
);
52 STP_VECT_br_id_print (" this->BrId",
55 stp_dbg_break_point (port
, this);
65 setRoleSelected (char* reason
, STPM_T
* stpm
, PORT_T
* port
,
72 port
->selectedRole
= newRole
;
74 if (newRole
== port
->role
)
80 new_role_name
= "Disabled";
85 new_role_name
= "Alternate";
90 new_role_name
= "Backup";
95 new_role_name
= "Root";
100 new_role_name
= "Designated";
105 new_role_name
= "NonStp";
107 port
->role
= newRole
;
111 stp_trace ("%s-%s:port %s => Unknown (%d ?)",
112 reason
, stpm
->name
, port
->port_name
, (int) newRole
);
120 if (port
->roletrns
->debug
)
121 stp_trace ("%s(%s-%s) => %s",
122 reason
, stpm
->name
, port
->port_name
, new_role_name
);
127 updtRoleDisableBridge (STPM_T
* this)
129 register PORT_T
*port
;
131 for (port
= this->ports
; port
; port
= port
->next
) {
132 port
->selectedRole
= DisabledPort
;
137 clearReselectBridge (STPM_T
* this)
139 register PORT_T
*port
;
141 for (port
= this->ports
; port
; port
= port
->next
) {
142 port
->reselect
= False
;
147 updtRootPrio (STATE_MACH_T
* this)
149 PRIO_VECTOR_T rootPathPrio
; /* 17.4.2.2 */
150 register PORT_T
*port
;
151 register STPM_T
*stpm
;
152 register unsigned int dm
;
154 stpm
= this->owner
.stpm
;
156 for (port
= stpm
->ports
; port
; port
= port
->next
) {
157 if (port
->admin_non_stp
) {
161 if (Disabled
== port
->infoIs
)
163 if (Aged
== port
->infoIs
)
165 if (Mine
== port
->infoIs
) {
166 #if 0 /* def STP_DBG */
167 stp_dbg_break_point (port
); /* for debugger break point */
172 STP_VECT_copy (&rootPathPrio
, &port
->portPrio
);
173 rootPathPrio
.root_path_cost
+= port
->operPCost
;
175 if (STP_VECT_compare_vector (&rootPathPrio
, &stpm
->rootPrio
) < 0) {
176 STP_VECT_copy (&stpm
->rootPrio
, &rootPathPrio
);
177 STP_copy_times (&stpm
->rootTimes
, &port
->portTimes
);
178 dm
= (8 + stpm
->rootTimes
.MaxAge
) / 16;
181 stpm
->rootTimes
.MessageAge
+= dm
;
183 if (port
->roletrns
->debug
)
184 stp_trace ("updtRootPrio: dm=%d rootTimes.MessageAge=%d on port %s",
185 (int) dm
, (int) stpm
->rootTimes
.MessageAge
,
193 updtRolesBridge (STATE_MACH_T
* this)
195 register PORT_T
* port
;
196 register STPM_T
* stpm
;
198 PORT_ID old_root_port
; /* for tracing of root port changing */
201 stpm
= this->owner
.stpm
;
203 old_root_port
= stpm
->rootPortId
;
206 STP_VECT_create (&stpm
->rootPrio
, &stpm
->BrId
, 0, &stpm
->BrId
, 0, 0);
207 STP_copy_times (&stpm
->rootTimes
, &stpm
->BrTimes
);
208 stpm
->rootPortId
= 0;
212 for (port
= stpm
->ports
; port
; port
= port
->next
) {
213 if (port
->admin_non_stp
) {
216 STP_VECT_create (&port
->designPrio
,
217 &stpm
->rootPrio
.root_bridge
,
218 stpm
->rootPrio
.root_path_cost
,
219 &stpm
->BrId
, port
->port_id
, port
->port_id
);
220 STP_copy_times (&port
->designTimes
, &stpm
->rootTimes
);
224 if (port
->roletrns
->debug
) {
225 STP_VECT_br_id_print ("ch:designPrio.design_bridge",
226 &port
->designPrio
.design_bridge
, True
);
232 stpm
->rootPortId
= stpm
->rootPrio
.bridge_port
;
235 if (old_root_port
!= stpm
->rootPortId
) {
236 if (! stpm
->rootPortId
) {
237 stp_trace ("bridge %s became root", stpm
->name
);
239 stp_trace ("bridge %s new root port: %s",
241 STP_stpm_get_port_name_by_id (stpm
, stpm
->rootPortId
));
246 for (port
= stpm
->ports
; port
; port
= port
->next
) {
247 if (port
->admin_non_stp
) {
248 setRoleSelected ("Non", stpm
, port
, NonStpPort
);
249 port
->forward
= port
->learn
= True
;
253 switch (port
->infoIs
) {
255 setRoleSelected ("Dis", stpm
, port
, DisabledPort
);
258 setRoleSelected ("Age", stpm
, port
, DesignatedPort
);
259 port
->updtInfo
= True
;
262 setRoleSelected ("Mine", stpm
, port
, DesignatedPort
);
263 if (0 != STP_VECT_compare_vector (&port
->portPrio
,
264 &port
->designPrio
) ||
265 0 != STP_compare_times (&port
->portTimes
,
266 &port
->designTimes
)) {
267 port
->updtInfo
= True
;
271 if (stpm
->rootPortId
== port
->port_id
) {
272 setRoleSelected ("Rec", stpm
, port
, RootPort
);
273 } else if (STP_VECT_compare_vector (&port
->designPrio
, &port
->portPrio
) < 0) {
274 /* Note: this important piece has been inserted after
275 * discussion with Mick Sieman and reading 802.1y Z1 */
276 setRoleSelected ("Rec", stpm
, port
, DesignatedPort
);
277 port
->updtInfo
= True
;
280 if (_is_backup_port (port
, stpm
)) {
281 setRoleSelected ("rec", stpm
, port
, BackupPort
);
283 setRoleSelected ("rec", stpm
, port
, AlternatePort
);
286 port
->updtInfo
= False
;
289 stp_trace ("undef infoIs=%d", (int) port
->infoIs
);
298 setSelectedBridge (STPM_T
* this)
300 register PORT_T
* port
;
302 for (port
= this->ports
; port
; port
= port
->next
) {
303 if (port
->reselect
) {
305 stp_trace ("setSelectedBridge: TRUE=reselect on port %s", port
->port_name
);
311 for (port
= this->ports
; port
; port
= port
->next
) {
312 port
->selected
= True
;
319 STP_rolesel_enter_state (STATE_MACH_T
* this)
323 stpm
= this->owner
.stpm
;
325 switch (this->State
) {
328 updtRoleDisableBridge (stpm
);
331 clearReselectBridge (stpm
);
332 updtRolesBridge (this);
333 (void) setSelectedBridge (stpm
);
339 STP_rolesel_check_conditions (STATE_MACH_T
* s
)
342 register PORT_T
* port
;
345 * This doesn't look right. Why should we hop state twice in a single check
346 * condition call? It means we can never perform the enter-state action for
349 #ifdef carlsonj_removed
350 if (BEGIN
== s
->State
) {
351 (void) STP_hop_2_state (s
, INIT_BRIDGE
);
357 return STP_hop_2_state (s
, INIT_BRIDGE
);
359 return STP_hop_2_state (s
, ROLE_SELECTION
);
361 stpm
= s
->owner
.stpm
;
362 for (port
= stpm
->ports
; port
; port
= port
->next
) {
363 if (port
->reselect
) {
364 /* stp_trace ("reselect on port %s", port->port_name); */
365 return STP_hop_2_state (s
, ROLE_SELECTION
);
375 STP_rolesel_update_stpm (STPM_T
* this)
377 register PORT_T
* port
;
378 PRIO_VECTOR_T rootPathPrio
; /* 17.4.2.2 */
380 stp_trace ("%s", "??? STP_rolesel_update_stpm ???");
381 STP_VECT_create (&rootPathPrio
, &this->BrId
, 0, &this->BrId
, 0, 0);
383 if (!this->rootPortId
||
384 STP_VECT_compare_vector (&rootPathPrio
, &this->rootPrio
) < 0) {
385 STP_VECT_copy (&this->rootPrio
, &rootPathPrio
);
388 for (port
= this->ports
; port
; port
= port
->next
) {
389 STP_VECT_create (&port
->designPrio
,
390 &this->rootPrio
.root_bridge
,
391 this->rootPrio
.root_path_cost
,
392 &this->BrId
, port
->port_id
, port
->port_id
);
393 if (Received
!= port
->infoIs
|| this->rootPortId
== port
->port_id
) {
394 STP_VECT_copy (&port
->portPrio
, &port
->designPrio
);
396 port
->reselect
= True
;
397 port
->selected
= False
;