hello.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003-2006 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,
00018 // Boston, MA  02110-1301, USA.
00019 
00020 #ifndef QOLYESTER_DAEMON_MSG_HELLO_HXX
00021 # define QOLYESTER_DAEMON_MSG_HELLO_HXX 1
00022 
00023 # include <ostream>
00024 # include <list>
00025 
00026 # include "alg/mainaddrof.hh"
00027 # include "utl/vtime.hh"
00028 # include "set/neighbors.hh"
00029 
00030 # include "hello.hh"
00031 
00032 namespace olsr {
00033 
00034   extern std::ostream   dump_hello;
00035   extern bool           do_dump_hello;
00036   extern cproxy_t       cproxy;
00037   extern thnset_t       thn_set;
00038 
00039   namespace msg {
00040 
00041     // Dump method for the HELLO message.
00042 
00043     // A few words on this:
00044 
00045     // As HELLO messages can be partial (i.e. not all the link set is
00046     // advertised at once because of possible lack of space), we have
00047     // to keep track of the last time a link was advertised on a given
00048     // interface.  Moreover, we want to include links by order of
00049     // increasing last time of advertisement, in order to prioritize
00050     // older -- in terms of advertised time -- links.
00051 
00052     // To achieve these goals, we maintain a special data structure in
00053     // linkset_t that allows for each interface separately to keep the
00054     // neighbors sorted in order of inscreasing last advertisement
00055     // time.  We consider the neighbors and not the links for a simple
00056     // reason: a link cannot exist by itself, it is always associated
00057     // to a neighbor -- be it an asymmetrical one -- and we need
00058     // information about the associated neighbor.  Moreover, one
00059     // neighbor cannot have more than exactly one link with one local
00060     // interface.
00061 
00062     bool
00063     HELLOMessage::dump(utl::Data& d, const address_t& interface) const {
00064 
00065       // Check if there is space left for at least one message.
00066       if (d.size() < Message::min_length + min_length)
00067         return true; // try again immediately
00068 
00069       if (do_dump_hello) {
00070         dump_hello << "HELLO preparation (" << interface << ") "
00071                    << Message::seqnum << " {\n";
00072       }
00073 
00074       // Fill Message header fields (raw->size is set at the end)
00075 
00076       Message::raw*     mraw = reinterpret_cast<Message::raw*>(d.raw());
00077 
00078       mraw->type     = HELLO_MESSAGE;                   // Message Type
00079       mraw->vtime    = utl::Vtime(cst::neighb_hold_time);       // VTime
00080       // mraw->size  = 0;                               // set later
00081       main_addr.dump(mraw->addr);                       // Main address
00082       mraw->ttl      = 1;                               // Time To Live
00083       mraw->hopcount = 0;                               // Hop Count
00084       mraw->seqnum   = htons(Message::seqnum);          // Sequence number
00085 
00086       // Fill HELLOMessage header fields
00087 
00088       raw*              hraw = reinterpret_cast<raw*>(mraw->data);
00089 
00090       hraw->reserved    = 0;
00091       hraw->htime       = utl::Vtime(cst::hello_interval);
00092       hraw->willingness = willingness;
00093 
00094       d += sizeof *mraw + sizeof *hraw;
00095 
00096       // We are now ready to build the body of the HELLO message.
00097       // We must first classify the links by linkcodes.
00098       // We need one set per linkcode.
00099 
00100       typedef std::pair<address_t,
00101                         cproxy_t::hello_linkset_t::iterator>    lpair_t;
00102       typedef std::list<lpair_t>        linklist_t;
00103 
00104       typedef enum {
00105         nu = NOT_NEIGH << 2 | UNSPEC_LINK,
00106         na = NOT_NEIGH << 2 | ASYM_LINK,
00107         nl = NOT_NEIGH << 2 | LOST_LINK,
00108 
00109         su = SYM_NEIGH << 2 | UNSPEC_LINK,
00110         sa = SYM_NEIGH << 2 | ASYM_LINK,
00111         ss = SYM_NEIGH << 2 | SYM_LINK,
00112         sl = SYM_NEIGH << 2 | LOST_LINK,
00113 
00114         mu = MPR_NEIGH << 2 | UNSPEC_LINK,
00115         ma = MPR_NEIGH << 2 | ASYM_LINK,
00116         ms = MPR_NEIGH << 2 | SYM_LINK,
00117         ml = MPR_NEIGH << 2 | LOST_LINK
00118       }                                                         linkcode_t;
00119 
00120       linklist_t        nu_list;
00121       linklist_t        na_list;
00122       linklist_t        nl_list;
00123 
00124       linklist_t        su_list;
00125       linklist_t        sa_list;
00126       linklist_t        ss_list;
00127       linklist_t        sl_list;
00128 
00129       linklist_t        mu_list;
00130       linklist_t        ma_list;
00131       linklist_t        ms_list;
00132       linklist_t        ml_list;
00133 
00134       // Now we have to iterate on the neighbors (using
00135       // linkset_t::mnset_iterator gives the neighbors in stamp order
00136       // for the current interface, so we get older stamped first).
00137       // We also check whether we can add the link.  We check the
00138       // potential link expiration on the next run to return proper
00139       // value (true if we need another HELLO message right away or
00140       // false if we can wait till the next generation.
00141 
00142       ::size_t  bytes_so_far = 0;
00143       bool      ret          = false;
00144       bool      just_stamped = false;
00145 
00146       std::set<address_t>       already_advertised;
00147 
00148       debug << up(2) << indent << "Considering links {\n" << indent;
00149 
00150       for (cproxy_t::hello_linkset_t::iterator l =
00151              cproxy.hello_linkset().begin(interface);
00152            l != cproxy.hello_linkset().end(interface); just_stamped ? l : ++l) {
00153 
00154         just_stamped = false;
00155 
00156         debug << "link to " << l->remote_addr() << '\n';
00157 
00158         // We don't want to advertise links too often either, so we
00159         // check if this link has just been sent in a previous run of
00160         // the HELLOMessage::dump() method.  As neighbors are iterated
00161         // on in increasing stamp time, we can safely stop iterating
00162         // here if this message has just been stamped.
00163         if (cproxy.hello_linkset().stamp(l) == timeval_t::now()) {
00164           debug << up
00165                 << "Stopping HELLO advertisement, since remaining already advertised\n"
00166                 << down;
00167           break; // the remaining have just been advertised
00168         }
00169 
00170         // Check if there is enough space left in the packet.
00171         if (d.size() - bytes_so_far < ADDRESS_SIZE) {
00172 
00173           debug << up << "No space left in packet\n" << down;
00174 
00175           // Check if the refresh interval would expire for this
00176           // neighbor if we wait till the next iteration.  If yes,
00177           // return true to force immediate additional message
00178           // emission.
00179           if (cproxy.hello_linkset().expired(l, cst::refresh_interval,
00180                                              timeval_t::in(cst::hello_interval))) {
00181 
00182             debug << up << "Some links would expire, request additional message\n" << down;
00183 
00184             ret = true;
00185             break;
00186           }
00187 
00188           // If the refresh interval would not expire, continue
00189           // checking the following entries.
00190           continue;
00191         }
00192 
00193         // Compute the Link Code
00194         cproxy_t::neighborset_t::iterator       n =
00195           cproxy.neighborset().find(set::Neighbor::make_key(l->main_addr()));
00196 
00197         assert(n != cproxy.neighborset().end());
00198 
00199         int     link_type = 0;
00200 
00201         if (l->local_addr() != interface) {
00202           // Check if there are links for this neighbor from this interface
00203           std::pair<set::Neighbor::linkset_t::const_iterator,
00204                     set::Neighbor::linkset_t::const_iterator>   er =
00205             n->find_lifaces(interface);
00206 
00207           // If there exists at least one link from this interface to
00208           // the neighbor, we will advertise it in due time, skip this
00209           // link.
00210           if (er.first != er.second ||
00211               already_advertised.find(n->main_addr()) != already_advertised.end()) {
00212             cproxy_t::hello_linkset_t::iterator tmp = l++;
00213             cproxy.hello_linkset().set_stamp(tmp);
00214             just_stamped = true;
00215             continue;
00216           }
00217 
00218           already_advertised.insert(n->main_addr());
00219 
00220           link_type = UNSPEC_LINK;
00221         } else {
00222 # ifdef QOLYESTER_ENABLE_LINKHYS
00223           if (!l->losttime().is_past())
00224             link_type = LOST_LINK;
00225           else if (l->pending()) {
00226             debug << up << "Skipped pending link\n" << down;
00227             continue;
00228           } else
00229 # endif // !QOLYESTER_ENABLE_LINKHYS
00230           if (!l->symtime().is_past())
00231             link_type = SYM_LINK;
00232           else if (!l->asymtime().is_past())
00233             link_type = ASYM_LINK;
00234           else
00235             link_type = LOST_LINK;
00236         }
00237 
00238         // Get the neighbor type code.
00239         int     neighbor_type = 0;
00240 
00241         if (n->is_mpr())
00242           neighbor_type = MPR_NEIGH;
00243         else if (n->is_sym())
00244           neighbor_type = SYM_NEIGH;
00245         else
00246           neighbor_type = NOT_NEIGH;
00247 
00248         if (do_dump_hello) {
00249           dump_hello << "  " << (link_type != UNSPEC_LINK ?
00250                                  l->remote_addr() :
00251                                  n->main_addr()) << ' ';
00252           switch (link_type) {
00253           case UNSPEC_LINK: dump_hello << "U "; break;
00254           case   ASYM_LINK: dump_hello << "A "; break;
00255           case    SYM_LINK: dump_hello << "S "; break;
00256           case   LOST_LINK: dump_hello << "L "; break;
00257           }
00258           switch (neighbor_type) {
00259           case NOT_NEIGH: dump_hello << "N\n"; break;
00260           case SYM_NEIGH: dump_hello << "S\n"; break;
00261           case MPR_NEIGH: dump_hello << "M\n"; break;
00262           }
00263         }
00264 
00265         // We use a pointer to the apropriate set, depending on the
00266         // link code.  We can avoid the indirection here using a
00267         // preprocessor macro, but the indirection is affordable and
00268         // preferable to the additional code generated.
00269         linklist_t*     list_ptr = 0;
00270 
00271         switch (linkcode_t(neighbor_type << 2 | link_type)) {
00272 
00273         case nu: list_ptr = &nu_list; break;
00274         case na: list_ptr = &na_list; break;
00275         case nl: list_ptr = &nl_list; break;
00276 
00277         case su: list_ptr = &su_list; break;
00278         case sa: list_ptr = &sa_list; break;
00279         case ss: list_ptr = &ss_list; break;
00280         case sl: list_ptr = &sl_list; break;
00281 
00282         case mu: list_ptr = &mu_list; break;
00283         case ma: list_ptr = &ma_list; break;
00284         case ms: list_ptr = &ms_list; break;
00285         case ml: list_ptr = &ml_list; break;
00286 
00287           // We want to catch this case and make it understandable.
00288         default: list_ptr = 0; assert(list_ptr != 0);
00289         }
00290 
00291         // If this is the first link entry of this link code, we must
00292         // take into account the link message header that would be
00293         // added.
00294         if (list_ptr->empty())
00295           // Check for free space.
00296           if (d.size() - bytes_so_far <
00297               sizeof (linksetraw) + ADDRESS_SIZE) {
00298             // If there is not enough room, check if we can delay the
00299             // advertisement of this link until the next iteration.
00300             if (cproxy.hello_linkset().expired(l, cst::refresh_interval,
00301                                                timeval_t::in(cst::hello_interval)))
00302               ret = true;
00303             // Same as before, we still can add some links.
00304             continue;
00305           } else
00306             bytes_so_far += sizeof (linksetraw) + ADDRESS_SIZE;
00307         else
00308           bytes_so_far += ADDRESS_SIZE;
00309 
00310         // If there is no link on this interface for the given
00311         // neighbor (the link code is UNSPEC_LINK), we advertise the
00312         // neighbor's main address, otherwise, we advertise the remote
00313         // interface address.
00314         if (link_type == UNSPEC_LINK)
00315           list_ptr->push_back(lpair_t(n->main_addr(), l));
00316         else
00317           list_ptr->push_back(lpair_t(l->remote_addr(), l));
00318       }
00319 
00320       debug << deindent << '}' << deindent << std::endl << down(2);
00321 
00322       if (do_dump_hello)
00323         dump_hello << '}' << std::endl;
00324 
00325       // Here comes the macro to generate each link message.  We could
00326       // replace this with a function, in order to spare code size.
00327 
00328 # define PROC_XX_SET(Code)                                                \
00329       do {                                                                \
00330         if (Code ## _list.empty())                                        \
00331           break;                                                          \
00332                                                                           \
00333         linksetraw*     lraw = reinterpret_cast<linksetraw*>(d.raw());    \
00334                                                                           \
00335         lraw->linkcode = linkcode_t(Code);                                \
00336         lraw->reserved = 0;                                               \
00337                                                                           \
00338         d += sizeof *lraw;                                                \
00339                                                                           \
00340         for (linklist_t::iterator i  = Code ## _list.begin();             \
00341                                   i != Code ## _list.end();               \
00342              d += ADDRESS_SIZE, ++i) {                                    \
00343           i->first.dump(d.raw());                                         \
00344           cproxy.hello_linkset().set_stamp(i->second);                    \
00345         }                                                                 \
00346                                                                           \
00347         lraw->linkmessagesize = htons(d.raw() -                           \
00348                                       reinterpret_cast<u_int8_t*>(lraw)); \
00349       } while (0)
00350 
00351       PROC_XX_SET(nu);
00352       PROC_XX_SET(na);
00353       PROC_XX_SET(nl);
00354 
00355       PROC_XX_SET(su);
00356       PROC_XX_SET(sa);
00357       PROC_XX_SET(ss);
00358       PROC_XX_SET(sl);
00359 
00360       PROC_XX_SET(mu);
00361       PROC_XX_SET(ma);
00362       PROC_XX_SET(ms);
00363       PROC_XX_SET(ml);
00364 
00365       mraw->size = htons(d.raw() - reinterpret_cast<u_int8_t*>(mraw));
00366 
00367       return ret;
00368     }
00369 
00370     // Parsing routine for HELLO messages.
00371     void HELLOMessage::parse(const utl::ConstData& d,
00372                              const Message::header& mh) {
00373 
00374       // Extract the message header.
00375       const raw*        h = reinterpret_cast<const raw*>(d.raw());
00376 
00377       if (do_dump_hello) {
00378         dump_hello << "HELLO from " << mh.originator
00379                    << " (" << mh.sender << " -> " << mh.receiver
00380                    << ") M(" << mh.mseqnum << ") P("
00381                    << mh.pseqnum << ") Ht(" << (float) utl::Vtime(h->htime) << ") {\n";
00382       }
00383 
00384       utl::ConstData    payload = d + sizeof (raw);
00385 
00386       int                               link_type  = UNSPEC_LINK;
00387       int                               neigh_type = NOT_NEIGH;
00388       typedef std::set<address_t>       thns_t;
00389       thns_t                            thns;
00390 
00391       // Process the link messages.
00392       for (const linksetraw* lraw =
00393              reinterpret_cast<const linksetraw*>(payload.raw());
00394 
00395            payload.size() > 0;
00396 
00397            payload += ntohs(lraw->linkmessagesize),
00398 
00399              lraw = reinterpret_cast<const linksetraw*>
00400              ((lraw->data - sizeof (linksetraw) +
00401                ntohs(lraw->linkmessagesize)))) {
00402         // Extract link message size.
00403         unsigned        len = (ntohs(lraw->linkmessagesize) -
00404                                sizeof (linksetraw)) / ADDRESS_SIZE;
00405         const u_int8_t  (*addrs)[ADDRESS_SIZE] =
00406           reinterpret_cast<const u_int8_t (*)[ADDRESS_SIZE]>(lraw->data);
00407 
00408         // Extract link and neighbor codes.
00409         u_int8_t        ltype = lraw->linkcode & 0x3;
00410         u_int8_t        ntype = lraw->linkcode >> 2 & 0x03;
00411 
00412         // Process the address list.
00413         for (unsigned i = 0; i < len; ++i) {
00414           // Extract link and main addresses.
00415           address_t     addr(addrs[i], ADDRESS_SIZE);
00416           address_t     maddr = alg::main_addr_of(addr);
00417 
00418           if (do_dump_hello) {
00419             dump_hello << "  " << addr << ' ';
00420             switch (ltype) {
00421             case UNSPEC_LINK: dump_hello << "U "; break;
00422             case   ASYM_LINK: dump_hello << "A "; break;
00423             case    SYM_LINK: dump_hello << "S "; break;
00424             case   LOST_LINK: dump_hello << "L "; break;
00425             }
00426             switch (ntype) {
00427             case NOT_NEIGH: dump_hello << "N\n"; break;
00428             case SYM_NEIGH: dump_hello << "S\n"; break;
00429             case MPR_NEIGH: dump_hello << "M\n"; break;
00430             }
00431           }
00432 
00433           if (addr == mh.receiver) {
00434             // This is the information about the local node.  We
00435             // extract here information about the link state between
00436             // the local and the neighbor nodes.
00437             link_type  = ltype;
00438             neigh_type = ntype;
00439           } else if (maddr == main_addr)
00440             // This is the local node, as seen on another interface.
00441             // Ignore it.
00442             continue;
00443           else {
00444             // This is another node, most probably a 2-hop neighbor.
00445             if (addr != maddr)
00446               // In case this is not the main address of this 2-hop
00447               // node, remove any possible previous information from
00448               // the 2-hop neighbor set in case we did not known the
00449               // multiple interface association of the 2-hop node at
00450               // the time of addition.
00451               thn_set.erase(set::TwoHopNeighbor::make_key(mh.originator,
00452                                                           addr));
00453             if (ntype == SYM_NEIGH || ntype == MPR_NEIGH) {
00454               // If the 2-hop node is a symmetric neighbor of the
00455               // 1-hop node, add an entry in the 2-hop neighbor set.
00456               thns.insert(maddr);
00457             } else {
00458               // Otherwise, remove any association between the two
00459               // nodes from the 2-hop neighbor set.
00460               thn_set.erase(set::TwoHopNeighbor::make_key(mh.originator,
00461                                                           maddr));
00462             }
00463           }
00464         }
00465       }
00466 
00467       if (do_dump_hello)
00468         dump_hello << '}' << std::endl;
00469 
00470       // Now that we have processed all the message,
00471       cproxy_t::neighborset_t::iterator n =
00472 # ifdef QOLYESTER_ENABLE_LINKHYS
00473         cproxy.insert_link(mh, link_type, h->willingness,
00474                            utl::Vtime(h->htime)).first;
00475 # else // !QOLYESTER_ENABLE_LINKHYS
00476         cproxy.insert_link(mh, link_type, h->willingness).first;
00477 # endif
00478 
00479       if (link_type != UNSPEC_LINK)
00480         if (neigh_type == MPR_NEIGH)
00481           cproxy.set_mprsel(n, mh.validity);
00482         else if (neigh_type == SYM_NEIGH)
00483           cproxy.unset_mprsel(n);
00484 
00485       if (n->is_sym()) { // process this neighbor for THN
00486 
00487         for (thns_t::const_iterator i = thns.begin(); i != thns.end(); ++i)
00488           thn_set.insert(set::TwoHopNeighbor(mh.originator, *i, mh.validity));
00489 
00490       }
00491 
00492     }
00493 
00494   } // namespace msg
00495 
00496 } // namespace olsr
00497 
00498 #endif // ! QOLYESTER_DAEMON_MSG_HELLO_HXX

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