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 432