summaryrefslogtreecommitdiff
path: root/babeld/route.c
diff options
context:
space:
mode:
authorDaniel Walton <dwalton@cumulusnetworks.com>2016-02-11 08:55:24 -0800
committerDaniel Walton <dwalton@cumulusnetworks.com>2016-02-11 08:55:24 -0800
commit41d9cc6a6569e3a66f77a9cfd2869d209e665fa0 (patch)
treef7de1b136260d314a26b378156d7f94cf42e36a7 /babeld/route.c
parentb3556ea327bf3abc4bd183a4b5b8ad1a15d15035 (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.c1019
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:
- ;
- }
-}