IP.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004 Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 
00019 #include <omnetpp.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 
00023 #include "IP.h"
00024 #include "IPDatagram.h"
00025 #include "IPControlInfo.h"
00026 #include "ICMPMessage_m.h"
00027 #include "IPv4InterfaceData.h"
00028 #include "ARPPacket_m.h"
00029 
00030 Define_Module(IP);
00031 
00032 
00033 void IP::initialize()
00034 {
00035     QueueBase::initialize();
00036 
00037     ift = InterfaceTableAccess().get();
00038     rt = RoutingTableAccess().get();
00039 
00040     queueOutGate = gate("queueOut");
00041 
00042     defaultTimeToLive = par("timeToLive");
00043     defaultMCTimeToLive = par("multicastTimeToLive");
00044     fragmentTimeoutTime = par("fragmentTimeout");
00045     mapping.parseProtocolMapping(par("protocolMapping"));
00046 
00047     curFragmentId = 0;
00048     lastCheckTime = 0;
00049     fragbuf.init(icmpAccess.get());
00050 
00051     numMulticast = numLocalDeliver = numDropped = numUnroutable = numForwarded = 0;
00052 
00053     WATCH(numMulticast);
00054     WATCH(numLocalDeliver);
00055     WATCH(numDropped);
00056     WATCH(numUnroutable);
00057     WATCH(numForwarded);
00058 }
00059 
00060 void IP::updateDisplayString()
00061 {
00062     char buf[80] = "";
00063     if (numForwarded>0) sprintf(buf+strlen(buf), "fwd:%d ", numForwarded);
00064     if (numLocalDeliver>0) sprintf(buf+strlen(buf), "up:%d ", numLocalDeliver);
00065     if (numMulticast>0) sprintf(buf+strlen(buf), "mcast:%d ", numMulticast);
00066     if (numDropped>0) sprintf(buf+strlen(buf), "DROP:%d ", numDropped);
00067     if (numUnroutable>0) sprintf(buf+strlen(buf), "UNROUTABLE:%d ", numUnroutable);
00068     getDisplayString().setTagArg("t",0,buf);
00069 }
00070 
00071 void IP::endService(cPacket *msg)
00072 {
00073     if (msg->getArrivalGate()->isName("transportIn"))
00074     {
00075         handleMessageFromHL( msg );
00076     }
00077     else if (dynamic_cast<ARPPacket *>(msg))
00078     {
00079         // dispatch ARP packets to ARP
00080         handleARP((ARPPacket *)msg);
00081     }
00082     else
00083     {
00084         IPDatagram *dgram = check_and_cast<IPDatagram *>(msg);
00085         handlePacketFromNetwork(dgram);
00086     }
00087 
00088     if (ev.isGUI())
00089         updateDisplayString();
00090 }
00091 
00092 InterfaceEntry *IP::getSourceInterfaceFrom(cPacket *msg)
00093 {
00094     cGate *g = msg->getArrivalGate();
00095     return g ? ift->getInterfaceByNetworkLayerGateIndex(g->getIndex()) : NULL;
00096 }
00097 
00098 void IP::handlePacketFromNetwork(IPDatagram *datagram)
00099 {
00100     //
00101     // "Prerouting"
00102     //
00103 
00104     // check for header biterror
00105     if (datagram->hasBitError())
00106     {
00107         // probability of bit error in header = size of header / size of total message
00108         // (ignore bit error if in payload)
00109         double relativeHeaderLength = datagram->getHeaderLength() / (double)datagram->getByteLength();
00110         if (dblrand() <= relativeHeaderLength)
00111         {
00112             EV << "bit error found, sending ICMP_PARAMETER_PROBLEM\n";
00113             icmpAccess.get()->sendErrorMessage(datagram, ICMP_PARAMETER_PROBLEM, 0);
00114             return;
00115         }
00116     }
00117 
00118     // remove control info
00119     delete datagram->removeControlInfo();
00120 
00121     // hop counter decrement; FIXME but not if it will be locally delivered
00122     datagram->setTimeToLive(datagram->getTimeToLive()-1);
00123 
00124     // route packet
00125     if (!datagram->getDestAddress().isMulticast())
00126         routePacket(datagram, NULL, false);
00127     else
00128         routeMulticastPacket(datagram, NULL, getSourceInterfaceFrom(datagram));
00129 }
00130 
00131 void IP::handleARP(ARPPacket *msg)
00132 {
00133     // FIXME hasBitError() check  missing!
00134 
00135     // delete old control info
00136     delete msg->removeControlInfo();
00137 
00138     // dispatch ARP packets to ARP and let it know the gate index it arrived on
00139     InterfaceEntry *fromIE = getSourceInterfaceFrom(msg);
00140     ASSERT(fromIE);
00141 
00142     IPRoutingDecision *routingDecision = new IPRoutingDecision();
00143     routingDecision->setInterfaceId(fromIE->getInterfaceId());
00144     msg->setControlInfo(routingDecision);
00145 
00146     send(msg, queueOutGate);
00147 }
00148 
00149 void IP::handleReceivedICMP(ICMPMessage *msg)
00150 {
00151     switch (msg->getType())
00152     {
00153         case ICMP_REDIRECT: // TODO implement redirect handling
00154         case ICMP_DESTINATION_UNREACHABLE:
00155         case ICMP_TIME_EXCEEDED:
00156         case ICMP_PARAMETER_PROBLEM: {
00157             // ICMP errors are delivered to the appropriate higher layer protocol
00158             IPDatagram *bogusPacket = check_and_cast<IPDatagram *>(msg->getEncapsulatedMsg());
00159             int protocol = bogusPacket->getTransportProtocol();
00160             int gateindex = mapping.getOutputGateForProtocol(protocol);
00161             send(msg, "transportOut", gateindex);
00162             break;
00163         }
00164         default: {
00165             // all others are delivered to ICMP: ICMP_ECHO_REQUEST, ICMP_ECHO_REPLY,
00166             // ICMP_TIMESTAMP_REQUEST, ICMP_TIMESTAMP_REPLY, etc.
00167             int gateindex = mapping.getOutputGateForProtocol(IP_PROT_ICMP);
00168             send(msg, "transportOut", gateindex);
00169         }
00170     }
00171 }
00172 
00173 void IP::handleMessageFromHL(cPacket *msg)
00174 {
00175     // if no interface exists, do not send datagram
00176     if (ift->getNumInterfaces() == 0)
00177     {
00178         EV << "No interfaces exist, dropping packet\n";
00179         delete msg;
00180         return;
00181     }
00182 
00183     // encapsulate and send
00184     InterfaceEntry *destIE; // will be filled in by encapsulate()
00185     IPDatagram *datagram = encapsulate(msg, destIE);
00186 
00187     // route packet
00188     if (!datagram->getDestAddress().isMulticast())
00189         routePacket(datagram, destIE, true);
00190     else
00191         routeMulticastPacket(datagram, destIE, NULL);
00192 }
00193 
00194 void IP::routePacket(IPDatagram *datagram, InterfaceEntry *destIE, bool fromHL)
00195 {
00196     // TBD add option handling code here
00197 
00198     IPAddress destAddr = datagram->getDestAddress();
00199 
00200     EV << "Routing datagram `" << datagram->getName() << "' with dest=" << destAddr << ": ";
00201 
00202     // check for local delivery
00203     if (rt->isLocalAddress(destAddr))
00204     {
00205         EV << "local delivery\n";
00206         if (datagram->getSrcAddress().isUnspecified())
00207             datagram->setSrcAddress(destAddr); // allows two apps on the same host to communicate
00208         numLocalDeliver++;
00209         reassembleAndDeliver(datagram);
00210         return;
00211     }
00212 
00213     // if datagram arrived from input gate and IP_FORWARD is off, delete datagram
00214     if (!fromHL && !rt->isIPForwardingEnabled())
00215     {
00216         EV << "forwarding off, dropping packet\n";
00217         numDropped++;
00218         delete datagram;
00219         return;
00220     }
00221 
00222     IPAddress nextHopAddr;
00223 
00224     // if output port was explicitly requested, use that, otherwise use IP routing
00225     if (destIE)
00226     {
00227         EV << "using manually specified output interface " << destIE->getName() << "\n";
00228         // and nextHopAddr remains unspecified
00229     }
00230     else
00231     {
00232         // use IP routing (lookup in routing table)
00233         const IPRoute *re = rt->findBestMatchingRoute(destAddr);
00234 
00235         // error handling: destination address does not exist in routing table:
00236         // notify ICMP, throw packet away and continue
00237         if (re==NULL)
00238         {
00239             EV << "unroutable, sending ICMP_DESTINATION_UNREACHABLE\n";
00240             numUnroutable++;
00241             icmpAccess.get()->sendErrorMessage(datagram, ICMP_DESTINATION_UNREACHABLE, 0);
00242             return;
00243         }
00244 
00245         // extract interface and next-hop address from routing table entry
00246         destIE = re->getInterface();
00247         nextHopAddr = re->getGateway();
00248     }
00249 
00250     // set datagram source address if not yet set
00251     if (datagram->getSrcAddress().isUnspecified())
00252         datagram->setSrcAddress(destIE->ipv4Data()->getIPAddress());
00253 
00254     // default: send datagram to fragmentation
00255     EV << "output interface is " << destIE->getName() << ", next-hop address: " << nextHopAddr << "\n";
00256     numForwarded++;
00257 
00258     //
00259     // fragment and send the packet
00260     //
00261     fragmentAndSend(datagram, destIE, nextHopAddr);
00262 }
00263 
00264 void IP::routeMulticastPacket(IPDatagram *datagram, InterfaceEntry *destIE, InterfaceEntry *fromIE)
00265 {
00266     IPAddress destAddr = datagram->getDestAddress();
00267     EV << "Routing multicast datagram `" << datagram->getName() << "' with dest=" << destAddr << "\n";
00268 
00269     numMulticast++;
00270 
00271     // DVMRP: process datagram only if sent locally or arrived on the shortest
00272     // route (provided routing table already contains srcAddr); otherwise
00273     // discard and continue.
00274     InterfaceEntry *shortestPathIE = rt->getInterfaceForDestAddr(datagram->getSrcAddress());
00275     if (fromIE!=NULL && shortestPathIE!=NULL && fromIE!=shortestPathIE)
00276     {
00277         // FIXME count dropped
00278         EV << "Packet dropped.\n";
00279         delete datagram;
00280         return;
00281     }
00282 
00283     // if received from the network...
00284     if (fromIE!=NULL)
00285     {
00286         // check for local delivery
00287         if (rt->isLocalMulticastAddress(destAddr))
00288         {
00289             IPDatagram *datagramCopy = (IPDatagram *) datagram->dup();
00290 
00291             // FIXME code from the MPLS model: set packet dest address to routerId (???)
00292             datagramCopy->setDestAddress(rt->getRouterId());
00293 
00294             reassembleAndDeliver(datagramCopy);
00295         }
00296 
00297         // don't forward if IP forwarding is off
00298         if (!rt->isIPForwardingEnabled())
00299         {
00300             delete datagram;
00301             return;
00302         }
00303 
00304         // don't forward if dest address is link-scope
00305         if (destAddr.isLinkLocalMulticast())
00306         {
00307             delete datagram;
00308             return;
00309         }
00310 
00311     }
00312 
00313     // routed explicitly via IP_MULTICAST_IF
00314     if (destIE!=NULL)
00315     {
00316         ASSERT(datagram->getDestAddress().isMulticast());
00317 
00318         EV << "multicast packet explicitly routed via output interface " << destIE->getName() << endl;
00319 
00320         // set datagram source address if not yet set
00321         if (datagram->getSrcAddress().isUnspecified())
00322             datagram->setSrcAddress(destIE->ipv4Data()->getIPAddress());
00323 
00324         // send
00325         fragmentAndSend(datagram, destIE, datagram->getDestAddress());
00326 
00327         return;
00328     }
00329 
00330     // now: routing
00331     MulticastRoutes routes = rt->getMulticastRoutesFor(destAddr);
00332     if (routes.size()==0)
00333     {
00334         // no destination: delete datagram
00335         delete datagram;
00336     }
00337     else
00338     {
00339         // copy original datagram for multiple destinations
00340         for (unsigned int i=0; i<routes.size(); i++)
00341         {
00342             InterfaceEntry *destIE = routes[i].interf;
00343 
00344             // don't forward to input port
00345             if (destIE && destIE!=fromIE)
00346             {
00347                 IPDatagram *datagramCopy = (IPDatagram *) datagram->dup();
00348 
00349                 // set datagram source address if not yet set
00350                 if (datagramCopy->getSrcAddress().isUnspecified())
00351                     datagramCopy->setSrcAddress(destIE->ipv4Data()->getIPAddress());
00352 
00353                 // send
00354                 IPAddress nextHopAddr = routes[i].gateway;
00355                 fragmentAndSend(datagramCopy, destIE, nextHopAddr);
00356             }
00357         }
00358 
00359         // only copies sent, delete original datagram
00360         delete datagram;
00361     }
00362 }
00363 
00364 void IP::reassembleAndDeliver(IPDatagram *datagram)
00365 {
00366     // reassemble the packet (if fragmented)
00367     if (datagram->getFragmentOffset()!=0 || datagram->getMoreFragments())
00368     {
00369         EV << "Datagram fragment: offset=" << datagram->getFragmentOffset()
00370            << ", MORE=" << (datagram->getMoreFragments() ? "true" : "false") << ".\n";
00371 
00372         // erase timed out fragments in fragmentation buffer; check every 10 seconds max
00373         if (simTime() >= lastCheckTime + 10)
00374         {
00375             lastCheckTime = simTime();
00376             fragbuf.purgeStaleFragments(simTime()-fragmentTimeoutTime);
00377         }
00378 
00379         datagram = fragbuf.addFragment(datagram, simTime());
00380         if (!datagram)
00381         {
00382             EV << "No complete datagram yet.\n";
00383             return;
00384         }
00385         EV << "This fragment completes the datagram.\n";
00386     }
00387 
00388     // decapsulate and send on appropriate output gate
00389     int protocol = datagram->getTransportProtocol();
00390     cPacket *packet = decapsulateIP(datagram);
00391 
00392     if (protocol==IP_PROT_ICMP)
00393     {
00394         // incoming ICMP packets are handled specially
00395         handleReceivedICMP(check_and_cast<ICMPMessage *>(packet));
00396     }
00397     else if (protocol==IP_PROT_IP)
00398     {
00399         // tunnelled IP packets are handled separately
00400         send(packet, "preRoutingOut");
00401     }
00402     else
00403     {
00404         int gateindex = mapping.getOutputGateForProtocol(protocol);
00405         send(packet, "transportOut", gateindex);
00406     }
00407 }
00408 
00409 cPacket *IP::decapsulateIP(IPDatagram *datagram)
00410 {
00411     // decapsulate transport packet
00412     InterfaceEntry *fromIE = getSourceInterfaceFrom(datagram);
00413     cPacket *packet = datagram->decapsulate();
00414 
00415     // create and fill in control info
00416     IPControlInfo *controlInfo = new IPControlInfo();
00417     controlInfo->setProtocol(datagram->getTransportProtocol());
00418     controlInfo->setSrcAddr(datagram->getSrcAddress());
00419     controlInfo->setDestAddr(datagram->getDestAddress());
00420     controlInfo->setDiffServCodePoint(datagram->getDiffServCodePoint());
00421     controlInfo->setInterfaceId(fromIE ? fromIE->getInterfaceId() : -1);
00422 
00423     // original IP datagram might be needed in upper layers to send back ICMP error message
00424     controlInfo->setOrigDatagram(datagram);
00425 
00426     // attach control info
00427     packet->setControlInfo(controlInfo);
00428 
00429     return packet;
00430 }
00431 
00432 
00433 void IP::fragmentAndSend(IPDatagram *datagram, InterfaceEntry *ie, IPAddress nextHopAddr)
00434 {
00435     int mtu = ie->getMTU();
00436 
00437     // check if datagram does not require fragmentation
00438     if (datagram->getByteLength() <= mtu)
00439     {
00440         sendDatagramToOutput(datagram, ie, nextHopAddr);
00441         return;
00442     }
00443 
00444     int headerLength = datagram->getHeaderLength();
00445     int payload = datagram->getByteLength() - headerLength;
00446 
00447     int noOfFragments =
00448         int(ceil((float(payload)/mtu) /
00449         (1-float(headerLength)/mtu) ) ); // FIXME ???
00450 
00451     // if "don't fragment" bit is set, throw datagram away and send ICMP error message
00452     if (datagram->getDontFragment() && noOfFragments>1)
00453     {
00454         EV << "datagram larger than MTU and don't fragment bit set, sending ICMP_DESTINATION_UNREACHABLE\n";
00455         icmpAccess.get()->sendErrorMessage(datagram, ICMP_DESTINATION_UNREACHABLE,
00456                                                      ICMP_FRAGMENTATION_ERROR_CODE);
00457         return;
00458     }
00459 
00460     // create and send fragments
00461     EV << "Breaking datagram into " << noOfFragments << " fragments\n";
00462     std::string fragMsgName = datagram->getName();
00463     fragMsgName += "-frag";
00464 
00465     // FIXME revise this!
00466     for (int i=0; i<noOfFragments; i++)
00467     {
00468         // FIXME is it ok that full encapsulated packet travels in every datagram fragment?
00469         // should better travel in the last fragment only. Cf. with reassembly code!
00470         IPDatagram *fragment = (IPDatagram *) datagram->dup();
00471         fragment->setName(fragMsgName.c_str());
00472 
00473         // total_length equal to mtu, except for last fragment;
00474         // "more fragments" bit is unchanged in the last fragment, otherwise true
00475         if (i != noOfFragments-1)
00476         {
00477             fragment->setMoreFragments(true);
00478             fragment->setByteLength(mtu);
00479         }
00480         else
00481         {
00482             // size of last fragment
00483             int bytes = datagram->getByteLength() - (noOfFragments-1) * (mtu - datagram->getHeaderLength());
00484             fragment->setByteLength(bytes);
00485         }
00486         fragment->setFragmentOffset( i*(mtu - datagram->getHeaderLength()) );
00487 
00488         sendDatagramToOutput(fragment, ie, nextHopAddr);
00489     }
00490 
00491     delete datagram;
00492 }
00493 
00494 
00495 IPDatagram *IP::encapsulate(cPacket *transportPacket, InterfaceEntry *&destIE)
00496 {
00497     IPControlInfo *controlInfo = check_and_cast<IPControlInfo*>(transportPacket->removeControlInfo());
00498     IPDatagram *datagram = encapsulate(transportPacket, destIE, controlInfo);
00499     delete controlInfo;
00500     return datagram;
00501 }
00502 
00503 IPDatagram *IP::encapsulate(cPacket *transportPacket, InterfaceEntry *&destIE, IPControlInfo *controlInfo)
00504 {
00505     IPDatagram *datagram = createIPDatagram(transportPacket->getName());
00506     datagram->setByteLength(IP_HEADER_BYTES);
00507     datagram->encapsulate(transportPacket);
00508 
00509     // set source and destination address
00510     IPAddress dest = controlInfo->getDestAddr();
00511     datagram->setDestAddress(dest);
00512 
00513     // IP_MULTICAST_IF option, but allow interface selection for unicast packets as well
00514     destIE = ift->getInterfaceById(controlInfo->getInterfaceId());
00515 
00516     IPAddress src = controlInfo->getSrcAddr();
00517 
00518     // when source address was given, use it; otherwise it'll get the address
00519     // of the outgoing interface after routing
00520     if (!src.isUnspecified())
00521     {
00522         // if interface parameter does not match existing interface, do not send datagram
00523         if (rt->getInterfaceByAddress(src)==NULL)
00524             opp_error("Wrong source address %s in (%s)%s: no interface with such address",
00525                       src.str().c_str(), transportPacket->getClassName(), transportPacket->getFullName());
00526         datagram->setSrcAddress(src);
00527     }
00528 
00529     // set other fields
00530     datagram->setDiffServCodePoint(controlInfo->getDiffServCodePoint());
00531 
00532     datagram->setIdentification(curFragmentId++);
00533     datagram->setMoreFragments(false);
00534     datagram->setDontFragment (controlInfo->getDontFragment());
00535     datagram->setFragmentOffset(0);
00536 
00537     short ttl;
00538     if (controlInfo->getTimeToLive() > 0)
00539         ttl = controlInfo->getTimeToLive();
00540     else if (datagram->getDestAddress().isLinkLocalMulticast())
00541         ttl = 1;
00542     else if (datagram->getDestAddress().isMulticast())
00543         ttl = defaultMCTimeToLive;
00544     else
00545         ttl = defaultTimeToLive;
00546 
00547     datagram->setTimeToLive(ttl);
00548     datagram->setTransportProtocol(controlInfo->getProtocol());
00549 
00550     // setting IP options is currently not supported
00551 
00552     return datagram;
00553 }
00554 
00555 IPDatagram *IP::createIPDatagram(const char *name)
00556 {
00557     return new IPDatagram(name);
00558 }
00559 
00560 void IP::sendDatagramToOutput(IPDatagram *datagram, InterfaceEntry *ie, IPAddress nextHopAddr)
00561 {
00562     // hop counter check
00563     if (datagram->getTimeToLive() <= 0)
00564     {
00565         // drop datagram, destruction responsibility in ICMP
00566         EV << "datagram TTL reached zero, sending ICMP_TIME_EXCEEDED\n";
00567         icmpAccess.get()->sendErrorMessage(datagram, ICMP_TIME_EXCEEDED, 0);
00568         return;
00569     }
00570 
00571     // send out datagram to ARP, with control info attached
00572     IPRoutingDecision *routingDecision = new IPRoutingDecision();
00573     routingDecision->setInterfaceId(ie->getInterfaceId());
00574     routingDecision->setNextHopAddr(nextHopAddr);
00575     datagram->setControlInfo(routingDecision);
00576 
00577     send(datagram, queueOutGate);
00578 }
00579 
00580