#include <ARP.h>
Public Types | |
typedef std::map< IPAddress, ARPCacheEntry * > | ARPCache |
typedef std::vector< cMessage * > | MsgPtrVector |
Public Member Functions | |
ARP () | |
virtual | ~ARP () |
Protected Member Functions | |
virtual void | initialize () |
virtual void | handleMessage (cMessage *msg) |
virtual void | finish () |
virtual void | processOutboundPacket (cMessage *msg) |
virtual void | sendPacketToNIC (cMessage *msg, InterfaceEntry *ie, const MACAddress &macAddress) |
virtual void | initiateARPResolution (ARPCacheEntry *entry) |
virtual void | sendARPRequest (InterfaceEntry *ie, IPAddress ipAddress) |
virtual void | requestTimedOut (cMessage *selfmsg) |
virtual bool | addressRecognized (IPAddress destAddr, InterfaceEntry *ie) |
virtual void | processARPPacket (ARPPacket *arp) |
virtual void | updateARPCache (ARPCacheEntry *entry, const MACAddress &macAddress) |
virtual void | dumpARPPacket (ARPPacket *arp) |
virtual void | updateDisplayString () |
Protected Attributes | |
simtime_t | retryTimeout |
int | retryCount |
simtime_t | cacheTimeout |
bool | doProxyARP |
long | numResolutions |
long | numFailedResolutions |
long | numRequestsSent |
long | numRepliesSent |
ARPCache | arpCache |
cQueue | pendingQueue |
int | nicOutBaseGateId |
IInterfaceTable * | ift |
IRoutingTable * | rt |
Classes | |
struct | ARPCacheEntry |
typedef std::map<IPAddress, ARPCacheEntry*> ARP::ARPCache |
typedef std::vector<cMessage*> ARP::MsgPtrVector |
ARP::~ARP | ( | ) | [virtual] |
void ARP::initialize | ( | ) | [protected, virtual] |
00043 { 00044 ift = InterfaceTableAccess().get(); 00045 rt = RoutingTableAccess().get(); 00046 00047 nicOutBaseGateId = gateSize("nicOut")==0 ? -1 : gate("nicOut",0)->getId(); 00048 00049 retryTimeout = par("retryTimeout"); 00050 retryCount = par("retryCount"); 00051 cacheTimeout = par("cacheTimeout"); 00052 doProxyARP = par("proxyARP"); 00053 00054 pendingQueue.setName("pendingQueue"); 00055 00056 // init statistics 00057 numRequestsSent = numRepliesSent = 0; 00058 numResolutions = numFailedResolutions = 0; 00059 WATCH(numRequestsSent); 00060 WATCH(numRepliesSent); 00061 WATCH(numResolutions); 00062 WATCH(numFailedResolutions); 00063 00064 WATCH_PTRMAP(arpCache); 00065 }
void ARP::handleMessage | ( | cMessage * | msg | ) | [protected, virtual] |
00086 { 00087 if (msg->isSelfMessage()) 00088 { 00089 requestTimedOut(msg); 00090 } 00091 else if (dynamic_cast<ARPPacket *>(msg)) 00092 { 00093 ARPPacket *arp = (ARPPacket *)msg; 00094 processARPPacket(arp); 00095 } 00096 else // not ARP 00097 { 00098 processOutboundPacket(msg); 00099 } 00100 if (ev.isGUI()) 00101 updateDisplayString(); 00102 }
void ARP::finish | ( | ) | [protected, virtual] |
00068 { 00069 recordScalar("ARP requests sent", numRequestsSent); 00070 recordScalar("ARP replies sent", numRepliesSent); 00071 recordScalar("ARP resolutions", numResolutions); 00072 recordScalar("failed ARP resolutions", numFailedResolutions); 00073 }
void ARP::processOutboundPacket | ( | cMessage * | msg | ) | [protected, virtual] |
Referenced by handleMessage().
00113 { 00114 EV << "Packet " << msg << " arrived from higher layer, "; 00115 00116 // get next hop address from control info in packet 00117 IPRoutingDecision *controlInfo = check_and_cast<IPRoutingDecision*>(msg->removeControlInfo()); 00118 IPAddress nextHopAddr = controlInfo->getNextHopAddr(); 00119 InterfaceEntry *ie = ift->getInterfaceById(controlInfo->getInterfaceId()); 00120 delete controlInfo; 00121 00122 // if output interface is not broadcast, don't bother with ARP 00123 if (!ie->isBroadcast()) 00124 { 00125 EV << "output interface " << ie->getName() << " is not broadcast, skipping ARP\n"; 00126 sendDirect(msg, getParentModule(), "ifOut", ie->getNetworkLayerGateIndex()); 00127 return; 00128 } 00129 00130 // determine what address to look up in ARP cache 00131 if (!nextHopAddr.isUnspecified()) 00132 { 00133 EV << "using next-hop address " << nextHopAddr << "\n"; 00134 } 00135 else 00136 { 00137 // try proxy ARP 00138 IPDatagram *datagram = check_and_cast<IPDatagram *>(msg); 00139 nextHopAddr = datagram->getDestAddress(); 00140 EV << "no next-hop address, using destination address " << nextHopAddr << " (proxy ARP)\n"; 00141 } 00142 00143 // 00144 // Handle multicast IP addresses. RFC 1112, section 6.4 says: 00145 // "An IP host group address is mapped to an Ethernet multicast address 00146 // by placing the low-order 23 bits of the IP address into the low-order 00147 // 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex). 00148 // Because there are 28 significant bits in an IP host group address, 00149 // more than one host group address may map to the same Ethernet multicast 00150 // address." 00151 // 00152 if (nextHopAddr.isMulticast()) 00153 { 00154 // FIXME: we do a simpler solution right now: send to the Broadcast MAC address 00155 EV << "destination address is multicast, sending packet to broadcast MAC address\n"; 00156 static MACAddress broadcastAddr("FF:FF:FF:FF:FF:FF"); 00157 sendPacketToNIC(msg, ie, broadcastAddr); 00158 return; 00159 #if 0 00160 // experimental RFC 1112 code 00161 // TBD needs counterpart to be implemented in EtherMAC processReceivedDataFrame(). 00162 unsigned char macBytes[6]; 00163 macBytes[0] = 0x01; 00164 macBytes[1] = 0x00; 00165 macBytes[2] = 0x5e; 00166 macBytes[3] = nextHopAddr.getDByte(1) & 0x7f; 00167 macBytes[4] = nextHopAddr.getDByte(2); 00168 macBytes[5] = nextHopAddr.getDByte(3); 00169 MACAddress multicastMacAddr; 00170 multicastMacAddr.setAddressBytes(bytes); 00171 sendPacketToNIC(msg, ie, multicastMacAddr); 00172 return; 00173 #endif 00174 } 00175 00176 // try look up 00177 ARPCache::iterator it = arpCache.find(nextHopAddr); 00178 //ASSERT(it==arpCache.end() || ie==(*it).second->ie); // verify: if arpCache gets keyed on InterfaceEntry* too, this becomes unnecessary 00179 if (it==arpCache.end()) 00180 { 00181 // no cache entry: launch ARP request 00182 ARPCacheEntry *entry = new ARPCacheEntry(); 00183 ARPCache::iterator where = arpCache.insert(arpCache.begin(), std::make_pair(nextHopAddr,entry)); 00184 entry->myIter = where; // note: "inserting a new element into a map does not invalidate iterators that point to existing elements" 00185 entry->ie = ie; 00186 00187 EV << "Starting ARP resolution for " << nextHopAddr << "\n"; 00188 initiateARPResolution(entry); 00189 00190 // and queue up packet 00191 entry->pendingPackets.push_back(msg); 00192 pendingQueue.insert(msg); 00193 } 00194 else if ((*it).second->pending) 00195 { 00196 // an ARP request is already pending for this address -- just queue up packet 00197 EV << "ARP resolution for " << nextHopAddr << " is pending, queueing up packet\n"; 00198 (*it).second->pendingPackets.push_back(msg); 00199 pendingQueue.insert(msg); 00200 } 00201 else if ((*it).second->lastUpdate+cacheTimeout<simTime()) 00202 { 00203 EV << "ARP cache entry for " << nextHopAddr << " expired, starting new ARP resolution\n"; 00204 00205 // cache entry stale, send new ARP request 00206 ARPCacheEntry *entry = (*it).second; 00207 entry->ie = ie; // routing table may have changed 00208 initiateARPResolution(entry); 00209 00210 // and queue up packet 00211 entry->pendingPackets.push_back(msg); 00212 pendingQueue.insert(msg); 00213 } 00214 else 00215 { 00216 // valid ARP cache entry found, flag msg with MAC address and send it out 00217 EV << "ARP cache hit, MAC address for " << nextHopAddr << " is " << (*it).second->macAddress << ", sending packet down\n"; 00218 sendPacketToNIC(msg, ie, (*it).second->macAddress); 00219 } 00220 }
void ARP::sendPacketToNIC | ( | cMessage * | msg, | |
InterfaceEntry * | ie, | |||
const MACAddress & | macAddress | |||
) | [protected, virtual] |
Referenced by processARPPacket(), processOutboundPacket(), sendARPRequest(), and updateARPCache().
00239 { 00240 // add control info with MAC address 00241 Ieee802Ctrl *controlInfo = new Ieee802Ctrl(); 00242 controlInfo->setDest(macAddress); 00243 msg->setControlInfo(controlInfo); 00244 00245 // send out 00246 //send(msg, nicOutBaseGateId + ie->getNetworkLayerGateIndex()); 00247 sendDirect(msg, getParentModule(), "ifOut", 00248 ie->getNetworkLayerGateIndex()); 00249 }
void ARP::initiateARPResolution | ( | ARPCacheEntry * | entry | ) | [protected, virtual] |
Referenced by processOutboundPacket().
00223 { 00224 IPAddress nextHopAddr = entry->myIter->first; 00225 entry->pending = true; 00226 entry->numRetries = 0; 00227 entry->lastUpdate = 0; 00228 sendARPRequest(entry->ie, nextHopAddr); 00229 00230 // start timer 00231 cMessage *msg = entry->timer = new cMessage("ARP timeout"); 00232 msg->setContextPointer(entry); 00233 scheduleAt(simTime()+retryTimeout, msg); 00234 00235 numResolutions++; 00236 }
void ARP::sendARPRequest | ( | InterfaceEntry * | ie, | |
IPAddress | ipAddress | |||
) | [protected, virtual] |
Referenced by initiateARPResolution(), and requestTimedOut().
00252 { 00253 // find our own IP address and MAC address on the given interface 00254 MACAddress myMACAddress = ie->getMacAddress(); 00255 IPAddress myIPAddress = ie->ipv4Data()->getIPAddress(); 00256 00257 // both must be set 00258 ASSERT(!myMACAddress.isUnspecified()); 00259 ASSERT(!myIPAddress.isUnspecified()); 00260 00261 // fill out everything in ARP Request packet except dest MAC address 00262 ARPPacket *arp = new ARPPacket("arpREQ"); 00263 arp->setByteLength(ARP_HEADER_BYTES); 00264 arp->setOpcode(ARP_REQUEST); 00265 arp->setSrcMACAddress(myMACAddress); 00266 arp->setSrcIPAddress(myIPAddress); 00267 arp->setDestIPAddress(ipAddress); 00268 00269 static MACAddress broadcastAddress("ff:ff:ff:ff:ff:ff"); 00270 sendPacketToNIC(arp, ie, broadcastAddress); 00271 numRequestsSent++; 00272 }
void ARP::requestTimedOut | ( | cMessage * | selfmsg | ) | [protected, virtual] |
Referenced by handleMessage().
00275 { 00276 ARPCacheEntry *entry = (ARPCacheEntry *)selfmsg->getContextPointer(); 00277 entry->numRetries++; 00278 if (entry->numRetries < retryCount) 00279 { 00280 // retry 00281 IPAddress nextHopAddr = entry->myIter->first; 00282 EV << "ARP request for " << nextHopAddr << " timed out, resending\n"; 00283 sendARPRequest(entry->ie, nextHopAddr); 00284 scheduleAt(simTime()+retryTimeout, selfmsg); 00285 return; 00286 } 00287 00288 // max retry count reached: ARP failure. 00289 // throw out entry from cache, delete pending messages 00290 MsgPtrVector& pendingPackets = entry->pendingPackets; 00291 EV << "ARP timeout, max retry count " << retryCount << " for " 00292 << entry->myIter->first << " reached. Dropping " << pendingPackets.size() 00293 << " waiting packets from the queue\n"; 00294 while (!pendingPackets.empty()) 00295 { 00296 MsgPtrVector::iterator i = pendingPackets.begin(); 00297 cMessage *msg = (*i); 00298 pendingPackets.erase(i); 00299 pendingQueue.remove(msg); 00300 delete msg; 00301 } 00302 delete selfmsg; 00303 arpCache.erase(entry->myIter); 00304 delete entry; 00305 numFailedResolutions++; 00306 }
bool ARP::addressRecognized | ( | IPAddress | destAddr, | |
InterfaceEntry * | ie | |||
) | [protected, virtual] |
Referenced by processARPPacket().
00310 { 00311 if (rt->isLocalAddress(destAddr)) 00312 return true; 00313 00314 // respond to Proxy ARP request: if we can route this packet (and the 00315 // output port is different from this one), say yes 00316 if (!doProxyARP) 00317 return false; 00318 InterfaceEntry *rtie = rt->getInterfaceForDestAddr(destAddr); 00319 return rtie!=NULL && rtie!=ie; 00320 }
void ARP::processARPPacket | ( | ARPPacket * | arp | ) | [protected, virtual] |
Referenced by handleMessage().
00331 { 00332 EV << "ARP packet " << arp << " arrived:\n"; 00333 dumpARPPacket(arp); 00334 00335 // extract input port 00336 IPRoutingDecision *controlInfo = check_and_cast<IPRoutingDecision*>(arp->removeControlInfo()); 00337 InterfaceEntry *ie = ift->getInterfaceById(controlInfo->getInterfaceId()); 00338 delete controlInfo; 00339 00340 // 00341 // Recipe a'la RFC 826: 00342 // 00343 // ?Do I have the hardware type in ar$hrd? 00344 // Yes: (almost definitely) 00345 // [optionally check the hardware length ar$hln] 00346 // ?Do I speak the protocol in ar$pro? 00347 // Yes: 00348 // [optionally check the protocol length ar$pln] 00349 // Merge_flag := false 00350 // If the pair <protocol type, sender protocol address> is 00351 // already in my translation table, update the sender 00352 // hardware address field of the entry with the new 00353 // information in the packet and set Merge_flag to true. 00354 // ?Am I the target protocol address? 00355 // Yes: 00356 // If Merge_flag is false, add the triplet <protocol type, 00357 // sender protocol address, sender hardware address> to 00358 // the translation table. 00359 // ?Is the opcode ares_op$REQUEST? (NOW look at the opcode!!) 00360 // Yes: 00361 // Swap hardware and protocol fields, putting the local 00362 // hardware and protocol addresses in the sender fields. 00363 // Set the ar$op field to ares_op$REPLY 00364 // Send the packet to the (new) target hardware address on 00365 // the same hardware on which the request was received. 00366 // 00367 00368 MACAddress srcMACAddress = arp->getSrcMACAddress(); 00369 IPAddress srcIPAddress = arp->getSrcIPAddress(); 00370 00371 if (srcMACAddress.isUnspecified()) 00372 error("wrong ARP packet: source MAC address is empty"); 00373 if (srcIPAddress.isUnspecified()) 00374 error("wrong ARP packet: source IP address is empty"); 00375 00376 bool mergeFlag = false; 00377 // "If ... sender protocol address is already in my translation table" 00378 ARPCache::iterator it = arpCache.find(srcIPAddress); 00379 if (it!=arpCache.end()) 00380 { 00381 // "update the sender hardware address field" 00382 ARPCacheEntry *entry = (*it).second; 00383 updateARPCache(entry, srcMACAddress); 00384 mergeFlag = true; 00385 } 00386 00387 // "?Am I the target protocol address?" 00388 // if Proxy ARP is enabled, we also have to reply if we're a router to the dest IP address 00389 if (addressRecognized(arp->getDestIPAddress(), ie)) 00390 { 00391 // "If Merge_flag is false, add the triplet protocol type, sender 00392 // protocol address, sender hardware address to the translation table" 00393 if (!mergeFlag) 00394 { 00395 ARPCacheEntry *entry; 00396 if (it!=arpCache.end()) 00397 { 00398 entry = (*it).second; 00399 } 00400 else 00401 { 00402 entry = new ARPCacheEntry(); 00403 ARPCache::iterator where = arpCache.insert(arpCache.begin(), std::make_pair(srcIPAddress,entry)); 00404 entry->myIter = where; 00405 entry->ie = ie; 00406 00407 entry->pending = false; 00408 entry->timer = NULL; 00409 entry->numRetries = 0; 00410 } 00411 updateARPCache(entry, srcMACAddress); 00412 } 00413 00414 // "?Is the opcode ares_op$REQUEST? (NOW look at the opcode!!)" 00415 switch (arp->getOpcode()) 00416 { 00417 case ARP_REQUEST: 00418 { 00419 EV << "Packet was ARP REQUEST, sending REPLY\n"; 00420 00421 // find our own IP address and MAC address on the given interface 00422 MACAddress myMACAddress = ie->getMacAddress(); 00423 IPAddress myIPAddress = ie->ipv4Data()->getIPAddress(); 00424 00425 // "Swap hardware and protocol fields", etc. 00426 arp->setName("arpREPLY"); 00427 IPAddress origDestAddress = arp->getDestIPAddress(); 00428 arp->setDestIPAddress(srcIPAddress); 00429 arp->setDestMACAddress(srcMACAddress); 00430 arp->setSrcIPAddress(origDestAddress); 00431 arp->setSrcMACAddress(myMACAddress); 00432 arp->setOpcode(ARP_REPLY); 00433 delete arp->removeControlInfo(); 00434 sendPacketToNIC(arp, ie, srcMACAddress); 00435 numRepliesSent++; 00436 break; 00437 } 00438 case ARP_REPLY: 00439 { 00440 EV << "Discarding packet\n"; 00441 delete arp; 00442 break; 00443 } 00444 case ARP_RARP_REQUEST: error("RARP request received: RARP is not supported"); 00445 case ARP_RARP_REPLY: error("RARP reply received: RARP is not supported"); 00446 default: error("Unsupported opcode %d in received ARP packet",arp->getOpcode()); 00447 } 00448 } 00449 else 00450 { 00451 // address not recognized 00452 EV << "IP address " << arp->getDestIPAddress() << " not recognized, dropping ARP packet\n"; 00453 delete arp; 00454 } 00455 }
void ARP::updateARPCache | ( | ARPCacheEntry * | entry, | |
const MACAddress & | macAddress | |||
) | [protected, virtual] |
Referenced by processARPPacket().
00458 { 00459 EV << "Updating ARP cache entry: " << entry->myIter->first << " <--> " << macAddress << "\n"; 00460 00461 // update entry 00462 if (entry->pending) 00463 { 00464 entry->pending = false; 00465 delete cancelEvent(entry->timer); 00466 entry->timer = NULL; 00467 entry->numRetries = 0; 00468 } 00469 entry->macAddress = macAddress; 00470 entry->lastUpdate = simTime(); 00471 00472 // process queued packets 00473 MsgPtrVector& pendingPackets = entry->pendingPackets; 00474 while (!pendingPackets.empty()) 00475 { 00476 MsgPtrVector::iterator i = pendingPackets.begin(); 00477 cMessage *msg = (*i); 00478 pendingPackets.erase(i); 00479 pendingQueue.remove(msg); 00480 EV << "Sending out queued packet " << msg << "\n"; 00481 sendPacketToNIC(msg, entry->ie, macAddress); 00482 } 00483 }
void ARP::dumpARPPacket | ( | ARPPacket * | arp | ) | [protected, virtual] |
Referenced by processARPPacket().
00323 { 00324 EV << (arp->getOpcode()==ARP_REQUEST ? "ARP_REQ" : arp->getOpcode()==ARP_REPLY ? "ARP_REPLY" : "unknown type") 00325 << " src=" << arp->getSrcIPAddress() << " / " << arp->getSrcMACAddress() 00326 << " dest=" << arp->getDestIPAddress() << " / " << arp->getDestMACAddress() << "\n"; 00327 }
void ARP::updateDisplayString | ( | ) | [protected, virtual] |
Referenced by handleMessage().
00105 { 00106 char buf[80]; 00107 sprintf(buf, "%d cache entries\nsent req:%ld repl:%ld fail:%ld", 00108 arpCache.size(), numRequestsSent, numRepliesSent, numFailedResolutions); 00109 getDisplayString().setTagArg("t",0,buf); 00110 }
simtime_t ARP::retryTimeout [protected] |
Referenced by initialize(), initiateARPResolution(), and requestTimedOut().
int ARP::retryCount [protected] |
Referenced by initialize(), and requestTimedOut().
simtime_t ARP::cacheTimeout [protected] |
Referenced by initialize(), and processOutboundPacket().
bool ARP::doProxyARP [protected] |
Referenced by addressRecognized(), and initialize().
long ARP::numResolutions [protected] |
Referenced by finish(), initialize(), and initiateARPResolution().
long ARP::numFailedResolutions [protected] |
Referenced by finish(), initialize(), requestTimedOut(), and updateDisplayString().
long ARP::numRequestsSent [protected] |
Referenced by finish(), initialize(), sendARPRequest(), and updateDisplayString().
long ARP::numRepliesSent [protected] |
Referenced by finish(), initialize(), processARPPacket(), and updateDisplayString().
ARPCache ARP::arpCache [protected] |
Referenced by initialize(), processARPPacket(), processOutboundPacket(), requestTimedOut(), updateDisplayString(), and ~ARP().
cQueue ARP::pendingQueue [protected] |
Referenced by initialize(), processOutboundPacket(), requestTimedOut(), and updateARPCache().
int ARP::nicOutBaseGateId [protected] |
Referenced by initialize().
IInterfaceTable* ARP::ift [protected] |
Referenced by initialize(), processARPPacket(), and processOutboundPacket().
IRoutingTable* ARP::rt [protected] |
Referenced by addressRecognized(), and initialize().