|
INET Framework for OMNeT++/OMNEST
|
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->getEncapsulatedPacket()); 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