Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ARP Class Reference

#include <ARP.h>

List of all members.


Detailed Description

ARP implementation.


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
InterfaceTableift
RoutingTablert

Classes

struct  ARPCacheEntry


Member Typedef Documentation

typedef std::vector<cMessage*> ARP::MsgPtrVector
 


Constructor & Destructor Documentation

ARP::ARP  )  [inline]
 

00086 {}

ARP::~ARP  ) 
 

00075 {
00076     while (!arpCache.empty())
00077     {
00078         ARPCache::iterator i = arpCache.begin();
00079         delete (*i).second;
00080         arpCache.erase(i);
00081     }
00082 }


Member Function Documentation

bool ARP::addressRecognized IPAddress  destAddr,
InterfaceEntry ie
[protected]
 

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 }

void ARP::dumpARPPacket ARPPacket *  arp  )  [protected]
 

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 }

void ARP::finish  )  [protected, virtual]
 

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 }

void ARP::handleMessage cMessage *  msg  )  [protected, virtual]
 

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 }

void ARP::initialize  )  [protected, virtual]
 

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 }

void ARP::initiateARPResolution ARPCacheEntry entry  )  [protected]
 

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 }

void ARP::processARPPacket ARPPacket *  arp  )  [protected]
 

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 }

void ARP::processOutboundPacket cMessage *  msg  )  [protected]
 

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 }

void ARP::requestTimedOut cMessage *  selfmsg  )  [protected]
 

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 }

void ARP::sendARPRequest InterfaceEntry ie,
IPAddress  ipAddress
[protected]
 

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 }

void ARP::sendPacketToNIC cMessage *  msg,
InterfaceEntry ie,
const MACAddress macAddress
[protected]
 

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 }

void ARP::updateARPCache ARPCacheEntry entry,
const MACAddress macAddress
[protected]
 

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 }

void ARP::updateDisplayString  )  [protected]
 

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 }


Member Data Documentation

ARPCache ARP::arpCache [protected]
 

struct typedef std::map<IPAddress, ARPCacheEntry*> ARP::ARPCache
 

simtime_t ARP::cacheTimeout [protected]
 

bool ARP::doProxyARP [protected]
 

InterfaceTable* ARP::ift [protected]
 

long ARP::numFailedResolutions [protected]
 

long ARP::numRepliesSent [protected]
 

long ARP::numRequestsSent [protected]
 

long ARP::numResolutions [protected]
 

cQueue ARP::pendingQueue [protected]
 

int ARP::retryCount [protected]
 

simtime_t ARP::retryTimeout [protected]
 

RoutingTable* ARP::rt [protected]
 


The documentation for this class was generated from the following files:
Generated on Sat Apr 1 20:52:21 2006 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.1