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