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