Annotation of embedaddon/quagga/babeld/route.c, revision 1.1

1.1     ! misho       1: /*  
        !             2:  *  This file is free software: you may copy, redistribute and/or modify it  
        !             3:  *  under the terms of the GNU General Public License as published by the  
        !             4:  *  Free Software Foundation, either version 2 of the License, or (at your  
        !             5:  *  option) any later version.  
        !             6:  *  
        !             7:  *  This file is distributed in the hope that it will be useful, but  
        !             8:  *  WITHOUT ANY WARRANTY; without even the implied warranty of  
        !             9:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
        !            10:  *  General Public License for more details.  
        !            11:  *  
        !            12:  *  You should have received a copy of the GNU General Public License  
        !            13:  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  
        !            14:  *  
        !            15:  * This file incorporates work covered by the following copyright and  
        !            16:  * permission notice:  
        !            17:  *  
        !            18: Copyright (c) 2007, 2008 by Juliusz Chroboczek
        !            19: Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
        !            20: 
        !            21: Permission is hereby granted, free of charge, to any person obtaining a copy
        !            22: of this software and associated documentation files (the "Software"), to deal
        !            23: in the Software without restriction, including without limitation the rights
        !            24: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            25: copies of the Software, and to permit persons to whom the Software is
        !            26: furnished to do so, subject to the following conditions:
        !            27: 
        !            28: The above copyright notice and this permission notice shall be included in
        !            29: all copies or substantial portions of the Software.
        !            30: 
        !            31: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            32: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            33: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
        !            34: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            35: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            36: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            37: THE SOFTWARE.
        !            38: */
        !            39: 
        !            40: #include <zebra.h>
        !            41: #include "if.h"
        !            42: 
        !            43: #include "babeld.h"
        !            44: #include "util.h"
        !            45: #include "kernel.h"
        !            46: #include "babel_interface.h"
        !            47: #include "source.h"
        !            48: #include "neighbour.h"
        !            49: #include "route.h"
        !            50: #include "xroute.h"
        !            51: #include "message.h"
        !            52: #include "resend.h"
        !            53: 
        !            54: static void consider_route(struct babel_route *route);
        !            55: 
        !            56: struct babel_route **routes = NULL;
        !            57: static int route_slots = 0, max_route_slots = 0;
        !            58: int kernel_metric = 0;
        !            59: int allow_duplicates = -1;
        !            60: int diversity_kind = DIVERSITY_NONE;
        !            61: int diversity_factor = 256;     /* in units of 1/256 */
        !            62: int keep_unfeasible = 0;
        !            63: 
        !            64: /* We maintain a list of "slots", ordered by prefix.  Every slot
        !            65:    contains a linked list of the routes to this prefix, with the
        !            66:    installed route, if any, at the head of the list. */
        !            67: 
        !            68: static int
        !            69: route_compare(const unsigned char *prefix, unsigned char plen,
        !            70:                struct babel_route *route)
        !            71: {
        !            72:     int i = memcmp(prefix, route->src->prefix, 16);
        !            73:     if(i != 0)
        !            74:         return i;
        !            75: 
        !            76:     if(plen < route->src->plen)
        !            77:         return -1;
        !            78:     else if(plen > route->src->plen)
        !            79:         return 1;
        !            80:     else
        !            81:         return 0;
        !            82: }
        !            83: 
        !            84: /* Performs binary search, returns -1 in case of failure.  In the latter
        !            85:    case, new_return is the place where to insert the new element. */
        !            86: 
        !            87: static int
        !            88: find_route_slot(const unsigned char *prefix, unsigned char plen,
        !            89:                 int *new_return)
        !            90: {
        !            91:     int p, m, g, c;
        !            92: 
        !            93:     if(route_slots < 1) {
        !            94:         if(new_return)
        !            95:             *new_return = 0;
        !            96:         return -1;
        !            97:     }
        !            98: 
        !            99:     p = 0; g = route_slots - 1;
        !           100: 
        !           101:     do {
        !           102:         m = (p + g) / 2;
        !           103:         c = route_compare(prefix, plen, routes[m]);
        !           104:         if(c == 0)
        !           105:             return m;
        !           106:         else if(c < 0)
        !           107:             g = m - 1;
        !           108:         else
        !           109:             p = m + 1;
        !           110:     } while(p <= g);
        !           111: 
        !           112:     if(new_return)
        !           113:         *new_return = p;
        !           114: 
        !           115:     return -1;
        !           116: }
        !           117: 
        !           118: struct babel_route *
        !           119: find_route(const unsigned char *prefix, unsigned char plen,
        !           120:            struct neighbour *neigh, const unsigned char *nexthop)
        !           121: {
        !           122:     struct babel_route *route;
        !           123:     int i = find_route_slot(prefix, plen, NULL);
        !           124: 
        !           125:     if(i < 0)
        !           126:         return NULL;
        !           127: 
        !           128:     route = routes[i];
        !           129: 
        !           130:     while(route) {
        !           131:         if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0)
        !           132:             return route;
        !           133:         route = route->next;
        !           134:     }
        !           135: 
        !           136:     return NULL;
        !           137: }
        !           138: 
        !           139: struct babel_route *
        !           140: find_installed_route(const unsigned char *prefix, unsigned char plen)
        !           141: {
        !           142:     int i = find_route_slot(prefix, plen, NULL);
        !           143: 
        !           144:     if(i >= 0 && routes[i]->installed)
        !           145:         return routes[i];
        !           146: 
        !           147:     return NULL;
        !           148: }
        !           149: 
        !           150: /* Returns an overestimate of the number of installed routes. */
        !           151: int
        !           152: installed_routes_estimate(void)
        !           153: {
        !           154:     return route_slots;
        !           155: }
        !           156: 
        !           157: static int
        !           158: resize_route_table(int new_slots)
        !           159: {
        !           160:     struct babel_route **new_routes;
        !           161:     assert(new_slots >= route_slots);
        !           162: 
        !           163:     if(new_slots == 0) {
        !           164:         new_routes = NULL;
        !           165:         free(routes);
        !           166:     } else {
        !           167:         new_routes = realloc(routes, new_slots * sizeof(struct babel_route*));
        !           168:         if(new_routes == NULL)
        !           169:             return -1;
        !           170:     }
        !           171: 
        !           172:     max_route_slots = new_slots;
        !           173:     routes = new_routes;
        !           174:     return 1;
        !           175: }
        !           176: 
        !           177: /* Insert a route into the table.  If successful, retains the route.
        !           178:    On failure, caller must free the route. */
        !           179: static struct babel_route *
        !           180: insert_route(struct babel_route *route)
        !           181: {
        !           182:     int i, n;
        !           183: 
        !           184:     assert(!route->installed);
        !           185: 
        !           186:     i = find_route_slot(route->src->prefix, route->src->plen, &n);
        !           187: 
        !           188:     if(i < 0) {
        !           189:         if(route_slots >= max_route_slots)
        !           190:             resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots);
        !           191:         if(route_slots >= max_route_slots)
        !           192:             return NULL;
        !           193:         route->next = NULL;
        !           194:         if(n < route_slots)
        !           195:             memmove(routes + n + 1, routes + n,
        !           196:                     (route_slots - n) * sizeof(struct babel_route*));
        !           197:         route_slots++;
        !           198:         routes[n] = route;
        !           199:     } else {
        !           200:         struct babel_route *r;
        !           201:         r = routes[i];
        !           202:         while(r->next)
        !           203:             r = r->next;
        !           204:         r->next = route;
        !           205:         route->next = NULL;
        !           206:     }
        !           207: 
        !           208:     return route;
        !           209: }
        !           210: 
        !           211: void
        !           212: flush_route(struct babel_route *route)
        !           213: {
        !           214:     int i;
        !           215:     struct source *src;
        !           216:     unsigned oldmetric;
        !           217:     int lost = 0;
        !           218: 
        !           219:     oldmetric = route_metric(route);
        !           220:     src = route->src;
        !           221: 
        !           222:     if(route->installed) {
        !           223:         uninstall_route(route);
        !           224:         lost = 1;
        !           225:     }
        !           226: 
        !           227:     i = find_route_slot(route->src->prefix, route->src->plen, NULL);
        !           228:     assert(i >= 0 && i < route_slots);
        !           229: 
        !           230:     if(route == routes[i]) {
        !           231:         routes[i] = route->next;
        !           232:         route->next = NULL;
        !           233:         free(route);
        !           234: 
        !           235:         if(routes[i] == NULL) {
        !           236:             if(i < route_slots - 1)
        !           237:                 memmove(routes + i, routes + i + 1,
        !           238:                         (route_slots - i - 1) * sizeof(struct babel_route*));
        !           239:             routes[route_slots - 1] = NULL;
        !           240:             route_slots--;
        !           241:         }
        !           242: 
        !           243:         if(route_slots == 0)
        !           244:             resize_route_table(0);
        !           245:         else if(max_route_slots > 8 && route_slots < max_route_slots / 4)
        !           246:             resize_route_table(max_route_slots / 2);
        !           247:     } else {
        !           248:         struct babel_route *r = routes[i];
        !           249:         while(r->next != route)
        !           250:             r = r->next;
        !           251:         r->next = route->next;
        !           252:         route->next = NULL;
        !           253:         free(route);
        !           254:     }
        !           255: 
        !           256:     if(lost)
        !           257:         route_lost(src, oldmetric);
        !           258: 
        !           259:     release_source(src);
        !           260: }
        !           261: 
        !           262: void
        !           263: flush_all_routes()
        !           264: {
        !           265:     int i;
        !           266: 
        !           267:     /* Start from the end, to avoid shifting the table. */
        !           268:     i = route_slots - 1;
        !           269:     while(i >= 0) {
        !           270:         while(i < route_slots) {
        !           271:         /* Uninstall first, to avoid calling route_lost. */
        !           272:             if(routes[i]->installed)
        !           273:                 uninstall_route(routes[0]);
        !           274:             flush_route(routes[i]);
        !           275:         }
        !           276:         i--;
        !           277:     }
        !           278: 
        !           279:     check_sources_released();
        !           280: }
        !           281: 
        !           282: void
        !           283: flush_neighbour_routes(struct neighbour *neigh)
        !           284: {
        !           285:     int i;
        !           286: 
        !           287:     i = 0;
        !           288:     while(i < route_slots) {
        !           289:         struct babel_route *r;
        !           290:         r = routes[i];
        !           291:         while(r) {
        !           292:             if(r->neigh == neigh) {
        !           293:                 flush_route(r);
        !           294:                 goto again;
        !           295:             }
        !           296:             r = r->next;
        !           297:         }
        !           298:         i++;
        !           299:     again:
        !           300:         ;
        !           301:     }
        !           302: }
        !           303: 
        !           304: void
        !           305: flush_interface_routes(struct interface *ifp, int v4only)
        !           306: {
        !           307:     int i;
        !           308: 
        !           309:     i = 0;
        !           310:     while(i < route_slots) {
        !           311:         struct babel_route *r;
        !           312:         r = routes[i];
        !           313:         while(r) {
        !           314:             if(r->neigh->ifp == ifp &&
        !           315:                (!v4only || v4mapped(r->nexthop))) {
        !           316:                 flush_route(r);
        !           317:                 goto again;
        !           318:             }
        !           319:             r = r->next;
        !           320:         }
        !           321:         i++;
        !           322:     again:
        !           323:         ;
        !           324:     }
        !           325: }
        !           326: 
        !           327: /* Iterate a function over all routes. */
        !           328: void
        !           329: for_all_routes(void (*f)(struct babel_route*, void*), void *closure)
        !           330: {
        !           331:     int i;
        !           332: 
        !           333:     for(i = 0; i < route_slots; i++) {
        !           334:         struct babel_route *r = routes[i];
        !           335:         while(r) {
        !           336:             (*f)(r, closure);
        !           337:             r = r->next;
        !           338:         }
        !           339:     }
        !           340: }
        !           341: 
        !           342: void
        !           343: for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure)
        !           344: {
        !           345:     int i;
        !           346: 
        !           347:     for(i = 0; i < route_slots; i++) {
        !           348:         if(routes[i]->installed)
        !           349:             (*f)(routes[i], closure);
        !           350:     }
        !           351: }
        !           352: 
        !           353: static int
        !           354: metric_to_kernel(int metric)
        !           355: {
        !           356:     return metric < INFINITY ? kernel_metric : KERNEL_INFINITY;
        !           357: }
        !           358: 
        !           359: /* This is used to maintain the invariant that the installed route is at
        !           360:    the head of the list. */
        !           361: static void
        !           362: move_installed_route(struct babel_route *route, int i)
        !           363: {
        !           364:     assert(i >= 0 && i < route_slots);
        !           365:     assert(route->installed);
        !           366: 
        !           367:     if(route != routes[i]) {
        !           368:         struct babel_route *r = routes[i];
        !           369:         while(r->next != route)
        !           370:             r = r->next;
        !           371:         r->next = route->next;
        !           372:         route->next = routes[i];
        !           373:         routes[i] = route;
        !           374:     }
        !           375: }
        !           376: 
        !           377: void
        !           378: install_route(struct babel_route *route)
        !           379: {
        !           380:     int i, rc;
        !           381: 
        !           382:     if(route->installed)
        !           383:         return;
        !           384: 
        !           385:     if(!route_feasible(route))
        !           386:         zlog_err("WARNING: installing unfeasible route "
        !           387:                  "(this shouldn't happen).");
        !           388: 
        !           389:     i = find_route_slot(route->src->prefix, route->src->plen, NULL);
        !           390:     assert(i >= 0 && i < route_slots);
        !           391: 
        !           392:     if(routes[i] != route && routes[i]->installed) {
        !           393:         fprintf(stderr, "WARNING: attempting to install duplicate route "
        !           394:                 "(this shouldn't happen).");
        !           395:         return;
        !           396:     }
        !           397: 
        !           398:     rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
        !           399:                       route->nexthop,
        !           400:                       route->neigh->ifp->ifindex,
        !           401:                       metric_to_kernel(route_metric(route)), NULL, 0, 0);
        !           402:     if(rc < 0) {
        !           403:         int save = errno;
        !           404:         zlog_err("kernel_route(ADD): %s", safe_strerror(errno));
        !           405:         if(save != EEXIST)
        !           406:             return;
        !           407:     }
        !           408:     route->installed = 1;
        !           409:     move_installed_route(route, i);
        !           410: 
        !           411: }
        !           412: 
        !           413: void
        !           414: uninstall_route(struct babel_route *route)
        !           415: {
        !           416:     int rc;
        !           417: 
        !           418:     if(!route->installed)
        !           419:         return;
        !           420: 
        !           421:     rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen,
        !           422:                       route->nexthop,
        !           423:                       route->neigh->ifp->ifindex,
        !           424:                       metric_to_kernel(route_metric(route)), NULL, 0, 0);
        !           425:     if(rc < 0)
        !           426:         zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno));
        !           427: 
        !           428:     route->installed = 0;
        !           429: }
        !           430: 
        !           431: /* This is equivalent to uninstall_route followed with install_route,
        !           432:    but without the race condition.  The destination of both routes
        !           433:    must be the same. */
        !           434: 
        !           435: static void
        !           436: switch_routes(struct babel_route *old, struct babel_route *new)
        !           437: {
        !           438:     int rc;
        !           439: 
        !           440:     if(!old) {
        !           441:         install_route(new);
        !           442:         return;
        !           443:     }
        !           444: 
        !           445:     if(!old->installed)
        !           446:         return;
        !           447: 
        !           448:     if(!route_feasible(new))
        !           449:         zlog_err("WARNING: switching to unfeasible route "
        !           450:                  "(this shouldn't happen).");
        !           451: 
        !           452:     rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen,
        !           453:                       old->nexthop, old->neigh->ifp->ifindex,
        !           454:                       metric_to_kernel(route_metric(old)),
        !           455:                       new->nexthop, new->neigh->ifp->ifindex,
        !           456:                       metric_to_kernel(route_metric(new)));
        !           457:     if(rc < 0) {
        !           458:         zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno));
        !           459:         return;
        !           460:     }
        !           461: 
        !           462:     old->installed = 0;
        !           463:     new->installed = 1;
        !           464:     move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen,
        !           465:                                               NULL));
        !           466: }
        !           467: 
        !           468: static void
        !           469: change_route_metric(struct babel_route *route,
        !           470:                     unsigned refmetric, unsigned cost, unsigned add)
        !           471: {
        !           472:     int old, new;
        !           473:     int newmetric = MIN(refmetric + cost + add, INFINITY);
        !           474: 
        !           475:     old = metric_to_kernel(route_metric(route));
        !           476:     new = metric_to_kernel(newmetric);
        !           477: 
        !           478:     if(route->installed && old != new) {
        !           479:         int rc;
        !           480:         rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen,
        !           481:                           route->nexthop, route->neigh->ifp->ifindex,
        !           482:                           old,
        !           483:                           route->nexthop, route->neigh->ifp->ifindex,
        !           484:                           new);
        !           485:         if(rc < 0) {
        !           486:             zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno));
        !           487:             return;
        !           488:         }
        !           489:     }
        !           490: 
        !           491:     route->refmetric = refmetric;
        !           492:     route->cost = cost;
        !           493:     route->add_metric = add;
        !           494: }
        !           495: 
        !           496: static void
        !           497: retract_route(struct babel_route *route)
        !           498: {
        !           499:     change_route_metric(route, INFINITY, INFINITY, 0);
        !           500: }
        !           501: 
        !           502: int
        !           503: route_feasible(struct babel_route *route)
        !           504: {
        !           505:     return update_feasible(route->src, route->seqno, route->refmetric);
        !           506: }
        !           507: 
        !           508: int
        !           509: route_old(struct babel_route *route)
        !           510: {
        !           511:     return route->time < babel_now.tv_sec - route->hold_time * 7 / 8;
        !           512: }
        !           513: 
        !           514: int
        !           515: route_expired(struct babel_route *route)
        !           516: {
        !           517:     return route->time < babel_now.tv_sec - route->hold_time;
        !           518: }
        !           519: 
        !           520: static int
        !           521: channels_interfere(int ch1, int ch2)
        !           522: {
        !           523:     if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING
        !           524:        || ch2 == BABEL_IF_CHANNEL_NONINTERFERING)
        !           525:         return 0;
        !           526:     if(ch1 == BABEL_IF_CHANNEL_INTERFERING
        !           527:        || ch2 == BABEL_IF_CHANNEL_INTERFERING)
        !           528:         return 1;
        !           529:     return ch1 == ch2;
        !           530: }
        !           531: 
        !           532: int
        !           533: route_interferes(struct babel_route *route, struct interface *ifp)
        !           534: {
        !           535:     struct babel_interface *babel_ifp = NULL;
        !           536:     switch(diversity_kind) {
        !           537:     case DIVERSITY_NONE:
        !           538:         return 1;
        !           539:     case DIVERSITY_INTERFACE_1:
        !           540:         return route->neigh->ifp == ifp;
        !           541:     case DIVERSITY_CHANNEL_1:
        !           542:     case DIVERSITY_CHANNEL:
        !           543:         if(route->neigh->ifp == ifp)
        !           544:             return 1;
        !           545:         babel_ifp = babel_get_if_nfo(ifp);
        !           546:         if(channels_interfere(babel_ifp->channel,
        !           547:                               babel_get_if_nfo(route->neigh->ifp)->channel))
        !           548:             return 1;
        !           549:         if(diversity_kind == DIVERSITY_CHANNEL) {
        !           550:             int i;
        !           551:             for(i = 0; i < DIVERSITY_HOPS; i++) {
        !           552:                 if(route->channels[i] == 0)
        !           553:                     break;
        !           554:                 if(channels_interfere(babel_ifp->channel, route->channels[i]))
        !           555:                     return 1;
        !           556:             }
        !           557:         }
        !           558:         return 0;
        !           559:     default:
        !           560:         fprintf(stderr, "Unknown kind of diversity.\n");
        !           561:         return 1;
        !           562:     }
        !           563: }
        !           564: 
        !           565: int
        !           566: update_feasible(struct source *src,
        !           567:                 unsigned short seqno, unsigned short refmetric)
        !           568: {
        !           569:     if(src == NULL)
        !           570:         return 1;
        !           571: 
        !           572:     if(src->time < babel_now.tv_sec - SOURCE_GC_TIME)
        !           573:         /* Never mind what is probably stale data */
        !           574:         return 1;
        !           575: 
        !           576:     if(refmetric >= INFINITY)
        !           577:         /* Retractions are always feasible */
        !           578:         return 1;
        !           579: 
        !           580:     return (seqno_compare(seqno, src->seqno) > 0 ||
        !           581:             (src->seqno == seqno && refmetric < src->metric));
        !           582: }
        !           583: 
        !           584: /* This returns the feasible route with the smallest metric. */
        !           585: struct babel_route *
        !           586: find_best_route(const unsigned char *prefix, unsigned char plen, int feasible,
        !           587:                 struct neighbour *exclude)
        !           588: {
        !           589:     struct babel_route *route = NULL, *r = NULL;
        !           590:     int i = find_route_slot(prefix, plen, NULL);
        !           591: 
        !           592:     if(i < 0)
        !           593:         return NULL;
        !           594: 
        !           595:     route = routes[i];
        !           596: 
        !           597:     r = route->next;
        !           598:     while(r) {
        !           599:         if(!route_expired(r) &&
        !           600:            (!feasible || route_feasible(r)) &&
        !           601:            (!exclude || r->neigh != exclude) &&
        !           602:            (route_metric(r) < route_metric(route)))
        !           603:             route = r;
        !           604:         r = r->next;
        !           605:     }
        !           606:     return route;
        !           607: }
        !           608: 
        !           609: void
        !           610: update_route_metric(struct babel_route *route)
        !           611: {
        !           612:     int oldmetric = route_metric(route);
        !           613: 
        !           614:     if(route_expired(route)) {
        !           615:         if(route->refmetric < INFINITY) {
        !           616:             route->seqno = seqno_plus(route->src->seqno, 1);
        !           617:             retract_route(route);
        !           618:             if(oldmetric < INFINITY)
        !           619:                 route_changed(route, route->src, oldmetric);
        !           620:         }
        !           621:     } else {
        !           622:         struct neighbour *neigh = route->neigh;
        !           623:         int add_metric = input_filter(route->src->id,
        !           624:                                       route->src->prefix, route->src->plen,
        !           625:                                       neigh->address,
        !           626:                                       neigh->ifp->ifindex);
        !           627:         change_route_metric(route, route->refmetric,
        !           628:                             neighbour_cost(route->neigh), add_metric);
        !           629:         if(route_metric(route) != oldmetric)
        !           630:             route_changed(route, route->src, oldmetric);
        !           631:     }
        !           632: }
        !           633: 
        !           634: /* Called whenever a neighbour's cost changes, to update the metric of
        !           635:    all routes through that neighbour.  Calls local_notify_neighbour. */
        !           636: void
        !           637: update_neighbour_metric(struct neighbour *neigh, int changed)
        !           638: {
        !           639: 
        !           640:     if(changed) {
        !           641:         int i;
        !           642: 
        !           643:         for(i = 0; i < route_slots; i++) {
        !           644:             struct babel_route *r = routes[i];
        !           645:             while(r) {
        !           646:                 if(r->neigh == neigh)
        !           647:                     update_route_metric(r);
        !           648:                 r = r->next;
        !           649:             }
        !           650:         }
        !           651:     }
        !           652: }
        !           653: 
        !           654: void
        !           655: update_interface_metric(struct interface *ifp)
        !           656: {
        !           657:     int i;
        !           658: 
        !           659:     for(i = 0; i < route_slots; i++) {
        !           660:         struct babel_route *r = routes[i];
        !           661:         while(r) {
        !           662:             if(r->neigh->ifp == ifp)
        !           663:                 update_route_metric(r);
        !           664:             r = r->next;
        !           665:         }
        !           666:     }
        !           667: }
        !           668: 
        !           669: /* This is called whenever we receive an update. */
        !           670: struct babel_route *
        !           671: update_route(const unsigned char *router_id,
        !           672:              const unsigned char *prefix, unsigned char plen,
        !           673:              unsigned short seqno, unsigned short refmetric,
        !           674:              unsigned short interval,
        !           675:              struct neighbour *neigh, const unsigned char *nexthop,
        !           676:              const unsigned char *channels, int channels_len)
        !           677: {
        !           678:     struct babel_route *route;
        !           679:     struct source *src;
        !           680:     int metric, feasible;
        !           681:     int add_metric;
        !           682:     int hold_time = MAX((4 * interval) / 100 + interval / 50, 15);
        !           683: 
        !           684:     if(memcmp(router_id, myid, 8) == 0)
        !           685:         return NULL;
        !           686: 
        !           687:     if(martian_prefix(prefix, plen)) {
        !           688:         zlog_err("Rejecting martian route to %s through %s.",
        !           689:                  format_prefix(prefix, plen), format_address(router_id));
        !           690:         return NULL;
        !           691:     }
        !           692: 
        !           693:     add_metric = input_filter(router_id, prefix, plen,
        !           694:                               neigh->address, neigh->ifp->ifindex);
        !           695:     if(add_metric >= INFINITY)
        !           696:         return NULL;
        !           697: 
        !           698:     route = find_route(prefix, plen, neigh, nexthop);
        !           699: 
        !           700:     if(route && memcmp(route->src->id, router_id, 8) == 0)
        !           701:         /* Avoid scanning the source table. */
        !           702:         src = route->src;
        !           703:     else
        !           704:         src = find_source(router_id, prefix, plen, 1, seqno);
        !           705: 
        !           706:     if(src == NULL)
        !           707:         return NULL;
        !           708: 
        !           709:     feasible = update_feasible(src, seqno, refmetric);
        !           710:     metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY);
        !           711: 
        !           712:     if(route) {
        !           713:         struct source *oldsrc;
        !           714:         unsigned short oldmetric;
        !           715:         int lost = 0;
        !           716: 
        !           717:         oldsrc = route->src;
        !           718:         oldmetric = route_metric(route);
        !           719: 
        !           720:         /* If a successor switches sources, we must accept his update even
        !           721:            if it makes a route unfeasible in order to break any routing loops
        !           722:            in a timely manner.  If the source remains the same, we ignore
        !           723:            the update. */
        !           724:         if(!feasible && route->installed) {
        !           725:             debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s "
        !           726:                    "(%s %d %d -> %s %d %d).",
        !           727:                    format_prefix(src->prefix, src->plen),
        !           728:                    format_address(route->src->id),
        !           729:                    route->seqno, route->refmetric,
        !           730:                    format_address(src->id), seqno, refmetric);
        !           731:             if(src != route->src) {
        !           732:                 uninstall_route(route);
        !           733:                 lost = 1;
        !           734:             }
        !           735:         }
        !           736: 
        !           737:         route->src = retain_source(src);
        !           738:         if((feasible || keep_unfeasible) && refmetric < INFINITY)
        !           739:             route->time = babel_now.tv_sec;
        !           740:         route->seqno = seqno;
        !           741:         change_route_metric(route,
        !           742:                             refmetric, neighbour_cost(neigh), add_metric);
        !           743:         route->hold_time = hold_time;
        !           744: 
        !           745:         route_changed(route, oldsrc, oldmetric);
        !           746:         if(lost)
        !           747:             route_lost(oldsrc, oldmetric);
        !           748: 
        !           749:         if(!feasible)
        !           750:             send_unfeasible_request(neigh, route->installed && route_old(route),
        !           751:                                     seqno, metric, src);
        !           752:         release_source(oldsrc);
        !           753:     } else {
        !           754:         struct babel_route *new_route;
        !           755: 
        !           756:         if(refmetric >= INFINITY)
        !           757:             /* Somebody's retracting a route we never saw. */
        !           758:             return NULL;
        !           759:         if(!feasible) {
        !           760:             send_unfeasible_request(neigh, 0, seqno, metric, src);
        !           761:             if(!keep_unfeasible)
        !           762:                 return NULL;
        !           763:         }
        !           764: 
        !           765:         route = malloc(sizeof(struct babel_route));
        !           766:         if(route == NULL) {
        !           767:             perror("malloc(route)");
        !           768:             return NULL;
        !           769:         }
        !           770: 
        !           771:         route->src = retain_source(src);
        !           772:         route->refmetric = refmetric;
        !           773:         route->cost = neighbour_cost(neigh);
        !           774:         route->add_metric = add_metric;
        !           775:         route->seqno = seqno;
        !           776:         route->neigh = neigh;
        !           777:         memcpy(route->nexthop, nexthop, 16);
        !           778:         route->time = babel_now.tv_sec;
        !           779:         route->hold_time = hold_time;
        !           780:         route->installed = 0;
        !           781:         memset(&route->channels, 0, sizeof(route->channels));
        !           782:         if(channels_len > 0)
        !           783:             memcpy(&route->channels, channels,
        !           784:                    MIN(channels_len, DIVERSITY_HOPS));
        !           785:         route->next = NULL;
        !           786:         new_route = insert_route(route);
        !           787:         if(new_route == NULL) {
        !           788:             fprintf(stderr, "Couldn't insert route.\n");
        !           789:             free(route);
        !           790:             return NULL;
        !           791:         }
        !           792:         consider_route(route);
        !           793:     }
        !           794:     return route;
        !           795: }
        !           796: 
        !           797: /* We just received an unfeasible update.  If it's any good, send
        !           798:    a request for a new seqno. */
        !           799: void
        !           800: send_unfeasible_request(struct neighbour *neigh, int force,
        !           801:                         unsigned short seqno, unsigned short metric,
        !           802:                         struct source *src)
        !           803: {
        !           804:     struct babel_route *route = find_installed_route(src->prefix, src->plen);
        !           805: 
        !           806:     if(seqno_minus(src->seqno, seqno) > 100) {
        !           807:         /* Probably a source that lost its seqno.  Let it time-out. */
        !           808:         return;
        !           809:     }
        !           810: 
        !           811:     if(force || !route || route_metric(route) >= metric + 512) {
        !           812:         send_unicast_multihop_request(neigh, src->prefix, src->plen,
        !           813:                                       src->metric >= INFINITY ?
        !           814:                                       src->seqno :
        !           815:                                       seqno_plus(src->seqno, 1),
        !           816:                                       src->id, 127);
        !           817:     }
        !           818: }
        !           819: 
        !           820: /* This takes a feasible route and decides whether to install it. */
        !           821: static void
        !           822: consider_route(struct babel_route *route)
        !           823: {
        !           824:     struct babel_route *installed;
        !           825:     struct xroute *xroute;
        !           826: 
        !           827:     if(route->installed)
        !           828:         return;
        !           829: 
        !           830:     if(!route_feasible(route))
        !           831:         return;
        !           832: 
        !           833:     xroute = find_xroute(route->src->prefix, route->src->plen);
        !           834:     if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates))
        !           835:         return;
        !           836: 
        !           837:     installed = find_installed_route(route->src->prefix, route->src->plen);
        !           838: 
        !           839:     if(installed == NULL)
        !           840:         goto install;
        !           841: 
        !           842:     if(route_metric(route) >= INFINITY)
        !           843:         return;
        !           844: 
        !           845:     if(route_metric(installed) >= INFINITY)
        !           846:         goto install;
        !           847: 
        !           848:     if(route_metric(installed) >= route_metric(route) + 64)
        !           849:         goto install;
        !           850: 
        !           851:     return;
        !           852: 
        !           853:  install:
        !           854:     switch_routes(installed, route);
        !           855:     if(installed && route->installed)
        !           856:         send_triggered_update(route, installed->src, route_metric(installed));
        !           857:     else
        !           858:         send_update(NULL, 1, route->src->prefix, route->src->plen);
        !           859:     return;
        !           860: }
        !           861: 
        !           862: void
        !           863: retract_neighbour_routes(struct neighbour *neigh)
        !           864: {
        !           865:     int i;
        !           866: 
        !           867:     for(i = 0; i < route_slots; i++) {
        !           868:         struct babel_route *r = routes[i];
        !           869:         while(r) {
        !           870:             if(r->neigh == neigh) {
        !           871:                 if(r->refmetric != INFINITY) {
        !           872:                     unsigned short oldmetric = route_metric(r);
        !           873:                     retract_route(r);
        !           874:                     if(oldmetric != INFINITY)
        !           875:                         route_changed(r, r->src, oldmetric);
        !           876:                 }
        !           877:             }
        !           878:             r = r->next;
        !           879:         }
        !           880:         i++;
        !           881:     }
        !           882: }
        !           883: 
        !           884: void
        !           885: send_triggered_update(struct babel_route *route, struct source *oldsrc,
        !           886:                       unsigned oldmetric)
        !           887: {
        !           888:     unsigned newmetric, diff;
        !           889:     /* 1 means send speedily, 2 means resend */
        !           890:     int urgent;
        !           891: 
        !           892:     if(!route->installed)
        !           893:         return;
        !           894: 
        !           895:     newmetric = route_metric(route);
        !           896:     diff =
        !           897:         newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric;
        !           898: 
        !           899:     if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY))
        !           900:         /* Switching sources can cause transient routing loops.
        !           901:            Retractions can cause blackholes. */
        !           902:         urgent = 2;
        !           903:     else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512)
        !           904:         /* Route getting significantly worse */
        !           905:         urgent = 1;
        !           906:     else if(unsatisfied_request(route->src->prefix, route->src->plen,
        !           907:                                 route->seqno, route->src->id))
        !           908:         /* Make sure that requests are satisfied speedily */
        !           909:         urgent = 1;
        !           910:     else if(oldmetric >= INFINITY && newmetric < INFINITY)
        !           911:         /* New route */
        !           912:         urgent = 0;
        !           913:     else if(newmetric < oldmetric && diff < 1024)
        !           914:         /* Route getting better.  This may be a transient fluctuation, so
        !           915:            don't advertise it to avoid making routes unfeasible later on. */
        !           916:         return;
        !           917:     else if(diff < 384)
        !           918:         /* Don't fret about trivialities */
        !           919:         return;
        !           920:     else
        !           921:         urgent = 0;
        !           922: 
        !           923:     if(urgent >= 2)
        !           924:         send_update_resend(NULL, route->src->prefix, route->src->plen);
        !           925:     else
        !           926:         send_update(NULL, urgent, route->src->prefix, route->src->plen);
        !           927: 
        !           928:     if(oldmetric < INFINITY) {
        !           929:         if(newmetric >= oldmetric + 512) {
        !           930:             send_request_resend(NULL, route->src->prefix, route->src->plen,
        !           931:                                 route->src->metric >= INFINITY ?
        !           932:                                 route->src->seqno :
        !           933:                                 seqno_plus(route->src->seqno, 1),
        !           934:                                 route->src->id);
        !           935:         } else if(newmetric >= oldmetric + 288) {
        !           936:             send_request(NULL, route->src->prefix, route->src->plen);
        !           937:         }
        !           938:     }
        !           939: }
        !           940: 
        !           941: /* A route has just changed.  Decide whether to switch to a different route or
        !           942:    send an update. */
        !           943: void
        !           944: route_changed(struct babel_route *route,
        !           945:               struct source *oldsrc, unsigned short oldmetric)
        !           946: {
        !           947:     if(route->installed) {
        !           948:         if(route_metric(route) > oldmetric) {
        !           949:             struct babel_route *better_route;
        !           950:             better_route =
        !           951:                 find_best_route(route->src->prefix, route->src->plen, 1, NULL);
        !           952:             if(better_route &&
        !           953:                route_metric(better_route) <= route_metric(route) - 96)
        !           954:                 consider_route(better_route);
        !           955:         }
        !           956: 
        !           957:         if(route->installed)
        !           958:             /* We didn't change routes after all. */
        !           959:             send_triggered_update(route, oldsrc, oldmetric);
        !           960:     } else {
        !           961:         /* Reconsider routes even when their metric didn't decrease,
        !           962:            they may not have been feasible before. */
        !           963:         consider_route(route);
        !           964:     }
        !           965: }
        !           966: 
        !           967: /* We just lost the installed route to a given destination. */
        !           968: void
        !           969: route_lost(struct source *src, unsigned oldmetric)
        !           970: {
        !           971:     struct babel_route *new_route;
        !           972:     new_route = find_best_route(src->prefix, src->plen, 1, NULL);
        !           973:     if(new_route) {
        !           974:         consider_route(new_route);
        !           975:     } else if(oldmetric < INFINITY) {
        !           976:         /* Complain loudly. */
        !           977:         send_update_resend(NULL, src->prefix, src->plen);
        !           978:         send_request_resend(NULL, src->prefix, src->plen,
        !           979:                             src->metric >= INFINITY ?
        !           980:                             src->seqno : seqno_plus(src->seqno, 1),
        !           981:                             src->id);
        !           982:     }
        !           983: }
        !           984: 
        !           985: /* This is called periodically to flush old routes.  It will also send
        !           986:    requests for routes that are about to expire. */
        !           987: void
        !           988: expire_routes(void)
        !           989: {
        !           990:     struct babel_route *r;
        !           991:     int i;
        !           992: 
        !           993:     debugf(BABEL_DEBUG_COMMON,"Expiring old routes.");
        !           994: 
        !           995:     i = 0;
        !           996:     while(i < route_slots) {
        !           997:         r = routes[i];
        !           998:         while(r) {
        !           999:             /* Protect against clock being stepped. */
        !          1000:             if(r->time > babel_now.tv_sec || route_old(r)) {
        !          1001:                 flush_route(r);
        !          1002:                 goto again;
        !          1003:             }
        !          1004: 
        !          1005:             update_route_metric(r);
        !          1006: 
        !          1007:             if(r->installed && r->refmetric < INFINITY) {
        !          1008:                 if(route_old(r))
        !          1009:                     /* Route about to expire, send a request. */
        !          1010:                     send_unicast_request(r->neigh,
        !          1011:                                          r->src->prefix, r->src->plen);
        !          1012:             }
        !          1013:             r = r->next;
        !          1014:         }
        !          1015:         i++;
        !          1016:     again:
        !          1017:         ;
        !          1018:     }
        !          1019: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>