|
INET Framework for OMNeT++/OMNEST
|
00001 /* 00002 * Copyright (C) 2003 Andras Varga; CTIE, Monash University, Australia 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public License 00015 * along with this program; if not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #include "MACRelayUnitNP.h" 00019 #include "EtherFrame_m.h" 00020 #include "Ethernet.h" 00021 #include "MACAddress.h" 00022 00023 00024 Define_Module( MACRelayUnitNP ); 00025 00026 00027 /* unused for now 00028 static std::ostream& operator<< (std::ostream& os, cMessage *msg) 00029 { 00030 os << "(" << msg->getClassName() << ")" << msg->getFullName(); 00031 return os; 00032 } 00033 */ 00034 00035 MACRelayUnitNP::MACRelayUnitNP() 00036 { 00037 endProcEvents = NULL; 00038 numCPUs = 0; 00039 } 00040 00041 MACRelayUnitNP::~MACRelayUnitNP() 00042 { 00043 for (int i=0; i<numCPUs; i++) 00044 { 00045 cMessage *endProcEvent = endProcEvents[i]; 00046 EtherFrame *etherFrame = (EtherFrame *)endProcEvent->getContextPointer(); 00047 if (etherFrame) 00048 { 00049 endProcEvent->setContextPointer(NULL); 00050 delete etherFrame; 00051 } 00052 cancelAndDelete(endProcEvent); 00053 } 00054 delete [] endProcEvents; 00055 } 00056 00057 void MACRelayUnitNP::initialize() 00058 { 00059 MACRelayUnitBase::initialize(); 00060 00061 bufferLevel.setName("buffer level"); 00062 queue.setName("queue"); 00063 00064 numProcessedFrames = numDroppedFrames = 0; 00065 WATCH(numProcessedFrames); 00066 WATCH(numDroppedFrames); 00067 00068 numCPUs = par("numCPUs"); 00069 00070 processingTime = par("processingTime"); 00071 bufferSize = par("bufferSize"); 00072 highWatermark = par("highWatermark"); 00073 pauseUnits = par("pauseUnits"); 00074 00075 // 1 pause unit is 512 bit times; we assume 100Mb MACs here. 00076 // We send a pause again when previous one is about to expire. 00077 pauseInterval = pauseUnits*512.0/100000.0; 00078 00079 pauseLastSent = 0; 00080 WATCH(pauseLastSent); 00081 00082 bufferUsed = 0; 00083 WATCH(bufferUsed); 00084 00085 endProcEvents = new cMessage *[numCPUs]; 00086 for (int i=0; i<numCPUs; i++) 00087 { 00088 char msgname[20]; 00089 sprintf(msgname, "endProcessing-cpu%d", i); 00090 endProcEvents[i] = new cMessage(msgname,i); 00091 } 00092 00093 EV << "Parameters of (" << getClassName() << ") " << getFullPath() << "\n"; 00094 EV << "number of processors: " << numCPUs << "\n"; 00095 EV << "processing time: " << processingTime << "\n"; 00096 EV << "ports: " << numPorts << "\n"; 00097 EV << "buffer size: " << bufferSize << "\n"; 00098 EV << "address table size: " << addressTableSize << "\n"; 00099 EV << "aging time: " << agingTime << "\n"; 00100 EV << "high watermark: " << highWatermark << "\n"; 00101 EV << "pause time: " << pauseUnits << "\n"; 00102 EV << "\n"; 00103 } 00104 00105 void MACRelayUnitNP::handleMessage(cMessage *msg) 00106 { 00107 if (!msg->isSelfMessage()) 00108 { 00109 // Frame received from MAC unit 00110 handleIncomingFrame(check_and_cast<EtherFrame *>(msg)); 00111 } 00112 else 00113 { 00114 // Self message signal used to indicate a frame has finished processing 00115 processFrame(msg); 00116 } 00117 } 00118 00119 void MACRelayUnitNP::handleIncomingFrame(EtherFrame *frame) 00120 { 00121 // If buffer not full, insert payload frame into buffer and process the frame in parallel. 00122 00123 long length = frame->getByteLength(); 00124 if (length + bufferUsed < bufferSize) 00125 { 00126 bufferUsed += length; 00127 00128 // send PAUSE if above watermark 00129 if (pauseUnits>0 && highWatermark>0 && bufferUsed>=highWatermark && simTime()-pauseLastSent>pauseInterval) 00130 { 00131 // send PAUSE on all ports 00132 for (int i=0; i<numPorts; i++) 00133 sendPauseFrame(i, pauseUnits); 00134 pauseLastSent = simTime(); 00135 } 00136 00137 // assign frame to a free CPU (if there is one) 00138 int i; 00139 for (i=0; i<numCPUs; i++) 00140 if (!endProcEvents[i]->isScheduled()) 00141 break; 00142 if (i==numCPUs) 00143 { 00144 EV << "All CPUs busy, enqueueing incoming frame " << frame << " for later processing\n"; 00145 queue.insert(frame); 00146 } 00147 else 00148 { 00149 EV << "Idle CPU-" << i << " starting processing of incoming frame " << frame << endl; 00150 cMessage *msg = endProcEvents[i]; 00151 ASSERT(msg->getContextPointer()==NULL); 00152 msg->setContextPointer(frame); 00153 scheduleAt(simTime() + processingTime, msg); 00154 } 00155 } 00156 // Drop the frame and record the number of dropped frames 00157 else 00158 { 00159 EV << "Buffer full, dropping frame " << frame << endl; 00160 delete frame; 00161 ++numDroppedFrames; 00162 } 00163 00164 // Record statistics of buffer usage levels 00165 bufferLevel.record(bufferUsed); 00166 } 00167 00168 void MACRelayUnitNP::processFrame(cMessage *msg) 00169 { 00170 int cpu = msg->getKind(); 00171 EtherFrame *frame = (EtherFrame *) msg->getContextPointer(); 00172 ASSERT(frame); 00173 msg->setContextPointer(NULL); 00174 long length = frame->getByteLength(); 00175 int inputport = frame->getArrivalGate()->getIndex(); 00176 00177 EV << "CPU-" << cpu << " completed processing of frame " << frame << endl; 00178 00179 handleAndDispatchFrame(frame, inputport); 00180 printAddressTable(); 00181 00182 bufferUsed -= length; 00183 bufferLevel.record(bufferUsed); 00184 00185 numProcessedFrames++; 00186 00187 // Process next frame in queue if they are pending 00188 if (!queue.empty()) 00189 { 00190 EtherFrame *newframe = (EtherFrame *) queue.pop(); 00191 msg->setContextPointer(newframe); 00192 EV << "CPU-" << cpu << " starting processing of frame " << newframe << endl; 00193 scheduleAt(simTime()+processingTime, msg); 00194 } 00195 else 00196 { 00197 EV << "CPU-" << cpu << " idle\n"; 00198 } 00199 } 00200 00201 void MACRelayUnitNP::finish() 00202 { 00203 recordScalar("processed frames", numProcessedFrames); 00204 recordScalar("dropped frames", numDroppedFrames); 00205 }