From 878eeec12bf020c9e7460040d225a929bbbd2bd2 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 29 Sep 2021 16:15:13 +0200 Subject: Routing tables now have their own loops. This basically means that: * there are some more levels of indirection and asynchronicity, mostly in cleanup procedures, requiring correct lock ordering * all the internal table operations (prune, next hop update) are done without blocking the other parts of BIRD * the protocols may get their own loops very soon --- nest/proto.c | 75 +++++++---- nest/protocol.h | 9 +- nest/route.h | 108 ++++++++++------ nest/rt-attr.c | 11 +- nest/rt-show.c | 29 +++-- nest/rt-table.c | 395 +++++++++++++++++++++++++++++++++++++++----------------- 6 files changed, 418 insertions(+), 209 deletions(-) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index 35af3c6c..4ae0cbfd 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -172,7 +172,7 @@ proto_cf_find_channel(struct proto_config *pc, uint net_type) * Returns pointer to channel or NULL */ struct channel * -proto_find_channel_by_table(struct proto *p, struct rtable *t) +proto_find_channel_by_table(struct proto *p, rtable *t) { struct channel *c; @@ -236,7 +236,9 @@ proto_add_channel(struct proto *p, struct channel_config *cf) c->channel = cf->channel; c->proto = p; c->table = cf->table->table; - rt_lock_table(c->table); + + RT_LOCKED(c->table, t) + rt_lock_table(t); c->in_filter = cf->in_filter; c->out_filter = cf->out_filter; @@ -277,7 +279,9 @@ proto_remove_channel(struct proto *p UNUSED, struct channel *c) CD(c, "Removed", c->name); - rt_unlock_table(c->table); + RT_LOCKED(c->table, t) + rt_unlock_table(t); + rem_node(&c->n); mb_free(c); } @@ -391,7 +395,7 @@ static void channel_roa_subscribe_filter(struct channel *c, int dir) { const struct filter *f = dir ? c->in_filter : c->out_filter; - struct rtable *tab; + rtable *tab; int valid = 1, found = 0; if ((f == FILTER_ACCEPT) || (f == FILTER_REJECT)) @@ -560,11 +564,11 @@ channel_check_stopped(struct channel *c) } void -channel_import_stopped(struct rt_import_request *req) +channel_import_stopped(void *_c) { - struct channel *c = SKIP_BACK(struct channel, in_req, req); + struct channel *c = _c; - req->hook = NULL; + c->in_req.hook = NULL; mb_free(c->in_req.name); c->in_req.name = NULL; @@ -661,17 +665,16 @@ channel_aux_stopped(void *data) else c->in_table = NULL; - rfree(cat->tab->rp); - + rfree(cat->tab->priv.rp); mb_free(cat); - return channel_check_stopped(c); + channel_check_stopped(c); } static void -channel_aux_import_stopped(struct rt_import_request *req) +channel_aux_import_stopped(void *_cat) { - struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, push, req); - ASSERT_DIE(cat->tab->delete_event); + struct channel_aux_table *cat = _cat; + cat->push.hook = NULL; } static void @@ -680,24 +683,35 @@ channel_aux_export_stopped(struct rt_export_request *req) struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req); req->hook = NULL; - if (cat->refeed_pending && !cat->tab->delete_event) - { - cat->refeed_pending = 0; - rt_request_export(cat->tab, req); - } - else - ASSERT_DIE(cat->tab->delete_event); + int del; + RT_LOCKED(cat->tab, t) + del = !!t->delete_event; + + if (del) + return; + + ASSERT_DIE(cat->refeed_pending); + cat->refeed_pending = 0; + rt_request_export(cat->tab, req); } static void channel_aux_stop(struct channel_aux_table *cat) { - rt_stop_import(&cat->push, channel_aux_import_stopped); - rt_stop_export(&cat->get, channel_aux_export_stopped); + RT_LOCKED(cat->tab, t) + { + t->delete_event = ev_new_init(t->rp, channel_aux_stopped, cat); + t->delete_event->list = proto_event_list(cat->c->proto); + } - cat->tab->delete_event = ev_new_init(cat->tab->rp, channel_aux_stopped, cat); + cat->push_stopped = (event) { + .hook = channel_aux_import_stopped, + .data = cat, + .list = proto_event_list(cat->c->proto), + }; - rt_unlock_table(cat->tab); + rt_stop_import(&cat->push, &cat->push_stopped); + rt_stop_export(&cat->get, channel_aux_export_stopped); } static void @@ -889,7 +903,6 @@ channel_setup_in_table(struct channel *c, int best) c->in_table->c = c; c->in_table->tab = rt_setup(c->proto->pool, &cat->tab_cf); - rt_lock_table(c->in_table->tab); rt_request_import(c->in_table->tab, &c->in_table->push); rt_request_export(c->in_table->tab, &c->in_table->get); @@ -931,7 +944,6 @@ channel_setup_out_table(struct channel *c) c->out_table->c = c; c->out_table->tab = rt_setup(c->proto->pool, &cat->tab_cf); - rt_lock_table(c->out_table->tab); rt_request_import(c->out_table->tab, &c->out_table->push); rt_request_export(c->out_table->tab, &c->out_table->get); @@ -993,7 +1005,14 @@ channel_do_stop(struct channel *c) /* Stop import */ if (c->in_req.hook) - rt_stop_import(&c->in_req, channel_import_stopped); + { + c->in_stopped = (event) { + .hook = channel_import_stopped, + .data = c, + .list = proto_event_list(c->proto), + }; + rt_stop_import(&c->in_req, &c->in_stopped); + } c->gr_wait = 0; if (c->gr_lock) @@ -2339,7 +2358,7 @@ proto_do_start(struct proto *p) { p->active = 1; - rt_init_sources(&p->sources, p->name, proto_event_list(p)); + rt_init_sources(&p->sources, p->name, proto_work_list(p)); if (!p->sources.class) p->sources.class = &default_rte_owner_class; diff --git a/nest/protocol.h b/nest/protocol.h index 1647fbba..8d077e44 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -18,7 +18,6 @@ struct iface; struct ifa; -struct rtable; struct rte; struct neighbor; struct rta; @@ -207,7 +206,7 @@ struct proto { * rte_remove Called whenever a rte is removed from the routing table. */ - int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *); + int (*rte_recalculate)(rtable *, struct network *, struct rte *, struct rte *, struct rte *); int (*rte_better)(struct rte *, struct rte *); int (*rte_mergable)(struct rte *, struct rte *); void (*rte_insert)(struct network *, struct rte *); @@ -496,7 +495,7 @@ struct channel { const struct channel_class *channel; struct proto *proto; - struct rtable *table; + rtable *table; const struct filter *in_filter; /* Input filter */ const struct filter *out_filter; /* Output filter */ struct bmap export_map; /* Keeps track which routes were really exported */ @@ -556,6 +555,7 @@ struct channel { btime last_state_change; /* Time of last state transition */ struct channel_aux_table *in_table; /* Internal table for received routes */ + struct event in_stopped; /* Import stop callback */ u8 reload_pending; /* Reloading and another reload is scheduled */ u8 refeed_pending; /* Refeeding and another refeed is scheduled */ @@ -570,6 +570,7 @@ struct channel_aux_table { struct channel *c; struct rt_import_request push; struct rt_export_request get; + event push_stopped; rtable *tab; event *stop; u8 refeed_pending; @@ -633,7 +634,7 @@ struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_ty static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc) { return proto_cf_find_channel(pc, pc->net_type); } -struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t); +struct channel *proto_find_channel_by_table(struct proto *p, rtable *t); struct channel *proto_find_channel_by_name(struct proto *p, const char *n); struct channel *proto_add_channel(struct proto *p, struct channel_config *cf); int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf); diff --git a/nest/route.h b/nest/route.h index 683c966e..9417d97d 100644 --- a/nest/route.h +++ b/nest/route.h @@ -146,30 +146,21 @@ void fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src) * It's guaranteed that there is at most one RTE for every (prefix,proto) pair. */ -struct rtable_config { - node n; - char *name; - struct config *config; - struct rtable *table; - struct proto_config *krt_attached; /* Kernel syncer attached to this table */ - uint addr_type; /* Type of address data stored in table (NET_*) */ - int gc_max_ops; /* Maximum number of operations before GC is run */ - int gc_min_time; /* Minimum time between two consecutive GC runs */ - byte sorted; /* Routes of network are sorted according to rte_better() */ - btime min_settle_time; /* Minimum settle time for notifications */ - btime max_settle_time; /* Maximum settle time for notifications */ - btime export_settle_time; /* Delay before exports are announced */ - uint cork_limit; /* Amount of routes to be pending on export to cork imports */ -}; - -typedef struct rtable { - resource r; - node n; /* Node in list of all tables */ +typedef struct rtable_private { +#define RTABLE_PUBLIC \ + resource r; \ + node n; /* Node in list of all tables */ \ + struct birdloop *loop; /* This loop runs the table */ \ + char *name; /* Name of this table */ \ + uint addr_type; /* Type of address data stored in table (NET_*) */ \ + struct rtable_config *config; /* Configuration of this table */ \ + struct event *nhu_event; /* Event to update next hops */ \ + _Atomic byte nhu_state; /* Next Hop Update state */ \ + + RTABLE_PUBLIC; pool *rp; /* Resource pool to allocate everything from, including itself */ struct slab *rte_slab; /* Slab to allocate route objects */ struct fib fib; - char *name; /* Name of this table */ - uint addr_type; /* Type of address data stored in table (NET_*) */ int use_count; /* Number of protocols using this table */ u32 rt_count; /* Number of routes in the table */ @@ -178,18 +169,15 @@ typedef struct rtable { struct hmap id_map; struct hostcache *hostcache; - struct rtable_config *config; /* Configuration of this table */ struct event *prune_event; /* Event to prune abandoned routes */ struct event *ec_event; /* Event to prune finished exports */ struct event *hcu_event; /* Event to update host cache */ - struct event *nhu_event; /* Event to update next hops */ struct event *delete_event; /* Event to delete the table */ btime last_rt_change; /* Last time when route changed */ btime base_settle_time; /* Start time of rtable settling interval */ btime gc_time; /* Time of last GC */ int gc_counter; /* Number of operations since last GC */ byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */ - byte nhu_state; /* Next Hop Update state */ byte cork_active; /* Congestion control activated */ @@ -208,8 +196,35 @@ typedef struct rtable { struct rt_pending_export *first_export; /* First export to announce */ u64 next_export_seq; /* The next export will have this ID */ +} rtable_private; + +typedef union { + struct { RTABLE_PUBLIC }; + rtable_private priv; } rtable; +#define RT_LOCK(tab) ({ birdloop_enter((tab)->loop); &(tab)->priv; }) +#define RT_UNLOCK(tab) birdloop_leave((tab)->loop) +#define RT_PRIV(tab) ({ ASSERT_DIE(birdloop_inside((tab)->loop)); &(tab)->priv; }) + +#define RT_LOCKED(tpub, tpriv) for (rtable_private *tpriv = RT_LOCK(tpub); tpriv; RT_UNLOCK(tpriv), (tpriv = NULL)) + +struct rtable_config { + node n; + char *name; + struct config *config; + rtable *table; + struct proto_config *krt_attached; /* Kernel syncer attached to this table */ + uint addr_type; /* Type of address data stored in table (NET_*) */ + int gc_max_ops; /* Maximum number of operations before GC is run */ + int gc_min_time; /* Minimum time between two consecutive GC runs */ + byte sorted; /* Routes of network are sorted according to rte_better() */ + btime min_settle_time; /* Minimum settle time for notifications */ + btime max_settle_time; /* Maximum settle time for notifications */ + btime export_settle_time; /* Delay before exports are announced */ + uint cork_limit; /* Amount of routes to be pending on export to cork imports */ +}; + struct rt_subscription { node n; rtable *tab; @@ -244,7 +259,7 @@ struct hostentry { ip_addr addr; /* IP address of host, part of key */ ip_addr link; /* (link-local) IP address of host, used as gw if host is directly attached */ - struct rtable *tab; /* Dependent table, part of key */ + rtable *tab; /* Dependent table, part of key */ struct hostentry *next; /* Next in hash chain */ unsigned hash_key; /* Hash key */ unsigned uc; /* Use count */ @@ -324,7 +339,7 @@ struct rt_import_hook { u8 stale_pruned; /* Last prune finished when this value was set at stale_valid */ u8 stale_pruning; /* Last prune started when this value was set at stale_valid */ - void (*stopped)(struct rt_import_request *); /* Stored callback when import is stopped */ + struct event *stopped; /* Event to run when import is stopped */ }; struct rt_pending_export { @@ -405,7 +420,7 @@ extern struct event_cork rt_cork; void rt_request_import(rtable *tab, struct rt_import_request *req); void rt_request_export(rtable *tab, struct rt_export_request *req); -void rt_stop_import(struct rt_import_request *, void (*stopped)(struct rt_import_request *)); +void rt_stop_import(struct rt_import_request *, struct event *stopped); void rt_stop_export(struct rt_export_request *, void (*stopped)(struct rt_export_request *)); const char *rt_import_state_name(u8 state); @@ -480,27 +495,27 @@ struct config; void rt_init(void); void rt_preconfig(struct config *); void rt_commit(struct config *new, struct config *old); -void rt_lock_table(rtable *); -void rt_unlock_table(rtable *); +void rt_lock_table(rtable_private *); +void rt_unlock_table(rtable_private *); void rt_subscribe(rtable *tab, struct rt_subscription *s); void rt_unsubscribe(struct rt_subscription *s); rtable *rt_setup(pool *, struct rtable_config *); -static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } -static inline net *net_find_valid(rtable *tab, const net_addr *addr) +static inline net *net_find(rtable_private *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } +static inline net *net_find_valid(rtable_private *tab, const net_addr *addr) { net *n = net_find(tab, addr); return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; } -static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); } -void *net_route(rtable *tab, const net_addr *n); +static inline net *net_get(rtable_private *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); } +void *net_route(rtable_private *tab, const net_addr *n); int net_roa_check(rtable *tab, const net_addr *n, u32 asn); -int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter); +int rt_examine(rtable_private *t, net_addr *a, struct channel *c, const struct filter *filter); rte *rt_export_merged(struct channel *c, rte ** feed, uint count, linpool *pool, int silent); void rt_refresh_begin(struct rt_import_request *); void rt_refresh_end(struct rt_import_request *); -void rt_schedule_prune(rtable *t); +void rt_schedule_prune(rtable_private *t); void rte_dump(struct rte_storage *); -void rte_free(struct rte_storage *, rtable *); -struct rte_storage *rte_store(const rte *, net *net, rtable *); +void rte_free(struct rte_storage *, rtable_private *); +struct rte_storage *rte_store(const rte *, net *net, rtable_private *); void rt_dump(rtable *); void rt_dump_all(void); void rt_dump_hooks(rtable *); @@ -591,7 +606,7 @@ struct rte_src { typedef struct rta { struct rta *next, **pprev; /* Hash chain */ - _Atomic u32 uc; /* Use count */ + u32 uc; /* Use count */ u32 hash_key; /* Hash over important fields */ struct ea_list *eattrs; /* Extended Attribute chain */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */ @@ -732,7 +747,7 @@ struct rte_owner_class { struct rte_owner { struct rte_owner_class *class; - int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *); + int (*rte_recalculate)(rtable_private *, struct network *, struct rte *, struct rte *, struct rte *); HASH(struct rte_src) hash; const char *name; u32 hash_key; @@ -863,9 +878,20 @@ static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a #define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK) rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ static inline int rta_is_cached(rta *r) { return r->cached; } -static inline rta *rta_clone(rta *r) { ASSERT_DIE(0 < atomic_fetch_add_explicit(&r->uc, 1, memory_order_acq_rel)); return r; } +static inline rta *rta_clone(rta *r) { + RTA_LOCK; + r->uc++; + RTA_UNLOCK; + return r; +} + void rta__free(rta *r); -static inline void rta_free(rta *r) { if (r && (1 == atomic_fetch_sub_explicit(&r->uc, 1, memory_order_acq_rel))) rta__free(r); } +static inline void rta_free(rta *r) { + RTA_LOCK; + if (r && !--r->uc) + rta__free(r); + RTA_UNLOCK; +} rta *rta_do_cow(rta *o, linpool *lp); static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta_do_cow(r, lp) : r; } static inline void rta_uncache(rta *r) { r->cached = 0; r->uc = 0; } diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 20f9835d..cd4c6892 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1287,7 +1287,7 @@ rta_lookup(rta *o) for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next) if (r->hash_key == h && rta_same(r, o)) { - atomic_fetch_add_explicit(&r->uc, 1, memory_order_acq_rel); + r->uc++; RTA_UNLOCK; return r; } @@ -1308,14 +1308,6 @@ rta_lookup(rta *o) void rta__free(rta *a) { - RTA_LOCK; - if (atomic_load_explicit(&a->uc, memory_order_acquire)) - { - /* Somebody has cloned this rta inbetween. This sometimes happens. */ - RTA_UNLOCK; - return; - } - ASSERT(rta_cache_count && a->cached); rta_cache_count--; *a->pprev = a->next; @@ -1327,7 +1319,6 @@ rta__free(rta *a) ea_free(a->eattrs); a->cached = 0; sl_free(rta_slab(a), a); - RTA_UNLOCK; } rta * diff --git a/nest/rt-show.c b/nest/rt-show.c index 8196903d..65b59af4 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -239,11 +239,13 @@ rt_show_cleanup(struct cli *c) /* Unlink the iterator */ if (d->table_open) - fit_get(&d->tab->table->fib, &d->fit); + RT_LOCKED(d->tab->table, t) + fit_get(&t->fib, &d->fit); /* Unlock referenced tables */ WALK_LIST(tab, d->tables) - rt_unlock_table(tab->table); + RT_LOCKED(tab->table, t) + rt_unlock_table(t); } static void @@ -255,8 +257,6 @@ rt_show_cont(struct cli *c) #else unsigned max = 64; #endif - struct fib *fib = &d->tab->table->fib; - struct fib_iterator *it = &d->fit; if (d->running_on_config && (d->running_on_config != config)) { @@ -264,9 +264,14 @@ rt_show_cont(struct cli *c) goto done; } + rtable_private *t = RT_LOCK(d->tab->table); + + struct fib *fib = &t->fib; + struct fib_iterator *it = &d->fit; + if (!d->table_open) { - FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib); + FIB_ITERATE_INIT(&d->fit, fib); d->table_open = 1; d->table_counter++; d->kernel = rt_show_get_kernel(d); @@ -284,6 +289,7 @@ rt_show_cont(struct cli *c) if (!max--) { FIB_ITERATE_PUT(it); + RT_UNLOCK(d->tab->table); return; } rt_show_net(c, n, d); @@ -300,6 +306,8 @@ rt_show_cont(struct cli *c) d->net_counter - d->net_counter_last, d->tab->table->name); } + RT_UNLOCK(d->tab->table); + d->kernel = NULL; d->table_open = 0; d->tab = NODE_NEXT(d->tab); @@ -431,7 +439,8 @@ rt_show(struct rt_show_data *d) if (!d->addr) { WALK_LIST(tab, d->tables) - rt_lock_table(tab->table); + RT_LOCKED(tab->table, t) + rt_lock_table(t); /* There is at least one table */ d->tab = HEAD(d->tables); @@ -446,13 +455,17 @@ rt_show(struct rt_show_data *d) d->tab = tab; d->kernel = rt_show_get_kernel(d); + RT_LOCK(tab->table); + if (d->show_for) - n = net_route(tab->table, d->addr); + n = net_route(RT_PRIV(tab->table), d->addr); else - n = net_find(tab->table, d->addr); + n = net_find(RT_PRIV(tab->table), d->addr); if (n) rt_show_net(this_cli, n, d); + + RT_UNLOCK(tab->table); } if (d->rt_counter) diff --git a/nest/rt-table.c b/nest/rt-table.c index fb0496bd..f304372f 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -61,15 +61,15 @@ struct rt_export_block { struct rt_pending_export export[]; }; -static void rt_free_hostcache(rtable *tab); -static void rt_notify_hostcache(rtable *tab, net *net); +static void rt_free_hostcache(rtable_private *tab); +static void rt_notify_hostcache(rtable_private *tab, net *net); static void rt_update_hostcache(void *tab); static void rt_next_hop_update(void *tab); static inline void rt_prune_table(void *tab); -static inline void rt_schedule_notify(rtable *tab); +static inline void rt_schedule_notify(rtable_private *tab); static void rt_feed_channel(void *); -static inline void rt_export_used(rtable *tab); +static inline void rt_export_used(rtable_private *tab); static void rt_export_cleanup(void *tab); const char *rt_import_state_name_array[TIS_MAX] = { @@ -122,7 +122,7 @@ rte_update_unlock(struct channel *c) /* Like fib_route(), but skips empty net entries */ static inline void * -net_route_ip4(rtable *t, net_addr_ip4 *n) +net_route_ip4(rtable_private *t, net_addr_ip4 *n) { net *r; @@ -136,7 +136,7 @@ net_route_ip4(rtable *t, net_addr_ip4 *n) } static inline void * -net_route_ip6(rtable *t, net_addr_ip6 *n) +net_route_ip6(rtable_private *t, net_addr_ip6 *n) { net *r; @@ -150,7 +150,7 @@ net_route_ip6(rtable *t, net_addr_ip6 *n) } static inline void * -net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n) +net_route_ip6_sadr(rtable_private *t, net_addr_ip6_sadr *n) { struct fib_node *fn; @@ -189,7 +189,7 @@ net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n) } void * -net_route(rtable *tab, const net_addr *n) +net_route(rtable_private *tab, const net_addr *n) { ASSERT(tab->addr_type == n->type); @@ -218,12 +218,15 @@ net_route(rtable *tab, const net_addr *n) static int -net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn) +net_roa_check_ip4(rtable *t, const net_addr_ip4 *px, u32 asn) { struct net_addr_roa4 n = NET_ADDR_ROA4(px->prefix, px->pxlen, 0, 0); struct fib_node *fn; int anything = 0; + RT_LOCK(t); + rtable_private *tab = RT_PRIV(t); + while (1) { for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next) @@ -235,7 +238,10 @@ net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn) { anything = 1; if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen)) + { + RT_UNLOCK(tab); return ROA_VALID; + } } } @@ -246,16 +252,20 @@ net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn) ip4_clrbit(&n.prefix, n.pxlen); } + RT_UNLOCK(tab); return anything ? ROA_INVALID : ROA_UNKNOWN; } static int -net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn) +net_roa_check_ip6(rtable *t, const net_addr_ip6 *px, u32 asn) { struct net_addr_roa6 n = NET_ADDR_ROA6(px->prefix, px->pxlen, 0, 0); struct fib_node *fn; int anything = 0; + RT_LOCK(t); + rtable_private *tab = RT_PRIV(t); + while (1) { for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next) @@ -267,7 +277,10 @@ net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn) { anything = 1; if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen)) + { + RT_UNLOCK(tab); return ROA_VALID; + } } } @@ -278,6 +291,7 @@ net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn) ip6_clrbit(&n.prefix, n.pxlen); } + RT_UNLOCK(tab); return anything ? ROA_INVALID : ROA_UNKNOWN; } @@ -328,7 +342,7 @@ rte_find(net *net, struct rte_src *src) struct rte_storage * -rte_store(const rte *r, net *net, rtable *tab) +rte_store(const rte *r, net *net, rtable_private *tab) { struct rte_storage *e = sl_alloc(tab->rte_slab); @@ -354,7 +368,7 @@ rte_store(const rte *r, net *net, rtable *tab) */ void -rte_free(struct rte_storage *e, rtable *tab) +rte_free(struct rte_storage *e, rtable_private *tab) { rt_unlock_source(e->rte.src); rta_free(e->rte.attrs); @@ -912,6 +926,7 @@ rte_export(struct rt_export_hook *hook, struct rt_pending_export *rpe) hook->req->export_one(hook->req, n, rpe); else if (hook->req->export_bulk) { + RT_LOCK(hook->table); net *net = SKIP_BACK(struct network, n.addr, (net_addr (*)[0]) n); uint count = rte_feed_count(net); rte **feed = NULL; @@ -920,6 +935,7 @@ rte_export(struct rt_export_hook *hook, struct rt_pending_export *rpe) feed = alloca(count * sizeof(rte *)); rte_feed_obtain(net, feed, count); } + RT_UNLOCK(hook->table); hook->req->export_bulk(hook->req, n, rpe, feed, count); } else @@ -931,7 +947,11 @@ seen: /* The last block may be available to free */ if (PAGE_HEAD(hook->rpe_next) != PAGE_HEAD(rpe)) - rt_export_used(hook->table); + { + RT_LOCK(hook->table); + rt_export_used(RT_PRIV(hook->table)); + RT_UNLOCK(hook->table); + } /* Releasing this export for cleanup routine */ DBG("store hook=%p last_export=%p seq=%lu\n", hook, rpe, rpe->seq); @@ -970,7 +990,7 @@ seen: * done outside of scope of rte_announce(). */ static void -rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage *old, +rte_announce(rtable_private *tab, net *net, struct rte_storage *new, struct rte_storage *old, struct rte_storage *new_best, struct rte_storage *old_best) { if (!new_best || !rte_is_valid(&new_best->rte)) @@ -1085,10 +1105,10 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage { ev_cork(&rt_cork); tab->cork_active = 1; - tm_start(tab->export_timer, 0); + tm_start_in(tab->export_timer, 0, tab->loop); } else if (!tm_active(tab->export_timer)) - tm_start(tab->export_timer, tab->config->export_settle_time); + tm_start_in(tab->export_timer, tab->config->export_settle_time, tab->loop); } static struct rt_pending_export * @@ -1117,7 +1137,7 @@ rt_next_export_fast(struct rt_pending_export *last) } static struct rt_pending_export * -rt_next_export(struct rt_export_hook *hook, rtable *tab) +rt_next_export(struct rt_export_hook *hook, rtable_private *tab) { /* As the table is locked, it is safe to reload the last export pointer */ struct rt_pending_export *last = atomic_load_explicit(&hook->last_export, memory_order_acquire); @@ -1140,7 +1160,8 @@ rt_send_export_event(struct rt_export_hook *hook) static void rt_announce_exports(timer *tm) { - rtable *tab = tm->data; + rtable_private *tab = tm->data; + ASSERT_DIE(birdloop_inside(tab->loop)); struct rt_export_hook *c; node *n; WALK_LIST2(c, n, tab->exports, n) @@ -1153,7 +1174,7 @@ rt_announce_exports(timer *tm) } static struct rt_pending_export * -rt_last_export(rtable *tab) +rt_last_export(rtable_private *tab) { struct rt_pending_export *rpe = NULL; @@ -1179,13 +1200,17 @@ rt_export_hook(void *_data) if (!c->rpe_next) { - c->rpe_next = rt_next_export(c, c->table); + RT_LOCK(c->table); + c->rpe_next = rt_next_export(c, RT_PRIV(c->table)); if (!c->rpe_next) { - rt_export_used(c->table); + rt_export_used(RT_PRIV(c->table)); + RT_UNLOCK(c->table); return; } + + RT_UNLOCK(c->table); } /* Process the export */ @@ -1255,10 +1280,9 @@ rte_same(rte *x, rte *y) static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); } static void -rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *src) +rte_recalculate(rtable_private *table, struct rt_import_hook *c, net *net, rte *new, struct rte_src *src) { struct rt_import_request *req = c->req; - struct rtable *table = c->table; struct rt_import_stats *stats = &c->stats; struct rte_storage *old_best_stored = net->routes, *old_stored = NULL; rte *old_best = old_best_stored ? &old_best_stored->rte : NULL; @@ -1521,7 +1545,6 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) ASSERT(c->channel_state == CS_UP); - if (c->in_table) rte_import(&c->in_table->push, n, new, src); else @@ -1575,27 +1598,32 @@ rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rt if (!hook) return; + RT_LOCK(hook->table); + rtable_private *tab = RT_PRIV(hook->table); + net *nn; if (new) { /* Use the actual struct network, not the dummy one */ - nn = net_get(hook->table, n); + nn = net_get(tab, n); new->net = nn->n.addr; new->sender = hook; } - else if (!(nn = net_find(hook->table, n))) + else if (!(nn = net_find(tab, n))) { req->hook->stats.withdraws_ignored++; + RT_UNLOCK(tab); return; } /* And recalculate the best route */ - rte_recalculate(hook, nn, new, src); + rte_recalculate(tab, hook, nn, new, src); + RT_UNLOCK(tab); } /* Check rtable for best route to given net whether it would be exported do p */ int -rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter) +rt_examine(rtable_private *t, net_addr *a, struct channel *c, const struct filter *filter) { net *n = net_find(t, a); @@ -1623,22 +1651,27 @@ static void rt_export_stopped(void *data) { struct rt_export_hook *hook = data; - rtable *tab = hook->table; - /* Drop pending exports */ - rt_export_used(tab); + RT_LOCKED(hook->table, tab) + { + /* Drop pending exports */ + rt_export_used(tab); - /* Unlist */ - rem_node(&hook->n); + /* Unlist */ + rem_node(&hook->n); + } /* Report the channel as stopped. */ hook->stopped(hook->req); - /* Free the hook together with its coroutine. */ - rfree(hook->pool); - rt_unlock_table(tab); + RT_LOCKED(hook->table, tab) + { + /* Free the hook together with its coroutine. */ + rfree(hook->pool); + rt_unlock_table(tab); - DBG("Export hook %p in table %s finished uc=%u\n", hook, tab->name, tab->use_count); + DBG("Export hook %p in table %s finished uc=%u\n", hook, tab->name, tab->use_count); + } } @@ -1663,8 +1696,10 @@ rt_set_export_state(struct rt_export_hook *hook, u8 state) } void -rt_request_import(rtable *tab, struct rt_import_request *req) +rt_request_import(rtable *t, struct rt_import_request *req) { + RT_LOCK(t); + rtable_private *tab = RT_PRIV(t); rt_lock_table(tab); struct rt_import_hook *hook = req->hook = mb_allocz(tab->rp, sizeof(struct rt_import_hook)); @@ -1672,7 +1707,7 @@ rt_request_import(rtable *tab, struct rt_import_request *req) DBG("Lock table %s for import %p req=%p uc=%u\n", tab->name, hook, req, tab->use_count); hook->req = req; - hook->table = tab; + hook->table = t; if (!hook->stale_set) hook->stale_set = hook->stale_valid = hook->stale_pruning = hook->stale_pruned = 1; @@ -1681,24 +1716,30 @@ rt_request_import(rtable *tab, struct rt_import_request *req) hook->n = (node) {}; add_tail(&tab->imports, &hook->n); + + RT_UNLOCK(t); } void -rt_stop_import(struct rt_import_request *req, void (*stopped)(struct rt_import_request *)) +rt_stop_import(struct rt_import_request *req, event *stopped) { ASSERT_DIE(req->hook); struct rt_import_hook *hook = req->hook; - rt_schedule_prune(hook->table); + RT_LOCK(hook->table); + rt_schedule_prune(RT_PRIV(hook->table)); rt_set_import_state(hook, TIS_STOP); hook->stopped = stopped; + RT_UNLOCK(hook->table); } void -rt_request_export(rtable *tab, struct rt_export_request *req) +rt_request_export(rtable *t, struct rt_export_request *req) { + RT_LOCK(t); + rtable_private *tab = RT_PRIV(t); rt_lock_table(tab); pool *p = rp_new(tab->rp, "Export hook"); @@ -1706,7 +1747,7 @@ rt_request_export(rtable *tab, struct rt_export_request *req) hook->pool = p; hook->req = req; - hook->table = tab; + hook->table = t; /* stats zeroed by mb_allocz */ @@ -1714,7 +1755,7 @@ rt_request_export(rtable *tab, struct rt_export_request *req) rt_set_export_state(hook, TES_HUNGRY); - struct rt_pending_export *rpe = rt_last_export(hook->table); + struct rt_pending_export *rpe = rt_last_export(tab); DBG("store hook=%p last_export=%p seq=%lu\n", hook, rpe, rpe ? rpe->seq : 0); atomic_store_explicit(&hook->last_export, rpe, memory_order_relaxed); @@ -1726,9 +1767,11 @@ rt_request_export(rtable *tab, struct rt_export_request *req) DBG("New export hook %p req %p in table %s uc=%u\n", hook, req, tab->name, tab->use_count); hook->event = ev_new_init(p, rt_feed_channel, hook); - rt_send_export_event(hook); + RT_UNLOCK(t); rt_set_export_state(hook, TES_FEEDING); + ASSERT_DIE(hook->export_state == TES_FEEDING); + rt_send_export_event(hook); } void @@ -1737,7 +1780,8 @@ rt_stop_export(struct rt_export_request *req, void (*stopped)(struct rt_export_r ASSERT_DIE(req->hook); struct rt_export_hook *hook = req->hook; - rtable *tab = hook->table; + RT_LOCK(hook->table); + rtable_private *tab = RT_PRIV(hook->table); /* Stop feeding */ ev_postpone(hook->event); @@ -1750,10 +1794,11 @@ rt_stop_export(struct rt_export_request *req, void (*stopped)(struct rt_export_r rt_send_export_event(hook); + RT_UNLOCK(hook->table); + rt_set_export_state(hook, TES_STOP); } - /** * rt_refresh_begin - start a refresh cycle * @t: related routing table @@ -1772,14 +1817,17 @@ rt_refresh_begin(struct rt_import_request *req) struct rt_import_hook *hook = req->hook; ASSERT_DIE(hook); + RT_LOCK(hook->table); + rtable_private *tab = RT_PRIV(hook->table); + ASSERT_DIE(hook->stale_set == hook->stale_valid); /* If the pruning routine is too slow */ if ((hook->stale_pruned < hook->stale_valid) && (hook->stale_pruned + 128 < hook->stale_valid) || (hook->stale_pruned > hook->stale_valid) && (hook->stale_pruned > hook->stale_valid + 128)) { - log(L_WARN "Route refresh flood in table %s", hook->table->name); - FIB_WALK(&hook->table->fib, net, n) + log(L_WARN "Route refresh flood in table %s", tab->name); + FIB_WALK(&tab->fib, net, n) { for (struct rte_storage *e = n->routes; e; e = e->next) if (e->rte.sender == req->hook) @@ -1799,6 +1847,8 @@ rt_refresh_begin(struct rt_import_request *req) if (req->trace_routes & D_STATES) log(L_TRACE "%s: route refresh begin [%u]", req->name, hook->stale_set); + + RT_UNLOCK(tab); } /** @@ -1815,13 +1865,16 @@ rt_refresh_end(struct rt_import_request *req) struct rt_import_hook *hook = req->hook; ASSERT_DIE(hook); + RT_LOCK(hook->table); hook->stale_valid++; ASSERT_DIE(hook->stale_set == hook->stale_valid); - rt_schedule_prune(hook->table); + rt_schedule_prune(RT_PRIV(hook->table)); if (req->trace_routes & D_STATES) log(L_TRACE "%s: route refresh end [%u]", req->name, hook->stale_valid); + + RT_UNLOCK(hook->table); } /** @@ -1846,8 +1899,10 @@ rte_dump(struct rte_storage *e) * This function dumps contents of a given routing table to debug output. */ void -rt_dump(rtable *t) +rt_dump(rtable *tab) { + RT_LOCK(tab); + rtable_private *t = RT_PRIV(tab); debug("Dump of routing table <%s>%s\n", t->name, t->delete_event ? " (deleted)" : ""); #ifdef DEBUGGING fib_check(&t->fib); @@ -1859,6 +1914,7 @@ rt_dump(rtable *t) } FIB_WALK_END; debug("\n"); + RT_UNLOCK(tab); } /** @@ -1877,11 +1933,13 @@ rt_dump_all(void) } void -rt_dump_hooks(rtable *tab) +rt_dump_hooks(rtable *t) { + RT_LOCK(t); + rtable_private *tab = RT_PRIV(t); debug("Dump of hooks in routing table <%s>%s\n", tab->name, tab->delete_event ? " (deleted)" : ""); debug(" nhu_state=%u hcu_scheduled=%u use_count=%d rt_count=%u\n", - tab->nhu_state, ev_active(tab->hcu_event), tab->use_count, tab->rt_count); + atomic_load(&tab->nhu_state), ev_active(tab->hcu_event), tab->use_count, tab->rt_count); debug(" last_rt_change=%t gc_time=%t gc_counter=%d prune_state=%u\n", tab->last_rt_change, tab->gc_time, tab->gc_counter, tab->prune_state); @@ -1904,6 +1962,7 @@ rt_dump_hooks(rtable *tab) eh, eh->req, eh->refeed_pending, eh->last_state_change, atomic_load_explicit(&eh->export_state, memory_order_relaxed)); } debug("\n"); + RT_UNLOCK(t); } void @@ -1921,37 +1980,36 @@ rt_dump_hooks_all(void) static inline void rt_schedule_nhu(rtable *tab) { - if (tab->nhu_state == NHU_CLEAN) - ev_schedule(tab->nhu_event); + atomic_fetch_or_explicit(&tab->nhu_state, NHU_SCHEDULED, memory_order_acq_rel); + ev_send_loop(tab->loop, tab->nhu_event); /* state change: * NHU_CLEAN -> NHU_SCHEDULED * NHU_RUNNING -> NHU_DIRTY */ - tab->nhu_state |= NHU_SCHEDULED; } void -rt_schedule_prune(rtable *tab) +rt_schedule_prune(rtable_private *tab) { if (tab->prune_state == 0) - ev_schedule(tab->prune_event); + ev_send_loop(tab->loop, tab->prune_event); /* state change 0->1, 2->3 */ tab->prune_state |= 1; } void -rt_export_used(rtable *tab) +rt_export_used(rtable_private *tab) { if (config->table_debug) log(L_TRACE "%s: Export cleanup requested", tab->name); - ev_schedule(tab->ec_event); + ev_send_loop(tab->loop, tab->ec_event); } static inline btime -rt_settled_time(rtable *tab) +rt_settled_time(rtable_private *tab) { ASSUME(tab->base_settle_time != 0); @@ -1962,7 +2020,8 @@ rt_settled_time(rtable *tab) static void rt_settle_timer(timer *t) { - rtable *tab = t->data; + rtable_private *tab = t->data; + ASSERT_DIE(birdloop_inside(tab->loop)); if (!tab->base_settle_time) return; @@ -1970,7 +2029,7 @@ rt_settle_timer(timer *t) btime settled_time = rt_settled_time(tab); if (current_time() < settled_time) { - tm_set(tab->settle_timer, settled_time); + tm_set_in(tab->settle_timer, settled_time, tab->loop); return; } @@ -1983,7 +2042,7 @@ rt_settle_timer(timer *t) } static void -rt_kick_settle_timer(rtable *tab) +rt_kick_settle_timer(rtable_private *tab) { tab->base_settle_time = current_time(); @@ -1991,11 +2050,11 @@ rt_kick_settle_timer(rtable *tab) tab->settle_timer = tm_new_init(tab->rp, rt_settle_timer, tab, 0, 0); if (!tm_active(tab->settle_timer)) - tm_set(tab->settle_timer, rt_settled_time(tab)); + tm_set_in(tab->settle_timer, rt_settled_time(tab), tab->loop); } static inline void -rt_schedule_notify(rtable *tab) +rt_schedule_notify(rtable_private *tab) { if (EMPTY_LIST(tab->subscribers)) return; @@ -2007,25 +2066,33 @@ rt_schedule_notify(rtable *tab) } void -rt_subscribe(rtable *tab, struct rt_subscription *s) +rt_subscribe(rtable *t, struct rt_subscription *s) { - s->tab = tab; - rt_lock_table(tab); - DBG("rt_subscribe(%s)\n", tab->name); - add_tail(&tab->subscribers, &s->n); + s->tab = t; + RT_LOCKED(t, tab) + { + rt_lock_table(tab); + DBG("rt_subscribe(%s)\n", tab->name); + add_tail(&tab->subscribers, &s->n); + } } void rt_unsubscribe(struct rt_subscription *s) { - rem_node(&s->n); - rt_unlock_table(s->tab); + RT_LOCKED(s->tab, tab) + { + rem_node(&s->n); + if (EMPTY_LIST(tab->subscribers) && tm_active(tab->settle_timer)) + tm_stop(tab->settle_timer); + rt_unlock_table(tab); + } } static void rt_free(resource *_r) { - rtable *r = (rtable *) _r; + rtable_private *r = (rtable_private *) _r; DBG("Deleting routing table %s\n", r->name); ASSERT_DIE(r->use_count == 0); @@ -2046,14 +2113,14 @@ rt_free(resource *_r) static void rt_res_dump(resource *_r) { - rtable *r = (rtable *) _r; + RT_LOCKED((rtable *) _r, r) debug("name \"%s\", addr_type=%s, rt_count=%u, use_count=%d\n", r->name, net_label[r->addr_type], r->rt_count, r->use_count); } static struct resclass rt_class = { .name = "Routing table", - .size = sizeof(struct rtable), + .size = sizeof(rtable_private), .free = rt_free, .dump = rt_res_dump, .lookup = NULL, @@ -2068,9 +2135,8 @@ rt_setup(pool *pp, struct rtable_config *cf) ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name)); pool *p = rp_new(pp, nb); - mb_move(nb, p); - rtable *t = ralloc(p, &rt_class); + rtable_private *t = ralloc(p, &rt_class); t->rp = p; t->rte_slab = sl_new(p, sizeof(struct rte_storage)); @@ -2090,6 +2156,8 @@ rt_setup(pool *pp, struct rtable_config *cf) init_list(&t->pending_exports); init_list(&t->subscribers); + t->loop = birdloop_new(p, DOMAIN_ORDER(rtable), nb); + t->ec_event = ev_new_init(p, rt_export_cleanup, t); t->prune_event = ev_new_init(p, rt_prune_table, t); t->hcu_event = ev_new_init(p, rt_update_hostcache, t); @@ -2106,7 +2174,8 @@ rt_setup(pool *pp, struct rtable_config *cf) t->nhu_lp = lp_new_default(p); - return t; + mb_move(nb, p); + return (rtable *) t; } /** @@ -2141,7 +2210,9 @@ rt_init(void) static void rt_prune_table(void *data) { - rtable *tab = data; + rtable_private *tab = data; + ASSERT_DIE(birdloop_inside(tab->loop)); + struct fib_iterator *fit = &tab->prune_fit; int limit = 512; @@ -2156,6 +2227,8 @@ rt_prune_table(void *data) if (tab->prune_state == 0) return; + rt_lock_table(tab); + if (tab->prune_state == 1) { /* Mark channels to flush */ @@ -2189,11 +2262,12 @@ again: if (limit <= 0) { FIB_ITERATE_PUT(fit); - ev_schedule(tab->prune_event); + ev_send_loop(tab->loop, tab->prune_event); + rt_unlock_table(tab); return; } - rte_recalculate(e->rte.sender, n, NULL, e->rte.src); + rte_recalculate(tab, e->rte.sender, n, NULL, e->rte.src); limit--; goto rescan; @@ -2217,7 +2291,8 @@ again: tab->gc_time = current_time(); /* state change 2->0, 3->1 */ - tab->prune_state &= 1; + if (tab->prune_state &= 1) + ev_send_loop(tab->loop, tab->prune_event); uint flushed_channels = 0; @@ -2240,12 +2315,15 @@ again: /* In some cases, we may want to directly proceed to export cleanup */ if (EMPTY_LIST(tab->exports) && flushed_channels) rt_export_cleanup(tab); + + rt_unlock_table(tab); } static void rt_export_cleanup(void *data) { - rtable *tab = data; + rtable_private *tab = data; + ASSERT_DIE(birdloop_inside(tab->loop)); u64 min_seq = ~((u64) 0); struct rt_pending_export *last_export_to_free = NULL; @@ -2394,7 +2472,7 @@ done:; if (!first_export || (first_export->seq >= ih->flush_seq)) { ih->import_state = TIS_CLEARED; - ih->stopped(ih->req); + ev_send(ih->stopped->list, ih->stopped); rem_node(&ih->n); mb_free(ih); rt_unlock_table(tab); @@ -2535,7 +2613,7 @@ no_nexthop: } static inline struct rte_storage * -rt_next_hop_update_rte(rtable *tab, net *n, rte *old) +rt_next_hop_update_rte(rtable_private *tab, net *n, rte *old) { rta *a = alloca(RTA_MAX_SIZE); memcpy(a, old->attrs, rta_size(old->attrs)); @@ -2553,7 +2631,7 @@ rt_next_hop_update_rte(rtable *tab, net *n, rte *old) } static inline int -rt_next_hop_update_net(rtable *tab, net *n) +rt_next_hop_update_net(rtable_private *tab, net *n) { struct rte_storage *new; int count = 0; @@ -2638,17 +2716,21 @@ rt_next_hop_update_net(rtable *tab, net *n) static void rt_next_hop_update(void *data) { - rtable *tab = data; + rtable_private *tab = data; + ASSERT_DIE(birdloop_inside(tab->loop)); + struct fib_iterator *fit = &tab->nhu_fit; int max_feed = 32; - if (tab->nhu_state == NHU_CLEAN) + if (atomic_load_explicit(&tab->nhu_state, memory_order_acquire) == NHU_CLEAN) return; - if (tab->nhu_state == NHU_SCHEDULED) + rt_lock_table(tab); + + if (atomic_load_explicit(&tab->nhu_state, memory_order_acquire) == NHU_SCHEDULED) { FIB_ITERATE_INIT(fit, &tab->fib); - tab->nhu_state = NHU_RUNNING; + ASSERT_DIE(atomic_exchange_explicit(&tab->nhu_state, NHU_RUNNING, memory_order_acq_rel) == NHU_SCHEDULED); } FIB_ITERATE_START(&tab->fib, fit, net, n) @@ -2656,7 +2738,8 @@ rt_next_hop_update(void *data) if (max_feed <= 0) { FIB_ITERATE_PUT(fit); - ev_schedule(tab->nhu_event); + ev_send_loop(tab->loop, tab->nhu_event); + rt_unlock_table(tab); return; } max_feed -= rt_next_hop_update_net(tab, n); @@ -2667,10 +2750,10 @@ rt_next_hop_update(void *data) * NHU_DIRTY -> NHU_SCHEDULED * NHU_RUNNING -> NHU_CLEAN */ - tab->nhu_state &= 1; + if (atomic_fetch_and_explicit(&tab->nhu_state, NHU_SCHEDULED, memory_order_acq_rel) != NHU_RUNNING) + ev_send_loop(tab->loop, tab->nhu_event); - if (tab->nhu_state != NHU_CLEAN) - ev_schedule(tab->nhu_event); + rt_unlock_table(tab); } @@ -2713,11 +2796,22 @@ rt_new_table(struct symbol *s, uint addr_type) * configuration. */ void -rt_lock_table(rtable *r) +rt_lock_table(rtable_private *r) { r->use_count++; } +static void +rt_loop_stopped(void *data) +{ + rtable_private *r = data; + birdloop_free(r->loop); + r->loop = NULL; + r->prune_event->list = r->ec_event->list = NULL; + r->nhu_event->list = r->hcu_event->list = NULL; + ev_send(r->delete_event->list, r->delete_event); +} + /** * rt_unlock_table - unlock a routing table * @r: routing table to be unlocked @@ -2727,14 +2821,14 @@ rt_lock_table(rtable *r) * for deletion by configuration changes. */ void -rt_unlock_table(rtable *r) +rt_unlock_table(rtable_private *r) { - if (!--r->use_count && r->delete_event) + if (!--r->use_count && r->delete_event && + !r->prune_state && !atomic_load_explicit(&r->nhu_state, memory_order_acquire)) /* Delete the routing table by freeing its pool */ - ev_schedule(r->delete_event); + birdloop_stop_self(r->loop, rt_loop_stopped, r); } - static struct rtable_config * rt_find_table_config(struct config *cf, char *name) { @@ -2745,7 +2839,9 @@ rt_find_table_config(struct config *cf, char *name) static void rt_done(void *data) { - rtable *t = data; + rtable_private *t = data; + ASSERT_DIE(t->loop == NULL); + struct rtable_config *tc = t->config; struct config *c = tc->config; @@ -2755,6 +2851,7 @@ rt_done(void *data) if (t->hostcache) rt_free_hostcache(t); + rfree(t->delete_event); rfree(t->rp); config_del_obstacle(c); @@ -2782,14 +2879,15 @@ rt_commit(struct config *new, struct config *old) { WALK_LIST(o, old->tables) { - rtable *ot = o->table; + RT_LOCK(o->table); + rtable_private *ot = RT_PRIV(o->table); if (!ot->delete_event) { r = rt_find_table_config(new, o->name); if (r && (r->addr_type == o->addr_type) && !new->shutdown) { DBG("\t%s: same\n", o->name); - r->table = ot; + r->table = (rtable *) ot; ot->name = r->name; ot->config = r; if (o->sorted != r->sorted) @@ -2799,11 +2897,13 @@ rt_commit(struct config *new, struct config *old) { DBG("\t%s: deleted\n", o->name); rt_lock_table(ot); - ot->delete_event = ev_new_init(ot->rp, rt_done, ot); + ot->delete_event = ev_new_init(&root_pool, rt_done, ot); + ot->delete_event->list = &global_event_list; config_add_obstacle(old); rt_unlock_table(ot); } } + RT_UNLOCK(o->table); } } @@ -2834,46 +2934,98 @@ rt_feed_channel(void *data) struct fib_iterator *fit = &c->feed_fit; int max_feed = 256; + RT_LOCK(c->table); + rtable_private *tab = RT_PRIV(c->table); + ASSERT(atomic_load_explicit(&c->export_state, memory_order_relaxed) == TES_FEEDING); - FIB_ITERATE_START(&c->table->fib, fit, net, n) +redo: + FIB_ITERATE_START(&tab->fib, fit, net, n) { if (max_feed <= 0) { FIB_ITERATE_PUT(fit); rt_send_export_event(c); + + RT_UNLOCK(c->table); return; } if (atomic_load_explicit(&c->export_state, memory_order_acquire) != TES_FEEDING) + { + RT_UNLOCK(c->table); return; + } - if (c->req->export_bulk) + if (!n->routes || !rte_is_valid(&n->routes->rte)) + ; /* if no route, do nothing */ + else if (c->req->export_bulk) { uint count = rte_feed_count(n); if (count) { rte **feed = alloca(count * sizeof(rte *)); rte_feed_obtain(n, feed, count); + + struct rt_pending_export *rpe_last, *rpe_first = n->first; + for (struct rt_pending_export *rpe = rpe_first; rpe; rpe = rpe_next(rpe, NULL)) + rpe_last = rpe; + + FIB_ITERATE_PUT_NEXT(fit, &tab->fib); + RT_UNLOCK(c->table); + c->req->export_bulk(c->req, n->n.addr, NULL, feed, count); + + RT_LOCK(c->table); + + for (struct rt_pending_export *rpe = rpe_first; rpe; rpe = rpe_next(rpe, NULL)) + { + rpe_mark_seen(c, rpe); + if (rpe == rpe_last) + break; + ASSERT_DIE(rpe->seq < rpe_last->seq); + } + max_feed -= count; + + goto redo; } } - else if (n->routes && rte_is_valid(&n->routes->rte)) + else if (c->req->export_one) { struct rt_pending_export rpe = { .new = n->routes, .new_best = n->routes }; + + struct rt_pending_export *rpe_last, *rpe_first = n->first; + for (struct rt_pending_export *rpe = rpe_first; rpe; rpe = rpe_next(rpe, NULL)) + rpe_last = rpe; + + FIB_ITERATE_PUT_NEXT(fit, &tab->fib); + RT_UNLOCK(c->table); + c->req->export_one(c->req, n->n.addr, &rpe); + + RT_LOCK(c->table); + for (struct rt_pending_export *rpe = rpe_first; rpe; rpe = rpe_next(rpe, NULL)) + { + rpe_mark_seen(c, rpe); + if (rpe == rpe_last) + break; + ASSERT_DIE(rpe->seq < rpe_last->seq); + } + max_feed--; + goto redo; } - - for (struct rt_pending_export *rpe = n->first; rpe; rpe = rpe_next(rpe, NULL)) - rpe_mark_seen(c, rpe); + else + bug("Export request must always provide an export method"); } FIB_ITERATE_END; c->event->hook = rt_export_hook; rt_send_export_event(c); + RT_UNLOCK(c->table); + rt_set_export_state(c, TES_READY); } @@ -2981,7 +3133,7 @@ hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he) } static void -rt_init_hostcache(rtable *tab) +rt_init_hostcache(rtable_private *tab) { struct hostcache *hc = mb_allocz(tab->rp, sizeof(struct hostcache)); init_list(&hc->hostentries); @@ -2997,7 +3149,7 @@ rt_init_hostcache(rtable *tab) } static void -rt_free_hostcache(rtable *tab) +rt_free_hostcache(rtable_private *tab) { struct hostcache *hc = tab->hostcache; @@ -3020,13 +3172,13 @@ rt_free_hostcache(rtable *tab) } static void -rt_notify_hostcache(rtable *tab, net *net) +rt_notify_hostcache(rtable_private *tab, net *net) { if (ev_active(tab->hcu_event)) return; if (trie_match_net(tab->hostcache->trie, net->n.addr)) - ev_schedule(tab->hcu_event); + ev_send_loop(tab->loop, tab->hcu_event); } static int @@ -3059,7 +3211,7 @@ rt_get_igp_metric(rte *rt) } static int -rt_update_hostentry(rtable *tab, struct hostentry *he) +rt_update_hostentry(rtable_private *tab, struct hostentry *he) { rta *old_src = he->src; int direct = 0; @@ -3125,7 +3277,9 @@ done: static void rt_update_hostcache(void *data) { - rtable *tab = data; + rtable_private *tab = data; + ASSERT_DIE(birdloop_inside(tab->loop)); + struct hostcache *hc = tab->hostcache; struct hostentry *he; node *n, *x; @@ -3149,10 +3303,12 @@ rt_update_hostcache(void *data) } struct hostentry * -rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep) +rt_get_hostentry(rtable *t, ip_addr a, ip_addr ll, rtable *dep) { struct hostentry *he; + rtable_private *tab = RT_LOCK(t); + if (!tab->hostcache) rt_init_hostcache(tab); @@ -3160,10 +3316,13 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep) struct hostcache *hc = tab->hostcache; for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next) if (ipa_equal(he->addr, a) && (he->tab == dep)) - return he; + goto done; he = hc_new_hostentry(hc, tab->rp, a, ipa_zero(ll) ? a : ll, dep, k); rt_update_hostentry(tab, he); + +done: + RT_UNLOCK(t); return he; } -- cgit v1.2.3 From dc160e11e1a9e4344bbee6fd0bc8aee229d7c540 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 12 Nov 2021 15:53:33 +0000 Subject: Route table import-to-export announcement indirection to reduce pipe traffic --- nest/proto.c | 3 +++ nest/route.h | 7 ++++--- nest/rt-table.c | 53 +++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 44 insertions(+), 19 deletions(-) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index 623585f1..b7dbae5e 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -468,6 +468,7 @@ channel_start_import(struct channel *c) c->in_req = (struct rt_import_request) { .name = rn, + .list = proto_work_list(c->proto), .trace_routes = c->debug | c->proto->debug, .dump_req = channel_dump_import_req, .log_state_change = channel_import_log_state_change, @@ -886,6 +887,7 @@ channel_setup_in_table(struct channel *c, int best) c->in_table = &cat->cat; c->in_table->push = (struct rt_import_request) { .name = cat->name, + .list = proto_work_list(c->proto), .trace_routes = c->debug | c->proto->debug, .dump_req = channel_in_push_dump_req, .log_state_change = channel_push_log_state_change, @@ -928,6 +930,7 @@ channel_setup_out_table(struct channel *c) c->out_table = &cat->cat; c->out_table->push = (struct rt_import_request) { .name = cat->name, + .list = proto_work_list(c->proto), .trace_routes = c->debug | c->proto->debug, .dump_req = channel_out_push_dump_req, .log_state_change = channel_push_log_state_change, diff --git a/nest/route.h b/nest/route.h index 9417d97d..3f8bf433 100644 --- a/nest/route.h +++ b/nest/route.h @@ -170,6 +170,7 @@ typedef struct rtable_private { struct hmap id_map; struct hostcache *hostcache; struct event *prune_event; /* Event to prune abandoned routes */ + struct event *announce_event; /* Event to announce pending exports */ struct event *ec_event; /* Event to prune finished exports */ struct event *hcu_event; /* Event to update host cache */ struct event *delete_event; /* Event to delete the table */ @@ -191,8 +192,6 @@ typedef struct rtable_private { struct timer *settle_timer; /* Settle time for notifications */ list pending_exports; /* List of packed struct rt_pending_export */ - btime base_export_time; /* When first pending export was announced */ - struct timer *export_timer; struct rt_pending_export *first_export; /* First export to announce */ u64 next_export_seq; /* The next export will have this ID */ @@ -221,7 +220,6 @@ struct rtable_config { byte sorted; /* Routes of network are sorted according to rte_better() */ btime min_settle_time; /* Minimum settle time for notifications */ btime max_settle_time; /* Maximum settle time for notifications */ - btime export_settle_time; /* Delay before exports are announced */ uint cork_limit; /* Amount of routes to be pending on export to cork imports */ }; @@ -309,6 +307,8 @@ struct rt_import_request { char *name; u8 trace_routes; + event_list *list; /* Where to schedule import events */ + void (*dump_req)(struct rt_import_request *req); void (*log_state_change)(struct rt_import_request *req, u8 state); /* Preimport is called when the @new route is just-to-be inserted, replacing @old. @@ -339,6 +339,7 @@ struct rt_import_hook { u8 stale_pruned; /* Last prune finished when this value was set at stale_valid */ u8 stale_pruning; /* Last prune started when this value was set at stale_valid */ + struct event *export_announce_event; /* Event to run to announce new exports */ struct event *stopped; /* Event to run when import is stopped */ }; diff --git a/nest/rt-table.c b/nest/rt-table.c index f304372f..f33b9153 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1023,8 +1023,6 @@ rte_announce(rtable_private *tab, net *net, struct rte_storage *new, struct rte_ rt_notify_hostcache(tab, net); } - rt_schedule_notify(tab); - if (EMPTY_LIST(tab->exports) && EMPTY_LIST(tab->pending_exports)) { /* No export hook and no pending exports to cleanup. We may free the route immediately. */ @@ -1105,10 +1103,7 @@ rte_announce(rtable_private *tab, net *net, struct rte_storage *new, struct rte_ { ev_cork(&rt_cork); tab->cork_active = 1; - tm_start_in(tab->export_timer, 0, tab->loop); } - else if (!tm_active(tab->export_timer)) - tm_start_in(tab->export_timer, tab->config->export_settle_time, tab->loop); } static struct rt_pending_export * @@ -1158,11 +1153,13 @@ rt_send_export_event(struct rt_export_hook *hook) } static void -rt_announce_exports(timer *tm) +rt_announce_exports(void *data) { - rtable_private *tab = tm->data; + rtable_private *tab = data; ASSERT_DIE(birdloop_inside(tab->loop)); + rt_schedule_notify(tab); + struct rt_export_hook *c; node *n; WALK_LIST2(c, n, tab->exports, n) { @@ -1173,6 +1170,26 @@ rt_announce_exports(timer *tm) } } +static void +rt_import_announce_exports(void *data) +{ + struct rt_import_hook *hook = data; + RT_LOCKED(hook->table, tab) + { + if (hook->import_state == TIS_CLEARED) + { + rfree(hook->export_announce_event); + + ev_send(hook->stopped->list, hook->stopped); + rem_node(&hook->n); + mb_free(hook); + rt_unlock_table(tab); + } + else + ev_send_loop(tab->loop, tab->announce_event); + } +} + static struct rt_pending_export * rt_last_export(rtable_private *tab) { @@ -1471,6 +1488,8 @@ rte_recalculate(rtable_private *table, struct rt_import_hook *c, net *net, rte * rte_announce(table, net, new_stored, old_stored, net->routes, old_best_stored); + ev_send(req->list, c->export_announce_event); + if (!net->routes && (table->gc_counter++ >= table->config->gc_max_ops) && (table->gc_time + table->config->gc_min_time <= current_time())) @@ -1709,6 +1728,8 @@ rt_request_import(rtable *t, struct rt_import_request *req) hook->req = req; hook->table = t; + hook->export_announce_event = ev_new_init(tab->rp, rt_import_announce_exports, hook); + if (!hook->stale_set) hook->stale_set = hook->stale_valid = hook->stale_pruning = hook->stale_pruned = 1; @@ -1727,11 +1748,12 @@ rt_stop_import(struct rt_import_request *req, event *stopped) struct rt_import_hook *hook = req->hook; RT_LOCK(hook->table); + rt_schedule_prune(RT_PRIV(hook->table)); rt_set_import_state(hook, TIS_STOP); - hook->stopped = stopped; + RT_UNLOCK(hook->table); } @@ -2158,6 +2180,7 @@ rt_setup(pool *pp, struct rtable_config *cf) t->loop = birdloop_new(p, DOMAIN_ORDER(rtable), nb); + t->announce_event = ev_new_init(p, rt_announce_exports, t); t->ec_event = ev_new_init(p, rt_export_cleanup, t); t->prune_event = ev_new_init(p, rt_prune_table, t); t->hcu_event = ev_new_init(p, rt_update_hostcache, t); @@ -2166,7 +2189,6 @@ rt_setup(pool *pp, struct rtable_config *cf) t->nhu_event->cork = &rt_cork; t->prune_event->cork = &rt_cork; - t->export_timer = tm_new_init(p, rt_announce_exports, t, 0, 0); t->last_rt_change = t->gc_time = current_time(); t->next_export_seq = 1; @@ -2472,15 +2494,11 @@ done:; if (!first_export || (first_export->seq >= ih->flush_seq)) { ih->import_state = TIS_CLEARED; - ev_send(ih->stopped->list, ih->stopped); - rem_node(&ih->n); - mb_free(ih); - rt_unlock_table(tab); + ev_send(ih->req->list, ih->export_announce_event); } - - if (EMPTY_LIST(tab->pending_exports) && tm_active(tab->export_timer)) - tm_stop(tab->export_timer); + if (EMPTY_LIST(tab->pending_exports) && ev_active(tab->announce_event)) + ev_postpone(tab->announce_event); /* If reduced to at most one export block pending */ if (tab->cork_active && @@ -2753,6 +2771,8 @@ rt_next_hop_update(void *data) if (atomic_fetch_and_explicit(&tab->nhu_state, NHU_SCHEDULED, memory_order_acq_rel) != NHU_RUNNING) ev_send_loop(tab->loop, tab->nhu_event); + ev_send_loop(tab->loop, tab->announce_event); + rt_unlock_table(tab); } @@ -2809,6 +2829,7 @@ rt_loop_stopped(void *data) r->loop = NULL; r->prune_event->list = r->ec_event->list = NULL; r->nhu_event->list = r->hcu_event->list = NULL; + r->announce_event->list = NULL; ev_send(r->delete_event->list, r->delete_event); } -- cgit v1.2.3 From 4f3fa1623f66acd24c227cf0cc5a4af2f5133b6c Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 18 Oct 2021 21:22:58 +0200 Subject: Pipe runs in parallel. --- nest/proto.c | 1 + proto/pipe/config.Y | 1 + 2 files changed, 2 insertions(+) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index 4ae0cbfd..623585f1 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1413,6 +1413,7 @@ proto_event(void *ptr) { if (p->proto == &proto_unix_iface) if_flush_ifaces(p); + p->do_stop = 0; } diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y index c869de9f..fc08445f 100644 --- a/proto/pipe/config.Y +++ b/proto/pipe/config.Y @@ -25,6 +25,7 @@ proto: pipe_proto '}' { this_channel = NULL; } ; pipe_proto_start: proto_start PIPE { this_proto = proto_config_new(&proto_pipe, $1); + this_proto->loop_order = DOMAIN_ORDER(proto); PIPE_CFG->max_generation = 16; } proto_name -- cgit v1.2.3 From adf37d8eff8f281871295c402a51ae1dd654851c Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 15 Nov 2021 10:53:58 +0100 Subject: VRF setting reduced to one argument, using default dummy iface for default vrf --- nest/config.Y | 4 ++-- nest/iface.c | 13 +++++++++---- nest/iface.h | 2 ++ nest/neighbor.c | 10 +++++----- nest/proto.c | 8 +++----- nest/protocol.h | 2 -- proto/bfd/bfd.c | 2 +- 7 files changed, 22 insertions(+), 19 deletions(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index 6e7689ed..0914048b 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -266,8 +266,8 @@ proto_item: | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; } | ROUTER ID idval { this_proto->router_id = $3; } | DESCRIPTION text { this_proto->dsc = $2; } - | VRF text { this_proto->vrf = if_get_by_name($2); this_proto->vrf_set = 1; } - | VRF DEFAULT { this_proto->vrf = NULL; this_proto->vrf_set = 1; } + | VRF text { this_proto->vrf = if_get_by_name($2); } + | VRF DEFAULT { this_proto->vrf = &default_vrf; } ; diff --git a/nest/iface.c b/nest/iface.c index 83a633a3..5cb9e814 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -37,6 +37,7 @@ static pool *if_pool; list iface_list; +struct iface default_vrf; static void if_recalc_preferred(struct iface *i); @@ -147,7 +148,7 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a) { if (p->ifa_notify && (p->proto_state != PS_DOWN) && - (!p->vrf_set || p->vrf == a->iface->master)) + (!p->vrf || p->vrf == a->iface->master)) { if (p->debug & D_IFACES) log(L_TRACE "%s < address %N on interface %s %s", @@ -185,7 +186,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i) { if (p->if_notify && (p->proto_state != PS_DOWN) && - (!p->vrf_set || p->vrf == i->master)) + (!p->vrf || p->vrf == i->master)) { if (p->debug & D_IFACES) log(L_TRACE "%s < interface %s %s", p->name, i->name, @@ -243,7 +244,7 @@ if_recalc_flags(struct iface *i UNUSED, uint flags) { if ((flags & IF_ADMIN_UP) && !(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) && - !(i->master_index && !i->master)) + !(i->master_index && i->master == &default_vrf)) flags |= IF_UP; else flags &= ~IF_UP; @@ -301,6 +302,9 @@ if_update(struct iface *new) struct iface *i; unsigned c; + if (!new->master) + new->master = &default_vrf; + WALK_LIST(i, iface_list) if (!strcmp(new->name, i->name)) { @@ -711,6 +715,7 @@ if_init(void) { if_pool = rp_new(&root_pool, "Interfaces"); init_list(&iface_list); + strcpy(default_vrf.name, "default"); neigh_init(if_pool); } @@ -843,7 +848,7 @@ if_show(void) continue; char mbuf[16 + sizeof(i->name)] = {}; - if (i->master) + if (i->master != &default_vrf) bsprintf(mbuf, " master=%s", i->master->name); else if (i->master_index) bsprintf(mbuf, " master=#%u", i->master_index); diff --git a/nest/iface.h b/nest/iface.h index 1189cdd4..13f3bd12 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -28,6 +28,8 @@ struct ifa { /* Interface address */ unsigned flags; /* Analogous to iface->flags */ }; +extern struct iface default_vrf; + struct iface { node n; char name[16]; diff --git a/nest/neighbor.c b/nest/neighbor.c index 1a31fb79..cb2d1b2b 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -142,7 +142,7 @@ if_connected(ip_addr a, struct iface *i, struct ifa **ap, uint flags) } static inline int -if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **iface, struct ifa **addr, uint flags) +if_connected_any(ip_addr a, struct iface *vrf, struct iface **iface, struct ifa **addr, uint flags) { struct iface *i; struct ifa *b; @@ -153,7 +153,7 @@ if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **ifac /* Prefer SCOPE_HOST or longer prefix */ WALK_LIST(i, iface_list) - if ((!vrf_set || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0)) + if ((!vrf || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0)) if (scope_better(s, scope) || (scope_remote(s, scope) && ifa_better(b, *addr))) { *iface = i; @@ -245,7 +245,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags) iface = (scope < 0) ? NULL : iface; } else - scope = if_connected_any(a, p->vrf, p->vrf_set, &iface, &addr, flags); + scope = if_connected_any(a, p->vrf, &iface, &addr, flags); /* scope < 0 means i don't know neighbor */ /* scope >= 0 <=> iface != NULL */ @@ -369,7 +369,7 @@ neigh_update(neighbor *n, struct iface *iface) return; /* VRF-bound neighbors ignore changes in other VRFs */ - if (p->vrf_set && (p->vrf != iface->master)) + if (p->vrf && (p->vrf != iface->master)) return; scope = if_connected(n->addr, iface, &ifa, n->flags); @@ -379,7 +379,7 @@ neigh_update(neighbor *n, struct iface *iface) { /* When neighbor is going down, try to respawn it on other ifaces */ if ((scope < 0) && (n->scope >= 0) && !n->ifreq && (n->flags & NEF_STICKY)) - scope = if_connected_any(n->addr, p->vrf, p->vrf_set, &iface, &ifa, n->flags); + scope = if_connected_any(n->addr, p->vrf, &iface, &ifa, n->flags); } else { diff --git a/nest/proto.c b/nest/proto.c index b7dbae5e..8babedee 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1469,7 +1469,6 @@ proto_init(struct proto_config *c, node *n) p->proto_state = PS_DOWN; p->last_state_change = current_time(); p->vrf = c->vrf; - p->vrf_set = c->vrf_set; insert_node(&p->n, n); p->event = ev_new_init(proto_pool, proto_event, p); @@ -1654,8 +1653,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config if ((nc->protocol != oc->protocol) || (nc->net_type != oc->net_type) || (nc->disabled != p->disabled) || - (nc->vrf != oc->vrf) || - (nc->vrf_set != oc->vrf_set)) + (nc->vrf != oc->vrf)) return 0; p->name = nc->name; @@ -2626,8 +2624,8 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt) cli_msg(-1006, " Message: %s", p->message); if (p->cf->router_id) cli_msg(-1006, " Router ID: %R", p->cf->router_id); - if (p->vrf_set) - cli_msg(-1006, " VRF: %s", p->vrf ? p->vrf->name : "default"); + if (p->vrf) + cli_msg(-1006, " VRF: %s", p->vrf->name); if (p->proto->show_proto_info) p->proto->show_proto_info(p); diff --git a/nest/protocol.h b/nest/protocol.h index 8d077e44..1d4f2059 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -117,7 +117,6 @@ struct proto_config { int class; /* SYM_PROTO or SYM_TEMPLATE */ u8 net_type; /* Protocol network type (NET_*), 0 for undefined */ u8 disabled; /* Protocol enabled/disabled by default */ - u8 vrf_set; /* Related VRF instance (below) is defined */ u8 late_if_feed; /* Delay interface feed after channels are up */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ u32 router_id; /* Protocol specific router ID */ @@ -154,7 +153,6 @@ struct proto { uint active_coroutines; /* Number of active coroutines */ byte net_type; /* Protocol network type (NET_*), 0 for undefined */ byte disabled; /* Manually disabled */ - byte vrf_set; /* Related VRF instance (above) is defined */ byte proto_state; /* Protocol state machine (PS_*, see below) */ byte active; /* From PS_START to cleanup after PS_STOP */ byte do_stop; /* Stop actions are scheduled */ diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 3964c267..dd3488d4 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -658,7 +658,7 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req) { struct bfd_config *cf = (struct bfd_config *) (p->p.cf); - if (p->p.vrf_set && (p->p.vrf != req->vrf)) + if (p->p.vrf && (p->p.vrf != req->vrf)) return 0; if (ipa_is_ip4(req->addr) ? !cf->accept_ipv4 : !cf->accept_ipv6) -- cgit v1.2.3 From dc28c6ed1c6643ec19d2e8f94f92955f58c357a7 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 18 Aug 2022 18:32:33 +0200 Subject: Simplified the protocol hookup code in Makefiles --- Makefile.in | 11 +---------- nest/Makefile | 5 ++--- proto/babel/Makefile | 1 - proto/bfd/Makefile | 1 - proto/bgp/Makefile | 1 - proto/mrt/Makefile | 1 - proto/ospf/Makefile | 1 - proto/perf/Makefile | 1 - proto/pipe/Makefile | 1 - proto/radv/Makefile | 1 - proto/rip/Makefile | 1 - proto/rpki/Makefile | 1 - proto/static/Makefile | 1 - sysdep/unix/Makefile | 2 -- 14 files changed, 3 insertions(+), 26 deletions(-) (limited to 'nest') diff --git a/Makefile.in b/Makefile.in index 0d55807b..fa534872 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,6 +26,7 @@ INSTALL_DATA=@INSTALL_DATA@ client=$(addprefix $(exedir)/,@CLIENT@) daemon=$(exedir)/bird protocols=@protocols@ +PROTO_BUILD := $(protocols) dev kif krt prefix=@prefix@ exec_prefix=@exec_prefix@ @@ -82,9 +83,6 @@ conf-lex-targets := $(addprefix $(objdir)/conf/,cf-lex.o) conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h) cf-local = $(conf-y-targets): $(s)config.Y -# nest/Makefile declarations needed for all other modules -proto-build-c := $(addprefix $(objdir)/nest/,proto-build.c) - src-o-files = $(patsubst %.c,$(o)%.o,$(src)) tests-target-files = $(patsubst %.c,$(o)%,$(tests_src)) @@ -98,13 +96,6 @@ else o = $(patsubst $(srcdir)%,$(objdir)%,$(s)) endif -define proto-build_in = -PROTO_BUILD += $(1) -$(proto-build-c): $(lastword $(MAKEFILE_LIST)) -endef - -proto-build = $(eval $(call proto-build_in,$(1))) - define clean_in = clean:: rm -f $(addprefix $(o),$(1)) diff --git a/nest/Makefile b/nest/Makefile index 7d451ba4..a2e30ee2 100644 --- a/nest/Makefile +++ b/nest/Makefile @@ -2,11 +2,10 @@ src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,dev_build) -$(proto-build-c): $(lastword $(MAKEFILE_LIST)) +$(objdir)/nest/proto-build.c: $(lastword $(MAKEFILE_LIST)) $(E)echo GEN $@ - $(Q)echo "$(patsubst %,void %(void); ,$(PROTO_BUILD)) void protos_build_gen(void) { $(patsubst %, %(); ,$(PROTO_BUILD))}" > $@ + $(Q)echo "$(patsubst %,void %_build(void); ,$(PROTO_BUILD)) void protos_build_gen(void) { $(patsubst %, %_build(); ,$(PROTO_BUILD))}" > $@ tests_src := a-set_test.c a-path_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/proto/babel/Makefile b/proto/babel/Makefile index ae6aeaf2..06b58e95 100644 --- a/proto/babel/Makefile +++ b/proto/babel/Makefile @@ -2,6 +2,5 @@ src := babel.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,babel_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/bfd/Makefile b/proto/bfd/Makefile index dbdc0a09..d9aecfa9 100644 --- a/proto/bfd/Makefile +++ b/proto/bfd/Makefile @@ -2,6 +2,5 @@ src := bfd.c io.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,bfd_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/bgp/Makefile b/proto/bgp/Makefile index 2a4cc99c..f6a38678 100644 --- a/proto/bgp/Makefile +++ b/proto/bgp/Makefile @@ -2,6 +2,5 @@ src := attrs.c bgp.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,bgp_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/mrt/Makefile b/proto/mrt/Makefile index 000e1c1c..8cd44ac1 100644 --- a/proto/mrt/Makefile +++ b/proto/mrt/Makefile @@ -2,6 +2,5 @@ src := mrt.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,mrt_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/ospf/Makefile b/proto/ospf/Makefile index 85664543..015f394a 100644 --- a/proto/ospf/Makefile +++ b/proto/ospf/Makefile @@ -2,6 +2,5 @@ src := dbdes.c hello.c iface.c lsack.c lsalib.c lsreq.c lsupd.c neighbor.c ospf. obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,ospf_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/perf/Makefile b/proto/perf/Makefile index 42051f43..7877fb19 100644 --- a/proto/perf/Makefile +++ b/proto/perf/Makefile @@ -2,6 +2,5 @@ src := perf.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,perf_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/pipe/Makefile b/proto/pipe/Makefile index ba66027f..0d68db4c 100644 --- a/proto/pipe/Makefile +++ b/proto/pipe/Makefile @@ -2,6 +2,5 @@ src := pipe.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,pipe_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/radv/Makefile b/proto/radv/Makefile index 4780bee3..5c56fbf3 100644 --- a/proto/radv/Makefile +++ b/proto/radv/Makefile @@ -2,6 +2,5 @@ src := packets.c radv.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,radv_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/rip/Makefile b/proto/rip/Makefile index b9ff62d6..f4a6fa72 100644 --- a/proto/rip/Makefile +++ b/proto/rip/Makefile @@ -2,6 +2,5 @@ src := packets.c rip.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,rip_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/rpki/Makefile b/proto/rpki/Makefile index 8e3a2761..0f60b2a0 100644 --- a/proto/rpki/Makefile +++ b/proto/rpki/Makefile @@ -2,6 +2,5 @@ src := rpki.c packets.c tcp_transport.c ssh_transport.c transport.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,rpki_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/static/Makefile b/proto/static/Makefile index 26aed31f..de6e819b 100644 --- a/proto/static/Makefile +++ b/proto/static/Makefile @@ -2,6 +2,5 @@ src := static.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,static_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile index 51ab98a9..d0d36b5f 100644 --- a/sysdep/unix/Makefile +++ b/sysdep/unix/Makefile @@ -2,8 +2,6 @@ src := alloc.c io.c krt.c log.c main.c random.c obj := $(src-o-files) $(all-daemon) $(cf-local) -$(call proto-build,kif_build) -$(call proto-build,krt_build) $(conf-y-targets): $(s)krt.Y src := $(filter-out main.c, $(src)) -- cgit v1.2.3 From 974f16b1f70ae8b7fa4efa6a217988e1811069e7 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 9 Sep 2022 15:04:36 +0200 Subject: Created a dedicated settle timer structure --- conf/confbase.Y | 10 +++++++++ doc/bird.sgml | 17 +++++++-------- lib/settle.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ nest/config.Y | 6 ++---- nest/proto.c | 53 ++++++++++++++++++++--------------------------- nest/protocol.h | 7 +++---- 6 files changed, 110 insertions(+), 47 deletions(-) create mode 100644 lib/settle.h (limited to 'nest') diff --git a/conf/confbase.Y b/conf/confbase.Y index 241c332d..8e5da9e3 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -14,6 +14,7 @@ CF_HDR #include "conf/conf.h" #include "lib/resource.h" #include "lib/socket.h" +#include "lib/settle.h" #include "lib/timer.h" #include "lib/string.h" #include "nest/protocol.h" @@ -93,6 +94,7 @@ CF_DECLS struct proto_spec ps; struct channel_limit cl; struct timeformat *tf; + struct settle_config settle; struct adata *ad; struct bytestring *bs; } @@ -111,6 +113,7 @@ CF_DECLS %type expr bool pxlen4 %type