summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2013-12-10 22:30:46 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2013-12-10 22:30:46 +0100
commit6601a14831cdd32fc671ebc9dc299d2be427e489 (patch)
tree00b89854e36fbecd17443d09587c7cd80352893f /nest
parent2d0b7e24a52d51904faa8a8e96d68863491c110a (diff)
parent283c7dfada53a6dee6a8a17ecab492ffafd44b66 (diff)
Merge branch 'add-path'
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.c117
6 files changed, 308 insertions, 70 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 5876e5d4..cfa6ff4b 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -218,6 +218,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
@@ -830,6 +831,9 @@ 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;
@@ -837,6 +841,7 @@ proto_schedule_feed(struct proto *p, int initial)
p->main_ahook->in_limit = p->cf->in_limit;
p->main_ahook->out_limit = p->cf->out_limit;
p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered;
+
proto_reset_limit(p->main_ahook->rx_limit);
proto_reset_limit(p->main_ahook->in_limit);
proto_reset_limit(p->main_ahook->out_limit);
@@ -890,6 +895,8 @@ proto_flush_loop(void *unused UNUSED)
return;
}
+ rt_prune_sources();
+
again:
WALK_LIST(p, flush_proto_list)
if (p->flushing)
@@ -1088,6 +1095,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 96923447..b58f9e67 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -187,7 +187,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).
@@ -203,6 +203,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 e0b88551..f00f8b2b 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -251,10 +251,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);
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
void rte_dump(rte *);
@@ -300,9 +300,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) */
@@ -421,6 +430,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 *);
@@ -437,6 +453,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 3f79ee59..0fb7c820 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(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)
{
@@ -681,14 +866,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 &&
@@ -785,6 +970,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);
@@ -804,6 +990,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);
@@ -826,7 +1013,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");
@@ -894,6 +1081,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 4fb5bddb..1a859dac 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -51,29 +51,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 fc554081..8c91ea0a 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;
}
@@ -148,16 +156,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;
}
@@ -201,8 +209,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;
}
@@ -552,9 +559,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);
@@ -605,7 +612,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);
}
@@ -625,13 +632,13 @@ 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 inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
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;
@@ -645,7 +652,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
@@ -681,7 +688,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;
@@ -796,7 +803,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))
@@ -970,7 +977,7 @@ rte_unhide_dummy_routes(net *net, rte **dummy)
*/
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;
@@ -1004,8 +1011,7 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
}
else
{
- if (src->make_tmp_attrs)
- tmpa = src->make_tmp_attrs(new, rte_update_pool);
+ tmpa = make_tmp_attrs(new, rte_update_pool);
if (filter && (filter != FILTER_REJECT))
{
ea_list *old_tmpa = tmpa;
@@ -1020,17 +1026,25 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
new->flags |= REF_FILTERED;
}
- 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;
+ }
+ }
recalc:
rte_hide_dummy_routes(net, &dummy);
@@ -1051,12 +1065,10 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
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();
}
@@ -1065,7 +1077,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();
}
@@ -1082,8 +1094,7 @@ rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter
rte_update_lock();
/* Rest is stripped down export_filter() */
- struct proto *src = rt->attrs->proto;
- ea_list *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, rte_update_pool) : NULL;
+ ea_list *tmpa = make_tmp_attrs(rt, rte_update_pool);
int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0;
if (v == RIC_PROCESS)
v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
@@ -1110,8 +1121,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");
}
@@ -1232,7 +1243,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
@@ -1298,7 +1312,7 @@ again:
rescan:
for (e=n->routes; e; e=e->next)
if (e->sender->proto->flushing ||
- (step && e->attrs->proto->flushing))
+ (step && e->attrs->src->proto->flushing))
{
if (*max_feed <= 0)
{
@@ -1308,7 +1322,7 @@ again:
if (step)
log_rl(&rl_flush, L_WARN "Route %I/%d from %s still in %s after flush",
- n->n.prefix, n->n.pxlen, e->attrs->proto->name, tab->name);
+ n->n.prefix, n->n.pxlen, e->attrs->src->proto->name, tab->name);
rte_discard(tab, e);
(*max_feed)--;
@@ -1452,8 +1466,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);
@@ -1651,11 +1665,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
@@ -2041,7 +2054,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;
@@ -2062,9 +2075,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
*/
@@ -2094,6 +2108,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);
@@ -2102,7 +2117,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;
@@ -2111,11 +2128,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);
@@ -2139,7 +2156,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
continue;
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;
@@ -2148,9 +2165,9 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
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 = 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;