summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2012-08-14 16:25:22 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2012-08-14 16:46:43 +0200
commit094d2bdb79e1ffa0a02761fd651aa0f0b6b0c585 (patch)
treef7cb65c540403ed152677dde3b803c3dd117d8e5 /nest
parentd760229ab897fa1bf1fd0fe7019cc2431d21a1cc (diff)
Implements ADD-PATH extension for BGP.
Allows to send and receive multiple routes for one network by one BGP session. Also contains necessary core changes to support this (routing tables accepting several routes for one network from one protocol). It needs some more cleanup before merging to the master branch.
Diffstat (limited to 'nest')
-rw-r--r--nest/proto.c13
-rw-r--r--nest/protocol.h3
-rw-r--r--nest/route.h25
-rw-r--r--nest/rt-attr.c194
-rw-r--r--nest/rt-dev.c26
-rw-r--r--nest/rt-table.c111
6 files changed, 307 insertions, 65 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 53d3f1a2..399c02e3 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -219,6 +219,7 @@ proto_free_ahooks(struct proto *p)
p->main_ahook = NULL;
}
+
/**
* proto_config_new - create a new protocol configuration
* @pr: protocol the configuration will belong to
@@ -791,11 +792,15 @@ proto_schedule_feed(struct proto *p, int initial)
/* Connect protocol to routing table */
if (initial && !p->proto->multitable)
{
+ p->main_source = rt_get_source(p, 0);
+ rt_lock_source(p->main_source);
+
p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
p->main_ahook->in_filter = p->cf->in_filter;
p->main_ahook->out_filter = p->cf->out_filter;
p->main_ahook->in_limit = p->cf->in_limit;
p->main_ahook->out_limit = p->cf->out_limit;
+
proto_reset_limit(p->main_ahook->in_limit);
proto_reset_limit(p->main_ahook->out_limit);
}
@@ -844,6 +849,8 @@ proto_flush_loop(void *unused UNUSED)
return;
}
+ rt_prune_sources();
+
again:
WALK_LIST(p, flush_proto_list)
if (p->flushing)
@@ -1040,6 +1047,12 @@ proto_notify_state(struct proto *p, unsigned ps)
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p);
+ if (p->proto->multitable)
+ {
+ rt_unlock_source(p->main_source);
+ p->main_source = NULL;
+ }
+
neigh_prune(); // FIXME convert neighbors to resource?
rfree(p->pool);
p->pool = NULL;
diff --git a/nest/protocol.h b/nest/protocol.h
index 11fcb164..d80201f3 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -183,7 +183,7 @@ struct proto {
int (*reload_routes)(struct proto *);
/*
- * Routing entry hooks (called only for rte's belonging to this protocol):
+ * Routing entry hooks (called only for routes belonging to this protocol):
*
* rte_recalculate Called at the beginning of the best route selection
* rte_better Compare two rte's and decide which one is better (1=first, 0=second).
@@ -199,6 +199,7 @@ struct proto {
void (*rte_remove)(struct network *, struct rte *);
struct rtable *table; /* Our primary routing table */
+ struct rte_src *main_source; /* Primary route source */
struct announce_hook *main_ahook; /* Primary announcement hook */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */
diff --git a/nest/route.h b/nest/route.h
index 524e69b3..3b65a855 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -237,10 +237,10 @@ void rt_unlock_table(rtable *);
void rt_setup(pool *, rtable *, char *, struct rtable_config *);
static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); }
static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); }
-rte *rte_find(net *net, struct proto *p);
+rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *);
-void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src);
-static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); }
+void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src);
+static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); }
void rte_discard(rtable *tab, rte *old);
void rte_dump(rte *);
void rte_free(rte *);
@@ -286,9 +286,18 @@ struct mpnh {
unsigned char weight;
};
+struct rte_src {
+ struct rte_src *next; /* Hash chain */
+ struct proto *proto; /* Protocol the source is based on */
+ u32 private_id; /* Private ID, assigned by the protocol */
+ u32 global_id; /* Globally unique ID of the source */
+ unsigned uc; /* Use count */
+};
+
+
typedef struct rta {
struct rta *next, **pprev; /* Hash chain */
- struct proto *proto; /* Protocol instance that originally created the route */
+ struct rte_src *src; /* Route source that created the route */
unsigned uc; /* Use count */
byte source; /* Route source (RTS_...) */
byte scope; /* Route scope (SCOPE_... -- see ip.h) */
@@ -403,6 +412,13 @@ typedef struct ea_list {
#define EALF_BISECT 2 /* Use interval bisection for searching */
#define EALF_CACHED 4 /* Attributes belonging to cached rta */
+struct rte_src *rt_find_source(struct proto *p, u32 id);
+struct rte_src *rt_get_source(struct proto *p, u32 id);
+static inline void rt_lock_source(struct rte_src *src) { src->uc++; }
+static inline void rt_unlock_source(struct rte_src *src) { src->uc--; }
+void rt_prune_sources(void);
+
+
eattr *ea_find(ea_list *, unsigned ea);
int ea_get_int(ea_list *, unsigned ea, int def);
void ea_dump(ea_list *);
@@ -419,6 +435,7 @@ static inline int mpnh_same(struct mpnh *x, struct mpnh *y)
void rta_init(void);
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
+static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
void rta__free(rta *r);
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 6aed318b..b2bb152f 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -58,9 +58,194 @@ pool *rta_pool;
static slab *rta_slab;
static slab *mpnh_slab;
+static slab *rte_src_slab;
+
+/* rte source ID bitmap */
+static u32 *src_ids;
+static u32 src_id_size, src_id_used, src_id_pos;
+#define SRC_ID_SIZE_DEF 4
+
+/* rte source hash */
+static struct rte_src **src_table;
+static u32 src_hash_order, src_hash_size, src_hash_count;
+#define SRC_HASH_ORDER_DEF 6
+#define SRC_HASH_ORDER_MAX 18
+#define SRC_HASH_ORDER_MIN 10
struct protocol *attr_class_to_protocol[EAP_MAX];
+
+static void
+rte_src_init(void)
+{
+ rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src));
+
+ src_id_pos = 0;
+ src_id_size = SRC_ID_SIZE_DEF;
+ src_ids = mb_allocz(rta_pool, src_id_size * sizeof(u32));
+
+ /* ID 0 is reserved */
+ src_ids[0] = 1;
+ src_id_used = 1;
+
+ src_hash_count = 0;
+ src_hash_order = SRC_HASH_ORDER_DEF;
+ src_hash_size = 1 << src_hash_order;
+ src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
+}
+
+static inline int u32_cto(unsigned int x) { return ffs(~x) - 1; }
+
+static inline u32
+rte_src_alloc_id(void)
+{
+ int i, j;
+ for (i = src_id_pos; i < src_id_size; i++)
+ if (src_ids[i] != 0xffffffff)
+ goto found;
+
+ /* If we are at least 7/8 full, expand */
+ if (src_id_used > (src_id_size * 28))
+ {
+ src_id_size *= 2;
+ src_ids = mb_realloc(rta_pool, src_ids, src_id_size * sizeof(u32));
+ bzero(src_ids + i, (src_id_size - i) * sizeof(u32));
+ goto found;
+ }
+
+ for (i = 0; i < src_id_pos; i++)
+ if (src_ids[i] != 0xffffffff)
+ goto found;
+
+ ASSERT(0);
+
+ found:
+ ASSERT(i < 0x8000000);
+
+ src_id_pos = i;
+ j = u32_cto(src_ids[i]);
+
+ src_ids[i] |= (1 << j);
+ src_id_used++;
+ return 32 * i + j;
+}
+
+static inline void
+rte_src_free_id(u32 id)
+{
+ int i = id / 32;
+ int j = id % 32;
+
+ ASSERT((i < src_id_size) && (src_ids[i] & (1 << j)));
+ src_ids[i] &= ~(1 << j);
+ src_id_used--;
+}
+
+static inline u32 rte_src_hash(struct proto *p, u32 x, u32 order)
+{ return (x * 2902958171u) >> (32 - order); }
+
+static void
+rte_src_rehash(int step)
+{
+ struct rte_src **old_tab, *src, *src_next;
+ u32 old_size, hash, i;
+
+ old_tab = src_table;
+ old_size = src_hash_size;
+
+ src_hash_order += step;
+ src_hash_size = 1 << src_hash_order;
+ src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
+
+ for (i = 0; i < old_size; i++)
+ for (src = old_tab[i]; src; src = src_next)
+ {
+ src_next = src->next;
+ hash = rte_src_hash(src->proto, src->private_id, src_hash_order);
+ src->next = src_table[hash];
+ src_table[hash] = src;
+ }
+
+ mb_free(old_tab);
+}
+
+struct rte_src *
+rt_find_source(struct proto *p, u32 id)
+{
+ struct rte_src *src;
+ u32 hash = rte_src_hash(p, id, src_hash_order);
+
+ for (src = src_table[hash]; src; src = src->next)
+ if ((src->proto == p) && (src->private_id == id))
+ return src;
+
+ return NULL;
+}
+
+struct rte_src *
+rt_get_source(struct proto *p, u32 id)
+{
+ struct rte_src *src;
+ u32 hash = rte_src_hash(p, id, src_hash_order);
+
+ for (src = src_table[hash]; src; src = src->next)
+ if ((src->proto == p) && (src->private_id == id))
+ return src;
+
+ src = sl_alloc(rte_src_slab);
+ src->proto = p;
+ src->private_id = id;
+ src->global_id = rte_src_alloc_id();
+ src->uc = 0;
+
+ src->next = src_table[hash];
+ src_table[hash] = src;
+
+ src_hash_count++;
+ if ((src_hash_count > src_hash_size) && (src_hash_order < SRC_HASH_ORDER_MAX))
+ rte_src_rehash(1);
+
+ return src;
+}
+
+static inline void
+rt_remove_source(struct rte_src **sp)
+{
+ struct rte_src *src = *sp;
+
+ *sp = src->next;
+ rte_src_free_id(src->global_id);
+ sl_free(rte_src_slab, src);
+ src_hash_count--;
+}
+
+void
+rt_prune_sources(void)
+{
+ struct rte_src **sp;
+ int i;
+
+ for (i = 0; i < src_hash_size; i++)
+ {
+ sp = &src_table[i];
+ while (*sp)
+ {
+ if ((*sp)->uc == 0)
+ rt_remove_source(sp);
+ else
+ sp = &(*sp)->next;
+ }
+ }
+
+ while ((src_hash_count < (src_hash_size / 4)) && (src_hash_order > SRC_HASH_ORDER_MIN))
+ rte_src_rehash(-1);
+}
+
+
+/*
+ * Multipath Next Hop
+ */
+
static inline unsigned int
mpnh_hash(struct mpnh *x)
{
@@ -682,14 +867,14 @@ rta_alloc_hash(void)
static inline unsigned int
rta_hash(rta *a)
{
- return (a->proto->hash_key ^ ipa_hash(a->gw) ^
+ return (((unsigned) a->src) ^ ipa_hash(a->gw) ^
mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
}
static inline int
rta_same(rta *x, rta *y)
{
- return (x->proto == y->proto &&
+ return (x->src == y->src &&
x->source == y->source &&
x->scope == y->scope &&
x->cast == y->cast &&
@@ -786,6 +971,7 @@ rta_lookup(rta *o)
r = rta_copy(o);
r->hash_key = h;
r->aflags = RTAF_CACHED;
+ rt_lock_source(r->src);
rt_lock_hostentry(r->hostentry);
rta_insert(r);
@@ -805,6 +991,7 @@ rta__free(rta *a)
a->next->pprev = a->pprev;
a->aflags = 0; /* Poison the entry */
rt_unlock_hostentry(a->hostentry);
+ rt_unlock_source(a->src);
mpnh_free(a->nexthops);
ea_free(a->eattrs);
sl_free(rta_slab, a);
@@ -827,7 +1014,7 @@ rta_dump(rta *a)
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
debug("p=%s uc=%d %s %s%s%s h=%04x",
- a->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
+ a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
rtd[a->dest], a->hash_key);
if (!(a->aflags & RTAF_CACHED))
debug(" !CACHED");
@@ -895,6 +1082,7 @@ rta_init(void)
rta_slab = sl_new(rta_pool, sizeof(rta));
mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh));
rta_alloc_hash();
+ rte_src_init();
}
/*
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 54cb14ba..7319018f 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -48,29 +48,31 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
DBG("dev_if_notify: device shutdown: prefix not found\n");
return;
}
- rte_update(p->table, n, p, p, NULL);
+ rte_update(p, n, NULL);
}
else if (c & IF_CHANGE_UP)
{
- rta *a, A;
+ rta *a;
net *n;
rte *e;
DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
- bzero(&A, sizeof(A));
- A.proto = p;
- A.source = RTS_DEVICE;
- A.scope = SCOPE_UNIVERSE;
- A.cast = RTC_UNICAST;
- A.dest = RTD_DEVICE;
- A.iface = ad->iface;
- A.eattrs = NULL;
- a = rta_lookup(&A);
+
+ rta a0 = {
+ .src = p->main_source,
+ .source = RTS_DEVICE,
+ .scope = SCOPE_UNIVERSE,
+ .cast = RTC_UNICAST,
+ .dest = RTD_DEVICE,
+ .iface = ad->iface
+ };
+
+ a = rta_lookup(&a0);
n = net_get(p->table, ad->prefix, ad->pxlen);
e = rte_get_temp(a);
e->net = n;
e->pflags = 0;
- rte_update(p->table, n, p, p, e);
+ rte_update(p, n, e);
}
}
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 118f4c25..ecd6e324 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -58,6 +58,14 @@ static void rt_next_hop_update(rtable *tab);
static inline void rt_schedule_gc(rtable *tab);
+static inline struct ea_list *
+make_tmp_attrs(struct rte *rt, struct linpool *pool)
+{
+ struct ea_list *(*mta)(struct rte *rt, struct linpool *pool);
+ mta = rt->attrs->src->proto->make_tmp_attrs;
+ return mta ? mta(rt, rte_update_pool) : NULL;
+}
+
/* Like fib_route(), but skips empty net entries */
static net *
net_route(rtable *tab, ip_addr a, int len)
@@ -88,17 +96,17 @@ rte_init(struct fib_node *N)
/**
* rte_find - find a route
* @net: network node
- * @p: protocol
+ * @src: route source
*
* The rte_find() function returns a route for destination @net
- * which belongs has been defined by protocol @p.
+ * which is from route source @src.
*/
rte *
-rte_find(net *net, struct proto *p)
+rte_find(net *net, struct rte_src *src)
{
rte *e = net->routes;
- while (e && e->attrs->proto != p)
+ while (e && e->attrs->src != src)
e = e->next;
return e;
}
@@ -119,7 +127,7 @@ rte_get_temp(rta *a)
e->attrs = a;
e->flags = 0;
- e->pref = a->proto->preference;
+ e->pref = a->src->proto->preference;
return e;
}
@@ -145,16 +153,16 @@ rte_better(rte *new, rte *old)
return 1;
if (new->pref < old->pref)
return 0;
- if (new->attrs->proto->proto != old->attrs->proto->proto)
+ if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
{
/*
* If the user has configured protocol preferences, so that two different protocols
* have the same preference, try to break the tie by comparing addresses. Not too
* useful, but keeps the ordering of routes unambiguous.
*/
- return new->attrs->proto->proto > old->attrs->proto->proto;
+ return new->attrs->src->proto->proto > old->attrs->src->proto->proto;
}
- if (better = new->attrs->proto->rte_better)
+ if (better = new->attrs->src->proto->rte_better)
return better(new, old);
return 0;
}
@@ -198,8 +206,7 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
/* If called does not care for eattrs, we prepare one internally */
if (!tmpa)
{
- struct proto *src = rt->attrs->proto;
- tmpb = src->make_tmp_attrs ? src->make_tmp_attrs(rt, rte_update_pool) : NULL;
+ tmpb = make_tmp_attrs(rt, rte_update_pool);
tmpa = &tmpb;
}
@@ -536,9 +543,9 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *befo
if (type == RA_OPTIMAL)
{
if (new)
- new->attrs->proto->stats.pref_routes++;
+ new->attrs->src->proto->stats.pref_routes++;
if (old)
- old->attrs->proto->stats.pref_routes--;
+ old->attrs->src->proto->stats.pref_routes--;
if (tab->hostcache)
rt_notify_hostcache(tab, net);
@@ -588,7 +595,7 @@ rte_validate(rte *e)
void
rte_free(rte *e)
{
- if (e->attrs->aflags & RTAF_CACHED)
+ if (rta_is_cached(e->attrs))
rta_free(e->attrs);
sl_free(rte_slab, e);
}
@@ -608,11 +615,11 @@ rte_same(rte *x, rte *y)
x->flags == y->flags &&
x->pflags == y->pflags &&
x->pref == y->pref &&
- (!x->attrs->proto->rte_same || x->attrs->proto->rte_same(x, y));
+ (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y));
}
static void
-rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct proto *src)
+rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct rte_src *src)
{
struct proto *p = ah->proto;
struct rtable *table = ah->table;
@@ -625,7 +632,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
- if (old->attrs->proto == src)
+ if (old->attrs->src == src)
{
/* If there is the same route in the routing table but from
* a different sender, then there are two paths from the
@@ -656,7 +663,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
#ifdef CONFIG_RIP
/* lastmod is used internally by RIP as the last time
when the route was received. */
- if (src->proto == &proto_rip)
+ if (src->proto->proto == &proto_rip)
old->lastmod = now;
#endif
return;
@@ -725,7 +732,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
/* If routes are not sorted, find the best route and move it on
the first position. There are several optimized cases. */
- if (src->rte_recalculate && src->rte_recalculate(table, net, new, old, old_best))
+ if (src->proto->rte_recalculate && src->proto->rte_recalculate(table, net, new, old, old_best))
goto do_recalculate;
if (new && rte_better(new, old_best))
@@ -881,7 +888,7 @@ rte_update_unlock(void)
*/
void
-rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
+rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
{
struct proto *p = ah->proto;
struct proto_stats *stats = ah->stats;
@@ -906,8 +913,8 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop;
}
- if (src->make_tmp_attrs)
- tmpa = src->make_tmp_attrs(new, rte_update_pool);
+
+ tmpa = make_tmp_attrs(new, rte_update_pool);
if (filter)
{
ea_list *old_tmpa = tmpa;
@@ -918,15 +925,25 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop;
}
- if (tmpa != old_tmpa && src->store_tmp_attrs)
- src->store_tmp_attrs(new, tmpa);
+ if (tmpa != old_tmpa && src->proto->store_tmp_attrs)
+ src->proto->store_tmp_attrs(new, tmpa);
}
- if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
+
+ if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
new->attrs = rta_lookup(new->attrs);
new->flags |= REF_COW;
}
else
- stats->imp_withdraws_received++;
+ {
+ stats->imp_withdraws_received++;
+
+ if (!net || !src)
+ {
+ stats->imp_withdraws_ignored++;
+ rte_update_unlock();
+ return;
+ }
+ }
rte_recalculate(ah, net, new, tmpa, src);
rte_update_unlock();
@@ -943,12 +960,10 @@ drop:
static inline void
rte_announce_i(rtable *tab, unsigned type, net *n, rte *new, rte *old)
{
- struct proto *src;
ea_list *tmpa;
rte_update_lock();
- src = new->attrs->proto;
- tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(new, rte_update_pool) : NULL;
+ tmpa = make_tmp_attrs(new, rte_update_pool);
rte_announce(tab, type, n, new, old, NULL, tmpa);
rte_update_unlock();
}
@@ -957,7 +972,7 @@ void
rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during garbage collection */
{
rte_update_lock();
- rte_recalculate(old->sender, old->net, NULL, NULL, old->attrs->proto);
+ rte_recalculate(old->sender, old->net, NULL, NULL, old->attrs->src);
rte_update_unlock();
}
@@ -974,8 +989,8 @@ rte_dump(rte *e)
debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
rta_dump(e->attrs);
- if (e->attrs->proto->proto->dump_attrs)
- e->attrs->proto->proto->dump_attrs(e);
+ if (e->attrs->src->proto->proto->dump_attrs)
+ e->attrs->src->proto->proto->dump_attrs(e);
debug("\n");
}
@@ -1096,7 +1111,10 @@ rt_event(void *ptr)
rt_next_hop_update(tab);
if (tab->gc_scheduled)
- rt_prune_nets(tab);
+ {
+ rt_prune_nets(tab);
+ rt_prune_sources(); // FIXME this should be moved to independent event
+ }
}
void
@@ -1303,8 +1321,8 @@ rt_next_hop_update_net(rtable *tab, net *n)
/* Call a pre-comparison hook */
/* Not really an efficient way to compute this */
- if (e->attrs->proto->rte_recalculate)
- e->attrs->proto->rte_recalculate(tab, n, new, e, NULL);
+ if (e->attrs->src->proto->rte_recalculate)
+ e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL);
if (e != old_best)
rte_free_quick(e);
@@ -1502,11 +1520,10 @@ rt_commit(struct config *new, struct config *old)
static inline void
do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
{
- struct proto *src = e->attrs->proto;
ea_list *tmpa;
rte_update_lock();
- tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(e, rte_update_pool) : NULL;
+ tmpa = make_tmp_attrs(e, rte_update_pool);
if (type == RA_ACCEPTED)
rt_notify_accepted(h, n, e, NULL, NULL, tmpa, p->refeeding ? 2 : 1);
else
@@ -1889,7 +1906,7 @@ rt_update_hostcache(rtable *tab)
}
static struct hostentry *
-rt_find_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
+rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
{
struct hostentry *he;
@@ -1910,9 +1927,10 @@ rt_find_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
void
rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll)
{
- rta_apply_hostentry(a, rt_find_hostentry(tab, *gw, *ll, dep));
+ rta_apply_hostentry(a, rt_get_hostentry(tab, *gw, *ll, dep));
}
+
/*
* CLI commands
*/
@@ -1942,6 +1960,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
rta *a = e->attrs;
int primary = (e->net->routes == e);
int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
+ void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
struct mpnh *nh;
rt_format_via(e, via);
@@ -1950,7 +1969,9 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
bsprintf(from, " from %I", a->from);
else
from[0] = 0;
- if (a->proto->proto->get_route_info || d->verbose)
+
+ get_route_info = a->src->proto->proto->get_route_info;
+ if (get_route_info || d->verbose)
{
/* Need to normalize the extended attributes */
ea_list *t = tmpa;
@@ -1959,11 +1980,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
ea_merge(t, tmpa);
ea_sort(tmpa);
}
- if (a->proto->proto->get_route_info)
- a->proto->proto->get_route_info(e, info, tmpa);
+ if (get_route_info)
+ get_route_info(e, info, tmpa);
else
bsprintf(info, " (%d)", e->pref);
- cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->proto->name,
+ cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->src->proto->name,
tm, from, primary ? (sync_error ? " !" : " *") : "", info);
for (nh = a->nexthops; nh; nh = nh->next)
cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1);
@@ -1985,15 +2006,15 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
for(e=n->routes; e; e=e->next)
{
struct ea_list *tmpa;
- struct proto *p0 = e->attrs->proto;
+ struct rte_src *src = e->attrs->src;
struct proto *p1 = d->export_protocol;
struct proto *p2 = d->show_protocol;
d->rt_counter++;
ee = e;
rte_update_lock(); /* We use the update buffer for filtering */
- tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
+ tmpa = make_tmp_attrs(e, rte_update_pool);
ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
- if (p2 && p2 != p0) ok = 0;
+ if (p2 && p2 != src->proto) ok = 0;
if (ok && d->export_mode)
{
int ic;