tora.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the Computer Systems
00017  *      Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * Ported from CMU/Monarch's code
00035  *
00036  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tora/tora.cc,v 1.18 2005/08/28 23:23:03 tomh Exp $
00037  */
00038 
00039 #include <agent.h>
00040 #include <random.h>
00041 #include <trace.h>
00042 
00043 #include <ll.h>
00044 #include <priqueue.h>
00045 #include <tora/tora_packet.h>
00046 #include <tora/tora.h>
00047 
00048 #define LOG(s)                          \
00049     fprintf(stdout, "%s --- %s (index: %d, time: %f)\n",    \
00050         __PRETTY_FUNCTION__, (s), index, Scheduler::instance().clock())
00051 
00052 // #define DEBUG
00053 #define CURRENT_TIME    Scheduler::instance().clock()
00054 
00055 /* sec of spacing inserted between pkts when a bunch of packets are
00056    dumped into the link layer all at once.  Allows arp time to resolve
00057    dst, preventing the dumping of all but the last pkt on the floor */
00058 #define ARP_SEPARATION_DELAY 0.030
00059       
00060 
00061 /* ======================================================================
00062    TCL Hooks
00063    ====================================================================== */
00064 int hdr_tora::offset_;
00065 static class TORAHeaderClass : public PacketHeaderClass {
00066 public:
00067         TORAHeaderClass() : PacketHeaderClass("PacketHeader/TORA",
00068                           TORA_HDR_LEN) { 
00069         bind_offset(&hdr_tora::offset_);
00070     } 
00071 } class_toraAgent_hdr;
00072 
00073 static class toraAgentclass : public TclClass {
00074 public:
00075     toraAgentclass() : TclClass("Agent/TORA") {}
00076     TclObject* create(int argc, const char*const* argv) {
00077         assert(argc == 5);
00078         return (new toraAgent((nsaddr_t) atoi(argv[4])));
00079     }
00080 } class_toraAgent;
00081 
00082 
00083 /* ======================================================================
00084    toraAgent Class Functions
00085    ====================================================================== */
00086 toraAgent::toraAgent(nsaddr_t id) :
00087     rtAgent(id, PT_TORA),
00088     rqueue()
00089 {
00090     LIST_INIT(&dstlist);
00091     imepagent = 0;
00092     logtarget = 0;
00093     ifqueue = 0;
00094 }
00095 
00096 void
00097 toraAgent::reset()
00098 {
00099     Packet *p;
00100     while((p = rqueue.deque())) {
00101         drop(p,DROP_END_OF_SIMULATION);
00102     }
00103 }
00104 
00105 int
00106 toraAgent::command(int argc, const char*const* argv)
00107 {
00108     if(argc == 2) {
00109         Tcl& tcl = Tcl::instance();
00110 
00111         if(strncasecmp(argv[1], "id", 2) == 0) {
00112             tcl.resultf("%d", index);
00113             return TCL_OK;
00114         }
00115     }
00116     else if(argc == 3) {
00117 
00118         if(strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0 ) {
00119             logtarget = (Trace*) TclObject::lookup(argv[2]);
00120             if(logtarget == 0)
00121                 return TCL_ERROR;
00122             return TCL_OK;
00123         }
00124         else if(strcmp(argv[1], "drop-target") == 0) {
00125                 int stat = rqueue.command(argc,argv);
00126             if (stat != TCL_OK) return stat;
00127                     return Agent::command(argc, argv);
00128         }
00129         else if(strcmp(argv[1], "if-queue") == 0) {
00130             ifqueue = (PriQueue*) TclObject::lookup(argv[2]);
00131             if(ifqueue == 0)
00132                 return TCL_ERROR;
00133             return TCL_OK;
00134         }
00135         else if(strcmp(argv[1], "imep-agent") == 0) {
00136             imepagent = (imepAgent*) TclObject::lookup(argv[2]);
00137             if(imepagent == 0)
00138                 return TCL_ERROR;
00139             imepagent->imepRegister((rtAgent*) this);
00140             return TCL_OK;
00141         }
00142     }
00143     return Agent::command(argc, argv);
00144 }
00145 
00146 
00147 /* ======================================================================
00148    Destination Management Functions
00149    ====================================================================== */
00150 TORADest*
00151 toraAgent::dst_find(nsaddr_t id)
00152 {
00153     TORADest* td = dstlist.lh_first;
00154     for( ; td; td = td->link.le_next) {
00155         if(td->index == id)
00156             return td;
00157     }
00158     return 0;
00159 }
00160 
00161 TORADest*
00162 toraAgent::dst_add(nsaddr_t id)
00163 {
00164     TORADest *td = new TORADest(id, this);
00165     assert(td);
00166 
00167     LIST_INSERT_HEAD(&dstlist, td, link);
00168 
00169     int *nblist = 0, nbcnt = 0;
00170     imepagent->imepGetBiLinks(nblist, nbcnt);
00171 
00172     for(int i = 0; i < nbcnt; i++)
00173         (void) td->nb_add(nblist[i]);
00174 
00175     if(nblist) delete[] nblist;
00176 
00177     return td;
00178 }
00179 
00180 void
00181 toraAgent::dst_dump()
00182 {
00183     TORADest *td = dstlist.lh_first;
00184 
00185     for( ; td; td = td->link.le_next)
00186         td->dump();
00187 }
00188 
00189 
00190 /* ======================================================================
00191    Route Resolution
00192    ====================================================================== */
00193 void
00194 toraAgent::forward(Packet *p, nsaddr_t nexthop, Time delay)
00195 {
00196         struct hdr_cmn *ch = HDR_CMN(p);
00197 
00198 #ifdef TORA_DISALLOW_ROUTE_LOOP
00199         if(nexthop == ch->prev_hop_) {
00200         log_route_loop(ch->prev_hop_, nexthop);
00201                 drop(p, DROP_RTR_ROUTE_LOOP);
00202                 return;
00203         }
00204 #endif
00205         ch->next_hop() = nexthop;
00206         ch->prev_hop_ = ipaddr();
00207         ch->addr_type() = NS_AF_INET;
00208 
00209     // change the packet direction to DOWN
00210     ch->direction() = hdr_cmn::DOWN;
00211 
00212     if (0.0 == delay) {
00213       tora_output(p);
00214     } else {
00215       Scheduler::instance().schedule(target_, p, delay);
00216     }
00217 }
00218 
00219 
00220 void
00221 toraAgent::rt_resolve(Packet *p)
00222 {
00223     struct hdr_ip *ih = HDR_IP(p);
00224     TORADest *td;
00225     TORANeighbor *tn;
00226 
00227     td = dst_find(ih->daddr());
00228     if(td == 0) {
00229         td = dst_add(ih->daddr());
00230     }
00231 
00232     tn = td->nb_find_next_hop();
00233     if(tn == 0) {
00234         rqueue.enque(p);
00235 
00236         trace("T %.9f _%d_ tora enq %d->%d",
00237               Scheduler::instance().clock(), ipaddr(), 
00238               ih->saddr(), ih->daddr());
00239 
00240         if(!td->rt_req)
00241           { // if no QRY pending, then send one
00242             sendQRY(ih->daddr());
00243             td->time_tx_qry = CURRENT_TIME;
00244             td->rt_req = 1;
00245           }
00246     }
00247     else {
00248                 forward(p, tn->index);
00249     }
00250 }
00251 
00252 
00253 /* ======================================================================
00254    Incoming Packets
00255    ====================================================================== */
00256 void
00257 toraAgent::recv(Packet *p, Handler *)
00258 {
00259     struct hdr_cmn *ch = HDR_CMN(p);
00260     struct hdr_ip *ih = HDR_IP(p);
00261 
00262     assert(initialized());
00263 
00264     if(ch->ptype() == PT_TORA) {
00265         recvTORA(p);
00266         return;
00267     }
00268 
00269         /*
00270          *  Must be a packet I'm originating...
00271          */
00272     if(ih->saddr() == ipaddr() && ch->num_forwards() == 0) {
00273                 /*
00274                  *  Add the IP Header.
00275                  */
00276                 ch->size() += IP_HDR_LEN;
00277                 
00278                 ih->ttl_ = IP_DEF_TTL;
00279     }
00280 
00281 #ifdef TORA_DISALLOW_ROUTE_LOOP
00282         /*
00283          *  I received a packet that I sent.  Probably
00284          *  a routing loop.
00285          */
00286         else if(ih->saddr() == ipaddr()) {
00287                 drop(p, DROP_RTR_ROUTE_LOOP);
00288                 return;
00289         }
00290 #endif
00291     /*
00292      *  Packet I'm forwarding...
00293      */
00294     else {
00295         /*
00296          *  Check the TTL.  If it is zero, then discard.
00297          */
00298         if(--ih->ttl_ == 0) {
00299             drop(p, DROP_RTR_TTL);
00300             return;
00301         }
00302     }
00303 
00304     rt_resolve(p);
00305 }
00306 
00307 void
00308 toraAgent::recvTORA(Packet *p)
00309 {
00310     struct hdr_tora *th = HDR_TORA(p);
00311     TORADest *td;
00312     TORANeighbor *tn;
00313 
00314     /*
00315      * Fix the source IP address.
00316      */
00317     assert(HDR_IP (p)->sport() == RT_PORT);
00318     assert(HDR_IP (p)->dport() == RT_PORT);
00319 
00320     /*
00321      * Incoming Packets.
00322      */
00323     switch(th->th_type) {
00324         case TORATYPE_QRY:
00325             recvQRY(p);
00326             Packet::free(p);
00327             return;     // don't add/change routing state
00328 
00329         case TORATYPE_UPD:
00330             log_recv_upd(p);
00331             recvUPD(p);
00332             break;
00333 
00334         case TORATYPE_CLR:
00335             log_recv_clr(p);
00336             recvCLR(p);
00337             break;
00338 
00339         default:
00340             fprintf(stderr,
00341                 "%s: Invalid TORA type (%x)\n",
00342                 __PRETTY_FUNCTION__, th->th_type);
00343             exit(1);
00344     }
00345 
00346     if((td = dst_find(th->th_dst)) == 0) {
00347         Packet::free(p);
00348         return;
00349     }
00350 
00351     logNextHopChange(td);
00352 
00353     if((tn = td->nb_find_next_hop())) {
00354         Packet *p0;
00355         Time delay = 0.0;
00356 
00357         while((p0 = rqueue.deque(td->index))) {
00358                         forward(p0, tn->index, delay);
00359             delay += ARP_SEPARATION_DELAY;
00360         }
00361     }
00362     Packet::free(p);
00363 }
00364 
00365 
00366 
00367 /*
00368  *  IETF Draft - TORA Specification, section 3.7.6
00369  */
00370 void
00371 toraAgent::recvQRY(Packet *p)
00372 {
00373     struct hdr_ip *ih = HDR_IP(p);
00374     struct hdr_tora_qry *qh = HDR_TORA_QRY(p);
00375     TORADest *td;
00376     TORANeighbor *tn;
00377 
00378     if(qh->tq_dst == ipaddr()) {
00379 #ifdef DEBUG
00380         fprintf(stderr, "node %d received `QRY` for itself.\n", index);
00381 #endif
00382         return;
00383     }
00384 
00385     td = dst_find(qh->tq_dst);
00386     if(td == 0)
00387         td = dst_add(qh->tq_dst);
00388 
00389     if(td->rt_req) {
00390         return;
00391     }
00392 
00393     if(td->height.r == 0) {                 // II, A
00394         tn = td->nb_find(ih->saddr());
00395 
00396         if(tn && tn->time_act > td->time_upd) {     // II, A, 1
00397             td->time_upd = Scheduler::instance().clock();
00398             sendUPD(td->index);
00399         }
00400         else {                      // II, A, 2
00401         }
00402     }
00403     else {
00404         tn = td->nb_find_min_height(0);
00405 
00406         if(tn) {                    // II, B, 1
00407             td->update_height(tn->height.tau,
00408                       tn->height.oid,
00409                       tn->height.r,
00410                       tn->height.delta + 1,
00411                       ipaddr());
00412 
00413             td->time_upd = Scheduler::instance().clock();
00414 
00415             sendUPD(td->index);
00416         }
00417         else {
00418             td->rt_req = 1;
00419             td->time_rt_req = CURRENT_TIME;
00420 
00421             if(td->num_active > 1) {        // II, B, 1, a
00422                 sendQRY(td->index);
00423             }
00424             else {                  // II, B, 1, b
00425 
00426             }
00427         }
00428     }
00429 }
00430 
00431 
00432 /*
00433  *  IETF Draft - TORA Specification, section 3.7.7
00434  */
00435 void
00436 toraAgent::recvUPD(Packet *p)
00437 {
00438     struct hdr_ip *ih = HDR_IP(p);
00439     struct hdr_tora_upd *uh = HDR_TORA_UPD(p);
00440     TORADest *td;
00441     TORANeighbor *tn;
00442 
00443     if(uh->tu_dst == ipaddr()) {
00444         return;
00445     }
00446 
00447     td = dst_find(uh->tu_dst);
00448     if(td == 0)
00449         td = dst_add(uh->tu_dst);
00450 
00451     tn = td->nb_find(ih->saddr());
00452     if(tn == 0) {
00453         /*
00454          * update link status? -josh
00455          */
00456 
00457              // No, don't update linkstatus: it may be an update
00458              // that was delayed in the IMEP layer for sequencing -dam
00459              // no way at the TORA level to tell if we're connected...
00460              trace("T %.9f _%d_ received `UPD` from non-neighbor %d",
00461                CURRENT_TIME, ipaddr(), ih->saddr());         
00462 #ifdef DEBUG
00463         fprintf(stderr,
00464                         "node %d received `UPD` from non-neighbor %d\n",
00465             index, ih->src_);
00466 #endif
00467         return;
00468     }
00469 
00470     /*
00471      *  Update height and link status for neighbor [j][k].
00472      */
00473     td->update_height_nb(tn, uh);
00474 
00475     if(td->rt_req && tn->height.r == 0) {                               // I
00476 
00477         td->update_height(tn->height.tau,
00478                   tn->height.oid,
00479                   tn->height.r,
00480                   tn->height.delta + 1,
00481                   ipaddr());
00482 
00483         td->rt_req = 0;
00484 
00485         td->time_upd = Scheduler::instance().clock();
00486 
00487         sendUPD(td->index);
00488     }
00489     else if(td->num_down == 0) {                                    // II
00490         if(td->num_up == 0) {                                   // II, A
00491             if(td->height.isNull())                             // II, A, 1
00492                 return;                                 // II, A, 1, a
00493             else {
00494                 td->height.Null();                          // II, A, 1, b 
00495 
00496                 td->time_upd = Scheduler::instance().clock();
00497 
00498                 sendUPD(td->index);
00499             }
00500         }
00501         else {
00502             if(td->nb_check_same_ref()) {                           // II, A, 2
00503                 TORANeighbor *tn;
00504 
00505                 if( (tn = td->nb_find_min_height(0)) ) {            // II, A, 2, a
00506                     td->update_height(tn->height.tau,               // II, A, 2, a, i 
00507                               tn->height.oid,
00508                               1,
00509                               0,
00510                               ipaddr());
00511                     td->time_upd = Scheduler::instance().clock();
00512 
00513                     sendUPD(td->index);
00514                 }
00515                 else {
00516                     if(td->height.oid == ipaddr()) {                    // II, A, 2, a, ii
00517                         double temp_tau = td->height.tau;           // II, A, 2, a, ii, x 
00518                         nsaddr_t temp_oid = td->height.oid;
00519 
00520                         td->height.Null();
00521                         td->num_down = 0;
00522                         td->num_up = 0;
00523 
00524                         /*
00525                          *  For every active link n, if the neighbor connected
00526                          *  via link n is the destination j, set HT_NEIGH[j][n]=ZERO
00527                          *  and LNK_STAT[j][n] = DN.
00528                          *  Otherwise, set HT_NEIGH[j][n] = NULL and LNK_STAT[j][n] = UN.
00529                          */
00530                         for(tn = td->nblist.lh_first; tn; tn = tn->link.le_next) {
00531                             if(tn->index == td->index) {
00532                                 tn->height.Zero();
00533                                 tn->lnk_stat = LINK_DN;
00534 
00535                             }
00536                             else {
00537                                 tn->height.Null();
00538                                 tn->lnk_stat = LINK_UN;
00539                             }
00540                         }
00541 
00542                         sendCLR(td->index, temp_tau, temp_oid);
00543                     }
00544                     else {
00545                         td->update_height(Scheduler::instance().clock(),    // II, A, 2, a, ii, y
00546                                   ipaddr(),
00547                                   0,
00548                                   0,
00549                                   ipaddr());
00550                         td->rt_req = 0;
00551                         td->time_upd = Scheduler::instance().clock();
00552 
00553 #ifdef DEBUG
00554                         // under what circumstances does this rule fire?
00555                         // seems like it will prevent the detection of 
00556                         // partitions...??? -dam 8/24/98
00557 
00558                         if (logtarget) 
00559                           {
00560                             sprintf(logtarget->pt_->buffer(), "T %.9f _%d_ rule IIA2a(ii)x fires %d",
00561                                 Scheduler::instance().clock(), ipaddr(), td->index);
00562                             logtarget->pt_->dump();
00563                           }
00564 #endif
00565                         sendUPD(td->index);
00566                     }
00567                 }
00568 
00569             }
00570             else {
00571                 TORANeighbor *n = td->nb_find_max_height();             // II, A, 2, b
00572                 assert(n);
00573                 TORANeighbor *m = td->nb_find_min_nonnull_height(&n->height);
00574                 assert(m);
00575 
00576                 td->update_height(m->height.tau,
00577                           m->height.oid,
00578                           m->height.r,
00579                           m->height.delta - 1,
00580                           ipaddr());
00581 
00582                 td->time_upd = Scheduler::instance().clock();
00583 
00584                 sendUPD(td->index);
00585             }
00586         }
00587     }
00588     else {                                              // II, B
00589 
00590     }
00591 }
00592 
00593 
00594 /*
00595  *  IETF Draft - TORA Specification, section 3.7.8
00596  */
00597 void
00598 toraAgent::recvCLR(Packet *p)
00599 {
00600     struct hdr_ip *ih = HDR_IP(p);
00601     struct hdr_tora_clr *th = HDR_TORA_CLR(p);
00602     TORADest *td;
00603     TORANeighbor *tn;
00604 
00605     if(th->tc_dst == ipaddr()) {
00606         return;
00607     }
00608 
00609     td = dst_find(th->tc_dst);
00610     if(td == 0)
00611         td = dst_add(th->tc_dst);
00612     assert(td);
00613 
00614     if(td->height.tau == th->tc_tau &&
00615        td->height.oid == th->tc_oid &&
00616        td->height.r == 1) {                 // I
00617         double temp_tau = td->height.tau;
00618         nsaddr_t temp_oid = td->height.oid;
00619 
00620         td->height.Null();
00621         td->num_up = 0;
00622         td->num_down = 0;
00623 
00624         for(tn = td->nblist.lh_first; tn; tn = tn->link.le_next) {
00625             if(tn->index == td->index) {
00626                 tn->height.Zero();
00627                 tn->lnk_stat = LINK_DN;
00628             }
00629             else {
00630                 tn->height.Null();
00631                 tn->lnk_stat = LINK_UN;
00632             }
00633         }
00634         if(td->num_active > 1) {            // I, A
00635             sendCLR(td->index, temp_tau, temp_oid);
00636         }
00637         else {                      // I, B
00638         }
00639     }
00640     else {
00641         tn = td->nb_find(ih->saddr());          // II
00642         if(tn == 0) {
00643             /*
00644              *  XXX - update link status?
00645              */
00646                 trace("T %.9f _%d_ received `CLR` from non-neighbor %d",
00647                        CURRENT_TIME, index, ih->saddr());       
00648 #ifdef DEBUG
00649             fprintf(stderr,
00650                 "node %d received `CLR` from non-neighbor %d\n",
00651                 index, ih->src_);
00652 #endif
00653             return;
00654         }
00655 
00656         tn->height.Null();
00657         tn->lnk_stat = LINK_UN;
00658 
00659         for(tn = td->nblist.lh_first; tn; tn = tn->link.le_next) {
00660             if(tn->height.tau == th->tc_tau &&
00661                tn->height.oid == th->tc_oid &&
00662                tn->height.r == 1) {
00663                 tn->height.Null();
00664                 tn->lnk_stat = LINK_UN;
00665                         }
00666         }
00667         if(td->num_down == 0) {             // II, A
00668             if(td->num_up == 0) {           // II, A, 1
00669                 if(td->height.isNull()) {   // II, A, 1, a
00670                 }
00671                 else {
00672                     td->height.Null();
00673                     td->time_upd = Scheduler::instance().clock();
00674                     sendUPD(td->index);
00675                 }
00676             }
00677             else {
00678                 td->update_height(Scheduler::instance().clock(),
00679                           ipaddr(),
00680                           0,
00681                           0,
00682                           ipaddr());
00683                 td->rt_req = 0;
00684                 td->time_upd = Scheduler::instance().clock();
00685                 sendUPD(td->index);
00686             }
00687         }
00688         else {
00689                                 // II, B
00690         }
00691     }
00692 }
00693 
00694 void
00695 toraAgent::trace(char* fmt, ...)
00696 {
00697   va_list ap;
00698   
00699   if (!logtarget) return;
00700 
00701   va_start(ap, fmt);
00702   vsprintf(logtarget->pt_->buffer(), fmt, ap);
00703   logtarget->pt_->dump();
00704   va_end(ap);
00705 }
00706 
00707 

Generated on Tue Mar 6 16:47:52 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6