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::map< IPAddress,
ARPCacheEntry * > 
ARPCache
typedef std::vector< cMessage * > MsgPtrVector

Public Member Functions

 ARP ()
 ~ARP ()

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::map<IPAddress, ARPCacheEntry*> ARP::ARPCache
 

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]
 

00307 {
00308     if (rt->localDeliver(destAddr))
00309         return true;
00310 
00311     // respond to Proxy ARP request: if we can route this packet (and the
00312     // output port is different from this one), say yes
00313     if (!doProxyARP)
00314         return false;
00315     InterfaceEntry *rtie = rt->interfaceForDestAddr(destAddr);
00316     return rtie!=NULL && rtie!=ie;
00317 }

void ARP::dumpARPPacket ARPPacket arp  )  [protected]
 

00320 {
00321     EV << (arp->getOpcode()==ARP_REQUEST ? "ARP_REQ" : arp->getOpcode()==ARP_REPLY ? "ARP_REPLY" : "unknown type")
00322        << "  src=" << arp->getSrcIPAddress() << " / " << arp->getSrcMACAddress()
00323        << "  dest=" << arp->getDestIPAddress() << " / " << arp->getDestMACAddress() << "\n";
00324 }

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]
 

00328 {
00329     EV << "ARP packet " << arp << " arrived:\n";
00330     dumpARPPacket(arp);
00331 
00332     // extract input port
00333     IPRoutingDecision *controlInfo = check_and_cast<IPRoutingDecision*>(arp->removeControlInfo());
00334     InterfaceEntry *ie = ift->interfaceAt(controlInfo->interfaceId());
00335     delete controlInfo;
00336 
00337     //
00338     // Recipe a'la RFC 826:
00339     //
00340     // ?Do I have the hardware type in ar$hrd?
00341     // Yes: (almost definitely)
00342     //   [optionally check the hardware length ar$hln]
00343     //   ?Do I speak the protocol in ar$pro?
00344     //   Yes:
00345     //     [optionally check the protocol length ar$pln]
00346     //     Merge_flag := false
00347     //     If the pair <protocol type, sender protocol address> is
00348     //         already in my translation table, update the sender
00349     //         hardware address field of the entry with the new
00350     //         information in the packet and set Merge_flag to true.
00351     //     ?Am I the target protocol address?
00352     //     Yes:
00353     //       If Merge_flag is false, add the triplet <protocol type,
00354     //           sender protocol address, sender hardware address> to
00355     //           the translation table.
00356     //       ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
00357     //       Yes:
00358     //         Swap hardware and protocol fields, putting the local
00359     //             hardware and protocol addresses in the sender fields.
00360     //         Set the ar$op field to ares_op$REPLY
00361     //         Send the packet to the (new) target hardware address on
00362     //             the same hardware on which the request was received.
00363     //
00364 
00365     MACAddress srcMACAddress = arp->getSrcMACAddress();
00366     IPAddress srcIPAddress = arp->getSrcIPAddress();
00367 
00368     if (srcMACAddress.isUnspecified())
00369         error("wrong ARP packet: source MAC address is empty");
00370     if (srcIPAddress.isUnspecified())
00371         error("wrong ARP packet: source IP address is empty");
00372 
00373     bool mergeFlag = false;
00374     // "If ... sender protocol address is already in my translation table"
00375     ARPCache::iterator it = arpCache.find(srcIPAddress);
00376     if (it!=arpCache.end())
00377     {
00378         // "update the sender hardware address field"
00379         ARPCacheEntry *entry = (*it).second;
00380         updateARPCache(entry, srcMACAddress);
00381         mergeFlag = true;
00382     }
00383 
00384     // "?Am I the target protocol address?"
00385     // if Proxy ARP is enabled, we also have to reply if we're a router to the dest IP address
00386     if (addressRecognized(arp->getDestIPAddress(), ie))
00387     {
00388         // "If Merge_flag is false, add the triplet protocol type, sender
00389         // protocol address, sender hardware address to the translation table"
00390         if (!mergeFlag)
00391         {
00392             ARPCacheEntry *entry;
00393             if (it!=arpCache.end())
00394             {
00395                 entry = (*it).second;
00396             }
00397             else
00398             {
00399                 entry = new ARPCacheEntry();
00400                 ARPCache::iterator where = arpCache.insert(arpCache.begin(), std::make_pair(srcIPAddress,entry));
00401                 entry->myIter = where;
00402                 entry->ie = ie;
00403 
00404                 entry->pending = false;
00405                 entry->timer = NULL;
00406                 entry->numRetries = 0;
00407             }
00408             updateARPCache(entry, srcMACAddress);
00409         }
00410 
00411         // "?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)"
00412         switch (arp->getOpcode())
00413         {
00414             case ARP_REQUEST:
00415             {
00416                 EV << "Packet was ARP REQUEST, sending REPLY\n";
00417 
00418                 // find our own IP address and MAC address on the given interface
00419                 MACAddress myMACAddress = ie->macAddress();
00420                 IPAddress myIPAddress = ie->ipv4()->inetAddress();
00421 
00422                 // "Swap hardware and protocol fields", etc.
00423                 arp->setName("arpREPLY");
00424                 IPAddress origDestAddress = arp->getDestIPAddress();
00425                 arp->setDestIPAddress(srcIPAddress);
00426                 arp->setDestMACAddress(srcMACAddress);
00427                 arp->setSrcIPAddress(origDestAddress);
00428                 arp->setSrcMACAddress(myMACAddress);
00429                 arp->setOpcode(ARP_REPLY);
00430                 delete arp->removeControlInfo();
00431                 sendPacketToNIC(arp, ie, srcMACAddress);
00432                 numRepliesSent++;
00433                 break;
00434             }
00435             case ARP_REPLY:
00436             {
00437                 EV << "Discarding packet\n";
00438                 delete arp;
00439                 break;
00440             }
00441             case ARP_RARP_REQUEST: error("RARP request received: RARP is not supported");
00442             case ARP_RARP_REPLY: error("RARP reply received: RARP is not supported");
00443             default: error("Unsupported opcode %d in received ARP packet",arp->getOpcode());
00444         }
00445     }
00446     else
00447     {
00448         // address not recognized
00449         EV << "IP address " << arp->getDestIPAddress() << " not recognized, dropping ARP packet\n";
00450         delete arp;
00451     }
00452 }

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]
 

00272 {
00273     ARPCacheEntry *entry = (ARPCacheEntry *)selfmsg->contextPointer();
00274     entry->numRetries++;
00275     if (entry->numRetries < retryCount)
00276     {
00277         // retry
00278         IPAddress nextHopAddr = entry->myIter->first;
00279         EV << "ARP request for " << nextHopAddr << " timed out, resending\n";
00280         sendARPRequest(entry->ie, nextHopAddr);
00281         scheduleAt(simTime()+retryTimeout, selfmsg);
00282         return;
00283     }
00284 
00285     // max retry count reached: ARP failure.
00286     // throw out entry from cache, delete pending messages
00287     MsgPtrVector& pendingPackets = entry->pendingPackets;
00288     EV << "ARP timeout, max retry count " << retryCount << " for "
00289        << entry->myIter->first << " reached. Dropping " << pendingPackets.size()
00290        << " waiting packets from the queue\n";
00291     while (!pendingPackets.empty())
00292     {
00293         MsgPtrVector::iterator i = pendingPackets.begin();
00294         cMessage *msg = (*i);
00295         pendingPackets.erase(i);
00296         pendingQueue.remove(msg);
00297         delete msg;
00298     }
00299     delete selfmsg;
00300     arpCache.erase(entry->myIter);
00301     delete entry;
00302     numFailedResolutions++;
00303 }

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     // both must be set
00255     ASSERT(!myMACAddress.isUnspecified());
00256     ASSERT(!myIPAddress.isUnspecified());
00257 
00258     // fill out everything in ARP Request packet except dest MAC address
00259     ARPPacket *arp = new ARPPacket("arpREQ");
00260     arp->setByteLength(ARP_HEADER_BYTES);
00261     arp->setOpcode(ARP_REQUEST);
00262     arp->setSrcMACAddress(myMACAddress);
00263     arp->setSrcIPAddress(myIPAddress);
00264     arp->setDestIPAddress(ipAddress);
00265 
00266     static MACAddress broadcastAddress("ff:ff:ff:ff:ff:ff");
00267     sendPacketToNIC(arp, ie, broadcastAddress);
00268     numRequestsSent++;
00269 }

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]
 

00455 {
00456     EV << "Updating ARP cache entry: " << entry->myIter->first << " <--> " << macAddress << "\n";
00457 
00458     // update entry
00459     if (entry->pending)
00460     {
00461         entry->pending = false;
00462         delete cancelEvent(entry->timer);
00463         entry->timer = NULL;
00464         entry->numRetries = 0;
00465     }
00466     entry->macAddress = macAddress;
00467     entry->lastUpdate = simTime();
00468 
00469     // process queued packets
00470     MsgPtrVector& pendingPackets = entry->pendingPackets;
00471     while (!pendingPackets.empty())
00472     {
00473         MsgPtrVector::iterator i = pendingPackets.begin();
00474         cMessage *msg = (*i);
00475         pendingPackets.erase(i);
00476         pendingQueue.remove(msg);
00477         EV << "Sending out queued packet " << msg << "\n";
00478         sendPacketToNIC(msg, entry->ie, macAddress);
00479     }
00480 }

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]
 

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 Thu Oct 19 18:22:21 2006 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.0