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]

00315 {
00316     if (rt->localDeliver(destAddr))
00317         return true;
00318 
00319     // respond to Proxy ARP request: if we can route this packet (and the
00320     // output port is different from this one), say yes
00321     if (!doProxyARP)
00322         return false;
00323     InterfaceEntry *rtie = rt->interfaceForDestAddr(destAddr);
00324     return rtie!=NULL && rtie!=ie;
00325 }

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

00328 {
00329     EV << (arp->getOpcode()==ARP_REQUEST ? "ARP_REQ" : arp->getOpcode()==ARP_REPLY ? "ARP_REPLY" : "unknown type")
00330        << "  src=" << arp->getSrcIPAddress() << " / " << arp->getSrcMACAddress()
00331        << "  dest=" << arp->getDestIPAddress() << " / " << arp->getDestMACAddress() << "\n";
00332 }

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]

00226 {
00227     IPAddress nextHopAddr = entry->myIter->first;
00228     entry->pending = true;
00229     entry->numRetries = 0;
00230     entry->lastUpdate = 0;
00231     sendARPRequest(entry->ie, nextHopAddr);
00232 
00233     // start timer
00234     cMessage *msg = entry->timer = new cMessage("ARP timeout");
00235     msg->setContextPointer(entry);
00236     scheduleAt(simTime()+retryTimeout, msg);
00237 
00238     numResolutions++;
00239 }

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

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

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 #ifdef _MAX_SPEED
00126         sendDirect(msg, 0, parentModule(), "ifOut", ie->networkLayerGateIndex());
00127 #else
00128         send(msg, "nicOut", ie->networkLayerGateIndex());
00129 #endif
00130         return;
00131     }
00132 
00133     // determine what address to look up in ARP cache
00134     if (!nextHopAddr.isUnspecified())
00135     {
00136         EV << "using next-hop address " << nextHopAddr << "\n";
00137     }
00138     else
00139     {
00140         // try proxy ARP
00141         IPDatagram *datagram = check_and_cast<IPDatagram *>(msg);
00142         nextHopAddr = datagram->destAddress();
00143         EV << "no next-hop address, using destination address " << nextHopAddr << " (proxy ARP)\n";
00144     }
00145 
00146     //
00147     // Handle multicast IP addresses. RFC 1112, section 6.4 says:
00148     // "An IP host group address is mapped to an Ethernet multicast address
00149     // by placing the low-order 23 bits of the IP address into the low-order
00150     // 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
00151     // Because there are 28 significant bits in an IP host group address,
00152     // more than one host group address may map to the same Ethernet multicast
00153     // address."
00154     //
00155     if (nextHopAddr.isMulticast())
00156     {
00157         // FIXME: we do a simpler solution right now: send to the Broadcast MAC address
00158         EV << "destination address is multicast, sending packet to broadcast MAC address\n";
00159         static MACAddress broadcastAddr("FF:FF:FF:FF:FF:FF");
00160         sendPacketToNIC(msg, ie, broadcastAddr);
00161         return;
00162 #if 0
00163         // experimental RFC 1112 code
00164         // TBD needs counterpart to be implemented in EtherMAC processReceivedDataFrame().
00165         unsigned char macBytes[6];
00166         macBytes[0] = 0x01;
00167         macBytes[1] = 0x00;
00168         macBytes[2] = 0x5e;
00169         macBytes[3] = nextHopAddr.getDByte(1) & 0x7f;
00170         macBytes[4] = nextHopAddr.getDByte(2);
00171         macBytes[5] = nextHopAddr.getDByte(3);
00172         MACAddress multicastMacAddr;
00173         multicastMacAddr.setAddressBytes(bytes);
00174         sendPacketToNIC(msg, ie, multicastMacAddr);
00175         return;
00176 #endif
00177     }
00178 
00179     // try look up
00180     ARPCache::iterator it = arpCache.find(nextHopAddr);
00181     //ASSERT(it==arpCache.end() || ie==(*it).second->ie); // verify: if arpCache gets keyed on InterfaceEntry* too, this becomes unnecessary
00182     if (it==arpCache.end())
00183     {
00184         // no cache entry: launch ARP request
00185         ARPCacheEntry *entry = new ARPCacheEntry();
00186         ARPCache::iterator where = arpCache.insert(arpCache.begin(), std::make_pair(nextHopAddr,entry));
00187         entry->myIter = where; // note: "inserting a new element into a map does not invalidate iterators that point to existing elements"
00188         entry->ie = ie;
00189 
00190         EV << "Starting ARP resolution for " << nextHopAddr << "\n";
00191         initiateARPResolution(entry);
00192 
00193         // and queue up packet
00194         entry->pendingPackets.push_back(msg);
00195         pendingQueue.insert(msg);
00196     }
00197     else if ((*it).second->pending)
00198     {
00199         // an ARP request is already pending for this address -- just queue up packet
00200         EV << "ARP resolution for " << nextHopAddr << " is pending, queueing up packet\n";
00201         (*it).second->pendingPackets.push_back(msg);
00202         pendingQueue.insert(msg);
00203     }
00204     else if ((*it).second->lastUpdate+cacheTimeout<simTime())
00205     {
00206         EV << "ARP cache entry for " << nextHopAddr << " expired, starting new ARP resolution\n";
00207 
00208         // cache entry stale, send new ARP request
00209         ARPCacheEntry *entry = (*it).second;
00210         entry->ie = ie; // routing table may have changed
00211         initiateARPResolution(entry);
00212 
00213         // and queue up packet
00214         entry->pendingPackets.push_back(msg);
00215         pendingQueue.insert(msg);
00216     }
00217     else
00218     {
00219         // valid ARP cache entry found, flag msg with MAC address and send it out
00220         EV << "ARP cache hit, MAC address for " << nextHopAddr << " is " << (*it).second->macAddress << ", sending packet down\n";
00221         sendPacketToNIC(msg, ie, (*it).second->macAddress);
00222     }
00223 }

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

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

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

00257 {
00258     // find our own IP address and MAC address on the given interface
00259     MACAddress myMACAddress = ie->macAddress();
00260     IPAddress myIPAddress = ie->ipv4()->inetAddress();
00261 
00262     // both must be set
00263     ASSERT(!myMACAddress.isUnspecified());
00264     ASSERT(!myIPAddress.isUnspecified());
00265 
00266     // fill out everything in ARP Request packet except dest MAC address
00267     ARPPacket *arp = new ARPPacket("arpREQ");
00268     arp->setByteLength(ARP_HEADER_BYTES);
00269     arp->setOpcode(ARP_REQUEST);
00270     arp->setSrcMACAddress(myMACAddress);
00271     arp->setSrcIPAddress(myIPAddress);
00272     arp->setDestIPAddress(ipAddress);
00273 
00274     static MACAddress broadcastAddress("ff:ff:ff:ff:ff:ff");
00275     sendPacketToNIC(arp, ie, broadcastAddress);
00276     numRequestsSent++;
00277 }

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

00242 {
00243     // add control info with MAC address
00244     Ieee802Ctrl *controlInfo = new Ieee802Ctrl();
00245     controlInfo->setDest(macAddress);
00246     msg->setControlInfo(controlInfo);
00247 
00248     // send out
00249 #ifdef _MAX_SPEED
00250     sendDirect(msg, 0, parentModule(), "ifOut", ie->networkLayerGateIndex());
00251 #else
00252     send(msg, "nicOut", ie->networkLayerGateIndex());
00253 #endif
00254 }

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

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

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 Wed Apr 4 13:20:19 2007 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.7