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