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

IP Class Reference

#include <IP.h>

Inheritance diagram for IP:

QueueBase AbstractQueue List of all members.

Detailed Description

Implements the IP protocol.


Public Member Functions

 IP ()

Protected Member Functions

InterfaceEntrysourceInterfaceFrom (cMessage *msg)
void updateDisplayString ()
IPDatagramencapsulate (cMessage *transportPacket, InterfaceEntry *&destIE)
virtual void handlePacketFromNetwork (IPDatagram *datagram)
virtual void handleMessageFromHL (cMessage *msg)
virtual void handleARP (ARPPacket *msg)
virtual void handleReceivedICMP (ICMPMessage *msg)
virtual void routePacket (IPDatagram *datagram, InterfaceEntry *destIE, bool fromHL)
virtual void routeMulticastPacket (IPDatagram *datagram, InterfaceEntry *destIE, InterfaceEntry *fromIE)
virtual void localDeliver (IPDatagram *datagram)
virtual cMessage * decapsulateIP (IPDatagram *datagram)
virtual void fragmentAndSend (IPDatagram *datagram, InterfaceEntry *ie, IPAddress nextHopAddr)
virtual void sendDatagramToOutput (IPDatagram *datagram, InterfaceEntry *ie, IPAddress nextHopAddr)
virtual void initialize ()
virtual void endService (cMessage *msg)

Protected Attributes

RoutingTablert
InterfaceTableift
ICMPAccess icmpAccess
int defaultTimeToLive
int defaultMCTimeToLive
simtime_t fragmentTimeoutTime
long curFragmentId
IPFragBuf fragbuf
simtime_t lastCheckTime
ProtocolMapping mapping
int numMulticast
int numLocalDeliver
int numDropped
int numUnroutable
int numForwarded


Constructor & Destructor Documentation

IP::IP  )  [inline]
 

00138 {}


Member Function Documentation

cMessage * IP::decapsulateIP IPDatagram datagram  )  [protected, virtual]
 

Decapsulate and return encapsulated packet after attaching IPControlInfo.

00409 {
00410     // decapsulate transport packet
00411     InterfaceEntry *fromIE = sourceInterfaceFrom(datagram);
00412     cMessage *packet = datagram->decapsulate();
00413 
00414     // create and fill in control info
00415     IPControlInfo *controlInfo = new IPControlInfo();
00416     controlInfo->setProtocol(datagram->transportProtocol());
00417     controlInfo->setSrcAddr(datagram->srcAddress());
00418     controlInfo->setDestAddr(datagram->destAddress());
00419     controlInfo->setDiffServCodePoint(datagram->diffServCodePoint());
00420     controlInfo->setInterfaceId(fromIE ? fromIE->interfaceId() : -1);
00421 
00422     // original IP datagram might be needed in upper layers to send back ICMP error message
00423     controlInfo->setOrigDatagram(datagram);
00424 
00425     // attach control info
00426     packet->setControlInfo(controlInfo);
00427 
00428     return packet;
00429 }

IPDatagram * IP::encapsulate cMessage *  transportPacket,
InterfaceEntry *&  destIE
[protected]
 

Encapsulate packet coming from higher layers into IPDatagram

00495 {
00496     IPControlInfo *controlInfo = check_and_cast<IPControlInfo*>(transportPacket->removeControlInfo());
00497 
00498     IPDatagram *datagram = new IPDatagram(transportPacket->name());
00499     datagram->setByteLength(IP_HEADER_BYTES);
00500     datagram->encapsulate(transportPacket);
00501 
00502     // set source and destination address
00503     IPAddress dest = controlInfo->destAddr();
00504     datagram->setDestAddress(dest);
00505 
00506     // IP_MULTICAST_IF option, but allow interface selection for unicast packets as well
00507     destIE = ift->interfaceAt(controlInfo->interfaceId());
00508 
00509     IPAddress src = controlInfo->srcAddr();
00510 
00511     // when source address was given, use it; otherwise it'll get the address
00512     // of the outgoing interface after routing
00513     if (!src.isUnspecified())
00514     {
00515         // if interface parameter does not match existing interface, do not send datagram
00516         if (rt->interfaceByAddress(src)==NULL)
00517             opp_error("Wrong source address %s in (%s)%s: no interface with such address",
00518                       src.str().c_str(), transportPacket->className(), transportPacket->fullName());
00519         datagram->setSrcAddress(src);
00520     }
00521 
00522     // set other fields
00523     datagram->setDiffServCodePoint(controlInfo->diffServCodePoint());
00524 
00525     datagram->setIdentification(curFragmentId++);
00526     datagram->setMoreFragments(false);
00527     datagram->setDontFragment (controlInfo->dontFragment());
00528     datagram->setFragmentOffset(0);
00529 
00530     datagram->setTimeToLive(
00531            controlInfo->timeToLive() > 0 ?
00532            controlInfo->timeToLive() :
00533            (datagram->destAddress().isMulticast() ? defaultMCTimeToLive : defaultTimeToLive)
00534     );
00535 
00536     datagram->setTransportProtocol(controlInfo->protocol());
00537     delete controlInfo;
00538 
00539     // setting IP options is currently not supported
00540 
00541     return datagram;
00542 }

void IP::endService cMessage *  msg  )  [protected, virtual]
 

Processing of IP datagrams. Called when a datagram reaches the front of the queue.

Implements AbstractQueue.

00071 {
00072     if (msg->arrivalGate()->isName("transportIn"))
00073     {
00074         handleMessageFromHL(msg);
00075     }
00076     else if (dynamic_cast<ARPPacket *>(msg))
00077     {
00078         // dispatch ARP packets to ARP
00079         handleARP((ARPPacket *)msg);
00080     }
00081     else
00082     {
00083         IPDatagram *dgram = check_and_cast<IPDatagram *>(msg);
00084         handlePacketFromNetwork(dgram);
00085     }
00086 
00087     if (ev.isGUI())
00088         updateDisplayString();
00089 }

void IP::fragmentAndSend IPDatagram datagram,
InterfaceEntry ie,
IPAddress  nextHopAddr
[protected, virtual]
 

Fragment packet if needed, then send it to the selected interface using sendDatagramToOutput().

00433 {
00434     int mtu = ie->mtu();
00435 
00436     // check if datagram does not require fragmentation
00437     if (datagram->byteLength() <= mtu)
00438     {
00439         sendDatagramToOutput(datagram, ie, nextHopAddr);
00440         return;
00441     }
00442 
00443     int headerLength = datagram->headerLength();
00444     int payload = datagram->byteLength() - headerLength;
00445 
00446     int noOfFragments =
00447         int(ceil((float(payload)/mtu) /
00448         (1-float(headerLength)/mtu) ) ); // FIXME ???
00449 
00450     // if "don't fragment" bit is set, throw datagram away and send ICMP error message
00451     if (datagram->dontFragment() && noOfFragments>1)
00452     {
00453         EV << "datagram larger than MTU and don't fragment bit set, sending ICMP_DESTINATION_UNREACHABLE\n";
00454         icmpAccess.get()->sendErrorMessage(datagram, ICMP_DESTINATION_UNREACHABLE,
00455                                                      ICMP_FRAGMENTATION_ERROR_CODE);
00456         return;
00457     }
00458 
00459     // create and send fragments
00460     EV << "Breaking datagram into " << noOfFragments << " fragments\n";
00461     std::string fragMsgName = datagram->name();
00462     fragMsgName += "-frag";
00463 
00464     // FIXME revise this!
00465     for (int i=0; i<noOfFragments; i++)
00466     {
00467         // FIXME is it ok that full encapsulated packet travels in every datagram fragment?
00468         // should better travel in the last fragment only. Cf. with reassembly code!
00469         IPDatagram *fragment = (IPDatagram *) datagram->dup();
00470         fragment->setName(fragMsgName.c_str());
00471 
00472         // total_length equal to mtu, except for last fragment;
00473         // "more fragments" bit is unchanged in the last fragment, otherwise true
00474         if (i != noOfFragments-1)
00475         {
00476             fragment->setMoreFragments(true);
00477             fragment->setByteLength(mtu);
00478         }
00479         else
00480         {
00481             // size of last fragment
00482             int bytes = datagram->byteLength() - (noOfFragments-1) * (mtu - datagram->headerLength());
00483             fragment->setByteLength(bytes);
00484         }
00485         fragment->setFragmentOffset( i*(mtu - datagram->headerLength()) );
00486 
00487         sendDatagramToOutput(fragment, ie, nextHopAddr);
00488     }
00489 
00490     delete datagram;
00491 }

void IP::handleARP ARPPacket msg  )  [protected, virtual]
 

Handle incoming ARP packets by sending them over "queueOut" to ARP.

00131 {
00132     // FIXME hasBitError() check  missing!
00133 
00134     // delete old control info
00135     delete msg->removeControlInfo();
00136 
00137     // dispatch ARP packets to ARP and let it know the gate index it arrived on
00138     InterfaceEntry *fromIE = sourceInterfaceFrom(msg);
00139     ASSERT(fromIE);
00140 
00141     IPRoutingDecision *routingDecision = new IPRoutingDecision();
00142     routingDecision->setInterfaceId(fromIE->interfaceId());
00143     msg->setControlInfo(routingDecision);
00144 
00145     send(msg, "queueOut");
00146 }

void IP::handleMessageFromHL cMessage *  msg  )  [protected, virtual]
 

Handle messages (typically packets to be send in IP) from transport or ICMP. Invokes encapsulate(), then routePacket().

00173 {
00174     // if no interface exists, do not send datagram
00175     if (ift->numInterfaces() == 0)
00176     {
00177         EV << "No interfaces exist, dropping packet\n";
00178         delete msg;
00179         return;
00180     }
00181 
00182     // encapsulate and send
00183     InterfaceEntry *destIE; // will be filled in by encapsulate()
00184     IPDatagram *datagram = encapsulate(msg, destIE);
00185 
00186     // route packet
00187     if (!datagram->destAddress().isMulticast())
00188         routePacket(datagram, destIE, true);
00189     else
00190         routeMulticastPacket(datagram, destIE, NULL);
00191 }

void IP::handlePacketFromNetwork IPDatagram datagram  )  [protected, virtual]
 

Handle IPDatagram messages arriving from lower layer. Decrements TTL, then invokes routePacket().

00098 {
00099     //
00100     // "Prerouting"
00101     //
00102 
00103     // check for header biterror
00104     if (datagram->hasBitError())
00105     {
00106         // probability of bit error in header = size of header / size of total message
00107         // (ignore bit error if in payload)
00108         double relativeHeaderLength = datagram->headerLength() / (double)datagram->byteLength();
00109         if (dblrand() <= relativeHeaderLength)
00110         {
00111             EV << "bit error found, sending ICMP_PARAMETER_PROBLEM\n";
00112             icmpAccess.get()->sendErrorMessage(datagram, ICMP_PARAMETER_PROBLEM, 0);
00113             return;
00114         }
00115     }
00116 
00117     // remove control info
00118     delete datagram->removeControlInfo();
00119 
00120     // hop counter decrement; FIXME but not if it will be locally delivered
00121     datagram->setTimeToLive(datagram->timeToLive()-1);
00122 
00123     // route packet
00124     if (!datagram->destAddress().isMulticast())
00125         routePacket(datagram, NULL, false);
00126     else
00127         routeMulticastPacket(datagram, NULL, sourceInterfaceFrom(datagram));
00128 }

void IP::handleReceivedICMP ICMPMessage msg  )  [protected, virtual]
 

Handle incoming ICMP messages.

00149 {
00150     switch (msg->getType())
00151     {
00152         case ICMP_REDIRECT: // TODO implement redirect handling
00153         case ICMP_DESTINATION_UNREACHABLE:
00154         case ICMP_TIME_EXCEEDED:
00155         case ICMP_PARAMETER_PROBLEM: {
00156             // ICMP errors are delivered to the appropriate higher layer protocol
00157             IPDatagram *bogusPacket = check_and_cast<IPDatagram *>(msg->encapsulatedMsg());
00158             int protocol = bogusPacket->transportProtocol();
00159             int gateindex = mapping.outputGateForProtocol(protocol);
00160             send(msg, "transportOut", gateindex);
00161             break;
00162         }
00163         default: {
00164             // all others are delivered to ICMP: ICMP_ECHO_REQUEST, ICMP_ECHO_REPLY,
00165             // ICMP_TIMESTAMP_REQUEST, ICMP_TIMESTAMP_REPLY, etc.
00166             int gateindex = mapping.outputGateForProtocol(IP_PROT_ICMP);
00167             send(msg, "transportOut", gateindex);
00168         }
00169     }
00170 }

void IP::initialize  )  [protected, virtual]
 

Initialization

Reimplemented from QueueBase.

00035 {
00036     QueueBase::initialize();
00037 
00038     ift = InterfaceTableAccess().get();
00039     rt = RoutingTableAccess().get();
00040 
00041     defaultTimeToLive = par("timeToLive");
00042     defaultMCTimeToLive = par("multicastTimeToLive");
00043     fragmentTimeoutTime = par("fragmentTimeout");
00044     mapping.parseProtocolMapping(par("protocolMapping"));
00045 
00046     curFragmentId = 0;
00047     lastCheckTime = 0;
00048     fragbuf.init(icmpAccess.get());
00049 
00050     numMulticast = numLocalDeliver = numDropped = numUnroutable = numForwarded = 0;
00051 
00052     WATCH(numMulticast);
00053     WATCH(numLocalDeliver);
00054     WATCH(numDropped);
00055     WATCH(numUnroutable);
00056     WATCH(numForwarded);
00057 }

void IP::localDeliver IPDatagram datagram  )  [protected, virtual]
 

Perform reassembly of fragmented datagrams, then send them up to the higher layers using sendToHL().

00364 {
00365     // Defragmentation. skip defragmentation if datagram is not fragmented
00366     if (datagram->fragmentOffset()!=0 || datagram->moreFragments())
00367     {
00368         EV << "Datagram fragment: offset=" << datagram->fragmentOffset()
00369            << ", MORE=" << (datagram->moreFragments() ? "true" : "false") << ".\n";
00370 
00371         // erase timed out fragments in fragmentation buffer; check every 10 seconds max
00372         if (simTime() >= lastCheckTime + 10)
00373         {
00374             lastCheckTime = simTime();
00375             fragbuf.purgeStaleFragments(simTime()-fragmentTimeoutTime);
00376         }
00377 
00378         datagram = fragbuf.addFragment(datagram, simTime());
00379         if (!datagram)
00380         {
00381             EV << "No complete datagram yet.\n";
00382             return;
00383         }
00384         EV << "This fragment completes the datagram.\n";
00385     }
00386 
00387     // decapsulate and send on appropriate output gate
00388     int protocol = datagram->transportProtocol();
00389     cMessage *packet = decapsulateIP(datagram);
00390 
00391     if (protocol==IP_PROT_ICMP)
00392     {
00393         // incoming ICMP packets are handled specially
00394         handleReceivedICMP(check_and_cast<ICMPMessage *>(packet));
00395     }
00396     else if (protocol==IP_PROT_IP)
00397     {
00398         // tunnelled IP packets are handled separately
00399         send(packet, "preRoutingOut");
00400     }
00401     else
00402     {
00403         int gateindex = mapping.outputGateForProtocol(protocol);
00404         send(packet, "transportOut", gateindex);
00405     }
00406 }

void IP::routeMulticastPacket IPDatagram datagram,
InterfaceEntry destIE,
InterfaceEntry fromIE
[protected, virtual]
 

Forwards packets to all multicast destinations, using fragmentAndSend().

00264 {
00265     IPAddress destAddr = datagram->destAddress();
00266     EV << "Routing multicast datagram `" << datagram->name() << "' with dest=" << destAddr << "\n";
00267 
00268     numMulticast++;
00269 
00270     // DVMRP: process datagram only if sent locally or arrived on the shortest
00271     // route (provided routing table already contains srcAddr); otherwise
00272     // discard and continue.
00273     InterfaceEntry *shortestPathIE = rt->interfaceForDestAddr(datagram->srcAddress());
00274     if (fromIE!=NULL && shortestPathIE!=NULL && fromIE!=shortestPathIE)
00275     {
00276         // FIXME count dropped
00277         EV << "Packet dropped.\n";
00278         delete datagram;
00279         return;
00280     }
00281 
00282     // if received from the network...
00283     if (fromIE!=NULL)
00284     {
00285         // check for local delivery
00286         if (rt->multicastLocalDeliver(destAddr))
00287         {
00288             IPDatagram *datagramCopy = (IPDatagram *) datagram->dup();
00289 
00290             // FIXME code from the MPLS model: set packet dest address to routerId (???)
00291             datagramCopy->setDestAddress(rt->routerId());
00292 
00293             localDeliver(datagramCopy);
00294         }
00295 
00296         // don't forward if IP forwarding is off
00297         if (!rt->ipForward())
00298         {
00299             delete datagram;
00300             return;
00301         }
00302 
00303         // don't forward if dest address is link-scope
00304         if (destAddr.isLinkLocalMulticast())
00305         {
00306             delete datagram;
00307             return;
00308         }
00309 
00310     }
00311 
00312     // routed explicitly via IP_MULTICAST_IF
00313     if (destIE!=NULL)
00314     {
00315         ASSERT(datagram->destAddress().isMulticast());
00316 
00317         EV << "multicast packet explicitly routed via output interface " << destIE->name() << endl;
00318 
00319         // set datagram source address if not yet set
00320         if (datagram->srcAddress().isUnspecified())
00321             datagram->setSrcAddress(destIE->ipv4()->inetAddress());
00322 
00323         // send
00324         fragmentAndSend(datagram, destIE, datagram->destAddress());
00325 
00326         return;
00327     }
00328 
00329     // now: routing
00330     MulticastRoutes routes = rt->multicastRoutesFor(destAddr);
00331     if (routes.size()==0)
00332     {
00333         // no destination: delete datagram
00334         delete datagram;
00335     }
00336     else
00337     {
00338         // copy original datagram for multiple destinations
00339         for (unsigned int i=0; i<routes.size(); i++)
00340         {
00341             InterfaceEntry *destIE = routes[i].interf;
00342 
00343             // don't forward to input port
00344             if (destIE && destIE!=fromIE)
00345             {
00346                 IPDatagram *datagramCopy = (IPDatagram *) datagram->dup();
00347 
00348                 // set datagram source address if not yet set
00349                 if (datagramCopy->srcAddress().isUnspecified())
00350                     datagramCopy->setSrcAddress(destIE->ipv4()->inetAddress());
00351 
00352                 // send
00353                 IPAddress nextHopAddr = routes[i].gateway;
00354                 fragmentAndSend(datagramCopy, destIE, nextHopAddr);
00355             }
00356         }
00357 
00358         // only copies sent, delete original datagram
00359         delete datagram;
00360     }
00361 }

void IP::routePacket IPDatagram datagram,
InterfaceEntry destIE,
bool  fromHL
[protected, virtual]
 

Performs routing. Based on the routing decision, it dispatches to localDeliver() for local packets, to fragmentAndSend() for forwarded packets, to handleMulticastPacket() for multicast packets, or drops the packet if it's unroutable or forwarding is off.

00194 {
00195     // TBD add option handling code here
00196 
00197     IPAddress destAddr = datagram->destAddress();
00198 
00199     EV << "Routing datagram `" << datagram->name() << "' with dest=" << destAddr << ": ";
00200 
00201     // check for local delivery
00202     if (rt->localDeliver(destAddr))
00203     {
00204         EV << "local delivery\n";
00205         if (datagram->srcAddress().isUnspecified())
00206             datagram->setSrcAddress(destAddr); // allows two apps on the same host to communicate
00207         numLocalDeliver++;
00208         localDeliver(datagram);
00209         return;
00210     }
00211 
00212     // if datagram arrived from input gate and IP_FORWARD is off, delete datagram
00213     if (!fromHL && !rt->ipForward())
00214     {
00215         EV << "forwarding off, dropping packet\n";
00216         numDropped++;
00217         delete datagram;
00218         return;
00219     }
00220 
00221     IPAddress nextHopAddr;
00222 
00223     // if output port was explicitly requested, use that, otherwise use IP routing
00224     if (destIE)
00225     {
00226         EV << "using manually specified output interface " << destIE->name() << "\n";
00227         // and nextHopAddr remains unspecified
00228     }
00229     else
00230     {
00231         // use IP routing (lookup in routing table)
00232         RoutingEntry *re = rt->findBestMatchingRoute(destAddr);
00233 
00234         // error handling: destination address does not exist in routing table:
00235         // notify ICMP, throw packet away and continue
00236         if (re==NULL)
00237         {
00238             EV << "unroutable, sending ICMP_DESTINATION_UNREACHABLE\n";
00239             numUnroutable++;
00240             icmpAccess.get()->sendErrorMessage(datagram, ICMP_DESTINATION_UNREACHABLE, 0);
00241             return;
00242         }
00243 
00244         // extract interface and next-hop address from routing table entry
00245         destIE = re->interfacePtr;
00246         nextHopAddr = re->gateway;
00247     }
00248 
00249     // set datagram source address if not yet set
00250     if (datagram->srcAddress().isUnspecified())
00251         datagram->setSrcAddress(destIE->ipv4()->inetAddress());
00252 
00253     // default: send datagram to fragmentation
00254     EV << "output interface is " << destIE->name() << ", next-hop address: " << nextHopAddr << "\n";
00255     numForwarded++;
00256 
00257     //
00258     // fragment and send the packet
00259     //
00260     fragmentAndSend(datagram, destIE, nextHopAddr);
00261 }

void IP::sendDatagramToOutput IPDatagram datagram,
InterfaceEntry ie,
IPAddress  nextHopAddr
[protected, virtual]
 

Last TTL check, then send datagram on the given interface.

00545 {
00546     // hop counter check
00547     if (datagram->timeToLive() <= 0)
00548     {
00549         // drop datagram, destruction responsibility in ICMP
00550         EV << "datagram TTL reached zero, sending ICMP_TIME_EXCEEDED\n";
00551         icmpAccess.get()->sendErrorMessage(datagram, ICMP_TIME_EXCEEDED, 0);
00552         return;
00553     }
00554 
00555     // send out datagram to ARP, with control info attached
00556     IPRoutingDecision *routingDecision = new IPRoutingDecision();
00557     routingDecision->setInterfaceId(ie->interfaceId());
00558     routingDecision->setNextHopAddr(nextHopAddr);
00559     datagram->setControlInfo(routingDecision);
00560 
00561     send(datagram, "queueOut");
00562 }

InterfaceEntry * IP::sourceInterfaceFrom cMessage *  msg  )  [protected]
 

00092 {
00093     cGate *g = msg->arrivalGate();
00094     return g ? ift->interfaceByNetworkLayerGateIndex(g->index()) : NULL;
00095 }

void IP::updateDisplayString  )  [protected]
 

00060 {
00061     char buf[80] = "";
00062     if (numForwarded>0) sprintf(buf+strlen(buf), "fwd:%d ", numForwarded);
00063     if (numLocalDeliver>0) sprintf(buf+strlen(buf), "up:%d ", numLocalDeliver);
00064     if (numMulticast>0) sprintf(buf+strlen(buf), "mcast:%d ", numMulticast);
00065     if (numDropped>0) sprintf(buf+strlen(buf), "DROP:%d ", numDropped);
00066     if (numUnroutable>0) sprintf(buf+strlen(buf), "UNROUTABLE:%d ", numUnroutable);
00067     displayString().setTagArg("t",0,buf);
00068 }


Member Data Documentation

long IP::curFragmentId [protected]
 

int IP::defaultMCTimeToLive [protected]
 

int IP::defaultTimeToLive [protected]
 

IPFragBuf IP::fragbuf [protected]
 

simtime_t IP::fragmentTimeoutTime [protected]
 

ICMPAccess IP::icmpAccess [protected]
 

InterfaceTable* IP::ift [protected]
 

simtime_t IP::lastCheckTime [protected]
 

ProtocolMapping IP::mapping [protected]
 

int IP::numDropped [protected]
 

int IP::numForwarded [protected]
 

int IP::numLocalDeliver [protected]
 

int IP::numMulticast [protected]
 

int IP::numUnroutable [protected]
 

RoutingTable* IP::rt [protected]
 


The documentation for this class was generated from the following files:
Generated on Thu Oct 19 18:22:24 2006 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.0