diff options
| author | Daniel Walton <dwalton@cumulusnetworks.com> | 2016-02-11 08:55:24 -0800 | 
|---|---|---|
| committer | Daniel Walton <dwalton@cumulusnetworks.com> | 2016-02-11 08:55:24 -0800 | 
| commit | 41d9cc6a6569e3a66f77a9cfd2869d209e665fa0 (patch) | |
| tree | f7de1b136260d314a26b378156d7f94cf42e36a7 /babeld/route.c | |
| parent | b3556ea327bf3abc4bd183a4b5b8ad1a15d15035 (diff) | |
quagga: remove babel
Ticket: CM-9274
Reviewed By: sharpd@cumulusnetworks.com
Testing Done:
<DETAILED DESCRIPTION (REPLACE)>
Diffstat (limited to 'babeld/route.c')
| -rw-r--r-- | babeld/route.c | 1019 | 
1 files changed, 0 insertions, 1019 deletions
diff --git a/babeld/route.c b/babeld/route.c deleted file mode 100644 index fe2b9cebb7..0000000000 --- a/babeld/route.c +++ /dev/null @@ -1,1019 +0,0 @@ -/*   - *  This file is free software: you may copy, redistribute and/or modify it   - *  under the terms of the GNU General Public License as published by the   - *  Free Software Foundation, either version 2 of the License, or (at your   - *  option) any later version.   - *   - *  This file is distributed in the hope that it will be useful, but   - *  WITHOUT ANY WARRANTY; without even the implied warranty of   - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   - *  General Public License for more details.   - *   - *  You should have received a copy of the GNU General Public License   - *  along with this program.  If not, see <http://www.gnu.org/licenses/>.   - *   - * This file incorporates work covered by the following copyright and   - * permission notice:   - *   -Copyright (c) 2007, 2008 by Juliusz Chroboczek -Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include <zebra.h> -#include "if.h" - -#include "babeld.h" -#include "util.h" -#include "kernel.h" -#include "babel_interface.h" -#include "source.h" -#include "neighbour.h" -#include "route.h" -#include "xroute.h" -#include "message.h" -#include "resend.h" - -static void consider_route(struct babel_route *route); - -struct babel_route **routes = NULL; -static int route_slots = 0, max_route_slots = 0; -int kernel_metric = 0; -int allow_duplicates = -1; -int diversity_kind = DIVERSITY_NONE; -int diversity_factor = 256;     /* in units of 1/256 */ -int keep_unfeasible = 0; - -/* We maintain a list of "slots", ordered by prefix.  Every slot -   contains a linked list of the routes to this prefix, with the -   installed route, if any, at the head of the list. */ - -static int -route_compare(const unsigned char *prefix, unsigned char plen, -               struct babel_route *route) -{ -    int i = memcmp(prefix, route->src->prefix, 16); -    if(i != 0) -        return i; - -    if(plen < route->src->plen) -        return -1; -    else if(plen > route->src->plen) -        return 1; -    else -        return 0; -} - -/* Performs binary search, returns -1 in case of failure.  In the latter -   case, new_return is the place where to insert the new element. */ - -static int -find_route_slot(const unsigned char *prefix, unsigned char plen, -                int *new_return) -{ -    int p, m, g, c; - -    if(route_slots < 1) { -        if(new_return) -            *new_return = 0; -        return -1; -    } - -    p = 0; g = route_slots - 1; - -    do { -        m = (p + g) / 2; -        c = route_compare(prefix, plen, routes[m]); -        if(c == 0) -            return m; -        else if(c < 0) -            g = m - 1; -        else -            p = m + 1; -    } while(p <= g); - -    if(new_return) -        *new_return = p; - -    return -1; -} - -struct babel_route * -find_route(const unsigned char *prefix, unsigned char plen, -           struct neighbour *neigh, const unsigned char *nexthop) -{ -    struct babel_route *route; -    int i = find_route_slot(prefix, plen, NULL); - -    if(i < 0) -        return NULL; - -    route = routes[i]; - -    while(route) { -        if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0) -            return route; -        route = route->next; -    } - -    return NULL; -} - -struct babel_route * -find_installed_route(const unsigned char *prefix, unsigned char plen) -{ -    int i = find_route_slot(prefix, plen, NULL); - -    if(i >= 0 && routes[i]->installed) -        return routes[i]; - -    return NULL; -} - -/* Returns an overestimate of the number of installed routes. */ -int -installed_routes_estimate(void) -{ -    return route_slots; -} - -static int -resize_route_table(int new_slots) -{ -    struct babel_route **new_routes; -    assert(new_slots >= route_slots); - -    if(new_slots == 0) { -        new_routes = NULL; -        free(routes); -    } else { -        new_routes = realloc(routes, new_slots * sizeof(struct babel_route*)); -        if(new_routes == NULL) -            return -1; -    } - -    max_route_slots = new_slots; -    routes = new_routes; -    return 1; -} - -/* Insert a route into the table.  If successful, retains the route. -   On failure, caller must free the route. */ -static struct babel_route * -insert_route(struct babel_route *route) -{ -    int i, n; - -    assert(!route->installed); - -    i = find_route_slot(route->src->prefix, route->src->plen, &n); - -    if(i < 0) { -        if(route_slots >= max_route_slots) -            resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots); -        if(route_slots >= max_route_slots) -            return NULL; -        route->next = NULL; -        if(n < route_slots) -            memmove(routes + n + 1, routes + n, -                    (route_slots - n) * sizeof(struct babel_route*)); -        route_slots++; -        routes[n] = route; -    } else { -        struct babel_route *r; -        r = routes[i]; -        while(r->next) -            r = r->next; -        r->next = route; -        route->next = NULL; -    } - -    return route; -} - -void -flush_route(struct babel_route *route) -{ -    int i; -    struct source *src; -    unsigned oldmetric; -    int lost = 0; - -    oldmetric = route_metric(route); -    src = route->src; - -    if(route->installed) { -        uninstall_route(route); -        lost = 1; -    } - -    i = find_route_slot(route->src->prefix, route->src->plen, NULL); -    assert(i >= 0 && i < route_slots); - -    if(route == routes[i]) { -        routes[i] = route->next; -        route->next = NULL; -        free(route); - -        if(routes[i] == NULL) { -            if(i < route_slots - 1) -                memmove(routes + i, routes + i + 1, -                        (route_slots - i - 1) * sizeof(struct babel_route*)); -            routes[route_slots - 1] = NULL; -            route_slots--; -        } - -        if(route_slots == 0) -            resize_route_table(0); -        else if(max_route_slots > 8 && route_slots < max_route_slots / 4) -            resize_route_table(max_route_slots / 2); -    } else { -        struct babel_route *r = routes[i]; -        while(r->next != route) -            r = r->next; -        r->next = route->next; -        route->next = NULL; -        free(route); -    } - -    if(lost) -        route_lost(src, oldmetric); - -    release_source(src); -} - -void -flush_all_routes() -{ -    int i; - -    /* Start from the end, to avoid shifting the table. */ -    i = route_slots - 1; -    while(i >= 0) { -        while(i < route_slots) { -        /* Uninstall first, to avoid calling route_lost. */ -            if(routes[i]->installed) -                uninstall_route(routes[0]); -            flush_route(routes[i]); -        } -        i--; -    } - -    check_sources_released(); -} - -void -flush_neighbour_routes(struct neighbour *neigh) -{ -    int i; - -    i = 0; -    while(i < route_slots) { -        struct babel_route *r; -        r = routes[i]; -        while(r) { -            if(r->neigh == neigh) { -                flush_route(r); -                goto again; -            } -            r = r->next; -        } -        i++; -    again: -        ; -    } -} - -void -flush_interface_routes(struct interface *ifp, int v4only) -{ -    int i; - -    i = 0; -    while(i < route_slots) { -        struct babel_route *r; -        r = routes[i]; -        while(r) { -            if(r->neigh->ifp == ifp && -               (!v4only || v4mapped(r->nexthop))) { -                flush_route(r); -                goto again; -            } -            r = r->next; -        } -        i++; -    again: -        ; -    } -} - -/* Iterate a function over all routes. */ -void -for_all_routes(void (*f)(struct babel_route*, void*), void *closure) -{ -    int i; - -    for(i = 0; i < route_slots; i++) { -        struct babel_route *r = routes[i]; -        while(r) { -            (*f)(r, closure); -            r = r->next; -        } -    } -} - -void -for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure) -{ -    int i; - -    for(i = 0; i < route_slots; i++) { -        if(routes[i]->installed) -            (*f)(routes[i], closure); -    } -} - -static int -metric_to_kernel(int metric) -{ -    return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; -} - -/* This is used to maintain the invariant that the installed route is at -   the head of the list. */ -static void -move_installed_route(struct babel_route *route, int i) -{ -    assert(i >= 0 && i < route_slots); -    assert(route->installed); - -    if(route != routes[i]) { -        struct babel_route *r = routes[i]; -        while(r->next != route) -            r = r->next; -        r->next = route->next; -        route->next = routes[i]; -        routes[i] = route; -    } -} - -void -install_route(struct babel_route *route) -{ -    int i, rc; - -    if(route->installed) -        return; - -    if(!route_feasible(route)) -        zlog_err("WARNING: installing unfeasible route " -                 "(this shouldn't happen)."); - -    i = find_route_slot(route->src->prefix, route->src->plen, NULL); -    assert(i >= 0 && i < route_slots); - -    if(routes[i] != route && routes[i]->installed) { -        fprintf(stderr, "WARNING: attempting to install duplicate route " -                "(this shouldn't happen)."); -        return; -    } - -    rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, -                      route->nexthop, -                      route->neigh->ifp->ifindex, -                      metric_to_kernel(route_metric(route)), NULL, 0, 0); -    if(rc < 0) { -        int save = errno; -        zlog_err("kernel_route(ADD): %s", safe_strerror(errno)); -        if(save != EEXIST) -            return; -    } -    route->installed = 1; -    move_installed_route(route, i); - -} - -void -uninstall_route(struct babel_route *route) -{ -    int rc; - -    if(!route->installed) -        return; - -    rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, -                      route->nexthop, -                      route->neigh->ifp->ifindex, -                      metric_to_kernel(route_metric(route)), NULL, 0, 0); -    if(rc < 0) -        zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno)); - -    route->installed = 0; -} - -/* This is equivalent to uninstall_route followed with install_route, -   but without the race condition.  The destination of both routes -   must be the same. */ - -static void -switch_routes(struct babel_route *old, struct babel_route *new) -{ -    int rc; - -    if(!old) { -        install_route(new); -        return; -    } - -    if(!old->installed) -        return; - -    if(!route_feasible(new)) -        zlog_err("WARNING: switching to unfeasible route " -                 "(this shouldn't happen)."); - -    rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, -                      old->nexthop, old->neigh->ifp->ifindex, -                      metric_to_kernel(route_metric(old)), -                      new->nexthop, new->neigh->ifp->ifindex, -                      metric_to_kernel(route_metric(new))); -    if(rc < 0) { -        zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno)); -        return; -    } - -    old->installed = 0; -    new->installed = 1; -    move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen, -                                              NULL)); -} - -static void -change_route_metric(struct babel_route *route, -                    unsigned refmetric, unsigned cost, unsigned add) -{ -    int old, new; -    int newmetric = MIN(refmetric + cost + add, INFINITY); - -    old = metric_to_kernel(route_metric(route)); -    new = metric_to_kernel(newmetric); - -    if(route->installed && old != new) { -        int rc; -        rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, -                          route->nexthop, route->neigh->ifp->ifindex, -                          old, -                          route->nexthop, route->neigh->ifp->ifindex, -                          new); -        if(rc < 0) { -            zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno)); -            return; -        } -    } - -    route->refmetric = refmetric; -    route->cost = cost; -    route->add_metric = add; -} - -static void -retract_route(struct babel_route *route) -{ -    change_route_metric(route, INFINITY, INFINITY, 0); -} - -int -route_feasible(struct babel_route *route) -{ -    return update_feasible(route->src, route->seqno, route->refmetric); -} - -int -route_old(struct babel_route *route) -{ -    return route->time < babel_now.tv_sec - route->hold_time * 7 / 8; -} - -int -route_expired(struct babel_route *route) -{ -    return route->time < babel_now.tv_sec - route->hold_time; -} - -static int -channels_interfere(int ch1, int ch2) -{ -    if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING -       || ch2 == BABEL_IF_CHANNEL_NONINTERFERING) -        return 0; -    if(ch1 == BABEL_IF_CHANNEL_INTERFERING -       || ch2 == BABEL_IF_CHANNEL_INTERFERING) -        return 1; -    return ch1 == ch2; -} - -int -route_interferes(struct babel_route *route, struct interface *ifp) -{ -    struct babel_interface *babel_ifp = NULL; -    switch(diversity_kind) { -    case DIVERSITY_NONE: -        return 1; -    case DIVERSITY_INTERFACE_1: -        return route->neigh->ifp == ifp; -    case DIVERSITY_CHANNEL_1: -    case DIVERSITY_CHANNEL: -        if(route->neigh->ifp == ifp) -            return 1; -        babel_ifp = babel_get_if_nfo(ifp); -        if(channels_interfere(babel_ifp->channel, -                              babel_get_if_nfo(route->neigh->ifp)->channel)) -            return 1; -        if(diversity_kind == DIVERSITY_CHANNEL) { -            int i; -            for(i = 0; i < DIVERSITY_HOPS; i++) { -                if(route->channels[i] == 0) -                    break; -                if(channels_interfere(babel_ifp->channel, route->channels[i])) -                    return 1; -            } -        } -        return 0; -    default: -        fprintf(stderr, "Unknown kind of diversity.\n"); -        return 1; -    } -} - -int -update_feasible(struct source *src, -                unsigned short seqno, unsigned short refmetric) -{ -    if(src == NULL) -        return 1; - -    if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) -        /* Never mind what is probably stale data */ -        return 1; - -    if(refmetric >= INFINITY) -        /* Retractions are always feasible */ -        return 1; - -    return (seqno_compare(seqno, src->seqno) > 0 || -            (src->seqno == seqno && refmetric < src->metric)); -} - -/* This returns the feasible route with the smallest metric. */ -struct babel_route * -find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, -                struct neighbour *exclude) -{ -    struct babel_route *route = NULL, *r = NULL; -    int i = find_route_slot(prefix, plen, NULL); - -    if(i < 0) -        return NULL; - -    route = routes[i]; - -    r = route->next; -    while(r) { -        if(!route_expired(r) && -           (!feasible || route_feasible(r)) && -           (!exclude || r->neigh != exclude) && -           (route_metric(r) < route_metric(route))) -            route = r; -        r = r->next; -    } -    return route; -} - -void -update_route_metric(struct babel_route *route) -{ -    int oldmetric = route_metric(route); - -    if(route_expired(route)) { -        if(route->refmetric < INFINITY) { -            route->seqno = seqno_plus(route->src->seqno, 1); -            retract_route(route); -            if(oldmetric < INFINITY) -                route_changed(route, route->src, oldmetric); -        } -    } else { -        struct neighbour *neigh = route->neigh; -        int add_metric = input_filter(route->src->id, -                                      route->src->prefix, route->src->plen, -                                      neigh->address, -                                      neigh->ifp->ifindex); -        change_route_metric(route, route->refmetric, -                            neighbour_cost(route->neigh), add_metric); -        if(route_metric(route) != oldmetric) -            route_changed(route, route->src, oldmetric); -    } -} - -/* Called whenever a neighbour's cost changes, to update the metric of -   all routes through that neighbour.  Calls local_notify_neighbour. */ -void -update_neighbour_metric(struct neighbour *neigh, int changed) -{ - -    if(changed) { -        int i; - -        for(i = 0; i < route_slots; i++) { -            struct babel_route *r = routes[i]; -            while(r) { -                if(r->neigh == neigh) -                    update_route_metric(r); -                r = r->next; -            } -        } -    } -} - -void -update_interface_metric(struct interface *ifp) -{ -    int i; - -    for(i = 0; i < route_slots; i++) { -        struct babel_route *r = routes[i]; -        while(r) { -            if(r->neigh->ifp == ifp) -                update_route_metric(r); -            r = r->next; -        } -    } -} - -/* This is called whenever we receive an update. */ -struct babel_route * -update_route(const unsigned char *router_id, -             const unsigned char *prefix, unsigned char plen, -             unsigned short seqno, unsigned short refmetric, -             unsigned short interval, -             struct neighbour *neigh, const unsigned char *nexthop, -             const unsigned char *channels, int channels_len) -{ -    struct babel_route *route; -    struct source *src; -    int metric, feasible; -    int add_metric; -    int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); - -    if(memcmp(router_id, myid, 8) == 0) -        return NULL; - -    if(martian_prefix(prefix, plen)) { -        zlog_err("Rejecting martian route to %s through %s.", -                 format_prefix(prefix, plen), format_address(router_id)); -        return NULL; -    } - -    add_metric = input_filter(router_id, prefix, plen, -                              neigh->address, neigh->ifp->ifindex); -    if(add_metric >= INFINITY) -        return NULL; - -    route = find_route(prefix, plen, neigh, nexthop); - -    if(route && memcmp(route->src->id, router_id, 8) == 0) -        /* Avoid scanning the source table. */ -        src = route->src; -    else -        src = find_source(router_id, prefix, plen, 1, seqno); - -    if(src == NULL) -        return NULL; - -    feasible = update_feasible(src, seqno, refmetric); -    metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); - -    if(route) { -        struct source *oldsrc; -        unsigned short oldmetric; -        int lost = 0; - -        oldsrc = route->src; -        oldmetric = route_metric(route); - -        /* If a successor switches sources, we must accept his update even -           if it makes a route unfeasible in order to break any routing loops -           in a timely manner.  If the source remains the same, we ignore -           the update. */ -        if(!feasible && route->installed) { -            debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s " -                   "(%s %d %d -> %s %d %d).", -                   format_prefix(src->prefix, src->plen), -                   format_address(route->src->id), -                   route->seqno, route->refmetric, -                   format_address(src->id), seqno, refmetric); -            if(src != route->src) { -                uninstall_route(route); -                lost = 1; -            } -        } - -        route->src = retain_source(src); -        if((feasible || keep_unfeasible) && refmetric < INFINITY) -            route->time = babel_now.tv_sec; -        route->seqno = seqno; -        change_route_metric(route, -                            refmetric, neighbour_cost(neigh), add_metric); -        route->hold_time = hold_time; - -        route_changed(route, oldsrc, oldmetric); -        if(lost) -            route_lost(oldsrc, oldmetric); - -        if(!feasible) -            send_unfeasible_request(neigh, route->installed && route_old(route), -                                    seqno, metric, src); -        release_source(oldsrc); -    } else { -        struct babel_route *new_route; - -        if(refmetric >= INFINITY) -            /* Somebody's retracting a route we never saw. */ -            return NULL; -        if(!feasible) { -            send_unfeasible_request(neigh, 0, seqno, metric, src); -            if(!keep_unfeasible) -                return NULL; -        } - -        route = malloc(sizeof(struct babel_route)); -        if(route == NULL) { -            perror("malloc(route)"); -            return NULL; -        } - -        route->src = retain_source(src); -        route->refmetric = refmetric; -        route->cost = neighbour_cost(neigh); -        route->add_metric = add_metric; -        route->seqno = seqno; -        route->neigh = neigh; -        memcpy(route->nexthop, nexthop, 16); -        route->time = babel_now.tv_sec; -        route->hold_time = hold_time; -        route->installed = 0; -        memset(&route->channels, 0, sizeof(route->channels)); -        if(channels_len > 0) -            memcpy(&route->channels, channels, -                   MIN(channels_len, DIVERSITY_HOPS)); -        route->next = NULL; -        new_route = insert_route(route); -        if(new_route == NULL) { -            fprintf(stderr, "Couldn't insert route.\n"); -            free(route); -            return NULL; -        } -        consider_route(route); -    } -    return route; -} - -/* We just received an unfeasible update.  If it's any good, send -   a request for a new seqno. */ -void -send_unfeasible_request(struct neighbour *neigh, int force, -                        unsigned short seqno, unsigned short metric, -                        struct source *src) -{ -    struct babel_route *route = find_installed_route(src->prefix, src->plen); - -    if(seqno_minus(src->seqno, seqno) > 100) { -        /* Probably a source that lost its seqno.  Let it time-out. */ -        return; -    } - -    if(force || !route || route_metric(route) >= metric + 512) { -        send_unicast_multihop_request(neigh, src->prefix, src->plen, -                                      src->metric >= INFINITY ? -                                      src->seqno : -                                      seqno_plus(src->seqno, 1), -                                      src->id, 127); -    } -} - -/* This takes a feasible route and decides whether to install it. */ -static void -consider_route(struct babel_route *route) -{ -    struct babel_route *installed; -    struct xroute *xroute; - -    if(route->installed) -        return; - -    if(!route_feasible(route)) -        return; - -    xroute = find_xroute(route->src->prefix, route->src->plen); -    if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates)) -        return; - -    installed = find_installed_route(route->src->prefix, route->src->plen); - -    if(installed == NULL) -        goto install; - -    if(route_metric(route) >= INFINITY) -        return; - -    if(route_metric(installed) >= INFINITY) -        goto install; - -    if(route_metric(installed) >= route_metric(route) + 64) -        goto install; - -    return; - - install: -    switch_routes(installed, route); -    if(installed && route->installed) -        send_triggered_update(route, installed->src, route_metric(installed)); -    else -        send_update(NULL, 1, route->src->prefix, route->src->plen); -    return; -} - -void -retract_neighbour_routes(struct neighbour *neigh) -{ -    int i; - -    for(i = 0; i < route_slots; i++) { -        struct babel_route *r = routes[i]; -        while(r) { -            if(r->neigh == neigh) { -                if(r->refmetric != INFINITY) { -                    unsigned short oldmetric = route_metric(r); -                    retract_route(r); -                    if(oldmetric != INFINITY) -                        route_changed(r, r->src, oldmetric); -                } -            } -            r = r->next; -        } -        i++; -    } -} - -void -send_triggered_update(struct babel_route *route, struct source *oldsrc, -                      unsigned oldmetric) -{ -    unsigned newmetric, diff; -    /* 1 means send speedily, 2 means resend */ -    int urgent; - -    if(!route->installed) -        return; - -    newmetric = route_metric(route); -    diff = -        newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric; - -    if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY)) -        /* Switching sources can cause transient routing loops. -           Retractions can cause blackholes. */ -        urgent = 2; -    else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512) -        /* Route getting significantly worse */ -        urgent = 1; -    else if(unsatisfied_request(route->src->prefix, route->src->plen, -                                route->seqno, route->src->id)) -        /* Make sure that requests are satisfied speedily */ -        urgent = 1; -    else if(oldmetric >= INFINITY && newmetric < INFINITY) -        /* New route */ -        urgent = 0; -    else if(newmetric < oldmetric && diff < 1024) -        /* Route getting better.  This may be a transient fluctuation, so -           don't advertise it to avoid making routes unfeasible later on. */ -        return; -    else if(diff < 384) -        /* Don't fret about trivialities */ -        return; -    else -        urgent = 0; - -    if(urgent >= 2) -        send_update_resend(NULL, route->src->prefix, route->src->plen); -    else -        send_update(NULL, urgent, route->src->prefix, route->src->plen); - -    if(oldmetric < INFINITY) { -        if(newmetric >= oldmetric + 512) { -            send_request_resend(NULL, route->src->prefix, route->src->plen, -                                route->src->metric >= INFINITY ? -                                route->src->seqno : -                                seqno_plus(route->src->seqno, 1), -                                route->src->id); -        } else if(newmetric >= oldmetric + 288) { -            send_request(NULL, route->src->prefix, route->src->plen); -        } -    } -} - -/* A route has just changed.  Decide whether to switch to a different route or -   send an update. */ -void -route_changed(struct babel_route *route, -              struct source *oldsrc, unsigned short oldmetric) -{ -    if(route->installed) { -        if(route_metric(route) > oldmetric) { -            struct babel_route *better_route; -            better_route = -                find_best_route(route->src->prefix, route->src->plen, 1, NULL); -            if(better_route && -               route_metric(better_route) <= route_metric(route) - 96) -                consider_route(better_route); -        } - -        if(route->installed) -            /* We didn't change routes after all. */ -            send_triggered_update(route, oldsrc, oldmetric); -    } else { -        /* Reconsider routes even when their metric didn't decrease, -           they may not have been feasible before. */ -        consider_route(route); -    } -} - -/* We just lost the installed route to a given destination. */ -void -route_lost(struct source *src, unsigned oldmetric) -{ -    struct babel_route *new_route; -    new_route = find_best_route(src->prefix, src->plen, 1, NULL); -    if(new_route) { -        consider_route(new_route); -    } else if(oldmetric < INFINITY) { -        /* Complain loudly. */ -        send_update_resend(NULL, src->prefix, src->plen); -        send_request_resend(NULL, src->prefix, src->plen, -                            src->metric >= INFINITY ? -                            src->seqno : seqno_plus(src->seqno, 1), -                            src->id); -    } -} - -/* This is called periodically to flush old routes.  It will also send -   requests for routes that are about to expire. */ -void -expire_routes(void) -{ -    struct babel_route *r; -    int i; - -    debugf(BABEL_DEBUG_COMMON,"Expiring old routes."); - -    i = 0; -    while(i < route_slots) { -        r = routes[i]; -        while(r) { -            /* Protect against clock being stepped. */ -            if(r->time > babel_now.tv_sec || route_old(r)) { -                flush_route(r); -                goto again; -            } - -            update_route_metric(r); - -            if(r->installed && r->refmetric < INFINITY) { -                if(route_old(r)) -                    /* Route about to expire, send a request. */ -                    send_unicast_request(r->neigh, -                                         r->src->prefix, r->src->plen); -            } -            r = r->next; -        } -        i++; -    again: -        ; -    } -}  | 
