Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00028
00029
00030
00031
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
00051 char *line = new char[MAX_LINE];
00052 if (fgets(line,MAX_LINE,fp)==NULL)
00053 return NULL;
00054
00055
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
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
00072 addressTableSize = par("addressTableSize");
00073 addressTableSize = addressTableSize >= 0 ? addressTableSize : 0;
00074
00075 agingTime = par("agingTime");
00076 agingTime = agingTime > 0 ? agingTime : 10;
00077
00078
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
00091 updateTableWithAddress(frame->getSrc(), inputport);
00092
00093
00094 if (frame->getDest().isBroadcast())
00095 {
00096 EV << "Broadcasting broadcast frame " << frame << endl;
00097 broadcastFrame(frame, inputport);
00098 return;
00099 }
00100
00101
00102
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++;
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
00185 if (addressTableSize!=0 && addresstable.size() == (unsigned int)addressTableSize)
00186 {
00187
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
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
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
00218 return -1;
00219 }
00220 if (iter->second.insertionTime + agingTime <= simTime())
00221 {
00222
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
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 char *line;
00248 int lineno = 0;
00249 while ((line = fgetline(fp)) != NULL)
00250 {
00251 lineno++;
00252
00253
00254 if (line[0]=='#')
00255 continue;
00256
00257
00258 char *hexaddress = strtok(line, " \t");
00259
00260 char *portno = strtok(NULL, " \t");
00261
00262
00263 if (!hexaddress)
00264 continue;
00265
00266
00267 if (!portno)
00268 error("line %d invalid in address table file `%s'", lineno, fileName);
00269
00270
00271 AddressEntry entry;
00272 entry.insertionTime = 0;
00273 entry.portno = atoi(portno);
00274 addresstable[MACAddress(hexaddress)] = entry;
00275
00276
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
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