summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/f-inst.c5
-rw-r--r--lib/locking.h1
-rw-r--r--nest/proto.c12
-rw-r--r--nest/protocol.h4
-rw-r--r--nest/route.h62
-rw-r--r--nest/rt-attr.c123
-rw-r--r--nest/rt-dev.c2
-rw-r--r--nest/rt-show.c6
-rw-r--r--nest/rt-table.c37
-rw-r--r--proto/babel/babel.c16
-rw-r--r--proto/bgp/attrs.c20
-rw-r--r--proto/bgp/bgp.c15
-rw-r--r--proto/bgp/bgp.h7
-rw-r--r--proto/bgp/packets.c5
-rw-r--r--proto/mrt/mrt.c4
-rw-r--r--proto/ospf/ospf.c13
-rw-r--r--proto/ospf/ospf.h2
-rw-r--r--proto/pipe/pipe.c2
-rw-r--r--proto/rip/rip.c25
-rw-r--r--proto/static/static.c27
-rw-r--r--sysdep/unix/krt.c5
21 files changed, 289 insertions, 104 deletions
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 00e22383..706eb684 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -526,7 +526,7 @@
case SA_FROM: RESULT(sa.f_type, ip, rta->from); break;
case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break;
case SA_NET: RESULT(sa.f_type, net, fs->rte->net); break;
- case SA_PROTO: RESULT(sa.f_type, s, fs->rte->src->proto->name); break;
+ case SA_PROTO: RESULT(sa.f_type, s, fs->rte->src->owner->name); break;
case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break;
case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break;
case SA_DEST: RESULT(sa.f_type, i, rta->dest); break;
@@ -562,7 +562,8 @@
{
ip_addr ip = v1.val.ip;
struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
- neighbor *n = neigh_find(fs->rte->src->proto, ip, ifa, 0);
+ /* XXX this code supposes that every owner is a protocol XXX */
+ neighbor *n = neigh_find(SKIP_BACK(struct proto, sources, fs->rte->src->owner), ip, ifa, 0);
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
diff --git a/lib/locking.h b/lib/locking.h
index 0cbdead8..0a69f50f 100644
--- a/lib/locking.h
+++ b/lib/locking.h
@@ -16,6 +16,7 @@ struct lock_order {
struct domain_generic *the_bird;
struct domain_generic *proto;
struct domain_generic *rtable;
+ struct domain_generic *attrs;
struct domain_generic *cork;
struct domain_generic *event;
};
diff --git a/nest/proto.c b/nest/proto.c
index f8e1ba31..930fad1d 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -2329,10 +2329,17 @@ channel_reset_limit(struct channel *c, struct limit *l, int dir)
c->limit_active &= ~(1 << dir);
}
+static struct rte_owner_class default_rte_owner_class;
+
static inline void
proto_do_start(struct proto *p)
{
p->active = 1;
+
+ rt_init_sources(&p->sources, p->name, proto_event_list(p));
+ if (!p->sources.class)
+ p->sources.class = &default_rte_owner_class;
+
if (!p->cf->late_if_feed)
if_feed_baby(p);
}
@@ -2341,10 +2348,8 @@ static void
proto_do_up(struct proto *p)
{
if (!p->main_source)
- {
p->main_source = rt_get_source(p, 0);
- rt_lock_source(p->main_source);
- }
+ // Locked automaticaly
proto_start_channels(p);
@@ -2371,6 +2376,7 @@ proto_do_stop(struct proto *p)
}
proto_stop_channels(p);
+ rt_destroy_sources(&p->sources, p->event);
p->do_stop = 1;
proto_send_event(p);
diff --git a/nest/protocol.h b/nest/protocol.h
index 981ca96a..440297a1 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -78,7 +78,6 @@ struct protocol {
int (*start)(struct proto *); /* Start the instance */
int (*shutdown)(struct proto *); /* Stop the instance */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
- void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
@@ -146,6 +145,7 @@ struct proto {
list channels; /* List of channels to rtables (struct channel) */
struct channel *main_channel; /* Primary channel */
struct rte_src *main_source; /* Primary route source */
+ struct rte_owner sources; /* Route source owner structure */
struct iface *vrf; /* Related VRF instance, NULL if global */
const char *name; /* Name of this instance (== cf->name) */
@@ -360,7 +360,7 @@ void proto_notify_state(struct proto *p, unsigned state);
*/
static inline int proto_is_inactive(struct proto *p)
-{ return (p->active_channels == 0) && (p->active_coroutines == 0); }
+{ return (p->active_channels == 0) && (p->active_coroutines == 0) && (p->sources.uc == 0); }
/*
diff --git a/nest/route.h b/nest/route.h
index 310cea92..a01eff1a 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -15,6 +15,8 @@
#include "lib/bitmap.h"
#include "lib/resource.h"
#include "lib/net.h"
+#include "lib/hash.h"
+#include "lib/event.h"
#include <stdatomic.h>
@@ -579,10 +581,10 @@ struct nexthop {
struct rte_src {
struct rte_src *next; /* Hash chain */
- struct proto *proto; /* Protocol the source is based on */
+ struct rte_owner *owner; /* Route source owner */
u32 private_id; /* Private ID, assigned by the protocol */
u32 global_id; /* Globally unique ID of the source */
- unsigned uc; /* Use count */
+ _Atomic u64 uc; /* Use count */
};
@@ -720,11 +722,57 @@ 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);
+struct rte_owner_class {
+ void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
+ int (*rte_better)(struct rte *, struct rte *);
+ int (*rte_mergable)(struct rte *, struct rte *);
+ u32 (*rte_igp_metric)(struct rte *);
+};
+
+struct rte_owner {
+ struct rte_owner_class *class;
+ int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
+ HASH(struct rte_src) hash;
+ const char *name;
+ u32 hash_key;
+ u32 uc;
+ event_list *list;
+ event *prune;
+ event *stop;
+};
+
+DEFINE_DOMAIN(attrs);
+extern DOMAIN(attrs) attrs_domain;
+
+#define RTA_LOCK LOCK_DOMAIN(attrs, attrs_domain)
+#define RTA_UNLOCK UNLOCK_DOMAIN(attrs, attrs_domain)
+
+#define RTE_SRC_PU_SHIFT 44
+#define RTE_SRC_IN_PROGRESS (1ULL << RTE_SRC_PU_SHIFT)
+
+struct rte_src *rt_get_source_o(struct rte_owner *o, u32 id);
+#define rt_get_source(p, id) rt_get_source_o(&(p)->sources, (id))
+static inline void rt_lock_source(struct rte_src *src)
+{
+ u64 uc = atomic_fetch_add_explicit(&src->uc, 1, memory_order_acq_rel);
+ ASSERT_DIE(uc > 0);
+}
+
+static inline void rt_unlock_source(struct rte_src *src)
+{
+ u64 uc = atomic_fetch_add_explicit(&src->uc, RTE_SRC_IN_PROGRESS, memory_order_acq_rel);
+ u64 pending = uc >> RTE_SRC_PU_SHIFT;
+ uc &= RTE_SRC_IN_PROGRESS - 1;
+
+ ASSERT_DIE(uc > pending);
+ if (uc == pending + 1)
+ ev_send(src->owner->list, src->owner->prune);
+
+ atomic_fetch_sub_explicit(&src->uc, RTE_SRC_IN_PROGRESS + 1, memory_order_acq_rel);
+}
+
+void rt_init_sources(struct rte_owner *, const char *name, event_list *list);
+void rt_destroy_sources(struct rte_owner *, event *);
struct ea_walk_state {
ea_list *eattrs; /* Ccurrent ea_list, initially set by caller */
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 77fd3c3b..f7e33d72 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -85,6 +85,8 @@ const char * rta_dest_names[RTD_MAX] = {
[RTD_PROHIBIT] = "prohibited",
};
+DOMAIN(attrs) attrs_domain;
+
pool *rta_pool;
static slab *rta_slab_[4];
@@ -96,16 +98,14 @@ static struct idm src_ids;
/* rte source hash */
-#define RSH_KEY(n) n->proto, n->private_id
+#define RSH_KEY(n) n->private_id
#define RSH_NEXT(n) n->next
-#define RSH_EQ(p1,n1,p2,n2) p1 == p2 && n1 == n2
-#define RSH_FN(p,n) p->hash_key ^ u32_hash(n)
+#define RSH_EQ(n1,n2) n1 == n2
+#define RSH_FN(n) u32_hash(n)
#define RSH_REHASH rte_src_rehash
#define RSH_PARAMS /2, *2, 1, 1, 8, 20
-#define RSH_INIT_ORDER 6
-
-static HASH(struct rte_src) src_hash;
+#define RSH_INIT_ORDER 2
static void
rte_src_init(void)
@@ -113,55 +113,134 @@ rte_src_init(void)
rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src));
idm_init(&src_ids, rta_pool, SRC_ID_INIT_SIZE);
-
- HASH_INIT(src_hash, rta_pool, RSH_INIT_ORDER);
}
-
HASH_DEFINE_REHASH_FN(RSH, struct rte_src)
-struct rte_src *
-rt_find_source(struct proto *p, u32 id)
+static struct rte_src *
+rt_find_source(struct rte_owner *p, u32 id)
{
- return HASH_FIND(src_hash, RSH, p, id);
+ return HASH_FIND(p->hash, RSH, id);
}
struct rte_src *
-rt_get_source(struct proto *p, u32 id)
+rt_get_source_o(struct rte_owner *p, u32 id)
{
+ if (p->stop)
+ bug("Stopping route owner asked for another source.");
+
struct rte_src *src = rt_find_source(p, id);
if (src)
+ {
+ UNUSED u64 uc = atomic_fetch_add_explicit(&src->uc, 1, memory_order_acq_rel);
return src;
+ }
+ RTA_LOCK;
src = sl_allocz(rte_src_slab);
- src->proto = p;
+ src->owner = p;
src->private_id = id;
src->global_id = idm_alloc(&src_ids);
- src->uc = 0;
- HASH_INSERT2(src_hash, RSH, rta_pool, src);
+ atomic_store_explicit(&src->uc, 1, memory_order_release);
+ p->uc++;
+
+ HASH_INSERT2(p->hash, RSH, rta_pool, src);
+ if (config->table_debug)
+ log(L_TRACE "Allocated new rte_src for %s, ID %uL %uG, have %u sources now",
+ p->name, src->private_id, src->global_id, p->uc);
+
+ RTA_UNLOCK;
return src;
}
+static inline void
+rt_done_sources(struct rte_owner *o)
+{
+ if (o->stop->list)
+ ev_send(o->stop->list, o->stop);
+ else
+ ev_send(o->list, o->stop);
+}
+
void
-rt_prune_sources(void)
+rt_prune_sources(void *data)
{
- HASH_WALK_FILTER(src_hash, next, src, sp)
+ struct rte_owner *o = data;
+
+ HASH_WALK_FILTER(o->hash, next, src, sp)
{
- if (src->uc == 0)
+ u64 uc;
+ while ((uc = atomic_load_explicit(&src->uc, memory_order_acquire)) >> RTE_SRC_PU_SHIFT)
+ ;
+
+ if (uc == 0)
{
- HASH_DO_REMOVE(src_hash, RSH, sp);
+ o->uc--;
+
+ HASH_DO_REMOVE(o->hash, RSH, sp);
+
+ RTA_LOCK;
idm_free(&src_ids, src->global_id);
sl_free(rte_src_slab, src);
+ RTA_UNLOCK;
}
}
HASH_WALK_FILTER_END;
- HASH_MAY_RESIZE_DOWN(src_hash, RSH, rta_pool);
+ RTA_LOCK;
+ HASH_MAY_RESIZE_DOWN(o->hash, RSH, rta_pool);
+
+ if (o->stop && !o->uc)
+ {
+ rfree(o->prune);
+ RTA_UNLOCK;
+
+ if (config->table_debug)
+ log(L_TRACE "All rte_src's for %s pruned, scheduling stop event", o->name);
+
+ rt_done_sources(o);
+ }
+ else
+ RTA_UNLOCK;
}
+void
+rt_init_sources(struct rte_owner *o, const char *name, event_list *list)
+{
+ RTA_LOCK;
+ HASH_INIT(o->hash, rta_pool, RSH_INIT_ORDER);
+ o->hash_key = random_u32();
+ o->uc = 0;
+ o->name = name;
+ o->prune = ev_new_init(rta_pool, rt_prune_sources, o);
+ o->stop = NULL;
+ o->list = list;
+ RTA_UNLOCK;
+}
+
+void
+rt_destroy_sources(struct rte_owner *o, event *done)
+{
+ o->stop = done;
+
+ if (!o->uc)
+ {
+ if (config->table_debug)
+ log(L_TRACE "Source owner %s destroy requested. All rte_src's already pruned, scheduling stop event", o->name);
+
+ RTA_LOCK;
+ rfree(o->prune);
+ RTA_UNLOCK;
+
+ rt_done_sources(o);
+ }
+ else
+ if (config->table_debug)
+ log(L_TRACE "Source owner %s destroy requested. Remaining %u rte_src's to prune.", o->name, o->uc);
+}
/*
* Multipath Next Hop
@@ -1328,6 +1407,8 @@ rta_show(struct cli *c, rta *a)
void
rta_init(void)
{
+ attrs_domain = DOMAIN_NEW(attrs, "Attributes");
+
rta_pool = rp_new(&root_pool, "Attributes");
rta_slab_[0] = sl_new(rta_pool, sizeof(rta));
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 5d1e57b3..c1251675 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -68,6 +68,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
/* Use iface ID as local source ID */
struct rte_src *src = rt_get_source(P, ad->iface->index);
rte_update(c, net, NULL, src);
+ rt_unlock_source(src);
}
else if (flags & IF_CHANGE_UP)
{
@@ -93,6 +94,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
};
rte_update(c, net, &e0, src);
+ rt_unlock_source(src);
}
}
diff --git a/nest/rt-show.c b/nest/rt-show.c
index d942b8e1..8196903d 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -56,7 +56,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
if (d->verbose && !rta_is_cached(a) && a->eattrs)
ea_normalize(a->eattrs);
- get_route_info = e->src->proto->proto->get_route_info;
+ get_route_info = e->src->owner->class ? e->src->owner->class->get_route_info : NULL;
if (get_route_info)
get_route_info(e, info);
else
@@ -66,7 +66,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
rt_show_table(c, d);
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
- e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
+ e->src->owner->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
if (a->dest == RTD_UNICAST)
for (nh = &(a->nh); nh; nh = nh->next)
@@ -211,7 +211,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
}
}
- if (d->show_protocol && (d->show_protocol != e.src->proto))
+ if (d->show_protocol && (&d->show_protocol->sources != e.src->owner))
goto skip;
if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT)
diff --git a/nest/rt-table.c b/nest/rt-table.c
index b4cd0448..c67f5bf8 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -367,16 +367,16 @@ rte_better(rte *new, rte *old)
return 1;
if (new->attrs->pref < old->attrs->pref)
return 0;
- if (new->src->proto->proto != old->src->proto->proto)
+ if (new->src->owner->class != old->src->owner->class)
{
/*
* 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->src->proto->proto > old->src->proto->proto;
+ return new->src->owner->class > old->src->owner->class;
}
- if (better = new->src->proto->rte_better)
+ if (better = new->src->owner->class->rte_better)
return better(new, old);
return 0;
}
@@ -392,10 +392,10 @@ rte_mergable(rte *pri, rte *sec)
if (pri->attrs->pref != sec->attrs->pref)
return 0;
- if (pri->src->proto->proto != sec->src->proto->proto)
+ if (pri->src->owner->class != sec->src->owner->class)
return 0;
- if (mergable = pri->src->proto->rte_mergable)
+ if (mergable = pri->src->owner->class->rte_mergable)
return mergable(pri, sec);
return 0;
@@ -1269,10 +1269,10 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr
{
if (!old->generation && !new->generation)
bug("Two protocols claim to author a route with the same rte_src in table %s: %N %s/%u:%u",
- c->table->name, net->n.addr, old->src->proto->name, old->src->private_id, old->src->global_id);
+ c->table->name, net->n.addr, old->src->owner->name, old->src->private_id, old->src->global_id);
log_rl(&table->rl_pipe, L_ERR "Route source collision in table %s: %N %s/%u:%u",
- c->table->name, net->n.addr, old->src->proto->name, old->src->private_id, old->src->global_id);
+ c->table->name, net->n.addr, old->src->owner->name, old->src->private_id, old->src->global_id);
}
if (new && rte_same(old, new))
@@ -1341,8 +1341,8 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr
/* If routes are not sorted, find the best route and move it on
the first position. There are several optimized cases. */
- if (src->proto->rte_recalculate &&
- src->proto->rte_recalculate(table, net, new_stored ? &new_stored->rte : NULL, old, old_best))
+ if (src->owner->rte_recalculate &&
+ src->owner->rte_recalculate(table, net, new_stored ? &new_stored->rte : NULL, old, old_best))
goto do_recalculate;
if (new_stored && rte_better(&new_stored->rte, old_best))
@@ -2237,8 +2237,6 @@ again:
/* state change 2->0, 3->1 */
tab->prune_state &= 1;
- rt_prune_sources();
-
uint flushed_channels = 0;
/* Close flushed channels */
@@ -2409,7 +2407,6 @@ rt_export_cleanup(void *data)
done:;
struct rt_import_hook *ih; node *x;
- _Bool imports_stopped = 0;
WALK_LIST2_DELSAFE(ih, n, x, tab->imports, n)
if (ih->import_state == TIS_WAITING)
if (!first_export || (first_export->seq >= ih->flush_seq))
@@ -2419,16 +2416,8 @@ done:;
rem_node(&ih->n);
mb_free(ih);
rt_unlock_table(tab);
- imports_stopped = 1;
}
- if (imports_stopped)
- {
- if (config->table_debug)
- log(L_TRACE "%s: Sources pruning routine requested", tab->name);
-
- rt_prune_sources();
- }
if (EMPTY_LIST(tab->pending_exports) && tm_active(tab->export_timer))
tm_stop(tab->export_timer);
@@ -2610,8 +2599,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->rte.src->proto->rte_recalculate)
- e->rte.src->proto->rte_recalculate(tab, n, &new->rte, &e->rte, &old_best->rte);
+ if (e->rte.src->owner->rte_recalculate)
+ e->rte.src->owner->rte_recalculate(tab, n, &new->rte, &e->rte, &old_best->rte);
updates[pos++] = (struct rte_multiupdate) {
.old = e,
@@ -3083,8 +3072,8 @@ rt_get_igp_metric(rte *rt)
if (rt->attrs->source == RTS_DEVICE)
return 0;
- if (rt->src->proto->rte_igp_metric)
- return rt->src->proto->rte_igp_metric(rt);
+ if (rt->src->owner->class->rte_igp_metric)
+ return rt->src->owner->class->rte_igp_metric(rt);
return IGP_METRIC_UNKNOWN;
}
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 03c85b7d..40e85a16 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -2264,7 +2264,7 @@ babel_preexport(struct channel *c, struct rte *new)
{
struct rta *a = new->attrs;
/* Reject our own unreachable routes */
- if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == c->proto))
+ if ((a->dest == RTD_UNREACHABLE) && (new->src->owner == &c->proto->sources))
return -1;
return 0;
@@ -2288,7 +2288,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
uint rt_metric = ea_get_int(new->attrs->eattrs, EA_BABEL_METRIC, 0);
u64 rt_router_id = 0;
- if (new->src->proto == P)
+ if (new->src->owner == &P->sources)
{
rt_seqno = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
eattr *e = ea_find(new->attrs->eattrs, EA_BABEL_ROUTER_ID);
@@ -2372,6 +2372,12 @@ babel_postconfig(struct proto_config *CF)
cf->ip6_channel = ip6 ?: ip6_sadr;
}
+static struct rte_owner_class babel_rte_owner_class = {
+ .get_route_info = babel_get_route_info,
+ .rte_better = babel_rte_better,
+ .rte_igp_metric = babel_rte_igp_metric,
+};
+
static struct proto *
babel_init(struct proto_config *CF)
{
@@ -2385,8 +2391,8 @@ babel_init(struct proto_config *CF)
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
P->preexport = babel_preexport;
- P->rte_better = babel_rte_better;
- P->rte_igp_metric = babel_rte_igp_metric;
+
+ P->sources.class = &babel_rte_owner_class;
return P;
}
@@ -2479,7 +2485,6 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
return 1;
}
-
struct protocol proto_babel = {
.name = "Babel",
.template = "babel%d",
@@ -2494,6 +2499,5 @@ struct protocol proto_babel = {
.start = babel_start,
.shutdown = babel_shutdown,
.reconfigure = babel_reconfigure,
- .get_route_info = babel_get_route_info,
.get_attr = babel_get_attr
};
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 892b26e3..9b9013f9 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1670,9 +1670,8 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
int
bgp_preexport(struct channel *c, rte *e)
{
- struct proto *SRC = e->src->proto;
struct bgp_proto *p = (struct bgp_proto *) (c->proto);
- struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
+ struct bgp_proto *src = bgp_rte_proto(e);
/* Reject our routes */
if (src == p)
@@ -1725,8 +1724,7 @@ bgp_preexport(struct channel *c, rte *e)
static ea_list *
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
{
- struct proto *SRC = e->src->proto;
- struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
+ struct bgp_proto *src = bgp_rte_proto(e);
struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls };
ea_list *attrs = attrs0;
eattr *a;
@@ -1880,7 +1878,7 @@ bgp_get_neighbor(rte *r)
return as;
/* If AS_PATH is not defined, we treat rte as locally originated */
- struct bgp_proto *p = (void *) r->src->proto;
+ struct bgp_proto *p = bgp_rte_proto(r);
return p->cf->confederation ?: p->local_as;
}
@@ -1910,8 +1908,8 @@ rte_stale(rte *r)
int
bgp_rte_better(rte *new, rte *old)
{
- struct bgp_proto *new_bgp = (struct bgp_proto *) new->src->proto;
- struct bgp_proto *old_bgp = (struct bgp_proto *) old->src->proto;
+ struct bgp_proto *new_bgp = bgp_rte_proto(new);
+ struct bgp_proto *old_bgp = bgp_rte_proto(old);
eattr *x, *y;
u32 n, o;
@@ -2055,8 +2053,8 @@ bgp_rte_better(rte *new, rte *old)
int
bgp_rte_mergable(rte *pri, rte *sec)
{
- struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->src->proto;
- struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->src->proto;
+ struct bgp_proto *pri_bgp = bgp_rte_proto(pri);
+ struct bgp_proto *sec_bgp = bgp_rte_proto(sec);
eattr *x, *y;
u32 p, s;
@@ -2137,8 +2135,8 @@ same_group(rte *r, u32 lpref, u32 lasn)
static inline int
use_deterministic_med(struct rte_storage *r)
{
- struct proto *P = r->rte.src->proto;
- return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
+ struct bgp_proto *p = bgp_rte_proto(&r->rte);
+ return p && p->cf->deterministic_med;
}
int
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 5f2e7dfd..dc845550 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -1726,6 +1726,13 @@ done:
return p->p.proto_state;
}
+struct rte_owner_class bgp_rte_owner_class = {
+ .get_route_info = bgp_get_route_info,
+ .rte_better = bgp_rte_better,
+ .rte_mergable = bgp_rte_mergable,
+ .rte_igp_metric = bgp_rte_igp_metric,
+};
+
static struct proto *
bgp_init(struct proto_config *CF)
{
@@ -1739,10 +1746,9 @@ bgp_init(struct proto_config *CF)
P->reload_routes = bgp_reload_routes;
P->feed_begin = bgp_feed_begin;
P->feed_end = bgp_feed_end;
- P->rte_better = bgp_rte_better;
- P->rte_mergable = bgp_rte_mergable;
- P->rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
- P->rte_igp_metric = bgp_rte_igp_metric;
+
+ P->sources.class = &bgp_rte_owner_class;
+ P->sources.rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
p->cf = cf;
p->is_internal = (cf->local_as == cf->remote_as);
@@ -2605,6 +2611,5 @@ struct protocol proto_bgp = {
.copy_config = bgp_copy_config,
.get_status = bgp_get_status,
.get_attr = bgp_get_attr,
- .get_route_info = bgp_get_route_info,
.show_proto_info = bgp_show_proto_info
};
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 342dc023..7cb4df1f 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -523,6 +523,7 @@ rta_resolvable(rta *a)
return a->dest == RTD_UNICAST;
}
+extern struct rte_owner_class bgp_rte_owner_class;
#ifdef LOCAL_DEBUG
#define BGP_FORCE_DEBUG 1
@@ -594,6 +595,12 @@ int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *);
int bgp_total_aigp_metric_(rta *a, u64 *metric, const struct adata **ad);
+static inline struct bgp_proto *bgp_rte_proto(struct rte *rte)
+{
+ return (rte->src->owner->class == &bgp_rte_owner_class) ?
+ SKIP_BACK(struct bgp_proto, p.sources, rte->src->owner) : NULL;
+}
+
#define BGP_AIGP_METRIC 1
#define BGP_AIGP_MAX U64(0xffffffffffffffff)
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 647551e5..d2d5b174 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1339,6 +1339,8 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
{
if (path_id != s->last_id)
{
+ rt_unlock_source(s->last_src);
+
s->last_src = rt_get_source(&s->proto->p, path_id);
s->last_id = path_id;
@@ -2421,6 +2423,7 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
s->last_id = 0;
s->last_src = s->proto->p.main_source;
+ rt_lock_source(s->last_src);
/*
* IPv4 BGP and MP-BGP may be used together in one update, therefore we do not
@@ -2451,6 +2454,8 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
rta_free(s->cached_rta);
s->cached_rta = NULL;
+
+ rt_unlock_source(s->last_src);
}
static void
diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c
index 5da3c7c6..9d78438d 100644
--- a/proto/mrt/mrt.c
+++ b/proto/mrt/mrt.c
@@ -472,9 +472,9 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
#ifdef CONFIG_BGP
/* Find peer index */
- if (r->src->proto->proto == &proto_bgp)
+ struct bgp_proto *p = bgp_rte_proto(r);
+ if (p)
{
- struct bgp_proto *p = (void *) r->src->proto;
struct mrt_peer_entry *n =
HASH_FIND(s->peer_hash, PEER, p->remote_id, p->remote_as, p->remote_ip);
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 22150590..16774df6 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -376,8 +376,8 @@ ospf_init(struct proto_config *CF)
P->reload_routes = ospf_reload_routes;
P->feed_begin = ospf_feed_begin;
P->feed_end = ospf_feed_end;
- P->rte_better = ospf_rte_better;
- P->rte_igp_metric = ospf_rte_igp_metric;
+
+ P->sources.class = &ospf_rte_owner_class;
return P;
}
@@ -488,7 +488,7 @@ ospf_preexport(struct channel *c, rte *e)
struct ospf_area *oa = ospf_main_area(p);
/* Reject our own routes */
- if (e->src->proto == c->proto)
+ if (e->sender == c->in_req.hook)
return -1;
/* Do not export routes to stub areas */
@@ -1517,6 +1517,12 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
}
+struct rte_owner_class ospf_rte_owner_class = {
+ .get_route_info = ospf_get_route_info,
+ .rte_better = ospf_rte_better,
+ .rte_igp_metric = ospf_rte_igp_metric,
+};
+
struct protocol proto_ospf = {
.name = "OSPF",
.template = "ospf%d",
@@ -1532,5 +1538,4 @@ struct protocol proto_ospf = {
.reconfigure = ospf_reconfigure,
.get_status = ospf_get_status,
.get_attr = ospf_get_attr,
- .get_route_info = ospf_get_route_info
};
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 3e704ae8..a5f83e79 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -1007,6 +1007,8 @@ void ospf_sh_state(struct proto *P, int verbose, int reachable);
void ospf_sh_lsadb(struct lsadb_show_data *ld);
+extern struct rte_owner_class ospf_rte_owner_class;
+
/* iface.c */
void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
void ospf_iface_sm(struct ospf_iface *ifa, int event);
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index bbcd8f0d..a30da0e2 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -91,7 +91,7 @@ pipe_preexport(struct channel *c, rte *e)
{
log_rl(&p->rl_gen, L_ERR "Route overpiped (%u hops of %u configured in %s) in table %s: %N %s/%u:%u",
e->generation, max_generation, c->proto->name,
- c->table->name, e->net, e->src->proto->name, e->src->private_id, e->src->global_id);
+ c->table->name, e->net, e->src->owner->name, e->src->private_id, e->src->global_id);
return -1;
}
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 0a9844f3..ee05f058 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -353,7 +353,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, s
en->valid = RIP_ENTRY_VALID;
en->metric = rt_metric;
en->tag = rt_tag;
- en->from = (new->src->proto == P) ? rt_from : NULL;
+ en->from = (new->src->owner == &P->sources) ? rt_from : NULL;
en->iface = new->attrs->nh.iface;
en->next_hop = new->attrs->nh.gw;
}
@@ -1082,11 +1082,20 @@ rip_reload_routes(struct channel *C)
rip_kick_timer(p);
}
+static struct rte_owner_class rip_rte_owner_class;
+
+static inline struct rip_proto *
+rip_rte_proto(struct rte *rte)
+{
+ return (rte->src->owner->class == &rip_rte_owner_class) ?
+ SKIP_BACK(struct rip_proto, p.sources, rte->src->owner) : NULL;
+}
+
static int
rip_rte_better(struct rte *new, struct rte *old)
{
ASSERT_DIE(new->src == old->src);
- struct rip_proto *p = (struct rip_proto *) new->src->proto;
+ struct rip_proto *p = rip_rte_proto(new);
u32 new_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, p->infinity);
u32 old_metric = ea_get_int(old->attrs->eattrs, EA_RIP_METRIC, p->infinity);
@@ -1121,8 +1130,7 @@ rip_init(struct proto_config *CF)
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
P->reload_routes = rip_reload_routes;
- P->rte_better = rip_rte_better;
- P->rte_igp_metric = rip_rte_igp_metric;
+ P->sources.class = &rip_rte_owner_class;
return P;
}
@@ -1197,7 +1205,7 @@ rip_reconfigure(struct proto *P, struct proto_config *CF)
static void
rip_get_route_info(rte *rte, byte *buf)
{
- struct rip_proto *p = (struct rip_proto *) rte->src->proto;
+ struct rip_proto *p = rip_rte_proto(rte);
u32 rt_metric = ea_get_int(rte->attrs->eattrs, EA_RIP_METRIC, p->infinity);
u32 rt_tag = ea_get_int(rte->attrs->eattrs, EA_RIP_TAG, 0);
@@ -1324,6 +1332,12 @@ rip_dump(struct proto *P)
}
+static struct rte_owner_class rip_rte_owner_class = {
+ .get_route_info = rip_get_route_info,
+ .rte_better = rip_rte_better,
+ .rte_igp_metric = rip_rte_igp_metric,
+};
+
struct protocol proto_rip = {
.name = "RIP",
.template = "rip%d",
@@ -1338,6 +1352,5 @@ struct protocol proto_rip = {
.start = rip_start,
.shutdown = rip_shutdown,
.reconfigure = rip_reconfigure,
- .get_route_info = rip_get_route_info,
.get_attr = rip_get_attr
};
diff --git a/proto/static/static.c b/proto/static/static.c
index f8ac9c81..b0c9d640 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -52,11 +52,14 @@ static linpool *static_lp;
static inline struct rte_src * static_get_source(struct static_proto *p, uint i)
{ return i ? rt_get_source(&p->p, i) : p->p.main_source; }
+static inline void static_free_source(struct rte_src *src, uint i)
+{ if (i) rt_unlock_source(src); }
+
static void
static_announce_rte(struct static_proto *p, struct static_route *r)
{
+ struct rte_src *src;
rta *a = allocz(RTA_MAX_SIZE);
- struct rte_src *src = static_get_source(p, r->index);
a->source = RTS_STATIC;
a->scope = SCOPE_UNIVERSE;
a->dest = r->dest;
@@ -103,6 +106,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
return;
/* We skip rta_lookup() here */
+ src = static_get_source(p, r->index);
rte e0 = { .attrs = a, .src = src, .net = r->net, }, *e = &e0;
/* Evaluate the filter */
@@ -110,6 +114,8 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
f_eval_rte(r->cmds, e, static_lp);
rte_update(p->p.main_channel, r->net, e, src);
+ static_free_source(src, r->index);
+
r->state = SRS_CLEAN;
if (r->cmds)
@@ -121,7 +127,9 @@ withdraw:
if (r->state == SRS_DOWN)
return;
+ src = static_get_source(p, r->index);
rte_update(p->p.main_channel, r->net, NULL, src);
+ static_free_source(src, r->index);
r->state = SRS_DOWN;
}
@@ -287,7 +295,11 @@ static void
static_remove_rte(struct static_proto *p, struct static_route *r)
{
if (r->state)
- rte_update(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
+ {
+ struct rte_src *src = static_get_source(p, r->index);
+ rte_update(p->p.main_channel, r->net, NULL, src);
+ static_free_source(src, r->index);
+ }
static_reset_rte(p, r);
}
@@ -444,6 +456,8 @@ static_postconfig(struct proto_config *CF)
static_index_routes(cf);
}
+static struct rte_owner_class static_rte_owner_class;
+
static struct proto *
static_init(struct proto_config *CF)
{
@@ -455,8 +469,7 @@ static_init(struct proto_config *CF)
P->neigh_notify = static_neigh_notify;
P->reload_routes = static_reload_routes;
- P->rte_better = static_rte_better;
- P->rte_mergable = static_rte_mergable;
+ P->sources.class = &static_rte_owner_class;
if (cf->igp_table_ip4)
p->igp_table_ip4 = cf->igp_table_ip4->table;
@@ -757,6 +770,11 @@ static_show(struct proto *P)
static_show_rt(r);
}
+static struct rte_owner_class static_rte_owner_class = {
+ .get_route_info = static_get_route_info,
+ .rte_better = static_rte_better,
+ .rte_mergable = static_rte_mergable,
+};
struct protocol proto_static = {
.name = "Static",
@@ -773,5 +791,4 @@ struct protocol proto_static = {
.shutdown = static_shutdown,
.reconfigure = static_reconfigure,
.copy_config = static_copy_config,
- .get_route_info = static_get_route_info,
};
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 609ee921..5431bebe 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -294,8 +294,9 @@ krt_rte_better(rte *a, rte *b)
static void
krt_learn_rte(struct krt_proto *p, rte *e)
{
- e->src = rt_get_source(&p->p, krt_metric(e));
+ struct rte_src *src = e->src = rt_get_source(&p->p, krt_metric(e));
rte_update(p->p.main_channel, e->net, e, e->src);
+ rt_unlock_source(src);
}
static void
@@ -674,7 +675,7 @@ krt_scan_timer_kick(struct krt_proto *p)
static int
krt_preexport(struct channel *c, rte *e)
{
- if (e->src->proto == c->proto)
+ if (e->src->owner == &c->proto->sources)
return -1;
if (!krt_capable(e))