Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

dsdv.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, nov'98 -Padma.
00035  *
00036  * $Header: /nfs/jade/vint/CVSROOT/ns-2/dsdv/dsdv.cc,v 1.22 2001/05/21 19:27:33 haldar Exp $
00037  */
00038 
00039 extern "C" {
00040 #include <stdarg.h>
00041 #include <float.h>
00042 };
00043 
00044 #include "dsdv.h"
00045 #include "priqueue.h"
00046 
00047 #include <random.h>
00048 
00049 #include <cmu-trace.h>
00050 #include <address.h>
00051 #include <mobilenode.h>
00052 
00053 
00054 #define DSDV_STARTUP_JITTER 2.0 // secs to jitter start of periodic activity from
00055                                 // when start-dsr msg sent to agent
00056 #define DSDV_ALMOST_NOW     0.1 // jitter used for events that should be effectively
00057                                 // instantaneous but are jittered to prevent
00058                                 // synchronization
00059 #define DSDV_BROADCAST_JITTER 0.01 // jitter for all broadcast packets
00060 #define DSDV_MIN_TUP_PERIOD 1.0 // minimum time between triggered updates
00061 #define IP_DEF_TTL   32 // default TTTL
00062 
00063 #undef TRIGGER_UPDATE_ON_FRESH_SEQNUM
00064 //#define TRIGGER_UPDATE_ON_FRESH_SEQNUM
00065 /* should the receipt of a fresh (newer) sequence number cause us
00066    to send a triggered update?  If undef'd, we'll only trigger on
00067    routing metric changes */
00068 
00069 // Returns a random number between 0 and max
00070 static inline double 
00071 jitter (double max, int be_random_)
00072 {
00073   return (be_random_ ? Random::uniform(max) : 0);
00074 }
00075 
00076 void DSDV_Agent::
00077 trace (char *fmt,...)
00078 {
00079   va_list ap;
00080 
00081   if (!tracetarget)
00082     return;
00083 
00084   va_start (ap, fmt);
00085   vsprintf (tracetarget->pt_->buffer (), fmt, ap);
00086   tracetarget->pt_->dump ();
00087   va_end (ap);
00088 }
00089 
00090 void 
00091 DSDV_Agent::tracepkt (Packet * p, double now, int me, const char *type)
00092 {
00093   char buf[1024];
00094 
00095   unsigned char *walk = p->accessdata ();
00096 
00097   int ct = *(walk++);
00098   int seq, dst, met;
00099 
00100   snprintf (buf, 1024, "V%s %.5f _%d_ [%d]:", type, now, me, ct);
00101   while (ct--)
00102     {
00103       dst = *(walk++);
00104       dst = dst << 8 | *(walk++);
00105       dst = dst << 8 | *(walk++);
00106       dst = dst << 8 | *(walk++);
00107       met = *(walk++);
00108       seq = *(walk++);
00109       seq = seq << 8 | *(walk++);
00110       seq = seq << 8 | *(walk++);
00111       seq = seq << 8 | *(walk++);
00112       snprintf (buf, 1024, "%s (%d,%d,%d)", buf, dst, met, seq);
00113     }
00114   // Now do trigger handling.
00115   //trace("VTU %.5f %d", now, me);
00116   if (verbose_)
00117     trace ("%s", buf);
00118 }
00119 
00120 // Prints out an rtable element.
00121 void
00122 DSDV_Agent::output_rte(const char *prefix, rtable_ent * prte, DSDV_Agent * a)
00123 {
00124   a->trace("DFU: deimplemented");
00125   printf("DFU: deimplemented");
00126 
00127   prte = 0;
00128   prefix = 0;
00129 #if 0
00130   printf ("%s%d %d %d %d %f %f %f %f 0x%08x\n",
00131           prefix, prte->dst, prte->hop, prte->metric, prte->seqnum,
00132           prte->udtime, prte->new_seqnum_at, prte->wst, prte->changed_at,
00133           (unsigned int) prte->timeout_event);
00134   a->trace ("VTE %.5f %d %d %d %d %f %f %f %f 0x%08x",
00135           Scheduler::instance ().clock (), prte->dst, prte->hop, prte->metric,
00136           prte->seqnum, prte->udtime, prte->new_seqnum_at, prte->wst, prte->changed_at,
00137             prte->timeout_event);
00138 #endif
00139 }
00140 
00141 class DSDVTriggerHandler : public Handler {
00142   public:
00143     DSDVTriggerHandler(DSDV_Agent *a_) { a = a_; }
00144     virtual void handle(Event *e);
00145   private:
00146     DSDV_Agent *a;
00147 };
00148 
00149 
00150 void
00151 DSDVTriggerHandler::handle(Event *e)
00152  // send a triggered update (or a full update if one's needed)
00153 {
00154         //DEBUG
00155         //printf("(%d)-->triggered update with e=%x\n", a->myaddr_,e); 
00156 
00157   Scheduler & s = Scheduler::instance ();
00158   Time now = s.clock ();
00159   rtable_ent *prte;
00160   int update_type;       // we want periodic (=1) or triggered (=0) update?
00161   Time next_possible = a->lasttup_ + DSDV_MIN_TUP_PERIOD;
00162 
00163   for (a->table_->InitLoop(); (prte = a->table_->NextLoop());)
00164           if (prte->trigger_event == e) break;
00165 
00166   assert(prte && prte->trigger_event == e);
00167 
00168   if (now < next_possible)
00169     {
00170             //DEBUG
00171             //printf("(%d)..Re-scheduling triggered update\n",a->myaddr_);
00172       s.schedule(a->trigger_handler, e, next_possible - now);
00173       a->cancelTriggersBefore(next_possible);
00174       return;
00175     }
00176 
00177   update_type = 0;
00178   Packet * p = a->makeUpdate(/*in-out*/update_type);
00179       
00180   if (p != NULL) 
00181     {     
00182       if (update_type == 1)
00183         { // we got a periodic update, though we only asked for triggered
00184           // cancel and reschedule periodic update
00185           s.cancel(a->periodic_callback_);
00186           //DEBUG
00187           //printf("we got a periodic update, though asked for trigg\n");
00188           s.schedule (a->helper_, a->periodic_callback_, 
00189                       a->perup_ * (0.75 + jitter (0.25, a->be_random_)));
00190           if (a->verbose_) a->tracepkt (p, now, a->myaddr_, "PU");        
00191         }
00192       else
00193         {
00194           if (a->verbose_) a->tracepkt (p, now, a->myaddr_, "TU");        
00195         }
00196       assert (!HDR_CMN (p)->xmit_failure_);     // DEBUG 0x2      
00197       s.schedule (a->target_, p, jitter(DSDV_BROADCAST_JITTER, a->be_random_));
00198       
00199       a->lasttup_ = now; // even if we got a full update, it still counts
00200       // for our last triggered update time
00201     }
00202   
00203   // free this event
00204   for (a->table_->InitLoop (); (prte = a->table_->NextLoop ());)
00205     if (prte->trigger_event && prte->trigger_event == e)
00206       {
00207         prte->trigger_event = 0;
00208         delete e;
00209       }
00210 }
00211 
00212 void
00213 DSDV_Agent::cancelTriggersBefore(Time t)
00214   // Cancel any triggered events scheduled to take place *before* time
00215   // t (exclusive)
00216 {
00217   rtable_ent *prte;
00218   Scheduler & s = Scheduler::instance ();
00219 
00220   for (table_->InitLoop (); (prte = table_->NextLoop ());)
00221     if (prte->trigger_event && prte->trigger_event->time_ < t)
00222       {
00223               //DEBUG
00224               //printf("(%d) cancel event %x\n",myaddr_,prte->trigger_event);
00225         s.cancel(prte->trigger_event);
00226         delete prte->trigger_event;
00227         prte->trigger_event = 0;
00228       }
00229 }
00230 
00231 void
00232 DSDV_Agent::needTriggeredUpdate(rtable_ent *prte, Time t)
00233   // if no triggered update already pending, make one so
00234 {
00235   Scheduler & s = Scheduler::instance();
00236   Time now = Scheduler::instance().clock();
00237 
00238   assert(t >= now);
00239 
00240   if (prte->trigger_event) 
00241     s.cancel(prte->trigger_event);
00242   else
00243     prte->trigger_event = new Event;
00244   //DEBUG
00245   //printf("(%d)..scheduling trigger-update with event %x\n",myaddr_,prte->trigger_event);
00246   s.schedule(trigger_handler, prte->trigger_event, t - now);
00247 }
00248 
00249 void
00250 DSDV_Agent::helper_callback (Event * e)
00251 {
00252   Scheduler & s = Scheduler::instance ();
00253   double now = s.clock ();
00254   rtable_ent *prte;
00255   rtable_ent *pr2;
00256   int update_type;       // we want periodic (=1) or triggered (=0) update?
00257   //DEBUG
00258   //printf("Triggered handler on 0x%08x\n", e);
00259 
00260   // Check for periodic callback
00261   if (periodic_callback_ && e == periodic_callback_)
00262     {
00263       update_type = 1;
00264       Packet *p = makeUpdate(/*in-out*/update_type);
00265       if (verbose_)
00266         {
00267           trace ("VPC %.5f _%d_", now, myaddr_);
00268           tracepkt (p, now, myaddr_, "PU");
00269         }
00270 
00271       
00272       if (p) {
00273               assert (!HDR_CMN (p)->xmit_failure_);     // DEBUG 0x2
00274               // send out update packet jitter to avoid sync
00275               //DEBUG
00276               //printf("(%d)..sendout update pkt (periodic=%d)\n",myaddr_,update_type);
00277               s.schedule (target_, p, jitter(DSDV_BROADCAST_JITTER, be_random_));
00278       }
00279       
00280       // put the periodic update sending callback back onto the 
00281       // the scheduler queue for next time....
00282       s.schedule (helper_, periodic_callback_, 
00283                   perup_ * (0.75 + jitter (0.25, be_random_)));
00284 
00285       // this will take the place of any planned triggered updates
00286       lasttup_ = now;
00287       return;
00288     }
00289 
00290   // Check for timeout
00291   // If it was a timeout, fix the routing table.
00292   for (table_->InitLoop (); (prte = table_->NextLoop ());)
00293     if (prte->timeout_event && (prte->timeout_event == e))
00294       break;
00295 
00296   // If it was a timeout, prte will be non-NULL
00297   // Note that in the if we don't touch the changed_at time, so that when
00298   // wst is computed, it doesn't consider the infinte metric the best
00299   // one at that sequence number.
00300   if (prte)
00301           {
00302       if (verbose_)
00303         {
00304           trace ("VTO %.5f _%d_ %d->%d", now, myaddr_, myaddr_, prte->dst);
00305           /*      trace ("VTO %.5f _%d_ trg_sch %x on sched %x time %f", now, myaddr_, 
00306                  trigupd_scheduled, 
00307                  trigupd_scheduled ? s.lookup(trigupd_scheduled->uid_) : 0,
00308                  trigupd_scheduled ? trigupd_scheduled->time_ : 0); */
00309         }
00310       
00311       for (table_->InitLoop (); (pr2 = table_->NextLoop ()); )
00312         {
00313           if (pr2->hop == prte->dst && pr2->metric != BIG)
00314             {
00315               if (verbose_)
00316                 trace ("VTO %.5f _%d_ marking %d", now, myaddr_, pr2->dst);
00317               pr2->metric = BIG;
00318               pr2->advertise_ok_at = now;
00319               pr2->advert_metric = true;
00320               pr2->advert_seqnum = true;
00321               pr2->seqnum++;
00322               // And we have routing info to propogate.
00323               //DEBUG
00324               //printf("(%d)..we have routing info to propagate..trigger update for dst %d\n",myaddr_,pr2->dst);
00325               needTriggeredUpdate(pr2, now);
00326             }
00327         }
00328 
00329       // OK the timeout expired, so we'll free it. No dangling pointers.
00330       prte->timeout_event = 0;    
00331     }
00332   else 
00333     { // unknown event on  queue
00334       fprintf(stderr,"DFU: unknown queue event\n");
00335      abort();
00336     }
00337 
00338   if (e)
00339     delete e;
00340 }
00341 
00342 void
00343 DSDV_Agent::lost_link (Packet *p)
00344 {
00345   hdr_cmn *hdrc = HDR_CMN (p);
00346   rtable_ent *prte = table_->GetEntry (hdrc->next_hop_);
00347 
00348   if(use_mac_ == 0) {
00349           drop(p, DROP_RTR_MAC_CALLBACK);
00350           return;
00351   }
00352 
00353   //DEBUG
00354   //printf("(%d)..Lost link..\n",myaddr_);
00355   if (verbose_ && hdrc->addr_type_ == NS_AF_INET)
00356     trace("VLL %.8f %d->%d lost at %d",
00357     Scheduler::instance().clock(),
00358            hdr_ip::access(p)->saddr(), hdr_ip::access(p)->daddr(),
00359            myaddr_);
00360 
00361   if (!use_mac_ || !prte || hdrc->addr_type_ != NS_AF_INET)
00362     return;
00363 
00364   if (verbose_)
00365     trace ("VLP %.5f %d:%d->%d:%d lost at %d [hop %d]",
00366   Scheduler::instance ().clock (),
00367            hdr_ip::access (p)->saddr(),
00368            hdr_ip::access (p)->sport(),
00369            hdr_ip::access (p)->daddr(),
00370            hdr_ip::access (p)->dport(),
00371            myaddr_, prte->dst);
00372 
00373   if (prte->timeout_event)
00374     {
00375       Scheduler::instance ().cancel (prte->timeout_event);
00376       helper_callback (prte->timeout_event);
00377     }
00378   else if (prte->metric != BIG)
00379     {
00380       assert(prte->timeout_event == 0);
00381       prte->timeout_event = new Event ();
00382       helper_callback (prte->timeout_event);
00383     }
00384 
00385   // Queue these packets up...
00386   recv(p, 0);
00387 
00388 #if 0
00389   while (p2 = ((PriQueue *) target_)->filter (prte->dst))
00390     {
00391       if (verbose_)
00392       trace ("VRS %.5f %d:%d->%d:%d lost at %d", Scheduler::instance ().clock (),
00393                hdr_ip::access (p2)->saddr(),
00394                hdr_ip::access (p2)->sport(),
00395                hdr_ip::access (p2)->daddr(),
00396                hdr_ip::access (p2)->dport(), myaddr_);
00397 
00398       recv(p2, 0);
00399     }
00400 
00401   while (p2 = ll_queue->filter (prte->dst))
00402     {
00403       if (verbose_)
00404       trace ("VRS %.5f %d:%d->%d:%d lost at %d", Scheduler::instance ().clock (),
00405                hdr_ip::access (p2)->saddr(),
00406                hdr_ip::access (p2)->sport(),
00407                hdr_ip::access (p2)->daddr(),
00408                hdr_ip::access (p2)->dport(), myaddr_);
00409 
00410       recv (p2, 0);
00411     }
00412 #endif
00413 }
00414 
00415 static void 
00416 mac_callback (Packet * p, void *arg)
00417 {
00418   ((DSDV_Agent *) arg)->lost_link (p);
00419 }
00420 
00421 Packet *
00422 DSDV_Agent::makeUpdate(int& periodic)
00423     // return a packet advertising the state in the routing table
00424     // makes a full ``periodic'' update if requested, or a ``triggered''
00425     // partial update if there are only a few changes and full update otherwise
00426     // returns with periodic = 1 if full update returned, or = 0 if partial
00427   //   update returned
00428         
00429 {
00430         //DEBUG
00431         //printf("(%d)-->Making update pkt\n",myaddr_);
00432         
00433   Packet *p = allocpkt ();
00434   hdr_ip *iph = hdr_ip::access(p);
00435   hdr_cmn *hdrc = HDR_CMN (p);
00436   double now = Scheduler::instance ().clock ();
00437   rtable_ent *prte;
00438   unsigned char *walk;
00439 
00440   int change_count;             // count of entries to go in this update
00441   int rtbl_sz;                  // counts total entries in rt table
00442   int unadvertiseable;          // number of routes we can't advertise yet
00443 
00444   //printf("Update packet from %d [per=%d]\n", myaddr_, periodic);
00445 
00446   // The packet we send wants to be broadcast
00447   hdrc->next_hop_ = IP_BROADCAST;
00448   hdrc->addr_type_ = NS_AF_INET;
00449   iph->daddr() = IP_BROADCAST << Address::instance().nodeshift();
00450   iph->dport() = ROUTER_PORT;
00451 
00452   change_count = 0;
00453   rtbl_sz = 0;
00454   unadvertiseable = 0;
00455   for (table_->InitLoop (); 
00456        (prte = table_->NextLoop ()); )
00457     {
00458       rtbl_sz++;
00459       if ((prte->advert_seqnum || prte->advert_metric) 
00460           && prte->advertise_ok_at <= now) 
00461         change_count++;
00462 
00463       if (prte->advertise_ok_at > now) unadvertiseable++;
00464     }
00465   //printf("change_count = %d\n",change_count);
00466   if (change_count * 3 > rtbl_sz && change_count > 3)
00467     { // much of the table has changed, just do a periodic update now
00468       periodic = 1;
00469     }
00470 
00471   // Periodic update... increment the sequence number...
00472   if (periodic)
00473     {
00474       change_count = rtbl_sz - unadvertiseable;
00475       //printf("rtbsize-%d, unadvert-%d\n",rtbl_sz,unadvertiseable);
00476       rtable_ent rte;
00477       bzero(&rte, sizeof(rte));
00478 
00479       /* inc sequence number on any periodic update, even if we started
00480          off wanting to do a triggered update, b/c we're doing a real
00481          live periodic update now that'll take the place of our next
00482          periodic update */
00483       seqno_ += 2;
00484 
00485       rte.dst = myaddr_;
00486       //rte.hop = iph->src();
00487       rte.hop = Address::instance().get_nodeaddr(iph->saddr());
00488       rte.metric = 0;
00489       rte.seqnum = seqno_;
00490 
00491       rte.advertise_ok_at = 0.0; // can always advert ourselves
00492       rte.advert_seqnum = true;  // always include ourselves in Triggered Upds
00493       rte.changed_at = now;
00494       rte.new_seqnum_at = now;
00495       rte.wst = 0;
00496       rte.timeout_event = 0;            // Don't time out our localhost :)
00497 
00498       rte.q = 0;                // Don't buffer pkts for self!
00499 
00500       table_->AddEntry (rte);
00501     }
00502 
00503   if (change_count == 0) 
00504     {
00505       Packet::free(p); // allocated by us, no drop needed
00506 
00507       return NULL; // nothing to advertise
00508     }
00509 
00510   /* ****** make the update packet.... ***********
00511      with less than 100+ nodes, an update for all nodes is less than the
00512      MTU, so don't bother worrying about splitting the update over
00513      multiple packets -dam 4/26/98 */
00514   assert(rtbl_sz <= (1500 / 12));
00515 
00516   p->allocdata((change_count * 9) + 1);
00517   walk = p->accessdata ();
00518   *(walk++) = change_count;
00519 
00520   // hdrc->size_ = change_count * 12 + 20;      // DSDV + IP
00521   hdrc->size_ = change_count * 12 + IP_HDR_LEN; // DSDV + IP
00522 
00523   for (table_->InitLoop (); (prte = table_->NextLoop ());)
00524     {
00525 
00526       if (periodic && prte->advertise_ok_at > now)
00527         { // don't send out routes that shouldn't be advertised
00528           // even in periodic updates
00529           continue;
00530         }
00531 
00532       if (periodic || 
00533           ((prte->advert_seqnum || prte->advert_metric) 
00534            && prte->advertise_ok_at <= now))
00535         { // include this rte in the advert
00536           if (!periodic && verbose_)
00537             trace ("VCT %.5f _%d_ %d", now, myaddr_, prte->dst);
00538 
00539           //assert (prte->dst < 256 && prte->metric < 256);
00540           //*(walk++) = prte->dst;
00541           *(walk++) = prte->dst >> 24;
00542           *(walk++) = (prte->dst >> 16) & 0xFF;
00543           *(walk++) = (prte->dst >> 8) & 0xFF;
00544           *(walk++) = (prte->dst >> 0) & 0xFF;
00545           *(walk++) = prte->metric;
00546           *(walk++) = (prte->seqnum) >> 24;
00547           *(walk++) = ((prte->seqnum) >> 16) & 0xFF;
00548           *(walk++) = ((prte->seqnum) >> 8) & 0xFF;
00549           *(walk++) = (prte->seqnum) & 0xFF;
00550 
00551           prte->last_advertised_metric = prte->metric;
00552 
00553           // seqnum's only need to be advertised once after they change
00554           prte->advert_seqnum = false; // don't need to advert seqnum again
00555 
00556           if (periodic) 
00557             { // a full advert means we don't have to re-advert either 
00558               // metrics or seqnums again until they change
00559               prte->advert_seqnum = false;
00560               prte->advert_metric = false;
00561             }
00562           change_count--;
00563         }
00564     }  
00565   assert(change_count == 0);
00566   return p;
00567 }
00568 
00569 void
00570 DSDV_Agent::updateRoute(rtable_ent *old_rte, rtable_ent *new_rte)
00571 {
00572   int negvalue = -1;
00573   assert(new_rte);
00574 
00575   Time now = Scheduler::instance().clock();
00576 
00577   char buf[1024];
00578   //  snprintf (buf, 1024, "%c %.5f _%d_ (%d,%d->%d,%d->%d,%d->%d,%lf)",
00579   snprintf (buf, 1024, "%c %.5f _%d_ (%d,%d->%d,%d->%d,%d->%d,%f)",
00580             (new_rte->metric != BIG 
00581              && (!old_rte || old_rte->metric != BIG)) ? 'D' : 'U', 
00582             now, myaddr_, new_rte->dst, 
00583             old_rte ? old_rte->metric : negvalue, new_rte->metric, 
00584             old_rte ? old_rte->seqnum : negvalue,  new_rte->seqnum,
00585             old_rte ? old_rte->hop : -1,  new_rte->hop, 
00586             new_rte->advertise_ok_at);
00587 
00588   table_->AddEntry (*new_rte);
00589   //printf("(%d),Route table updated..\n",myaddr_);
00590   if (trace_wst_)
00591     trace ("VWST %.12lf frm %d to %d wst %.12lf nxthp %d [of %d]",
00592            now, myaddr_, new_rte->dst, new_rte->wst, new_rte->hop, 
00593            new_rte->metric);
00594   if (verbose_)
00595     trace ("VS%s", buf);
00596 }
00597 
00598 void
00599 DSDV_Agent::processUpdate (Packet * p)
00600 {
00601   hdr_ip *iph = HDR_IP(p);
00602   Scheduler & s = Scheduler::instance ();
00603   double now = s.clock ();
00604   
00605   // it's a dsdv packet
00606   int i;
00607   unsigned char *d = p->accessdata ();
00608   unsigned char *w = d + 1;
00609   rtable_ent rte;               // new rte learned from update being processed
00610   rtable_ent *prte;             // ptr to entry *in* routing tbl
00611 
00612   //DEBUG
00613   //int src, dst;
00614   //src = Address::instance().get_nodeaddr(iph->src());
00615   //dst = Address::instance().get_nodeaddr(iph->dst());
00616   //printf("Received DSDV packet from %d(%d) to %d(%d) [%d)]\n", src, iph->sport(), dst, iph->dport(), myaddr_);
00617 
00618   for (i = *d; i > 0; i--)
00619     {
00620       bool trigger_update = false;  // do we need to do a triggered update?
00621       nsaddr_t dst;
00622       prte = NULL;
00623 
00624       dst = *(w++);
00625       dst = dst << 8 | *(w++);
00626       dst = dst << 8 | *(w++);
00627       dst = dst << 8 | *(w++);
00628 
00629       if ((prte = table_->GetEntry (dst)))
00630         {
00631           bcopy(prte, &rte, sizeof(rte));
00632         }
00633       else
00634         {
00635           bzero(&rte, sizeof(rte));
00636         }
00637 
00638       rte.dst = dst;
00639       //rte.hop = iph->src();
00640       rte.hop = Address::instance().get_nodeaddr(iph->saddr());
00641       rte.metric = *(w++);
00642       rte.seqnum = *(w++);
00643       rte.seqnum = rte.seqnum << 8 | *(w++);
00644       rte.seqnum = rte.seqnum << 8 | *(w++);
00645       rte.seqnum = rte.seqnum << 8 | *(w++);
00646       rte.changed_at = now;
00647       if (rte.metric != BIG) rte.metric += 1;
00648 
00649       if (rte.dst == myaddr_)
00650         {
00651           if (rte.metric == BIG && periodic_callback_)
00652             {
00653               // You have the last word on yourself...
00654               // Tell the world right now that I'm still here....
00655               // This is a CMU Monarch optimiziation to fix the 
00656               // the problem of other nodes telling you and your neighbors
00657               // that you don't exist described in the paper.
00658               s.cancel (periodic_callback_);
00659               s.schedule (helper_, periodic_callback_, 0);
00660             }
00661           continue;             // don't corrupt your own routing table.
00662 
00663         }
00664 
00665       /**********  fill in meta data for new route ***********/
00666       // If it's in the table, make it the same timeout and queue.
00667       if (prte)
00668         { // we already have a route to this dst
00669           if (prte->seqnum == rte.seqnum)
00670             { // we've got an update with out a new squenece number
00671               // this update must have come along a different path
00672               // than the previous one, and is just the kind of thing
00673               // the weighted settling time is supposed to track.
00674 
00675               // this code is now a no-op left here for clarity -dam XXX
00676               rte.wst = prte->wst;
00677               rte.new_seqnum_at = prte->new_seqnum_at;
00678             }
00679           else 
00680             { // we've got a new seq number, end the measurement period
00681               // for wst over the course of the old sequence number
00682               // and update wst with the difference between the last
00683               // time we changed the route (which would be when the 
00684               // best route metric arrives) and the first time we heard
00685               // the sequence number that started the measurement period
00686 
00687               // do we care if we've missed a sequence number, such
00688               // that we have a wst measurement period that streches over
00689               // more than a single sequence number??? XXX -dam 4/20/98
00690               rte.wst = alpha_ * prte->wst + 
00691                 (1.0 - alpha_) * (prte->changed_at - prte->new_seqnum_at);
00692               rte.new_seqnum_at = now;
00693             }
00694         }
00695       else
00696         { // inititallize the wst for the new route
00697           rte.wst = wst0_;
00698           rte.new_seqnum_at = now;
00699         }
00700           
00701       // Now that we know the wst_, we know when to update...
00702       if (rte.metric != BIG && (!prte || prte->metric != BIG))
00703         rte.advertise_ok_at = now + (rte.wst * 2);
00704       else
00705         rte.advertise_ok_at = now;
00706 
00707       /*********** decide whether to update our routing table *********/
00708       if (!prte)
00709         { // we've heard from a brand new destination
00710           if (rte.metric < BIG) 
00711             {
00712               rte.advert_metric = true;
00713               trigger_update = true;
00714             }
00715           updateRoute(prte,&rte);
00716         }
00717       else if ( prte->seqnum == rte.seqnum )
00718         { // stnd dist vector case
00719           if (rte.metric < prte->metric) 
00720             { // a shorter route!
00721               if (rte.metric == prte->last_advertised_metric)
00722                 { // we've just gone back to a metric we've already advertised
00723                   rte.advert_metric = false;
00724                   trigger_update = false;
00725                 }
00726               else
00727                 { // we're changing away from the last metric we announced
00728                   rte.advert_metric = true;
00729                   trigger_update = true;
00730                 }
00731               updateRoute(prte,&rte);
00732             }
00733           else
00734             { // ignore the longer route
00735             }
00736         }
00737       else if ( prte->seqnum < rte.seqnum )
00738         { // we've heard a fresher sequence number
00739           // we *must* believe its rt metric
00740           rte.advert_seqnum = true;     // we've got a new seqnum to advert
00741           if (rte.metric == prte->last_advertised_metric)
00742             { // we've just gone back to our old metric
00743               rte.advert_metric = false;
00744             }
00745           else
00746             { // we're using a metric different from our last advert
00747               rte.advert_metric = true;
00748             }
00749 
00750           updateRoute(prte,&rte);
00751 
00752 #ifdef TRIGGER_UPDATE_ON_FRESH_SEQNUM
00753           trigger_update = true;
00754 #else
00755           trigger_update = false;
00756 #endif
00757         }
00758       else if ( prte->seqnum > rte.seqnum )
00759         { // our neighbor has older sequnum info than we do
00760           if (rte.metric == BIG && prte->metric != BIG)
00761             { // we must go forth and educate this ignorant fellow
00762               // about our more glorious and happy metric
00763               prte->advertise_ok_at = now;
00764               prte->advert_metric = true;
00765               // directly schedule a triggered update now for 
00766               // prte, since the other logic only works with rte.*
00767               needTriggeredUpdate(prte,now);
00768             }
00769           else
00770             { // we don't care about their stale info
00771             }
00772         }
00773       else
00774         {
00775           fprintf(stderr,
00776                   "%s DFU: unhandled adding a route entry?\n", __FILE__);
00777           abort();
00778         }
00779       
00780       if (trigger_update)
00781         {
00782           prte = table_->GetEntry (rte.dst);
00783           assert(prte != NULL && prte->advertise_ok_at == rte.advertise_ok_at);
00784           needTriggeredUpdate(prte, prte->advertise_ok_at);
00785         }
00786 
00787       // see if we can send off any packets we've got queued
00788       if (rte.q && rte.metric != BIG)
00789         {
00790           Packet *queued_p;
00791           while ((queued_p = rte.q->deque()))
00792           // XXX possible loop here  
00793           // while ((queued_p = rte.q->deque()))
00794           // Only retry once to avoid looping
00795           // for (int jj = 0; jj < rte.q->length(); jj++){
00796           //  queued_p = rte.q->deque();
00797             recv(queued_p, 0); // give the packets to ourselves to forward
00798           // }
00799           delete rte.q;
00800           rte.q = 0;
00801           table_->AddEntry(rte); // record the now zero'd queue
00802         }
00803     } // end of all destination mentioned in routing update packet
00804 
00805   // Reschedule the timeout for this neighbor
00806   prte = table_->GetEntry(Address::instance().get_nodeaddr(iph->saddr()));
00807   if (prte)
00808     {
00809       if (prte->timeout_event)
00810         s.cancel (prte->timeout_event);
00811       else
00812         {
00813           prte->timeout_event = new Event ();
00814         }
00815       
00816       s.schedule (helper_, prte->timeout_event, min_update_periods_ * perup_);
00817     }
00818   else
00819     { // If the first thing we hear from a node is a triggered update
00820       // that doesn't list the node sending the update as the first
00821       // thing in the packet (which is disrecommended by the paper)
00822       // we won't have a route to that node already.  In order to timeout
00823       // the routes we just learned, we need a harmless route to keep the
00824       // timeout metadata straight.
00825       
00826       // Hi there, nice to meet you. I'll make a fake advertisement
00827       bzero(&rte, sizeof(rte));
00828       rte.dst = Address::instance().get_nodeaddr(iph->saddr());
00829       rte.hop = Address::instance().get_nodeaddr(iph->saddr());
00830       rte.metric = 1;
00831       rte.seqnum = 0;
00832       rte.advertise_ok_at = now + 604800;       // check back next week... :)
00833       
00834       rte.changed_at = now;
00835       rte.new_seqnum_at = now;
00836       rte.wst = wst0_;
00837       rte.timeout_event = new Event ();
00838       rte.q = 0;
00839       
00840       updateRoute(NULL, &rte);
00841       s.schedule(helper_, rte.timeout_event, min_update_periods_ * perup_);
00842     }
00843   
00844   /*
00845    * Freeing a routing layer packet --> don't need to
00846    * call drop here.
00847    */
00848   Packet::free (p);
00849 
00850 }
00851 
00852 int 
00853 DSDV_Agent::diff_subnet(int dst) 
00854 {
00855         char* dstnet = Address::instance().get_subnetaddr(dst);
00856         if (subnet_ != NULL) {
00857                 if (dstnet != NULL) {
00858                         if (strcmp(dstnet, subnet_) != 0) {
00859                                 delete [] dstnet;
00860                                 return 1;
00861                         }
00862                         delete [] dstnet;
00863                 }
00864         }
00865         //assert(dstnet == NULL);
00866         return 0;
00867 }
00868 
00869 
00870 
00871 void
00872 DSDV_Agent::forwardPacket (Packet * p)
00873 {
00874   hdr_ip *iph = HDR_IP(p);
00875   Scheduler & s = Scheduler::instance ();
00876   double now = s.clock ();
00877   hdr_cmn *hdrc = HDR_CMN (p);
00878   int dst;
00879   rtable_ent *prte;
00880   
00881   // We should route it.
00882   //printf("(%d)-->forwardig pkt\n",myaddr_);
00883   // set direction of pkt to -1 , i.e downward
00884   hdrc->direction() = hdr_cmn::DOWN;
00885 
00886   // if the destination is outside mobilenode's domain
00887   // forward it to base_stn node
00888   // Note: pkt is not buffered if route to base_stn is unknown
00889 
00890   dst = Address::instance().get_nodeaddr(iph->daddr());  
00891   if (diff_subnet(iph->daddr())) {
00892            prte = table_->GetEntry (dst);
00893           if (prte && prte->metric != BIG) 
00894                   goto send;
00895           
00896           //int dst = (node_->base_stn())->address();
00897           dst = node_->base_stn();
00898           prte = table_->GetEntry (dst);
00899           if (prte && prte->metric != BIG) 
00900                   goto send;
00901           
00902           else {
00903                   //drop pkt with warning
00904                   fprintf(stderr, "warning: Route to base_stn not known: dropping pkt\n");
00905                   Packet::free(p);
00906                   return;
00907           }
00908   }
00909   
00910   prte = table_->GetEntry (dst);
00911   
00912   //  trace("VDEBUG-RX %d %d->%d %d %d 0x%08x 0x%08x %d %d", 
00913   //  myaddr_, iph->src(), iph->dst(), hdrc->next_hop_, hdrc->addr_type_,
00914   //  hdrc->xmit_failure_, hdrc->xmit_failure_data_,
00915   //  hdrc->num_forwards_, hdrc->opt_num_forwards);
00916 
00917   if (prte && prte->metric != BIG)
00918     {
00919        //printf("(%d)-have route for dst\n",myaddr_);
00920        goto send;
00921     }
00922   else if (prte)
00923     { /* must queue the packet */
00924             //printf("(%d)-no route, queue pkt\n",myaddr_);
00925       if (!prte->q)
00926         {
00927           prte->q = new PacketQueue ();
00928         }
00929 
00930       prte->q->enque(p);
00931 
00932       if (verbose_)
00933         trace ("VBP %.5f _%d_ %d:%d -> %d:%d", now, myaddr_, iph->saddr(),
00934                iph->sport(), iph->daddr(), iph->dport());
00935 
00936       while (prte->q->length () > MAX_QUEUE_LENGTH)
00937               drop (prte->q->deque (), DROP_RTR_QFULL);
00938       return;
00939     }
00940   else
00941     { // Brand new destination
00942       rtable_ent rte;
00943       double now = s.clock();
00944       
00945       bzero(&rte, sizeof(rte));
00946       rte.dst = dst;
00947       rte.hop = dst;
00948       rte.metric = BIG;
00949       rte.seqnum = 0;
00950 
00951       rte.advertise_ok_at = now + 604800;       // check back next week... :)
00952       rte.changed_at = now;
00953       rte.new_seqnum_at = now;  // was now + wst0_, why??? XXX -dam
00954       rte.wst = wst0_;
00955       rte.timeout_event = 0;
00956 
00957       rte.q = new PacketQueue();
00958       rte.q->enque(p);
00959           
00960       assert (rte.q->length() == 1 && 1 <= MAX_QUEUE_LENGTH);
00961       table_->AddEntry(rte);
00962       
00963       if (verbose_)
00964               trace ("VBP %.5f _%d_ %d:%d -> %d:%d", now, myaddr_,
00965                      iph->saddr(), iph->sport(), iph->daddr(), iph->dport());
00966       return;
00967     }
00968 
00969 
00970  send:
00971   hdrc->addr_type_ = NS_AF_INET;
00972   hdrc->xmit_failure_ = mac_callback;
00973   hdrc->xmit_failure_data_ = this;
00974   if (prte->metric > 1)
00975           hdrc->next_hop_ = prte->hop;
00976   else
00977           hdrc->next_hop_ = dst;
00978   if (verbose_)
00979           trace ("Routing pkts outside domain: \
00980 VFP %.5f _%d_ %d:%d -> %d:%d", now, myaddr_, iph->saddr(),
00981                  iph->sport(), iph->daddr(), iph->dport());  
00982 
00983   assert (!HDR_CMN (p)->xmit_failure_ ||
00984           HDR_CMN (p)->xmit_failure_ == mac_callback);
00985   target_->recv(p, (Handler *)0);
00986   return;
00987   
00988 }
00989 
00990 void 
00991 DSDV_Agent::sendOutBCastPkt(Packet *p)
00992 {
00993   Scheduler & s = Scheduler::instance ();
00994   // send out bcast pkt with jitter to avoid sync
00995   s.schedule (target_, p, jitter(DSDV_BROADCAST_JITTER, be_random_));
00996 }
00997 
00998 
00999 void
01000 DSDV_Agent::recv (Packet * p, Handler *)
01001 {
01002   hdr_ip *iph = HDR_IP(p);
01003   hdr_cmn *cmh = HDR_CMN(p);
01004   int src = Address::instance().get_nodeaddr(iph->saddr());
01005   int dst = cmh->next_hop();
01006   /*
01007    *  Must be a packet I'm originating...
01008    */
01009   if(src == myaddr_ && cmh->num_forwards() == 0) {
01010     /*
01011      * Add the IP Header
01012      */
01013     cmh->size() += IP_HDR_LEN;    
01014     iph->ttl_ = IP_DEF_TTL;
01015   }
01016   /*
01017    *  I received a packet that I sent.  Probably
01018    *  a routing loop.
01019    */
01020   else if(src == myaddr_) {
01021     drop(p, DROP_RTR_ROUTE_LOOP);
01022     return;
01023   }
01024   /*
01025    *  Packet I'm forwarding...
01026    */
01027   else {
01028     /*
01029      *  Check the TTL.  If it is zero, then discard.
01030      */
01031     if(--iph->ttl_ == 0) {
01032       drop(p, DROP_RTR_TTL);
01033       return;
01034     }
01035   }
01036   
01037   if ((src != myaddr_) && (iph->dport() == ROUTER_PORT))
01038     {
01039             // XXX disable this feature for mobileIP where
01040             // the MH and FA (belonging to diff domains)
01041             // communicate with each other.
01042 
01043             // Drop pkt if rtg update from some other domain:
01044             // if (diff_subnet(iph->src())) 
01045             // drop(p, DROP_OUTSIDE_SUBNET);
01046             //else    
01047             processUpdate(p);
01048     }
01049   else if ((u_int32_t) dst == IP_BROADCAST && 
01050            (iph->dport() != ROUTER_PORT)) 
01051           {
01052              if (src == myaddr_) {
01053                      // handle brdcast pkt
01054                      sendOutBCastPkt(p);
01055              }
01056              else {
01057                      // hand it over to the port-demux
01058                     
01059                     port_dmux_->recv(p, (Handler*)0);
01060              }
01061           }
01062   else 
01063     {
01064             forwardPacket(p);
01065     }
01066 }
01067 
01068 static class DSDVClass:public TclClass
01069 {
01070   public:
01071   DSDVClass ():TclClass ("Agent/DSDV")
01072   {
01073   }
01074   TclObject *create (int, const char *const *)
01075   {
01076     return (new DSDV_Agent ());
01077   }
01078 } class_dsdv;
01079 
01080 DSDV_Agent::DSDV_Agent (): Agent (PT_MESSAGE), ll_queue (0), seqno_ (0), 
01081   myaddr_ (0), subnet_ (0), node_ (0), port_dmux_(0),
01082   periodic_callback_ (0), be_random_ (1), 
01083   use_mac_ (0), verbose_ (1), trace_wst_ (0), lasttup_ (-10), 
01084   alpha_ (0.875),  wst0_ (6), perup_ (15), 
01085   min_update_periods_ (3)       // constants
01086  {
01087   table_ = new RoutingTable ();
01088   helper_ = new DSDV_Helper (this);
01089   trigger_handler = new DSDVTriggerHandler(this);
01090 
01091   bind_time ("wst0_", &wst0_);
01092   bind_time ("perup_", &perup_);
01093 
01094   bind ("use_mac_", &use_mac_);
01095   bind ("be_random_", &be_random_);
01096   bind ("alpha_", &alpha_);
01097   bind ("min_update_periods_", &min_update_periods_);
01098   bind ("verbose_", &verbose_);
01099   bind ("trace_wst_", &trace_wst_);
01100   //DEBUG
01101   address = 0;
01102  
01103 }
01104 
01105 void
01106 DSDV_Agent::startUp()
01107 {
01108  Time now = Scheduler::instance().clock();
01109 
01110   subnet_ = Address::instance().get_subnetaddr(myaddr_);
01111   //DEBUG
01112   address = Address::instance().print_nodeaddr(myaddr_);
01113   //printf("myaddress: %d -> %s\n",myaddr_,address);
01114   
01115   rtable_ent rte;
01116   bzero(&rte, sizeof(rte));
01117 
01118   rte.dst = myaddr_;
01119   rte.hop = myaddr_;
01120   rte.metric = 0;
01121   rte.seqnum = seqno_;
01122   seqno_ += 2;
01123 
01124   rte.advertise_ok_at = 0.0; // can always advert ourselves
01125   rte.advert_seqnum = true;
01126   rte.advert_metric = true;
01127   rte.changed_at = now;
01128   rte.new_seqnum_at = now;
01129   rte.wst = 0;
01130   rte.timeout_event = 0;                // Don't time out our localhost :)
01131   
01132   rte.q = 0;            // Don't buffer pkts for self!
01133   
01134   table_->AddEntry (rte);
01135 
01136   // kick off periodic advertisments
01137   periodic_callback_ = new Event ();
01138   Scheduler::instance ().schedule (helper_, 
01139                                    periodic_callback_,
01140                                    jitter (DSDV_STARTUP_JITTER, be_random_));
01141 }
01142 
01143 int 
01144 DSDV_Agent::command (int argc, const char *const *argv)
01145 {
01146   if (argc == 2)
01147     {
01148       if (strcmp (argv[1], "start-dsdv") == 0)
01149         {
01150           startUp();
01151           return (TCL_OK);
01152         }
01153       else if (strcmp (argv[1], "dumprtab") == 0)
01154         {
01155           Packet *p2 = allocpkt ();
01156           hdr_ip *iph2 = HDR_IP(p2);
01157           rtable_ent *prte;
01158 
01159           printf ("Table Dump %d[%d]\n----------------------------------\n",
01160                   iph2->saddr(), iph2->sport());
01161         trace ("VTD %.5f %d:%d\n", Scheduler::instance ().clock (),
01162                  iph2->saddr(), iph2->sport());
01163 
01164           /*
01165            * Freeing a routing layer packet --> don't need to
01166            * call drop here.
01167            */
01168         Packet::free (p2);
01169 
01170           for (table_->InitLoop (); (prte = table_->NextLoop ());)
01171             output_rte ("\t", prte, this);
01172 
01173           printf ("\n");
01174 
01175           return (TCL_OK);
01176         }
01177       else if (strcasecmp (argv[1], "ll-queue") == 0)
01178         {
01179         if (!(ll_queue = (PriQueue *) TclObject::lookup (argv[2])))
01180             {
01181               fprintf (stderr, "DSDV_Agent: ll-queue lookup of %s failed\n", argv[2]);
01182               return TCL_ERROR;
01183             }
01184 
01185           return TCL_OK;
01186         }
01187 
01188     }
01189   else if (argc == 3)
01190     {
01191       if (strcasecmp (argv[1], "addr") == 0) {
01192          int temp;
01193          temp = Address::instance().str2addr(argv[2]);
01194          myaddr_ = temp;
01195          return TCL_OK;
01196       }
01197       TclObject *obj;
01198       if ((obj = TclObject::lookup (argv[2])) == 0)
01199         {
01200           fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1],
01201                    argv[2]);
01202           return TCL_ERROR;
01203         }
01204       if (strcasecmp (argv[1], "tracetarget") == 0)
01205         {
01206           
01207           tracetarget = (Trace *) obj;
01208           return TCL_OK;
01209         }
01210       else if (strcasecmp (argv[1], "node") == 0) {
01211               node_ = (MobileNode*) obj;
01212               return TCL_OK;
01213       }
01214       else if (strcasecmp (argv[1], "port-dmux") == 0) {
01215               port_dmux_ = (NsObject *) obj;
01216               return TCL_OK;
01217       }
01218     }
01219   
01220   return (Agent::command (argc, argv));
01221 }
01222 
01223 
01224 
01225 

Generated on Tue Apr 20 12:14:14 2004 for NS2.26SourcesOriginal by doxygen 1.3.3