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)
usleep(roughly(10000));
gettime(&now);
/* Uninstall and flush all routes. */
while(numroutes > 0) {
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]);
}
/* We need to flush so interface_up won't try to reinstall. */
flush_all_routes();
FOR_ALL_INTERFACES(ifp) {
if(!if_up(ifp))
......@@ -923,6 +918,50 @@ init_signals(void)
#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
dump_tables(FILE *out)
{
......@@ -948,45 +987,7 @@ dump_tables(FILE *out)
format_prefix(xroutes[i].prefix, xroutes[i].plen),
xroutes[i].metric);
}
for(i = 0; i < numroutes; i++) {
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)" : "");
}
for_all_routes(dump_route_callback, out);
fflush(out);
}
......
......@@ -222,6 +222,12 @@ local_notify_route(struct route *route, int kind)
return;
}
static void
local_notify_route_callback(struct route *route, void *closure)
{
local_notify_route(route, LOCAL_ADD);
}
void
local_notify_all()
{
......@@ -242,8 +248,7 @@ local_notify_all()
}
for(i = 0; i < numxroutes; i++)
local_notify_xroute(&xroutes[i], LOCAL_ADD);
for(i = 0; i < numroutes; i++)
local_notify_route(&routes[i], LOCAL_ADD);
for_all_routes(local_notify_route_callback, NULL);
return;
fail:
......
......@@ -1082,12 +1082,17 @@ buffer_update(struct interface *ifp,
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
send_update(struct interface *ifp, int urgent,
const unsigned char *prefix, unsigned char plen)
{
int i;
if(ifp == NULL) {
struct interface *ifp_aux;
struct route *route;
......@@ -1118,11 +1123,7 @@ send_update(struct interface *ifp, int urgent,
send_self_update(ifp);
if(!parasitic) {
debugf("Sending update to %s for any.\n", ifp->name);
for(i = 0; i < numroutes; i++)
if(routes[i].installed)
buffer_update(ifp,
routes[i].src->prefix,
routes[i].src->plen);
for_all_installed_routes(buffer_update_callback, ifp);
}
}
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
of this software and associated documentation files (the "Software"), to deal
......@@ -39,10 +39,10 @@ struct route {
unsigned short hold_time; /* in seconds */
short installed;
unsigned char channels[DIVERSITY_HOPS];
struct route *next;
};
extern struct route *routes;
extern int numroutes, maxroutes;
extern struct route **routes;
extern int kernel_metric, allow_duplicates;
extern int diversity_kind, diversity_factor;
extern int keep_unfeasible;
......@@ -70,8 +70,12 @@ struct route *find_route(const unsigned char *prefix, unsigned char plen,
struct route *find_installed_route(const unsigned char *prefix,
unsigned char plen);
void flush_route(struct route *route);
void flush_all_routes(void);
void flush_neighbour_routes(struct neighbour *neigh);
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 uninstall_route(struct route *route);
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,
continue;
if(memcmp(src->id, id, 8) != 0)
continue;
if(source_match(src, p, plen))
return src;
if(src->plen != plen)
continue;
if(memcmp(src->prefix, p, 16) == 0)
return src;
}
if(!create)
......@@ -73,15 +75,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
int
flush_source(struct source *src)
{
int i;
/* This is absolutely horrible -- it makes expire_sources quadratic.
But it's not called very often. */
for(i = 0; i < numroutes; i++) {
if(routes[i].src == src)
return 0;
}
if(find_route_with_source(src))
return 0;
if(srcs == src) {
srcs = src->next;
......@@ -96,19 +93,6 @@ flush_source(struct source *src)
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
update_source(struct source *src,
unsigned short seqno, unsigned short metric)
......
......@@ -32,9 +32,6 @@ struct source {
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,
const unsigned char *p,
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