summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/proto.c12
-rw-r--r--nest/protocol.h4
-rw-r--r--nest/rt-attr.c121
-rw-r--r--nest/rt-dev.c2
-rw-r--r--nest/rt-show.c6
-rw-r--r--nest/rt-table.c37
6 files changed, 129 insertions, 53 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 1d480ba2..e64cef28 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -1963,10 +1963,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);
}
@@ -1975,10 +1982,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);
@@ -2005,6 +2010,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 3c823ae1..709d6415 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -60,7 +60,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 */
@@ -128,6 +127,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) */
@@ -342,7 +342,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_loops == 0); }
+{ return (p->active_channels == 0) && (p->active_loops == 0) && (p->sources.uc == 0); }
/*
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index b31bc5cc..b3a4c7a1 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -178,6 +178,8 @@ const char * flowspec_valid_names[FLOWSPEC__MAX] = {
[FLOWSPEC_INVALID] = "invalid",
};
+DOMAIN(attrs) attrs_domain;
+
pool *rta_pool;
static slab *rte_src_slab;
@@ -187,16 +189,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 struct rte_src **rte_src_global;
static uint rte_src_global_max = SRC_ID_INIT_SIZE;
@@ -207,34 +207,44 @@ rte_src_init(void)
rte_src_global = mb_allocz(rta_pool, sizeof(struct rte_src *) * rte_src_global_max);
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);
+
if (src->global_id >= rte_src_global_max)
{
rte_src_global = mb_realloc(rte_src_global, sizeof(struct rte_src *) * (rte_src_global_max *= 2));
@@ -243,6 +253,7 @@ rt_get_source(struct proto *p, u32 id)
}
rte_src_global[src->global_id] = src;
+ RTA_UNLOCK;
return src;
}
@@ -256,23 +267,89 @@ rt_find_source_global(u32 id)
return rte_src_global[id];
}
+static inline void
+rt_done_sources(struct rte_owner *o)
+{
+ 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)
+ synchronize_rcu();
+
+ if (uc == 0)
{
- HASH_DO_REMOVE(src_hash, RSH, sp);
+ o->uc--;
+
+ HASH_DO_REMOVE(o->hash, RSH, sp);
+
+ RTA_LOCK;
+ rte_src_global[src->global_id] = NULL;
idm_free(&src_ids, src->global_id);
sl_free(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
@@ -1466,6 +1543,8 @@ ea_show_list(struct cli *c, ea_list *eal)
void
rta_init(void)
{
+ attrs_domain = DOMAIN_NEW(attrs, "Attributes");
+
rta_pool = rp_new(&root_pool, "Attributes");
rta_alloc_hash();
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 7f45985f..4199e17c 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)
{
@@ -95,6 +96,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 b784bf83..17400029 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -58,7 +58,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)
a = ea_normalize(a, 0);
- 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
@@ -74,7 +74,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia,
net_is_flow(e->net) ? flowspec_valid_name(flowspec_valid) : had ? "recursive" : rta_dest_name(dest),
- e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
+ e->src->owner->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
if (d->verbose)
{
@@ -178,7 +178,7 @@ rt_show_net(struct rt_show_data *d, const net_addr *n, rte **feed, uint count)
}
}
- 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, 0) > F_ACCEPT)
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 15dbc371..b8f0e61d 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -673,16 +673,16 @@ rte_better(rte *new, rte *old)
return 1;
if (np < op)
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;
}
@@ -698,10 +698,10 @@ rte_mergable(rte *pri, rte *sec)
if (rt_get_preference(pri) != rt_get_preference(sec))
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;
@@ -1596,10 +1596,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_stored->rte))
@@ -1675,8 +1675,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))
@@ -2876,8 +2876,6 @@ again:
}
}
- rt_prune_sources();
-
uint flushed_channels = 0;
/* Close flushed channels */
@@ -3048,7 +3046,6 @@ rt_export_cleanup(rtable *tab)
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 || (first->seq >= ih->flush_seq))
@@ -3058,19 +3055,11 @@ done:;
rem_node(&ih->n);
mb_free(ih);
rt_unlock_table(tab);
- imports_stopped = 1;
}
if (tab->export_used)
ev_schedule(tab->rt_event);
- if (imports_stopped)
- {
- if (config->table_debug)
- log(L_TRACE "%s: Sources pruning routine requested", tab->name);
-
- rt_prune_sources();
- }
if (EMPTY_LIST(tab->exporter.pending) && tm_active(tab->exporter.export_timer))
tm_stop(tab->exporter.export_timer);
@@ -3554,8 +3543,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,
@@ -4170,8 +4159,8 @@ rt_get_igp_metric(const rte *rt)
if (rt_get_source_attr(rt) == 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;
}