Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

MACRelayUnitBase.cc

Go to the documentation of this file.
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 #ifdef _MSC_VER
00020 #pragma warning(disable:4786)
00021 #endif
00022 
00023 
00024 #include "MACRelayUnitBase.h"
00025 
00026 #include "MACAddress.h"
00027 #include "EtherFrame_m.h"
00028 #include "utils.h"
00029 #include "Ethernet.h"
00030 
00031 
00032 #ifndef OPP3
00033 static cEnvir& operator<< (cEnvir& ev, const MACAddress& addr)
00034 {
00035     char buf[20];
00036     ev << addr.toHexString(buf);
00037     return ev;
00038 }
00039 #endif
00040 
00041 static std::ostream& operator<< (std::ostream& ev, const MACAddress& addr)
00042 {
00043     char buf[20];
00044     ev << addr.toHexString(buf);
00045     return ev;
00046 }
00047 
00048 static cEnvir& operator<< (cEnvir& ev, cMessage *msg)
00049 {
00050     ev.printf("(%s)%s",msg->className(),msg->fullName());
00051     return ev;
00052 }
00053 
00054 
00055 void MACRelayUnitBase::initialize()
00056 {
00057     // number of ports
00058     numPorts = gate("lowerLayerOut",0)->size();
00059     if (gate("lowerLayerIn",0)->size()!=numPorts)
00060         error("the sizes of the lowerLayerIn[] and lowerLayerOut[] gate vectors must be the same");
00061 
00062     // other parameters
00063     addressTableSize = par("addressTableSize");
00064     addressTableSize = addressTableSize >= 0 ? addressTableSize : 0;
00065 
00066     agingTime = par("agingTime");
00067     agingTime = agingTime > 0 ? agingTime : 10;
00068 
00069     // Option to pre-read in Address Table. To turn ot off, set addressTableFile to empty string
00070     const char *addressTableFile = par("addressTableFile");
00071     if (addressTableFile && *addressTableFile)
00072         readAddressTable(addressTableFile);
00073 
00074     seqNum = 0;
00075 }
00076 
00077 void MACRelayUnitBase::handleAndDispatchFrame(EtherFrame *frame, int inputport)
00078 {
00079     // update address table
00080     updateTableWithAddress(frame->getSrc(), inputport);
00081 
00082     // handle broadcast frames first
00083     if (frame->getDest().isBroadcast())
00084     {
00085         EV << "Broadcasting broadcast frame " << frame << endl;
00086         broadcastFrame(frame, inputport);
00087         return;
00088     }
00089 
00090     // Finds output port of destination address and sends to output port
00091     // if not found then broadcasts to all other ports instead
00092     int outputport = getPortForAddress(frame->getDest());
00093     if (inputport==outputport)
00094     {
00095         EV << "Output port is same as input port, " << frame->fullName() << 
00096               " dest " << frame->getDest() << ", discarding frame\n";
00097         delete frame;
00098         return;
00099     }
00100     if (outputport>=0)
00101     {
00102         EV << "Sending frame " << frame << " with dest address " << frame->getDest() << " to port " << outputport << endl;
00103         send(frame, "lowerLayerOut", outputport);
00104     }
00105     else
00106     {
00107         EV << "Dest address " << frame->getDest() << " unknown, broadcasting frame " << frame << endl;
00108         broadcastFrame(frame, inputport);
00109     }
00110 }
00111 
00112 void MACRelayUnitBase::broadcastFrame(EtherFrame *frame, int inputport)
00113 {
00114     for (int i=0; i<numPorts; ++i)
00115         if (i!=inputport)
00116             send((EtherFrame*)frame->dup(), "lowerLayerOut", i);
00117     delete frame;
00118 }
00119 
00120 void MACRelayUnitBase::printAddressTable()
00121 {
00122     AddressTable::iterator iter;
00123     EV << "Address Table (" << addresstable.size() << " entries):\n";
00124     for (iter = addresstable.begin(); iter!=addresstable.end(); ++iter)
00125     {
00126         EV << "  " << iter->first << " --> port" << iter->second.portno <<
00127               (iter->second.insertionTime+agingTime <= simTime() ? " (aged)" : "") << endl;
00128     }
00129 }
00130 
00131 void MACRelayUnitBase::removeAgedEntriesFromTable()
00132 {
00133     for (AddressTable::iterator iter = addresstable.begin(); iter != addresstable.end();)
00134     {
00135         AddressTable::iterator cur = iter++; // iter will get invalidated after erase()
00136         AddressEntry& entry = cur->second;
00137         if (entry.insertionTime + agingTime <= simTime())
00138         {
00139             EV << "Removing aged entry from Address Table: " <<
00140                   cur->first << " --> port" << cur->second.portno << "\n";
00141             addresstable.erase(cur);
00142         }
00143     }
00144 }
00145 
00146 void MACRelayUnitBase::removeOldestTableEntry()
00147 {
00148     AddressTable::iterator oldest = addresstable.end();
00149     simtime_t oldestInsertTime = simTime()+1;
00150     for (AddressTable::iterator iter = addresstable.begin(); iter != addresstable.end(); iter++)
00151     {
00152         if (iter->second.insertionTime < oldestInsertTime)
00153         {
00154             oldest = iter;
00155             oldestInsertTime = iter->second.insertionTime;
00156         }
00157     }
00158     if (oldest != addresstable.end())
00159     {
00160         EV << "Table full, removing oldest entry: " <<
00161               oldest->first << " --> port" << oldest->second.portno << "\n";
00162         addresstable.erase(oldest);
00163     }
00164 }
00165 
00166 void MACRelayUnitBase::updateTableWithAddress(MACAddress& address, int portno)
00167 {
00168     AddressTable::iterator iter;
00169 
00170     iter = addresstable.find(address);
00171     if (iter == addresstable.end())
00172     {
00173         // Observe finite table size
00174         if (addressTableSize!=0 && addresstable.size() == (unsigned int)addressTableSize)
00175         {
00176             // lazy removal of aged entries: only if table gets full (this step is not strictly needed)
00177             EV << "Making room in Address Table by throwing out aged entries.\n";
00178             removeAgedEntriesFromTable();
00179 
00180             if (addresstable.size() == (unsigned int)addressTableSize)
00181                 removeOldestTableEntry();
00182         }
00183 
00184         // Add entry to table
00185         EV << "Adding entry to Address Table: "<< address << " --> port" << portno << "\n";
00186         AddressEntry entry;
00187         entry.portno = portno;
00188         entry.insertionTime = simTime();
00189         addresstable[address] = entry;
00190     }
00191     else
00192     {
00193         // Update existing entry
00194         EV << "Updating entry in Address Table: "<< address << " --> port" << portno << "\n";
00195         AddressEntry& entry = iter->second;
00196         entry.insertionTime = simTime();
00197         entry.portno = portno;
00198     }
00199 }
00200 
00201 int MACRelayUnitBase::getPortForAddress(MACAddress& address)
00202 {
00203     AddressTable::iterator iter = addresstable.find(address);
00204     if (iter == addresstable.end())
00205     {
00206         // not found
00207         return -1;
00208     }
00209     if (iter->second.insertionTime + agingTime <= simTime())
00210     {
00211         // don't use (and throw out) aged entries
00212         EV << "Ignoring and deleting aged entry: "<< iter->first << " --> port" << iter->second.portno << "\n";
00213         addresstable.erase(iter);
00214         return -1;
00215     }
00216     return iter->second.portno;
00217 }
00218 
00219 
00220 void MACRelayUnitBase::readAddressTable(const char* fileName)
00221 {
00222     FILE *fp = fopen(fileName, "r");
00223     if (fp == NULL)
00224         error("cannot open address table file `%s'", fileName);
00225 
00226     //  Syntax of the file goes as:
00227     //  Address in hexadecimal representation, Portno
00228     //  ffffffff    1
00229     //  ffffeed1    2
00230     //  aabcdeff    3
00231     //
00232     //  etc...
00233     //
00234     //  Each iteration of the loop reads in an entire line i.e. up to '\n' or EOF characters
00235     //  and uses strtok to extract tokens from the resulting string
00236     char *line;
00237     int lineno = 0;
00238     while ((line = fgetline(fp)) != NULL)
00239     {
00240         lineno++;
00241 
00242         // lines beginning with '#' are treated as comments
00243         if (line[0]=='#')
00244             continue;
00245 
00246         // scan in hexaddress
00247         char *hexaddress = strtok(line, " \t");
00248         // scan in port number
00249         char *portno = strtok(NULL, " \t");
00250 
00251         // empty line?
00252         if (!hexaddress)
00253             continue;
00254 
00255         // broken line?
00256         if (!portno)
00257             error("line %d invalid in address table file `%s'", lineno, fileName);
00258 
00259         // Create an entry with address and portno and insert into table
00260         AddressEntry entry;
00261         entry.insertionTime = 0;
00262         entry.portno = atoi(portno);
00263         addresstable[MACAddress(hexaddress)] = entry;
00264 
00265         // Garbage collection before next iteration
00266         delete [] line;
00267     }
00268     fclose(fp);
00269 }
00270 
00271 
00272 void MACRelayUnitBase::sendPauseFrame(int portno, int pauseUnits)
00273 {
00274     EV << "Creating and sending PAUSE frame on port " << portno << " with duration=" << pauseUnits << " units\n";
00275 
00276     // create Ethernet frame
00277     char framename[40];
00278     sprintf(framename, "pause-%d-%d", id(), seqNum++);
00279     EtherPauseFrame *frame = new EtherPauseFrame(framename, ETH_PAUSE);
00280     frame->setPauseTime(pauseUnits);
00281 
00282     frame->setLength(8*(ETHER_MAC_FRAME_BYTES+ETHER_PAUSE_COMMAND_BYTES));
00283     if (frame->length() < 8*MIN_ETHERNET_FRAME)
00284         frame->setLength(8*MIN_ETHERNET_FRAME);
00285 
00286     send(frame, "lowerLayerOut", portno);
00287 }
00288 

Generated on Sat May 15 20:30:43 2004 for Ethernet by doxygen1.2.17