|
INET Framework for OMNeT++/OMNEST
|
00001 /* 00002 * stpInstance.cpp 00003 * 00004 * Created on: 16.5.2011 00005 * Author: aranel 00006 */ 00007 00008 #include "stpi.h" 00009 #include "STPMACCompare.h" 00010 00011 stpi::stpi(unsigned int _vlan, unsigned int _portCount, MACAddress _bridgeAddress, MACTable * _addrTable) { 00012 00013 portCount = _portCount; 00014 bridgeAddress = _bridgeAddress; // apply the bridge address 00015 vlan = _vlan; 00016 addrTable = _addrTable; 00017 initPortTable(); 00018 00019 helloTime = 2; 00020 maxAge = 20; 00021 fwdDelay = 15; 00022 bridgePriority = 32768; 00023 ubridgePriority = bridgePriority; 00024 00025 isRoot = true; 00026 topologyChange = 0; 00027 topologyChangeNotification = false; 00028 topologyChangeRecvd = false; 00029 00030 rootPriority = bridgePriority; 00031 rootID = bridgeAddress; 00032 rootPathCost = 0; 00033 rootPort = 0; 00034 cHelloTime = helloTime; 00035 cMaxAge = maxAge; 00036 cFwdDelay = fwdDelay; 00037 00038 00039 helloTimer = 0; 00040 00041 00042 allDesignated(); 00043 00044 } 00045 00046 stpi::~stpi() { 00047 00048 } 00049 00050 void stpi::send(cMessage * _msg, unsigned int _port) { 00051 tMsg tmp; 00052 tmp.port = _port; 00053 tmp.msg = _msg; 00054 msgList.push_back(tmp); 00055 } 00056 00057 00058 00059 /* dummy records to portTable to be learned */ 00060 void stpi::initPortTable() { 00061 tPortFlags flag; 00062 flag.Forwarding = false; 00063 flag.Learning = false; 00064 00065 tPort port; 00066 00067 port.enabled = true; 00068 port.state = SDISCARDING; 00069 port.role = RUNKNOWN; 00070 port.priority = 128; 00071 port.flags = flag; 00072 port.rootPathCost = INT16_MAX; 00073 port.rootPriority = 65536; 00074 port.rootID = MACAddress("FF-FF-FF-FF-FF-FF"); 00075 port.bridgePriority = 65536; 00076 port.bridgeID = MACAddress("FF-FF-FF-FF-FF-FF"); 00077 port.portPriority = 256; 00078 port.portID = 256; 00079 port.age = 0; 00080 port.fdWhile = 0; 00081 port.maxAge = 20; 00082 port.fwdDelay = 15; 00083 port.helloTime = 2; 00084 port.linkCost = 19; 00085 00086 defaultPort = port; 00087 00088 portTable.insert(portTable.begin(), portCount, port); 00089 00090 } 00091 00092 void stpi::handleMessage(cMessage *msg) 00093 { 00094 cMessage * tmp = msg; 00095 00096 if (!msg->isSelfMessage()) { 00097 if (dynamic_cast<STPBPDU *>(tmp)){ // Configuration BPDU 00098 STPBPDU * bpdu = (STPBPDU *) tmp; 00099 handleBPDU(bpdu); 00100 } else if (dynamic_cast<STPTCN *>(tmp)){ // Topology Change Notification 00101 STPTCN * tcn = (STPTCN *) tmp; 00102 handleTCN(tcn); 00103 } else { // Rubbish 00104 delete msg; 00105 } 00106 } else { // self rubbish 00107 delete msg; 00108 } 00109 } 00110 00111 bool stpi::learning(unsigned int port) { 00112 return portTable.at(port).flags.Learning; 00113 } 00114 00115 bool stpi::forwarding(unsigned int port) { 00116 return portTable.at(port).flags.Forwarding; 00117 } 00118 00119 void stpi::handleBPDU(STPBPDU * bpdu) { 00120 00121 /* get inferior BPDU, reply with superior */ 00122 if (superiorBPDU(bpdu->getArrivalGate()->getIndex(), bpdu) == false) { 00123 /* ONLY on designated port, because of flapping old root bridge information 00124 * between bridges, when only parameters changed 00125 */ 00126 if (portTable.at(bpdu->getArrivalGate()->getIndex()).role == RDESIGNATED) { 00127 generateHelloBPDU(bpdu->getArrivalGate()->getIndex()); 00128 } 00129 } 00130 /* relay BPDU from root */ 00131 else if (portTable.at(bpdu->getArrivalGate()->getIndex()).role == RROOT) { 00132 00133 if (bpdu->getTca()) { 00134 topologyChangeNotification = false; 00135 } 00136 if (bpdu->getTc()) { 00137 topologyChange++; 00138 addrTable->enableFasterAging(); 00139 } else { 00140 addrTable->resetAging(); 00141 } 00142 00143 for (unsigned int i = 0; i < desPorts.size(); i++) { 00144 generateHelloBPDU(desPorts.at(i)); 00145 } 00146 if (topologyChangeRecvd) { // TCA with BPDUs 00147 topologyChangeRecvd = false; 00148 } 00149 if (topologyChange > 0) { 00150 topologyChange--; 00151 } 00152 } 00153 00154 00155 /* --- BEGIN RUBBISH --- */ 00156 00157 tryRoot(); 00158 00159 /* --- END OF RUBBISH --- */ 00160 00161 delete bpdu; 00162 } 00163 00164 void stpi::handleTCN(STPTCN * tcn) { 00165 topologyChangeNotification = true; 00166 topologyChangeRecvd = true; 00167 //delete tcn; 00168 } 00169 00170 00171 00172 void stpi::generateHelloBPDU(int port) { 00173 STPBPDU * bpdu = new STPBPDU("BPDU", vlan); 00174 bpdu->setVlan(vlan); 00175 bpdu->setPortRole(stpi::RDESIGNATED); 00176 bpdu->setBridgeID(bridgeAddress); 00177 bpdu->setBridgePriority(bridgePriority); 00178 bpdu->setRootPathCost(rootPathCost); 00179 bpdu->setRootID(rootID); 00180 bpdu->setRootPriority(rootPriority); 00181 bpdu->setPortID(port); 00182 bpdu->setPortPriority(portTable.at(port).priority); 00183 bpdu->setMsgAge(0); 00184 bpdu->setMaxAge(cMaxAge); 00185 bpdu->setHelloTime(cHelloTime); 00186 bpdu->setFwdDelay(cFwdDelay); 00187 00188 00189 00190 if (topologyChangeRecvd) { 00191 bpdu->setTca(true); 00192 } else { 00193 bpdu->setTca(false); 00194 } 00195 if (topologyChange > 0) { 00196 /* lowering value is in reply to root bpdu, 00197 * for root in generator 00198 */ 00199 bpdu->setTc(true); 00200 } else { 00201 bpdu->setTc(false); 00202 } 00203 00204 send(bpdu, port); 00205 } 00206 00207 void stpi::generateTCN() { 00208 if (topologyChangeNotification) { // is something to notify 00209 if (portTable.at(rootPort).role == RROOT) { // exist root port to notifying 00210 STPTCN * tcn = new STPTCN("TCN", vlan); 00211 tcn->setVlan(vlan); 00212 send(tcn, rootPort); 00213 } 00214 } 00215 00216 } 00217 00218 /* check of the received BPDU is superior to port information from porttable */ 00219 bool stpi::superiorBPDU(int p, STPBPDU * bpdu) { 00220 tPort port = portTable.at(p); 00221 tPort xbpdu; 00222 int result; 00223 00224 xbpdu.rootPriority = bpdu->getRootPriority(); 00225 xbpdu.rootID = bpdu->getRootID(); 00226 xbpdu.rootPathCost = bpdu->getRootPathCost() + port.linkCost; 00227 xbpdu.bridgePriority = bpdu->getBridgePriority(); 00228 xbpdu.bridgeID = bpdu->getBridgeID(); 00229 xbpdu.portPriority = bpdu->getPortPriority(); 00230 xbpdu.portID = bpdu->getPortID(); 00231 00232 result = superiorTPort(port, xbpdu); 00233 00234 if (result > 0) { // port is superior 00235 return false; 00236 } 00237 if (result < 0) { // BPDU is superior 00238 resetFDWhile(p); // renew info 00239 setPortState(p, SDISCARDING); 00240 setSuperiorBPDU(p, bpdu); // renew information 00241 return true; 00242 } 00243 00244 setSuperiorBPDU(p, bpdu); // renew information 00245 return true; 00246 } 00247 00248 /* set all new information to the port, or renew old one, eg. reset timer */ 00249 void stpi::setSuperiorBPDU(int port, STPBPDU * bpdu) { 00250 if (bpdu->getMsgAge() >= bpdu->getMaxAge()) { 00251 return; 00252 } 00253 00254 portTable.at(port).rootPriority = bpdu->getRootPriority(); 00255 portTable.at(port).rootID = bpdu->getRootID(); 00256 portTable.at(port).rootPathCost = bpdu->getRootPathCost() + portTable.at(port).linkCost; 00257 portTable.at(port).bridgePriority = bpdu->getBridgePriority(); 00258 portTable.at(port).bridgeID = bpdu->getBridgeID(); 00259 portTable.at(port).portPriority = bpdu->getPortPriority(); 00260 portTable.at(port).portID = bpdu->getPortID(); 00261 00262 portTable.at(port).maxAge = bpdu->getMaxAge(); 00263 portTable.at(port).fwdDelay = bpdu->getFwdDelay(); 00264 portTable.at(port).helloTime = bpdu->getHelloTime(); 00265 00266 00267 resetAge(port); // renew info 00268 00269 } 00270 00271 void stpi::generator() { 00272 if (!isRoot) { 00273 return; 00274 } 00275 for (unsigned int i = 0; i < portCount; i++) { 00276 generateHelloBPDU(i); 00277 } 00278 if (topologyChangeRecvd) { // TCA with BPDUs 00279 topologyChangeRecvd = false; 00280 } 00281 if (topologyChange > 0) { 00282 addrTable->enableFasterAging(); 00283 topologyChange--; 00284 } else { 00285 addrTable->resetAging(); 00286 } 00287 } 00288 00289 00290 void stpi::handleTick() { 00291 /* BRIDGE TIMERS */ 00292 if (isRoot) { 00293 helloTimer++; 00294 } else { 00295 helloTimer = 0; 00296 } 00297 00298 for (unsigned int i = 0; i < portCount; i++) { // PORT TIMERS 00299 // DISABLED ports is not operational 00300 if (portTable.at(i).enabled == false) { 00301 continue; 00302 } 00303 00304 // designated port's origins informations to LAN, 00305 // cannot aged out yourself 00306 if (portTable.at(i).role != RDESIGNATED) { 00307 portTable.at(i).age++; 00308 } 00309 if (portTable.at(i).role == RROOT || portTable.at(i).role == RDESIGNATED) { 00310 portTable.at(i).fdWhile++; 00311 } 00312 } 00313 00314 checkTimers(); 00315 checkParametersChange(); 00316 00317 generateTCN(); // if something to notify 00318 } 00319 00320 void stpi::checkTimers() { 00321 00322 /* Hello timer check */ 00323 if (helloTimer >= cHelloTime) { 00324 generator(); 00325 helloTimer = 0; 00326 } 00327 00328 /* information age check */ 00329 for (unsigned int i = 0; i < portCount; i++) { 00330 if (portTable.at(i).age >= cMaxAge) { 00331 if (portTable.at(i).role == RROOT) { 00332 portTable.at(i) = defaultPort; 00333 lostRoot(); 00334 } else { 00335 portTable.at(i) = defaultPort; 00336 lostAlternate(i); 00337 } 00338 } 00339 } 00340 00341 00342 /* fdWhile timer */ 00343 for (unsigned int i = 0; i < portCount; i++) { 00344 /* ROOT / DESIGNATED, can transition */ 00345 if (portTable.at(i).role == RROOT || portTable.at(i).role == RDESIGNATED) { 00346 if (portTable.at(i).fdWhile >= cFwdDelay) { 00347 switch (portTable.at(i).state) { 00348 case SDISABLED: 00349 setPortState(i, SDISCARDING); 00350 resetFDWhile(i); 00351 break; 00352 case SDISCARDING: 00353 setPortState(i, SLEARNING); 00354 resetFDWhile(i); 00355 break; 00356 case SLEARNING: 00357 setPortState(i, SFORWARDING); 00358 resetFDWhile(i); 00359 break; 00360 default: 00361 resetFDWhile(i); 00362 break; 00363 } 00364 00365 } 00366 } else { 00367 resetFDWhile(i); 00368 setPortState(i, SDISCARDING); 00369 } 00370 } 00371 00372 /* TOPOLOGY CHANGE HANDLING */ 00373 if (topologyChangeNotification == true) { 00374 if (isRoot == true) { 00375 topologyChange = 5; 00376 topologyChangeNotification = false; 00377 } 00378 } 00379 00380 } 00381 00382 void stpi::checkParametersChange() { 00383 if (isRoot) { 00384 cHelloTime = helloTime; 00385 cMaxAge = maxAge; 00386 cFwdDelay = fwdDelay; 00387 } 00388 if (ubridgePriority != bridgePriority) { 00389 ubridgePriority = bridgePriority; 00390 reset(); 00391 } 00392 } 00393 00394 00395 void stpi::resetAge(int p) { 00396 portTable.at(p).age = 0; 00397 } 00398 00399 void stpi::resetFDWhile(int p) { 00400 portTable.at(p).fdWhile = 0; 00401 } 00402 00403 bool stpi::checkRootEligibility() { 00404 for (unsigned int i = 0; i < portCount; i++) { 00405 if (superiorID(portTable.at(i).rootPriority, portTable.at(i).rootID, 00406 bridgePriority, bridgeAddress) > 0) { 00407 /* port information is superior to bridge ID, is not root eligible */ 00408 return false; 00409 } 00410 } 00411 return true; 00412 } 00413 00414 void stpi::tryRoot() { 00415 if (checkRootEligibility() == false) { 00416 isRoot = false; 00417 // EV << this->getParentModule()->getFullName() << ": not eligible to be root!" << std::endl; 00418 selectRootPort(); 00419 selectDesignatedPorts(); 00420 } else { 00421 00422 // EV << this->getParentModule()->getFullName() << ": Iam root!" << std::endl; 00423 isRoot = true; 00424 allDesignated(); 00425 rootPriority = bridgePriority; 00426 rootID = bridgeAddress; 00427 rootPathCost = 0; 00428 cHelloTime = helloTime; 00429 cMaxAge = maxAge; 00430 cFwdDelay = fwdDelay; 00431 } 00432 00433 00434 } 00435 00436 int stpi::superiorID(unsigned int APR, MACAddress AID, unsigned int BPR, MACAddress BID) { 00437 if (APR < BPR) { 00438 return 1; // A is superior 00439 } else if (APR > BPR) { 00440 return -1; 00441 } 00442 00443 // APR == BPR 00444 if (AID < BID) { 00445 return 1; // A is superior 00446 } else if (AID > BID) { 00447 return -1; 00448 } 00449 00450 /* A==B 00451 * (can happen if bridge have two port connected to one not bridged lan, 00452 * "cable loopback") 00453 */ 00454 return 0; 00455 } 00456 00457 int stpi::superiorPort(unsigned int APR, unsigned int AID, unsigned int BPR, unsigned int BID) { 00458 if (APR < BPR) { 00459 return 1; // A is superior 00460 } else if (APR > BPR) { 00461 return -1; 00462 } 00463 00464 // APR == BPR 00465 if (AID < BID) { 00466 return 1; // A is superior 00467 } else if (AID > BID) { 00468 return -1; 00469 } 00470 00471 /* A==B */ 00472 return 0; 00473 } 00474 00475 00476 00477 int stpi::superiorTPort(tPort A, tPort B) { 00478 int result; 00479 /* ROOT COMPARSION */ 00480 result = superiorID(A.rootPriority, A.rootID, 00481 B.rootPriority, B.rootID); 00482 if (result != 0){ // not same, so pass result 00483 return result; 00484 } 00485 00486 /* PATH COST */ 00487 if (A.rootPathCost < B.rootPathCost) { 00488 return 1; 00489 } 00490 if (A.rootPathCost > B.rootPathCost) { 00491 return -1; 00492 } 00493 00494 /* DESIGNATED BRIDGE */ 00495 result = superiorID(A.bridgePriority, A.bridgeID, 00496 B.bridgePriority, B.bridgeID); 00497 if (result != 0){ // not same, so pass result 00498 return result; 00499 } 00500 00501 00502 /* DESIGNATED PORT OF DESIGNATED BRIDGE*/ 00503 result = superiorPort(A.portPriority, A.portID, 00504 B.portPriority, B.portID); 00505 if (result != 0){ // not same, so pass result 00506 return result; 00507 } 00508 00509 return 0; // same 00510 } 00511 00512 void stpi::selectRootPort() { 00513 unsigned int xRootPort = 0; 00514 int result; 00515 tPort best = defaultPort; // can be superseded by all real tPort structures 00516 tPort tmp; 00517 00518 for (unsigned int i = 0; i < portCount; i++) { 00519 tmp = portTable.at(i); 00520 portTable.at(i).role = RUNKNOWN; 00521 result = superiorTPort(tmp, best); 00522 if (result > 0) { // new root port 00523 xRootPort = i; 00524 best = tmp; 00525 continue; 00526 } 00527 if (result < 0) { // inferior information 00528 continue; 00529 } 00530 /* same info on tPort */ 00531 if (tmp.priority < best.priority) { // better priority 00532 xRootPort = i; 00533 best = tmp; 00534 continue; 00535 } 00536 if (tmp.priority > best.priority) { // inferior priority 00537 continue; 00538 } 00539 /* ALL IS THE SAME, index of port resolving stalemate, 00540 * because of for cycle is the existing xRootPort lower 00541 * so it' remains */ 00542 continue; 00543 00544 } 00545 if (rootPort != xRootPort) { 00546 topologyChangeNotification = true; 00547 } 00548 00549 rootPort = xRootPort; 00550 portTable.at(rootPort).role = RROOT; 00551 00552 rootPathCost = best.rootPathCost; 00553 rootID = best.rootID; 00554 rootPriority = best.rootPriority; 00555 00556 cMaxAge = best.maxAge; 00557 cFwdDelay = best.fwdDelay; 00558 cHelloTime = best.helloTime; 00559 00560 } 00561 00562 /* select designated ports */ 00563 void stpi::selectDesignatedPorts() { 00564 /* designated is the best with same Root, OR inferior root */ 00565 std::vector<unsigned int> xDesPorts; 00566 tPort tmp; 00567 tPort bridge; // current bridge information 00568 int result; 00569 00570 bridge.bridgePriority = bridgePriority; 00571 bridge.bridgeID = bridgeAddress; 00572 bridge.rootID = rootID; 00573 bridge.rootPriority = rootPriority; 00574 00575 00576 00577 for (unsigned int i = 0; i < portCount; i++) { 00578 tmp = portTable.at(i); 00579 00580 if (tmp.role == RROOT) { 00581 continue; 00582 } 00583 if (tmp.enabled == false) { 00584 continue; 00585 } 00586 00587 bridge.portPriority = portTable.at(i).priority; 00588 bridge.portID = i; 00589 00590 bridge.rootPathCost = rootPathCost + portTable.at(i).linkCost; 00591 00592 if (superiorID(rootPriority, rootID, tmp.rootPriority, tmp.rootID) < 0) { 00593 // error("cannot be superior Root on port !"); 00594 } 00595 // EV << this->getFullName() << "I:" << bridge << " ? " << tmp << std::endl; 00596 result = superiorTPort(bridge, tmp); 00597 if (result > 0) { 00598 xDesPorts.push_back(i); 00599 portTable.at(i).role = RDESIGNATED; 00600 continue; 00601 } 00602 if (result < 0) { 00603 portTable.at(i).role = RALTERNATE; 00604 continue; 00605 } 00606 // error("cannot be the same !"); 00607 00608 } 00609 00610 desPorts.clear(); 00611 desPorts = xDesPorts; 00612 00613 } 00614 00615 void stpi::allDesignated() { 00616 std::vector<unsigned int> xDesPorts; 00617 for (unsigned int i = 0; i < portCount; i++) { 00618 if (portTable.at(i).enabled == false) { 00619 continue; 00620 } 00621 xDesPorts.push_back(i); 00622 portTable.at(i).role = RDESIGNATED; 00623 } 00624 desPorts.clear(); 00625 desPorts = xDesPorts; 00626 } 00627 00628 00629 /* neighbor lost handling */ 00630 void stpi::lostRoot() { 00631 topologyChangeNotification = true; // information for bridge, that topology change is commited 00632 // EV << this->getParentModule()->getFullName() << ": ROOT IS DOWN!" << std::endl; 00633 tryRoot(); 00634 00635 } 00636 00637 void stpi::lostAlternate(int port) { 00638 selectDesignatedPorts(); 00639 topologyChangeNotification = true; 00640 } 00641 00642 void stpi::reset() { 00643 isRoot = true; 00644 rootPriority = bridgePriority; 00645 rootID = bridgeAddress; 00646 rootPathCost = 0; 00647 cHelloTime = helloTime; 00648 cMaxAge = maxAge; 00649 cFwdDelay = fwdDelay; 00650 allDesignated(); 00651 00652 for (unsigned int i = 0; i < portCount; i++) { 00653 portTable.at(i) = defaultPort; 00654 } 00655 } 00656 00657 void stpi::setPortState(unsigned int i, tPortState state) { 00658 portTable.at(i).state = state; 00659 00660 switch (state) { 00661 case SDISABLED: 00662 case SDISCARDING: 00663 portTable.at(i).flags.Learning = false; 00664 portTable.at(i).flags.Forwarding = false; 00665 break; 00666 case SLEARNING: 00667 portTable.at(i).flags.Learning = true; 00668 portTable.at(i).flags.Forwarding = false; 00669 break; 00670 case SFORWARDING: 00671 portTable.at(i).flags.Learning = true; 00672 portTable.at(i).flags.Forwarding = true; 00673 break; 00674 default: 00675 break; 00676 } 00677 00678 } 00679