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 Transitions state machine : 17.24 */
32 CHOOSE(BLOCKED_PORT), \
33 CHOOSE(BACKUP_PORT), \
34 CHOOSE(ROOT_PROPOSED), \
35 CHOOSE(ROOT_AGREED), \
40 CHOOSE(ROOT_FORWARD), \
41 CHOOSE(DESIGNATED_PROPOSE), \
42 CHOOSE(DESIGNATED_SYNCED), \
43 CHOOSE(DESIGNATED_RETIRED), \
44 CHOOSE(DESIGNATED_PORT), \
45 CHOOSE(DESIGNATED_LISTEN), \
46 CHOOSE(DESIGNATED_LEARN), \
47 CHOOSE(DESIGNATED_FORWARD) \
50 #define GET_STATE_NAME STP_roletrns_get_state_name
54 setSyncBridge (STATE_MACH_T
*this)
56 register PORT_T
* port
;
58 for (port
= this->owner
.port
->owner
->ports
; port
; port
= port
->next
) {
59 port
->sync
= True
; /* in ROOT_PROPOSED (setSyncBridge) */
64 setReRootBridge (STATE_MACH_T
*this)
66 register PORT_T
* port
;
68 for (port
= this->owner
.port
->owner
->ports
; port
; port
= port
->next
) {
69 port
->reRoot
= True
; /* In setReRootBridge */
74 compute_all_synced (PORT_T
* this)
76 register PORT_T
* port
;
78 for (port
= this->owner
->ports
; port
; port
= port
->next
) {
79 if (port
->port_index
== this->port_index
) continue;
89 compute_re_rooted (PORT_T
* this)
91 register PORT_T
* port
;
93 for (port
= this->owner
->ports
; port
; port
= port
->next
) {
94 if (port
->port_index
== this->port_index
) continue;
103 STP_roletrns_enter_state (STATE_MACH_T
* this)
105 register PORT_T
* port
= this->owner
.port
;
106 register STPM_T
* stpm
;
110 switch (this->State
) {
113 #if 0 /* due 802.1y Z.4 */
114 port
->role
= DisabledPort
;
116 port
->role
= port
->selectedRole
= DisabledPort
;
117 port
->reselect
= True
;
119 port
->synced
= False
; /* in INIT */
120 port
->sync
= True
; /* in INIT */
121 port
->reRoot
= True
; /* in INIT_PORT */
122 port
->rrWhile
= stpm
->rootTimes
.ForwardDelay
;
123 port
->fdWhile
= stpm
->rootTimes
.ForwardDelay
;
127 STP_port_trace_flags ("after init", port
);
131 port
->role
= port
->selectedRole
;
133 port
->forward
= False
;
136 port
->fdWhile
= stpm
->rootTimes
.ForwardDelay
;
137 port
->synced
= True
; /* In BLOCKED_PORT */
139 port
->sync
= port
->reRoot
= False
; /* BLOCKED_PORT */
142 port
->rbWhile
= 2 * stpm
->rootTimes
.HelloTime
;
147 setSyncBridge (this);
148 port
->proposed
= False
;
151 STP_port_trace_flags ("ROOT_PROPOSED", port
);
155 port
->proposed
= port
->sync
= False
; /* in ROOT_AGREED */
156 port
->synced
= True
; /* In ROOT_AGREED */
157 port
->newInfo
= True
;
160 STP_port_trace_flags ("ROOT_AGREED", port
);
164 setReRootBridge (this);
167 STP_port_trace_flags ("REROOT", port
);
171 port
->role
= RootPort
;
172 port
->rrWhile
= stpm
->rootTimes
.ForwardDelay
;
175 STP_port_trace_flags ("ROOT_PORT", port
);
179 port
->reRoot
= False
; /* In REROOTED */
182 STP_port_trace_flags ("REROOTED", port
);
186 port
->fdWhile
= stpm
->rootTimes
.ForwardDelay
;
190 STP_port_trace_flags ("ROOT_LEARN", port
);
195 port
->forward
= True
;
198 STP_port_trace_flags ("ROOT_FORWARD", port
);
203 case DESIGNATED_PROPOSE
:
204 port
->proposing
= True
; /* in DESIGNATED_PROPOSE */
205 port
->newInfo
= True
;
208 STP_port_trace_flags ("DESIGNATED_PROPOSE", port
);
211 case DESIGNATED_SYNCED
:
213 port
->synced
= True
; /* DESIGNATED_SYNCED */
214 port
->sync
= False
; /* DESIGNATED_SYNCED */
217 STP_port_trace_flags ("DESIGNATED_SYNCED", port
);
220 case DESIGNATED_RETIRED
:
221 port
->reRoot
= False
; /* DESIGNATED_RETIRED */
224 STP_port_trace_flags ("DESIGNATED_RETIRED", port
);
227 case DESIGNATED_PORT
:
228 port
->role
= DesignatedPort
;
231 STP_port_trace_flags ("DESIGNATED_PORT", port
);
234 case DESIGNATED_LISTEN
:
235 port
->learn
= port
->forward
= False
;
236 port
->fdWhile
= stpm
->rootTimes
.ForwardDelay
;
239 STP_port_trace_flags ("DESIGNATED_LISTEN", port
);
242 case DESIGNATED_LEARN
:
244 port
->fdWhile
= stpm
->rootTimes
.ForwardDelay
;
247 STP_port_trace_flags ("DESIGNATED_LEARN", port
);
250 case DESIGNATED_FORWARD
:
251 port
->forward
= True
;
255 STP_port_trace_flags ("DESIGNATED_FORWARD", port
);
262 STP_roletrns_check_conditions (STATE_MACH_T
* this)
264 register PORT_T
*port
= this->owner
.port
;
265 register STPM_T
*stpm
;
271 if (BEGIN
== this->State
) {
272 return STP_hop_2_state (this, INIT_PORT
);
275 if (port
->role
!= port
->selectedRole
&&
278 switch (port
->selectedRole
) {
282 #if 0 /* def STP_DBG */
284 stp_trace ("hop to BLOCK_PORT role=%d selectedRole=%d",
285 (int) port
->role
, (int) port
->selectedRole
);
288 return STP_hop_2_state (this, BLOCK_PORT
);
290 return STP_hop_2_state (this, ROOT_PORT
);
292 return STP_hop_2_state (this, DESIGNATED_PORT
);
298 switch (this->State
) {
301 return STP_hop_2_state (this, BLOCK_PORT
);
303 if (!port
->selected
|| port
->updtInfo
) break;
304 if (!port
->learning
&& !port
->forwarding
) {
305 return STP_hop_2_state (this, BLOCKED_PORT
);
309 if (!port
->selected
|| port
->updtInfo
) break;
310 if (port
->fdWhile
!= stpm
->rootTimes
.ForwardDelay
||
314 return STP_hop_2_state (this, BLOCKED_PORT
);
316 if (port
->rbWhile
!= 2 * stpm
->rootTimes
.HelloTime
&&
317 port
->role
== BackupPort
) {
318 return STP_hop_2_state (this, BACKUP_PORT
);
322 return STP_hop_2_state (this, BLOCKED_PORT
);
326 return STP_hop_2_state (this, ROOT_PORT
);
328 return STP_hop_2_state (this, ROOT_PORT
);
330 return STP_hop_2_state (this, ROOT_PORT
);
332 if (!port
->selected
|| port
->updtInfo
) break;
333 if (!port
->forward
&& !port
->reRoot
) {
334 return STP_hop_2_state (this, REROOT
);
336 allSynced
= compute_all_synced (port
);
337 if ((port
->proposed
&& allSynced
) ||
338 (!port
->synced
&& allSynced
)) {
339 return STP_hop_2_state (this, ROOT_AGREED
);
341 if (port
->proposed
&& !port
->synced
) {
342 return STP_hop_2_state (this, ROOT_PROPOSED
);
345 allReRooted
= compute_re_rooted (port
);
346 if ((!port
->fdWhile
||
347 ((allReRooted
&& !port
->rbWhile
) && stpm
->ForceVersion
>=2)) &&
348 port
->learn
&& !port
->forward
) {
349 return STP_hop_2_state (this, ROOT_FORWARD
);
351 if ((!port
->fdWhile
||
352 ((allReRooted
&& !port
->rbWhile
) && stpm
->ForceVersion
>=2)) &&
354 return STP_hop_2_state (this, ROOT_LEARN
);
357 if (port
->reRoot
&& port
->forward
) {
358 return STP_hop_2_state (this, REROOTED
);
360 if (port
->rrWhile
!= stpm
->rootTimes
.ForwardDelay
) {
361 return STP_hop_2_state (this, ROOT_PORT
);
365 return STP_hop_2_state (this, ROOT_PORT
);
367 return STP_hop_2_state (this, ROOT_PORT
);
369 return STP_hop_2_state (this, ROOT_PORT
);
372 case DESIGNATED_PROPOSE
:
373 return STP_hop_2_state (this, DESIGNATED_PORT
);
374 case DESIGNATED_SYNCED
:
375 return STP_hop_2_state (this, DESIGNATED_PORT
);
376 case DESIGNATED_RETIRED
:
377 return STP_hop_2_state (this, DESIGNATED_PORT
);
378 case DESIGNATED_PORT
:
379 if (!port
->selected
|| port
->updtInfo
) break;
381 if (!port
->forward
&& !port
->agreed
&& !port
->proposing
&& !port
->operEdge
) {
382 return STP_hop_2_state (this, DESIGNATED_PROPOSE
);
385 if (!port
->rrWhile
&& port
->reRoot
) {
386 return STP_hop_2_state (this, DESIGNATED_RETIRED
);
389 if (!port
->learning
&& !port
->forwarding
&& !port
->synced
) {
390 return STP_hop_2_state (this, DESIGNATED_SYNCED
);
393 if (port
->agreed
&& !port
->synced
) {
394 return STP_hop_2_state (this, DESIGNATED_SYNCED
);
396 if (port
->operEdge
&& !port
->synced
) {
397 return STP_hop_2_state (this, DESIGNATED_SYNCED
);
399 if (port
->sync
&& port
->synced
) {
400 return STP_hop_2_state (this, DESIGNATED_SYNCED
);
403 if ((!port
->fdWhile
|| port
->agreed
|| port
->operEdge
) &&
404 (!port
->rrWhile
|| !port
->reRoot
) &&
406 (port
->learn
&& !port
->forward
)) {
407 return STP_hop_2_state (this, DESIGNATED_FORWARD
);
409 if ((!port
->fdWhile
|| port
->agreed
|| port
->operEdge
) &&
410 (!port
->rrWhile
|| !port
->reRoot
) &&
411 !port
->sync
&& !port
->learn
) {
412 return STP_hop_2_state (this, DESIGNATED_LEARN
);
414 if (((port
->sync
&& !port
->synced
) ||
415 (port
->reRoot
&& port
->rrWhile
)) &&
416 !port
->operEdge
&& (port
->learn
|| port
->forward
)) {
417 return STP_hop_2_state (this, DESIGNATED_LISTEN
);
420 case DESIGNATED_LISTEN
:
421 return STP_hop_2_state (this, DESIGNATED_PORT
);
422 case DESIGNATED_LEARN
:
423 return STP_hop_2_state (this, DESIGNATED_PORT
);
424 case DESIGNATED_FORWARD
:
425 return STP_hop_2_state (this, DESIGNATED_PORT
);