routing_table.c

00001 /* Copyright 2008 Michael Marsh, University of Maryland.
00002  *
00003  * This file is part of pydtn.
00004  *
00005  * pydtn is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * pydtn 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 pydtn.  If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The views and conclusions contained in the software and documentation
00019  * are those of the authors and should not be interpreted as representing
00020  * official policies, either expressed or implied, of the University
00021  * of Maryland.
00022  *
00023  * pydtn extends and embeds the Python interpreter, which is
00024  * Copyright 2001-2006 Python Software Foundation, All Rights Reserved,
00025  * and is released under the PSF License Agreement.
00026  *
00027  * RANLUX random number generation uses the Boost library,
00028  * Copyright 1994-2006 by various authors (details in individual files),
00029  * which is released under the Boost Software License, Version 1.0.
00030  */
00031 
00032 #include "aodv.h"
00033 #include <string.h>
00034 
00035 void
00036 clear_aodv_routing_table( aodv_routing_table_t* table )
00037 {
00038    aodv_table_entry_t* head;
00039    aodv_table_entry_t* curr;
00040    aodv_table_entry_t* next;
00041 
00042    if ( NULL == table )
00043    {
00044       return;
00045    }
00046    if ( NULL == table->head )
00047    {
00048       return;
00049    }
00050 
00051    head = table->head;
00052    curr = head;
00053    do
00054    {
00055       next = curr->next;
00056       free_aodv_table_entry(curr);
00057       curr = next;
00058    } while ( curr != head );
00059 
00060    table->head = NULL;
00061 }
00062 
00063 aodv_table_entry_t*
00064 add_aodv_table_entry( aodv_routing_table_t* table,
00065                       const aodv_addr_t* destination,
00066                       uint16_t prefix_size )
00067 {
00068    aodv_table_entry_t* head;
00069    aodv_table_entry_t* tail;
00070    aodv_table_entry_t* temp;
00071 
00072    if ( NULL == table )
00073    {
00074       return NULL;
00075    }
00076 
00077    temp = new_aodv_table_entry();
00078    if ( NULL == temp )
00079    {
00080       return NULL;
00081    }
00082    set_aodv_addr( &(temp->destination.addr), destination );
00083    temp->destination.prefix = prefix_size;
00084 
00085    if ( NULL == table->head )
00086    {
00087       table->head = temp;
00088       temp->next = temp;
00089       temp->prev = temp;
00090    }
00091    else
00092    {
00093       head = table->head;
00094       tail = head->prev;
00095       temp->next = head;
00096       temp->prev = tail;
00097       head->prev = temp;
00098       tail->next = temp;
00099    }
00100 
00101    return temp;
00102 }
00103 
00104 void
00105 remove_aodv_table_entry( aodv_routing_table_t* table,
00106                          aodv_table_entry_t* entry )
00107 {
00108    aodv_table_entry_t* curr;
00109    aodv_table_entry_t* next;
00110    unsigned char is_head;
00111    unsigned char is_tail;
00112 
00113    if ( NULL == table ) return;
00114    if ( NULL == entry ) return;
00115    if ( NULL == table->head ) return;
00116 
00117    curr = table->head;
00118    do
00119    {
00120       next = curr->next;
00121       if ( curr == entry )
00122       {
00123          is_head = 0;
00124          is_tail = 0;
00125          if ( curr == table->head ) is_head = 1;
00126          if ( curr == table->head->prev ) is_tail = 1;
00127 
00128          if ( is_head && is_tail )
00129          {
00130             table->head = NULL;
00131             next = NULL;
00132          }
00133          else
00134          {
00135             if ( is_head )
00136             {
00137                table->head = next;
00138             }
00139             curr->prev->next = next;
00140             next->prev = curr->prev;
00141          }
00142          free_aodv_table_entry( curr );
00143          return;
00144       }
00145       curr = next;
00146    } while ( curr != table->head );
00147 }
00148 
00149 aodv_table_entry_t*
00150 update_aodv_table_entry( aodv_state_t* state,
00151                          const aodv_msghdr_t* hdrs,
00152                          const aodv_node_list_t* node,
00153                          unsigned char hop_count )
00154 {
00155    aodv_table_entry_t*  entry;
00156    uint32_t cmp;
00157 
00158    if ( NULL == state ) return NULL;
00159    if ( NULL == hdrs ) return NULL;
00160    if ( NULL == node ) return NULL;
00161 
00162    entry = aodv_lookup( &(state->routing_table), &(node->node) );
00163    if ( NULL == entry )
00164    {
00165       entry =
00166          add_aodv_table_entry( &(state->routing_table), &(node->node), 0 );
00167       if ( NULL == entry ) return NULL;
00168    }
00169    cmp = aodv_cmp_seq( node->seq, entry->dest_seq );
00170    if ( ( cmp > 0 ) ||
00171         ( ( 0 == cmp ) && ( ( ! entry->valid_route ) ||
00172                             ( hop_count < entry->hop_count ) ) ) )
00173    {
00174       aodv_update_route_expiry( state, entry );
00175       entry->dest_seq = node->seq;
00176       set_aodv_addr( &(entry->next_hop), &(hdrs->addr) );
00177       entry->hop_count = hop_count;
00178       entry->interface = hdrs->interface;
00179       entry->valid_route = 1;
00180    }
00181    return entry;
00182 }
00183 
00184 aodv_table_entry_t*
00185 new_aodv_table_entry()
00186 {
00187    aodv_table_entry_t* temp;
00188    temp = (aodv_table_entry_t*) malloc( sizeof(aodv_table_entry_t) );
00189    if ( NULL == temp )
00190    {
00191       return NULL;
00192    }
00193    temp->next                    = NULL;
00194    temp->prev                    = NULL;
00195    temp->destination.addr.data   = NULL;
00196    temp->destination.addr.length = 0U;
00197    temp->destination.prefix      = 0;
00198    temp->dest_seq                = 0;
00199    temp->next_hop.data           = NULL;
00200    temp->next_hop.length         = 0U;
00201    temp->lifetime.tv_sec         = -1;
00202    temp->lifetime.tv_usec        = 0;
00203    temp->hop_count               = 0;
00204    temp->interface               = -1;
00205    temp->valid_route             = 0;
00206    return temp;
00207 }
00208 
00209 void
00210 free_aodv_table_entry( aodv_table_entry_t* entry )
00211 {
00212    if ( NULL == entry ) return;
00213    if ( NULL != entry->destination.addr.data )
00214       free( entry->destination.addr.data );
00215    if ( NULL != entry->next_hop.data )
00216       free( entry->next_hop.data );
00217    free(entry);
00218 }
00219 
00220 /*
00221  * This is a horribly inefficient way to do lookups, but for the moment
00222  * we're using a regular linked list for the routing table, so we can't
00223  * really do too much better.  Ideally we'd have a better structure
00224  * for storing routing table entries.
00225  *
00226  */
00227 aodv_table_entry_t*
00228 aodv_lookup( const aodv_routing_table_t* table,
00229              const aodv_addr_t* destination )
00230 {
00231    aodv_table_entry_t* curr;
00232    aodv_table_entry_t* best;
00233    uint16_t curr_prefix;
00234    uint16_t best_prefix;
00235 
00236    if ( NULL == table )
00237    {
00238       return NULL;
00239    }
00240    if ( NULL == table->head )
00241    {
00242       return NULL;
00243    }
00244    if ( NULL == destination )
00245    {
00246       return NULL;
00247    }
00248 
00249    best = NULL;
00250    best_prefix = ~0;
00251    curr = table->head;
00252    do
00253    {
00254       if ( 0 == curr->destination.prefix )
00255       {
00256          if ( 0 == aodv_cmp_addr( &(curr->destination.addr), destination ) )
00257          {
00258             return curr;
00259          }
00260       }
00261       else
00262       {
00263          /*
00264           * I believe this does what the previous version did.
00265           * That is, it starts with a longest-possible prefix
00266           * length.  It then looks at each entry, and if it
00267           * matches with a shorter prefix, then it takes the
00268           * new entry.
00269           *
00270           * Two things to note:
00271           *
00272           * 1) "prefix length" is inverted here relative to what
00273           *    we'd generally think of.  This is to conform with
00274           *    the terminology in the specification.  The length
00275           *    of the prefix is the number of bits that are masked.
00276           *    Consequently, a length-0 prefix has no bits masked, and
00277           *    the whole thing is relevant.
00278           *
00279           * 2) We need an additional check that the specified prefix
00280           *    is not longer than the destination's fully specified
00281           *    address.
00282           */
00283          curr_prefix = curr->destination.prefix;
00284          if ( (8 * destination->length) >= curr_prefix )
00285          {
00286             if ( curr_prefix < best_prefix )
00287             {
00288                char nomatch = 0;
00289                uint16_t ip = curr_prefix / 8;
00290                unsigned char bp = curr_prefix % 8;
00291 
00292                /*
00293                 * General comment:
00294                 *
00295                 * We're using or-equal here because anything non-zero
00296                 * or true will have a bit set somewhere, and or-equal
00297                 * will never flip a bit from 1 to 0, only from 0 to 1.
00298                 * That means something passing a (rejection) test will
00299                 * set *something* to 1, and this will carry through
00300                 * subsequent tests.
00301                 */
00302 
00303                /* First check full-width bytes, if any. */
00304                if ( ip > 0 )
00305                {
00306                   nomatch |= memcmp( curr->destination.addr.data,
00307                                      destination->data,
00308                                      ip );
00309                }
00310 
00311                /* Now mask the bits in the final byte, if any. */
00312                if ( ( !nomatch ) && ( bp > 0 ) )
00313                {
00314                   unsigned char mask = ~0 << bp;
00315                   nomatch |= ( ( curr->destination.addr.data[ip] & mask ) !=
00316                                ( destination->data[ip] & mask ) );
00317 
00318                }
00319 
00320                if ( !nomatch )
00321                {
00322                   best = curr;
00323                   best_prefix = curr_prefix;
00324                }
00325             }
00326          }
00327       }
00328       curr = curr->next;
00329    } while ( curr != table->head );
00330 
00331    return best;
00332 }
00333 
00334 void
00335 aodv_invalidate_route( aodv_state_t* state, const aodv_addr_t* destination )
00336 {
00337    aodv_routing_table_t* table;
00338    aodv_table_entry_t* entry;
00339 
00340    if ( NULL == state ) return;
00341 
00342    table = &(state->routing_table);
00343    entry = aodv_lookup( table, destination );
00344    if ( NULL == entry )
00345    {
00346       return;
00347    }
00348    if ( entry->valid_route )
00349    {
00350       aodv_invalidate_routing_entry( state, entry );
00351    }
00352 }
00353 
00354 void
00355 aodv_invalidate_routing_entry( aodv_state_t* state,
00356                                aodv_table_entry_t* entry )
00357 {
00358    if ( NULL == state ) return;
00359    if ( NULL == entry ) return;
00360 
00361    entry->valid_route = 0;
00362    aodv_incr_seq_base( &(entry->dest_seq) );
00363 }
00364 
00365 unsigned char
00366 aodv_table_entry_is_expired( const aodv_table_entry_t* entry )
00367 {
00368    if ( NULL == entry ) return 0;
00369 
00370    return aodv_pasttime( &(entry->lifetime) );
00371 }
00372 
00373 static void
00374 _update_route_lifetime( aodv_table_entry_t* entry,
00375                         unsigned int lifetime )
00376 {
00377    struct timeval* tv = &(entry->lifetime);
00378    aodv_gettime(tv);
00379    tv->tv_usec += 1000 * lifetime;
00380    while( tv->tv_usec >= 1000000 )
00381    {
00382       tv->tv_usec -= 1000000;
00383       tv->tv_sec += 1;
00384    }
00385 }
00386 
00387 void
00388 aodv_update_route_expiry( const aodv_state_t* state,
00389                           aodv_table_entry_t* entry )
00390 {
00391    _update_route_lifetime( entry, state->params.active_route_timeout );
00392 }
00393 
00394 void
00395 aodv_update_invalid_route_lifetime( const aodv_state_t* state,
00396                                     aodv_table_entry_t* entry )
00397 {
00398    _update_route_lifetime( entry, state->params.delete_period );
00399 }
00400 
00401 void
00402 aodv_broken_link( aodv_state_t* state, const aodv_addr_t* bad_hop )
00403 {
00404    aodv_table_entry_t* thead;
00405    aodv_table_entry_t* tcurr;
00406    int gen_rerr = 0;
00407    aodv_rerr_t rerr;
00408    rerr.dest_count = 0;
00409    rerr.unreachable = 0;
00410 
00411    if ( NULL == state ) return;
00412 
00413    thead = state->routing_table.head;
00414    tcurr = thead;
00415    if ( 0 != thead )
00416    {
00417       do
00418       {
00419          if ( tcurr->valid_route &&
00420               ( 0 == aodv_cmp_addr( bad_hop, &(tcurr->next_hop) ) ) )
00421          {
00422             gen_rerr = 1;
00423             aodv_invalidate_routing_entry( state, tcurr );
00424             rerr.dest_count++;
00425             aodv_add_to_node_list( &(rerr.unreachable),
00426                                    &(tcurr->destination.addr),
00427                                    tcurr->dest_seq );
00428          }
00429          tcurr = tcurr->next;
00430       } while ( tcurr != thead );
00431    }
00432 
00433    if ( gen_rerr )
00434    {
00435       if ( aodv_insert_time( state->rerr_time_ring ) )
00436       {
00437          aodv_bcast_rerr( state, &rerr );
00438       }
00439    }
00440 }

Generated on Mon Mar 24 11:15:45 2008 for Pydtn Simulator by  doxygen 1.5.4