Commit a08dde85 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Make route operations execute in O(log n).

This changes the route table to be a sorted table of linked lists of
routes to a given prefix, which makes most route operations behave in
O(log n).  Insertion and flushing of a prefix is still O(n), but these
are fairly rare operations.

A nice side-effect is that the route table is now private to route.c,
which should make it easy to switch to a different data structure in
the future.
parent a19cdda2
...@@ -722,13 +722,8 @@ main(int argc, char **argv) ...@@ -722,13 +722,8 @@ main(int argc, char **argv)
usleep(roughly(10000)); usleep(roughly(10000));
gettime(&now); gettime(&now);
/* Uninstall and flush all routes. */ /* We need to flush so interface_up won't try to reinstall. */
while(numroutes > 0) { flush_all_routes();
if(routes[0].installed)
uninstall_route(&routes[0]);
/* We need to flush the route so interface_up won't reinstall it */
flush_route(&routes[0]);
}
FOR_ALL_INTERFACES(ifp) { FOR_ALL_INTERFACES(ifp) {
if(!if_up(ifp)) if(!if_up(ifp))
...@@ -923,6 +918,50 @@ init_signals(void) ...@@ -923,6 +918,50 @@ init_signals(void)
#endif #endif
} }
static void
dump_route_callback(struct route *route, void *closure)
{
FILE *out = (FILE*)closure;
const unsigned char *nexthop =
memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
NULL : route->nexthop;
char channels[100];
if(route->channels[0] == 0)
channels[0] = '\0';
else {
int k, j = 0;
snprintf(channels, 100, " chan (");
j = strlen(channels);
for(k = 0; k < DIVERSITY_HOPS; k++) {
if(route->channels[k] == 0)
break;
if(k > 0)
channels[j++] = ',';
snprintf(channels + j, 100 - j, "%d", route->channels[k]);
j = strlen(channels);
}
snprintf(channels + j, 100 - j, ")");
if(k == 0)
channels[0] = '\0';
}
fprintf(out, "%s metric %d refmetric %d id %s seqno %d%s age %d "
"via %s neigh %s%s%s%s\n",
format_prefix(route->src->prefix, route->src->plen),
route_metric(route), route->refmetric,
format_eui64(route->src->id),
(int)route->seqno,
channels,
(int)(now.tv_sec - route->time),
route->neigh->ifp->name,
format_address(route->neigh->address),
nexthop ? " nexthop " : "",
nexthop ? format_address(nexthop) : "",
route->installed ? " (installed)" :
route_feasible(route) ? " (feasible)" : "");
}
static void static void
dump_tables(FILE *out) dump_tables(FILE *out)
{ {
...@@ -948,45 +987,7 @@ dump_tables(FILE *out) ...@@ -948,45 +987,7 @@ dump_tables(FILE *out)
format_prefix(xroutes[i].prefix, xroutes[i].plen), format_prefix(xroutes[i].prefix, xroutes[i].plen),
xroutes[i].metric); xroutes[i].metric);
} }
for(i = 0; i < numroutes; i++) { for_all_routes(dump_route_callback, out);
const unsigned char *nexthop =
memcmp(routes[i].nexthop, routes[i].neigh->address, 16) == 0 ?
NULL : routes[i].nexthop;
char channels[100];
if(routes[i].channels[0] == 0)
channels[0] = '\0';
else {
int k, j = 0;
snprintf(channels, 100, " chan (");
j = strlen(channels);
for(k = 0; k < DIVERSITY_HOPS; k++) {
if(routes[i].channels[k] == 0)
break;
if(k > 0)
channels[j++] = ',';
snprintf(channels + j, 100 - j, "%d", routes[i].channels[k]);
j = strlen(channels);
}
snprintf(channels + j, 100 - j, ")");
if(k == 0)
channels[0] = '\0';
}
fprintf(out, "%s metric %d refmetric %d id %s seqno %d%s age %d "
"via %s neigh %s%s%s%s\n",
format_prefix(routes[i].src->prefix, routes[i].src->plen),
route_metric(&routes[i]), routes[i].refmetric,
format_eui64(routes[i].src->id),
(int)routes[i].seqno,
channels,
(int)(now.tv_sec - routes[i].time),
routes[i].neigh->ifp->name,
format_address(routes[i].neigh->address),
nexthop ? " nexthop " : "",
nexthop ? format_address(nexthop) : "",
routes[i].installed ? " (installed)" :
route_feasible(&routes[i]) ? " (feasible)" : "");
}
fflush(out); fflush(out);
} }
......
...@@ -222,6 +222,12 @@ local_notify_route(struct route *route, int kind) ...@@ -222,6 +222,12 @@ local_notify_route(struct route *route, int kind)
return; return;
} }
static void
local_notify_route_callback(struct route *route, void *closure)
{
local_notify_route(route, LOCAL_ADD);
}
void void
local_notify_all() local_notify_all()
{ {
...@@ -242,8 +248,7 @@ local_notify_all() ...@@ -242,8 +248,7 @@ local_notify_all()
} }
for(i = 0; i < numxroutes; i++) for(i = 0; i < numxroutes; i++)
local_notify_xroute(&xroutes[i], LOCAL_ADD); local_notify_xroute(&xroutes[i], LOCAL_ADD);
for(i = 0; i < numroutes; i++) for_all_routes(local_notify_route_callback, NULL);
local_notify_route(&routes[i], LOCAL_ADD);
return; return;
fail: fail:
......
...@@ -1082,12 +1082,17 @@ buffer_update(struct interface *ifp, ...@@ -1082,12 +1082,17 @@ buffer_update(struct interface *ifp,
ifp->num_buffered_updates++; ifp->num_buffered_updates++;
} }
void
buffer_update_callback(struct route *route, void *closure)
{
buffer_update((struct interface*)closure,
route->src->prefix, route->src->plen);
}
void void
send_update(struct interface *ifp, int urgent, send_update(struct interface *ifp, int urgent,
const unsigned char *prefix, unsigned char plen) const unsigned char *prefix, unsigned char plen)
{ {
int i;
if(ifp == NULL) { if(ifp == NULL) {
struct interface *ifp_aux; struct interface *ifp_aux;
struct route *route; struct route *route;
...@@ -1118,11 +1123,7 @@ send_update(struct interface *ifp, int urgent, ...@@ -1118,11 +1123,7 @@ send_update(struct interface *ifp, int urgent,
send_self_update(ifp); send_self_update(ifp);
if(!parasitic) { if(!parasitic) {
debugf("Sending update to %s for any.\n", ifp->name); debugf("Sending update to %s for any.\n", ifp->name);
for(i = 0; i < numroutes; i++) for_all_installed_routes(buffer_update_callback, ifp);
if(routes[i].installed)
buffer_update(ifp,
routes[i].src->prefix,
routes[i].src->plen);
} }
} }
set_timeout(&ifp->update_timeout, ifp->update_interval); set_timeout(&ifp->update_timeout, ifp->update_interval);
......
/* /*
Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright (c) 2007-2011 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
...@@ -40,39 +40,154 @@ THE SOFTWARE. ...@@ -40,39 +40,154 @@ THE SOFTWARE.
#include "configuration.h" #include "configuration.h"
#include "local.h" #include "local.h"
struct route *routes = NULL; struct route **routes = NULL;
int numroutes = 0, maxroutes = 0; static int route_slots = 0, max_route_slots = 0;
int kernel_metric = 0; int kernel_metric = 0;
int allow_duplicates = -1; int allow_duplicates = -1;
int diversity_kind = DIVERSITY_NONE; int diversity_kind = DIVERSITY_NONE;
int diversity_factor = 256; /* in units of 1/256 */ int diversity_factor = 256; /* in units of 1/256 */
int keep_unfeasible = 0; 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 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 route * struct route *
find_route(const unsigned char *prefix, unsigned char plen, find_route(const unsigned char *prefix, unsigned char plen,
struct neighbour *neigh, const unsigned char *nexthop) struct neighbour *neigh, const unsigned char *nexthop)
{ {
int i; struct route *route;
for(i = 0; i < numroutes; i++) { int i = find_route_slot(prefix, plen, NULL);
if(routes[i].neigh == neigh &&
memcmp(routes[i].nexthop, nexthop, 16) == 0 && if(i < 0)
source_match(routes[i].src, prefix, plen)) return NULL;
return &routes[i];
route = routes[i];
while(route) {
if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0)
return route;
route = route->next;
} }
return NULL; return NULL;
} }
struct route * struct route *
find_installed_route(const unsigned char *prefix, unsigned char plen) find_installed_route(const unsigned char *prefix, unsigned char plen)
{ {
int i; int i = find_route_slot(prefix, plen, NULL);
for(i = 0; i < numroutes; i++) {
if(routes[i].installed && source_match(routes[i].src, prefix, plen)) if(i >= 0 && routes[i]->installed)
return &routes[i]; return routes[i];
}
return NULL; return NULL;
} }
static int
resize_route_table(int new_slots)
{
struct 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 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 route *
insert_route(struct 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 route*));
route_slots++;
routes[n] = route;
} else {
struct route *r;
r = routes[i];
while(r->next)
r = r->next;
r->next = route;
route->next = NULL;
}
return route;
}
void void
flush_route(struct route *route) flush_route(struct route *route)
{ {
...@@ -81,53 +196,80 @@ flush_route(struct route *route) ...@@ -81,53 +196,80 @@ flush_route(struct route *route)
unsigned oldmetric; unsigned oldmetric;
int lost = 0; int lost = 0;
i = route - routes;
assert(i >= 0 && i < numroutes);
oldmetric = route_metric(route); oldmetric = route_metric(route);
src = route->src;
if(route->installed) { if(route->installed) {
uninstall_route(route); uninstall_route(route);
lost = 1; lost = 1;
} }
local_notify_route(route, LOCAL_FLUSH); i = find_route_slot(route->src->prefix, route->src->plen, NULL);
assert(i >= 0 && i < route_slots);
src = route->src;
if(i != numroutes - 1) local_notify_route(route, LOCAL_FLUSH);
memcpy(routes + i, routes + numroutes - 1, sizeof(struct route));
numroutes--;
VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct route));
if(numroutes == 0) { if(route == routes[i]) {
free(routes); routes[i] = route->next;
routes = NULL; route->next = NULL;
maxroutes = 0; free(route);
} else if(maxroutes > 8 && numroutes < maxroutes / 4) {
struct route *new_routes; if(routes[i] == NULL) {
int n = maxroutes / 2; if(i < route_slots - 1)
new_routes = realloc(routes, n * sizeof(struct route)); memmove(routes + i + 1, routes + i,
if(new_routes != NULL) { (route_slots - i - 1) * sizeof(struct route*));
routes = new_routes; routes[route_slots - 1] = NULL;
maxroutes = n; 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 route *r = routes[i];
while(r->next != route)
r = r->next;
r->next = route->next;
route->next = NULL;
free(route);
} }
if(lost) if(lost)
route_lost(src, oldmetric); route_lost(src, oldmetric);
} }
void
flush_all_routes()
{
/* Start from the end, to avoid shifting the table. */
int 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--;
}
}
void void
flush_neighbour_routes(struct neighbour *neigh) flush_neighbour_routes(struct neighbour *neigh)
{ {
int i; int i;
i = 0; for(i = 0; i < route_slots; i++) {
while(i < numroutes) { struct route *r;
if(routes[i].neigh == neigh) { again:
flush_route(&routes[i]); r = routes[i];
continue; while(r) {
if(r->neigh == neigh) {
flush_route(r);
goto again;
}
r = r->next;
} }
i++; i++;
} }
...@@ -138,15 +280,63 @@ flush_interface_routes(struct interface *ifp, int v4only) ...@@ -138,15 +280,63 @@ flush_interface_routes(struct interface *ifp, int v4only)
{ {
int i; int i;
i = 0; for(i = 0; i < route_slots; i++) {
while(i < numroutes) { struct route *r;
if(routes[i].neigh->ifp == ifp && again:
(!v4only || v4mapped(routes[i].nexthop))) { r = routes[i];
flush_route(&routes[i]); while(r) {
continue; if(r->neigh->ifp == ifp &&
(!v4only || v4mapped(r->nexthop))) {
flush_route(r);
goto again;
}
r = r->next;
}
}
}
/* Iterate a function over all routes. */
void
for_all_routes(void (*f)(struct route*, void*), void *closure)
{
int i;
for(i = 0; i < route_slots; i++) {
struct route *r = routes[i];
while(r) {
(*f)(r, closure);
r = r->next;
}
}
}
void
for_all_installed_routes(void (*f)(struct route*, void*), void *closure)
{
int i;
for(i = 0; i < route_slots; i++) {
if(routes[i]->installed)
(*f)(routes[i], closure);
}
}
/* Find any route with a given source. This should go when we fix our
data structures. */
struct route *
find_route_with_source(struct source *src)
{
int i;
for(i = 0; i < route_slots; i++) {
struct route *r = routes[i];
while(r) {
if(r->src == src)
return r;
r = r->next;
} }
i++;
} }
return NULL;
} }
static int static int
...@@ -155,10 +345,28 @@ metric_to_kernel(int metric) ...@@ -155,10 +345,28 @@ metric_to_kernel(int metric)
return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; 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 route *route, int i)
{
assert(i >= 0 && i < route_slots);
assert(route->installed);
if(route != routes[i]) {
struct route *r = routes[i];
while(r->next != route)
r = r->next;
r->next = route->next;
route->next = routes[i];
routes[i] = route;
}
}
void void
install_route(struct route *route) install_route(struct route *route)
{ {
int rc; int i, rc;
if(route->installed) if(route->installed)
return; return;
...@@ -167,6 +375,15 @@ install_route(struct route *route) ...@@ -167,6 +375,15 @@ install_route(struct route *route)
fprintf(stderr, "WARNING: installing unfeasible route " fprintf(stderr, "WARNING: installing unfeasible route "
"(this shouldn't happen)."); "(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, rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen,
route->nexthop, route->nexthop,
route->neigh->ifp->ifindex, route->neigh->ifp->ifindex,
...@@ -178,6 +395,8 @@ install_route(struct route *route) ...@@ -178,6 +395,8 @@ install_route(struct route *route)
return; return;
} }
route->installed = 1; route->installed = 1;
move_installed_route(route, i);
local_notify_route(route, LOCAL_CHANGE); local_notify_route(route, LOCAL_CHANGE);
} }
...@@ -233,7 +452,8 @@ switch_routes(struct route *old, struct route *new) ...@@ -233,7 +452,8 @@ switch_routes(struct route *old, struct route *new)
old->installed = 0; old->installed = 0;
new->installed = 1; new->installed = 1;
move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen,
NULL));
local_notify_route(old, LOCAL_CHANGE); local_notify_route(old, LOCAL_CHANGE);
local_notify_route(new, LOCAL_CHANGE); local_notify_route(new, LOCAL_CHANGE);
} }
...@@ -355,21 +575,22 @@ struct route * ...@@ -355,21 +575,22 @@ struct route *
find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, find_best_route(const unsigned char *prefix, unsigned char plen, int feasible,
struct neighbour *exclude) struct neighbour *exclude)
{ {
struct route *route = NULL; struct route *route, *r;
int i; int i = find_route_slot(prefix, plen, NULL);
if(i < 0)
return NULL;
route = routes[i];
for(i = 0; i < numroutes; i++) { r = route->next;
if(!source_match(routes[i].src, prefix, plen)) while(r) {
continue; if(!route_expired(r) &&
if(route_expired(&routes[i])) (!feasible || route_feasible(r)) &&
continue; (!exclude || r->neigh != exclude) &&
if(feasible && !route_feasible(&routes[i])) (route_metric(r) < route_metric(route)))
continue; route = r;
if(exclude && routes[i].neigh == exclude) r = r->next;
continue;
if(route && route_metric(route) <= route_metric(&routes[i]))
continue;
route = &routes[i];
} }
return route; return route;
} }
...@@ -408,11 +629,13 @@ update_neighbour_metric(struct neighbour *neigh, int changed) ...@@ -408,11 +629,13 @@ update_neighbour_metric(struct neighbour *neigh, int changed)
if(changed) { if(changed) {
int i; int i;
i = 0; for(i = 0; i < route_slots; i++) {
while(i < numroutes) { struct route *r = routes[i];
if(routes[i].neigh == neigh) while(r) {
update_route_metric(&routes[i]); if(r->neigh == neigh)
i++; update_route_metric(r);
r = r->next;
}
} }
} }
...@@ -425,10 +648,13 @@ update_interface_metric(struct interface *ifp) ...@@ -425,10 +648,13 @@ update_interface_metric(struct interface *ifp)
int i; int i;
i = 0; i = 0;
while(i < numroutes) { for(i = 0; i < route_slots; i++) {
if(routes[i].neigh->ifp == ifp) struct route *r = routes[i];
update_route_metric(&routes[i]); while(r) {
i++; if(r->neigh->ifp == ifp)
update_route_metric(r);
r = r->next;
}
} }
} }
...@@ -508,6 +734,8 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, ...@@ -508,6 +734,8 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
send_unfeasible_request(neigh, route->installed && route_old(route), send_unfeasible_request(neigh, route->installed && route_old(route),
seqno, metric, src); seqno, metric, src);
} else { } else {
struct route *new_route;
if(refmetric >= INFINITY) if(refmetric >= INFINITY)
/* Somebody's retracting a route we never saw. */ /* Somebody's retracting a route we never saw. */
return NULL; return NULL;
...@@ -517,18 +745,12 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, ...@@ -517,18 +745,12 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
return NULL; return NULL;
} }
if(numroutes >= maxroutes) { route = malloc(sizeof(struct route));
struct route *new_routes; if(route == NULL) {
int n = maxroutes < 1 ? 8 : 2 * maxroutes; perror("malloc(route)");
new_routes = routes == NULL ? return NULL;
malloc(n * sizeof(struct route)) :
realloc(routes, n * sizeof(struct route));
if(new_routes == NULL)
return NULL;
maxroutes = n;
routes = new_routes;
} }
route = &routes[numroutes];
route->src = src; route->src = src;
route->refmetric = refmetric; route->refmetric = refmetric;
route->cost = neighbour_cost(neigh); route->cost = neighbour_cost(neigh);
...@@ -543,7 +765,13 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, ...@@ -543,7 +765,13 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
if(channels_len > 0) if(channels_len > 0)
memcpy(&route->channels, channels, memcpy(&route->channels, channels,
MIN(channels_len, DIVERSITY_HOPS)); MIN(channels_len, DIVERSITY_HOPS));
numroutes++; route->next = NULL;
new_route = insert_route(route);
if(new_route == NULL) {
fprintf(stderr, "Couldn't insert route.\n");
free(route);
return NULL;
}
local_notify_route(route, LOCAL_ADD); local_notify_route(route, LOCAL_ADD);
consider_route(route); consider_route(route);
} }
...@@ -628,15 +856,18 @@ retract_neighbour_routes(struct neighbour *neigh) ...@@ -628,15 +856,18 @@ retract_neighbour_routes(struct neighbour *neigh)
{ {
int i; int i;
i = 0; for(i = 0; i < route_slots; i++) {
while(i < numroutes) { struct route *r = routes[i];
if(routes[i].neigh == neigh) { while(r) {
if(routes[i].refmetric != INFINITY) { if(r->neigh == neigh) {
unsigned short oldmetric = route_metric(&routes[i]); if(r->refmetric != INFINITY) {
retract_route(&routes[i]); unsigned short oldmetric = route_metric(r);
retract_route(r);
if(oldmetric != INFINITY) if(oldmetric != INFINITY)
route_changed(&routes[i], routes[i].src, oldmetric); route_changed(r, r->src, oldmetric);
}
} }
r = r->next;
} }
i++; i++;
} }
...@@ -743,30 +974,35 @@ route_lost(struct source *src, unsigned oldmetric) ...@@ -743,30 +974,35 @@ route_lost(struct source *src, unsigned oldmetric)
} }
} }
/* This is called periodically to flush old routes. It will also send
requests for routes that are about to expire. */
void void
expire_routes(void) expire_routes(void)
{ {
struct route *r;
int i; int i;
debugf("Expiring old routes.\n"); debugf("Expiring old routes.\n");
i = 0; for(i = 0; i < route_slots; i++) {
while(i < numroutes) { again:
struct route *route = &routes[i]; r = routes[i];
while(r) {
if(route->time > now.tv_sec || /* clock stepped */ /* Protect against clock being stepped. */
route_old(route)) { if(r->time > now.tv_sec || route_old(r)) {
flush_route(route); flush_route(r);
continue; goto again;
} }
update_route_metric(route); update_route_metric(r);
if(route->installed && route->refmetric < INFINITY) { if(r->installed && r->refmetric < INFINITY) {
if(route_old(route)) if(route_old(r))
send_unicast_request(route->neigh, /* Route about to expire, send a request. */
route->src->prefix, route->src->plen); send_unicast_request(r->neigh,
r->src->prefix, r->src->plen);
}
r = r->next;
} }
i++;
} }
} }
/* /*
Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright (c) 2007-2011 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
...@@ -39,10 +39,10 @@ struct route { ...@@ -39,10 +39,10 @@ struct route {
unsigned short hold_time; /* in seconds */ unsigned short hold_time; /* in seconds */
short installed; short installed;
unsigned char channels[DIVERSITY_HOPS]; unsigned char channels[DIVERSITY_HOPS];
struct route *next;
}; };
extern struct route *routes; extern struct route **routes;
extern int numroutes, maxroutes;
extern int kernel_metric, allow_duplicates; extern int kernel_metric, allow_duplicates;
extern int diversity_kind, diversity_factor; extern int diversity_kind, diversity_factor;
extern int keep_unfeasible; extern int keep_unfeasible;
...@@ -70,8 +70,12 @@ struct route *find_route(const unsigned char *prefix, unsigned char plen, ...@@ -70,8 +70,12 @@ struct route *find_route(const unsigned char *prefix, unsigned char plen,
struct route *find_installed_route(const unsigned char *prefix, struct route *find_installed_route(const unsigned char *prefix,
unsigned char plen); unsigned char plen);
void flush_route(struct route *route); void flush_route(struct route *route);
void flush_all_routes(void);
void flush_neighbour_routes(struct neighbour *neigh); void flush_neighbour_routes(struct neighbour *neigh);
void flush_interface_routes(struct interface *ifp, int v4only); void flush_interface_routes(struct interface *ifp, int v4only);
void for_all_routes(void (*f)(struct route*, void*), void *closure);
void for_all_installed_routes(void (*f)(struct route*, void*), void *closure);
struct route *find_route_with_source(struct source *src);
void install_route(struct route *route); void install_route(struct route *route);
void uninstall_route(struct route *route); void uninstall_route(struct route *route);
void switch_route(struct route *old, struct route *new); void switch_route(struct route *old, struct route *new);
......
...@@ -46,8 +46,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, ...@@ -46,8 +46,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
continue; continue;
if(memcmp(src->id, id, 8) != 0) if(memcmp(src->id, id, 8) != 0)
continue; continue;
if(source_match(src, p, plen)) if(src->plen != plen)
return src; continue;
if(memcmp(src->prefix, p, 16) == 0)
return src;
} }
if(!create) if(!create)
...@@ -73,15 +75,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, ...@@ -73,15 +75,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
int int
flush_source(struct source *src) flush_source(struct source *src)
{ {
int i;
/* This is absolutely horrible -- it makes expire_sources quadratic. /* This is absolutely horrible -- it makes expire_sources quadratic.
But it's not called very often. */ But it's not called very often. */
if(find_route_with_source(src))
for(i = 0; i < numroutes; i++) { return 0;
if(routes[i].src == src)
return 0;
}
if(srcs == src) { if(srcs == src) {
srcs = src->next; srcs = src->next;
...@@ -96,19 +93,6 @@ flush_source(struct source *src) ...@@ -96,19 +93,6 @@ flush_source(struct source *src)
return 1; return 1;
} }
int
source_match(struct source *src,
const unsigned char *p, unsigned char plen)
{
if(src->plen != plen)
return 0;
if(src->prefix[15] != p[15])
return 0;
if(memcmp(src->prefix, p, 16) != 0)
return 0;
return 1;
}
void void
update_source(struct source *src, update_source(struct source *src,
unsigned short seqno, unsigned short metric) unsigned short seqno, unsigned short metric)
......
...@@ -32,9 +32,6 @@ struct source { ...@@ -32,9 +32,6 @@ struct source {
time_t time; time_t time;
}; };
int source_match(struct source *src,
const unsigned char *p, unsigned char plen)
ATTRIBUTE ((pure));
struct source *find_source(const unsigned char *id, struct source *find_source(const unsigned char *id,
const unsigned char *p, const unsigned char *p,
unsigned char plen, unsigned char plen,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment