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