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);
......
This diff is collapsed.
/* /*
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