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