Commit df7c427d authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Add reference counting to the source table.

This avoids the quadratic behaviour of expire_sources.
parent 5a3400fc
...@@ -237,13 +237,17 @@ flush_route(struct route *route) ...@@ -237,13 +237,17 @@ flush_route(struct route *route)
if(lost) if(lost)
route_lost(src, oldmetric); route_lost(src, oldmetric);
release_source(src);
} }
void void
flush_all_routes() flush_all_routes()
{ {
int i;
/* Start from the end, to avoid shifting the table. */ /* Start from the end, to avoid shifting the table. */
int i = route_slots - 1; i = route_slots - 1;
while(i >= 0) { while(i >= 0) {
while(i < route_slots) { while(i < route_slots) {
/* Uninstall first, to avoid calling route_lost. */ /* Uninstall first, to avoid calling route_lost. */
...@@ -253,6 +257,8 @@ flush_all_routes() ...@@ -253,6 +257,8 @@ flush_all_routes()
} }
i--; i--;
} }
check_sources_released();
} }
void void
...@@ -326,24 +332,6 @@ for_all_installed_routes(void (*f)(struct route*, void*), void *closure) ...@@ -326,24 +332,6 @@ for_all_installed_routes(void (*f)(struct route*, void*), void *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;
}
}
return NULL;
}
static int static int
metric_to_kernel(int metric) metric_to_kernel(int metric)
{ {
...@@ -723,7 +711,7 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, ...@@ -723,7 +711,7 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
} }
} }
route->src = src; route->src = retain_source(src);
if((feasible || keep_unfeasible) && refmetric < INFINITY) if((feasible || keep_unfeasible) && refmetric < INFINITY)
route->time = now.tv_sec; route->time = now.tv_sec;
route->seqno = seqno; route->seqno = seqno;
...@@ -738,6 +726,7 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, ...@@ -738,6 +726,7 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
if(!feasible) if(!feasible)
send_unfeasible_request(neigh, route->installed && route_old(route), send_unfeasible_request(neigh, route->installed && route_old(route),
seqno, metric, src); seqno, metric, src);
release_source(oldsrc);
} else { } else {
struct route *new_route; struct route *new_route;
...@@ -756,7 +745,7 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, ...@@ -756,7 +745,7 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
return NULL; return NULL;
} }
route->src = src; route->src = retain_source(src);
route->refmetric = refmetric; route->refmetric = refmetric;
route->cost = neighbour_cost(neigh); route->cost = neighbour_cost(neigh);
route->add_metric = add_metric; route->add_metric = add_metric;
......
...@@ -75,7 +75,6 @@ void flush_neighbour_routes(struct neighbour *neigh); ...@@ -75,7 +75,6 @@ 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_routes(void (*f)(struct route*, void*), void *closure);
void for_all_installed_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);
......
...@@ -24,6 +24,7 @@ THE SOFTWARE. ...@@ -24,6 +24,7 @@ THE SOFTWARE.
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
#include <assert.h>
#include "babeld.h" #include "babeld.h"
#include "util.h" #include "util.h"
...@@ -67,17 +68,32 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, ...@@ -67,17 +68,32 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
src->seqno = seqno; src->seqno = seqno;
src->metric = INFINITY; src->metric = INFINITY;
src->time = now.tv_sec; src->time = now.tv_sec;
src->route_count = 0;
src->next = srcs; src->next = srcs;
srcs = src; srcs = src;
return src; return src;
} }
struct source *
retain_source(struct source *src)
{
assert(src->route_count < 0xffff);
src->route_count++;
return src;
}
void
release_source(struct source *src)
{
assert(src->route_count > 0);
src->route_count--;
}
int int
flush_source(struct source *src) flush_source(struct source *src)
{ {
/* This is absolutely horrible -- it makes expire_sources quadratic. if(src->route_count > 0)
But it's not called very often. */ /* The source is in use by a route. */
if(find_route_with_source(src))
return 0; return 0;
if(srcs == src) { if(srcs == src) {
...@@ -128,3 +144,17 @@ expire_sources() ...@@ -128,3 +144,17 @@ expire_sources()
src = src->next; src = src->next;
} }
} }
void
check_sources_released(void)
{
struct source *src;
for(src = srcs; src; src = src->next) {
if(src->route_count != 0)
fprintf(stderr, "Warning: source %s %s has refcount %d.\n",
format_eui64(src->id),
format_prefix(src->prefix, src->plen),
(int)src->route_count);
}
}
...@@ -29,6 +29,7 @@ struct source { ...@@ -29,6 +29,7 @@ struct source {
unsigned char plen; unsigned char plen;
unsigned short seqno; unsigned short seqno;
unsigned short metric; unsigned short metric;
unsigned short route_count;
time_t time; time_t time;
}; };
...@@ -36,7 +37,10 @@ struct source *find_source(const unsigned char *id, ...@@ -36,7 +37,10 @@ struct source *find_source(const unsigned char *id,
const unsigned char *p, const unsigned char *p,
unsigned char plen, unsigned char plen,
int create, unsigned short seqno); int create, unsigned short seqno);
struct source *retain_source(struct source *src);
void release_source(struct source *src);
int flush_source(struct source *src); int flush_source(struct source *src);
void update_source(struct source *src, void update_source(struct source *src,
unsigned short seqno, unsigned short metric); unsigned short seqno, unsigned short metric);
void expire_sources(void); void expire_sources(void);
void check_sources_released(void);
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