IPv6.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Andras Varga
00003 // Copyright (C) 2005 Wei Yang, Ng
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public License
00016 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 
00020 #include <omnetpp.h>
00021 #include "IPv6.h"
00022 #include "InterfaceTableAccess.h"
00023 #include "RoutingTable6Access.h"
00024 #include "ICMPv6Access.h"
00025 #include "IPv6NeighbourDiscoveryAccess.h"
00026 #include "IPv6ControlInfo.h"
00027 #include "IPv6NDMessage_m.h"
00028 #include "Ieee802Ctrl_m.h"
00029 #include "ICMPv6Message_m.h"
00030 
00031 
00032 #define FRAGMENT_TIMEOUT 60   // 60 sec, from IPv6 RFC
00033 
00034 
00035 Define_Module(IPv6);
00036 
00037 void IPv6::initialize()
00038 {
00039     QueueBase::initialize();
00040 
00041     ift = InterfaceTableAccess().get();
00042     rt = RoutingTable6Access().get();
00043     nd = IPv6NeighbourDiscoveryAccess().get();
00044     icmp = ICMPv6Access().get();
00045 
00046     mapping.parseProtocolMapping(par("protocolMapping"));
00047 
00048     curFragmentId = 0;
00049     lastCheckTime = 0;
00050     fragbuf.init(icmp);
00051 
00052     numMulticast = numLocalDeliver = numDropped = numUnroutable = numForwarded = 0;
00053 
00054     WATCH(numMulticast);
00055     WATCH(numLocalDeliver);
00056     WATCH(numDropped);
00057     WATCH(numUnroutable);
00058     WATCH(numForwarded);
00059 }
00060 
00061 void IPv6::updateDisplayString()
00062 {
00063     char buf[80] = "";
00064     if (numForwarded>0) sprintf(buf+strlen(buf), "fwd:%d ", numForwarded);
00065     if (numLocalDeliver>0) sprintf(buf+strlen(buf), "up:%d ", numLocalDeliver);
00066     if (numMulticast>0) sprintf(buf+strlen(buf), "mcast:%d ", numMulticast);
00067     if (numDropped>0) sprintf(buf+strlen(buf), "DROP:%d ", numDropped);
00068     if (numUnroutable>0) sprintf(buf+strlen(buf), "UNROUTABLE:%d ", numUnroutable);
00069     getDisplayString().setTagArg("t",0,buf);
00070 }
00071 
00072 void IPv6::endService(cPacket *msg)
00073 {
00074     if (msg->getArrivalGate()->isName("transportIn") ||
00075        (msg->getArrivalGate()->isName("ndIn") && dynamic_cast<IPv6NDMessage*>(msg)) ||
00076        (msg->getArrivalGate()->isName("icmpIn") && dynamic_cast<ICMPv6Message*>(msg)))//Added this for ICMP msgs from ICMP module-WEI
00077     {
00078         // packet from upper layers or ND: encapsulate and send out
00079         handleMessageFromHL( msg );
00080     }
00081     else
00082     {
00083         // datagram from network or from ND: localDeliver and/or route
00084         IPv6Datagram *dgram = check_and_cast<IPv6Datagram *>(msg);
00085         handleDatagramFromNetwork(dgram);
00086     }
00087 
00088     if (ev.isGUI())
00089         updateDisplayString();
00090 }
00091 
00092 InterfaceEntry *IPv6::getSourceInterfaceFrom(cPacket *msg)
00093 {
00094     cGate *g = msg->getArrivalGate();
00095     return g ? ift->getInterfaceByNetworkLayerGateIndex(g->getIndex()) : NULL;
00096 }
00097 
00098 void IPv6::handleDatagramFromNetwork(IPv6Datagram *datagram)
00099 {
00100     // check for header biterror
00101     if (datagram->hasBitError())
00102     {
00103         EV << "bit error\n";return; // revise!
00104 /*FIXME revise
00105         // probability of bit error in header = size of header / size of total message
00106         // (ignore bit error if in payload)
00107         double relativeHeaderLength = datagram->getHeaderLength() / (double)datagram->getByteLength();
00108         if (dblrand() <= relativeHeaderLength)
00109         {
00110             EV << "bit error found, sending ICMP_PARAMETER_PROBLEM\n";
00111             icmp->sendErrorMessage(datagram, ICMP_PARAMETER_PROBLEM, 0);
00112             return;
00113         }
00114 */
00115     }
00116 
00117     // remove control info
00118     delete datagram->removeControlInfo();
00119 
00120     // routepacket
00121     if (!datagram->getDestAddress().isMulticast())
00122         routePacket(datagram, NULL, false);
00123     else
00124         routeMulticastPacket(datagram, NULL, getSourceInterfaceFrom(datagram));
00125 }
00126 
00127 void IPv6::handleMessageFromHL(cPacket *msg)
00128 {
00129     // if no interface exists, do not send datagram
00130     if (ift->getNumInterfaces() == 0)
00131     {
00132         EV << "No interfaces exist, dropping packet\n";
00133         delete msg;
00134         return;
00135     }
00136 
00137     // encapsulate upper-layer packet into IPv6Datagram
00138     InterfaceEntry *destIE; // to be filled in by encapsulate()
00139     IPv6Datagram *datagram = encapsulate(msg, destIE);
00140 
00141     // possibly fragment (in IPv6, only the source node does that), then route it
00142     fragmentAndRoute(datagram, destIE);
00143 }
00144 
00145 void IPv6::fragmentAndRoute(IPv6Datagram *datagram, InterfaceEntry *destIE)
00146 {
00147 /*
00148 FIXME implement fragmentation here.
00149    1. determine output interface
00150    2. compare packet size with interface MTU
00151    3. if bigger, do fragmentation
00152          int mtu = ift->interfaceByPortNo(outputGateIndex)->getMTU();
00153 */
00154     EV << "fragmentation not implemented yet\n";
00155 
00156     // route packet
00157     if (destIE!=NULL)
00158         sendDatagramToOutput(datagram, destIE, MACAddress::BROADCAST_ADDRESS); // FIXME what MAC address to use?
00159     else if (!datagram->getDestAddress().isMulticast())
00160         routePacket(datagram, destIE, true);
00161     else
00162         routeMulticastPacket(datagram, destIE, NULL);
00163 }
00164 
00165 void IPv6::routePacket(IPv6Datagram *datagram, InterfaceEntry *destIE, bool fromHL)
00166 {
00167     // TBD add option handling code here
00168     IPv6Address destAddress = datagram->getDestAddress();
00169 
00170     EV << "Routing datagram `" << datagram->getName() << "' with dest=" << destAddress << ": ";
00171 
00172     // local delivery of unicast packets
00173     if (rt->isLocalAddress(destAddress))
00174     {
00175         EV << "local delivery\n";
00176         if (datagram->getSrcAddress().isUnspecified())
00177             datagram->setSrcAddress(destAddress); // allows two apps on the same host to communicate
00178         numLocalDeliver++;
00179         isLocalAddress(datagram);
00180         return;
00181     }
00182 
00183     if (!fromHL)
00184     {
00185         // if datagram arrived from input gate and IP forwarding is off, delete datagram
00186         //yes but datagrams from the ND module is getting dropped too!-WEI
00187         //so we add a 2nd condition
00188         // FIXME rewrite code so that condition is cleaner --Andras
00189         //if (!rt->isRouter())
00190         if (!rt->isRouter() && !(datagram->getArrivalGate()->isName("ndIn")))
00191         {
00192             EV << "forwarding is off, dropping packet\n";
00193             numDropped++;
00194             delete datagram;
00195             return;
00196         }
00197 
00198         // don't forward link-local addresses or weaker
00199         if (destAddress.isLinkLocal() || destAddress.isLoopback())
00200         {
00201             EV << "dest address is link-local (or weaker) scope, doesn't get forwarded\n";
00202             delete datagram;
00203             return;
00204         }
00205 
00206         // hop counter decrement: only if datagram arrived from network, and will be
00207         // sent out to the network (hoplimit check will be done just before sending
00208         // out datagram)
00209         // TBD: in IPv4, arrange TTL check like this
00210         datagram->setHopLimit(datagram->getHopLimit()-1);
00211     }
00212 
00213     // routing
00214     // first try destination cache
00215     int interfaceId;
00216     IPv6Address nextHop = rt->lookupDestCache(destAddress, interfaceId);
00217     if (interfaceId==-1)
00218     {
00219         // address not in destination cache: do longest prefix match in routing table
00220         const IPv6Route *route = rt->doLongestPrefixMatch(destAddress);
00221         if (!route)
00222         {
00223             if (rt->isRouter())
00224             {
00225                 EV << "unroutable, sending ICMPv6_DESTINATION_UNREACHABLE\n";
00226                 numUnroutable++;
00227                 icmp->sendErrorMessage(datagram, ICMPv6_DESTINATION_UNREACHABLE, 0); // FIXME check ICMP 'code'
00228             }
00229             else // host
00230             {
00231                 EV << "no match in routing table, passing datagram to Neighbour Discovery module for default router selection\n";
00232                 send(datagram, "ndOut");
00233             }
00234             return;
00235         }
00236         interfaceId = route->getInterfaceId();
00237         nextHop = route->getNextHop();
00238         if (nextHop.isUnspecified())
00239             nextHop = destAddress;  // next hop is the host itself
00240 
00241         // add result into destination cache
00242         rt->updateDestCache(destAddress, nextHop, interfaceId);
00243     }
00244 
00245     InterfaceEntry *ie = ift->getInterfaceById(interfaceId);
00246     ASSERT(ie!=NULL);
00247     EV << "next hop for " << destAddress << " is " << nextHop << ", interface " << ie->getName() << "\n";
00248     ASSERT(!nextHop.isUnspecified());
00249 
00250     MACAddress macAddr = nd->resolveNeighbour(nextHop, interfaceId);
00251     if (macAddr.isUnspecified())
00252     {
00253         EV << "no link-layer address for next hop yet, passing datagram to Neighbour Discovery module\n";
00254         send(datagram, "ndOut");
00255         return;
00256     }
00257     EV << "link-layer address: " << macAddr << "\n";
00258 
00259     // set datagram source address if not yet set
00260     if (datagram->getSrcAddress().isUnspecified())
00261     {
00262         const IPv6Address& srcAddr = ie->ipv6Data()->getPreferredAddress();
00263         ASSERT(!srcAddr.isUnspecified()); // FIXME what if we don't have an address yet?
00264         datagram->setSrcAddress(srcAddr);
00265     }
00266 
00267     // send out datagram
00268     numForwarded++;
00269     sendDatagramToOutput(datagram, ie, macAddr);
00270 }
00271 
00272 void IPv6::routeMulticastPacket(IPv6Datagram *datagram, InterfaceEntry *destIE, InterfaceEntry *fromIE)
00273 {
00274     const IPv6Address& destAddr = datagram->getDestAddress();
00275 
00276     EV << "destination address " << destAddr << " is multicast, doing multicast routing\n";
00277     numMulticast++;
00278 
00279     // if received from the network...
00280     if (fromIE!=NULL)
00281     {
00282         // deliver locally
00283         if (rt->isLocalAddress(destAddr))
00284         {
00285             EV << "local delivery of multicast packet\n";
00286             numLocalDeliver++;
00287             isLocalAddress((IPv6Datagram *)datagram->dup());
00288         }
00289 
00290         // if datagram arrived from input gate and IP forwarding is off, delete datagram
00291         if (!rt->isRouter())
00292         {
00293             EV << "forwarding is off\n";
00294             delete datagram;
00295             return;
00296         }
00297 
00298         // make sure scope of multicast address is large enough to be forwarded to other links
00299         if (destAddr.getMulticastScope()<=2)
00300         {
00301             EV << "multicast dest address is link-local (or smaller) scope\n";
00302             delete datagram;
00303             return;
00304         }
00305 
00306         // hop counter decrement: only if datagram arrived from network, and will be
00307         // sent out to the network (hoplimit check will be done just before sending
00308         // out datagram)
00309         // TBD: in IPv4, arrange TTL check like this
00310         datagram->setHopLimit(datagram->getHopLimit()-1);
00311     }
00312 
00313     // for now, we just send it out on every interface except on which it came. FIXME better!!!
00314     EV << "sending out datagram on every interface (except incoming one)\n";
00315     for (int i=0; i<ift->getNumInterfaces(); i++)
00316     {
00317         InterfaceEntry *ie = ift->getInterface(i);
00318         if (fromIE!=ie)
00319             sendDatagramToOutput((IPv6Datagram *)datagram->dup(), ie, MACAddress::BROADCAST_ADDRESS);
00320     }
00321     delete datagram;
00322 
00323 /* FIXME implement handling of multicast
00324 
00325     According to Gopi: "multicast routing table" should map
00326        srcAddr+multicastDestAddr to a set of next hops (interface+nexthopAddr)
00327     Where srcAddr is the multicast server, and destAddr sort of narrows it down to a given stream
00328 
00329     // FIXME multicast-->tunneling link (present in original IPSuite) missing from here
00330 
00331     // DVMRP: process datagram only if sent locally or arrived on the shortest
00332     // route (provided routing table already contains srcAddr); otherwise
00333     // discard and continue.
00334     int inputGateIndex = datagram->getArrivalGate() ? datagram->getArrivalGate()->getIndex() : -1;
00335     int shortestPathInputGateIndex = rt->outputGateIndexNo(datagram->getSrcAddress());
00336     if (inputGateIndex!=-1 && shortestPathInputGateIndex!=-1 && inputGateIndex!=shortestPathInputGateIndex)
00337     {
00338         // FIXME count dropped
00339         EV << "Packet dropped.\n";
00340         delete datagram;
00341         return;
00342     }
00343 
00344     // check for local delivery
00345     IPv6Address destAddress = datagram->getDestAddress();
00346     if (rt->isLocalMulticastAddress(destAddress))
00347     {
00348         IPv6Datagram *datagramCopy = (IPv6Datagram *) datagram->dup();
00349 
00350         // FIXME code from the MPLS model: set packet dest address to routerId (???)
00351         datagramCopy->setDestAddress(rt->getRouterId());
00352 
00353         isLocalAddress(datagramCopy);
00354     }
00355 
00356     // forward datagram only if IP forward is enabled, or sent locally
00357     if (inputGateIndex!=-1 && !rt->isRouter())
00358     {
00359         delete datagram;
00360         return;
00361     }
00362 
00363     MulticastRoutes routes = rt->getMulticastRoutesFor(destAddress);
00364     if (routes.size()==0)
00365     {
00366         // no destination: delete datagram
00367         delete datagram;
00368     }
00369     else
00370     {
00371         // copy original datagram for multiple destinations
00372         for (unsigned int i=0; i<routes.size(); i++)
00373         {
00374             int outputGateIndex = routes[i].interf->outputGateIndex();
00375 
00376             // don't forward to input port
00377             if (outputGateIndex>=0 && outputGateIndex!=inputGateIndex)
00378             {
00379                 IPv6Datagram *datagramCopy = (IPv6Datagram *) datagram->dup();
00380 
00381                 // set datagram source address if not yet set
00382                 if (datagramCopy->getSrcAddress().isUnspecified())
00383                     datagramCopy->setSrcAddress(ift->interfaceByPortNo(outputGateIndex)->ipv6Data()->getIPAddress());
00384 
00385                 // send
00386                 IPv6Address nextHopAddr = routes[i].gateway;
00387                 sendDatagramToOutput(datagramCopy, outputGateIndex, macAddr);
00388             }
00389         }
00390 
00391         // only copies sent, delete original datagram
00392         delete datagram;
00393     }
00394 */
00395 }
00396 
00397 void IPv6::isLocalAddress(IPv6Datagram *datagram)
00398 {
00399 /* FIXME revise and complete defragmentation
00400     // Defragmentation. skip defragmentation if datagram is not fragmented
00401     if (datagram->getFragmentOffset()!=0 || datagram->getMoreFragments())
00402     {
00403         EV << "Datagram fragment: offset=" << datagram->getFragmentOffset()
00404            << ", MORE=" << (datagram->getMoreFragments() ? "true" : "false") << ".\n";
00405 
00406         // erase timed out fragments in fragmentation buffer; check every 10 seconds max
00407         if (simTime() >= lastCheckTime + 10)
00408         {
00409             lastCheckTime = simTime();
00410             fragbuf.purgeStaleFragments(simTime()-FRAGMENT_TIMEOUT);
00411         }
00412 
00413         datagram = fragbuf.addFragment(datagram, simTime());
00414         if (!datagram)
00415         {
00416             EV << "No complete datagram yet.\n";
00417             return;
00418         }
00419         EV << "This fragment completes the datagram.\n";
00420     }
00421 */
00422     // decapsulate and send on appropriate output gate
00423     int protocol = datagram->getTransportProtocol();
00424     cPacket *packet = decapsulate(datagram);
00425 
00426     if (protocol==IP_PROT_IPv6_ICMP && dynamic_cast<IPv6NDMessage*>(packet))
00427     {
00428         EV << "Neigbour Discovery packet: passing it to ND module\n";
00429         send(packet, "ndOut");
00430     }
00431     else if (protocol==IP_PROT_IPv6_ICMP && dynamic_cast<ICMPv6Message*>(packet))
00432     {
00433         EV << "ICMPv6 packet: passing it to ICMPv6 module\n";
00434         send(packet, "icmpOut");
00435     }//Added by WEI to forward ICMPv6 msgs to ICMPv6 module.
00436     else if (protocol==IP_PROT_IP || protocol==IP_PROT_IPv6)
00437     {
00438         EV << "Tunnelled IP datagram\n";
00439         // FIXME handle tunnelling
00440         error("tunnelling not yet implemented");
00441     }
00442     else
00443     {
00444         int gateindex = mapping.getOutputGateForProtocol(protocol);
00445         EV << "Protocol " << protocol << ", passing up on gate " << gateindex << "\n";
00446         //TODO: Indication of forward progress
00447         send(packet, "transportOut", gateindex);
00448     }
00449 }
00450 
00451 void IPv6::handleReceivedICMP(ICMPv6Message *msg)
00452 {
00453     switch (msg->getType())
00454     {
00455         case ICMPv6_REDIRECT:  // TODO implement redirect handling
00456         case ICMPv6_DESTINATION_UNREACHABLE:
00457         case ICMPv6_PACKET_TOO_BIG:
00458         case ICMPv6_TIME_EXCEEDED:
00459         case ICMPv6_PARAMETER_PROBLEM: {
00460             // ICMP errors are delivered to the appropriate higher layer protocols
00461             IPv6Datagram *bogusPacket = check_and_cast<IPv6Datagram *>(msg->getEncapsulatedMsg());
00462             int protocol = bogusPacket->getTransportProtocol();
00463             int gateindex = mapping.getOutputGateForProtocol(protocol);
00464             send(msg, "transportOut", gateindex);
00465             break;
00466         }
00467         default: {
00468             // all others are delivered to ICMP:
00469             // ICMPv6_ECHO_REQUEST, ICMPv6_ECHO_REPLY, ICMPv6_MLD_QUERY, ICMPv6_MLD_REPORT,
00470             // ICMPv6_MLD_DONE, ICMPv6_ROUTER_SOL, ICMPv6_ROUTER_AD, ICMPv6_NEIGHBOUR_SOL,
00471             // ICMPv6_NEIGHBOUR_AD, ICMPv6_MLDv2_REPORT
00472             int gateindex = mapping.getOutputGateForProtocol(IP_PROT_ICMP);
00473             send(msg, "transportOut", gateindex);
00474         }
00475      }
00476 }
00477 
00478 
00479 cPacket *IPv6::decapsulate(IPv6Datagram *datagram)
00480 {
00481     // decapsulate transport packet
00482     InterfaceEntry *fromIE = getSourceInterfaceFrom(datagram);
00483     cPacket *packet = datagram->decapsulate();
00484 
00485     // create and fill in control info
00486     IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00487     controlInfo->setProtocol(datagram->getTransportProtocol());
00488     controlInfo->setSrcAddr(datagram->getSrcAddress());
00489     controlInfo->setDestAddr(datagram->getDestAddress());
00490     controlInfo->setHopLimit(datagram->getHopLimit());
00491     controlInfo->setInterfaceId(fromIE ? fromIE->getInterfaceId() : -1);
00492 
00493     // original IP datagram might be needed in upper layers to send back ICMP error message
00494     controlInfo->setOrigDatagram(datagram);
00495 
00496     // attach control info
00497     packet->setControlInfo(controlInfo);
00498 
00499     return packet;
00500 }
00501 
00502 IPv6Datagram *IPv6::encapsulate(cPacket *transportPacket, InterfaceEntry *&destIE)
00503 {
00504     IPv6ControlInfo *controlInfo = check_and_cast<IPv6ControlInfo*>(transportPacket->removeControlInfo());
00505 
00506     IPv6Datagram *datagram = new IPv6Datagram(transportPacket->getName());
00507     datagram->setByteLength(datagram->calculateHeaderByteLength());
00508     datagram->encapsulate(transportPacket);
00509 
00510     // IPV6_MULTICAST_IF option, but allow interface selection for unicast packets as well
00511     destIE = ift->getInterfaceById(controlInfo->getInterfaceId());
00512 
00513     // set source and destination address
00514     IPv6Address dest = controlInfo->getDestAddr();
00515     datagram->setDestAddress(dest);
00516 
00517     IPv6Address src = controlInfo->getSrcAddr();
00518 
00519     // when source address was given, use it; otherwise it'll get the address
00520     // of the outgoing interface after routing
00521     if (!src.isUnspecified())
00522     {
00523         // if interface parameter does not match existing interface, do not send datagram
00524         if (rt->getInterfaceByAddress(src)==NULL)
00525             opp_error("Wrong source address %s in (%s)%s: no interface with such address",
00526                       src.str().c_str(), transportPacket->getClassName(), transportPacket->getFullName());
00527         datagram->setSrcAddress(src);
00528     }
00529 
00530     // set other fields
00531     datagram->setHopLimit(controlInfo->getHopLimit()>0 ? controlInfo->getHopLimit() : 32); //FIXME use iface hop limit instead of 32?
00532     datagram->setTransportProtocol(controlInfo->getProtocol());
00533     delete controlInfo;
00534 
00535     // setting IP options is currently not supported
00536 
00537     return datagram;
00538 }
00539 
00540 void IPv6::sendDatagramToOutput(IPv6Datagram *datagram, InterfaceEntry *ie, const MACAddress& macAddr)
00541 {
00542     // hop counter check
00543     if (datagram->getHopLimit() <= 0)
00544     {
00545         // drop datagram, destruction responsibility in ICMP
00546         EV << "datagram hopLimit reached zero, sending ICMPv6_TIME_EXCEEDED\n";
00547         icmp->sendErrorMessage(datagram, ICMPv6_TIME_EXCEEDED, 0); // FIXME check icmp 'code'
00548         return;
00549     }
00550 
00551     // in link layer uses MAC addresses (basically, not PPP), add control info
00552     if (!macAddr.isUnspecified())
00553     {
00554         Ieee802Ctrl *controlInfo = new Ieee802Ctrl();
00555         controlInfo->setDest(macAddr);
00556         datagram->setControlInfo(controlInfo);
00557     }
00558 
00559     // send datagram to link layer
00560     send(datagram, "queueOut", ie->getNetworkLayerGateIndex());
00561 }
00562 
00563