|
INET Framework for OMNeT++/OMNEST
|
00001 /* 00002 * Copyright (C) 2003 CTIE, Monash University 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 */ 00018 00019 #include <stdio.h> 00020 #include <string.h> 00021 #include <omnetpp.h> 00022 #include "AnsaEtherMAC.h" 00023 #include "Ieee802Ctrl_m.h" 00024 #include "IPassiveQueue.h" 00025 00026 00027 00028 static std::ostream& operator<< (std::ostream& out, cMessage *msg) 00029 { 00030 out << "(" << msg->getClassName() << ")" << msg->getFullName(); 00031 return out; 00032 } 00033 00034 00035 Define_Module( AnsaEtherMAC ); 00036 00037 AnsaEtherMAC::AnsaEtherMAC() 00038 { 00039 frameBeingReceived = NULL; 00040 endJammingMsg = endRxMsg = endBackoffMsg = NULL; 00041 } 00042 00043 AnsaEtherMAC::~AnsaEtherMAC() 00044 { 00045 delete frameBeingReceived; 00046 cancelAndDelete(endRxMsg); 00047 cancelAndDelete(endBackoffMsg); 00048 cancelAndDelete(endJammingMsg); 00049 } 00050 00051 void AnsaEtherMAC::initialize() 00052 { 00053 AnsaEtherMACBase::initialize(); 00054 00055 endRxMsg = new cMessage("EndReception", ENDRECEPTION); 00056 endBackoffMsg = new cMessage("EndBackoff", ENDBACKOFF); 00057 endJammingMsg = new cMessage("EndJamming", ENDJAMMING); 00058 00059 // check: datarate is forbidden with AnsaEtherMAC -- module's txrate must be used 00060 cGate *g = physOutGate; 00061 while (g) 00062 { 00063 cDatarateChannel *chan = dynamic_cast<cDatarateChannel*>(g->getChannel()); 00064 if (chan && chan->par("datarate").doubleValue()>0) 00065 error("connection on gate %s has data rate set: using data rate with AnsaEtherMAC " 00066 "is forbidden, module's txrate parameter must be used instead", 00067 g->getFullPath().c_str()); 00068 g = g->getNextGate(); 00069 } 00070 00071 // launch autoconfig process 00072 bool performAutoconfig = true; 00073 if (!disabled && connected && performAutoconfig) 00074 { 00075 startAutoconfig(); 00076 } 00077 else 00078 { 00079 autoconfigInProgress = false; 00080 duplexMode = par("duplexEnabled"); 00081 calculateParameters(); 00082 } 00083 WATCH(autoconfigInProgress); 00084 00085 // initialize state info 00086 backoffs = 0; 00087 numConcurrentTransmissions = 0; 00088 00089 WATCH(backoffs); 00090 WATCH(numConcurrentTransmissions); 00091 00092 // initialize statistics 00093 totalCollisionTime = 0.0; 00094 totalSuccessfulRxTxTime = 0.0; 00095 numCollisions = numBackoffs = 0; 00096 00097 WATCH(numCollisions); 00098 WATCH(numBackoffs); 00099 00100 numCollisionsVector.setName("collisions"); 00101 numBackoffsVector.setName("backoffs"); 00102 } 00103 00104 void AnsaEtherMAC::initializeTxrate() 00105 { 00106 txrate = par("txrate"); 00107 } 00108 00109 void AnsaEtherMAC::startAutoconfig() 00110 { 00111 autoconfigInProgress = true; 00112 lowestTxrateSuggested = 0; // none suggested 00113 duplexVetoed = false; 00114 00115 double initialTxrate = par("txrate"); 00116 bool duplexEnabled = par("duplexEnabled"); 00117 txrate = 0; 00118 duplexMode = duplexEnabled; 00119 if (!duplexEnabled || initialTxrate>0) 00120 { 00121 EV << "Autoconfig: advertising our settings: " << initialTxrate/1000000 << "Mb, " 00122 << (duplexMode ? "duplex" : "half-duplex") << endl; 00123 00124 EtherAutoconfig *autoconf = new EtherAutoconfig("autoconf"); 00125 if (!duplexEnabled) 00126 autoconf->setHalfDuplex(true); 00127 if (initialTxrate>0) 00128 autoconf->setTxrate(initialTxrate); 00129 send(autoconf, physOutGate); 00130 } 00131 scheduleAt(simTime()+AUTOCONFIG_PERIOD, new cMessage("EndAutoconfig",ENDAUTOCONFIG)); 00132 } 00133 00134 void AnsaEtherMAC::handleAutoconfigMessage(cMessage *msg) 00135 { 00136 if (!msg->isSelfMessage()) 00137 { 00138 if (msg->getArrivalGate() == gate("upperLayerIn")) 00139 { 00140 // from upper layer 00141 EV << "Received frame from upper layer during autoconfig period: " << msg << endl; 00142 processFrameFromUpperLayer(check_and_cast<EtherFrame *>(msg)); 00143 } 00144 else 00145 { 00146 // from network: must be autoconfig message 00147 EV << "Message from network during autoconfig period: " << msg << endl; 00148 EtherAutoconfig *autoconf = check_and_cast<EtherAutoconfig *>(msg); 00149 double acTxrate = autoconf->getTxrate(); 00150 00151 EV << "Autoconfig message: "; 00152 if (acTxrate>0) 00153 EV << acTxrate/1000000 << "Mb "; 00154 if (autoconf->getHalfDuplex()) 00155 EV << "non-duplex"; 00156 EV << "\n"; 00157 00158 if (acTxrate>0 && (acTxrate<lowestTxrateSuggested || lowestTxrateSuggested==0)) 00159 lowestTxrateSuggested = acTxrate; 00160 if (!duplexVetoed && autoconf->getHalfDuplex()) 00161 duplexVetoed = true; 00162 delete msg; 00163 } 00164 } 00165 else 00166 { 00167 // self-message signals end of autoconfig period 00168 EV << "Self-message during autoconfig period: " << msg << endl; 00169 00170 delete msg; 00171 autoconfigInProgress = false; 00172 00173 double initialTxrate = par("txrate"); 00174 bool duplexEnabled = par("duplexEnabled"); 00175 00176 txrate = (initialTxrate==0 && lowestTxrateSuggested==0) ? 100000000 /* 100 Mb */: 00177 (initialTxrate==0) ? lowestTxrateSuggested : 00178 (lowestTxrateSuggested==0) ? initialTxrate : 00179 (lowestTxrateSuggested<initialTxrate) ? lowestTxrateSuggested : initialTxrate; 00180 duplexMode = (duplexEnabled && !duplexVetoed); 00181 calculateParameters(); 00182 00183 EV << "Parameters after autoconfig: txrate=" << txrate/1000000 << "Mb, " << (duplexMode ? "duplex" : "half-duplex") << endl; 00184 00185 if (ev.isGUI()) 00186 { 00187 char modestr[64]; 00188 sprintf(modestr, "%dMb\n%s", int(txrate/1000000), (duplexMode ? "full duplex" : "half duplex")); 00189 getDisplayString().setTagArg("t",0,modestr); 00190 //getDisplayString().setTagArg("t",1,"r"); 00191 sprintf(modestr, "%s: %dMb %s", getFullName(), int(txrate/1000000), (duplexMode ? "duplex" : "half duplex")); 00192 getParentModule()->bubble(modestr); 00193 } 00194 00195 if (!txQueue.empty()) 00196 { 00197 EV << "Autoconfig period over, starting to send frames\n"; 00198 scheduleEndIFGPeriod(); 00199 } 00200 } 00201 } 00202 00203 void AnsaEtherMAC::handleMessage (cMessage *msg) 00204 { 00205 if (disabled) 00206 { 00207 EV << "MAC is disabled -- dropping message " << msg << "\n"; 00208 delete msg; 00209 return; 00210 } 00211 if (autoconfigInProgress) 00212 { 00213 handleAutoconfigMessage(msg); 00214 return; 00215 } 00216 00217 printState(); 00218 // some consistency check 00219 if (!duplexMode && transmitState==TRANSMITTING_STATE && receiveState!=RX_IDLE_STATE) 00220 error("Inconsistent state -- transmitting and receiving at the same time"); 00221 00222 if (!msg->isSelfMessage()) 00223 { 00224 // either frame from upper layer, or frame/jam signal from the network 00225 if (msg->getArrivalGate() == gate("upperLayerIn")) 00226 processFrameFromUpperLayer(check_and_cast<EtherFrame *>(msg)); 00227 else 00228 processMsgFromNetwork(PK(msg)); 00229 } 00230 else 00231 { 00232 // Process different self-messages (timer signals) 00233 EV << "Self-message " << msg << " received\n"; 00234 switch (msg->getKind()) 00235 { 00236 case ENDIFG: 00237 handleEndIFGPeriod(); 00238 break; 00239 00240 case ENDTRANSMISSION: 00241 handleEndTxPeriod(); 00242 break; 00243 00244 case ENDRECEPTION: 00245 handleEndRxPeriod(); 00246 break; 00247 00248 case ENDBACKOFF: 00249 handleEndBackoffPeriod(); 00250 break; 00251 00252 case ENDJAMMING: 00253 handleEndJammingPeriod(); 00254 break; 00255 00256 case ENDPAUSE: 00257 handleEndPausePeriod(); 00258 break; 00259 00260 default: 00261 error("self-message with unexpected message kind %d", msg->getKind()); 00262 } 00263 } 00264 printState(); 00265 00266 if (ev.isGUI()) 00267 updateDisplayString(); 00268 } 00269 00270 00271 void AnsaEtherMAC::processFrameFromUpperLayer(EtherFrame *frame) 00272 { 00273 AnsaEtherMACBase::processFrameFromUpperLayer(frame); 00274 00275 if (!autoconfigInProgress && (duplexMode || receiveState==RX_IDLE_STATE) && transmitState==TX_IDLE_STATE) 00276 { 00277 EV << "No incoming carrier signals detected, frame clear to send, wait IFG first\n"; 00278 scheduleEndIFGPeriod(); 00279 } 00280 } 00281 00282 00283 void AnsaEtherMAC::processMsgFromNetwork(cPacket *msg) 00284 { 00285 AnsaEtherMACBase::processMsgFromNetwork(msg); 00286 00287 simtime_t endRxTime = simTime() + msg->getBitLength()*bitTime; 00288 00289 if (!duplexMode && transmitState==TRANSMITTING_STATE) 00290 { 00291 // since we're halfduplex, receiveState must be RX_IDLE_STATE (asserted at top of handleMessage) 00292 if (dynamic_cast<EtherJam*>(msg) != NULL) 00293 error("Stray jam signal arrived while transmitting (usual cause is cable length exceeding allowed maximum)"); 00294 00295 EV << "Transmission interrupted by incoming frame, handling collision\n"; 00296 cancelEvent(endTxMsg); 00297 00298 EV << "Transmitting jam signal\n"; 00299 sendJamSignal(); // backoff will be executed when jamming finished 00300 00301 // set receive state and schedule end of reception 00302 receiveState = RX_COLLISION_STATE; 00303 numConcurrentTransmissions++; 00304 simtime_t endJamTime = simTime()+jamDuration; 00305 scheduleAt(endRxTime<endJamTime ? endJamTime : endRxTime, endRxMsg); 00306 delete msg; 00307 00308 numCollisions++; 00309 numCollisionsVector.record(numCollisions); 00310 } 00311 else if (receiveState==RX_IDLE_STATE) 00312 { 00313 if (dynamic_cast<EtherJam*>(msg) != NULL) 00314 error("Stray jam signal arrived (usual cause is cable length exceeding allowed maximum)"); 00315 00316 EV << "Start reception of frame\n"; 00317 numConcurrentTransmissions++; 00318 if (frameBeingReceived) 00319 error("frameBeingReceived!=0 in RX_IDLE_STATE"); 00320 frameBeingReceived = (EtherFrame *)msg; 00321 scheduleEndRxPeriod(msg); 00322 channelBusySince = simTime(); 00323 } 00324 else if (receiveState==RECEIVING_STATE && dynamic_cast<EtherJam*>(msg)==NULL && endRxMsg->getArrivalTime()-simTime()<bitTime) 00325 { 00326 // With the above condition we filter out "false" collisions that may occur with 00327 // back-to-back frames. That is: when "beginning of frame" message (this one) occurs 00328 // BEFORE "end of previous frame" event (endRxMsg) -- same simulation time, 00329 // only wrong order. 00330 00331 EV << "Back-to-back frames: completing reception of current frame, starting reception of next one\n"; 00332 00333 // complete reception of previous frame 00334 cancelEvent(endRxMsg); 00335 EtherFrame *frame = frameBeingReceived; 00336 frameBeingReceived = NULL; 00337 frameReceptionComplete(frame); 00338 00339 // start receiving next frame 00340 frameBeingReceived = (EtherFrame *)msg; 00341 scheduleEndRxPeriod(msg); 00342 } 00343 else // (receiveState==RECEIVING_STATE || receiveState==RX_COLLISION_STATE) 00344 { 00345 // handle overlapping receptions 00346 if (dynamic_cast<EtherJam*>(msg) != NULL) 00347 { 00348 if (numConcurrentTransmissions<=0) 00349 error("numConcurrentTransmissions=%d on jam arrival (stray jam?)",numConcurrentTransmissions); 00350 00351 numConcurrentTransmissions--; 00352 EV << "Jam signal received, this marks end of one transmission\n"; 00353 00354 // by the time jamming ends, all transmissions will have been aborted 00355 if (numConcurrentTransmissions==0) 00356 { 00357 EV << "Last jam signal received, collision will ends when jam ends\n"; 00358 cancelEvent(endRxMsg); 00359 scheduleAt(endRxTime, endRxMsg); 00360 } 00361 } 00362 else // EtherFrame or EtherPauseFrame 00363 { 00364 numConcurrentTransmissions++; 00365 if (endRxMsg->getArrivalTime() < endRxTime) 00366 { 00367 // otherwise just wait until the end of the longest transmission 00368 EV << "Overlapping receptions -- setting collision state and extending collision period\n"; 00369 cancelEvent(endRxMsg); 00370 scheduleAt(endRxTime, endRxMsg); 00371 } 00372 else 00373 { 00374 EV << "Overlapping receptions -- setting collision state\n"; 00375 } 00376 } 00377 00378 // delete collided frames: arrived frame as well as the one we're currently receiving 00379 delete msg; 00380 if (receiveState==RECEIVING_STATE) 00381 { 00382 delete frameBeingReceived; 00383 frameBeingReceived = NULL; 00384 00385 numCollisions++; 00386 numCollisionsVector.record(numCollisions); 00387 } 00388 00389 // go to collision state 00390 receiveState = RX_COLLISION_STATE; 00391 } 00392 } 00393 00394 00395 void AnsaEtherMAC::handleEndIFGPeriod() 00396 { 00397 AnsaEtherMACBase::handleEndIFGPeriod(); 00398 00399 // End of IFG period, okay to transmit, if Rx idle OR duplexMode 00400 cPacket *frame = (cPacket *)txQueue.front(); 00401 00402 // Perform carrier extension if in Gigabit Ethernet 00403 if (carrierExtension && frame->getByteLength() < GIGABIT_MIN_FRAME_WITH_EXT) 00404 { 00405 EV << "Performing carrier extension of small frame\n"; 00406 frame->setByteLength(GIGABIT_MIN_FRAME_WITH_EXT); 00407 } 00408 00409 // send frame to network 00410 startFrameTransmission(); 00411 } 00412 00413 void AnsaEtherMAC::startFrameTransmission() 00414 { 00415 cPacket *origFrame = (cPacket *)txQueue.front(); 00416 EV << "Transmitting a copy of frame " << origFrame << endl; 00417 cPacket *frame = origFrame->dup(); 00418 00419 // add preamble and SFD (Starting Frame Delimiter), then send out 00420 frame->addByteLength(PREAMBLE_BYTES+SFD_BYTES); 00421 if (ev.isGUI()) updateConnectionColor(TRANSMITTING_STATE); 00422 send(frame, physOutGate); 00423 00424 // update burst variables 00425 if (frameBursting) 00426 { 00427 bytesSentInBurst = frame->getByteLength(); 00428 framesSentInBurst++; 00429 } 00430 00431 // check for collisions (there might be an ongoing reception which we don't know about, see below) 00432 if (!duplexMode && receiveState!=RX_IDLE_STATE) 00433 { 00434 // During the IFG period the hardware cannot listen to the channel, 00435 // so it might happen that receptions have begun during the IFG, 00436 // and even collisions might be in progress. 00437 // 00438 // But we don't know of any ongoing transmission so we blindly 00439 // start transmitting, immediately collide and send a jam signal. 00440 // 00441 sendJamSignal(); 00442 // numConcurrentTransmissions stays the same: +1 transmission, -1 jam 00443 00444 if (receiveState==RECEIVING_STATE) 00445 { 00446 delete frameBeingReceived; 00447 frameBeingReceived = NULL; 00448 00449 numCollisions++; 00450 numCollisionsVector.record(numCollisions); 00451 } 00452 // go to collision state 00453 receiveState = RX_COLLISION_STATE; 00454 } 00455 else 00456 { 00457 // no collision 00458 scheduleEndTxPeriod(frame); 00459 00460 // only count transmissions in totalSuccessfulRxTxTime if channel is half-duplex 00461 if (!duplexMode) 00462 channelBusySince = simTime(); 00463 } 00464 } 00465 00466 void AnsaEtherMAC::handleEndTxPeriod() 00467 { 00468 AnsaEtherMACBase::handleEndTxPeriod(); 00469 00470 // only count transmissions in totalSuccessfulRxTxTime if channel is half-duplex 00471 if (!duplexMode) 00472 { 00473 simtime_t dt = simTime()-channelBusySince; 00474 totalSuccessfulRxTxTime += dt; 00475 } 00476 00477 backoffs = 0; 00478 00479 // check for and obey received PAUSE frames after each transmission 00480 if (checkAndScheduleEndPausePeriod()) 00481 return; 00482 00483 // Gigabit Ethernet: now decide if we transmit next frame right away (burst) or wait IFG 00484 // FIXME! this is not entirely correct, there must be IFG between burst frames too 00485 bool burstFrame=false; 00486 if (frameBursting && !txQueue.empty()) 00487 { 00488 // check if max bytes for burst not exceeded 00489 if (bytesSentInBurst<GIGABIT_MAX_BURST_BYTES) 00490 { 00491 burstFrame=true; 00492 EV << "Transmitting next frame in current burst\n"; 00493 } 00494 else 00495 { 00496 EV << "Next frame does not fit in current burst\n"; 00497 } 00498 } 00499 00500 if (burstFrame) 00501 startFrameTransmission(); 00502 else 00503 beginSendFrames(); 00504 } 00505 00506 void AnsaEtherMAC::handleEndRxPeriod() 00507 { 00508 EV << "Frame reception complete\n"; 00509 simtime_t dt = simTime()-channelBusySince; 00510 if (receiveState==RECEIVING_STATE) // i.e. not RX_COLLISION_STATE 00511 { 00512 EtherFrame *frame = frameBeingReceived; 00513 frameBeingReceived = NULL; 00514 frameReceptionComplete(frame); 00515 totalSuccessfulRxTxTime += dt; 00516 } 00517 else 00518 { 00519 totalCollisionTime += dt; 00520 } 00521 00522 receiveState = RX_IDLE_STATE; 00523 numConcurrentTransmissions = 0; 00524 00525 if (transmitState==TX_IDLE_STATE && !txQueue.empty()) 00526 { 00527 EV << "Receiver now idle, can transmit frames in output buffer after IFG period\n"; 00528 scheduleEndIFGPeriod(); 00529 } 00530 } 00531 00532 void AnsaEtherMAC::handleEndBackoffPeriod() 00533 { 00534 if (transmitState != BACKOFF_STATE) 00535 error("At end of BACKOFF not in BACKOFF_STATE!"); 00536 if (txQueue.empty()) 00537 error("At end of BACKOFF and buffer empty!"); 00538 00539 if (receiveState==RX_IDLE_STATE) 00540 { 00541 EV << "Backoff period ended, wait IFG\n"; 00542 scheduleEndIFGPeriod(); 00543 } 00544 else 00545 { 00546 EV << "Backoff period ended but channel not free, idling\n"; 00547 transmitState = TX_IDLE_STATE; 00548 } 00549 } 00550 00551 void AnsaEtherMAC::handleEndJammingPeriod() 00552 { 00553 if (transmitState != JAMMING_STATE) 00554 error("At end of JAMMING not in JAMMING_STATE!"); 00555 EV << "Jamming finished, executing backoff\n"; 00556 handleRetransmission(); 00557 } 00558 00559 void AnsaEtherMAC::sendJamSignal() 00560 { 00561 cPacket *jam = new EtherJam("JAM_SIGNAL"); 00562 jam->setByteLength(JAM_SIGNAL_BYTES); 00563 if (ev.isGUI()) updateConnectionColor(JAMMING_STATE); 00564 send(jam, physOutGate); 00565 00566 scheduleAt(simTime()+jamDuration, endJammingMsg); 00567 transmitState = JAMMING_STATE; 00568 } 00569 00570 void AnsaEtherMAC::scheduleEndRxPeriod(cPacket *frame) 00571 { 00572 scheduleAt(simTime()+frame->getBitLength()*bitTime, endRxMsg); 00573 receiveState = RECEIVING_STATE; 00574 } 00575 00576 void AnsaEtherMAC::handleRetransmission() 00577 { 00578 if (++backoffs > MAX_ATTEMPTS) 00579 { 00580 EV << "Number of retransmit attempts of frame exceeds maximum, cancelling transmission of frame\n"; 00581 delete txQueue.pop(); 00582 00583 transmitState = TX_IDLE_STATE; 00584 backoffs = 0; 00585 // no beginSendFrames(), because end of jam signal sending will trigger it automatically 00586 return; 00587 } 00588 00589 EV << "Executing backoff procedure\n"; 00590 int backoffrange = (backoffs>=BACKOFF_RANGE_LIMIT) ? 1024 : (1 << backoffs); 00591 int slotNumber = intuniform(0,backoffrange-1); 00592 simtime_t backofftime = slotNumber*slotTime; 00593 00594 scheduleAt(simTime()+backofftime, endBackoffMsg); 00595 transmitState = BACKOFF_STATE; 00596 00597 numBackoffs++; 00598 numBackoffsVector.record(numBackoffs); 00599 } 00600 00601 void AnsaEtherMAC::printState() 00602 { 00603 #define CASE(x) case x: EV << #x; break 00604 EV << "transmitState: "; 00605 switch (transmitState) { 00606 CASE(TX_IDLE_STATE); 00607 CASE(WAIT_IFG_STATE); 00608 CASE(TRANSMITTING_STATE); 00609 CASE(JAMMING_STATE); 00610 CASE(BACKOFF_STATE); 00611 CASE(PAUSE_STATE); 00612 } 00613 EV << ", receiveState: "; 00614 switch (receiveState) { 00615 CASE(RX_IDLE_STATE); 00616 CASE(RECEIVING_STATE); 00617 CASE(RX_COLLISION_STATE); 00618 } 00619 EV << ", backoffs: " << backoffs; 00620 EV << ", numConcurrentTransmissions: " << numConcurrentTransmissions; 00621 EV << ", queueLength: " << txQueue.length() << endl; 00622 #undef CASE 00623 } 00624 00625 void AnsaEtherMAC::finish() 00626 { 00627 AnsaEtherMACBase::finish(); 00628 00629 simtime_t t = simTime(); 00630 simtime_t totalChannelIdleTime = t - totalSuccessfulRxTxTime - totalCollisionTime; 00631 recordScalar("rx channel idle (%)", 100*(totalChannelIdleTime/t)); 00632 recordScalar("rx channel utilization (%)", 100*(totalSuccessfulRxTxTime/t)); 00633 recordScalar("rx channel collision (%)", 100*(totalCollisionTime/t)); 00634 recordScalar("collisions", numCollisions); 00635 recordScalar("backoffs", numBackoffs); 00636 } 00637 00638 void AnsaEtherMAC::updateHasSubcribers() 00639 { 00640 hasSubscribers = false; // currently we don't fire any notifications 00641 } 00642