MACRelayUnitNP.cc

Go to the documentation of this file.
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 }