00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00063 addressTableSize = par("addressTableSize");
00064 addressTableSize = addressTableSize >= 0 ? addressTableSize : 0;
00065
00066 agingTime = par("agingTime");
00067 agingTime = agingTime > 0 ? agingTime : 10;
00068
00069
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
00080 updateTableWithAddress(frame->getSrc(), inputport);
00081
00082
00083 if (frame->getDest().isBroadcast())
00084 {
00085 EV << "Broadcasting broadcast frame " << frame << endl;
00086 broadcastFrame(frame, inputport);
00087 return;
00088 }
00089
00090
00091
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++;
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
00174 if (addressTableSize!=0 && addresstable.size() == (unsigned int)addressTableSize)
00175 {
00176
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
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
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
00207 return -1;
00208 }
00209 if (iter->second.insertionTime + agingTime <= simTime())
00210 {
00211
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
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 char *line;
00237 int lineno = 0;
00238 while ((line = fgetline(fp)) != NULL)
00239 {
00240 lineno++;
00241
00242
00243 if (line[0]=='#')
00244 continue;
00245
00246
00247 char *hexaddress = strtok(line, " \t");
00248
00249 char *portno = strtok(NULL, " \t");
00250
00251
00252 if (!hexaddress)
00253 continue;
00254
00255
00256 if (!portno)
00257 error("line %d invalid in address table file `%s'", lineno, fileName);
00258
00259
00260 AddressEntry entry;
00261 entry.insertionTime = 0;
00262 entry.portno = atoi(portno);
00263 addresstable[MACAddress(hexaddress)] = entry;
00264
00265
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
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