ARP Class Reference

#include <ARP.h>

List of all members.


Detailed Description

ARP implementation.

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
IInterfaceTableift
IRoutingTablert

Classes

struct  ARPCacheEntry

Member Typedef Documentation

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

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


Constructor & Destructor Documentation

ARP::ARP (  )  [inline]

00082 {}

ARP::~ARP (  )  [virtual]

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


Member Function Documentation

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 }


Member Data Documentation

simtime_t ARP::retryTimeout [protected]

int ARP::retryCount [protected]

Referenced by initialize(), and requestTimedOut().

simtime_t ARP::cacheTimeout [protected]

bool ARP::doProxyARP [protected]

Referenced by addressRecognized(), and initialize().

long ARP::numResolutions [protected]

long ARP::numFailedResolutions [protected]

long ARP::numRequestsSent [protected]

long ARP::numRepliesSent [protected]

ARPCache ARP::arpCache [protected]

cQueue ARP::pendingQueue [protected]

int ARP::nicOutBaseGateId [protected]

Referenced by initialize().

IInterfaceTable* ARP::ift [protected]

IRoutingTable* ARP::rt [protected]

Referenced by addressRecognized(), and initialize().


The documentation for this class was generated from the following files:

Generated on Fri Mar 20 18:51:18 2009 for INET Framework for OMNeT++/OMNEST by  doxygen 1.5.5