linkcache.cc

Go to the documentation of this file.
00001 
00002 /*
00003  * linkcache.cc
00004  * Copyright (C) 2000 by the University of Southern California
00005  * $Id: linkcache.cc,v 1.2 2005/08/25 18:58:05 johnh Exp $
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00019  *
00020  *
00021  * The copyright of this module includes the following
00022  * linking-with-specific-other-licenses addition:
00023  *
00024  * In addition, as a special exception, the copyright holders of
00025  * this module give you permission to combine (via static or
00026  * dynamic linking) this module with free software programs or
00027  * libraries that are released under the GNU LGPL and with code
00028  * included in the standard release of ns-2 under the Apache 2.0
00029  * license or under otherwise-compatible licenses with advertising
00030  * requirements (or modified versions of such code, with unchanged
00031  * license).  You may copy and distribute such a system following the
00032  * terms of the GNU GPL for this module and the licenses of the
00033  * other code concerned, provided that you include the source code of
00034  * that other code when and as the GNU GPL requires distribution of
00035  * source code.
00036  *
00037  * Note that people who make modified versions of this module
00038  * are not obligated to grant this special exception for their
00039  * modified versions; it is their choice whether to do so.  The GNU
00040  * General Public License gives permission to release a modified
00041  * version without this exception; this exception also makes it
00042  * possible to release a modified version which carries forward this
00043  * exception.
00044  *
00045  */
00046 //
00047 // Other copyrights might apply to parts of this software and are so
00048 // noted when applicable.
00049 //
00050 // Ported from CMU/Monarch's code, appropriate copyright applies.  
00051 #ifdef DSR_LINKCACHE
00052 
00053 #include <god.h>
00054 #include "path.h"
00055 #include "routecache.h"
00056 #include <list.h>
00057 #ifdef DSR_CACHE_STATS
00058 #include "cache_stats.h"
00059 #endif
00060 
00061 #define CURRENT_TIME Scheduler::instance().clock()
00062 #define MAX_SIMTIME  86400
00063 
00064 bool cache_ignore_hints = false;     // ignore all hints?
00065 bool cache_use_overheard_routes = true; 
00066 
00067 // Specifies whether or not to retain links after they go bad
00068 // I don't think this is implemented.
00069 static const bool lc_cache_negative_links = false;
00070 static const double lc_neg_cache_life = 1.0;
00071 
00072 // When inserting/deleting link A->B, also insert/delete B->A.
00073 static const bool lc_bidirectional_links = true;
00074 
00075 // Evict "unreachable" links from the cache.
00076 static const bool lc_evict_unreachable_links = false;
00077 
00078 // do we expire in realtime? or do we wait for use?
00079 //#define REALTIME_EXPIRE
00080 
00081 // The maximum number of nodes supported by the cache.
00082 #define LC_MAX_NODES 200
00083 
00084 // General generational stuff...
00085 static const double lc_gen_use_bonus = 300;
00086 
00087 // Static stuff
00088 static const double lc_static_discover_life = 5.0;
00089 static const double lc_static_overhear_life = 5.0;
00090 
00091 // Table stuff
00092 static const double lc_table_init_val = 50.0;
00093 static const double lc_table_mult_by  = 0.5;
00094 static const double lc_linear_alpha   = 1.0/8.0;
00095 static const double lc_exp_add_amt    = 2.0;
00096 static const double lc_exp_div_amt    = 2.0;
00097 static const double lc_minlifetime    = 2.0;
00098 
00099 // types of linkgens
00100 #define EXPPOLICY_INFINITE  0
00101 #define EXPPOLICY_STATIC    1
00102 #define EXPPOLICY_LINEAR    2
00103 #define EXPPOLICY_EXP       3
00104 #ifdef GOD_STABILITY
00105 #define EXPPOLICY_GOD_OMNI  4
00106 #define EXPPOLICY_GOD_TABLE 5
00107 #endif
00108 #define LONGEST_LIVED_ROUTE
00109 
00110 static const int lc_exppolicy = EXPPOLICY_EXP;
00111 
00112 #ifdef GOD_STABILITY
00113 extern double *godavglife;
00114 #endif
00115 
00116 #ifndef REALTIME_EXPIRE
00117 // statistics...
00118 #define IS_GOOD     0
00119 #define IS_BAD      1
00120 #define CALLED_GOOD 0
00121 #define CALLED_BAD  2
00122 static int expirestats[4];
00123 #endif
00124 
00125 static int verbose_debug = 0;
00126 
00127 // *****************************************************
00128 
00129 class Link {
00130 public:
00131     Link(nsaddr_t dst) {
00132         ln_dst = dst;
00133         ln_flags = ln_cost = 0;
00134         ln_timeout = 0.0;
00135         ln_insert = 0.0;
00136         ln_t = 0.0;
00137         ln_linktype = LT_NONE;
00138         ln_logstat = LS_UNLOGGED;
00139     }
00140 
00141     inline bool expired() {
00142         return (ln_timeout <= CURRENT_TIME);
00143     }
00144 
00145     LIST_ENTRY(Link) ln_link;
00146     nsaddr_t   ln_dst;
00147     int        ln_flags;       // link status information
00148 #define LINK_FLAG_UP 0x01
00149 
00150     /*
00151      * Right now all links have the same cost (1). - josh
00152      */
00153     int        ln_cost;        // cost of using the link
00154 
00155     /*
00156      * the use of ln_timeout to expire links from the
00157      * cache has not yet been implemented. - josh
00158      * Implemented. - yihchun
00159      */
00160     double     ln_timeout;     // when the link expires
00161     double     ln_insert;      // when the link expires
00162 
00163 #define LINK_TIMEOUT MAX_SIMTIME
00164 
00165     // mirror the values kept in class ID
00166     Time       ln_t;
00167     Link_Type  ln_linktype;
00168     Log_Status ln_logstat;
00169 };
00170 
00171 LIST_HEAD(dsrLinkHead, Link);
00172 
00173 class LinkCache : public RouteCache {
00174 friend class MobiHandler;
00175 
00176 public:
00177     LinkCache();
00178 
00179     void noticeDeadLink(const ID&from, const ID& to, Time t);
00180     // the link from->to isn't working anymore, purge routes containing
00181     // it from the cache
00182 
00183     void noticeRouteUsed(const Path& route, Time t,
00184                  const ID& who_from);
00185     // tell the cache about a route we saw being used
00186 
00187     void addRoute(const Path& route, Time t, const ID& who_from);
00188     // add this route to the cache (presumably we did a route request
00189     // to find this route and don't want to lose it)
00190 
00191     bool findRoute(ID dest, Path& route, int for_me = 0);
00192     // if there is a cached path from us to dest returns true and fills in
00193     // the route accordingly. returns false otherwise
00194     // if for_use, then we assume that the node really wants to keep 
00195     // the returned route so it will be promoted to primary storage
00196     // if not there already
00197     int command(int argc, const char*const* argv);
00198 
00199 protected:
00200     dsrLinkHead lcache[LC_MAX_NODES + 1];
00201     // note the zeroth index is not used
00202 
00203     int addLink(const ID& from, const ID& to,
00204             int flags, double timeout = LINK_TIMEOUT, int cost = 1);
00205     int delLink(const ID& from, const ID& to);
00206     Link* findLink(int from, int to);
00207     void purgeLink(void);
00208     void dumpLink(void);
00209 
00210     void Link_to_ID(Link* l, ID& id);
00211 
00212 #ifdef DSR_CACHE_STATS
00213     void checkLink_logall(const ID& from, const ID& to, int action);
00214     void checkLink(const ID& from, const ID& to, int action);
00215     void periodic_checkCache();
00216 
00217     struct cache_stats stat;
00218 #endif
00219 private:
00221     // Dijkstra's Algorithm
00222 
00223     double dirty; // the next time it gets dirty
00224 #ifdef LONGEST_LIVED_ROUTE
00225     double dl[LC_MAX_NODES + 1];
00226 #endif
00227     u_int32_t d[LC_MAX_NODES + 1];
00228     u_int32_t pi[LC_MAX_NODES + 1];
00229     bool S[LC_MAX_NODES + 1];
00230     double exptable[LC_MAX_NODES + 1];
00231 #define INFINITY 0x7fffffff
00232 
00233     void init_single_source(int s);
00234 #ifdef LONGEST_LIVED_ROUTE
00235     void relax(u_int32_t u, u_int32_t v, u_int32_t w, double);
00236 #else
00237     void relax(u_int32_t u, u_int32_t v, u_int32_t w);
00238 #endif
00239     int  extract_min_q(void);
00240     void dijkstra(void);
00241     void dump_dijkstra(int dst);
00242     double find_timeout(ID a, ID b, bool discovered);
00243 };
00244 
00246 
00247 double LinkCache::find_timeout(ID a, ID b, bool discovered) {
00248     double lifetime = 0.0;
00249     switch (lc_exppolicy) {
00250     case EXPPOLICY_INFINITE:
00251 #ifdef GOD_STABILITY
00252         case EXPPOLICY_GOD_OMNI:
00253 #endif
00254         return MAX_SIMTIME;
00255     case EXPPOLICY_LINEAR: case EXPPOLICY_EXP:
00256         lifetime = exptable[a.addr] > exptable[b.addr] ? 
00257           exptable[b.addr] : exptable[a.addr];
00258         lifetime *= lc_table_mult_by;
00259         break;
00260 #ifdef GOD_STABILITY
00261     case EXPPOLICY_GOD_TABLE:
00262         lifetime = godavglife[a.addr] > godavglife[b.addr] ? 
00263           godavglife[b.addr] : godavglife[a.addr];
00264         lifetime *= lc_table_mult_by;
00265         break;
00266 #endif
00267     case EXPPOLICY_STATIC:
00268         lifetime = discovered ? lc_static_discover_life :
00269           lc_static_overhear_life;
00270         break;
00271     default:
00272         assert(0);
00273     }
00274 
00275     if (lifetime < lc_minlifetime)
00276         lifetime = lc_minlifetime;
00277 
00278     return CURRENT_TIME + lifetime;
00279 }
00280 
00281 RouteCache *
00282 makeRouteCache()
00283 {
00284   return new LinkCache();
00285 }
00286 
00287 LinkCache::LinkCache() : RouteCache()
00288 {
00289     int i = 0;
00290 
00291     for(i = 0; i <= LC_MAX_NODES; i++) {
00292         LIST_INIT(&lcache[i]);
00293         exptable[i] = lc_table_init_val;
00294     }
00295 
00296 #ifdef DSR_CACHE_STATS
00297     stat.reset();
00298 #endif
00299     dirty = -1;
00300 }
00301 
00302 
00303 int
00304 LinkCache::command(int argc, const char*const* argv)
00305 {
00306   if(argc == 2 && strcasecmp(argv[1], "startdsr") == 0)
00307     { 
00308       if (ID(1,::IP) == net_id) 
00309     trace("Sconfig %.5f using LINKCACHE %d", Scheduler::instance().clock(),
00310         lc_exppolicy);
00311       // FALL-THROUGH
00312     }
00313 
00314   if(argc == 3)
00315     {   
00316       if (strcasecmp(argv[1], "ip-addr") == 0)
00317         {
00318           assert(atoi(argv[2]) <= LC_MAX_NODES);
00319 
00320 #ifndef REALTIME_EXPIRE
00321       if (atoi(argv[2]) == 1)
00322         bzero(expirestats, sizeof(expirestats));
00323 #endif
00324 
00325           // don't return
00326         } 
00327     }
00328   return RouteCache::command(argc, argv);
00329 }
00330 
00331 
00332 void
00333 LinkCache::noticeDeadLink(const ID& from, const ID& to, Time)
00334 {
00335     Link *l = findLink(from.addr, to.addr);
00336 
00337     if (l && (l->ln_flags & LINK_FLAG_UP) &&
00338         (lc_exppolicy == EXPPOLICY_LINEAR || 
00339          lc_exppolicy == EXPPOLICY_EXP)) {
00340         if (lc_exppolicy == EXPPOLICY_LINEAR) {
00341             exptable[from.addr]=lc_linear_alpha*exptable[from.addr]
00342               +(CURRENT_TIME-l->ln_insert)*(1-lc_linear_alpha);
00343             exptable[to.addr]=lc_linear_alpha*exptable[to.addr]
00344               +(CURRENT_TIME-l->ln_insert)*(1-lc_linear_alpha);
00345         } else {
00346             exptable[from.addr] /= lc_exp_div_amt;
00347             exptable[to.addr] /= lc_exp_div_amt;
00348         }
00349     }
00350 
00351     if(lc_cache_negative_links == true) {
00352         if(l) {
00353             l->ln_flags &= ~LINK_FLAG_UP;
00354             l->ln_insert = CURRENT_TIME;
00355             l->ln_timeout = CURRENT_TIME + lc_neg_cache_life;
00356             dirty = CURRENT_TIME;
00357         } else {
00358             addLink(from, to, 0, CURRENT_TIME + lc_neg_cache_life);
00359         }
00360     }
00361     else {
00362         if(l) {
00363 #ifdef DSR_CACHE_STATS
00364             checkLink(from, to, ACTION_DEAD_LINK);
00365 #endif
00366             (void) delLink(from, to);
00367         }
00368     }
00369 }
00370 
00371 void
00372 LinkCache::noticeRouteUsed(const Path& p, Time t, const ID& who_from)
00373 {
00374   Path stub;
00375   int c;
00376 
00377   if(pre_noticeRouteUsed(p, stub, t, who_from) == 0)
00378       return;
00379   
00380 #ifdef DSR_CACHE_STATS
00381   int link_notice_count = stat.link_notice_count; 
00382   int link_notice_bad_count = stat.link_notice_bad_count;   
00383 #endif
00384 
00385   /*
00386    * Add each link in the "path" to the route cache.
00387    */
00388   for(c = 0; c < stub.length() - 1; c++) {
00389       if(addLink(stub[c], stub[c+1], LINK_FLAG_UP, 
00390              find_timeout(stub[c], stub[c+1], false))) {
00391 #ifdef DSR_CACHE_STATS
00392         checkLink(stub[c], stub[c+1], ACTION_NOTICE_ROUTE);
00393 #endif
00394       }
00395   }
00396 
00397 #ifdef DSR_CACHE_STATS
00398   if(stat.link_notice_count > link_notice_count)
00399       stat.route_notice_count++;
00400   if(stat.link_notice_bad_count > link_notice_bad_count)
00401       stat.route_notice_bad_count++;
00402 #endif
00403 }
00404 
00405 void
00406 LinkCache::addRoute(const Path& route, Time t, const ID& who_from)
00407 {
00408   Path rt;
00409   int c;
00410 
00411   if(pre_addRoute(route, rt, t, who_from) == 0)
00412       return;
00413   
00414 #ifdef DSR_CACHE_STATS
00415   int link_add_count = stat.link_add_count; 
00416   int link_add_bad_count = stat.link_add_bad_count;   
00417 #endif
00418 
00419   for(c = 0; c < rt.length() - 1; c++) {
00420       if(addLink(rt[c], rt[c+1], LINK_FLAG_UP,
00421              find_timeout(rt[c], rt[c+1], true))) {
00422 #ifdef DSR_CACHE_STATS
00423           checkLink(rt[c], rt[c+1], ACTION_ADD_ROUTE);
00424 #endif
00425       }
00426   }
00427 
00428 #ifdef DSR_CACHE_STATS
00429   if(stat.link_add_count > link_add_count)
00430       stat.route_add_count++;
00431   if(stat.link_add_bad_count > link_add_bad_count)
00432       stat.route_add_bad_count++;
00433 #endif
00434 }
00435 
00436 bool
00437 LinkCache::findRoute(ID dest, Path& route, int for_me = 0)
00438 {
00439     u_int32_t v;
00440     int rpath[MAX_SR_LEN];
00441     u_int32_t roff = 0;
00442 
00443     if(verbose_debug) dumpLink();
00444 
00445     /*
00446      * Compute all of the shortest paths...
00447      */
00448     if(dirty <= CURRENT_TIME) {
00449         dijkstra();
00450 
00451         // remove all of the links for nodes that are unreachable
00452         if(lc_evict_unreachable_links == true) {
00453             purgeLink();
00454         }
00455     }
00456     if(verbose_debug) dump_dijkstra(dest.addr);
00457 
00458     /*
00459      * Trace backwards to figure out the path to DEST
00460      */
00461     for(v = dest.addr; d[v] < INFINITY; v = pi[v]) {
00462       //assert(v >= 1 && v <= LC_MAX_NODES);
00463         if (roff >= MAX_SR_LEN) {
00464                 // path between us and dest is too long to be useful
00465                 break;
00466         }
00467 
00468         rpath[roff] = v;
00469         roff++;
00470 
00471         if(v == net_id.addr)
00472             break;
00473     }
00474 
00475     if(roff < 2 || d[v] == INFINITY || roff >= MAX_SR_LEN) {
00476 #ifdef DSR_CACHE_STATS
00477         stat.route_find_count += 1;
00478         if (for_me) stat.route_find_for_me += 1; 
00479         stat.route_find_miss_count += 1;
00480 #endif
00481         return false; // no path
00482     }
00483 
00484 
00485 #ifdef GOD_STABILITY
00486     /* The logic for God's omniscient expiration policy:
00487      *   if we expire in realtime, kill dead links immediately, and
00488      *     goto top. XXX this could create unnecessary overhead.
00489      *   if we expire on the fly, we set the timeout to an appropriate
00490      *     value, depending on whether or not the link is valid.
00491      */
00492     if (lc_exppolicy == EXPPOLICY_GOD_OMNI) {
00493         int last = net_id.addr;
00494         for (v=1;v<roff;v++) {
00495             Link *l = findLink(last, rpath[roff-v-1]);
00496 #ifdef REALTIME_EXPIRE
00497             if (God::instance()->hops(last, rpath[roff-v-1])!=1) {
00498                 LIST_REMOVE(l, ln_link);
00499                 delete l;
00500                 dirty = CURRENT_TIME;
00501                 return findRoute(dest, route, for_me);
00502             }
00503 #else
00504             if (God::instance()->hops(last, rpath[roff-v-1])!=1) {
00505                 l->ln_timeout = CURRENT_TIME;
00506             } else {
00507                 l->ln_timeout = MAX_SIMTIME;
00508             }
00509 #endif
00510             last = rpath[roff-v-1];
00511         }
00512     }
00513 #endif //GOD_STABILITY 
00514 
00515 
00516 #ifndef REALTIME_EXPIRE
00517     int last = net_id.addr;
00518     for (v=1;v<roff;v++) {
00519         Link *l = findLink(last, rpath[roff-v-1]);
00520         bool godsays = God::instance()->hops(last, rpath[roff-v-1])==1;
00521         last = rpath[roff-v-1];
00522         assert(l);
00523         if (l->expired()) {
00524             expirestats[CALLED_BAD + (godsays?IS_GOOD:IS_BAD)]++;
00525             LIST_REMOVE(l, ln_link);
00526             delete l;
00527             dirty = CURRENT_TIME;
00528             return findRoute(dest, route, for_me);
00529         } else {
00530             expirestats[CALLED_GOOD + (godsays?IS_GOOD:IS_BAD)]++;
00531         }
00532     }
00533 #endif
00534 
00535     /*
00536      * Build the path that we need...
00537      */
00538     ID id;
00539 
00540     route.reset();
00541 
00542     id.addr = net_id.addr;  // source route is rooted at "us"
00543     id.type = ::IP;
00544     id.link_type = LT_NONE;
00545     id.log_stat = LS_NONE;
00546     route.appendToPath(id);
00547 
00548     for(v = 1; v < roff ; v++) {
00549         assert((int) (roff - v - 1) >= 0 && (roff - v - 1) < MAX_SR_LEN);
00550 
00551         Link *l = findLink(route[v-1].addr, rpath[roff - v - 1]);
00552 
00553         assert(l && !l->expired());
00554 
00555         if (for_me)
00556             l->ln_timeout += lc_gen_use_bonus;
00557 
00558         if (lc_exppolicy == EXPPOLICY_EXP) {
00559             exptable[route[v-1].addr] += lc_exp_add_amt;
00560             exptable[rpath[roff - v - 1]] += lc_exp_add_amt;
00561         }
00562 
00563         id.addr = rpath[roff - v - 1];
00564         id.type = ::IP;
00565         id.link_type = LT_NONE;
00566         id.log_stat = LS_NONE;
00567         route.appendToPath(id);
00568 
00569         route[v-1].t = l->ln_t;
00570         route[v-1].link_type = l->ln_linktype;
00571         route[v-1].log_stat = l->ln_logstat;
00572     }
00573     
00574 #ifdef DSR_CACHE_STATS
00575     int bad = checkRoute_logall(&route, ACTION_FIND_ROUTE, 0);
00576     stat.route_find_count += 1; 
00577     if (for_me) stat.route_find_for_me += 1;     
00578     stat.route_find_bad_count += bad ? 1 : 0;
00579     stat.link_find_count += route.length() - 1;
00580     stat.link_find_bad_count +=  bad;
00581 #endif
00582     return true;
00583 }
00584 
00585 
00586 void
00587 LinkCache::Link_to_ID(Link *l, ID& id)
00588 {
00589     id.addr = l->ln_dst;
00590     id.type = ::IP;
00591     id.t = l->ln_t;
00592     id.link_type = l->ln_linktype;
00593     id.log_stat = l->ln_logstat;
00594 }
00595 
00597 
00598 /*
00599  * Dijkstra's algorithm taken from CLR.
00600  */
00601 
00602 void
00603 LinkCache::init_single_source(int s)
00604 {
00605     int v;
00606 
00607     for(v = 1; v <= LC_MAX_NODES; v++) {
00608         d[v] = INFINITY;
00609 #ifdef LONGEST_LIVED_ROUTE
00610         dl[v] = 0; // dies immediately
00611 #endif
00612         pi[v] = 0; // invalid node ID
00613 
00614         S[v] = false;
00615     }
00616     d[s] = 0;
00617 #ifdef LONGEST_LIVED_ROUTE
00618     dl[s] = MAX_SIMTIME;
00619 #endif
00620 }
00621 
00622 void
00623 #ifdef LONGEST_LIVED_ROUTE
00624 LinkCache::relax(u_int32_t u, u_int32_t v, u_int32_t w, double timeout)
00625 #else
00626 LinkCache::relax(u_int32_t u, u_int32_t v, u_int32_t w)
00627 #endif
00628 {
00629     assert(d[u] < INFINITY);
00630     assert(w == 1); /* make sure everything's working how I expect */
00631 
00632     if(d[v] > d[u] + w
00633 #ifdef LONGEST_LIVED_ROUTE
00634        || (d[v] == d[u] + w && dl[v] < dl[u] && dl[v] < timeout)
00635 #endif
00636        ) {
00637         d[v] = d[u] + w;
00638 #ifdef LONGEST_LIVED_ROUTE
00639         dl[v] = (dl[u] > timeout) ? timeout : dl[u];
00640 #endif
00641         pi[v] = u;
00642     }
00643 }
00644 
00645 
00646 int
00647 LinkCache::extract_min_q()
00648 {
00649     int u;
00650     int min_u = 0;
00651 
00652     for(u = 1; u <= LC_MAX_NODES; u++) {
00653         if(S[u] == false && d[u] < INFINITY && 
00654            (min_u == 0 || d[u] < d[min_u] 
00655 #ifdef LONGEST_LIVED_ROUTE
00656             || (d[u] == d[min_u] && dl[u] > dl[min_u])
00657 #endif
00658            )) {
00659             min_u = u;
00660         }
00661     }
00662     return min_u; // (min_u == 0) ==> no valid link
00663 }
00664 
00665 void
00666 LinkCache::dijkstra()
00667 {
00668     int u;  
00669     Link *v;
00670 
00671     dirty = MAX_SIMTIME;  // all of the info is up-to-date
00672 
00673 #ifdef REALTIME_EXPIRE
00674     for (u=1; u <= LC_MAX_NODES; u++) {
00675         v = lcache[u].lh_first;
00676         while (v) {
00677             if(v->ln_timeout <= CURRENT_TIME) {
00678                 Link *tmp;
00679                 tmp = v->ln_link.le_next;
00680                 LIST_REMOVE(v, ln_link);
00681                 delete v;
00682                 v = tmp;
00683             } else {
00684                 if (v->ln_timeout < dirty)
00685                     dirty = v->ln_timeout;
00686                 v = v->ln_link.le_next;
00687             }
00688         }
00689     }
00690 #endif
00691 
00692     init_single_source(net_id.addr);
00693 
00694     while((u = extract_min_q()) != 0) {
00695         S[u] = true;
00696         v = lcache[u].lh_first;
00697         for( ; v; v = v->ln_link.le_next) {
00698             if(v->ln_flags & LINK_FLAG_UP) {
00699 #ifdef LONGEST_LIVED_ROUTE
00700                 relax(u, v->ln_dst, v->ln_cost, v->ln_timeout);
00701 #else
00702                 relax(u, v->ln_dst, v->ln_cost);
00703 #endif
00704             }
00705         }
00706     }
00707 }
00708 
00709 void
00710 LinkCache::dump_dijkstra(int dst)
00711 {
00712     static char tbuf[512];
00713     u_int32_t u, toff = 0;
00714 
00715     bzero(tbuf, sizeof(tbuf));
00716     sprintf(tbuf, "SRC %.9f _%s_ dijkstra *%d* ",
00717         CURRENT_TIME, net_id.dump(), dst);
00718     toff = strlen(tbuf);
00719 
00720     for(u = 1; u <= LC_MAX_NODES; u++) {
00721         if(d[u] < INFINITY) {
00722             sprintf(tbuf+toff, "%d,%d,%d ", u, d[u], pi[u]);
00723             toff = strlen(tbuf);
00724             assert(toff < sizeof(tbuf));
00725         }
00726     }
00727 
00728     trace("%s", tbuf);
00729 }
00730     
00731 
00733 
00734 int
00735 LinkCache::addLink(const ID& from, const ID& to,
00736            int flags, double timeout, int cost)
00737 {
00738     Link *l;
00739     int rc = 0;
00740 
00741     if((l = findLink(from.addr, to.addr)) == 0) {
00742         l = new Link(to.addr);
00743         assert(l);
00744         LIST_INSERT_HEAD(&lcache[from.addr], l, ln_link);
00745         dirty = CURRENT_TIME;
00746         l->ln_insert = CURRENT_TIME;
00747         rc = 1;
00748     } else if ((l->ln_flags & flags) != flags) {
00749         // we want to set flags
00750         dirty = CURRENT_TIME;
00751         l->ln_insert = CURRENT_TIME;
00752     }
00753 
00754     l->ln_t = CURRENT_TIME;
00755     l->ln_linktype = from.link_type;
00756     l->ln_flags |= flags;
00757     l->ln_cost = cost;
00758     l->ln_timeout = timeout;
00759 
00760     if(lc_bidirectional_links == false)
00761         return rc;
00762 
00763     /*
00764      * Add the "other" direction of the link...
00765      */
00766     if((l = findLink(to.addr, from.addr)) == 0) {
00767         l = new Link(from.addr);
00768         assert(l);
00769         l->ln_insert = CURRENT_TIME;
00770         LIST_INSERT_HEAD(&lcache[to.addr], l, ln_link);
00771         dirty = CURRENT_TIME;
00772     } else if ((l->ln_flags & flags) != flags) {
00773         // we want to set flags
00774         dirty = CURRENT_TIME;
00775         l->ln_insert = CURRENT_TIME;
00776     }
00777     l->ln_t = CURRENT_TIME;
00778     l->ln_linktype = from.link_type;
00779     l->ln_flags |= flags;
00780     l->ln_cost = cost;
00781     l->ln_timeout = timeout;
00782 
00783     return rc;
00784 }
00785 
00786 int
00787 LinkCache::delLink(const ID& from, const ID& to)
00788 {
00789     Link *l;
00790     int rc = 0;
00791 
00792     if((l = findLink(from.addr, to.addr))) {
00793         LIST_REMOVE(l, ln_link);
00794         delete l;
00795         dirty = CURRENT_TIME;
00796         rc = 1;
00797     }
00798 
00799     if(lc_bidirectional_links == false)
00800         return rc;
00801 
00802     /*
00803      * Remove the "other" direction of the link...
00804      */
00805     if((l = findLink(to.addr, from.addr))) {
00806         LIST_REMOVE(l, ln_link);
00807         delete l;
00808         dirty = CURRENT_TIME;
00809     }
00810 
00811     return rc;
00812 }
00813 
00814 Link*
00815 LinkCache::findLink(int from, int to)
00816 {
00817     Link *l;
00818 
00819     for(l = lcache[from].lh_first; l; l = l->ln_link.le_next) {
00820         if(l->ln_dst == to) {
00821             return l;
00822         }
00823     }
00824     return 0;
00825 }
00826 
00827 void
00828 LinkCache::purgeLink()
00829 {
00830     int u;
00831     Link *l;
00832 
00833     for(u = 1; u <= LC_MAX_NODES; u++) {
00834         if(d[u] == INFINITY) {
00835             ID from, to;
00836 
00837             from.addr = u;
00838             from.type = ::IP;
00839             from.link_type = LT_NONE;
00840             from.log_stat = LS_NONE;
00841 
00842             l = lcache[u].lh_first;
00843             for( ; l; l = l->ln_link.le_next) {
00844                 Link_to_ID(l, to);
00845 #ifdef DSR_CACHE_STATS
00846                 checkLink_logall(from, to, ACTION_EVICT);
00847 #endif
00848                 (void) delLink(from, to);
00849             }
00850         }
00851     }
00852 }
00853 
00854 
00855 void
00856 LinkCache::dumpLink()
00857 {
00858     Link *l;
00859     int i;
00860     static char tbuf[512];
00861     u_int32_t toff = 0;
00862 
00863     bzero(tbuf, sizeof(tbuf));
00864     sprintf(tbuf, "SRC %.9f _%s_ dump-link ", CURRENT_TIME, net_id.dump());
00865     toff = strlen(tbuf);
00866 
00867     for(i = 1; i <= LC_MAX_NODES; i++) {
00868         for(l = lcache[i].lh_first; l; l = l->ln_link.le_next) {
00869             sprintf(tbuf+toff, "%d->%d, ", i, l->ln_dst);
00870             toff = strlen(tbuf);
00871             assert(toff < sizeof(tbuf));
00872         }
00873     }
00874 
00875     trace("%s", tbuf);
00876 }
00877 
00878 #ifdef DSR_CACHE_STATS
00879 
00880 /*
00881  * Called only from "purgeLink"
00882  */
00883 void
00884 LinkCache::checkLink_logall(const ID& from, const ID& to, int action)
00885 {
00886     Link *l = findLink(from.addr, to.addr);
00887 
00888     assert(action == ACTION_EVICT);
00889     assert(l);
00890 
00891     if(God::instance()->hops(from.addr, to.addr) != 1) {
00892         trace("SRC %.9f _%s_ %s [%d %d] %s->%s dead %d %.9f",
00893               CURRENT_TIME, net_id.dump(),
00894               action_name[action], 0, 0,
00895               from.dump(), to.dump(),
00896               l->ln_linktype, l->ln_t);
00897     }
00898 }
00899 
00900 void
00901 LinkCache::checkLink(const ID& from, const ID& to, int action)
00902 {
00903     Link *l = findLink(from.addr, to.addr);
00904     int alive = 0;
00905 
00906     assert(l);
00907 
00908     if(God::instance()->hops(from.addr, to.addr) != 1) {
00909         if(l->ln_logstat == LS_UNLOGGED) {
00910             trace("SRC %.9f _%s_ %s [%d %d] %s->%s dead %d %.9f",
00911                 CURRENT_TIME, net_id.dump(),
00912                 action_name[action], 0, 0,
00913                 from.dump(), to.dump(),
00914                 l->ln_linktype, l->ln_t);
00915             l->ln_logstat = LS_LOGGED;
00916         }
00917     } else {
00918         alive = 1;
00919         if(l->ln_logstat == LS_LOGGED) {
00920             trace("SRC %.9f _%s_ resurrected-link [%d %d] %s->%s dead %d %.9f",
00921                 CURRENT_TIME, net_id.dump(), 0, 0,
00922                 from.dump(), to.dump(),
00923                 l->ln_linktype, l->ln_t);
00924             l->ln_logstat = LS_UNLOGGED;
00925         }
00926         }
00927 
00928     switch(action) {
00929     case ACTION_ADD_ROUTE:
00930         stat.link_add_count += 1;
00931         if(alive == 0){
00932                 stat.link_add_bad_count += 1;
00933         }
00934         if(l->ln_linktype == LT_TESTED)
00935             stat.link_add_tested += 1;
00936         break;
00937 
00938     case ACTION_NOTICE_ROUTE:
00939         stat.link_notice_count += 1;
00940         if(alive == 0){
00941             stat.link_notice_bad_count += 1;
00942         }
00943         if(l->ln_linktype == LT_TESTED)
00944             stat.link_notice_tested += 1;
00945         break;
00946     }
00947 }
00948 
00949 void
00950 LinkCache::periodic_checkCache()
00951 {
00952   int c;
00953   int link_count = 0;
00954   int link_bad_count = 0;
00955   double link_bad_time = 0.0;
00956   int link_bad_tested = 0;
00957   int link_good_tested = 0;
00958 
00959 #ifndef REALTIME_EXPIRE
00960   if (ID(1,::IP) == net_id) 
00961     trace("SRC %.9f _%s_ cache-expire-bits %d %d %d %d",
00962       CURRENT_TIME, net_id.dump(), expirestats[0], expirestats[1], 
00963       expirestats[2], expirestats[3]);
00964 #endif
00965 
00966   for(c = 1; c <= LC_MAX_NODES; c++) {
00967     Link *v = lcache[c].lh_first;
00968     for( ; v; v = v->ln_link.le_next) {
00969         link_count += 1;
00970         if(God::instance()->hops(c, v->ln_dst) != 1) {
00971             link_bad_count += 1;
00972             link_bad_time += CURRENT_TIME - v->ln_t;
00973             if(v->ln_linktype == LT_TESTED)
00974                 link_bad_tested += 1;
00975         } else {
00976             if(v->ln_linktype == LT_TESTED)
00977                 link_good_tested += 1;
00978         }
00979     }
00980   }
00981 
00982   trace("SRC %.9f _%s_ cache-summary %d %d %d %d | %d %.9f %d %d | %d %d %d %d %d | %d %d %d %d %d | %d %d %d %d %d %d",
00983     CURRENT_TIME, net_id.dump(),
00984         0, //route_count,
00985         0, // route_bad_count,
00986         link_count, // subroute_count,
00987         0, // subroute_bad_count,
00988 
00989         link_bad_count,
00990         link_bad_count ? link_bad_time/link_bad_count : 0.0,
00991         link_bad_tested,
00992         link_good_tested,
00993 
00994         stat.route_add_count,     // always 0 -- not increment
00995         stat.route_add_bad_count, // always 0 -- not increment
00996         stat.link_add_count, // stat.subroute_add_count,
00997         stat.link_add_bad_count, // stat.subroute_add_bad_count,
00998         stat.link_add_tested,
00999              
01000         stat.route_notice_count,
01001         stat.route_notice_bad_count,
01002         stat.link_notice_count, // stat.subroute_notice_count,
01003         stat.link_notice_bad_count, // stat.subroute_notice_bad_count,
01004         stat.link_notice_tested,
01005              
01006         stat.route_find_count,
01007     stat.route_find_for_me,
01008         stat.route_find_bad_count,
01009         stat.route_find_miss_count,
01010         stat.subroute_find_count,
01011         stat.subroute_find_bad_count);
01012   stat.reset();
01013 }
01014 
01015 #endif
01016 #endif //DSR_LINKCACHE

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