1 /* 2 * mstp.c State machines from IEEE 802.1Q-2005 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Vitalii Demianets <dvitasgs@gmail.com> 10 */ 11 12 /* NOTE: The standard messes up Hello_Time timer management. 13 * The portTimes and msgTimes structures have it, while 14 * designatedTimes, rootTimes and BridgeTimes do not! 15 * And there are places, where standard says: 16 * "portTimes = designatedTimes" (13.32) 17 * "rootTimes = portTimes" (13.26.23) 18 * ---- Bad IEEE! ---- 19 * For now I decide: All structures will hold Hello_Time, 20 * because in 802.1D they do. 21 * Besides, it is necessary for compatibility with old STP implementations. 22 */ 23 24 /* 802.1Q-2005 does not define but widely use variable name newInfoXst. 25 * From the 802.1s I can guess that it means: 26 * - "newInfo" when tree is CIST; 27 * - "newInfoMsti" when tree is not CIST (is MSTI). 28 * But that is only a guess and I could be wrong here ;) 29 */ 30 31 /* Important coding convention: 32 * All functions that have dry_run argument must follow the 33 * return value convention: 34 * They should return true if state change detected during dry run. 35 * Otherwise (!dry_run || !state_change) they return false. 36 */ 37 38 #include <config.h> 39 40 #include <string.h> 41 #include <netinet/in.h> 42 #include <linux/if_bridge.h> 43 #include <asm/byteorder.h> 44 #include <time.h> 45 #include <sys/time.h> 46 47 #include "mstp.h" 48 #include "log.h" 49 #include "driver.h" 50 51 static void PTSM_tick(port_t *prt); 52 static bool TCSM_run(per_tree_port_t *ptp, bool dry_run); 53 static void BDSM_begin(port_t *prt); 54 static void br_state_machines_begin(bridge_t *br); 55 static void prt_state_machines_begin(port_t *prt); 56 static void tree_state_machines_begin(tree_t *tree); 57 static void br_state_machines_run(bridge_t *br); 58 static void updtbrAssuRcvdInfoWhile(port_t *prt); 59 60 #define FOREACH_PORT_IN_BRIDGE(port, bridge) \ 61 list_for_each_entry((port), &(bridge)->ports, br_list) 62 #define FOREACH_TREE_IN_BRIDGE(tree, bridge) \ 63 list_for_each_entry((tree), &(bridge)->trees, bridge_list) 64 #define FOREACH_PTP_IN_TREE(ptp, tree) \ 65 list_for_each_entry((ptp), &(tree)->ports, tree_list) 66 #define FOREACH_PTP_IN_PORT(ptp, port) \ 67 list_for_each_entry((ptp), &(port)->trees, port_list) 68 69 /* 17.20.11 of 802.1D */ 70 #define rstpVersion(br) ((br)->ForceProtocolVersion >= protoRSTP) 71 /* Bridge assurance is operational only when NetworkPort type is configured 72 * and the operation status is pointToPoint and version is RSTP/MSTP 73 */ 74 #define assurancePort(prt) ((prt)->NetworkPort && (prt)->operPointToPointMAC \ 75 && (prt)->sendRSTP) 76 /* 77 * Recalculate configuration digest. (13.7) 78 */ 79 static void RecalcConfigDigest(bridge_t *br) 80 { 81 __be16 vid2mstid[MAX_VID + 2]; 82 unsigned char mstp_key[] = HMAC_KEY; 83 int vid; 84 85 vid2mstid[0] = vid2mstid[MAX_VID + 1] = 0; 86 for(vid = 1; vid <= MAX_VID; ++vid) 87 vid2mstid[vid] = br->fid2mstid[br->vid2fid[vid]]; 88 89 hmac_md5((void *)vid2mstid, sizeof(vid2mstid), mstp_key, sizeof(mstp_key), 90 (caddr_t)br->MstConfigId.s.configuration_digest); 91 } 92 93 /* 94 * 13.37.1 - Table 13-3 95 */ 96 static __u32 compute_pcost(int speed) 97 { 98 /* speed is in MB/s*/ 99 if(speed > 0) 100 return (speed < 20000000) ? 20000000 / speed : 1; 101 else 102 return MAX_PATH_COST; 103 } 104 105 static void bridge_default_internal_vars(bridge_t *br) 106 { 107 br->uptime = 0; 108 } 109 110 static void tree_default_internal_vars(tree_t *tree) 111 { 112 /* 12.8.1.1.3.(b,c,d) */ 113 tree->time_since_topology_change = 0; 114 tree->topology_change_count = 0; 115 tree->topology_change = false; /* since all tcWhile are initialized to 0 */ 116 strncpy(tree->topology_change_port, "None", IFNAMSIZ); 117 strncpy(tree->last_topology_change_port, "None", IFNAMSIZ); 118 119 /* The following are initialized in BEGIN state: 120 * - rootPortId, rootPriority, rootTimes: in Port Role Selection SM 121 */ 122 } 123 124 static void port_default_internal_vars(port_t *prt) 125 { 126 prt->infoInternal = false; 127 prt->rcvdInternal = false; 128 prt->rcvdTcAck = false; 129 prt->rcvdTcn = false; 130 assign(prt->rapidAgeingWhile, 0u); 131 assign(prt->brAssuRcvdInfoWhile, 0u); 132 prt->BaInconsistent = false; 133 prt->num_rx_bpdu_filtered = 0; 134 prt->num_rx_bpdu = 0; 135 prt->num_rx_tcn = 0; 136 prt->num_tx_bpdu = 0; 137 prt->num_tx_tcn = 0; 138 prt->num_trans_fwd = 0; 139 prt->num_trans_blk = 0; 140 141 /* The following are initialized in BEGIN state: 142 * - mdelayWhile. mcheck, sendRSTP: in Port Protocol Migration SM 143 * - helloWhen, newInfo, newInfoMsti, txCount: in Port Transmit SM 144 * - edgeDelayWhile, rcvdBpdu, rcvdRSTP, rcvdSTP : in Port Receive SM 145 * - operEdge: in Bridge Detection SM 146 * - tcAck: in Topology Change SM 147 */ 148 } 149 150 static void ptp_default_internal_vars(per_tree_port_t *ptp) 151 { 152 ptp->rcvdTc = false; 153 ptp->tcProp = false; 154 ptp->updtInfo = false; 155 ptp->master = false; /* 13.24.5 */ 156 ptp->disputed = false; 157 assign(ptp->rcvdInfo, (port_info_t)0); 158 ptp->mastered = false; 159 memset(&ptp->msgPriority, 0, sizeof(ptp->msgPriority)); 160 memset(&ptp->msgTimes, 0, sizeof(ptp->msgTimes)); 161 162 /* The following are initialized in BEGIN state: 163 * - rcvdMsg: in Port Receive SM 164 * - fdWhile, rrWhile, rbWhile, role, learn, forward, 165 * sync, synced, reRoot: in Port Role Transitions SM 166 * - tcWhile, fdbFlush: Topology Change SM 167 * - rcvdInfoWhile, proposed, proposing, agree, agreed, 168 * infoIs, reselect, selected: Port Information SM 169 * - forwarding, learning: Port State Transition SM 170 * - selectedRole, designatedPriority, designatedTimes: Port Role Selection SM 171 */ 172 } 173 174 static tree_t * create_tree(bridge_t *br, __u8 *macaddr, __be16 MSTID) 175 { 176 /* Initialize all fields except anchor */ 177 tree_t *tree = calloc(1, sizeof(*tree)); 178 if(!tree) 179 { 180 ERROR_BRNAME(br, "Out of memory"); 181 return NULL; 182 } 183 tree->bridge = br; 184 tree->MSTID = MSTID; 185 INIT_LIST_HEAD(&tree->ports); 186 187 memcpy(tree->BridgeIdentifier.s.mac_address, macaddr, ETH_ALEN); 188 /* 0x8000 = default bridge priority (17.14 of 802.1D) */ 189 tree->BridgeIdentifier.s.priority = __constant_cpu_to_be16(0x8000) | MSTID; 190 assign(tree->BridgePriority.RootID, tree->BridgeIdentifier); 191 assign(tree->BridgePriority.RRootID, tree->BridgeIdentifier); 192 assign(tree->BridgePriority.DesignatedBridgeID, tree->BridgeIdentifier); 193 /* 13.23.4 */ 194 assign(tree->BridgeTimes.remainingHops, br->MaxHops); 195 assign(tree->BridgeTimes.Forward_Delay, br->Forward_Delay); 196 assign(tree->BridgeTimes.Max_Age, br->Max_Age); 197 assign(tree->BridgeTimes.Message_Age, (__u8)0); 198 assign(tree->BridgeTimes.Hello_Time, br->Hello_Time); 199 200 tree_default_internal_vars(tree); 201 202 return tree; 203 } 204 205 static per_tree_port_t * create_ptp(tree_t *tree, port_t *prt) 206 { 207 /* Initialize all fields except anchors */ 208 per_tree_port_t *ptp = calloc(1, sizeof(*ptp)); 209 if(!ptp) 210 { 211 ERROR_PRTNAME(prt->bridge, prt, "Out of memory"); 212 return NULL; 213 } 214 ptp->port = prt; 215 ptp->tree = tree; 216 ptp->MSTID = tree->MSTID; 217 218 ptp->state = BR_STATE_DISABLED; 219 /* 0x80 = default port priority (17.14 of 802.1D) */ 220 ptp->portId = __constant_cpu_to_be16(0x8000) | prt->port_number; 221 assign(ptp->AdminInternalPortPathCost, 0u); 222 assign(ptp->InternalPortPathCost, compute_pcost(GET_PORT_SPEED(prt))); 223 /* 802.1Q leaves portPriority and portTimes uninitialized */ 224 assign(ptp->portPriority, tree->BridgePriority); 225 assign(ptp->portTimes, tree->BridgeTimes); 226 227 ptp->calledFromFlushRoutine = false; 228 229 ptp_default_internal_vars(ptp); 230 231 return ptp; 232 } 233 234 /* External events */ 235 236 bool MSTP_IN_bridge_create(bridge_t *br, __u8 *macaddr) 237 { 238 tree_t *cist; 239 240 if (!driver_create_bridge(br, macaddr)) 241 return false; 242 243 /* Initialize all fields except sysdeps and anchor */ 244 INIT_LIST_HEAD(&br->ports); 245 INIT_LIST_HEAD(&br->trees); 246 br->bridgeEnabled = false; 247 memset(br->vid2fid, 0, sizeof(br->vid2fid)); 248 memset(br->fid2mstid, 0, sizeof(br->fid2mstid)); 249 assign(br->MstConfigId.s.selector, (__u8)0); 250 sprintf((char *)br->MstConfigId.s.configuration_name, 251 "%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", 252 macaddr[0], macaddr[1], macaddr[2], 253 macaddr[3], macaddr[4], macaddr[5]); 254 assign(br->MstConfigId.s.revision_level, __constant_cpu_to_be16(0)); 255 RecalcConfigDigest(br); /* set br->MstConfigId.s.configuration_digest */ 256 br->ForceProtocolVersion = protoRSTP; 257 assign(br->MaxHops, (__u8)20); /* 13.37.3 */ 258 assign(br->Forward_Delay, (__u8)15); /* 17.14 of 802.1D */ 259 assign(br->Max_Age, (__u8)20); /* 17.14 of 802.1D */ 260 assign(br->Transmit_Hold_Count, 6u); /* 17.14 of 802.1D */ 261 assign(br->Migrate_Time, 3u); /* 17.14 of 802.1D */ 262 assign(br->Ageing_Time, 300u);/* 8.8.3 Table 8-3 */ 263 assign(br->Hello_Time, (__u8)2); /* 17.14 of 802.1D */ 264 265 bridge_default_internal_vars(br); 266 267 /* Create CIST */ 268 if(!(cist = create_tree(br, macaddr, 0))) 269 return false; 270 list_add_tail(&cist->bridge_list, &br->trees); 271 272 return true; 273 } 274 275 bool MSTP_IN_port_create_and_add_tail(port_t *prt, __u16 portno) 276 { 277 tree_t *tree; 278 per_tree_port_t *ptp, *nxt; 279 bridge_t *br = prt->bridge; 280 281 if (!driver_create_port(prt, portno)) 282 return false; 283 284 /* Initialize all fields except sysdeps and bridge */ 285 INIT_LIST_HEAD(&prt->trees); 286 prt->port_number = __cpu_to_be16(portno); 287 288 assign(prt->AdminExternalPortPathCost, 0u); 289 /* Default for operP2P is false because by default AdminP2P 290 * says to auto-detect p2p state, and it is derived from duplex 291 * and initially port is in down state and in this down state 292 * duplex is set to false (half) */ 293 prt->AdminP2P = p2pAuto; 294 prt->operPointToPointMAC = false; 295 prt->portEnabled = false; 296 prt->restrictedRole = false; /* 13.25.14 */ 297 prt->restrictedTcn = false; /* 13.25.15 */ 298 assign(prt->ExternalPortPathCost, MAX_PATH_COST); /* 13.37.1 */ 299 prt->AdminEdgePort = false; /* 13.25 */ 300 prt->AutoEdge = true; /* 13.25 */ 301 prt->BpduGuardPort = false; 302 prt->BpduGuardError = false; 303 prt->NetworkPort = false; 304 prt->dontTxmtBpdu = false; 305 prt->bpduFilterPort = false; 306 prt->deleted = false; 307 308 port_default_internal_vars(prt); 309 310 /* Create PerTreePort structures for all existing trees */ 311 FOREACH_TREE_IN_BRIDGE(tree, br) 312 { 313 if(!(ptp = create_ptp(tree, prt))) 314 { 315 /* Remove and free all previously created entries in port's list */ 316 list_for_each_entry_safe(ptp, nxt, &prt->trees, port_list) 317 { 318 list_del(&ptp->port_list); 319 list_del(&ptp->tree_list); 320 free(ptp); 321 } 322 return false; 323 } 324 list_add_tail(&ptp->port_list, &prt->trees); 325 list_add_tail(&ptp->tree_list, &tree->ports); 326 } 327 328 /* Add new port to the tail of the list in the bridge */ 329 /* NOTE: if one wants add port NOT to the tail of the list of ports, 330 * one should revise above loop (FOREACH_TREE_IN_BRIDGE) 331 * because it heavily depends on the fact that port is added to the tail. 332 */ 333 list_add_tail(&prt->br_list, &br->ports); 334 335 prt_state_machines_begin(prt); 336 return true; 337 } 338 339 void MSTP_IN_delete_port(port_t *prt) 340 { 341 per_tree_port_t *ptp, *nxt; 342 bridge_t *br = prt->bridge; 343 344 driver_delete_port(prt); 345 346 prt->deleted = true; 347 if(prt->portEnabled) 348 { 349 prt->portEnabled = false; 350 br_state_machines_run(br); 351 } 352 353 list_for_each_entry_safe(ptp, nxt, &prt->trees, port_list) 354 { 355 list_del(&ptp->port_list); 356 list_del(&ptp->tree_list); 357 free(ptp); 358 } 359 360 list_del(&prt->br_list); 361 br_state_machines_run(br); 362 } 363 364 void MSTP_IN_delete_bridge(bridge_t *br) 365 { 366 tree_t *tree, *nxt_tree; 367 port_t *prt, *nxt_prt; 368 369 driver_delete_bridge(br); 370 371 br->bridgeEnabled = false; 372 373 /* We SHOULD first delete all ports and only THEN delete all tree_t 374 * structures as the tree_t structure contains the head for the per-port 375 * list of tree data (tree_t.ports). 376 * If this list_head will be deleted before all the per_tree_ports 377 * bad things will happen ;) 378 */ 379 380 list_for_each_entry_safe(prt, nxt_prt, &br->ports, br_list) 381 { 382 MSTP_IN_delete_port(prt); 383 free(prt); 384 } 385 386 list_for_each_entry_safe(tree, nxt_tree, &br->trees, bridge_list) 387 { 388 list_del(&tree->bridge_list); 389 free(tree); 390 } 391 } 392 393 void MSTP_IN_set_bridge_address(bridge_t *br, __u8 *macaddr) 394 { 395 tree_t *tree; 396 bool changed = false; 397 398 FOREACH_TREE_IN_BRIDGE(tree, br) 399 { 400 if(0 == memcmp(tree->BridgeIdentifier.s.mac_address, macaddr, ETH_ALEN)) 401 continue; 402 changed = true; 403 memcpy(tree->BridgeIdentifier.s.mac_address, macaddr, ETH_ALEN); 404 tree->BridgePriority.RootID = tree->BridgePriority.RRootID = 405 tree->BridgePriority.DesignatedBridgeID = tree->BridgeIdentifier; 406 } 407 408 if(changed) 409 br_state_machines_begin(br); 410 } 411 412 void MSTP_IN_set_bridge_enable(bridge_t *br, bool up) 413 { 414 port_t *prt; 415 per_tree_port_t *ptp; 416 tree_t *tree; 417 418 if(br->bridgeEnabled == up) 419 return; 420 br->bridgeEnabled = up; 421 422 /* Reset all internal states and variables, 423 * except those which are user-configurable */ 424 bridge_default_internal_vars(br); 425 FOREACH_TREE_IN_BRIDGE(tree, br) 426 { 427 tree_default_internal_vars(tree); 428 } 429 FOREACH_PORT_IN_BRIDGE(prt, br) 430 { 431 /* NOTE: Don't check prt->deleted here, as it is imposible condition */ 432 /* NOTE: In the port_default_internal_vars() rapidAgeingWhile will be 433 * reset, so we should stop rapid ageing procedure here. 434 */ 435 if(prt->rapidAgeingWhile) 436 { 437 MSTP_OUT_set_ageing_time(prt, br->Ageing_Time); 438 } 439 port_default_internal_vars(prt); 440 FOREACH_PTP_IN_PORT(ptp, prt) 441 { 442 if(BR_STATE_DISABLED != ptp->state) 443 { 444 MSTP_OUT_set_state(ptp, BR_STATE_DISABLED); 445 } 446 ptp_default_internal_vars(ptp); 447 } 448 } 449 br_state_machines_begin(br); 450 } 451 452 void MSTP_IN_set_port_enable(port_t *prt, bool up, int speed, int duplex) 453 { 454 __u32 computed_pcost, new_ExternalPathCost, new_InternalPathCost; 455 per_tree_port_t *ptp; 456 bool new_p2p; 457 bool changed = false; 458 459 if(up) 460 { 461 computed_pcost = compute_pcost(speed); 462 new_ExternalPathCost = (0 == prt->AdminExternalPortPathCost) ? 463 computed_pcost 464 : prt->AdminExternalPortPathCost; 465 if(prt->ExternalPortPathCost != new_ExternalPathCost) 466 { 467 assign(prt->ExternalPortPathCost, new_ExternalPathCost); 468 changed = true; 469 } 470 FOREACH_PTP_IN_PORT(ptp, prt) 471 { 472 new_InternalPathCost = (0 == ptp->AdminInternalPortPathCost) ? 473 computed_pcost 474 : ptp->AdminInternalPortPathCost; 475 if(ptp->InternalPortPathCost != new_InternalPathCost) 476 { 477 assign(ptp->InternalPortPathCost, new_InternalPathCost); 478 changed = true; 479 } 480 } 481 482 switch(prt->AdminP2P) 483 { 484 case p2pForceTrue: 485 new_p2p = true; 486 break; 487 case p2pForceFalse: 488 new_p2p = false; 489 break; 490 case p2pAuto: 491 default: 492 new_p2p = !!duplex; 493 break; 494 } 495 if(prt->operPointToPointMAC != new_p2p) 496 { 497 prt->operPointToPointMAC = new_p2p; 498 changed = true; 499 } 500 501 if(!prt->portEnabled) 502 { 503 prt->portEnabled = true; 504 prt->BpduGuardError = false; 505 prt->BaInconsistent = false; 506 prt->num_rx_bpdu_filtered = 0; 507 prt->num_rx_bpdu = 0; 508 prt->num_rx_tcn = 0; 509 prt->num_tx_bpdu = 0; 510 prt->num_tx_tcn = 0; 511 changed = true; 512 /* When port is enabled, initialize bridge assurance timer, 513 * so that enough time is given before port is put in 514 * inconsistent state. 515 */ 516 updtbrAssuRcvdInfoWhile(prt); 517 } 518 } 519 else 520 { 521 if(prt->portEnabled) 522 { 523 prt->portEnabled = false; 524 changed = true; 525 } 526 } 527 528 if(changed) 529 br_state_machines_run(prt->bridge); 530 } 531 532 void MSTP_IN_one_second(bridge_t *br) 533 { 534 port_t *prt; 535 tree_t *tree; 536 537 ++(br->uptime); 538 539 if(!br->bridgeEnabled) 540 return; 541 542 FOREACH_TREE_IN_BRIDGE(tree, br) 543 if(!(tree->topology_change)) 544 ++(tree->time_since_topology_change); 545 546 FOREACH_PORT_IN_BRIDGE(prt, br) 547 { 548 PTSM_tick(prt); 549 /* support for rapid ageing */ 550 if(prt->rapidAgeingWhile) 551 { 552 if((--(prt->rapidAgeingWhile)) == 0) 553 { 554 if(!prt->deleted) 555 MSTP_OUT_set_ageing_time(prt, br->Ageing_Time); 556 } 557 } 558 } 559 560 br_state_machines_run(br); 561 } 562 563 void MSTP_IN_all_fids_flushed(per_tree_port_t *ptp) 564 { 565 bridge_t *br = ptp->port->bridge; 566 ptp->fdbFlush = false; 567 if(!br->bridgeEnabled) 568 return; 569 if(!ptp->calledFromFlushRoutine) 570 { 571 TCSM_run(ptp, false /* actual run */); 572 br_state_machines_run(br); 573 } 574 } 575 576 /* NOTE: bpdu pointer is unaligned, but it works because 577 * bpdu_t is packed. Don't try to cast bpdu to non-packed type ;) 578 */ 579 void MSTP_IN_rx_bpdu(port_t *prt, bpdu_t *bpdu, int size) 580 { 581 int mstis_size; 582 bridge_t *br = prt->bridge; 583 584 ++(prt->num_rx_bpdu); 585 586 if(prt->BpduGuardPort) 587 { 588 prt->BpduGuardError = true; 589 ERROR_PRTNAME(br, prt, 590 "Received BPDU on BPDU Guarded Port - Port Down"); 591 MSTP_OUT_shutdown_port(prt); 592 return; 593 } 594 595 if(prt->bpduFilterPort) 596 { 597 LOG_PRTNAME(br, prt, 598 "Received BPDU on BPDU Filtered Port - discarded"); 599 ++(prt->num_rx_bpdu_filtered); 600 return; 601 } 602 603 if(!br->bridgeEnabled) 604 { 605 INFO_PRTNAME(br, prt, "Received BPDU while bridge is disabled"); 606 return; 607 } 608 609 if(prt->rcvdBpdu) 610 { 611 ERROR_PRTNAME(br, prt, "Port hasn't processed previous BPDU"); 612 return; 613 } 614 615 /* 14.4 Validation */ 616 if((TCN_BPDU_SIZE > size) || (0 != bpdu->protocolIdentifier)) 617 { 618 bpdu_validation_failed: 619 INFO_PRTNAME(br, prt, "BPDU validation failed"); 620 return; 621 } 622 switch(bpdu->bpduType) 623 { 624 case bpduTypeTCN: 625 /* 14.4.b) */ 626 /* Valid TCN BPDU */ 627 bpdu->protocolVersion = protoSTP; 628 LOG_PRTNAME(br, prt, "received TCN BPDU"); 629 break; 630 case bpduTypeConfig: 631 /* 14.4.a) */ 632 if(CONFIG_BPDU_SIZE > size) 633 goto bpdu_validation_failed; 634 /* Valid Config BPDU */ 635 bpdu->protocolVersion = protoSTP; 636 LOG_PRTNAME(br, prt, "received Config BPDU%s", 637 (bpdu->flags & (1 << offsetTc)) ? ", tcFlag" : "" 638 ); 639 break; 640 case bpduTypeRST: 641 if(protoRSTP == bpdu->protocolVersion) 642 { /* 14.4.c) */ 643 if(RST_BPDU_SIZE > size) 644 goto bpdu_validation_failed; 645 /* Valid RST BPDU */ 646 /* bpdu->protocolVersion = protoRSTP; */ 647 LOG_PRTNAME(br, prt, "received RST BPDU%s", 648 (bpdu->flags & (1 << offsetTc)) ? ", tcFlag" : "" 649 ); 650 break; 651 } 652 if(protoMSTP > bpdu->protocolVersion) 653 goto bpdu_validation_failed; 654 /* Yes, 802.1Q-2005 says here to check if it contains 655 * "35 or more octets", not 36! (see 14.4.d).1) ) 656 * That's why I check size against CONFIG_BPDU_SIZE 657 * and not RST_BPDU_SIZE. 658 */ 659 if(CONFIG_BPDU_SIZE > size) 660 goto bpdu_validation_failed; 661 mstis_size = __be16_to_cpu(bpdu->version3_len) 662 - MST_BPDU_VER3LEN_WO_MSTI_MSGS; 663 if((MST_BPDU_SIZE_WO_MSTI_MSGS > size) || (0 != bpdu->version1_len) 664 || (0 > mstis_size) 665 || ((MAX_STANDARD_MSTIS * sizeof(msti_configuration_message_t)) 666 < mstis_size) 667 || (0 != (mstis_size % sizeof(msti_configuration_message_t))) 668 ) 669 { /* 14.4.d) */ 670 /* Valid RST BPDU */ 671 bpdu->protocolVersion = protoRSTP; 672 LOG_PRTNAME(br, prt, "received RST BPDU"); 673 break; 674 } 675 /* 14.4.e) */ 676 /* Valid MST BPDU */ 677 bpdu->protocolVersion = protoMSTP; 678 prt->rcvdBpduNumOfMstis = mstis_size 679 / sizeof(msti_configuration_message_t); 680 LOG_PRTNAME(br, prt, "received MST BPDU%s with %d MSTIs", 681 (bpdu->flags & (1 << offsetTc)) ? ", tcFlag" : "", 682 prt->rcvdBpduNumOfMstis 683 ); 684 break; 685 default: 686 goto bpdu_validation_failed; 687 } 688 689 if((protoSTP == bpdu->protocolVersion) && (bpduTypeTCN == bpdu->bpduType)) 690 { 691 ++(prt->num_rx_tcn); 692 } 693 else 694 { 695 if(bpdu->flags & (1 << offsetTc)) 696 ++(prt->num_rx_tcn); 697 } 698 699 assign(prt->rcvdBpduData, *bpdu); 700 prt->rcvdBpdu = true; 701 702 /* Reset bridge assurance on receipt of valid BPDU */ 703 if(prt->BaInconsistent) 704 { 705 prt->BaInconsistent = false; 706 INFO_PRTNAME(br, prt, "Clear Bridge assurance inconsistency"); 707 } 708 updtbrAssuRcvdInfoWhile(prt); 709 710 br_state_machines_run(br); 711 } 712 713 /* 12.8.1.1 Read CIST Bridge Protocol Parameters */ 714 void MSTP_IN_get_cist_bridge_status(bridge_t *br, CIST_BridgeStatus *status) 715 { 716 tree_t *cist = GET_CIST_TREE(br); 717 assign(status->bridge_id, cist->BridgeIdentifier); 718 assign(status->time_since_topology_change, 719 cist->time_since_topology_change); 720 assign(status->topology_change_count, cist->topology_change_count); 721 status->topology_change = cist->topology_change; 722 strncpy(status->topology_change_port, cist->topology_change_port, 723 IFNAMSIZ); 724 strncpy(status->last_topology_change_port, cist->last_topology_change_port, 725 IFNAMSIZ); 726 assign(status->designated_root, cist->rootPriority.RootID); 727 assign(status->root_path_cost, 728 __be32_to_cpu(cist->rootPriority.ExtRootPathCost)); 729 assign(status->regional_root, cist->rootPriority.RRootID); 730 assign(status->internal_path_cost, 731 __be32_to_cpu(cist->rootPriority.IntRootPathCost)); 732 assign(status->root_port_id, cist->rootPortId); 733 assign(status->root_max_age, cist->rootTimes.Max_Age); 734 assign(status->root_forward_delay, cist->rootTimes.Forward_Delay); 735 assign(status->bridge_max_age, br->Max_Age); 736 assign(status->bridge_forward_delay, br->Forward_Delay); 737 assign(status->max_hops, br->MaxHops); 738 assign(status->tx_hold_count, br->Transmit_Hold_Count); 739 status->protocol_version = br->ForceProtocolVersion; 740 status->enabled = br->bridgeEnabled; 741 assign(status->bridge_hello_time, br->Hello_Time); 742 assign(status->Ageing_Time, br->Ageing_Time); 743 } 744 745 /* 12.8.1.2 Read MSTI Bridge Protocol Parameters */ 746 void MSTP_IN_get_msti_bridge_status(tree_t *tree, MSTI_BridgeStatus *status) 747 { 748 assign(status->bridge_id, tree->BridgeIdentifier); 749 assign(status->time_since_topology_change, 750 tree->time_since_topology_change); 751 assign(status->topology_change_count, tree->topology_change_count); 752 status->topology_change = tree->topology_change; 753 strncpy(status->topology_change_port, tree->topology_change_port, 754 IFNAMSIZ); 755 strncpy(status->last_topology_change_port, tree->last_topology_change_port, 756 IFNAMSIZ); 757 assign(status->regional_root, tree->rootPriority.RRootID); 758 assign(status->internal_path_cost, 759 __be32_to_cpu(tree->rootPriority.IntRootPathCost)); 760 assign(status->root_port_id, tree->rootPortId); 761 } 762 763 /* 12.8.1.3 Set CIST Bridge Protocol Parameters */ 764 int MSTP_IN_set_cist_bridge_config(bridge_t *br, CIST_BridgeConfig *cfg) 765 { 766 bool changed, changedBridgeTimes, init; 767 int r = 0; 768 __u8 new_forward_delay, new_max_age; 769 tree_t *tree; 770 port_t *prt; 771 per_tree_port_t *ptp; 772 773 /* Firstly, validation */ 774 if(cfg->set_bridge_max_age) 775 { 776 new_max_age = cfg->bridge_max_age; 777 if((6 > new_max_age) || (40 < new_max_age)) 778 { 779 ERROR_BRNAME(br, 780 "Bridge Max Age must be between 6 and 40 seconds"); 781 r = -1; 782 } 783 } 784 else 785 new_max_age = br->Max_Age; 786 787 if(cfg->set_bridge_forward_delay) 788 { 789 new_forward_delay = cfg->bridge_forward_delay; 790 if((4 > new_forward_delay) || (30 < new_forward_delay)) 791 { 792 ERROR_BRNAME(br, 793 "Bridge Forward Delay must be between 4 and 30 seconds"); 794 r = -1; 795 } 796 } 797 else 798 new_forward_delay = br->Forward_Delay; 799 800 if(cfg->set_bridge_max_age || cfg->set_bridge_forward_delay) 801 { 802 if((2 * (new_forward_delay - 1)) < new_max_age) 803 { 804 ERROR_BRNAME(br, "Configured Bridge Times don't meet " 805 "2 * (Bridge Foward Delay - 1 second) >= Bridge Max Age"); 806 r = -1; 807 } 808 } 809 810 if(cfg->set_protocol_version) 811 { 812 switch(cfg->protocol_version) 813 { 814 case protoSTP: 815 case protoRSTP: 816 case protoMSTP: 817 break; 818 default: 819 ERROR_BRNAME(br, "Bad protocol version (%d)", 820 cfg->protocol_version); 821 r = -1; 822 } 823 } 824 825 if(cfg->set_tx_hold_count) 826 { 827 if((1 > cfg->tx_hold_count) || (10 < cfg->tx_hold_count)) 828 { 829 ERROR_BRNAME(br, 830 "Transmit Hold Count must be between 1 and 10 seconds"); 831 r = -1; 832 } 833 } 834 835 if(cfg->set_max_hops) 836 { 837 if((6 > cfg->max_hops) || (40 < cfg->max_hops)) 838 { 839 ERROR_BRNAME(br, "Bridge Max Hops must be between 6 and 40"); 840 r = -1; 841 } 842 } 843 844 if(cfg->set_bridge_hello_time) 845 { 846 if((1 > cfg->bridge_hello_time) || (10 < cfg->bridge_hello_time)) 847 { 848 ERROR_BRNAME(br, "Bridge Hello Time must be between 1 and 10"); 849 r = -1; 850 } 851 } 852 853 if(cfg->set_bridge_ageing_time) 854 { 855 if((10 > cfg->bridge_ageing_time)||(1000000 < cfg->bridge_ageing_time)) 856 { 857 ERROR_BRNAME(br, 858 "Bridge Ageing Time must be between 10 and 1000000 seconds"); 859 r = -1; 860 } 861 } 862 863 if(r) 864 return r; 865 866 /* Secondly, do set */ 867 changed = changedBridgeTimes = init = false; 868 869 if(cfg->set_bridge_max_age || cfg->set_bridge_forward_delay) 870 { 871 if(cmp(new_max_age, !=, br->Max_Age) 872 || cmp(new_forward_delay, !=, br->Forward_Delay) 873 ) 874 { 875 assign(br->Max_Age, new_max_age); 876 assign(br->Forward_Delay, new_forward_delay); 877 changed = changedBridgeTimes = true; 878 } 879 } 880 881 if((cfg->set_protocol_version) 882 && (cfg->protocol_version != br->ForceProtocolVersion) 883 ) 884 { 885 br->ForceProtocolVersion = cfg->protocol_version; 886 changed = init = true; 887 } 888 889 if(cfg->set_tx_hold_count) 890 { 891 if(cfg->tx_hold_count != br->Transmit_Hold_Count) 892 { 893 assign(br->Transmit_Hold_Count, cfg->tx_hold_count); 894 FOREACH_PORT_IN_BRIDGE(prt, br) 895 assign(prt->txCount, 0u); 896 changed = true; 897 } 898 } 899 900 if(cfg->set_max_hops) 901 { 902 if(cfg->max_hops != br->MaxHops) 903 { 904 assign(br->MaxHops, cfg->max_hops); 905 changed = changedBridgeTimes = true; 906 } 907 } 908 909 if(cfg->set_bridge_hello_time) 910 { 911 if(cfg->bridge_hello_time != br->Hello_Time) 912 { 913 INFO_BRNAME(br, "bridge hello_time new=%hhu, old=%hhu", 914 cfg->bridge_hello_time, br->Hello_Time); 915 assign(br->Hello_Time, cfg->bridge_hello_time); 916 changed = changedBridgeTimes = true; 917 } 918 } 919 920 if(cfg->set_bridge_ageing_time) 921 { 922 if(cfg->bridge_ageing_time != br->Ageing_Time) 923 { 924 INFO_BRNAME(br, "bridge ageing_time new=%u, old=%u", 925 cfg->bridge_ageing_time, br->Ageing_Time); 926 assign(br->Ageing_Time, cfg->bridge_ageing_time); 927 } 928 } 929 930 /* Thirdly, finalize changes */ 931 if(changedBridgeTimes) 932 { 933 FOREACH_TREE_IN_BRIDGE(tree, br) 934 { 935 assign(tree->BridgeTimes.remainingHops, br->MaxHops); 936 assign(tree->BridgeTimes.Forward_Delay, br->Forward_Delay); 937 assign(tree->BridgeTimes.Max_Age, br->Max_Age); 938 assign(tree->BridgeTimes.Hello_Time, br->Hello_Time); 939 /* Comment found in rstpd by Srinivas Aji: 940 * Do this for any change in BridgeTimes. 941 * Otherwise we fail UNH rstp.op_D test 3.2 since when administratively 942 * setting BridgeForwardDelay, etc, the values don't propagate from 943 * rootTimes to designatedTimes immediately without this change. 944 */ 945 FOREACH_PTP_IN_TREE(ptp, tree) 946 { 947 ptp->selected = false; 948 ptp->reselect = true; 949 /* TODO: change this when Hello_Time will be configurable 950 * per-port. For now, copy Bridge's Hello_Time 951 * to the port's Hello_Time. 952 */ 953 assign(ptp->portTimes.Hello_Time, br->Hello_Time); 954 } 955 } 956 } 957 958 if(changed && br->bridgeEnabled) 959 { 960 if(init) 961 br_state_machines_begin(br); 962 else 963 br_state_machines_run(br); 964 } 965 966 return 0; 967 } 968 969 /* 12.8.1.4 Set MSTI Bridge Protocol Parameters */ 970 int MSTP_IN_set_msti_bridge_config(tree_t *tree, __u8 bridge_priority) 971 { 972 per_tree_port_t *ptp; 973 __u8 valuePri; 974 975 if(15 < bridge_priority) 976 { 977 ERROR_BRNAME(tree->bridge, 978 "MSTI %hu: Bridge Priority must be between 0 and 15", 979 __be16_to_cpu(tree->MSTID)); 980 return -1; 981 } 982 983 valuePri = bridge_priority << 4; 984 if(GET_PRIORITY_FROM_IDENTIFIER(tree->BridgeIdentifier) == valuePri) 985 return 0; 986 SET_PRIORITY_IN_IDENTIFIER(valuePri, tree->BridgeIdentifier); 987 tree->BridgePriority.RootID = tree->BridgePriority.RRootID = 988 tree->BridgePriority.DesignatedBridgeID = tree->BridgeIdentifier; 989 /* 12.8.1.4.4 do not require reselect, but I think it is needed, 990 * because 12.8.1.3.4.c) requires it */ 991 FOREACH_PTP_IN_TREE(ptp, tree) 992 { 993 ptp->selected = false; 994 ptp->reselect = true; 995 } 996 return 0; 997 } 998 999 /* 12.8.2.1 Read CIST Port Parameters */ 1000 void MSTP_IN_get_cist_port_status(port_t *prt, CIST_PortStatus *status) 1001 { 1002 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 1003 /* 12.8.2.2.3 b) */ 1004 status->uptime = (signed int)((prt->bridge)->uptime) 1005 - (signed int)(cist->start_time); 1006 status->state = cist->state; 1007 assign(status->port_id, cist->portId); 1008 assign(status->admin_external_port_path_cost, 1009 prt->AdminExternalPortPathCost); 1010 assign(status->external_port_path_cost, prt->ExternalPortPathCost); 1011 assign(status->designated_root, cist->portPriority.RootID); 1012 assign(status->designated_external_cost, 1013 __be32_to_cpu(cist->portPriority.ExtRootPathCost)); 1014 assign(status->designated_bridge, cist->portPriority.DesignatedBridgeID); 1015 assign(status->designated_port, cist->portPriority.DesignatedPortID); 1016 assign(status->designated_regional_root, cist->portPriority.RRootID); 1017 assign(status->designated_internal_cost, 1018 __be32_to_cpu(cist->portPriority.IntRootPathCost)); 1019 status->tc_ack = prt->tcAck; 1020 assign(status->port_hello_time, cist->portTimes.Hello_Time); 1021 status->admin_edge_port = prt->AdminEdgePort; 1022 status->auto_edge_port = prt->AutoEdge; 1023 status->oper_edge_port = prt->operEdge; 1024 status->enabled = prt->portEnabled; 1025 status->admin_p2p = prt->AdminP2P; 1026 status->oper_p2p = prt->operPointToPointMAC; 1027 status->restricted_role = prt->restrictedRole; 1028 status->restricted_tcn = prt->restrictedTcn; 1029 status->role = cist->role; 1030 status->disputed = cist->disputed; 1031 assign(status->admin_internal_port_path_cost, 1032 cist->AdminInternalPortPathCost); 1033 assign(status->internal_port_path_cost, cist->InternalPortPathCost); 1034 status->bpdu_guard_port = prt->BpduGuardPort; 1035 status->bpdu_guard_error = prt->BpduGuardError; 1036 status->network_port = prt->NetworkPort; 1037 status->ba_inconsistent = prt->BaInconsistent; 1038 status->bpdu_filter_port = prt->bpduFilterPort; 1039 status->num_rx_bpdu_filtered = prt->num_rx_bpdu_filtered; 1040 status->num_rx_bpdu = prt->num_rx_bpdu; 1041 status->num_rx_tcn = prt->num_rx_tcn; 1042 status->num_tx_bpdu = prt->num_tx_bpdu; 1043 status->num_tx_tcn = prt->num_tx_tcn; 1044 status->num_trans_fwd = prt->num_trans_fwd; 1045 status->num_trans_blk = prt->num_trans_blk; 1046 status->rcvdBpdu = prt->rcvdBpdu; 1047 status->rcvdRSTP = prt->rcvdRSTP; 1048 status->rcvdSTP = prt->rcvdSTP; 1049 status->rcvdTcAck = prt->rcvdTcAck; 1050 status->rcvdTcn = prt->rcvdTcn; 1051 status->sendRSTP = prt->sendRSTP; 1052 } 1053 1054 /* 12.8.2.2 Read MSTI Port Parameters */ 1055 void MSTP_IN_get_msti_port_status(per_tree_port_t *ptp, 1056 MSTI_PortStatus *status) 1057 { 1058 status->uptime = (signed int)((ptp->port->bridge)->uptime) 1059 - (signed int)(ptp->start_time); 1060 status->state = ptp->state; 1061 assign(status->port_id, ptp->portId); 1062 assign(status->admin_internal_port_path_cost, 1063 ptp->AdminInternalPortPathCost); 1064 assign(status->internal_port_path_cost, ptp->InternalPortPathCost); 1065 assign(status->designated_regional_root, ptp->portPriority.RRootID); 1066 assign(status->designated_internal_cost, 1067 __be32_to_cpu(ptp->portPriority.IntRootPathCost)); 1068 assign(status->designated_bridge, ptp->portPriority.DesignatedBridgeID); 1069 assign(status->designated_port, ptp->portPriority.DesignatedPortID); 1070 status->role = ptp->role; 1071 status->disputed = ptp->disputed; 1072 } 1073 1074 /* 12.8.2.3 Set CIST port parameters */ 1075 int MSTP_IN_set_cist_port_config(port_t *prt, CIST_PortConfig *cfg) 1076 { 1077 bool changed; 1078 __u32 new_ExternalPathCost; 1079 bool new_p2p; 1080 per_tree_port_t *cist; 1081 bridge_t *br = prt->bridge; 1082 1083 /* Firstly, validation */ 1084 if(cfg->set_admin_p2p) 1085 { 1086 switch(cfg->admin_p2p) 1087 { 1088 case p2pAuto: 1089 case p2pForceTrue: 1090 case p2pForceFalse: 1091 break; 1092 default: 1093 cfg->admin_p2p = p2pAuto; 1094 } 1095 } 1096 1097 /* Secondly, do set */ 1098 changed = false; 1099 1100 if(cfg->set_admin_external_port_path_cost) 1101 { 1102 prt->AdminExternalPortPathCost = cfg->admin_external_port_path_cost; 1103 new_ExternalPathCost = (0 == prt->AdminExternalPortPathCost) ? 1104 compute_pcost(GET_PORT_SPEED(prt)) 1105 : prt->AdminExternalPortPathCost; 1106 if(prt->ExternalPortPathCost != new_ExternalPathCost) 1107 { 1108 assign(prt->ExternalPortPathCost, new_ExternalPathCost); 1109 changed = true; 1110 /* 12.8.2.3.4 */ 1111 cist = GET_CIST_PTP_FROM_PORT(prt); 1112 cist->selected = false; 1113 cist->reselect = true; 1114 } 1115 } 1116 1117 if(cfg->set_admin_p2p) 1118 { 1119 prt->AdminP2P = cfg->admin_p2p; 1120 switch(prt->AdminP2P) 1121 { 1122 case p2pForceTrue: 1123 new_p2p = true; 1124 break; 1125 case p2pForceFalse: 1126 new_p2p = false; 1127 break; 1128 case p2pAuto: 1129 default: 1130 new_p2p = !!GET_PORT_DUPLEX(prt); 1131 break; 1132 } 1133 if(prt->operPointToPointMAC != new_p2p) 1134 { 1135 prt->operPointToPointMAC = new_p2p; 1136 changed = true; 1137 } 1138 } 1139 1140 if(cfg->set_admin_edge_port) 1141 { 1142 if(prt->AdminEdgePort != cfg->admin_edge_port) 1143 { 1144 prt->AdminEdgePort = cfg->admin_edge_port; 1145 BDSM_begin(prt); 1146 changed = true; 1147 } 1148 } 1149 1150 if(cfg->set_auto_edge_port) 1151 { 1152 if(prt->AutoEdge != cfg->auto_edge_port) 1153 { 1154 prt->AutoEdge = cfg->auto_edge_port; 1155 changed = true; 1156 } 1157 } 1158 1159 if(cfg->set_restricted_role) 1160 { 1161 if(prt->restrictedRole != cfg->restricted_role) 1162 { 1163 prt->restrictedRole = cfg->restricted_role; 1164 changed = true; 1165 } 1166 } 1167 1168 if(cfg->set_restricted_tcn) 1169 { 1170 if(prt->restrictedTcn != cfg->restricted_tcn) 1171 { 1172 prt->restrictedTcn = cfg->restricted_tcn; 1173 changed = true; 1174 } 1175 } 1176 1177 if(cfg->set_bpdu_guard_port) 1178 { 1179 if(prt->BpduGuardPort != cfg->bpdu_guard_port) 1180 { 1181 prt->BpduGuardPort = cfg->bpdu_guard_port; 1182 INFO_PRTNAME(br, prt,"BpduGuardPort new=%d", prt->BpduGuardPort); 1183 } 1184 } 1185 1186 if(cfg->set_network_port) 1187 { 1188 if(prt->NetworkPort != cfg->network_port) 1189 { 1190 prt->NetworkPort = cfg->network_port; 1191 INFO_PRTNAME(br, prt, "NetworkPort new=%d", prt->NetworkPort); 1192 /* When Network port config is removed and bridge assurance 1193 * inconsistency is set, clear the inconsistency. 1194 */ 1195 if(!prt->NetworkPort && prt->BaInconsistent) 1196 { 1197 prt->BaInconsistent = false; 1198 INFO_PRTNAME(br, prt, "Clear Bridge assurance inconsistency"); 1199 } 1200 changed = true; 1201 } 1202 } 1203 1204 if(cfg->set_dont_txmt) 1205 { 1206 if(prt->dontTxmtBpdu != cfg->dont_txmt) 1207 { 1208 prt->dontTxmtBpdu = cfg->dont_txmt; 1209 INFO_PRTNAME(br, prt, "donttxmt new=%d", prt->dontTxmtBpdu); 1210 } 1211 } 1212 1213 if(cfg->set_bpdu_filter_port) 1214 { 1215 if (prt->bpduFilterPort != cfg->bpdu_filter_port) 1216 { 1217 prt->bpduFilterPort = cfg->bpdu_filter_port; 1218 prt->num_rx_bpdu_filtered = 0; 1219 INFO_PRTNAME(br, prt,"bpduFilterPort new=%d", prt->bpduFilterPort); 1220 } 1221 } 1222 1223 if(changed && prt->portEnabled) 1224 br_state_machines_run(prt->bridge); 1225 1226 return 0; 1227 } 1228 1229 /* 12.8.2.4 Set MSTI port parameters */ 1230 int MSTP_IN_set_msti_port_config(per_tree_port_t *ptp, MSTI_PortConfig *cfg) 1231 { 1232 __u8 valuePri; 1233 __u32 new_InternalPathCost; 1234 bool changed = false; 1235 port_t *prt = ptp->port; 1236 bridge_t *br = prt->bridge; 1237 1238 if(cfg->set_port_priority) 1239 { 1240 if(15 < cfg->port_priority) 1241 { 1242 ERROR_MSTINAME(br, prt, ptp, 1243 "Port Priority must be between 0 and 15"); 1244 return -1; 1245 } 1246 valuePri = cfg->port_priority << 4; 1247 if(GET_PRIORITY_FROM_IDENTIFIER(ptp->portId) != valuePri) 1248 { 1249 SET_PRIORITY_IN_IDENTIFIER(valuePri, ptp->portId); 1250 changed = true; 1251 } 1252 } 1253 1254 if(cfg->set_admin_internal_port_path_cost) 1255 { 1256 ptp->AdminInternalPortPathCost = cfg->admin_internal_port_path_cost; 1257 new_InternalPathCost = (0 == ptp->AdminInternalPortPathCost) ? 1258 compute_pcost(GET_PORT_SPEED(prt)) 1259 : ptp->AdminInternalPortPathCost; 1260 if(ptp->InternalPortPathCost != new_InternalPathCost) 1261 { 1262 assign(ptp->InternalPortPathCost, new_InternalPathCost); 1263 changed = true; 1264 } 1265 } 1266 1267 if(changed && prt->portEnabled) 1268 { 1269 /* 12.8.2.4.4 */ 1270 ptp->selected = false; 1271 ptp->reselect = true; 1272 1273 br_state_machines_run(br); 1274 } 1275 1276 return 0; 1277 } 1278 1279 /* 12.8.2.5 Force BPDU Migration Check */ 1280 int MSTP_IN_port_mcheck(port_t *prt) 1281 { 1282 bridge_t *br = prt->bridge; 1283 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 1284 1285 if(rstpVersion(br) && prt->portEnabled && br->bridgeEnabled) 1286 { 1287 prt->mcheck = true; 1288 cist->proposing = true; 1289 br_state_machines_run(br); 1290 } 1291 1292 return 0; 1293 } 1294 1295 /* 12.10.3.8 Set VID to FID allocation */ 1296 bool MSTP_IN_set_vid2fid(bridge_t *br, __u16 vid, __u16 fid) 1297 { 1298 bool vid2mstid_changed; 1299 1300 if((vid < 1) || (vid > MAX_VID) || (fid > MAX_FID)) 1301 { 1302 ERROR_BRNAME(br, "Error allocating VID(%hu) to FID(%hu)", vid, fid); 1303 return false; 1304 } 1305 1306 vid2mstid_changed = 1307 (br->fid2mstid[fid] != br->fid2mstid[br->vid2fid[vid]]); 1308 br->vid2fid[vid] = fid; 1309 if(vid2mstid_changed) 1310 { 1311 RecalcConfigDigest(br); 1312 br_state_machines_begin(br); 1313 } 1314 1315 return true; 1316 } 1317 1318 /* Set all VID-to-FID mappings at once */ 1319 bool MSTP_IN_set_all_vids2fids(bridge_t *br, __u16 *vids2fids) 1320 { 1321 bool vid2mstid_changed; 1322 int vid; 1323 1324 vid2mstid_changed = false; 1325 for(vid = 1; vid <= MAX_VID; ++vid) 1326 { 1327 if(vids2fids[vid] > MAX_FID) 1328 { /* Incorrect value == keep prev value */ 1329 vids2fids[vid] = br->vid2fid[vid]; 1330 continue; 1331 } 1332 if(br->fid2mstid[vids2fids[vid]] != br->fid2mstid[br->vid2fid[vid]]) 1333 vid2mstid_changed = true; 1334 } 1335 memcpy(br->vid2fid, vids2fids, sizeof(br->vid2fid)); 1336 if(vid2mstid_changed) 1337 { 1338 RecalcConfigDigest(br); 1339 br_state_machines_begin(br); 1340 } 1341 1342 return true; 1343 } 1344 1345 /* 12.12.2.2 Set FID to MSTID allocation */ 1346 bool MSTP_IN_set_fid2mstid(bridge_t *br, __u16 fid, __u16 mstid) 1347 { 1348 tree_t *tree; 1349 __be16 MSTID; 1350 bool found; 1351 int vid; 1352 1353 if(fid > MAX_FID) 1354 { 1355 ERROR_BRNAME(br, "Bad FID(%hu)", fid); 1356 return false; 1357 } 1358 1359 MSTID = __cpu_to_be16(mstid); 1360 found = false; 1361 FOREACH_TREE_IN_BRIDGE(tree, br) 1362 { 1363 if(tree->MSTID == MSTID) 1364 { 1365 found = true; 1366 break; 1367 } 1368 } 1369 if(!found) 1370 { 1371 ERROR_BRNAME(br, "MSTID(%hu) not found", mstid); 1372 return false; 1373 } 1374 1375 if(br->fid2mstid[fid] != MSTID) 1376 { 1377 br->fid2mstid[fid] = MSTID; 1378 /* check if there are VLANs using this FID */ 1379 for(vid = 1; vid <= MAX_VID; ++vid) 1380 { 1381 if(br->vid2fid[vid] == fid) 1382 { 1383 RecalcConfigDigest(br); 1384 br_state_machines_begin(br); 1385 break; 1386 } 1387 } 1388 } 1389 1390 return true; 1391 } 1392 1393 /* Set all FID-to-MSTID mappings at once */ 1394 bool MSTP_IN_set_all_fids2mstids(bridge_t *br, __u16 *fids2mstids) 1395 { 1396 tree_t *tree; 1397 __be16 MSTID[MAX_FID + 1]; 1398 bool found, vid2mstid_changed; 1399 int fid, vid; 1400 __be16 prev_vid2mstid[MAX_VID + 2]; 1401 1402 for(fid = 0; fid <= MAX_FID; ++fid) 1403 { 1404 if(fids2mstids[fid] > MAX_MSTID) 1405 { /* Incorrect value == keep prev value */ 1406 fids2mstids[fid] = __be16_to_cpu(MSTID[fid] = br->fid2mstid[fid]); 1407 } 1408 else 1409 MSTID[fid] = __cpu_to_be16(fids2mstids[fid]); 1410 found = false; 1411 FOREACH_TREE_IN_BRIDGE(tree, br) 1412 { 1413 if(tree->MSTID == MSTID[fid]) 1414 { 1415 found = true; 1416 break; 1417 } 1418 } 1419 if(!found) 1420 { 1421 ERROR_BRNAME(br, 1422 "Error allocating FID(%hu) to MSTID(%hu): MSTID not found", 1423 fid, fids2mstids[fid]); 1424 return false; 1425 } 1426 } 1427 1428 for(vid = 1; vid <= MAX_VID; ++vid) 1429 prev_vid2mstid[vid] = br->fid2mstid[br->vid2fid[vid]]; 1430 memcpy(br->fid2mstid, MSTID, sizeof(br->fid2mstid)); 1431 vid2mstid_changed = false; 1432 for(vid = 1; vid <= MAX_VID; ++vid) 1433 { 1434 if(prev_vid2mstid[vid] != br->fid2mstid[br->vid2fid[vid]]) 1435 { 1436 vid2mstid_changed = true; 1437 break; 1438 } 1439 } 1440 if(vid2mstid_changed) 1441 { 1442 RecalcConfigDigest(br); 1443 br_state_machines_begin(br); 1444 } 1445 1446 return true; 1447 } 1448 1449 /* 12.12.1.1 Read MSTI List */ 1450 bool MSTP_IN_get_mstilist(bridge_t *br, int *num_mstis, __u16 *mstids) 1451 { 1452 tree_t *tree; 1453 1454 *num_mstis = 0; 1455 FOREACH_TREE_IN_BRIDGE(tree, br) 1456 { 1457 mstids[*num_mstis] = __be16_to_cpu(tree->MSTID); 1458 /* Check for "<", not for "<=", as num_mstis include CIST */ 1459 if(MAX_IMPLEMENTATION_MSTIS < ++(*num_mstis)) 1460 break; 1461 } 1462 1463 return true; 1464 } 1465 1466 /* 12.12.1.2 Create MSTI */ 1467 bool MSTP_IN_create_msti(bridge_t *br, __u16 mstid) 1468 { 1469 tree_t *tree, *tree_after, *new_tree; 1470 per_tree_port_t *ptp, *nxt, *ptp_after, *new_ptp; 1471 int num_of_mstis; 1472 __be16 MSTID; 1473 1474 if((mstid < 1) || (mstid > MAX_MSTID)) 1475 { 1476 ERROR_BRNAME(br, "Bad MSTID(%hu)", mstid); 1477 return false; 1478 } 1479 1480 MSTID = __cpu_to_be16(mstid); 1481 /* Find place where to insert new MSTID. 1482 * Also check if such MSTID is already in the list. 1483 * Also count existing mstis. 1484 */ 1485 tree_after = NULL; 1486 num_of_mstis = 0; 1487 FOREACH_TREE_IN_BRIDGE(tree, br) 1488 { 1489 if(tree->MSTID == MSTID) 1490 { 1491 INFO_BRNAME(br, "MSTID(%hu) is already in the list", mstid); 1492 return true; /* yes, it is success */ 1493 } 1494 if(cmp(tree->MSTID, <, MSTID)) 1495 tree_after = tree; 1496 ++num_of_mstis; 1497 } 1498 /* Sanity check */ 1499 if(NULL == tree_after) 1500 { 1501 ERROR_BRNAME(br, "Can't add MSTID(%hu): no CIST in the list", mstid); 1502 return false; 1503 } 1504 /* End of Sanity check */ 1505 1506 /* Check for "<", not for "<=", as num_of_mstis include CIST */ 1507 if(MAX_IMPLEMENTATION_MSTIS < num_of_mstis) 1508 { 1509 ERROR_BRNAME(br, "Can't add MSTID(%hu): maximum count(%u) reached", 1510 mstid, MAX_IMPLEMENTATION_MSTIS); 1511 return false; 1512 } 1513 1514 /* Create new tree and its list of PerTreePort structures */ 1515 tree = GET_CIST_TREE(br); 1516 if(!(new_tree=create_tree(br,tree->BridgeIdentifier.s.mac_address,MSTID))) 1517 return false; 1518 1519 FOREACH_PTP_IN_TREE(ptp_after, tree_after) 1520 { 1521 if(!(new_ptp = create_ptp(new_tree, ptp_after->port))) 1522 { 1523 /* Remove and free all previously created entries in tree's list */ 1524 list_for_each_entry_safe(ptp, nxt, &new_tree->ports, tree_list) 1525 { 1526 list_del(&ptp->port_list); 1527 list_del(&ptp->tree_list); 1528 free(ptp); 1529 } 1530 return false; 1531 } 1532 list_add(&new_ptp->port_list, &ptp_after->port_list); 1533 list_add_tail(&new_ptp->tree_list, &new_tree->ports); 1534 } 1535 1536 list_add(&new_tree->bridge_list, &tree_after->bridge_list); 1537 /* There are no FIDs allocated to this MSTID, so VID-to-MSTID mapping 1538 * did not change. So, no need in RecalcConfigDigest. 1539 * Just initialize state machines for this tree. 1540 */ 1541 tree_state_machines_begin(new_tree); 1542 return true; 1543 } 1544 1545 /* 12.12.1.3 Delete MSTI */ 1546 bool MSTP_IN_delete_msti(bridge_t *br, __u16 mstid) 1547 { 1548 tree_t *tree; 1549 per_tree_port_t *ptp, *nxt; 1550 int fid; 1551 bool found; 1552 __be16 MSTID = __cpu_to_be16(mstid); 1553 1554 if((mstid < 1) || (mstid > MAX_MSTID)) 1555 { 1556 ERROR_BRNAME(br, "Bad MSTID(%hu)", mstid); 1557 return false; 1558 } 1559 1560 /* Check if there are FIDs associated with this MSTID */ 1561 for(fid = 0; fid <= MAX_FID; ++fid) 1562 { 1563 if(br->fid2mstid[fid] == MSTID) 1564 { 1565 ERROR_BRNAME(br, 1566 "Can't delete MSTID(%hu): there are FIDs allocated to it", 1567 mstid); 1568 return false; 1569 } 1570 } 1571 1572 found = false; 1573 FOREACH_TREE_IN_BRIDGE(tree, br) 1574 { 1575 if(tree->MSTID == MSTID) 1576 { 1577 found = true; 1578 break; 1579 } 1580 } 1581 if(!found) 1582 { 1583 INFO_BRNAME(br, "MSTID(%hu) is not in the list", mstid); 1584 return true; /* yes, it is success */ 1585 } 1586 1587 list_del(&tree->bridge_list); 1588 list_for_each_entry_safe(ptp, nxt, &tree->ports, tree_list) 1589 { 1590 list_del(&ptp->port_list); 1591 list_del(&ptp->tree_list); 1592 free(ptp); 1593 } 1594 free(tree); 1595 1596 /* There are no FIDs allocated to this MSTID, so VID-to-MSTID mapping 1597 * did not change. So, no need in RecalcConfigDigest. 1598 * Give state machine a spare run, just for the case... 1599 */ 1600 br_state_machines_run(br); 1601 return true; 1602 } 1603 1604 /* 12.12.3.4 Set MST Configuration Identifier Elements */ 1605 void MSTP_IN_set_mst_config_id(bridge_t *br, __u16 revision, __u8 *name) 1606 { 1607 __be16 valueRevision = __cpu_to_be16(revision); 1608 bool changed = (0 != strncmp((char *)name, (char *)br->MstConfigId.s.configuration_name, 1609 sizeof(br->MstConfigId.s.configuration_name)) 1610 ) 1611 || (valueRevision != br->MstConfigId.s.revision_level); 1612 1613 if(changed) 1614 { 1615 assign(br->MstConfigId.s.revision_level, valueRevision); 1616 memset(br->MstConfigId.s.configuration_name, 0, 1617 sizeof(br->MstConfigId.s.configuration_name)); 1618 strncpy((char *)br->MstConfigId.s.configuration_name, (char *)name, 1619 sizeof(br->MstConfigId.s.configuration_name) - 1); 1620 br_state_machines_begin(br); 1621 } 1622 } 1623 1624 /* 1625 * If hint_SetToYes == true, some tcWhile in this tree has non-zero value. 1626 * If hint_SetToYes == false, some tcWhile in this tree has just became zero, 1627 * so we should check all other tcWhile's in this tree. 1628 */ 1629 static void set_TopologyChange(tree_t *tree, bool hint_SetToYes, port_t *port) 1630 { 1631 per_tree_port_t *ptp; 1632 bool prev_tc_not_set = !tree->topology_change; 1633 1634 if(hint_SetToYes) 1635 { 1636 tree->topology_change = true; 1637 tree->time_since_topology_change = 0; 1638 if(prev_tc_not_set) 1639 ++(tree->topology_change_count); 1640 strncpy(tree->topology_change_port, tree->last_topology_change_port, 1641 IFNAMSIZ); 1642 strncpy(tree->last_topology_change_port, port->sysdeps.name, IFNAMSIZ); 1643 return; 1644 } 1645 1646 /* Some tcWhile has just became zero. Check if we need reset 1647 * topology_change flag */ 1648 if(prev_tc_not_set) 1649 return; 1650 1651 tree->topology_change = false; 1652 FOREACH_PTP_IN_TREE(ptp, tree) 1653 { 1654 if(0 != ptp->tcWhile) 1655 { 1656 tree->topology_change = true; 1657 tree->time_since_topology_change = 0; 1658 return; 1659 } 1660 } 1661 } 1662 1663 /* Helper functions, compare two priority vectors */ 1664 static bool samePriorityAndTimers(port_priority_vector_t *vec1, 1665 port_priority_vector_t *vec2, 1666 times_t *time1, 1667 times_t *time2, 1668 bool cist) 1669 { 1670 if(cist) 1671 { 1672 if(cmp(time1->Forward_Delay, !=, time2->Forward_Delay)) 1673 return false; 1674 if(cmp(time1->Max_Age, !=, time2->Max_Age)) 1675 return false; 1676 if(cmp(time1->Message_Age, !=, time2->Message_Age)) 1677 return false; 1678 if(cmp(time1->Hello_Time, !=, time2->Hello_Time)) 1679 return false; 1680 1681 if(cmp(vec1->RootID, !=, vec2->RootID)) 1682 return false; 1683 if(cmp(vec1->ExtRootPathCost, !=, vec2->ExtRootPathCost)) 1684 return false; 1685 } 1686 1687 if(cmp(time1->remainingHops, !=, time2->remainingHops)) 1688 return false; 1689 1690 if(cmp(vec1->RRootID, !=, vec2->RRootID)) 1691 return false; 1692 if(cmp(vec1->IntRootPathCost, !=, vec2->IntRootPathCost)) 1693 return false; 1694 if(cmp(vec1->DesignatedBridgeID, !=, vec2->DesignatedBridgeID)) 1695 return false; 1696 if(cmp(vec1->DesignatedPortID, !=, vec2->DesignatedPortID)) 1697 return false; 1698 1699 return true; 1700 } 1701 1702 static bool betterorsamePriority(port_priority_vector_t *vec1, 1703 port_priority_vector_t *vec2, 1704 port_identifier_t pId1, 1705 port_identifier_t pId2, 1706 bool cist) 1707 { 1708 int result; 1709 1710 if(cist) 1711 { 1712 if(0 < (result = _ncmp(vec1->RootID, vec2->RootID))) 1713 return false; /* worse */ 1714 else if(0 > result) 1715 return true; /* better */ 1716 /* The same. Check further. */ 1717 if(0 < (result = _ncmp(vec1->ExtRootPathCost, vec2->ExtRootPathCost))) 1718 return false; /* worse */ 1719 else if(0 > result) 1720 return true; /* better */ 1721 /* The same. Check further. */ 1722 } 1723 1724 if(0 < (result = _ncmp(vec1->RRootID, vec2->RRootID))) 1725 return false; /* worse */ 1726 else if(0 > result) 1727 return true; /* better */ 1728 /* The same. Check further. */ 1729 1730 if(0 < (result = _ncmp(vec1->IntRootPathCost, vec2->IntRootPathCost))) 1731 return false; /* worse */ 1732 else if(0 > result) 1733 return true; /* better */ 1734 /* The same. Check further. */ 1735 1736 if(0 < (result = _ncmp(vec1->DesignatedBridgeID, vec2->DesignatedBridgeID))) 1737 return false; /* worse */ 1738 else if(0 > result) 1739 return true; /* better */ 1740 /* The same. Check further. */ 1741 1742 if(0 < (result = _ncmp(vec1->DesignatedPortID, vec2->DesignatedPortID))) 1743 return false; /* worse */ 1744 else if(0 > result) 1745 return true; /* better */ 1746 /* The same. Check further. */ 1747 1748 /* Port ID is a tie-breaker */ 1749 return cmp(pId1, <=, pId2); 1750 } 1751 1752 /* 13.26.1 betterorsameInfo */ 1753 static bool betterorsameInfo(per_tree_port_t *ptp, port_info_origin_t newInfoIs) 1754 { 1755 if((ioReceived == newInfoIs) && (ioReceived == ptp->infoIs)) 1756 return betterorsamePriority(&ptp->msgPriority, 1757 &ptp->portPriority, 1758 0, 0, (0 == ptp->MSTID)); 1759 else if((ioMine == newInfoIs) && (ioMine == ptp->infoIs)) 1760 return betterorsamePriority(&ptp->designatedPriority, 1761 &ptp->portPriority, 1762 0, 0, (0 == ptp->MSTID)); 1763 return false; 1764 } 1765 1766 /* 13.26.2 clearAllRcvdMsgs */ 1767 static bool clearAllRcvdMsgs(port_t *prt, bool dry_run) 1768 { 1769 per_tree_port_t *ptp; 1770 1771 if(dry_run) 1772 { 1773 FOREACH_PTP_IN_PORT(ptp, prt) 1774 if(ptp->rcvdMsg) 1775 return true; 1776 return false; 1777 } 1778 1779 FOREACH_PTP_IN_PORT(ptp, prt) 1780 ptp->rcvdMsg = false; 1781 1782 return false; 1783 } 1784 1785 /* 13.26.3 clearReselectTree */ 1786 static void clearReselectTree(tree_t *tree) 1787 { 1788 per_tree_port_t *ptp; 1789 1790 FOREACH_PTP_IN_TREE(ptp, tree) 1791 ptp->reselect = false; 1792 } 1793 1794 /* 13.26.4 fromSameRegion */ 1795 static bool fromSameRegion(port_t *prt) 1796 { 1797 /* Check for rcvdRSTP is superfluous here */ 1798 if((protoMSTP > prt->rcvdBpduData.protocolVersion)/* || (!prt->rcvdRSTP)*/) 1799 return false; 1800 return cmp(prt->bridge->MstConfigId, 1801 ==, prt->rcvdBpduData.mstConfigurationIdentifier); 1802 } 1803 1804 /* 13.26.5 newTcWhile */ 1805 static void newTcWhile(per_tree_port_t *ptp) 1806 { 1807 if(0 != ptp->tcWhile) 1808 return; 1809 1810 tree_t *tree = ptp->tree; 1811 port_t *prt = ptp->port; 1812 1813 if(prt->sendRSTP) 1814 { 1815 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 1816 1817 ptp->tcWhile = cist->portTimes.Hello_Time + 1; 1818 set_TopologyChange(tree, true, prt); 1819 1820 if(0 == ptp->MSTID) 1821 prt->newInfo = true; 1822 else 1823 prt->newInfoMsti = true; 1824 return; 1825 } 1826 1827 times_t *times = &tree->rootTimes; 1828 1829 ptp->tcWhile = times->Max_Age + times->Forward_Delay; 1830 set_TopologyChange(tree, true, prt); 1831 } 1832 1833 /* 13.26.6 rcvInfo */ 1834 static port_info_t rcvInfo(per_tree_port_t *ptp) 1835 { 1836 msti_configuration_message_t *msti_msg; 1837 per_tree_port_t *ptp_1; 1838 bool roleIsDesignated, cist; 1839 bool msg_Better_port, msg_SamePriorityAndTimers_port; 1840 port_priority_vector_t *mPri = &(ptp->msgPriority); 1841 times_t *mTimes = &(ptp->msgTimes); 1842 port_t *prt = ptp->port; 1843 bpdu_t *b = &(prt->rcvdBpduData); 1844 1845 if(bpduTypeTCN == b->bpduType) 1846 { 1847 prt->rcvdTcn = true; 1848 FOREACH_PTP_IN_PORT(ptp_1, prt) 1849 ptp_1->rcvdTc = true; 1850 return OtherInfo; 1851 } 1852 1853 if(0 == ptp->MSTID) 1854 { /* CIST */ 1855 if(protoSTP != b->protocolVersion) 1856 { 1857 switch(BPDU_FLAGS_ROLE_GET(b->flags)) 1858 { 1859 case encodedRoleAlternateBackup: 1860 case encodedRoleRoot: 1861 roleIsDesignated = false; 1862 break; 1863 case encodedRoleDesignated: 1864 roleIsDesignated = true; 1865 break; 1866 case encodedRoleMaster: 1867 /* 802.1D-2004 S9.2.9 P61. The Unknown value of Port Role 1868 * cannot be generated by a valid implementation; however, 1869 * this value is accepted on receipt. roleMaster in MSTP is 1870 * roleUnknown in RSTP. 1871 * NOTE.If the Unknown value of the Port Role parameter is 1872 * received, the state machines will effectively treat the RST 1873 * BPDU as if it were a Configuration BPDU 1874 */ 1875 if(protoRSTP == b->protocolVersion) 1876 { 1877 roleIsDesignated = true; 1878 break; 1879 } 1880 else 1881 { 1882 return OtherInfo; 1883 } 1884 break; 1885 default: 1886 return OtherInfo; 1887 } 1888 } 1889 else 1890 { /* 13.26.6.NOTE: A Configuration BPDU implicitly conveys a 1891 * Designated Port Role */ 1892 roleIsDesignated = true; 1893 } 1894 cist = true; 1895 1896 assign(mPri->RRootID, b->cistRRootID); 1897 assign(mPri->DesignatedPortID, b->cistPortID); 1898 assign(mPri->RootID, b->cistRootID); 1899 assign(mPri->ExtRootPathCost, b->cistExtRootPathCost); 1900 /* messageTimes */ 1901 #define NEAREST_WHOLE_SECOND(msgTime) \ 1902 ((128 > msgTime[1]) ? msgTime[0] : msgTime[0] + 1) 1903 mTimes->Forward_Delay = NEAREST_WHOLE_SECOND(b->ForwardDelay); 1904 mTimes->Max_Age = NEAREST_WHOLE_SECOND(b->MaxAge); 1905 mTimes->Message_Age = NEAREST_WHOLE_SECOND(b->MessageAge); 1906 mTimes->Hello_Time = NEAREST_WHOLE_SECOND(b->HelloTime); 1907 if(protoMSTP > b->protocolVersion) 1908 { /* STP Configuration BPDU or RST BPDU */ 1909 assign(mPri->IntRootPathCost, __constant_cpu_to_be32(0)); 1910 assign(mPri->DesignatedBridgeID, b->cistRRootID); 1911 /* messageTimes.remainingHops */ 1912 assign(mTimes->remainingHops, prt->bridge->MaxHops); 1913 } 1914 else 1915 { /* MST BPDU */ 1916 assign(mPri->IntRootPathCost, b->cistIntRootPathCost); 1917 assign(mPri->DesignatedBridgeID, b->cistBridgeID); 1918 /* messageTimes.remainingHops */ 1919 assign(mTimes->remainingHops, b->cistRemainingHops); 1920 } 1921 } 1922 else 1923 { /* MSTI */ 1924 if(protoMSTP > b->protocolVersion) 1925 return OtherInfo; 1926 msti_msg = ptp->rcvdMstiConfig; 1927 switch(BPDU_FLAGS_ROLE_GET(msti_msg->flags)) 1928 { 1929 case encodedRoleAlternateBackup: 1930 case encodedRoleRoot: 1931 roleIsDesignated = false; 1932 break; 1933 case encodedRoleDesignated: 1934 roleIsDesignated = true; 1935 break; 1936 default: 1937 return OtherInfo; 1938 } 1939 cist = false; 1940 1941 assign(mPri->RRootID, msti_msg->mstiRRootID); 1942 assign(mPri->IntRootPathCost, msti_msg->mstiIntRootPathCost); 1943 /* Build MSTI DesignatedBridgeID */ 1944 assign(mPri->DesignatedBridgeID, b->cistBridgeID); 1945 assign(mPri->DesignatedBridgeID.s.priority, ptp->MSTID); 1946 SET_PRIORITY_IN_IDENTIFIER(msti_msg->bridgeIdentifierPriority, 1947 mPri->DesignatedBridgeID); 1948 /* Build MSTI DesignatedPortID */ 1949 assign(mPri->DesignatedPortID, b->cistPortID); 1950 SET_PRIORITY_IN_IDENTIFIER(msti_msg->portIdentifierPriority, 1951 mPri->DesignatedPortID); 1952 /* messageTimes */ 1953 assign(mTimes->remainingHops, msti_msg->remainingHops); 1954 } 1955 1956 msg_Better_port = !betterorsamePriority(&(ptp->portPriority), mPri, 1957 0, 0, cist); 1958 if(roleIsDesignated) 1959 { 1960 /* a).1) */ 1961 if(msg_Better_port 1962 || ((0 == memcmp(mPri->DesignatedBridgeID.s.mac_address, 1963 ptp->portPriority.DesignatedBridgeID.s.mac_address, 1964 ETH_ALEN) 1965 ) 1966 && (0 == ((mPri->DesignatedPortID 1967 ^ ptp->portPriority.DesignatedPortID 1968 ) & __constant_cpu_to_be16(0x0FFF) 1969 ) 1970 ) 1971 ) 1972 ) 1973 return SuperiorDesignatedInfo; 1974 1975 /* a).2) */ 1976 /* We already know that msgPriority _IS_NOT_BETTER_than portPriority. 1977 * So, if msgPriority _IS_SAME_OR_BETTER_than portPriority then 1978 * msgPriority _IS_SAME_as portPriority. 1979 */ 1980 msg_SamePriorityAndTimers_port = 1981 samePriorityAndTimers(mPri, &(ptp->portPriority), 1982 mTimes, &(ptp->portTimes), 1983 cist); 1984 if((!msg_SamePriorityAndTimers_port) 1985 && betterorsamePriority(mPri, &(ptp->portPriority), 0, 0, cist) 1986 ) 1987 return SuperiorDesignatedInfo; 1988 1989 /* b) */ 1990 if(msg_SamePriorityAndTimers_port && (ioReceived == ptp->infoIs)) 1991 return RepeatedDesignatedInfo; 1992 1993 /* c) */ 1994 return InferiorDesignatedInfo; 1995 } 1996 1997 /* d) */ 1998 if(!msg_Better_port) 1999 return InferiorRootAlternateInfo; 2000 2001 return OtherInfo; 2002 } 2003 2004 /* 13.26.7 recordAgreement */ 2005 static void recordAgreement(per_tree_port_t *ptp) 2006 { 2007 bool cist_agreed, cist_proposing; 2008 per_tree_port_t *cist; 2009 port_t *prt = ptp->port; 2010 bpdu_t *b = &(prt->rcvdBpduData); 2011 2012 if(0 == ptp->MSTID) 2013 { /* CIST */ 2014 if(rstpVersion(prt->bridge) && prt->operPointToPointMAC 2015 && (b->flags & (1 << offsetAgreement)) 2016 ) 2017 { 2018 ptp->agreed = true; 2019 ptp->proposing = false; 2020 } 2021 else 2022 ptp->agreed = false; 2023 cist_agreed = ptp->agreed; 2024 cist_proposing = ptp->proposing; 2025 if(!prt->rcvdInternal) 2026 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2027 { 2028 ptp->agreed = cist_agreed; 2029 ptp->proposing = cist_proposing; 2030 } 2031 return; 2032 } 2033 /* MSTI */ 2034 cist = GET_CIST_PTP_FROM_PORT(prt); 2035 if(prt->operPointToPointMAC 2036 && cmp(b->cistRootID, ==, cist->portPriority.RootID) 2037 && cmp(b->cistExtRootPathCost, ==, cist->portPriority.ExtRootPathCost) 2038 && cmp(b->cistRRootID, ==, cist->portPriority.RRootID) 2039 && (ptp->rcvdMstiConfig->flags & (1 << offsetAgreement)) 2040 ) 2041 { 2042 ptp->agreed = true; 2043 ptp->proposing = false; 2044 } 2045 else 2046 ptp->agreed = false; 2047 } 2048 2049 /* 13.26.8 recordDispute */ 2050 static void recordDispute(per_tree_port_t *ptp) 2051 { 2052 port_t *prt; 2053 2054 if(0 == ptp->MSTID) 2055 { /* CIST */ 2056 prt = ptp->port; 2057 /* 802.1Q-2005(-2011) is somewhat unclear for the case 2058 * (!prt->rcvdInternal): if we should record dispute for all MSTIs 2059 * unconditionally or only when CIST Learning flag is set in BPDU. 2060 * I guess that in this case MSTIs should be in sync with CIST 2061 * so record dispute for the MSTIs only when the same is done for CIST. 2062 * Additional supporting argument to this guess is that in 2063 * setTcFlags() we do the same. 2064 * But that is only a guess and I could be wrong here ;) 2065 */ 2066 if(prt->rcvdBpduData.flags & (1 << offsetLearnig)) 2067 { 2068 ptp->disputed = true; 2069 ptp->agreed = false; 2070 if(!prt->rcvdInternal) 2071 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2072 { 2073 ptp->disputed = true; 2074 ptp->agreed = false; 2075 } 2076 } 2077 return; 2078 } 2079 /* MSTI */ 2080 if(ptp->rcvdMstiConfig->flags & (1 << offsetLearnig)) 2081 { 2082 ptp->disputed = true; 2083 ptp->agreed = false; 2084 } 2085 } 2086 2087 /* 13.26.9 recordMastered */ 2088 static void recordMastered(per_tree_port_t *ptp) 2089 { 2090 port_t *prt = ptp->port; 2091 2092 if(0 == ptp->MSTID) 2093 { /* CIST */ 2094 if(!prt->rcvdInternal) 2095 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2096 ptp->mastered = false; 2097 return; 2098 } 2099 /* MSTI */ 2100 ptp->mastered = prt->operPointToPointMAC 2101 && (ptp->rcvdMstiConfig->flags & (1 << offsetMaster)); 2102 } 2103 2104 /* 13.26.f) recordPriority */ 2105 static void recordPriority(per_tree_port_t *ptp) 2106 { 2107 assign(ptp->portPriority, ptp->msgPriority); 2108 } 2109 2110 /* 13.26.10 recordProposal */ 2111 static void recordProposal(per_tree_port_t *ptp) 2112 { 2113 bool cist_proposed; 2114 port_t *prt; 2115 2116 /* 802.1Q-2005 says to check if received message conveys 2117 * a Designated Port Role. But there is no need in this check, 2118 * as it is always true. This function is called only in two states: 2119 * PISM_SUPERIOR_DESIGNATED and PISM_REPEATED_DESIGNATED, which 2120 * can be entered only if rcvInfo returns 2121 * SuperiorDesignatedInfo or RepeatedDesignatedInfo. 2122 * Which in turn can only happen if message conveys designated role 2123 * (see rcvInfo). 2124 */ 2125 if(0 == ptp->MSTID) 2126 { /* CIST */ 2127 prt = ptp->port; 2128 if(prt->rcvdBpduData.flags & (1 << offsetProposal)) 2129 ptp->proposed = true; 2130 cist_proposed = ptp->proposed; 2131 if(!prt->rcvdInternal) 2132 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2133 ptp->proposed = cist_proposed; 2134 return; 2135 } 2136 /* MSTI */ 2137 if(ptp->rcvdMstiConfig->flags & (1 << offsetProposal)) 2138 ptp->proposed = true; 2139 } 2140 2141 /* 13.26.11 recordTimes */ 2142 static void recordTimes(per_tree_port_t *ptp) 2143 { 2144 /* 802.1Q-2005 and 802.1D-2004 both say that we have to copy 2145 * Hello_Time from msgTimes to portTimes. 2146 * 802.1Q-2011, on the other hand, says that Hello_Time should be set 2147 * to the default here. 2148 * As we have configurable Hello_Time, I choose the third option: 2149 * preserve the configured Hello_Time, It is in accordance with the 2150 * spirit of 802.1Q-2011, if we allow Hello_Time to be configurable. 2151 */ 2152 __u8 prev_Hello_Time = 0; 2153 assign(prev_Hello_Time, ptp->portTimes.Hello_Time); 2154 assign(ptp->portTimes, ptp->msgTimes); 2155 assign(ptp->portTimes.Hello_Time, prev_Hello_Time); 2156 } 2157 2158 /* 13.24.s) + 17.19.7 of 802.1D : fdbFlush */ 2159 static void set_fdbFlush(per_tree_port_t *ptp) 2160 { 2161 port_t *prt = ptp->port; 2162 2163 if(prt->operEdge || prt->deleted) 2164 { 2165 ptp->fdbFlush = false; 2166 return; 2167 } 2168 2169 bridge_t *br = prt->bridge; 2170 2171 if(rstpVersion(br)) 2172 { 2173 ptp->fdbFlush = true; 2174 ptp->calledFromFlushRoutine = true; 2175 MSTP_OUT_flush_all_fids(ptp); 2176 ptp->calledFromFlushRoutine = false; 2177 } 2178 else 2179 { 2180 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 2181 unsigned int FwdDelay = cist->designatedTimes.Forward_Delay; 2182 /* Initiate rapid ageing */ 2183 MSTP_OUT_set_ageing_time(prt, FwdDelay); 2184 assign(prt->rapidAgeingWhile, FwdDelay); 2185 ptp->fdbFlush = false; 2186 } 2187 } 2188 2189 /* 13.26.12 setRcvdMsgs */ 2190 static void setRcvdMsgs(port_t *prt) 2191 { 2192 msti_configuration_message_t *msti_msg; 2193 int i; 2194 __be16 msg_MSTID; 2195 bool found; 2196 per_tree_port_t *ptp = GET_CIST_PTP_FROM_PORT(prt); 2197 ptp->rcvdMsg = true; 2198 2199 /* 802.1Q-2005 says: 2200 * "Make the received CST or CIST message available to the CIST Port 2201 * Information state machines" 2202 * No need to do something special here, we already have rcvdBpduData. 2203 */ 2204 2205 if(prt->rcvdInternal) 2206 { 2207 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2208 { 2209 found = false; 2210 /* Find if message for this MSTI is conveyed in the BPDU */ 2211 for(i = 0, msti_msg = prt->rcvdBpduData.mstConfiguration; 2212 i < prt->rcvdBpduNumOfMstis; 2213 ++i, ++msti_msg) 2214 { 2215 msg_MSTID = msti_msg->mstiRRootID.s.priority 2216 & __constant_cpu_to_be16(0x0FFF); 2217 if(msg_MSTID == ptp->MSTID) 2218 { 2219 found = true; 2220 break; 2221 } 2222 } 2223 if(found) 2224 { 2225 ptp->rcvdMsg = true; 2226 /* 802.1Q-2005 says: 2227 * "Make available each MSTI message and the common parts of 2228 * the CIST message priority (the CIST Root Identifier, 2229 * External Root Path Cost and Regional Root Identifier) 2230 * to the Port Information state machine for that MSTI" 2231 * We set pointer to the MSTI configuration message for 2232 * fast access, while do not anything special for common 2233 * parts of the message, as the whole message is available 2234 * in rcvdBpduData. 2235 */ 2236 ptp->rcvdMstiConfig = msti_msg; 2237 } 2238 } 2239 } 2240 } 2241 2242 /* 13.26.13 setReRootTree */ 2243 static void setReRootTree(tree_t *tree) 2244 { 2245 per_tree_port_t *ptp; 2246 2247 FOREACH_PTP_IN_TREE(ptp, tree) 2248 ptp->reRoot = true; 2249 } 2250 2251 /* 13.26.14 setSelectedTree */ 2252 static void setSelectedTree(tree_t *tree) 2253 { 2254 per_tree_port_t *ptp; 2255 2256 /* 2257 * 802.1Q-2005 says that I should check "reselect" var 2258 * and take no action if it is "true" for any of the ports. 2259 * But there is no need in this check as setSelectedTree is called 2260 * only from PRSSM_to_ROLE_SELECTION, which is atomic, and it is called 2261 * in this sequence (13.33): 2262 * clearReselectTree(tree); 2263 * updtRolesTree(tree); 2264 * setSelectedTree(tree); 2265 * And we know that clearReselectTree resets "reselect" for all ports 2266 * and updtRolesTree() does not change value of "reselect". 2267 */ 2268 FOREACH_PTP_IN_TREE(ptp, tree) 2269 ptp->selected = true; 2270 } 2271 2272 /* 13.26.15 setSyncTree */ 2273 static void setSyncTree(tree_t *tree) 2274 { 2275 per_tree_port_t *ptp; 2276 2277 FOREACH_PTP_IN_TREE(ptp, tree) 2278 ptp->sync = true; 2279 } 2280 2281 /* 13.26.16 setTcFlags */ 2282 static void setTcFlags(per_tree_port_t *ptp) 2283 { 2284 __u8 cistFlags; 2285 port_t *prt; 2286 2287 if(0 == ptp->MSTID) 2288 { /* CIST */ 2289 prt = ptp->port; 2290 cistFlags = prt->rcvdBpduData.flags; 2291 if(cistFlags & (1 << offsetTcAck)) 2292 prt->rcvdTcAck = true; 2293 if(cistFlags & (1 << offsetTc)) 2294 { 2295 ptp->rcvdTc = true; 2296 if(!prt->rcvdInternal) 2297 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2298 ptp->proposed = true; 2299 } 2300 return; 2301 } 2302 /* MSTI */ 2303 if(ptp->rcvdMstiConfig->flags & (1 << offsetTc)) 2304 ptp->rcvdTc = true; 2305 } 2306 2307 /* 13.26.17 setTcPropTree */ 2308 static void setTcPropTree(per_tree_port_t *ptp) 2309 { 2310 per_tree_port_t *ptp_1; 2311 2312 if(ptp->port->restrictedTcn) 2313 return; 2314 2315 FOREACH_PTP_IN_TREE(ptp_1, ptp->tree) 2316 { 2317 if(ptp != ptp_1) 2318 ptp_1->tcProp = true; 2319 } 2320 } 2321 2322 /* 13.26.18 syncMaster */ 2323 static void syncMaster(bridge_t *br) 2324 { 2325 per_tree_port_t *ptp; 2326 tree_t *tree = GET_CIST_TREE(br); 2327 2328 /* For each MSTI */ 2329 list_for_each_entry_continue(tree, &br->trees, bridge_list) 2330 { 2331 FOREACH_PTP_IN_TREE(ptp, tree) 2332 { 2333 /* for each Port that has infoInternal set */ 2334 if(ptp->port->infoInternal) 2335 { 2336 ptp->agree = false; 2337 ptp->agreed = false; 2338 ptp->synced = false; 2339 ptp->sync = true; 2340 } 2341 } 2342 } 2343 } 2344 2345 /* 13.26.19 txConfig */ 2346 static void txConfig(port_t *prt) 2347 { 2348 bpdu_t b; 2349 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 2350 2351 if(prt->deleted || (roleDisabled == cist->role) || prt->dontTxmtBpdu) 2352 return; 2353 2354 b.protocolIdentifier = 0; 2355 b.protocolVersion = protoSTP; 2356 b.bpduType = bpduTypeConfig; 2357 /* Standard says "tcWhile ... for the Port". Which one tcWhile? 2358 * I guess that this means tcWhile for the CIST. 2359 * But that is only a guess and I could be wrong here ;) 2360 */ 2361 b.flags = (0 != cist->tcWhile) ? (1 << offsetTc) : 0; 2362 if(prt->tcAck) 2363 b.flags |= (1 << offsetTcAck); 2364 assign(b.cistRootID, cist->designatedPriority.RootID); 2365 assign(b.cistExtRootPathCost, cist->designatedPriority.ExtRootPathCost); 2366 assign(b.cistRRootID, cist->designatedPriority.DesignatedBridgeID); 2367 assign(b.cistPortID, cist->designatedPriority.DesignatedPortID); 2368 b.MessageAge[0] = cist->designatedTimes.Message_Age; 2369 b.MessageAge[1] = 0; 2370 b.MaxAge[0] = cist->designatedTimes.Max_Age; 2371 b.MaxAge[1] = 0; 2372 b.HelloTime[0] = cist->portTimes.Hello_Time; /* ! use portTimes ! */ 2373 b.HelloTime[1] = 0; 2374 b.ForwardDelay[0] = cist->designatedTimes.Forward_Delay; 2375 b.ForwardDelay[1] = 0; 2376 2377 MSTP_OUT_tx_bpdu(prt, &b, CONFIG_BPDU_SIZE); 2378 } 2379 2380 static inline __u8 message_role_from_port_role(per_tree_port_t *ptp) 2381 { 2382 switch(ptp->role) 2383 { 2384 case roleRoot: 2385 return encodedRoleRoot; 2386 case roleDesignated: 2387 return encodedRoleDesignated; 2388 case roleAlternate: 2389 case roleBackup: 2390 return encodedRoleAlternateBackup; 2391 case roleMaster: 2392 return encodedRoleMaster; 2393 default: 2394 ERROR_PRTNAME(ptp->port->bridge, ptp->port, 2395 "Attempt to send from port with Disabled role"); 2396 return encodedRoleAlternateBackup; 2397 } 2398 } 2399 2400 /* 802.1Q-2005: 13.26.20 txMstp 2401 * 802.1Q-2011: 13.27.27 txRstp 2402 */ 2403 static void txMstp(port_t *prt) 2404 { 2405 bpdu_t b; 2406 bridge_t *br = prt->bridge; 2407 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 2408 int msti_msgs_total_size; 2409 per_tree_port_t *ptp; 2410 msti_configuration_message_t *msti_msg; 2411 2412 if(prt->deleted || (roleDisabled == cist->role) || prt->dontTxmtBpdu) 2413 return; 2414 2415 b.protocolIdentifier = 0; 2416 b.bpduType = bpduTypeRST; 2417 /* Standard says "{tcWhile, agree, proposing} ... for the Port". 2418 * Which one {tcWhile, agree, proposing}? 2419 * I guess that this means {tcWhile, agree, proposing} for the CIST. 2420 * But that is only a guess and I could be wrong here ;) 2421 */ 2422 b.flags = BPDU_FLAGS_ROLE_SET(message_role_from_port_role(cist)); 2423 if(0 != cist->tcWhile) 2424 b.flags |= (1 << offsetTc); 2425 if(cist->proposing) 2426 b.flags |= (1 << offsetProposal); 2427 if(cist->learning) 2428 b.flags |= (1 << offsetLearnig); 2429 if(cist->forwarding) 2430 b.flags |= (1 << offsetForwarding); 2431 if(cist->agree) 2432 b.flags |= (1 << offsetAgreement); 2433 assign(b.cistRootID, cist->designatedPriority.RootID); 2434 assign(b.cistExtRootPathCost, cist->designatedPriority.ExtRootPathCost); 2435 assign(b.cistRRootID, cist->designatedPriority.RRootID); 2436 assign(b.cistPortID, cist->designatedPriority.DesignatedPortID); 2437 b.MessageAge[0] = cist->designatedTimes.Message_Age; 2438 b.MessageAge[1] = 0; 2439 b.MaxAge[0] = cist->designatedTimes.Max_Age; 2440 b.MaxAge[1] = 0; 2441 b.HelloTime[0] = cist->portTimes.Hello_Time; /* ! use portTimes ! */ 2442 b.HelloTime[1] = 0; 2443 b.ForwardDelay[0] = cist->designatedTimes.Forward_Delay; 2444 b.ForwardDelay[1] = 0; 2445 2446 b.version1_len = 0; 2447 2448 if(br->ForceProtocolVersion < protoMSTP) 2449 { 2450 b.protocolVersion = protoRSTP; 2451 MSTP_OUT_tx_bpdu(prt, &b, RST_BPDU_SIZE); 2452 return; 2453 } 2454 2455 b.protocolVersion = protoMSTP; 2456 2457 /* MST specific fields */ 2458 assign(b.mstConfigurationIdentifier, br->MstConfigId); 2459 assign(b.cistIntRootPathCost, cist->designatedPriority.IntRootPathCost); 2460 assign(b.cistBridgeID, cist->designatedPriority.DesignatedBridgeID); 2461 assign(b.cistRemainingHops, cist->designatedTimes.remainingHops); 2462 2463 msti_msgs_total_size = 0; 2464 ptp = cist; 2465 msti_msg = b.mstConfiguration; 2466 /* 13.26.20.f) requires that msti configs should be inserted in 2467 * MSTID order. This is met by inserting trees in port's list of trees 2468 * in sorted (by MSTID) order (see MSTP_IN_create_msti) */ 2469 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2470 { 2471 msti_msg->flags = 2472 BPDU_FLAGS_ROLE_SET(message_role_from_port_role(ptp)); 2473 if(0 != ptp->tcWhile) 2474 msti_msg->flags |= (1 << offsetTc); 2475 if(ptp->proposing) 2476 msti_msg->flags |= (1 << offsetProposal); 2477 if(ptp->learning) 2478 msti_msg->flags |= (1 << offsetLearnig); 2479 if(ptp->forwarding) 2480 msti_msg->flags |= (1 << offsetForwarding); 2481 if(ptp->agree) 2482 msti_msg->flags |= (1 << offsetAgreement); 2483 if(ptp->master) 2484 msti_msg->flags |= (1 << offsetMaster); 2485 assign(msti_msg->mstiRRootID, ptp->designatedPriority.RRootID); 2486 assign(msti_msg->mstiIntRootPathCost, 2487 ptp->designatedPriority.IntRootPathCost); 2488 msti_msg->bridgeIdentifierPriority = 2489 GET_PRIORITY_FROM_IDENTIFIER(ptp->designatedPriority.DesignatedBridgeID); 2490 msti_msg->portIdentifierPriority = 2491 GET_PRIORITY_FROM_IDENTIFIER(ptp->designatedPriority.DesignatedPortID); 2492 assign(msti_msg->remainingHops, ptp->designatedTimes.remainingHops); 2493 2494 msti_msgs_total_size += sizeof(msti_configuration_message_t); 2495 ++msti_msg; 2496 } 2497 2498 assign(b.version3_len, __cpu_to_be16(MST_BPDU_VER3LEN_WO_MSTI_MSGS 2499 + msti_msgs_total_size)); 2500 MSTP_OUT_tx_bpdu(prt, &b, MST_BPDU_SIZE_WO_MSTI_MSGS 2501 + msti_msgs_total_size); 2502 } 2503 2504 /* 13.26.a) txTcn */ 2505 static void txTcn(port_t *prt) 2506 { 2507 bpdu_t b; 2508 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 2509 2510 if(prt->deleted || (roleDisabled == cist->role) || prt->dontTxmtBpdu) 2511 return; 2512 2513 b.protocolIdentifier = 0; 2514 b.protocolVersion = protoSTP; 2515 b.bpduType = bpduTypeTCN; 2516 2517 MSTP_OUT_tx_bpdu(prt, &b, TCN_BPDU_SIZE); 2518 } 2519 2520 /* 13.26.21 updtBPDUVersion */ 2521 static void updtBPDUVersion(port_t *prt) 2522 { 2523 if(protoRSTP <= prt->rcvdBpduData.protocolVersion) 2524 prt->rcvdRSTP = true; 2525 else 2526 prt->rcvdSTP = true; 2527 } 2528 2529 /* 13.26.22 updtRcvdInfoWhile */ 2530 static void updtRcvdInfoWhile(per_tree_port_t *ptp) 2531 { 2532 port_t *prt = ptp->port; 2533 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 2534 unsigned int Message_Age = cist->portTimes.Message_Age; 2535 unsigned int Max_Age = cist->portTimes.Max_Age; 2536 unsigned int Hello_Time = cist->portTimes.Hello_Time; 2537 2538 /* NOTE: 802.1Q-2005(-2011) says that we should use 2539 * "remainingHops ... from the CIST's portTimes parameter" 2540 * As for me this is clear oversight in the standard, 2541 * the remainingHops should be taken form the port's own portTimes, 2542 * not from CIST's. After all, if we don't use port's own 2543 * remainingHops here, they aren't used anywhere at all. 2544 * Besides, there is a scenario which breaks if we use CIST's 2545 * remainingHops here: 2546 * 1) Connect two switches (SW1,SW2) with two ports, thus forming a loop 2547 * 2) Configure them to be in the same region, with two trees: 2548 * 0 (CIST) and 1. 2549 * 3) at SW1# mstpctl settreeprio br0 1 4 2550 * SW1 becomes regional root in tree 1 2551 * 4) at SW2# mstpctl settreeprio br0 1 14 2552 * 5) at SW1# mstpctl settreeprio br0 1 9 2553 * 2554 * And now we have the classic "count-to-infinity" problem when the old 2555 * info ("Regional Root is SW1 with priority 4") circulates in the loop, 2556 * because it is better than current info ("Regional Root is SW1 with 2557 * priority 9"). The only way to get rid of that old info is 2558 * to age it out by the means of remainingHops counter. 2559 * In this situation we certainly must use counter from tree 1, 2560 * not CIST's. 2561 */ 2562 if((!prt->rcvdInternal && ((Message_Age + 1) <= Max_Age)) 2563 || (prt->rcvdInternal && (ptp->portTimes.remainingHops > 1)) 2564 ) 2565 ptp->rcvdInfoWhile = 3 * Hello_Time; 2566 else 2567 ptp->rcvdInfoWhile = 0; 2568 } 2569 2570 static void updtbrAssuRcvdInfoWhile(port_t *prt) 2571 { 2572 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 2573 2574 prt->brAssuRcvdInfoWhile = 3 * cist->portTimes.Hello_Time; 2575 } 2576 2577 /* 13.26.24 updtRolesDisabledTree */ 2578 static void updtRolesDisabledTree(tree_t *tree) 2579 { 2580 per_tree_port_t *ptp; 2581 2582 FOREACH_PTP_IN_TREE(ptp, tree) 2583 ptp->selectedRole = roleDisabled; 2584 } 2585 2586 /* Aux function, not in standard. 2587 * Sets reselect for all MSTIs in the case CIST state for the port changes 2588 */ 2589 static void reselectMSTIs(port_t *prt) 2590 { 2591 per_tree_port_t *ptp = GET_CIST_PTP_FROM_PORT(prt); 2592 2593 /* For each non-CIST ptp */ 2594 list_for_each_entry_continue(ptp, &prt->trees, port_list) 2595 ptp->reselect = true; 2596 } 2597 2598 /* 13.26.23 updtRolesTree */ 2599 static void updtRolesTree(tree_t *tree) 2600 { 2601 per_tree_port_t *ptp, *root_ptp = NULL; 2602 port_priority_vector_t root_path_priority; 2603 bridge_identifier_t prevRRootID = tree->rootPriority.RRootID; 2604 __be32 prevExtRootPathCost = tree->rootPriority.ExtRootPathCost; 2605 bool cist = (0 == tree->MSTID); 2606 2607 /* a), b) Select new root priority vector = {rootPriority, rootPortId} */ 2608 /* Initial value = bridge priority vector = {BridgePriority, 0} */ 2609 assign(tree->rootPriority, tree->BridgePriority); 2610 assign(tree->rootPortId, __constant_cpu_to_be16(0)); 2611 /* Now check root path priority vectors of all ports in tree and see if 2612 * there is a better vector */ 2613 FOREACH_PTP_IN_TREE(ptp, tree) 2614 { 2615 port_t *prt = ptp->port; 2616 /* 802.1Q says to calculate root priority vector only if port 2617 * is not Disabled, but check (infoIs == ioReceived) covers 2618 * the case (infoIs != ioDisabled). 2619 */ 2620 if((ioReceived == ptp->infoIs) && !prt->restrictedRole 2621 && cmp(ptp->portPriority.DesignatedBridgeID, !=, 2622 tree->BridgeIdentifier) 2623 ) 2624 { 2625 root_path_priority = ptp->portPriority; 2626 if(prt->rcvdInternal) 2627 { 2628 assign(root_path_priority.IntRootPathCost, 2629 __cpu_to_be32(__be32_to_cpu(root_path_priority.IntRootPathCost) 2630 + ptp->InternalPortPathCost) 2631 ); 2632 } 2633 else if(cist) /* Yes, this check might be superfluous, 2634 * but I want to be on the safe side */ 2635 { 2636 assign(root_path_priority.ExtRootPathCost, 2637 __cpu_to_be32(__be32_to_cpu(root_path_priority.ExtRootPathCost) 2638 + prt->ExternalPortPathCost) 2639 ); 2640 assign(root_path_priority.RRootID, tree->BridgeIdentifier); 2641 assign(root_path_priority.IntRootPathCost, 2642 __constant_cpu_to_be32(0)); 2643 } 2644 if(betterorsamePriority(&root_path_priority, &tree->rootPriority, 2645 ptp->portId, tree->rootPortId, cist)) 2646 { 2647 assign(tree->rootPriority, root_path_priority); 2648 assign(tree->rootPortId, ptp->portId); 2649 root_ptp = ptp; 2650 } 2651 } 2652 } 2653 2654 /* 802.1q-2005 says, that at some point we need compare portTimes with 2655 * "... one for the Root Port ...". Bad IEEE! Why not mention explicit 2656 * var names??? (see 13.26.23.g) for instance) 2657 * These comparisons happen three times, twice in clause g) 2658 * and once in clause i). Look for samePriorityAndTimers() calls. 2659 * So, now I should guess what will work for the "times for the Root Port". 2660 * Thanks to Rajani's experiments I know for sure that I should use 2661 * designatedTimes here. Thank you, Rajani! 2662 * NOTE: Both Alex Rozin (author of rstplib) and Srinivas Aji (author 2663 * of rstpd) also compare portTimes with designatedTimes. 2664 */ 2665 2666 /* c) Set new rootTimes */ 2667 if(root_ptp) 2668 { 2669 assign(tree->rootTimes, root_ptp->portTimes); 2670 port_t *prt = root_ptp->port; 2671 if(prt->rcvdInternal) 2672 { 2673 if(tree->rootTimes.remainingHops) 2674 --(tree->rootTimes.remainingHops); 2675 } 2676 else 2677 ++(tree->rootTimes.Message_Age); 2678 } 2679 else 2680 { 2681 assign(tree->rootTimes, tree->BridgeTimes); 2682 } 2683 2684 FOREACH_PTP_IN_TREE(ptp, tree) 2685 { 2686 port_t *prt = ptp->port; 2687 2688 /* d) Set new designatedPriority */ 2689 assign(ptp->designatedPriority, tree->rootPriority); 2690 assign(ptp->designatedPriority.DesignatedBridgeID, 2691 tree->BridgeIdentifier); 2692 assign(ptp->designatedPriority.DesignatedPortID, ptp->portId); 2693 /* I am not sure which condition to check here, as 802.1Q-2005 says: 2694 * "... If {Port} is attached to a LAN that has one or more STP Bridges 2695 * attached (as determined by the Port Protocol Migration state 2696 * machine) ..." -- why not to mention explicit var name? Bad IEEE. 2697 * But I guess that sendSTP (i.e. !sendRSTP) var will do ;) 2698 */ 2699 if(cist && !prt->sendRSTP) 2700 assign(ptp->designatedPriority.RRootID, tree->BridgeIdentifier); 2701 2702 /* e) Set new designatedTimes */ 2703 assign(ptp->designatedTimes, tree->rootTimes); 2704 /* Keep the configured Hello_Time for the port. 2705 * NOTE: this is in accordance with the spirit of 802.1D-2004. 2706 * Also, this does not contradict 802.1Q-2005(-2011), as in these 2707 * standards both designatedTimes and rootTimes structures 2708 * don't have Hello_Time member. 2709 */ 2710 assign(ptp->designatedTimes.Hello_Time, ptp->portTimes.Hello_Time); 2711 } 2712 2713 /* syncMaster */ 2714 if(cist && cmp(tree->rootPriority.RRootID, !=, prevRRootID) 2715 && ((0 != tree->rootPriority.ExtRootPathCost) 2716 || (0 != prevExtRootPathCost) 2717 ) 2718 ) 2719 syncMaster(tree->bridge); 2720 2721 FOREACH_PTP_IN_TREE(ptp, tree) 2722 { 2723 port_t *prt = ptp->port; 2724 per_tree_port_t *cist_tree = GET_CIST_PTP_FROM_PORT(prt); 2725 2726 /* f) Set Disabled role */ 2727 if(ioDisabled == ptp->infoIs) 2728 { 2729 ptp->selectedRole = roleDisabled; 2730 continue; 2731 } 2732 2733 if(!cist && (ioReceived == cist_tree->infoIs) && !prt->infoInternal) 2734 { 2735 /* g) Set role for the boundary port in MSTI */ 2736 if(roleRoot == cist_tree->selectedRole) 2737 { 2738 ptp->selectedRole = roleMaster; 2739 if(!samePriorityAndTimers(&ptp->portPriority, 2740 &ptp->designatedPriority, 2741 &ptp->portTimes, 2742 &ptp->designatedTimes, 2743 /*cist*/ false)) 2744 ptp->updtInfo = true; 2745 continue; 2746 } 2747 /* Bad IEEE again! It says in 13.26.23 g) 2) that 2748 * MSTI state should follow CIST state only for the case of 2749 * Alternate port. This is obviously wrong! 2750 * In the descriptive clause 13.13 f) it says: 2751 * "At a Boundary Port frames allocated to the CIST and 2752 * all MSTIs are forwarded or not forwarded alike. 2753 * This is because Port Role assignments are such that 2754 * if the CIST Port Role is Root Port, the MSTI Port Role 2755 * will be Master Port, and if the CIST Port Role is 2756 * Designated Port, Alternate Port, Backup Port, 2757 * or Disabled Port, each MSTI’s Port Role will be the same." 2758 * So, ignore wrong 13.26.23 g) 2) and do as stated in 13.13 f) ! 2759 */ 2760 /* if(roleAlternate == cist_tree->selectedRole) */ 2761 { 2762 ptp->selectedRole = cist_tree->selectedRole; 2763 if(!samePriorityAndTimers(&ptp->portPriority, 2764 &ptp->designatedPriority, 2765 &ptp->portTimes, 2766 &ptp->designatedTimes, 2767 /*cist*/ false)) 2768 ptp->updtInfo = true; 2769 continue; 2770 } 2771 } 2772 else 2773 /* if(cist || (ioReceived != cist_tree->infoIs) || prt->infoInternal) */ 2774 { 2775 /* h) Set role for the aged info */ 2776 if(ioAged == ptp->infoIs) 2777 { 2778 ptp->selectedRole = roleDesignated; 2779 ptp->updtInfo = true; 2780 continue; 2781 } 2782 /* i) Set role for the mine info */ 2783 if(ioMine == ptp->infoIs) 2784 { 2785 ptp->selectedRole = roleDesignated; 2786 if(!samePriorityAndTimers(&ptp->portPriority, 2787 &ptp->designatedPriority, 2788 &ptp->portTimes, 2789 &ptp->designatedTimes, 2790 cist)) 2791 ptp->updtInfo = true; 2792 continue; 2793 } 2794 if(ioReceived == ptp->infoIs) 2795 { 2796 /* j) Set Root role */ 2797 if(root_ptp == ptp) 2798 { 2799 ptp->selectedRole = roleRoot; 2800 ptp->updtInfo = false; 2801 } 2802 else 2803 { 2804 if(betterorsamePriority(&ptp->portPriority, 2805 &ptp->designatedPriority, 2806 0, 0, cist)) 2807 { 2808 if(cmp(ptp->portPriority.DesignatedBridgeID, !=, 2809 tree->BridgeIdentifier)) 2810 { 2811 /* k) Set Alternate role */ 2812 ptp->selectedRole = roleAlternate; 2813 } 2814 else 2815 { 2816 /* l) Set Backup role */ 2817 ptp->selectedRole = roleBackup; 2818 } 2819 /* reset updtInfo for both k) and l) */ 2820 ptp->updtInfo = false; 2821 } 2822 else /* designatedPriority is better than portPriority */ 2823 { 2824 /* m) Set Designated role */ 2825 ptp->selectedRole = roleDesignated; 2826 ptp->updtInfo = true; 2827 } 2828 } 2829 /* This is not in standard. But we really should set here 2830 * reselect for all MSTIs so that updtRolesTree is called 2831 * for each MSTI and due to above clause g) MSTI role is 2832 * changed to Master or reflects CIST port role. 2833 * Because in 802.1Q-2005 this will not happen when BPDU arrives 2834 * at boundary port - the rcvdMsg is not set for the MSTIs and 2835 * updtRolesTree is not called. 2836 * Bad IEEE !!! 2837 */ 2838 if(cist && (ptp->selectedRole != ptp->role)) 2839 reselectMSTIs(prt); 2840 continue; 2841 } 2842 } 2843 } 2844 } 2845 2846 /* 13.27 The Port Timers state machine */ 2847 2848 static void PTSM_tick(port_t *prt) 2849 { 2850 per_tree_port_t *ptp; 2851 2852 if(prt->helloWhen) 2853 --(prt->helloWhen); 2854 if(prt->mdelayWhile) 2855 --(prt->mdelayWhile); 2856 if(prt->edgeDelayWhile) 2857 --(prt->edgeDelayWhile); 2858 if(prt->txCount) 2859 --(prt->txCount); 2860 if(prt->brAssuRcvdInfoWhile) 2861 --(prt->brAssuRcvdInfoWhile); 2862 2863 FOREACH_PTP_IN_PORT(ptp, prt) 2864 { 2865 if(ptp->fdWhile) 2866 --(ptp->fdWhile); 2867 if(ptp->rrWhile) 2868 --(ptp->rrWhile); 2869 if(ptp->rbWhile) 2870 --(ptp->rbWhile); 2871 if(ptp->tcWhile) 2872 { 2873 if(0 == --(ptp->tcWhile)) 2874 set_TopologyChange(ptp->tree, false, prt); 2875 } 2876 if(ptp->rcvdInfoWhile) 2877 --(ptp->rcvdInfoWhile); 2878 } 2879 } 2880 2881 /* 13.28 Port Receive state machine */ 2882 #define PRSM_begin(prt) PRSM_to_DISCARD((prt), false) 2883 static bool PRSM_to_DISCARD(port_t *prt, bool dry_run) 2884 { 2885 if(dry_run) 2886 { 2887 return (prt->PRSM_state != PRSM_DISCARD) 2888 || prt->rcvdBpdu || prt->rcvdRSTP || prt->rcvdSTP 2889 || (prt->edgeDelayWhile != prt->bridge->Migrate_Time) 2890 || clearAllRcvdMsgs(prt, dry_run); 2891 } 2892 2893 prt->PRSM_state = PRSM_DISCARD; 2894 2895 prt->rcvdBpdu = false; 2896 prt->rcvdRSTP = false; 2897 prt->rcvdSTP = false; 2898 clearAllRcvdMsgs(prt, false /* actual run */); 2899 assign(prt->edgeDelayWhile, prt->bridge->Migrate_Time); 2900 2901 /* No need to run, no one condition will be met 2902 * if(!begin) 2903 * PRSM_run(prt, false); */ 2904 return false; 2905 } 2906 2907 static void PRSM_to_RECEIVE(port_t *prt) 2908 { 2909 prt->PRSM_state = PRSM_RECEIVE; 2910 2911 updtBPDUVersion(prt); 2912 prt->rcvdInternal = fromSameRegion(prt); 2913 setRcvdMsgs(prt); 2914 prt->operEdge = false; 2915 prt->rcvdBpdu = false; 2916 assign(prt->edgeDelayWhile, prt->bridge->Migrate_Time); 2917 2918 /* No need to run, no one condition will be met 2919 PRSM_run(prt, false); */ 2920 } 2921 2922 static bool PRSM_run(port_t *prt, bool dry_run) 2923 { 2924 per_tree_port_t *ptp; 2925 bool rcvdAnyMsg; 2926 2927 if((prt->rcvdBpdu || (prt->edgeDelayWhile != prt->bridge->Migrate_Time)) 2928 && !prt->portEnabled) 2929 { 2930 return PRSM_to_DISCARD(prt, dry_run); 2931 } 2932 2933 switch(prt->PRSM_state) 2934 { 2935 case PRSM_DISCARD: 2936 if(prt->rcvdBpdu && prt->portEnabled) 2937 { 2938 if(dry_run) /* state change */ 2939 return true; 2940 PRSM_to_RECEIVE(prt); 2941 } 2942 return false; 2943 case PRSM_RECEIVE: 2944 rcvdAnyMsg = false; 2945 FOREACH_PTP_IN_PORT(ptp, prt) 2946 { 2947 if(ptp->rcvdMsg) 2948 { 2949 rcvdAnyMsg = true; 2950 break; 2951 } 2952 } 2953 if(prt->rcvdBpdu && prt->portEnabled && !rcvdAnyMsg) 2954 { 2955 if(dry_run) /* at least rcvdBpdu will change */ 2956 return true; 2957 PRSM_to_RECEIVE(prt); 2958 } 2959 default: 2960 return false; 2961 } 2962 } 2963 2964 /* 13.29 Port Protocol Migration state machine */ 2965 2966 static bool PPMSM_run(port_t *prt, bool dry_run); 2967 #define PPMSM_begin(prt) PPMSM_to_CHECKING_RSTP(prt) 2968 2969 static void PPMSM_to_CHECKING_RSTP(port_t *prt/*, bool begin*/) 2970 { 2971 prt->PPMSM_state = PPMSM_CHECKING_RSTP; 2972 2973 bridge_t *br = prt->bridge; 2974 prt->mcheck = false; 2975 prt->sendRSTP = rstpVersion(br); 2976 assign(prt->mdelayWhile, br->Migrate_Time); 2977 2978 /* No need to run, no one condition will be met 2979 * if(!begin) 2980 * PPMSM_run(prt, false); */ 2981 } 2982 2983 static void PPMSM_to_SELECTING_STP(port_t *prt) 2984 { 2985 prt->PPMSM_state = PPMSM_SELECTING_STP; 2986 2987 prt->sendRSTP = false; 2988 assign(prt->mdelayWhile, prt->bridge->Migrate_Time); 2989 2990 PPMSM_run(prt, false /* actual run */); 2991 } 2992 2993 static void PPMSM_to_SENSING(port_t *prt) 2994 { 2995 prt->PPMSM_state = PPMSM_SENSING; 2996 2997 prt->rcvdRSTP = false; 2998 prt->rcvdSTP = false; 2999 3000 PPMSM_run(prt, false /* actual run */); 3001 } 3002 3003 static bool PPMSM_run(port_t *prt, bool dry_run) 3004 { 3005 bridge_t *br = prt->bridge; 3006 3007 switch(prt->PPMSM_state) 3008 { 3009 case PPMSM_CHECKING_RSTP: 3010 if((prt->mdelayWhile != br->Migrate_Time) 3011 && !prt->portEnabled) 3012 { 3013 if(dry_run) /* at least mdelayWhile will change */ 3014 return true; 3015 PPMSM_to_CHECKING_RSTP(prt); 3016 return false; 3017 } 3018 if(0 == prt->mdelayWhile) 3019 { 3020 if(dry_run) /* state change */ 3021 return true; 3022 PPMSM_to_SENSING(prt); 3023 } 3024 return false; 3025 case PPMSM_SELECTING_STP: 3026 if(0 == prt->mdelayWhile || !prt->portEnabled || prt->mcheck) 3027 { 3028 if(dry_run) /* state change */ 3029 return true; 3030 PPMSM_to_SENSING(prt); 3031 } 3032 return false; 3033 case PPMSM_SENSING: 3034 if(!prt->portEnabled || prt->mcheck 3035 || (rstpVersion(br) && !prt->sendRSTP && prt->rcvdRSTP)) 3036 { 3037 if(dry_run) /* state change */ 3038 return true; 3039 PPMSM_to_CHECKING_RSTP(prt); 3040 return false; 3041 } 3042 if(prt->sendRSTP && prt->rcvdSTP) 3043 { 3044 if(dry_run) /* state change */ 3045 return true; 3046 PPMSM_to_SELECTING_STP(prt); 3047 } 3048 return false; 3049 } 3050 3051 return false; 3052 } 3053 3054 /* 13.30 Bridge Detection state machine */ 3055 static void BDSM_to_EDGE(port_t *prt/*, bool begin*/) 3056 { 3057 prt->BDSM_state = BDSM_EDGE; 3058 3059 prt->operEdge = true; 3060 3061 /* No need to run, no one condition will be met 3062 * if(!begin) 3063 * BDSM_run(prt, false); */ 3064 } 3065 3066 static void BDSM_to_NOT_EDGE(port_t *prt/*, bool begin*/) 3067 { 3068 prt->BDSM_state = BDSM_NOT_EDGE; 3069 3070 prt->operEdge = false; 3071 3072 /* No need to run, no one condition will be met 3073 * if(!begin) 3074 * BDSM_run(prt, false); */ 3075 } 3076 3077 static void BDSM_begin(port_t *prt/*, bool begin*/) 3078 { 3079 if(prt->AdminEdgePort) 3080 BDSM_to_EDGE(prt/*, begin*/); 3081 else 3082 BDSM_to_NOT_EDGE(prt/*, begin*/); 3083 } 3084 3085 static bool BDSM_run(port_t *prt, bool dry_run) 3086 { 3087 per_tree_port_t *cist; 3088 3089 switch(prt->BDSM_state) 3090 { 3091 case BDSM_EDGE: 3092 if(((!prt->portEnabled || !prt->AutoEdge) && !prt->AdminEdgePort) 3093 || !prt->operEdge 3094 ) 3095 { 3096 if(dry_run) /* state change */ 3097 return true; 3098 BDSM_to_NOT_EDGE(prt); 3099 } 3100 return false; 3101 case BDSM_NOT_EDGE: 3102 cist = GET_CIST_PTP_FROM_PORT(prt); 3103 /* NOTE: 802.1Q-2005(-2011) is not clear, which of the per-tree 3104 * "proposing" flags to use here, or one should combine 3105 * them all for all trees? 3106 * So, I decide that it will be the "proposing" flag 3107 * from CIST tree - it seems like a good bet. 3108 */ 3109 if((!prt->portEnabled && prt->AdminEdgePort) 3110 || ((0 == prt->edgeDelayWhile) && prt->AutoEdge && prt->sendRSTP 3111 && cist->proposing) 3112 ) 3113 { 3114 if(dry_run) /* state change */ 3115 return true; 3116 BDSM_to_EDGE(prt); 3117 } 3118 default: 3119 return false; 3120 } 3121 } 3122 3123 /* 13.31 Port Transmit state machine */ 3124 3125 static bool PTSM_run(port_t *prt, bool dry_run); 3126 #define PTSM_begin(prt) PTSM_to_TRANSMIT_INIT((prt), true, false) 3127 3128 static bool PTSM_to_TRANSMIT_INIT(port_t *prt, bool begin, bool dry_run) 3129 { 3130 if(dry_run) 3131 { 3132 return (prt->PTSM_state != PTSM_TRANSMIT_INIT) 3133 || (!prt->newInfo) || (!prt->newInfoMsti) 3134 || (0 != prt->txCount); 3135 } 3136 3137 prt->PTSM_state = PTSM_TRANSMIT_INIT; 3138 3139 prt->newInfo = true; 3140 prt->newInfoMsti = true; 3141 assign(prt->txCount, 0u); 3142 3143 if(!begin && prt->portEnabled) /* prevent infinite loop */ 3144 PTSM_run(prt, false /* actual run */); 3145 return false; 3146 } 3147 3148 static void PTSM_to_TRANSMIT_CONFIG(port_t *prt) 3149 { 3150 prt->PTSM_state = PTSM_TRANSMIT_CONFIG; 3151 3152 prt->newInfo = false; 3153 txConfig(prt); 3154 ++(prt->txCount); 3155 prt->tcAck = false; 3156 3157 PTSM_run(prt, false /* actual run */); 3158 } 3159 3160 static void PTSM_to_TRANSMIT_TCN(port_t *prt) 3161 { 3162 prt->PTSM_state = PTSM_TRANSMIT_TCN; 3163 3164 prt->newInfo = false; 3165 txTcn(prt); 3166 ++(prt->txCount); 3167 3168 PTSM_run(prt, false /* actual run */); 3169 } 3170 3171 static void PTSM_to_TRANSMIT_RSTP(port_t *prt) 3172 { 3173 prt->PTSM_state = PTSM_TRANSMIT_RSTP; 3174 3175 prt->newInfo = false; 3176 prt->newInfoMsti = false; 3177 txMstp(prt); 3178 ++(prt->txCount); 3179 prt->tcAck = false; 3180 3181 PTSM_run(prt, false /* actual run */); 3182 } 3183 3184 static void PTSM_to_TRANSMIT_PERIODIC(port_t *prt) 3185 { 3186 prt->PTSM_state = PTSM_TRANSMIT_PERIODIC; 3187 3188 per_tree_port_t *ptp = GET_CIST_PTP_FROM_PORT(prt); 3189 bool cistDesignatedOrTCpropagatingRootPort = 3190 (roleDesignated == ptp->role) 3191 || ((roleRoot == ptp->role) && (0 != ptp->tcWhile)); 3192 bool mstiDesignatedOrTCpropagatingRootPort; 3193 3194 mstiDesignatedOrTCpropagatingRootPort = false; 3195 list_for_each_entry_continue(ptp, &prt->trees, port_list) 3196 { 3197 if((roleDesignated == ptp->role) 3198 || ((roleRoot == ptp->role) && (0 != ptp->tcWhile)) 3199 ) 3200 { 3201 mstiDesignatedOrTCpropagatingRootPort = true; 3202 break; 3203 } 3204 } 3205 3206 prt->newInfo = prt->newInfo || cistDesignatedOrTCpropagatingRootPort; 3207 prt->newInfoMsti = prt->newInfoMsti 3208 || mstiDesignatedOrTCpropagatingRootPort; 3209 3210 PTSM_run(prt, false /* actual run */); 3211 } 3212 3213 static void PTSM_to_IDLE(port_t *prt) 3214 { 3215 prt->PTSM_state = PTSM_IDLE; 3216 3217 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 3218 prt->helloWhen = cist->portTimes.Hello_Time; 3219 3220 PTSM_run(prt, false /* actual run */); 3221 } 3222 3223 static bool PTSM_run(port_t *prt, bool dry_run) 3224 { 3225 /* bool allTransmitReady; */ 3226 per_tree_port_t *ptp; 3227 port_role_t cistRole; 3228 bool mstiMasterPort; 3229 3230 if(!prt->portEnabled) 3231 { 3232 return PTSM_to_TRANSMIT_INIT(prt, false, dry_run); 3233 } 3234 3235 switch(prt->PTSM_state) 3236 { 3237 case PTSM_TRANSMIT_INIT: 3238 /* return; */ 3239 case PTSM_TRANSMIT_CONFIG: 3240 /* return; */ 3241 case PTSM_TRANSMIT_TCN: 3242 /* return; */ 3243 case PTSM_TRANSMIT_RSTP: 3244 /* return; */ 3245 case PTSM_TRANSMIT_PERIODIC: 3246 if(dry_run) /* state change */ 3247 return true; 3248 PTSM_to_IDLE(prt); /* UnConditional Transition */ 3249 return false; 3250 case PTSM_IDLE: 3251 /* allTransmitReady = true; */ 3252 ptp = GET_CIST_PTP_FROM_PORT(prt); 3253 if(!ptp->selected || ptp->updtInfo) 3254 { 3255 /* allTransmitReady = false; */ 3256 return false; 3257 } 3258 cistRole = ptp->role; 3259 mstiMasterPort = false; 3260 list_for_each_entry_continue(ptp, &prt->trees, port_list) 3261 { 3262 if(!ptp->selected || ptp->updtInfo) 3263 { 3264 /* allTransmitReady = false; */ 3265 return false; 3266 } 3267 if(roleMaster == ptp->role) 3268 mstiMasterPort = true; 3269 } 3270 if(0 == prt->helloWhen) 3271 { 3272 if(dry_run) /* state change */ 3273 return true; 3274 PTSM_to_TRANSMIT_PERIODIC(prt); 3275 return false; 3276 } 3277 if(!(prt->txCount < prt->bridge->Transmit_Hold_Count)) 3278 return false; 3279 3280 if(prt->bpduFilterPort) 3281 return false; 3282 3283 if(prt->sendRSTP) 3284 { /* implement MSTP */ 3285 if(prt->newInfo || (prt->newInfoMsti && !mstiMasterPort) 3286 || assurancePort(prt) 3287 ) 3288 { 3289 if(dry_run) /* state change */ 3290 return true; 3291 PTSM_to_TRANSMIT_RSTP(prt); 3292 return false; 3293 } 3294 } 3295 else 3296 { /* fallback to STP */ 3297 if(prt->newInfo && (roleDesignated == cistRole)) 3298 { 3299 if(dry_run) /* state change */ 3300 return true; 3301 PTSM_to_TRANSMIT_CONFIG(prt); 3302 return false; 3303 } 3304 if(prt->newInfo && (roleRoot == cistRole)) 3305 { 3306 if(dry_run) /* state change */ 3307 return true; 3308 PTSM_to_TRANSMIT_TCN(prt); 3309 return false; 3310 } 3311 } 3312 return false; 3313 } 3314 3315 return false; 3316 } 3317 3318 /* 13.32 Port Information state machine */ 3319 3320 #ifdef PISM_ENABLE_LOG 3321 #define PISM_LOG(_fmt, _args...) SMLOG_MSTINAME(ptp, _fmt, ##_args) 3322 #else 3323 #define PISM_LOG(_fmt, _args...) {} 3324 #endif /* PISM_ENABLE_LOG */ 3325 3326 static bool PISM_run(per_tree_port_t *ptp, bool dry_run); 3327 #define PISM_begin(ptp) PISM_to_DISABLED((ptp), true) 3328 3329 static void PISM_to_DISABLED(per_tree_port_t *ptp, bool begin) 3330 { 3331 PISM_LOG(""); 3332 ptp->PISM_state = PISM_DISABLED; 3333 3334 ptp->rcvdMsg = false; 3335 ptp->proposing = false; 3336 ptp->proposed = false; 3337 ptp->agree = false; 3338 ptp->agreed = false; 3339 assign(ptp->rcvdInfoWhile, 0u); 3340 ptp->infoIs = ioDisabled; 3341 ptp->reselect = true; 3342 ptp->selected = false; 3343 3344 if(!begin) 3345 PISM_run(ptp, false /* actual run */); 3346 } 3347 3348 static void PISM_to_AGED(per_tree_port_t *ptp) 3349 { 3350 PISM_LOG(""); 3351 ptp->PISM_state = PISM_AGED; 3352 3353 ptp->infoIs = ioAged; 3354 ptp->reselect = true; 3355 ptp->selected = false; 3356 3357 PISM_run(ptp, false /* actual run */); 3358 } 3359 3360 static void PISM_to_UPDATE(per_tree_port_t *ptp) 3361 { 3362 PISM_LOG(""); 3363 ptp->PISM_state = PISM_UPDATE; 3364 3365 ptp->proposing = false; 3366 ptp->proposed = false; 3367 ptp->agreed = ptp->agreed && betterorsameInfo(ptp, ioMine); 3368 ptp->synced = ptp->synced && ptp->agreed; 3369 assign(ptp->portPriority, ptp->designatedPriority); 3370 assign(ptp->portTimes, ptp->designatedTimes); 3371 ptp->updtInfo = false; 3372 ptp->infoIs = ioMine; 3373 /* newInfoXst = TRUE; */ 3374 port_t *prt = ptp->port; 3375 if(0 == ptp->MSTID) 3376 prt->newInfo = true; 3377 else 3378 prt->newInfoMsti = true; 3379 3380 PISM_run(ptp, false /* actual run */); 3381 } 3382 3383 static void PISM_to_SUPERIOR_DESIGNATED(per_tree_port_t *ptp) 3384 { 3385 PISM_LOG(""); 3386 ptp->PISM_state = PISM_SUPERIOR_DESIGNATED; 3387 3388 port_t *prt = ptp->port; 3389 3390 prt->infoInternal = prt->rcvdInternal; 3391 ptp->agreed = false; 3392 ptp->proposing = false; 3393 recordProposal(ptp); 3394 setTcFlags(ptp); 3395 ptp->agree = ptp->agree && betterorsameInfo(ptp, ioReceived); 3396 recordAgreement(ptp); 3397 ptp->synced = ptp->synced && ptp->agreed; 3398 recordPriority(ptp); 3399 recordTimes(ptp); 3400 updtRcvdInfoWhile(ptp); 3401 ptp->infoIs = ioReceived; 3402 ptp->reselect = true; 3403 ptp->selected = false; 3404 ptp->rcvdMsg = false; 3405 3406 PISM_run(ptp, false /* actual run */); 3407 } 3408 3409 static void PISM_to_REPEATED_DESIGNATED(per_tree_port_t *ptp) 3410 { 3411 PISM_LOG(""); 3412 ptp->PISM_state = PISM_REPEATED_DESIGNATED; 3413 3414 port_t *prt = ptp->port; 3415 3416 prt->infoInternal = prt->rcvdInternal; 3417 recordProposal(ptp); 3418 setTcFlags(ptp); 3419 recordAgreement(ptp); 3420 updtRcvdInfoWhile(ptp); 3421 ptp->rcvdMsg = false; 3422 3423 PISM_run(ptp, false /* actual run */); 3424 } 3425 3426 static void PISM_to_INFERIOR_DESIGNATED(per_tree_port_t *ptp) 3427 { 3428 PISM_LOG(""); 3429 ptp->PISM_state = PISM_INFERIOR_DESIGNATED; 3430 3431 recordDispute(ptp); 3432 ptp->rcvdMsg = false; 3433 3434 PISM_run(ptp, false /* actual run */); 3435 } 3436 3437 static void PISM_to_NOT_DESIGNATED(per_tree_port_t *ptp) 3438 { 3439 PISM_LOG(""); 3440 ptp->PISM_state = PISM_NOT_DESIGNATED; 3441 3442 recordAgreement(ptp); 3443 setTcFlags(ptp); 3444 ptp->rcvdMsg = false; 3445 3446 PISM_run(ptp, false /* actual run */); 3447 } 3448 3449 static void PISM_to_OTHER(per_tree_port_t *ptp) 3450 { 3451 PISM_LOG(""); 3452 ptp->PISM_state = PISM_OTHER; 3453 3454 ptp->rcvdMsg = false; 3455 3456 PISM_run(ptp, false /* actual run */); 3457 } 3458 3459 static void PISM_to_CURRENT(per_tree_port_t *ptp) 3460 { 3461 PISM_LOG(""); 3462 ptp->PISM_state = PISM_CURRENT; 3463 3464 PISM_run(ptp, false /* actual run */); 3465 } 3466 3467 static void PISM_to_RECEIVE(per_tree_port_t *ptp) 3468 { 3469 PISM_LOG(""); 3470 ptp->PISM_state = PISM_RECEIVE; 3471 3472 ptp->rcvdInfo = rcvInfo(ptp); 3473 recordMastered(ptp); 3474 3475 PISM_run(ptp, false /* actual run */); 3476 } 3477 3478 static bool PISM_run(per_tree_port_t *ptp, bool dry_run) 3479 { 3480 bool rcvdXstMsg, updtXstInfo; 3481 port_t *prt = ptp->port; 3482 3483 if((!prt->portEnabled) && (ioDisabled != ptp->infoIs)) 3484 { 3485 if(dry_run) /* at least infoIs will change */ 3486 return true; 3487 PISM_to_DISABLED(ptp, false); 3488 return false; 3489 } 3490 3491 switch(ptp->PISM_state) 3492 { 3493 case PISM_DISABLED: 3494 if(prt->portEnabled) 3495 { 3496 if(dry_run) /* state change */ 3497 return true; 3498 PISM_to_AGED(ptp); 3499 return false; 3500 } 3501 if(ptp->rcvdMsg) 3502 { 3503 if(dry_run) /* at least rcvdMsg will change */ 3504 return true; 3505 PISM_to_DISABLED(ptp, false); 3506 } 3507 return false; 3508 case PISM_AGED: 3509 if(ptp->selected && ptp->updtInfo) 3510 { 3511 if(dry_run) /* state change */ 3512 return true; 3513 PISM_to_UPDATE(ptp); 3514 } 3515 return false; 3516 case PISM_UPDATE: 3517 /* return; */ 3518 case PISM_SUPERIOR_DESIGNATED: 3519 /* return; */ 3520 case PISM_REPEATED_DESIGNATED: 3521 /* return; */ 3522 case PISM_INFERIOR_DESIGNATED: 3523 /* return; */ 3524 case PISM_NOT_DESIGNATED: 3525 /* return; */ 3526 case PISM_OTHER: 3527 if(dry_run) /* state change */ 3528 return true; 3529 PISM_to_CURRENT(ptp); 3530 return false; 3531 case PISM_CURRENT: 3532 /* 3533 * Although 802.1Q-2005 does not define rcvdXstMsg and updtXstInfo 3534 * from 802.1s we can conclude that they are: 3535 * - rcvdXstMsg = rcvdCistMsg, if tree is CIST 3536 * rcvdMstiMsg, if tree is MSTI. 3537 * - updtXstInfo = updtCistInfo, if tree is CIST 3538 * updtMstiInfo, if tree is MSTI. 3539 */ 3540 if(0 == ptp->MSTID) 3541 { /* CIST */ 3542 rcvdXstMsg = ptp->rcvdMsg; /* 13.25.12 */ 3543 updtXstInfo = ptp->updtInfo; /* 13.25.16 */ 3544 } 3545 else 3546 { /* MSTI */ 3547 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt); 3548 rcvdXstMsg = !cist->rcvdMsg && ptp->rcvdMsg; /* 13.25.13 */ 3549 updtXstInfo = ptp->updtInfo || cist->updtInfo; /* 13.25.17 */ 3550 } 3551 if(rcvdXstMsg && !updtXstInfo) 3552 { 3553 if(dry_run) /* state change */ 3554 return true; 3555 PISM_to_RECEIVE(ptp); 3556 return false; 3557 } 3558 if((ioReceived == ptp->infoIs) && (0 == ptp->rcvdInfoWhile) 3559 && !ptp->updtInfo && !rcvdXstMsg) 3560 { 3561 if(dry_run) /* state change */ 3562 return true; 3563 PISM_to_AGED(ptp); 3564 return false; 3565 } 3566 if(ptp->selected && ptp->updtInfo) 3567 { 3568 if(dry_run) /* state change */ 3569 return true; 3570 PISM_to_UPDATE(ptp); 3571 } 3572 return false; 3573 case PISM_RECEIVE: 3574 switch(ptp->rcvdInfo) 3575 { 3576 case SuperiorDesignatedInfo: 3577 if(dry_run) /* state change */ 3578 return true; 3579 PISM_to_SUPERIOR_DESIGNATED(ptp); 3580 return false; 3581 case RepeatedDesignatedInfo: 3582 if(dry_run) /* state change */ 3583 return true; 3584 PISM_to_REPEATED_DESIGNATED(ptp); 3585 return false; 3586 case InferiorDesignatedInfo: 3587 if(dry_run) /* state change */ 3588 return true; 3589 PISM_to_INFERIOR_DESIGNATED(ptp); 3590 return false; 3591 case InferiorRootAlternateInfo: 3592 if(dry_run) /* state change */ 3593 return true; 3594 PISM_to_NOT_DESIGNATED(ptp); 3595 return false; 3596 case OtherInfo: 3597 if(dry_run) /* state change */ 3598 return true; 3599 PISM_to_OTHER(ptp); 3600 return false; 3601 } 3602 return false; 3603 } 3604 3605 return false; 3606 } 3607 3608 /* 13.33 Port Role Selection state machine */ 3609 3610 static bool PRSSM_run(tree_t *tree, bool dry_run); 3611 #define PRSSM_begin(tree) PRSSM_to_INIT_TREE(tree) 3612 3613 static void PRSSM_to_INIT_TREE(tree_t *tree/*, bool begin*/) 3614 { 3615 tree->PRSSM_state = PRSSM_INIT_TREE; 3616 3617 updtRolesDisabledTree(tree); 3618 3619 /* No need to check, as we assume begin = true here 3620 * because transition to this state can be initiated only by BEGIN var. 3621 * In other words, this function is called via xxx_begin macro only. 3622 * if(!begin) 3623 * PRSSM_run(prt, false); */ 3624 } 3625 3626 static void PRSSM_to_ROLE_SELECTION(tree_t *tree) 3627 { 3628 tree->PRSSM_state = PRSSM_ROLE_SELECTION; 3629 3630 clearReselectTree(tree); 3631 updtRolesTree(tree); 3632 setSelectedTree(tree); 3633 3634 /* No need to run, no one condition will be met 3635 PRSSM_run(tree, false); */ 3636 } 3637 3638 static bool PRSSM_run(tree_t *tree, bool dry_run) 3639 { 3640 per_tree_port_t *ptp; 3641 3642 switch(tree->PRSSM_state) 3643 { 3644 case PRSSM_INIT_TREE: 3645 if(dry_run) /* state change */ 3646 return true; 3647 PRSSM_to_ROLE_SELECTION(tree); 3648 return false; 3649 case PRSSM_ROLE_SELECTION: 3650 FOREACH_PTP_IN_TREE(ptp, tree) 3651 if(ptp->reselect) 3652 { 3653 if(dry_run) /* at least reselect will change */ 3654 return true; 3655 PRSSM_to_ROLE_SELECTION(tree); 3656 return false; 3657 } 3658 return false; 3659 } 3660 3661 return false; 3662 } 3663 3664 /* 13.34 Port Role Transitions state machine */ 3665 3666 #ifdef PRTSM_ENABLE_LOG 3667 #define PRTSM_LOG(_fmt, _args...) SMLOG_MSTINAME(ptp, _fmt, ##_args) 3668 #else 3669 #define PRTSM_LOG(_fmt, _args...) {} 3670 #endif /* PRTSM_ENABLE_LOG */ 3671 3672 static bool PRTSM_runr(per_tree_port_t *ptp, bool recursive_call, bool dry_run); 3673 #define PRTSM_run(ptp, dry_run) PRTSM_runr((ptp), false, (dry_run)) 3674 #define PRTSM_begin(ptp) PRTSM_to_INIT_PORT(ptp) 3675 3676 /* Disabled Port role transitions */ 3677 3678 static void PRTSM_to_INIT_PORT(per_tree_port_t *ptp/*, bool begin*/) 3679 { 3680 PRTSM_LOG(""); 3681 ptp->PRTSM_state = PRTSM_INIT_PORT; 3682 3683 unsigned int MaxAge, FwdDelay; 3684 per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(ptp->port); 3685 3686 ptp->role = roleDisabled; 3687 ptp->learn = false; 3688 ptp->forward = false; 3689 ptp->synced = false; 3690 ptp->sync = true; 3691 ptp->reRoot = true; 3692 /* 13.25.6 */ 3693 FwdDelay = cist->designatedTimes.Forward_Delay; 3694 assign(ptp->rrWhile, FwdDelay); 3695 /* 13.25.8 */ 3696 MaxAge = cist->designatedTimes.Max_Age; 3697 assign(ptp->fdWhile, MaxAge); 3698 assign(ptp->rbWhile, 0u); 3699 3700 /* No need to check, as we assume begin = true here 3701 * because transition to this state can be initiated only by BEGIN var. 3702 * In other words, this function is called via xxx_begin macro only. 3703 * if(!begin) 3704 * PRTSM_runr(ptp, false, false); */ 3705 } 3706 3707 static void PRTSM_to_DISABLE_PORT(per_tree_port_t *ptp) 3708 { 3709 PRTSM_LOG(""); 3710 ptp->PRTSM_state = PRTSM_DISABLE_PORT; 3711 3712 /* Although 802.1Q-2005 says here to do role = selectedRole 3713 * I have difficulties with it in the next scenario: 3714 * 1) port was designated (role == selectedRole == roleDesignated) 3715 * 2) some config event occurs, e.g. MAC address changes and 3716 * br_state_machines_begin is called 3717 * 3) role == selectedRole == roleDisabled, PRTSM_state = PRTSM_INIT_PORT 3718 * Because port was not actually down, on the next run 3719 * Port Role Selection state machine sets selectedRole = roleDesignated 3720 * and updtInfo = true: 3721 * 4) we have unconditional transition to DISABLE_PORT, and because 3722 * updtInfo = true we can not follow transition to DESIGNATED_PORT 3723 * 5) if we follow standard, role = selectedRole = roleDesignated and 3724 * on the next run we have transition to the DISABLED_PORT 3725 * And there we stuck. role == selectedRole, so we can not transit to 3726 * DESIGNATED_PORT (it requires role != selectedRole ). 3727 * 3728 * Solution: do not follow the standard, and do role = roleDisabled 3729 * instead of role = selectedRole. 3730 */ 3731 ptp->role = roleDisabled; 3732 ptp->learn = false; 3733 ptp->forward = false; 3734 3735 PRTSM_runr(ptp, true, false /* actual run */); 3736 } 3737 3738 static void PRTSM_to_DISABLED_PORT(per_tree_port_t *ptp, unsigned int MaxAge) 3739 { 3740 PRTSM_LOG(""); 3741 ptp->PRTSM_state = PRTSM_DISABLED_PORT; 3742 3743 assign(ptp->fdWhile, MaxAge); 3744 ptp->synced = true; 3745 assign(ptp->rrWhile, 0u); 3746 ptp->sync = false; 3747 ptp->reRoot = false; 3748 3749 PRTSM_runr(ptp, true, false /* actual run */); 3750 } 3751 3752 /* MasterPort role transitions */ 3753 3754 static void PRTSM_to_MASTER_PROPOSED(per_tree_port_t *ptp) 3755 { 3756 PRTSM_LOG(""); 3757 ptp->PRTSM_state = PRTSM_MASTER_PROPOSED; 3758 3759 setSyncTree(ptp->tree); 3760 ptp->proposed = false; 3761 3762 PRTSM_runr(ptp, true, false /* actual run */); 3763 } 3764 3765 static void PRTSM_to_MASTER_AGREED(per_tree_port_t *ptp) 3766 { 3767 PRTSM_LOG(""); 3768 ptp->PRTSM_state = PRTSM_MASTER_AGREED; 3769 3770 ptp->proposed = false; 3771 ptp->sync = false; 3772 ptp->agree = true; 3773 3774 PRTSM_runr(ptp, true, false /* actual run */); 3775 } 3776 3777 static void PRTSM_to_MASTER_SYNCED(per_tree_port_t *ptp) 3778 { 3779 PRTSM_LOG(""); 3780 ptp->PRTSM_state = PRTSM_MASTER_SYNCED; 3781 3782 assign(ptp->rrWhile, 0u); 3783 ptp->synced = true; 3784 ptp->sync = false; 3785 3786 PRTSM_runr(ptp, true, false /* actual run */); 3787 } 3788 3789 static void PRTSM_to_MASTER_RETIRED(per_tree_port_t *ptp) 3790 { 3791 PRTSM_LOG(""); 3792 ptp->PRTSM_state = PRTSM_MASTER_RETIRED; 3793 3794 ptp->reRoot = false; 3795 3796 PRTSM_runr(ptp, true, false /* actual run */); 3797 } 3798 3799 static void PRTSM_to_MASTER_FORWARD(per_tree_port_t *ptp) 3800 { 3801 PRTSM_LOG(""); 3802 ptp->PRTSM_state = PRTSM_MASTER_FORWARD; 3803 3804 ptp->forward = true; 3805 assign(ptp->fdWhile, 0u); 3806 ptp->agreed = ptp->port->sendRSTP; 3807 3808 PRTSM_runr(ptp, true, false /* actual run */); 3809 } 3810 3811 static void PRTSM_to_MASTER_LEARN(per_tree_port_t *ptp, unsigned int forwardDelay) 3812 { 3813 PRTSM_LOG(""); 3814 ptp->PRTSM_state = PRTSM_MASTER_LEARN; 3815 3816 ptp->learn = true; 3817 assign(ptp->fdWhile, forwardDelay); 3818 3819 PRTSM_runr(ptp, true, false /* actual run */); 3820 } 3821 3822 static void PRTSM_to_MASTER_DISCARD(per_tree_port_t *ptp, unsigned int forwardDelay) 3823 { 3824 PRTSM_LOG(""); 3825 ptp->PRTSM_state = PRTSM_MASTER_DISCARD; 3826 3827 ptp->learn = false; 3828 ptp->forward = false; 3829 ptp->disputed = false; 3830 assign(ptp->fdWhile, forwardDelay); 3831 3832 PRTSM_runr(ptp, true, false /* actual run */); 3833 } 3834 3835 static void PRTSM_to_MASTER_PORT(per_tree_port_t *ptp) 3836 { 3837 PRTSM_LOG(""); 3838 ptp->PRTSM_state = PRTSM_MASTER_PORT; 3839 3840 ptp->role = roleMaster; 3841 3842 PRTSM_runr(ptp, true, false /* actual run */); 3843 } 3844 3845 /* RootPort role transitions */ 3846 3847 static void PRTSM_to_ROOT_PROPOSED(per_tree_port_t *ptp) 3848 { 3849 PRTSM_LOG(""); 3850 ptp->PRTSM_state = PRTSM_ROOT_PROPOSED; 3851 3852 setSyncTree(ptp->tree); 3853 ptp->proposed = false; 3854 3855 PRTSM_runr(ptp, true, false /* actual run */); 3856 } 3857 3858 static void PRTSM_to_ROOT_AGREED(per_tree_port_t *ptp) 3859 { 3860 PRTSM_LOG(""); 3861 ptp->PRTSM_state = PRTSM_ROOT_AGREED; 3862 3863 ptp->proposed = false; 3864 ptp->sync = false; 3865 ptp->agree = true; 3866 /* newInfoXst = TRUE; */ 3867 port_t *prt = ptp->port; 3868 if(0 == ptp->MSTID) 3869 prt->newInfo = true; 3870 else 3871 prt->newInfoMsti = true; 3872 3873 PRTSM_runr(ptp, true, false /* actual run */); 3874 } 3875 3876 static void PRTSM_to_ROOT_SYNCED(per_tree_port_t *ptp) 3877 { 3878 PRTSM_LOG(""); 3879 ptp->PRTSM_state = PRTSM_ROOT_SYNCED; 3880 3881 ptp->synced = true; 3882 ptp->sync = false; 3883 3884 PRTSM_runr(ptp, true, false /* actual run */); 3885 } 3886 3887 static void PRTSM_to_REROOT(per_tree_port_t *ptp) 3888 { 3889 PRTSM_LOG(""); 3890 ptp->PRTSM_state = PRTSM_REROOT; 3891 3892 setReRootTree(ptp->tree); 3893 3894 PRTSM_runr(ptp, true, false /* actual run */); 3895 } 3896 3897 static void PRTSM_to_ROOT_FORWARD(per_tree_port_t *ptp) 3898 { 3899 PRTSM_LOG(""); 3900 ptp->PRTSM_state = PRTSM_ROOT_FORWARD; 3901 3902 assign(ptp->fdWhile, 0u); 3903 ptp->forward = true; 3904 3905 PRTSM_runr(ptp, true, false /* actual run */); 3906 } 3907 3908 static void PRTSM_to_ROOT_LEARN(per_tree_port_t *ptp, unsigned int forwardDelay) 3909 { 3910 PRTSM_LOG(""); 3911 ptp->PRTSM_state = PRTSM_ROOT_LEARN; 3912 3913 assign(ptp->fdWhile, forwardDelay); 3914 ptp->learn = true; 3915 3916 PRTSM_runr(ptp, true, false /* actual run */); 3917 } 3918 3919 static void PRTSM_to_REROOTED(per_tree_port_t *ptp) 3920 { 3921 PRTSM_LOG(""); 3922 ptp->PRTSM_state = PRTSM_REROOTED; 3923 3924 ptp->reRoot = false; 3925 3926 PRTSM_runr(ptp, true, false /* actual run */); 3927 } 3928 3929 static void PRTSM_to_ROOT_PORT(per_tree_port_t *ptp, unsigned int FwdDelay) 3930 { 3931 PRTSM_LOG(""); 3932 ptp->PRTSM_state = PRTSM_ROOT_PORT; 3933 3934 ptp->role = roleRoot; 3935 assign(ptp->rrWhile, FwdDelay); 3936 3937 PRTSM_runr(ptp, true, false /* actual run */); 3938 } 3939 3940 /* DesignatedPort role transitions */ 3941 3942 static void PRTSM_to_DESIGNATED_PROPOSE(per_tree_port_t *ptp) 3943 { 3944 PRTSM_LOG(""); 3945 ptp->PRTSM_state = PRTSM_DESIGNATED_PROPOSE; 3946 3947 port_t *prt = ptp->port; 3948 3949 ptp->proposing = true; 3950 /* newInfoXst = TRUE; */ 3951 if(0 == ptp->MSTID) 3952 { /* CIST */ 3953 /* 13.25.8. This tree is CIST. */ 3954 unsigned int MaxAge = ptp->designatedTimes.Max_Age; 3955 /* 13.25.c) -> 17.20.4 of 802.1D : EdgeDelay */ 3956 unsigned int EdgeDelay = prt->operPointToPointMAC ? 3957 prt->bridge->Migrate_Time 3958 : MaxAge; 3959 assign(prt->edgeDelayWhile, EdgeDelay); 3960 prt->newInfo = true; 3961 } 3962 else 3963 prt->newInfoMsti = true; 3964 3965 PRTSM_runr(ptp, true, false /* actual run */); 3966 } 3967 3968 static void PRTSM_to_DESIGNATED_AGREED(per_tree_port_t *ptp) 3969 { 3970 PRTSM_LOG(""); 3971 ptp->PRTSM_state = PRTSM_DESIGNATED_AGREED; 3972 3973 ptp->proposed = false; 3974 ptp->sync = false; 3975 ptp->agree = true; 3976 /* newInfoXst = TRUE; */ 3977 port_t *prt = ptp->port; 3978 if(0 == ptp->MSTID) 3979 prt->newInfo = true; 3980 else 3981 prt->newInfoMsti = true; 3982 3983 PRTSM_runr(ptp, true, false /* actual run */); 3984 } 3985 3986 static void PRTSM_to_DESIGNATED_SYNCED(per_tree_port_t *ptp) 3987 { 3988 PRTSM_LOG(""); 3989 ptp->PRTSM_state = PRTSM_DESIGNATED_SYNCED; 3990 3991 assign(ptp->rrWhile, 0u); 3992 ptp->synced = true; 3993 ptp->sync = false; 3994 3995 PRTSM_runr(ptp, true, false /* actual run */); 3996 } 3997 3998 static void PRTSM_to_DESIGNATED_RETIRED(per_tree_port_t *ptp) 3999 { 4000 PRTSM_LOG(""); 4001 ptp->PRTSM_state = PRTSM_DESIGNATED_RETIRED; 4002 4003 ptp->reRoot = false; 4004 4005 PRTSM_runr(ptp, true, false /* actual run */); 4006 } 4007 4008 static void PRTSM_to_DESIGNATED_FORWARD(per_tree_port_t *ptp) 4009 { 4010 PRTSM_LOG(""); 4011 ptp->PRTSM_state = PRTSM_DESIGNATED_FORWARD; 4012 4013 ptp->forward = true; 4014 assign(ptp->fdWhile, 0u); 4015 ptp->agreed = ptp->port->sendRSTP; 4016 4017 PRTSM_runr(ptp, true, false /* actual run */); 4018 } 4019 4020 static void PRTSM_to_DESIGNATED_LEARN(per_tree_port_t *ptp, unsigned int forwardDelay) 4021 { 4022 PRTSM_LOG(""); 4023 ptp->PRTSM_state = PRTSM_DESIGNATED_LEARN; 4024 4025 ptp->learn = true; 4026 assign(ptp->fdWhile, forwardDelay); 4027 4028 PRTSM_runr(ptp, true, false /* actual run */); 4029 } 4030 4031 static void PRTSM_to_DESIGNATED_DISCARD(per_tree_port_t *ptp, unsigned int forwardDelay) 4032 { 4033 PRTSM_LOG(""); 4034 ptp->PRTSM_state = PRTSM_DESIGNATED_DISCARD; 4035 4036 ptp->learn = false; 4037 ptp->forward = false; 4038 ptp->disputed = false; 4039 assign(ptp->fdWhile, forwardDelay); 4040 4041 PRTSM_runr(ptp, true, false /* actual run */); 4042 } 4043 4044 static void PRTSM_to_DESIGNATED_PORT(per_tree_port_t *ptp) 4045 { 4046 PRTSM_LOG(""); 4047 ptp->PRTSM_state = PRTSM_DESIGNATED_PORT; 4048 4049 ptp->role = roleDesignated; 4050 4051 PRTSM_runr(ptp, true, false /* actual run */); 4052 } 4053 4054 /* AlternatePort and BackupPort role transitions */ 4055 4056 static void PRTSM_to_BLOCK_PORT(per_tree_port_t *ptp) 4057 { 4058 PRTSM_LOG(""); 4059 ptp->PRTSM_state = PRTSM_BLOCK_PORT; 4060 4061 ptp->role = ptp->selectedRole; 4062 ptp->learn = false; 4063 ptp->forward = false; 4064 4065 PRTSM_runr(ptp, true, false /* actual run */); 4066 } 4067 4068 static void PRTSM_to_BACKUP_PORT(per_tree_port_t *ptp, unsigned int HelloTime) 4069 { 4070 PRTSM_LOG(""); 4071 ptp->PRTSM_state = PRTSM_BACKUP_PORT; 4072 4073 assign(ptp->rbWhile, 2 * HelloTime); 4074 4075 PRTSM_runr(ptp, true, false /* actual run */); 4076 } 4077 4078 static void PRTSM_to_ALTERNATE_PROPOSED(per_tree_port_t *ptp) 4079 { 4080 PRTSM_LOG(""); 4081 ptp->PRTSM_state = PRTSM_ALTERNATE_PROPOSED; 4082 4083 setSyncTree(ptp->tree); 4084 ptp->proposed = false; 4085 4086 PRTSM_runr(ptp, true, false /* actual run */); 4087 } 4088 4089 static void PRTSM_to_ALTERNATE_AGREED(per_tree_port_t *ptp) 4090 { 4091 PRTSM_LOG(""); 4092 ptp->PRTSM_state = PRTSM_ALTERNATE_AGREED; 4093 4094 ptp->proposed = false; 4095 ptp->agree = true; 4096 /* newInfoXst = TRUE; */ 4097 port_t *prt = ptp->port; 4098 if(0 == ptp->MSTID) 4099 prt->newInfo = true; 4100 else 4101 prt->newInfoMsti = true; 4102 4103 PRTSM_runr(ptp, true, false /* actual run */); 4104 } 4105 4106 static void PRTSM_to_ALTERNATE_PORT(per_tree_port_t *ptp, unsigned int forwardDelay) 4107 { 4108 PRTSM_LOG(""); 4109 ptp->PRTSM_state = PRTSM_ALTERNATE_PORT; 4110 4111 assign(ptp->fdWhile, forwardDelay); 4112 ptp->synced = true; 4113 assign(ptp->rrWhile, 0u); 4114 ptp->sync = false; 4115 ptp->reRoot = false; 4116 4117 PRTSM_runr(ptp, true, false /* actual run */); 4118 } 4119 4120 static bool PRTSM_runr(per_tree_port_t *ptp, bool recursive_call, bool dry_run) 4121 { 4122 /* Following vars do not need recalculating on recursive calls */ 4123 static unsigned int MaxAge, FwdDelay, forwardDelay, HelloTime; 4124 static port_t *prt; 4125 static tree_t *tree; 4126 static per_tree_port_t *cist; 4127 /* Following vars are recalculated on each state transition */ 4128 bool allSynced, reRooted; 4129 /* Following vars are auxiliary and don't depend on recursive_call */ 4130 per_tree_port_t *ptp_1; 4131 4132 if(!recursive_call) 4133 { /* calculate these intermediate vars only first time in chain of 4134 * recursive calls */ 4135 prt = ptp->port; 4136 tree = ptp->tree; 4137 4138 cist = GET_CIST_PTP_FROM_PORT(prt); 4139 4140 /* 13.25.6 */ 4141 FwdDelay = cist->designatedTimes.Forward_Delay; 4142 4143 /* 13.25.7 */ 4144 HelloTime = cist->portTimes.Hello_Time; 4145 4146 /* 13.25.d) -> 17.20.5 of 802.1D */ 4147 forwardDelay = prt->sendRSTP ? HelloTime : FwdDelay; 4148 4149 /* 13.25.8 */ 4150 MaxAge = cist->designatedTimes.Max_Age; 4151 } 4152 4153 PRTSM_LOG("role = %d, selectedRole = %d, selected = %d, updtInfo = %d", 4154 ptp->role, ptp->selectedRole, ptp->selected, ptp->updtInfo); 4155 if((ptp->role != ptp->selectedRole) && ptp->selected && !ptp->updtInfo) 4156 { 4157 switch(ptp->selectedRole) 4158 { 4159 case roleDisabled: 4160 if(dry_run) /* at least role will change */ 4161 return true; 4162 PRTSM_to_DISABLE_PORT(ptp); 4163 return false; 4164 case roleMaster: 4165 if(dry_run) /* at least role will change */ 4166 return true; 4167 PRTSM_to_MASTER_PORT(ptp); 4168 return false; 4169 case roleRoot: 4170 if(dry_run) /* at least role will change */ 4171 return true; 4172 PRTSM_to_ROOT_PORT(ptp, FwdDelay); 4173 return false; 4174 case roleDesignated: 4175 if(dry_run) /* at least role will change */ 4176 return true; 4177 PRTSM_to_DESIGNATED_PORT(ptp); 4178 return false; 4179 case roleAlternate: 4180 case roleBackup: 4181 if(dry_run) /* at least role will change */ 4182 return true; 4183 PRTSM_to_BLOCK_PORT(ptp); 4184 return false; 4185 } 4186 } 4187 4188 /* 13.25.1 */ 4189 allSynced = true; 4190 FOREACH_PTP_IN_TREE(ptp_1, tree) 4191 { 4192 /* a) */ 4193 if(!ptp_1->selected 4194 || (ptp_1->role != ptp_1->selectedRole) 4195 || ptp_1->updtInfo 4196 ) 4197 { 4198 allSynced = false; 4199 break; 4200 } 4201 4202 /* b) */ 4203 switch(ptp->role) 4204 { 4205 case roleRoot: 4206 case roleAlternate: 4207 if((roleRoot != ptp_1->role) && !ptp_1->synced) 4208 allSynced = false; 4209 break; 4210 case roleDesignated: 4211 case roleMaster: 4212 if((ptp != ptp_1) && !ptp_1->synced) 4213 allSynced = false; 4214 break; 4215 default: 4216 allSynced = false; 4217 } 4218 if(!allSynced) 4219 break; 4220 } 4221 4222 switch(ptp->PRTSM_state) 4223 { 4224 /* Disabled Port role transitions */ 4225 case PRTSM_INIT_PORT: 4226 if(dry_run) /* state change */ 4227 return true; 4228 PRTSM_to_DISABLE_PORT(ptp); 4229 return false; 4230 case PRTSM_DISABLE_PORT: 4231 if(ptp->selected && !ptp->updtInfo 4232 && !ptp->learning && !ptp->forwarding 4233 ) 4234 { 4235 if(dry_run) /* state change */ 4236 return true; 4237 PRTSM_to_DISABLED_PORT(ptp, MaxAge); 4238 } 4239 return false; 4240 case PRTSM_DISABLED_PORT: 4241 if(ptp->selected && !ptp->updtInfo 4242 && (ptp->sync || ptp->reRoot || !ptp->synced 4243 || (ptp->fdWhile != MaxAge)) 4244 ) 4245 { 4246 if(dry_run) /* one of (sync,reRoot,synced,fdWhile) will change */ 4247 return true; 4248 PRTSM_to_DISABLED_PORT(ptp, MaxAge); 4249 } 4250 return false; 4251 /* MasterPort role transitions */ 4252 case PRTSM_MASTER_PROPOSED: 4253 /* return; */ 4254 case PRTSM_MASTER_AGREED: 4255 /* return; */ 4256 case PRTSM_MASTER_SYNCED: 4257 /* return; */ 4258 case PRTSM_MASTER_RETIRED: 4259 /* return; */ 4260 case PRTSM_MASTER_FORWARD: 4261 /* return; */ 4262 case PRTSM_MASTER_LEARN: 4263 /* return; */ 4264 case PRTSM_MASTER_DISCARD: 4265 if(dry_run) /* state change */ 4266 return true; 4267 PRTSM_to_MASTER_PORT(ptp); 4268 return false; 4269 case PRTSM_MASTER_PORT: 4270 if(!(ptp->selected && !ptp->updtInfo)) 4271 return false; 4272 if(ptp->reRoot && (0 == ptp->rrWhile)) 4273 { 4274 if(dry_run) /* state change */ 4275 return true; 4276 PRTSM_to_MASTER_RETIRED(ptp); 4277 return false; 4278 } 4279 if((!ptp->learning && !ptp->forwarding && !ptp->synced) 4280 || (ptp->agreed && !ptp->synced) 4281 || (prt->operEdge && !ptp->synced) 4282 || (ptp->sync && ptp->synced) 4283 ) 4284 { 4285 if(dry_run) /* state change */ 4286 return true; 4287 PRTSM_to_MASTER_SYNCED(ptp); 4288 return false; 4289 } 4290 if((allSynced && !ptp->agree) 4291 || (ptp->proposed && ptp->agree) 4292 ) 4293 { 4294 if(dry_run) /* state change */ 4295 return true; 4296 PRTSM_to_MASTER_AGREED(ptp); 4297 return false; 4298 } 4299 if(ptp->proposed && !ptp->agree) 4300 { 4301 if(dry_run) /* state change */ 4302 return true; 4303 PRTSM_to_MASTER_PROPOSED(ptp); 4304 return false; 4305 } 4306 if(((0 == ptp->fdWhile) || allSynced) 4307 && ptp->learn && !ptp->forward 4308 ) 4309 { 4310 if(dry_run) /* state change */ 4311 return true; 4312 PRTSM_to_MASTER_FORWARD(ptp); 4313 return false; 4314 } 4315 if(((0 == ptp->fdWhile) || allSynced) 4316 && !ptp->learn 4317 ) 4318 { 4319 if(dry_run) /* state change */ 4320 return true; 4321 PRTSM_to_MASTER_LEARN(ptp, forwardDelay); 4322 return false; 4323 } 4324 if(((ptp->sync && !ptp->synced) 4325 || (ptp->reRoot && (0 != ptp->rrWhile)) 4326 || ptp->disputed 4327 ) 4328 && !prt->operEdge && (ptp->learn || ptp->forward) 4329 ) 4330 { 4331 if(dry_run) /* state change */ 4332 return true; 4333 PRTSM_to_MASTER_DISCARD(ptp, forwardDelay); 4334 return false; 4335 } 4336 return false; 4337 /* RootPort role transitions */ 4338 case PRTSM_ROOT_PROPOSED: 4339 /* return; */ 4340 case PRTSM_ROOT_AGREED: 4341 /* return; */ 4342 case PRTSM_ROOT_SYNCED: 4343 /* return; */ 4344 case PRTSM_REROOT: 4345 /* return; */ 4346 case PRTSM_ROOT_FORWARD: 4347 /* return; */ 4348 case PRTSM_ROOT_LEARN: 4349 /* return; */ 4350 case PRTSM_REROOTED: 4351 if(dry_run) /* state change */ 4352 return true; 4353 PRTSM_to_ROOT_PORT(ptp, FwdDelay); 4354 return false; 4355 case PRTSM_ROOT_PORT: 4356 if(!(ptp->selected && !ptp->updtInfo)) 4357 return false; 4358 if(!ptp->forward && !ptp->reRoot) 4359 { 4360 if(dry_run) /* state change */ 4361 return true; 4362 PRTSM_to_REROOT(ptp); 4363 return false; 4364 } 4365 if((ptp->agreed && !ptp->synced) || (ptp->sync && ptp->synced)) 4366 { 4367 if(dry_run) /* state change */ 4368 return true; 4369 PRTSM_to_ROOT_SYNCED(ptp); 4370 return false; 4371 } 4372 if((allSynced && !ptp->agree) || (ptp->proposed && ptp->agree)) 4373 { 4374 if(dry_run) /* state change */ 4375 return true; 4376 PRTSM_to_ROOT_AGREED(ptp); 4377 return false; 4378 } 4379 if(ptp->proposed && !ptp->agree) 4380 { 4381 if(dry_run) /* state change */ 4382 return true; 4383 PRTSM_to_ROOT_PROPOSED(ptp); 4384 return false; 4385 } 4386 /* 17.20.10 of 802.1D : reRooted */ 4387 reRooted = true; 4388 FOREACH_PTP_IN_TREE(ptp_1, tree) 4389 { 4390 if((ptp != ptp_1) && (0 != ptp_1->rrWhile)) 4391 { 4392 reRooted = false; 4393 break; 4394 } 4395 } 4396 if((0 == ptp->fdWhile) 4397 || (reRooted && (0 == ptp->rbWhile) && rstpVersion(prt->bridge)) 4398 ) 4399 { 4400 if(!ptp->learn) 4401 { 4402 if(dry_run) /* state change */ 4403 return true; 4404 PRTSM_to_ROOT_LEARN(ptp, forwardDelay); 4405 return false; 4406 } 4407 else if(!ptp->forward) 4408 { 4409 if(dry_run) /* state change */ 4410 return true; 4411 PRTSM_to_ROOT_FORWARD(ptp); 4412 return false; 4413 } 4414 } 4415 if(ptp->reRoot && ptp->forward) 4416 { 4417 if(dry_run) /* state change */ 4418 return true; 4419 PRTSM_to_REROOTED(ptp); 4420 return false; 4421 } 4422 if(ptp->rrWhile != FwdDelay) 4423 { 4424 if(dry_run) /* state change */ 4425 return true; 4426 PRTSM_to_ROOT_PORT(ptp, FwdDelay); 4427 return false; 4428 } 4429 return false; 4430 /* DesignatedPort role transitions */ 4431 case PRTSM_DESIGNATED_PROPOSE: 4432 /* return; */ 4433 case PRTSM_DESIGNATED_AGREED: 4434 /* return; */ 4435 case PRTSM_DESIGNATED_SYNCED: 4436 /* return; */ 4437 case PRTSM_DESIGNATED_RETIRED: 4438 /* return; */ 4439 case PRTSM_DESIGNATED_FORWARD: 4440 /* return; */ 4441 case PRTSM_DESIGNATED_LEARN: 4442 /* return; */ 4443 case PRTSM_DESIGNATED_DISCARD: 4444 if(dry_run) /* state change */ 4445 return true; 4446 PRTSM_to_DESIGNATED_PORT(ptp); 4447 return false; 4448 case PRTSM_DESIGNATED_PORT: 4449 if(!(ptp->selected && !ptp->updtInfo)) 4450 return false; 4451 if(ptp->reRoot && (0 == ptp->rrWhile)) 4452 { 4453 if(dry_run) /* state change */ 4454 return true; 4455 PRTSM_to_DESIGNATED_RETIRED(ptp); 4456 return false; 4457 } 4458 if((!ptp->learning && !ptp->forwarding && !ptp->synced) 4459 || (ptp->agreed && !ptp->synced) 4460 || (prt->operEdge && !ptp->synced) 4461 || (ptp->sync && ptp->synced) 4462 ) 4463 { 4464 if(dry_run) /* state change */ 4465 return true; 4466 PRTSM_to_DESIGNATED_SYNCED(ptp); 4467 return false; 4468 } 4469 if(allSynced && (ptp->proposed || !ptp->agree)) 4470 { 4471 if(dry_run) /* state change */ 4472 return true; 4473 PRTSM_to_DESIGNATED_AGREED(ptp); 4474 return false; 4475 } 4476 if(!ptp->forward && !ptp->agreed && !ptp->proposing 4477 && !prt->operEdge) 4478 { 4479 if(dry_run) /* state change */ 4480 return true; 4481 PRTSM_to_DESIGNATED_PROPOSE(ptp); 4482 return false; 4483 } 4484 /* Dont transition to learn/forward when BA inconsistent */ 4485 if(((0 == ptp->fdWhile) || ptp->agreed || prt->operEdge) 4486 && ((0 == ptp->rrWhile) || !ptp->reRoot) && !ptp->sync 4487 && !ptp->port->BaInconsistent 4488 ) 4489 { 4490 if(!ptp->learn) 4491 { 4492 if(dry_run) /* state change */ 4493 return true; 4494 PRTSM_to_DESIGNATED_LEARN(ptp, forwardDelay); 4495 return false; 4496 } 4497 else if(!ptp->forward) 4498 { 4499 if(dry_run) /* state change */ 4500 return true; 4501 PRTSM_to_DESIGNATED_FORWARD(ptp); 4502 return false; 4503 } 4504 } 4505 /* Transition to discarding when BA inconsistent */ 4506 if(((ptp->sync && !ptp->synced) 4507 || (ptp->reRoot && (0 != ptp->rrWhile)) 4508 || ptp->disputed 4509 || ptp->port->BaInconsistent 4510 ) 4511 && !prt->operEdge && (ptp->learn || ptp->forward) 4512 ) 4513 { 4514 if(dry_run) /* state change */ 4515 return true; 4516 PRTSM_to_DESIGNATED_DISCARD(ptp, forwardDelay); 4517 return false; 4518 } 4519 return false; 4520 /* AlternatePort and BackupPort role transitions */ 4521 case PRTSM_BLOCK_PORT: 4522 if(ptp->selected && !ptp->updtInfo 4523 && !ptp->learning && !ptp->forwarding 4524 ) 4525 { 4526 if(dry_run) /* state change */ 4527 return true; 4528 PRTSM_to_ALTERNATE_PORT(ptp, forwardDelay); 4529 } 4530 return false; 4531 case PRTSM_BACKUP_PORT: 4532 /* return; */ 4533 case PRTSM_ALTERNATE_PROPOSED: 4534 /* return; */ 4535 case PRTSM_ALTERNATE_AGREED: 4536 if(dry_run) /* state change */ 4537 return true; 4538 PRTSM_to_ALTERNATE_PORT(ptp, forwardDelay); 4539 return false; 4540 case PRTSM_ALTERNATE_PORT: 4541 if(!(ptp->selected && !ptp->updtInfo)) 4542 return false; 4543 if((allSynced && !ptp->agree) || (ptp->proposed && ptp->agree)) 4544 { 4545 if(dry_run) /* state change */ 4546 return true; 4547 PRTSM_to_ALTERNATE_AGREED(ptp); 4548 return false; 4549 } 4550 if(ptp->proposed && !ptp->agree) 4551 { 4552 if(dry_run) /* state change */ 4553 return true; 4554 PRTSM_to_ALTERNATE_PROPOSED(ptp); 4555 return false; 4556 } 4557 if((ptp->rbWhile != 2 * HelloTime) && (roleBackup == ptp->role)) 4558 { 4559 if(dry_run) /* state change */ 4560 return true; 4561 PRTSM_to_BACKUP_PORT(ptp, HelloTime); 4562 return false; 4563 } 4564 if((ptp->fdWhile != forwardDelay) || ptp->sync || ptp->reRoot 4565 || !ptp->synced) 4566 { 4567 if(dry_run) /* state change */ 4568 return true; 4569 PRTSM_to_ALTERNATE_PORT(ptp, forwardDelay); 4570 return false; 4571 } 4572 return false; 4573 } 4574 4575 return false; 4576 } 4577 4578 /* 13.35 Port State Transition state machine */ 4579 4580 static bool PSTSM_run(per_tree_port_t *ptp, bool dry_run); 4581 #define PSTSM_begin(ptp) PSTSM_to_DISCARDING((ptp), true) 4582 4583 static void PSTSM_to_DISCARDING(per_tree_port_t *ptp, bool begin) 4584 { 4585 ptp->PSTSM_state = PSTSM_DISCARDING; 4586 4587 /* This effectively sets BLOCKING state: 4588 disableLearning(); 4589 disableForwarding(); 4590 */ 4591 if(BR_STATE_BLOCKING != ptp->state) 4592 { 4593 if(!ptp->port->deleted) 4594 MSTP_OUT_set_state(ptp, BR_STATE_BLOCKING); 4595 } 4596 ptp->learning = false; 4597 ptp->forwarding = false; 4598 4599 if(!begin) 4600 PSTSM_run(ptp, false /* actual run */); 4601 } 4602 4603 static void PSTSM_to_LEARNING(per_tree_port_t *ptp) 4604 { 4605 ptp->PSTSM_state = PSTSM_LEARNING; 4606 4607 /* enableLearning(); */ 4608 if(BR_STATE_LEARNING != ptp->state) 4609 { 4610 if(!ptp->port->deleted) 4611 MSTP_OUT_set_state(ptp, BR_STATE_LEARNING); 4612 } 4613 ptp->learning = true; 4614 4615 PSTSM_run(ptp, false /* actual run */); 4616 } 4617 4618 static void PSTSM_to_FORWARDING(per_tree_port_t *ptp) 4619 { 4620 ptp->PSTSM_state = PSTSM_FORWARDING; 4621 4622 /* enableForwarding(); */ 4623 if(BR_STATE_FORWARDING != ptp->state) 4624 { 4625 if(!ptp->port->deleted) 4626 MSTP_OUT_set_state(ptp, BR_STATE_FORWARDING); 4627 } 4628 ptp->forwarding = true; 4629 4630 /* No need to run, no one condition will be met 4631 PSTSM_run(ptp, false); */ 4632 } 4633 4634 static bool PSTSM_run(per_tree_port_t *ptp, bool dry_run) 4635 { 4636 switch(ptp->PSTSM_state) 4637 { 4638 case PSTSM_DISCARDING: 4639 if(ptp->learn) 4640 { 4641 if(dry_run) /* state change */ 4642 return true; 4643 PSTSM_to_LEARNING(ptp); 4644 } 4645 return false; 4646 case PSTSM_LEARNING: 4647 if(!ptp->learn) 4648 { 4649 if(dry_run) /* state change */ 4650 return true; 4651 PSTSM_to_DISCARDING(ptp, false); 4652 } 4653 else if(ptp->forward) 4654 { 4655 if(dry_run) /* state change */ 4656 return true; 4657 PSTSM_to_FORWARDING(ptp); 4658 } 4659 return false; 4660 case PSTSM_FORWARDING: 4661 if(!ptp->forward) 4662 { 4663 if(dry_run) /* state change */ 4664 return true; 4665 PSTSM_to_DISCARDING(ptp, false); 4666 } 4667 return false; 4668 } 4669 4670 return false; 4671 } 4672 4673 /* 13.36 Topology Change state machine */ 4674 4675 #define TCSM_begin(ptp) TCSM_to_INACTIVE((ptp), true) 4676 4677 static void TCSM_to_INACTIVE(per_tree_port_t *ptp, bool begin) 4678 { 4679 ptp->TCSM_state = TCSM_INACTIVE; 4680 4681 set_fdbFlush(ptp); 4682 assign(ptp->tcWhile, 0u); 4683 set_TopologyChange(ptp->tree, false, ptp->port); 4684 if(0 == ptp->MSTID) /* CIST */ 4685 ptp->port->tcAck = false; 4686 4687 if(!begin) 4688 TCSM_run(ptp, false /* actual run */); 4689 } 4690 4691 static bool TCSM_to_LEARNING(per_tree_port_t *ptp, bool dry_run) 4692 { 4693 if(dry_run) 4694 { 4695 if((ptp->TCSM_state != TCSM_LEARNING) || ptp->rcvdTc || ptp->tcProp) 4696 return true; 4697 if(0 == ptp->MSTID) /* CIST */ 4698 { 4699 port_t *prt = ptp->port; 4700 if(prt->rcvdTcn || prt->rcvdTcAck) 4701 return true; 4702 } 4703 return false; 4704 } 4705 4706 ptp->TCSM_state = TCSM_LEARNING; 4707 4708 if(0 == ptp->MSTID) /* CIST */ 4709 { 4710 port_t *prt = ptp->port; 4711 prt->rcvdTcn = false; 4712 prt->rcvdTcAck = false; 4713 } 4714 ptp->rcvdTc = false; 4715 ptp->tcProp = false; 4716 4717 TCSM_run(ptp, false /* actual run */); 4718 return false; 4719 } 4720 4721 static void TCSM_to_DETECTED(per_tree_port_t *ptp) 4722 { 4723 ptp->TCSM_state = TCSM_DETECTED; 4724 4725 newTcWhile(ptp); 4726 setTcPropTree(ptp); 4727 /* newInfoXst = TRUE; */ 4728 port_t *prt = ptp->port; 4729 if(0 == ptp->MSTID) 4730 prt->newInfo = true; 4731 else 4732 prt->newInfoMsti = true; 4733 4734 TCSM_run(ptp, false /* actual run */); 4735 } 4736 4737 static void TCSM_to_NOTIFIED_TCN(per_tree_port_t *ptp) 4738 { 4739 ptp->TCSM_state = TCSM_NOTIFIED_TCN; 4740 4741 newTcWhile(ptp); 4742 4743 TCSM_run(ptp, false /* actual run */); 4744 } 4745 4746 static void TCSM_to_NOTIFIED_TC(per_tree_port_t *ptp) 4747 { 4748 ptp->TCSM_state = TCSM_NOTIFIED_TC; 4749 4750 ptp->rcvdTc = false; 4751 if(0 == ptp->MSTID) /* CIST */ 4752 { 4753 port_t *prt = ptp->port; 4754 prt->rcvdTcn = false; 4755 if(roleDesignated == ptp->role) 4756 prt->tcAck = true; 4757 } 4758 setTcPropTree(ptp); 4759 4760 TCSM_run(ptp, false /* actual run */); 4761 } 4762 4763 static void TCSM_to_PROPAGATING(per_tree_port_t *ptp) 4764 { 4765 ptp->TCSM_state = TCSM_PROPAGATING; 4766 4767 newTcWhile(ptp); 4768 set_fdbFlush(ptp); 4769 ptp->tcProp = false; 4770 4771 TCSM_run(ptp, false /* actual run */); 4772 } 4773 4774 static void TCSM_to_ACKNOWLEDGED(per_tree_port_t *ptp) 4775 { 4776 ptp->TCSM_state = TCSM_ACKNOWLEDGED; 4777 4778 assign(ptp->tcWhile, 0u); 4779 set_TopologyChange(ptp->tree, false, ptp->port); 4780 ptp->port->rcvdTcAck = false; 4781 4782 TCSM_run(ptp, false /* actual run */); 4783 } 4784 4785 static void TCSM_to_ACTIVE(per_tree_port_t *ptp) 4786 { 4787 ptp->TCSM_state = TCSM_ACTIVE; 4788 4789 TCSM_run(ptp, false /* actual run */); 4790 } 4791 4792 static bool TCSM_run(per_tree_port_t *ptp, bool dry_run) 4793 { 4794 bool active_port; 4795 port_t *prt = ptp->port; 4796 4797 switch(ptp->TCSM_state) 4798 { 4799 case TCSM_INACTIVE: 4800 if(ptp->learn && !ptp->fdbFlush) 4801 { 4802 if(dry_run) /* state change */ 4803 return true; 4804 TCSM_to_LEARNING(ptp, false /* actual run */); 4805 } 4806 return false; 4807 case TCSM_LEARNING: 4808 active_port = (roleRoot == ptp->role) 4809 || (roleDesignated == ptp->role) 4810 || (roleMaster == ptp->role); 4811 if(active_port && ptp->forward && !prt->operEdge) 4812 { 4813 if(dry_run) /* state change */ 4814 return true; 4815 TCSM_to_DETECTED(ptp); 4816 return false; 4817 } 4818 if(ptp->rcvdTc || prt->rcvdTcn || prt->rcvdTcAck || ptp->tcProp) 4819 { 4820 return TCSM_to_LEARNING(ptp, dry_run); 4821 } 4822 else if(!active_port && !(ptp->learn || ptp->learning)) 4823 { 4824 if(dry_run) /* state change */ 4825 return true; 4826 TCSM_to_INACTIVE(ptp, false); 4827 } 4828 return false; 4829 case TCSM_NOTIFIED_TCN: 4830 if(dry_run) /* state change */ 4831 return true; 4832 TCSM_to_NOTIFIED_TC(ptp); 4833 return false; 4834 case TCSM_DETECTED: 4835 /* return; */ 4836 case TCSM_NOTIFIED_TC: 4837 /* return; */ 4838 case TCSM_PROPAGATING: 4839 /* return; */ 4840 case TCSM_ACKNOWLEDGED: 4841 if(dry_run) /* state change */ 4842 return true; 4843 TCSM_to_ACTIVE(ptp); 4844 return false; 4845 case TCSM_ACTIVE: 4846 active_port = (roleRoot == ptp->role) 4847 || (roleDesignated == ptp->role) 4848 || (roleMaster == ptp->role); 4849 if(!active_port || prt->operEdge) 4850 { 4851 if(dry_run) /* state change */ 4852 return true; 4853 TCSM_to_LEARNING(ptp, false /* actual run */); 4854 return false; 4855 } 4856 if(prt->rcvdTcn) 4857 { 4858 if(dry_run) /* state change */ 4859 return true; 4860 TCSM_to_NOTIFIED_TCN(ptp); 4861 return false; 4862 } 4863 if(ptp->rcvdTc) 4864 { 4865 if(dry_run) /* state change */ 4866 return true; 4867 TCSM_to_NOTIFIED_TC(ptp); 4868 return false; 4869 } 4870 if(ptp->tcProp/* && !prt->operEdge */) 4871 { 4872 if(dry_run) /* state change */ 4873 return true; 4874 TCSM_to_PROPAGATING(ptp); 4875 return false; 4876 } 4877 if(prt->rcvdTcAck) 4878 { 4879 if(dry_run) /* state change */ 4880 return true; 4881 TCSM_to_ACKNOWLEDGED(ptp); 4882 return false; 4883 } 4884 return false; 4885 } 4886 4887 return false; 4888 } 4889 4890 /* Execute BEGIN state. We do not define BEGIN variable 4891 * but instead xxx_state_machines_begin execute begin state 4892 * abd do one step out of it 4893 */ 4894 4895 static void tree_state_machines_begin(tree_t *tree) 4896 { 4897 bridge_t *br = tree->bridge; 4898 per_tree_port_t *ptp; 4899 4900 if(!br->bridgeEnabled) 4901 return; 4902 4903 /* 13.32 Port Information state machine */ 4904 FOREACH_PTP_IN_TREE(ptp, tree) 4905 { 4906 ptp->start_time = br->uptime; /* 12.8.2.2.3 b) */ 4907 PISM_begin(ptp); 4908 } 4909 4910 /* 13.33 Port Role Selection state machine */ 4911 PRSSM_begin(tree); 4912 4913 /* 13.34 Port Role Transitions state machine */ 4914 FOREACH_PTP_IN_TREE(ptp, tree) 4915 PRTSM_begin(ptp); 4916 /* 13.35 Port State Transition state machine */ 4917 FOREACH_PTP_IN_TREE(ptp, tree) 4918 PSTSM_begin(ptp); 4919 /* 13.36 Topology Change state machine */ 4920 FOREACH_PTP_IN_TREE(ptp, tree) 4921 TCSM_begin(ptp); 4922 4923 br_state_machines_run(br); 4924 } 4925 4926 static void prt_state_machines_begin(port_t *prt) 4927 { 4928 bridge_t *br = prt->bridge; 4929 tree_t *tree; 4930 per_tree_port_t *ptp; 4931 4932 if(!br->bridgeEnabled) 4933 return; 4934 4935 /* 13.28 Port Receive state machine */ 4936 PRSM_begin(prt); 4937 /* 13.29 Port Protocol Migration state machine */ 4938 PPMSM_begin(prt); 4939 /* 13.30 Bridge Detection state machine */ 4940 BDSM_begin(prt); 4941 /* 13.31 Port Transmit state machine */ 4942 PTSM_begin(prt); 4943 4944 /* 13.32 Port Information state machine */ 4945 FOREACH_PTP_IN_PORT(ptp, prt) 4946 { 4947 ptp->start_time = br->uptime; /* 12.8.2.2.3 b) */ 4948 PISM_begin(ptp); 4949 } 4950 4951 /* 13.33 Port Role Selection state machine */ 4952 FOREACH_TREE_IN_BRIDGE(tree, br) 4953 PRSSM_run(tree, false /* actual run */); 4954 4955 /* 13.34 Port Role Transitions state machine */ 4956 FOREACH_PTP_IN_PORT(ptp, prt) 4957 PRTSM_begin(ptp); 4958 /* 13.35 Port State Transition state machine */ 4959 FOREACH_PTP_IN_PORT(ptp, prt) 4960 PSTSM_begin(ptp); 4961 /* 13.36 Topology Change state machine */ 4962 FOREACH_PTP_IN_PORT(ptp, prt) 4963 TCSM_begin(ptp); 4964 4965 br_state_machines_run(br); 4966 } 4967 4968 static void br_state_machines_begin(bridge_t *br) 4969 { 4970 port_t *prt; 4971 per_tree_port_t *ptp; 4972 tree_t *tree; 4973 4974 if(!br->bridgeEnabled) 4975 return; 4976 4977 /* 13.28 Port Receive state machine */ 4978 FOREACH_PORT_IN_BRIDGE(prt, br) 4979 PRSM_begin(prt); 4980 /* 13.29 Port Protocol Migration state machine */ 4981 FOREACH_PORT_IN_BRIDGE(prt, br) 4982 PPMSM_begin(prt); 4983 /* 13.30 Bridge Detection state machine */ 4984 FOREACH_PORT_IN_BRIDGE(prt, br) 4985 BDSM_begin(prt); 4986 /* 13.31 Port Transmit state machine */ 4987 FOREACH_PORT_IN_BRIDGE(prt, br) 4988 PTSM_begin(prt); 4989 4990 /* 13.32 Port Information state machine */ 4991 FOREACH_PORT_IN_BRIDGE(prt, br) 4992 { 4993 FOREACH_PTP_IN_PORT(ptp, prt) 4994 { 4995 ptp->start_time = br->uptime; /* 12.8.2.2.3 b) */ 4996 PISM_begin(ptp); 4997 } 4998 } 4999 5000 /* 13.33 Port Role Selection state machine */ 5001 FOREACH_TREE_IN_BRIDGE(tree, br) 5002 PRSSM_begin(tree); 5003 5004 /* 13.34 Port Role Transitions state machine */ 5005 FOREACH_PORT_IN_BRIDGE(prt, br) 5006 { 5007 FOREACH_PTP_IN_PORT(ptp, prt) 5008 PRTSM_begin(ptp); 5009 } 5010 /* 13.35 Port State Transition state machine */ 5011 FOREACH_PORT_IN_BRIDGE(prt, br) 5012 { 5013 FOREACH_PTP_IN_PORT(ptp, prt) 5014 PSTSM_begin(ptp); 5015 } 5016 /* 13.36 Topology Change state machine */ 5017 FOREACH_PORT_IN_BRIDGE(prt, br) 5018 { 5019 FOREACH_PTP_IN_PORT(ptp, prt) 5020 TCSM_begin(ptp); 5021 } 5022 5023 br_state_machines_run(br); 5024 } 5025 5026 /* Run each state machine. 5027 * Return false iff all state machines in dry run indicate that 5028 * state will not be changed. Otherwise return true. 5029 */ 5030 static bool __br_state_machines_run(bridge_t *br, bool dry_run) 5031 { 5032 port_t *prt; 5033 per_tree_port_t *ptp; 5034 tree_t *tree; 5035 5036 /* Check if bridge assurance timer expires */ 5037 FOREACH_PORT_IN_BRIDGE(prt, br) 5038 { 5039 if(prt->portEnabled && assurancePort(prt) 5040 && (0 == prt->brAssuRcvdInfoWhile) && !prt->BaInconsistent 5041 ) 5042 { 5043 if(dry_run) /* state change */ 5044 return true; 5045 prt->BaInconsistent = true; 5046 ERROR_PRTNAME(prt->bridge, prt, "Bridge assurance inconsistent"); 5047 } 5048 } 5049 5050 /* 13.28 Port Receive state machine */ 5051 FOREACH_PORT_IN_BRIDGE(prt, br) 5052 { 5053 if(PRSM_run(prt, dry_run) && dry_run) 5054 return true; 5055 } 5056 /* 13.29 Port Protocol Migration state machine */ 5057 FOREACH_PORT_IN_BRIDGE(prt, br) 5058 { 5059 if(PPMSM_run(prt, dry_run) && dry_run) 5060 return true; 5061 } 5062 /* 13.30 Bridge Detection state machine */ 5063 FOREACH_PORT_IN_BRIDGE(prt, br) 5064 { 5065 if(BDSM_run(prt, dry_run) && dry_run) 5066 return true; 5067 } 5068 /* 13.31 Port Transmit state machine */ 5069 FOREACH_PORT_IN_BRIDGE(prt, br) 5070 { 5071 if(PTSM_run(prt, dry_run) && dry_run) 5072 return true; 5073 } 5074 5075 /* 13.32 Port Information state machine */ 5076 FOREACH_PORT_IN_BRIDGE(prt, br) 5077 { 5078 FOREACH_PTP_IN_PORT(ptp, prt) 5079 { 5080 if(PISM_run(ptp, dry_run) && dry_run) 5081 return true; 5082 } 5083 } 5084 5085 /* 13.33 Port Role Selection state machine */ 5086 FOREACH_TREE_IN_BRIDGE(tree, br) 5087 { 5088 if(PRSSM_run(tree, dry_run) && dry_run) 5089 return true; 5090 } 5091 5092 /* 13.34 Port Role Transitions state machine */ 5093 FOREACH_PORT_IN_BRIDGE(prt, br) 5094 { 5095 FOREACH_PTP_IN_PORT(ptp, prt) 5096 { 5097 if(PRTSM_run(ptp, dry_run) && dry_run) 5098 return true; 5099 } 5100 } 5101 /* 13.35 Port State Transition state machine */ 5102 FOREACH_PORT_IN_BRIDGE(prt, br) 5103 { 5104 FOREACH_PTP_IN_PORT(ptp, prt) 5105 { 5106 if(PSTSM_run(ptp, dry_run) && dry_run) 5107 return true; 5108 } 5109 } 5110 /* 13.36 Topology Change state machine */ 5111 FOREACH_PORT_IN_BRIDGE(prt, br) 5112 { 5113 FOREACH_PTP_IN_PORT(ptp, prt) 5114 { 5115 if(TCSM_run(ptp, dry_run) && dry_run) 5116 return true; 5117 } 5118 } 5119 5120 return false; 5121 } 5122 5123 /* Run state machines until their state stabilizes. 5124 * Do not consume more than 1 second. 5125 */ 5126 static void br_state_machines_run(bridge_t *br) 5127 { 5128 struct timespec tv, tv_end; 5129 signed long delta; 5130 5131 if(!br->bridgeEnabled) 5132 return; 5133 5134 clock_gettime(CLOCK_MONOTONIC, &tv_end); 5135 ++(tv_end.tv_sec); 5136 5137 do { 5138 if(!__br_state_machines_run(br, true /* dry run */)) 5139 return; 5140 __br_state_machines_run(br, false /* actual run */); 5141 5142 /* Check for the timeout */ 5143 clock_gettime(CLOCK_MONOTONIC, &tv); 5144 if(0 < (delta = tv.tv_sec - tv_end.tv_sec)) 5145 return; 5146 if(0 == delta) 5147 { 5148 delta = tv.tv_nsec - tv_end.tv_nsec; 5149 if(0 < delta) 5150 return; 5151 } 5152 } while(true); 5153 } 5154
This page was automatically generated by LXR 0.3.1. • OpenWrt