]>
Commit | Line | Data |
---|---|---|
ad02a0eb SH |
1 | /************************************************************************ |
2 | * RSTP library - Rapid Spanning Tree (802.1t, 802.1w) | |
3 | * Copyright (C) 2001-2003 Optical Access | |
4 | * Author: Alex Rozin | |
5 | * | |
6 | * This file is part of RSTP library. | |
7 | * | |
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 | |
11 | * | |
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. | |
16 | * | |
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 | |
20 | * 02111-1307, USA. | |
21 | **********************************************************************/ | |
22 | ||
23 | /* Port Role Transitions state machine : 17.24 */ | |
24 | ||
25 | #include "base.h" | |
26 | ||
27 | #include "stpm.h" | |
28 | ||
29 | #define STATES { \ | |
30 | CHOOSE(INIT_PORT), \ | |
31 | CHOOSE(BLOCK_PORT), \ | |
32 | CHOOSE(BLOCKED_PORT), \ | |
33 | CHOOSE(BACKUP_PORT), \ | |
34 | CHOOSE(ROOT_PROPOSED), \ | |
35 | CHOOSE(ROOT_AGREED), \ | |
36 | CHOOSE(REROOT), \ | |
37 | CHOOSE(ROOT_PORT), \ | |
38 | CHOOSE(REROOTED), \ | |
39 | CHOOSE(ROOT_LEARN), \ | |
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), \ | |
48 | } | |
49 | ||
50 | #define GET_STATE_NAME STP_roletrns_get_state_name | |
51 | #include "choose.h" | |
52 | ||
53 | static void | |
54 | setSyncBridge (STATE_MACH_T *this) | |
55 | { | |
56 | register PORT_T* port; | |
57 | ||
58 | for (port = this->owner.port->owner->ports; port; port = port->next) { | |
59 | port->sync = True; /* in ROOT_PROPOSED (setSyncBridge) */ | |
60 | } | |
61 | } | |
62 | ||
63 | static void | |
64 | setReRootBridge (STATE_MACH_T *this) | |
65 | { | |
66 | register PORT_T* port; | |
67 | ||
68 | for (port = this->owner.port->owner->ports; port; port = port->next) { | |
69 | port->reRoot = True; /* In setReRootBridge */ | |
70 | } | |
71 | } | |
72 | ||
73 | static Bool | |
74 | compute_all_synced (PORT_T* this) | |
75 | { | |
76 | register PORT_T* port; | |
77 | ||
78 | for (port = this->owner->ports; port; port = port->next) { | |
79 | if (port->port_index == this->port_index) continue; | |
80 | if (! port->synced) { | |
81 | return False; | |
82 | } | |
83 | } | |
84 | ||
85 | return True; | |
86 | } | |
87 | ||
88 | static Bool | |
89 | compute_re_rooted (PORT_T* this) | |
90 | { | |
91 | register PORT_T* port; | |
92 | ||
93 | for (port = this->owner->ports; port; port = port->next) { | |
94 | if (port->port_index == this->port_index) continue; | |
95 | if (port->rrWhile) { | |
96 | return False; | |
97 | } | |
98 | } | |
99 | return True; | |
100 | } | |
101 | ||
102 | void | |
103 | STP_roletrns_enter_state (STATE_MACH_T* this) | |
104 | { | |
105 | register PORT_T* port = this->owner.port; | |
106 | register STPM_T* stpm; | |
107 | ||
108 | stpm = port->owner; | |
109 | ||
110 | switch (this->State) { | |
111 | case BEGIN: | |
112 | case INIT_PORT: | |
113 | #if 0 /* due 802.1y Z.4 */ | |
114 | port->role = DisabledPort; | |
115 | #else | |
116 | port->role = port->selectedRole = DisabledPort; | |
117 | port->reselect = True; | |
118 | #endif | |
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; | |
124 | port->rbWhile = 0; | |
125 | #ifdef STP_DBG | |
126 | if (this->debug) | |
127 | STP_port_trace_flags ("after init", port); | |
128 | #endif | |
129 | break; | |
130 | case BLOCK_PORT: | |
131 | port->role = port->selectedRole; | |
132 | port->learn = | |
133 | port->forward = False; | |
134 | break; | |
135 | case BLOCKED_PORT: | |
136 | port->fdWhile = stpm->rootTimes.ForwardDelay; | |
137 | port->synced = True; /* In BLOCKED_PORT */ | |
138 | port->rrWhile = 0; | |
139 | port->sync = port->reRoot = False; /* BLOCKED_PORT */ | |
140 | break; | |
141 | case BACKUP_PORT: | |
142 | port->rbWhile = 2 * stpm->rootTimes.HelloTime; | |
143 | break; | |
144 | ||
145 | /* 17.23.2 */ | |
146 | case ROOT_PROPOSED: | |
147 | setSyncBridge (this); | |
148 | port->proposed = False; | |
149 | #ifdef STP_DBG | |
150 | if (this->debug) | |
151 | STP_port_trace_flags ("ROOT_PROPOSED", port); | |
152 | #endif | |
153 | break; | |
154 | case ROOT_AGREED: | |
155 | port->proposed = port->sync = False; /* in ROOT_AGREED */ | |
156 | port->synced = True; /* In ROOT_AGREED */ | |
157 | port->newInfo = True; | |
158 | #ifdef STP_DBG | |
159 | if (this->debug) | |
160 | STP_port_trace_flags ("ROOT_AGREED", port); | |
161 | #endif | |
162 | break; | |
163 | case REROOT: | |
164 | setReRootBridge (this); | |
165 | #ifdef STP_DBG | |
166 | if (this->debug) | |
167 | STP_port_trace_flags ("REROOT", port); | |
168 | #endif | |
169 | break; | |
170 | case ROOT_PORT: | |
171 | port->role = RootPort; | |
172 | port->rrWhile = stpm->rootTimes.ForwardDelay; | |
173 | #ifdef STP_DBG | |
174 | if (this->debug) | |
175 | STP_port_trace_flags ("ROOT_PORT", port); | |
176 | #endif | |
177 | break; | |
178 | case REROOTED: | |
179 | port->reRoot = False; /* In REROOTED */ | |
180 | #ifdef STP_DBG | |
181 | if (this->debug) | |
182 | STP_port_trace_flags ("REROOTED", port); | |
183 | #endif | |
184 | break; | |
185 | case ROOT_LEARN: | |
186 | port->fdWhile = stpm->rootTimes.ForwardDelay; | |
187 | port->learn = True; | |
188 | #ifdef STP_DBG | |
189 | if (this->debug) | |
190 | STP_port_trace_flags ("ROOT_LEARN", port); | |
191 | #endif | |
192 | break; | |
193 | case ROOT_FORWARD: | |
194 | port->fdWhile = 0; | |
195 | port->forward = True; | |
196 | #ifdef STP_DBG | |
197 | if (this->debug) | |
198 | STP_port_trace_flags ("ROOT_FORWARD", port); | |
199 | #endif | |
200 | break; | |
201 | ||
202 | /* 17.23.3 */ | |
203 | case DESIGNATED_PROPOSE: | |
204 | port->proposing = True; /* in DESIGNATED_PROPOSE */ | |
205 | port->newInfo = True; | |
206 | #ifdef STP_DBG | |
207 | if (this->debug) | |
208 | STP_port_trace_flags ("DESIGNATED_PROPOSE", port); | |
209 | #endif | |
210 | break; | |
211 | case DESIGNATED_SYNCED: | |
212 | port->rrWhile = 0; | |
213 | port->synced = True; /* DESIGNATED_SYNCED */ | |
214 | port->sync = False; /* DESIGNATED_SYNCED */ | |
215 | #ifdef STP_DBG | |
216 | if (this->debug) | |
217 | STP_port_trace_flags ("DESIGNATED_SYNCED", port); | |
218 | #endif | |
219 | break; | |
220 | case DESIGNATED_RETIRED: | |
221 | port->reRoot = False; /* DESIGNATED_RETIRED */ | |
222 | #ifdef STP_DBG | |
223 | if (this->debug) | |
224 | STP_port_trace_flags ("DESIGNATED_RETIRED", port); | |
225 | #endif | |
226 | break; | |
227 | case DESIGNATED_PORT: | |
228 | port->role = DesignatedPort; | |
229 | #ifdef STP_DBG | |
230 | if (this->debug) | |
231 | STP_port_trace_flags ("DESIGNATED_PORT", port); | |
232 | #endif | |
233 | break; | |
234 | case DESIGNATED_LISTEN: | |
235 | port->learn = port->forward = False; | |
236 | port->fdWhile = stpm->rootTimes.ForwardDelay; | |
237 | #ifdef STP_DBG | |
238 | if (this->debug) | |
239 | STP_port_trace_flags ("DESIGNATED_LISTEN", port); | |
240 | #endif | |
241 | break; | |
242 | case DESIGNATED_LEARN: | |
243 | port->learn = True; | |
244 | port->fdWhile = stpm->rootTimes.ForwardDelay; | |
245 | #ifdef STP_DBG | |
246 | if (this->debug) | |
247 | STP_port_trace_flags ("DESIGNATED_LEARN", port); | |
248 | #endif | |
249 | break; | |
250 | case DESIGNATED_FORWARD: | |
251 | port->forward = True; | |
252 | port->fdWhile = 0; | |
253 | #ifdef STP_DBG | |
254 | if (this->debug) | |
255 | STP_port_trace_flags ("DESIGNATED_FORWARD", port); | |
256 | #endif | |
257 | break; | |
258 | }; | |
259 | } | |
260 | ||
261 | Bool | |
262 | STP_roletrns_check_conditions (STATE_MACH_T* this) | |
263 | { | |
264 | register PORT_T *port = this->owner.port; | |
265 | register STPM_T *stpm; | |
266 | Bool allSynced; | |
267 | Bool allReRooted; | |
268 | ||
269 | stpm = port->owner; | |
270 | ||
271 | if (BEGIN == this->State) { | |
272 | return STP_hop_2_state (this, INIT_PORT); | |
273 | } | |
274 | ||
275 | if (port->role != port->selectedRole && | |
276 | port->selected && | |
277 | ! port->updtInfo) { | |
278 | switch (port->selectedRole) { | |
279 | case DisabledPort: | |
280 | case AlternatePort: | |
281 | case BackupPort: | |
282 | #if 0 /* def STP_DBG */ | |
283 | if (this->debug) { | |
284 | stp_trace ("hop to BLOCK_PORT role=%d selectedRole=%d", | |
285 | (int) port->role, (int) port->selectedRole); | |
286 | } | |
287 | #endif | |
288 | return STP_hop_2_state (this, BLOCK_PORT); | |
289 | case RootPort: | |
290 | return STP_hop_2_state (this, ROOT_PORT); | |
291 | case DesignatedPort: | |
292 | return STP_hop_2_state (this, DESIGNATED_PORT); | |
293 | default: | |
294 | return False; | |
295 | } | |
296 | } | |
297 | ||
298 | switch (this->State) { | |
299 | /* 17.23.1 */ | |
300 | case INIT_PORT: | |
301 | return STP_hop_2_state (this, BLOCK_PORT); | |
302 | case BLOCK_PORT: | |
303 | if (!port->selected || port->updtInfo) break; | |
304 | if (!port->learning && !port->forwarding) { | |
305 | return STP_hop_2_state (this, BLOCKED_PORT); | |
306 | } | |
307 | break; | |
308 | case BLOCKED_PORT: | |
309 | if (!port->selected || port->updtInfo) break; | |
310 | if (port->fdWhile != stpm->rootTimes.ForwardDelay || | |
311 | port->sync || | |
312 | port->reRoot || | |
313 | !port->synced) { | |
314 | return STP_hop_2_state (this, BLOCKED_PORT); | |
315 | } | |
316 | if (port->rbWhile != 2 * stpm->rootTimes.HelloTime && | |
317 | port->role == BackupPort) { | |
318 | return STP_hop_2_state (this, BACKUP_PORT); | |
319 | } | |
320 | break; | |
321 | case BACKUP_PORT: | |
322 | return STP_hop_2_state (this, BLOCKED_PORT); | |
323 | ||
324 | /* 17.23.2 */ | |
325 | case ROOT_PROPOSED: | |
326 | return STP_hop_2_state (this, ROOT_PORT); | |
327 | case ROOT_AGREED: | |
328 | return STP_hop_2_state (this, ROOT_PORT); | |
329 | case REROOT: | |
330 | return STP_hop_2_state (this, ROOT_PORT); | |
331 | case ROOT_PORT: | |
332 | if (!port->selected || port->updtInfo) break; | |
333 | if (!port->forward && !port->reRoot) { | |
334 | return STP_hop_2_state (this, REROOT); | |
335 | } | |
336 | allSynced = compute_all_synced (port); | |
337 | if ((port->proposed && allSynced) || | |
338 | (!port->synced && allSynced)) { | |
339 | return STP_hop_2_state (this, ROOT_AGREED); | |
340 | } | |
341 | if (port->proposed && !port->synced) { | |
342 | return STP_hop_2_state (this, ROOT_PROPOSED); | |
343 | } | |
344 | ||
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); | |
350 | } | |
351 | if ((!port->fdWhile || | |
352 | ((allReRooted && !port->rbWhile) && stpm->ForceVersion >=2)) && | |
353 | !port->learn) { | |
354 | return STP_hop_2_state (this, ROOT_LEARN); | |
355 | } | |
356 | ||
357 | if (port->reRoot && port->forward) { | |
358 | return STP_hop_2_state (this, REROOTED); | |
359 | } | |
360 | if (port->rrWhile != stpm->rootTimes.ForwardDelay) { | |
361 | return STP_hop_2_state (this, ROOT_PORT); | |
362 | } | |
363 | break; | |
364 | case REROOTED: | |
365 | return STP_hop_2_state (this, ROOT_PORT); | |
366 | case ROOT_LEARN: | |
367 | return STP_hop_2_state (this, ROOT_PORT); | |
368 | case ROOT_FORWARD: | |
369 | return STP_hop_2_state (this, ROOT_PORT); | |
370 | ||
371 | /* 17.23.3 */ | |
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; | |
380 | ||
381 | if (!port->forward && !port->agreed && !port->proposing && !port->operEdge) { | |
382 | return STP_hop_2_state (this, DESIGNATED_PROPOSE); | |
383 | } | |
384 | ||
385 | if (!port->rrWhile && port->reRoot) { | |
386 | return STP_hop_2_state (this, DESIGNATED_RETIRED); | |
387 | } | |
388 | ||
389 | if (!port->learning && !port->forwarding && !port->synced) { | |
390 | return STP_hop_2_state (this, DESIGNATED_SYNCED); | |
391 | } | |
392 | ||
393 | if (port->agreed && !port->synced) { | |
394 | return STP_hop_2_state (this, DESIGNATED_SYNCED); | |
395 | } | |
396 | if (port->operEdge && !port->synced) { | |
397 | return STP_hop_2_state (this, DESIGNATED_SYNCED); | |
398 | } | |
399 | if (port->sync && port->synced) { | |
400 | return STP_hop_2_state (this, DESIGNATED_SYNCED); | |
401 | } | |
402 | ||
403 | if ((!port->fdWhile || port->agreed || port->operEdge) && | |
404 | (!port->rrWhile || !port->reRoot) && | |
405 | !port->sync && | |
406 | (port->learn && !port->forward)) { | |
407 | return STP_hop_2_state (this, DESIGNATED_FORWARD); | |
408 | } | |
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); | |
413 | } | |
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); | |
418 | } | |
419 | break; | |
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); | |
426 | }; | |
427 | ||
428 | return False; | |
429 | } | |
430 | ||
431 |