mprselection.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003, 2004, 2005, 2007 Laboratoire de Recherche en Informatique
00002 
00003 // This file is part of Qolyester.
00004 
00005 // Qolyester is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 // Qolyester is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 
00019 #ifndef QOLYESTER_DAEMON_ALG_MPRSELECTION_HXX
00020 # define QOLYESTER_DAEMON_ALG_MPRSELECTION_HXX 1
00021 
00022 # include "set/neighbors.hh"
00023 
00024 # include "mprselection.hh"
00025 
00026 namespace olsr {
00027 
00028   extern thnset_t       thn_set;
00029   extern utl::Mark      advset_changed;
00030 
00031   namespace alg {
00032 
00033     // The MPR selection routine.  This is the extended version,
00034     // taking into account the MPR_COVERAGE parameter, as described in
00035     // section 16.2.
00036     void mprselection()
00037     {
00038       debug << "SELECTING MPRs" << std::endl;
00039 
00040       // Declaration of several convenience types.
00041 
00042       // An address set
00043       typedef std::set<address_t>               aset_t;
00044 
00045       // A simple 2-hop neighbor set
00046       typedef std::map<address_t, aset_t>       thnsimpleset_t;
00047 
00048       // A neighbor set (in fact this is a pointer set, to spare
00049       // memory usage)
00050       typedef std::set<const set::Neighbor*, utl::pless<set::Neighbor> >
00051                                                 nset_t;
00052       // The iterator on the neighbor set, which can be used as though
00053       // the elements were references to neighbors themselves and not
00054       // pointers.
00055       typedef utl::DerefIterator<nset_t::const_iterator>
00056                                                 nset_const_iterator;
00057 
00058       // A degree map, mapping 1-hop neighbor addresses into their
00059       // degree (see the RFC 3626 section 8.3.1 for more info).
00060       typedef std::map<address_t, unsigned>     degreemap_t;
00061 
00062       // A coverer map, mapping 2-hop neighbor addresses into the set
00063       // of 1-hop neighbors that reach them.
00064       typedef std::map<address_t, aset_t>       coverermap_t;
00065 
00066       aset_t                            mprs;
00067       aset_t                            total_n2;
00068       nset_t                            rcandidates;
00069       thnsimpleset_t                    thns;
00070 
00071       // Compute the global 2-hop neighborhood.
00072 
00073       // We want to exclude 1-hop neighbors that would certainly not
00074       // be chosen as MPR regardless of the interface (asym nodes and
00075       // nodes with willingness equal to WILL_NEVER) and 2-hop
00076       // neighbors that are also symmetric 1-hop neighbors.
00077       for (thnset_t::thnset_t::iterator t = thn_set.thnset().begin();
00078            t != thn_set.thnset().end(); ++t) {
00079         cproxy_t::sym_neighborset_t::iterator   n =
00080           cproxy.sym_neighborset().find(set::Neighbor::make_key(t->main_addr()));
00081         if (n == cproxy.sym_neighborset().end() ||
00082             n->willingness() == WILL_NEVER)
00083           continue; // Ignore asym and non-willing nodes
00084         if (cproxy.sym_neighborset().find(set::Neighbor::make_key(t->twohop_addr())) !=
00085             cproxy.sym_neighborset().end())
00086           continue; // Ignore symmetric nodes
00087         thns[t->main_addr()].insert(t->twohop_addr());
00088         total_n2.insert(t->twohop_addr());
00089       }
00090 
00091 # ifdef QOLYESTER_ENABLE_MID
00092 
00093       // Cycle over all the interfaces to compute the per-interface MPR-set.
00094       for (ifaceset_t::const_iterator i = iface_set.begin();
00095            i != iface_set.end();
00096            ++i) {
00097 
00098 # else // ! QOLYESTER_ENABLE_MID
00099 
00100       {
00101         iface_t*        i = &this_interface;
00102 
00103 # endif
00104 
00105         thnsimpleset_t  lthns;
00106         nset_t          candidates;
00107         degreemap_t     degree_map;     // degree map
00108         coverermap_t    coverer_map;    // covered map
00109         aset_t          n2;             // temp N2 set
00110 
00111         // Compute the 2-hop set and candidates.
00112         for (thnsimpleset_t::const_iterator oh = thns.begin();
00113              oh != thns.end(); ++oh) {
00114           cproxy_t::sym_neighborset_t::iterator n =
00115             cproxy.sym_neighborset().find(set::Neighbor::make_key(oh->first));
00116           assert(n != cproxy.sym_neighborset().end());
00117           std::pair<set::Neighbor::linkset_t::iterator,
00118                     set::Neighbor::linkset_t::iterator> er =
00119             n->find_lifaces(i->addr());
00120           bool  sym_found = false;
00121           for (set::Neighbor::linkset_t::iterator l = er.first;
00122                l != er.second; ++l)
00123             if (l->is_sym()) {
00124               sym_found = true;
00125               break;
00126             }
00127           if (!sym_found)
00128             continue; // Ignore nodes unreachable through this iface
00129           candidates.insert(&*n);
00130           lthns.insert(*oh);
00131           degree_map[oh->first] = oh->second.size();
00132           for (aset_t::const_iterator th = oh->second.begin();
00133                th != oh->second.end(); ++th) {
00134             coverer_map[*th].insert(oh->first);
00135             n2.insert(*th);
00136           }
00137         }
00138 
00139 # ifdef QOLYESTER_ENABLE_MID
00140         aset_t          lmprs;          // iface-local MPR-set
00141 # else // ! QOLYESTER_ENABLE_MID
00142         aset_t&         lmprs = mprs;
00143 # endif
00144 
00145         // Preliminary MPR selection
00146 
00147         // Get the WILL_ALWAYS neighbors into the iface-local MPR-set first
00148         // and don't add them to the global removal-candidates set.
00149         for (nset_const_iterator n =
00150                nset_const_iterator::build(candidates.begin());
00151              n != nset_const_iterator::build(candidates.end()); ++n)
00152           if (n->willingness() == WILL_ALWAYS)
00153             lmprs.insert(n->main_addr());
00154 
00155         // Get the neighbors that are necessary relays to some 2-hop neighbors and update
00156         for (coverermap_t::const_iterator c = coverer_map.begin();
00157              c != coverer_map.end(); ++c)
00158           if (c->second.size() <= mprcoverage) {
00159             lmprs.insert(c->second.begin(), c->second.end());
00160             n2.erase(c->first);
00161           }
00162 
00163         // End of preliminary selection
00164 
00165         // Reach counter initialization and 'remaining' 2-hop neighbor
00166         // set populating
00167         // For each node in N2, the number of already-selected MPRs
00168         // reaching it is recorded.  The purpose is to let us know
00169         // when a node in N2 is already covered.
00170         typedef std::map<address_t, unsigned>   reachcount_t;
00171         reachcount_t                            reachcount;
00172         thnsimpleset_t                          rthns = lthns;
00173 
00174         for (aset_t::const_iterator m = lmprs.begin();
00175              m != lmprs.end(); ++m) {
00176           candidates.erase(&set::Neighbor::make_key(*m));
00177           thnsimpleset_t::const_iterator        oh = rthns.find(*m);
00178           assert(oh != rthns.end());
00179           for (aset_t::const_iterator th = oh->second.begin();
00180                th != oh->second.end(); ++th)
00181             if (++reachcount[*th] >= mprcoverage)
00182               n2.erase(*th);
00183         }
00184 
00185         // Cycle while N2 is not empty
00186         while (!n2.empty()) {
00187 
00188           typedef std::map<address_t, unsigned> reachmap_t;
00189           reachmap_t                            reachmap;
00190 
00191           // Build the reachability map
00192           for (nset_const_iterator n =
00193                  nset_const_iterator::build(candidates.begin());
00194                n != nset_const_iterator::build(candidates.end()); ++n)
00195             reachmap[n->main_addr()] = rthns[n->main_addr()].size();
00196 
00197           // Get the neighbor with max willingness, reachability, degree.
00198 
00199           bool                  first = true;
00200           const set::Neighbor*  maxn = 0;
00201           unsigned              r = 0;
00202           unsigned              d = 0;
00203 
00204           for (nset_const_iterator n =
00205                  nset_const_iterator::build(candidates.begin());
00206                n != nset_const_iterator::build(candidates.end()); ++n) {
00207             unsigned n_r = reachmap[n->main_addr()];
00208             if (first ||
00209                 n->willingness() > maxn->willingness() ||
00210                 (n->willingness() == maxn->willingness() &&
00211                  (n_r > r ||
00212                   n_r == r && degree_map[n->main_addr()] > d))) {
00213               first = false;
00214               maxn  = &*n;
00215               r     = n_r;
00216               d     = degree_map[n->main_addr()];
00217             }
00218           }
00219 
00220           assert(!first);
00221 
00222           // Update reach counters and remove any node in N2 that
00223           // has enough coverage thanks to the selection of this MPR.
00224           aset_t&       to_erase = rthns[maxn->main_addr()];
00225           for (aset_t::const_iterator th = to_erase.begin();
00226                th != to_erase.end(); ++th) {
00227             if (++reachcount[*th] >= mprcoverage) {
00228               n2.erase(*th);
00229               for (thnsimpleset_t::iterator i = rthns.begin();
00230                    i != rthns.end(); ++i)
00231                 if (i->first != maxn->main_addr())
00232                   i->second.erase(*th);
00233             }
00234           }
00235 
00236           // Insert the MPR into the iface-local MPR-set
00237           lmprs.insert(maxn->main_addr());
00238           // and in the removal-candidates set
00239           // and remove it from the set of candidates
00240           rcandidates.insert(maxn);
00241           candidates.erase(maxn);
00242         }
00243 
00244 # ifdef QOLYESTER_ENABLE_MID
00245         // Merge the iface-local MPR-set into the global MPR-set
00246         mprs.insert(lmprs.begin(), lmprs.end());
00247 # endif
00248 
00249       }
00250 
00251       // Optimize the MPR-set
00252 
00253       // Compute the coverage count for each node in N2.
00254       std::map<address_t, unsigned>     covcount_map;
00255       for (aset_t::const_iterator m = mprs.begin(); m != mprs.end(); ++m) {
00256         const aset_t&   m_thns = thns[*m];
00257         for (aset_t::const_iterator th = m_thns.begin(); th != m_thns.end(); ++th)
00258           ++covcount_map[*th];
00259       }
00260 
00261       // Compute a willingness map.  The point is to sort
00262       // removal-candidates by order of increasing willingness.
00263       typedef std::multimap<unsigned, address_t>        wmap_t;
00264       wmap_t                                            wmap;
00265       for (nset_const_iterator rc =
00266              nset_const_iterator::build(rcandidates.begin());
00267            rc != nset_const_iterator::build(rcandidates.end()); ++rc)
00268         wmap.insert(wmap_t::value_type(rc->willingness(), rc->main_addr()));
00269 
00270       // Iterate on the willingness map and check if the candidate can
00271       // be actually removed, i.e. check if removal doesn't decrease
00272       // some N2 node's coverage count below the MPR_COVERAGE
00273       // threshold.
00274       for (wmap_t::const_iterator rc = wmap.begin(); rc != wmap.end(); ++rc) {
00275         aset_t& rc_thns = thns[rc->second];
00276         bool    remove = true;
00277         for (aset_t::const_iterator th = rc_thns.begin(); th != rc_thns.end(); ++th)
00278           if (covcount_map[*th] <= mprcoverage) {
00279             remove = false;
00280             break;
00281           }
00282         if (remove) {
00283           for (aset_t::const_iterator th = rc_thns.begin();
00284                th != rc_thns.end(); ++th)
00285             --covcount_map[*th];
00286           mprs.erase(rc->second);
00287         }
00288       }
00289 
00290       bool      changed = false;
00291 
00292       // Apply the MPR changes.
00293       for (cproxy_t::sym_neighborset_t::iterator n =
00294              cproxy.sym_neighborset().begin();
00295            n != cproxy.sym_neighborset().end(); ++n) {
00296         if (n->is_mpr()) {
00297           if (mprs.find(n->main_addr()) == mprs.end()) {
00298             cproxy.unset_mpr(n);
00299             changed = true;
00300           }
00301         } else
00302           if (mprs.find(n->main_addr()) != mprs.end()) {
00303             cproxy.set_mpr(n);
00304             changed = true;
00305           }
00306       }
00307 
00308       if (changed) {
00309         routes_recomp.set_mark();
00310         if (tc_redundancy >= mprselset_mprset)
00311           advset_changed.set_mark();
00312       }
00313     }
00314 
00315   } // namespace alg
00316 
00317 } // Namespace olsr
00318 
00319 #endif // !QOLYESTER_DAEMON_ALG_MPRSELECTION_HXX

Generated on Mon Sep 10 17:02:12 2007 for Qolyester daemon by  doxygen 1.5.1