0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-18 09:08:42 +00:00

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
This commit is contained in:
Maria Matejka 2021-09-29 16:15:13 +02:00
parent c7d0c5b252
commit 878eeec12b
16 changed files with 504 additions and 242 deletions

View File

@ -1212,7 +1212,7 @@
INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */ INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */
NEVER_CONSTANT; NEVER_CONSTANT;
RTC(1); RTC(1);
struct rtable *table = rtc->table; rtable *table = rtc->table;
ACCESS_RTE; ACCESS_RTE;
ACCESS_EATTRS; ACCESS_EATTRS;
const net_addr *net = fs->rte->net; const net_addr *net = fs->rte->net;
@ -1244,7 +1244,7 @@
ARG(1, T_NET); ARG(1, T_NET);
ARG(2, T_INT); ARG(2, T_INT);
RTC(3); RTC(3);
struct rtable *table = rtc->table; rtable *table = rtc->table;
u32 as = v2.val.i; u32 as = v2.val.i;

View File

@ -172,7 +172,7 @@ proto_cf_find_channel(struct proto_config *pc, uint net_type)
* Returns pointer to channel or NULL * Returns pointer to channel or NULL
*/ */
struct channel * 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; struct channel *c;
@ -236,7 +236,9 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->channel = cf->channel; c->channel = cf->channel;
c->proto = p; c->proto = p;
c->table = cf->table->table; 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->in_filter = cf->in_filter;
c->out_filter = cf->out_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); CD(c, "Removed", c->name);
rt_unlock_table(c->table); RT_LOCKED(c->table, t)
rt_unlock_table(t);
rem_node(&c->n); rem_node(&c->n);
mb_free(c); mb_free(c);
} }
@ -391,7 +395,7 @@ static void
channel_roa_subscribe_filter(struct channel *c, int dir) channel_roa_subscribe_filter(struct channel *c, int dir)
{ {
const struct filter *f = dir ? c->in_filter : c->out_filter; const struct filter *f = dir ? c->in_filter : c->out_filter;
struct rtable *tab; rtable *tab;
int valid = 1, found = 0; int valid = 1, found = 0;
if ((f == FILTER_ACCEPT) || (f == FILTER_REJECT)) if ((f == FILTER_ACCEPT) || (f == FILTER_REJECT))
@ -560,11 +564,11 @@ channel_check_stopped(struct channel *c)
} }
void 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); mb_free(c->in_req.name);
c->in_req.name = NULL; c->in_req.name = NULL;
@ -661,17 +665,16 @@ channel_aux_stopped(void *data)
else else
c->in_table = NULL; c->in_table = NULL;
rfree(cat->tab->rp); rfree(cat->tab->priv.rp);
mb_free(cat); mb_free(cat);
return channel_check_stopped(c); channel_check_stopped(c);
} }
static void 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); struct channel_aux_table *cat = _cat;
ASSERT_DIE(cat->tab->delete_event); cat->push.hook = NULL;
} }
static void 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); struct channel_aux_table *cat = SKIP_BACK(struct channel_aux_table, get, req);
req->hook = NULL; req->hook = NULL;
if (cat->refeed_pending && !cat->tab->delete_event) int del;
{ RT_LOCKED(cat->tab, t)
cat->refeed_pending = 0; del = !!t->delete_event;
rt_request_export(cat->tab, req);
} if (del)
else return;
ASSERT_DIE(cat->tab->delete_event);
ASSERT_DIE(cat->refeed_pending);
cat->refeed_pending = 0;
rt_request_export(cat->tab, req);
} }
static void static void
channel_aux_stop(struct channel_aux_table *cat) channel_aux_stop(struct channel_aux_table *cat)
{ {
rt_stop_import(&cat->push, channel_aux_import_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->push_stopped = (event) {
.hook = channel_aux_import_stopped,
.data = cat,
.list = proto_event_list(cat->c->proto),
};
rt_stop_import(&cat->push, &cat->push_stopped);
rt_stop_export(&cat->get, channel_aux_export_stopped); rt_stop_export(&cat->get, channel_aux_export_stopped);
cat->tab->delete_event = ev_new_init(cat->tab->rp, channel_aux_stopped, cat);
rt_unlock_table(cat->tab);
} }
static void static void
@ -889,7 +903,6 @@ channel_setup_in_table(struct channel *c, int best)
c->in_table->c = c; c->in_table->c = c;
c->in_table->tab = rt_setup(c->proto->pool, &cat->tab_cf); 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_import(c->in_table->tab, &c->in_table->push);
rt_request_export(c->in_table->tab, &c->in_table->get); 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->c = c;
c->out_table->tab = rt_setup(c->proto->pool, &cat->tab_cf); 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_import(c->out_table->tab, &c->out_table->push);
rt_request_export(c->out_table->tab, &c->out_table->get); rt_request_export(c->out_table->tab, &c->out_table->get);
@ -993,7 +1005,14 @@ channel_do_stop(struct channel *c)
/* Stop import */ /* Stop import */
if (c->in_req.hook) 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; c->gr_wait = 0;
if (c->gr_lock) if (c->gr_lock)
@ -2339,7 +2358,7 @@ proto_do_start(struct proto *p)
{ {
p->active = 1; 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) if (!p->sources.class)
p->sources.class = &default_rte_owner_class; p->sources.class = &default_rte_owner_class;

View File

@ -18,7 +18,6 @@
struct iface; struct iface;
struct ifa; struct ifa;
struct rtable;
struct rte; struct rte;
struct neighbor; struct neighbor;
struct rta; struct rta;
@ -207,7 +206,7 @@ struct proto {
* rte_remove Called whenever a rte is removed from the routing table. * 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_better)(struct rte *, struct rte *);
int (*rte_mergable)(struct rte *, struct rte *); int (*rte_mergable)(struct rte *, struct rte *);
void (*rte_insert)(struct network *, struct rte *); void (*rte_insert)(struct network *, struct rte *);
@ -496,7 +495,7 @@ struct channel {
const struct channel_class *channel; const struct channel_class *channel;
struct proto *proto; struct proto *proto;
struct rtable *table; rtable *table;
const struct filter *in_filter; /* Input filter */ const struct filter *in_filter; /* Input filter */
const struct filter *out_filter; /* Output filter */ const struct filter *out_filter; /* Output filter */
struct bmap export_map; /* Keeps track which routes were really exported */ 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 */ btime last_state_change; /* Time of last state transition */
struct channel_aux_table *in_table; /* Internal table for received routes */ 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 reload_pending; /* Reloading and another reload is scheduled */
u8 refeed_pending; /* Refeeding and another refeed is scheduled */ u8 refeed_pending; /* Refeeding and another refeed is scheduled */
@ -570,6 +570,7 @@ struct channel_aux_table {
struct channel *c; struct channel *c;
struct rt_import_request push; struct rt_import_request push;
struct rt_export_request get; struct rt_export_request get;
event push_stopped;
rtable *tab; rtable *tab;
event *stop; event *stop;
u8 refeed_pending; 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) static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc)
{ return proto_cf_find_channel(pc, pc->net_type); } { 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_find_channel_by_name(struct proto *p, const char *n);
struct channel *proto_add_channel(struct proto *p, struct channel_config *cf); 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); int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);

View File

@ -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. * It's guaranteed that there is at most one RTE for every (prefix,proto) pair.
*/ */
struct rtable_config { typedef struct rtable_private {
node n; #define RTABLE_PUBLIC \
char *name; resource r; \
struct config *config; node n; /* Node in list of all tables */ \
struct rtable *table; struct birdloop *loop; /* This loop runs the table */ \
struct proto_config *krt_attached; /* Kernel syncer attached to this table */ char *name; /* Name of this table */ \
uint addr_type; /* Type of address data stored in table (NET_*) */ uint addr_type; /* Type of address data stored in table (NET_*) */ \
int gc_max_ops; /* Maximum number of operations before GC is run */ struct rtable_config *config; /* Configuration of this table */ \
int gc_min_time; /* Minimum time between two consecutive GC runs */ struct event *nhu_event; /* Event to update next hops */ \
byte sorted; /* Routes of network are sorted according to rte_better() */ _Atomic byte nhu_state; /* Next Hop Update state */ \
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 { RTABLE_PUBLIC;
resource r;
node n; /* Node in list of all tables */
pool *rp; /* Resource pool to allocate everything from, including itself */ pool *rp; /* Resource pool to allocate everything from, including itself */
struct slab *rte_slab; /* Slab to allocate route objects */ struct slab *rte_slab; /* Slab to allocate route objects */
struct fib fib; 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 */ int use_count; /* Number of protocols using this table */
u32 rt_count; /* Number of routes in the table */ u32 rt_count; /* Number of routes in the table */
@ -178,18 +169,15 @@ typedef struct rtable {
struct hmap id_map; struct hmap id_map;
struct hostcache *hostcache; struct hostcache *hostcache;
struct rtable_config *config; /* Configuration of this table */
struct event *prune_event; /* Event to prune abandoned routes */ struct event *prune_event; /* Event to prune abandoned routes */
struct event *ec_event; /* Event to prune finished exports */ struct event *ec_event; /* Event to prune finished exports */
struct event *hcu_event; /* Event to update host cache */ 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 */ struct event *delete_event; /* Event to delete the table */
btime last_rt_change; /* Last time when route changed */ btime last_rt_change; /* Last time when route changed */
btime base_settle_time; /* Start time of rtable settling interval */ btime base_settle_time; /* Start time of rtable settling interval */
btime gc_time; /* Time of last GC */ btime gc_time; /* Time of last GC */
int gc_counter; /* Number of operations since last GC */ int gc_counter; /* Number of operations since last GC */
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */ byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte nhu_state; /* Next Hop Update state */
byte cork_active; /* Congestion control activated */ byte cork_active; /* Congestion control activated */
@ -208,8 +196,35 @@ typedef struct rtable {
struct rt_pending_export *first_export; /* First export to announce */ struct rt_pending_export *first_export; /* First export to announce */
u64 next_export_seq; /* The next export will have this ID */ u64 next_export_seq; /* The next export will have this ID */
} rtable_private;
typedef union {
struct { RTABLE_PUBLIC };
rtable_private priv;
} rtable; } 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 { struct rt_subscription {
node n; node n;
rtable *tab; rtable *tab;
@ -244,7 +259,7 @@ struct hostentry {
ip_addr addr; /* IP address of host, part of key */ ip_addr addr; /* IP address of host, part of key */
ip_addr link; /* (link-local) IP address of host, used as gw ip_addr link; /* (link-local) IP address of host, used as gw
if host is directly attached */ 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 */ struct hostentry *next; /* Next in hash chain */
unsigned hash_key; /* Hash key */ unsigned hash_key; /* Hash key */
unsigned uc; /* Use count */ 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_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 */ 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 { 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_import(rtable *tab, struct rt_import_request *req);
void rt_request_export(rtable *tab, struct rt_export_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 *)); void rt_stop_export(struct rt_export_request *, void (*stopped)(struct rt_export_request *));
const char *rt_import_state_name(u8 state); const char *rt_import_state_name(u8 state);
@ -480,27 +495,27 @@ struct config;
void rt_init(void); void rt_init(void);
void rt_preconfig(struct config *); void rt_preconfig(struct config *);
void rt_commit(struct config *new, struct config *old); void rt_commit(struct config *new, struct config *old);
void rt_lock_table(rtable *); void rt_lock_table(rtable_private *);
void rt_unlock_table(rtable *); void rt_unlock_table(rtable_private *);
void rt_subscribe(rtable *tab, struct rt_subscription *s); void rt_subscribe(rtable *tab, struct rt_subscription *s);
void rt_unsubscribe(struct rt_subscription *s); void rt_unsubscribe(struct rt_subscription *s);
rtable *rt_setup(pool *, struct rtable_config *); 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(rtable_private *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_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; } { 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); } static inline net *net_get(rtable_private *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
void *net_route(rtable *tab, const net_addr *n); void *net_route(rtable_private *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn); 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); 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_begin(struct rt_import_request *);
void rt_refresh_end(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_dump(struct rte_storage *);
void rte_free(struct rte_storage *, rtable *); void rte_free(struct rte_storage *, rtable_private *);
struct rte_storage *rte_store(const rte *, net *net, rtable *); struct rte_storage *rte_store(const rte *, net *net, rtable_private *);
void rt_dump(rtable *); void rt_dump(rtable *);
void rt_dump_all(void); void rt_dump_all(void);
void rt_dump_hooks(rtable *); void rt_dump_hooks(rtable *);
@ -591,7 +606,7 @@ struct rte_src {
typedef struct rta { typedef struct rta {
struct rta *next, **pprev; /* Hash chain */ struct rta *next, **pprev; /* Hash chain */
_Atomic u32 uc; /* Use count */ u32 uc; /* Use count */
u32 hash_key; /* Hash over important fields */ u32 hash_key; /* Hash over important fields */
struct ea_list *eattrs; /* Extended Attribute chain */ struct ea_list *eattrs; /* Extended Attribute chain */
struct hostentry *hostentry; /* Hostentry for recursive next-hops */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */
@ -732,7 +747,7 @@ struct rte_owner_class {
struct rte_owner { struct rte_owner {
struct rte_owner_class *class; 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; HASH(struct rte_src) hash;
const char *name; const char *name;
u32 hash_key; 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) #define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
static inline int rta_is_cached(rta *r) { return r->cached; } 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); 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); 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 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; } static inline void rta_uncache(rta *r) { r->cached = 0; r->uc = 0; }

View File

@ -1287,7 +1287,7 @@ rta_lookup(rta *o)
for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next) for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next)
if (r->hash_key == h && rta_same(r, o)) if (r->hash_key == h && rta_same(r, o))
{ {
atomic_fetch_add_explicit(&r->uc, 1, memory_order_acq_rel); r->uc++;
RTA_UNLOCK; RTA_UNLOCK;
return r; return r;
} }
@ -1308,14 +1308,6 @@ rta_lookup(rta *o)
void void
rta__free(rta *a) 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); ASSERT(rta_cache_count && a->cached);
rta_cache_count--; rta_cache_count--;
*a->pprev = a->next; *a->pprev = a->next;
@ -1327,7 +1319,6 @@ rta__free(rta *a)
ea_free(a->eattrs); ea_free(a->eattrs);
a->cached = 0; a->cached = 0;
sl_free(rta_slab(a), a); sl_free(rta_slab(a), a);
RTA_UNLOCK;
} }
rta * rta *

View File

@ -239,11 +239,13 @@ rt_show_cleanup(struct cli *c)
/* Unlink the iterator */ /* Unlink the iterator */
if (d->table_open) 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 */ /* Unlock referenced tables */
WALK_LIST(tab, d->tables) WALK_LIST(tab, d->tables)
rt_unlock_table(tab->table); RT_LOCKED(tab->table, t)
rt_unlock_table(t);
} }
static void static void
@ -255,8 +257,6 @@ rt_show_cont(struct cli *c)
#else #else
unsigned max = 64; unsigned max = 64;
#endif #endif
struct fib *fib = &d->tab->table->fib;
struct fib_iterator *it = &d->fit;
if (d->running_on_config && (d->running_on_config != config)) if (d->running_on_config && (d->running_on_config != config))
{ {
@ -264,9 +264,14 @@ rt_show_cont(struct cli *c)
goto done; 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) 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_open = 1;
d->table_counter++; d->table_counter++;
d->kernel = rt_show_get_kernel(d); d->kernel = rt_show_get_kernel(d);
@ -284,6 +289,7 @@ rt_show_cont(struct cli *c)
if (!max--) if (!max--)
{ {
FIB_ITERATE_PUT(it); FIB_ITERATE_PUT(it);
RT_UNLOCK(d->tab->table);
return; return;
} }
rt_show_net(c, n, d); 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); d->net_counter - d->net_counter_last, d->tab->table->name);
} }
RT_UNLOCK(d->tab->table);
d->kernel = NULL; d->kernel = NULL;
d->table_open = 0; d->table_open = 0;
d->tab = NODE_NEXT(d->tab); d->tab = NODE_NEXT(d->tab);
@ -431,7 +439,8 @@ rt_show(struct rt_show_data *d)
if (!d->addr) if (!d->addr)
{ {
WALK_LIST(tab, d->tables) 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 */ /* There is at least one table */
d->tab = HEAD(d->tables); d->tab = HEAD(d->tables);
@ -446,13 +455,17 @@ rt_show(struct rt_show_data *d)
d->tab = tab; d->tab = tab;
d->kernel = rt_show_get_kernel(d); d->kernel = rt_show_get_kernel(d);
RT_LOCK(tab->table);
if (d->show_for) if (d->show_for)
n = net_route(tab->table, d->addr); n = net_route(RT_PRIV(tab->table), d->addr);
else else
n = net_find(tab->table, d->addr); n = net_find(RT_PRIV(tab->table), d->addr);
if (n) if (n)
rt_show_net(this_cli, n, d); rt_show_net(this_cli, n, d);
RT_UNLOCK(tab->table);
} }
if (d->rt_counter) if (d->rt_counter)

File diff suppressed because it is too large Load Diff

View File

@ -2140,7 +2140,7 @@ use_deterministic_med(struct rte_storage *r)
} }
int int
bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) bgp_rte_recalculate(rtable_private *table, net *net, rte *new, rte *old, rte *old_best)
{ {
rte *key = new ? new : old; rte *key = new ? new : old;
u32 lpref = key->attrs->pref; u32 lpref = key->attrs->pref;

View File

@ -1800,10 +1800,12 @@ bgp_channel_start(struct channel *C)
ip_addr src = p->local_ip; ip_addr src = p->local_ip;
if (c->igp_table_ip4) if (c->igp_table_ip4)
rt_lock_table(c->igp_table_ip4); RT_LOCKED(c->igp_table_ip4, t)
rt_lock_table(t);
if (c->igp_table_ip6) if (c->igp_table_ip6)
rt_lock_table(c->igp_table_ip6); RT_LOCKED(c->igp_table_ip6, t)
rt_lock_table(t);
c->pool = p->p.pool; // XXXX c->pool = p->p.pool; // XXXX
bgp_init_bucket_table(c); bgp_init_bucket_table(c);
@ -1884,10 +1886,12 @@ bgp_channel_cleanup(struct channel *C)
struct bgp_channel *c = (void *) C; struct bgp_channel *c = (void *) C;
if (c->igp_table_ip4) if (c->igp_table_ip4)
rt_unlock_table(c->igp_table_ip4); RT_LOCKED(c->igp_table_ip4, t)
rt_unlock_table(t);
if (c->igp_table_ip6) if (c->igp_table_ip6)
rt_unlock_table(c->igp_table_ip6); RT_LOCKED(c->igp_table_ip6, t)
rt_unlock_table(t);
c->index = 0; c->index = 0;

View File

@ -586,7 +586,7 @@ void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
int bgp_rte_better(struct rte *, struct rte *); int bgp_rte_better(struct rte *, struct rte *);
int bgp_rte_mergable(rte *pri, rte *sec); int bgp_rte_mergable(rte *pri, rte *sec);
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best); int bgp_rte_recalculate(rtable_private *table, net *net, rte *new, rte *old, rte *old_best);
void bgp_rte_modify_stale(struct rt_export_request *, const net_addr *, struct rt_pending_export *, rte **, uint); void bgp_rte_modify_stale(struct rt_export_request *, const net_addr *, struct rt_pending_export *, rte **, uint);
u32 bgp_rte_igp_metric(struct rte *); u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old); void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old);

View File

@ -228,7 +228,7 @@ mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
NODE_VALID(tn); NODE_VALID(tn);
tn = tn->next) tn = tn->next)
{ {
tab = SKIP_BACK(struct rtable, n, tn); tab = SKIP_BACK(rtable, n, tn);
if (patmatch(pattern, tab->name) && if (patmatch(pattern, tab->name) &&
((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6))) ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
return tab; return tab;
@ -243,13 +243,21 @@ mrt_next_table(struct mrt_table_dump_state *s)
rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr); rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
if (s->table) if (s->table)
rt_unlock_table(s->table); {
RT_LOCK(s->table);
rt_unlock_table(RT_PRIV(s->table));
RT_UNLOCK(s->table);
}
s->table = tab; s->table = tab;
s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0; s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
if (s->table) if (s->table)
rt_lock_table(s->table); {
RT_LOCK(s->table);
rt_lock_table(RT_PRIV(s->table));
RT_UNLOCK(s->table);
}
return s->table; return s->table;
} }
@ -573,14 +581,23 @@ mrt_table_dump_init(pool *pp)
static void static void
mrt_table_dump_free(struct mrt_table_dump_state *s) mrt_table_dump_free(struct mrt_table_dump_state *s)
{ {
if (s->table_open)
FIB_ITERATE_UNLINK(&s->fit, &s->table->fib);
if (s->table) if (s->table)
rt_unlock_table(s->table); {
RT_LOCK(s->table);
if (s->table_open)
FIB_ITERATE_UNLINK(&s->fit, &RT_PRIV(s->table)->fib);
rt_unlock_table(RT_PRIV(s->table));
RT_UNLOCK(s->table);
}
if (s->table_ptr) if (s->table_ptr)
rt_unlock_table(s->table_ptr); {
RT_LOCK(s->table_ptr);
rt_unlock_table(RT_PRIV(s->table_ptr));
RT_UNLOCK(s->table_ptr);
}
config_del_obstacle(s->config); config_del_obstacle(s->config);
@ -596,8 +613,14 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
s->max = 2048; s->max = 2048;
s->bws = &bws; s->bws = &bws;
rtable_private *tab;
if (s->table_open) if (s->table_open)
{
RT_LOCK(s->table);
tab = RT_PRIV(s->table);
goto step; goto step;
}
while (mrt_next_table(s)) while (mrt_next_table(s))
{ {
@ -606,15 +629,18 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
mrt_peer_table_dump(s); mrt_peer_table_dump(s);
FIB_ITERATE_INIT(&s->fit, &s->table->fib); RT_LOCK(s->table);
tab = RT_PRIV(s->table);
FIB_ITERATE_INIT(&s->fit, &tab->fib);
s->table_open = 1; s->table_open = 1;
step: step:
FIB_ITERATE_START(&s->table->fib, &s->fit, net, n) FIB_ITERATE_START(&tab->fib, &s->fit, net, n)
{ {
if (s->max < 0) if (s->max < 0)
{ {
FIB_ITERATE_PUT(&s->fit); FIB_ITERATE_PUT(&s->fit);
RT_UNLOCK(s->table);
return 0; return 0;
} }
@ -634,6 +660,7 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
mrt_peer_table_flush(s); mrt_peer_table_flush(s);
} }
RT_UNLOCK(s->table);
return 1; return 1;
} }
@ -661,7 +688,11 @@ mrt_timer(timer *t)
s->always_add_path = cf->always_add_path; s->always_add_path = cf->always_add_path;
if (s->table_ptr) if (s->table_ptr)
rt_lock_table(s->table_ptr); {
RT_LOCK(s->table_ptr);
rt_lock_table(RT_PRIV(s->table_ptr));
RT_UNLOCK(s->table_ptr);
}
p->table_dump = s; p->table_dump = s;
ev_schedule(p->event); ev_schedule(p->event);
@ -734,7 +765,11 @@ mrt_dump_cmd(struct mrt_dump_data *d)
s->filename = d->filename; s->filename = d->filename;
if (s->table_ptr) if (s->table_ptr)
rt_lock_table(s->table_ptr); {
RT_LOCK(s->table_ptr);
rt_lock_table(RT_PRIV(s->table_ptr));
RT_UNLOCK(s->table_ptr);
}
this_cli->cont = mrt_dump_cont; this_cli->cont = mrt_dump_cont;
this_cli->cleanup = mrt_dump_cleanup; this_cli->cleanup = mrt_dump_cleanup;

View File

@ -40,7 +40,7 @@ struct mrt_proto {
struct mrt_dump_data { struct mrt_dump_data {
const char *table_expr; const char *table_expr;
struct rtable *table_ptr; rtable *table_ptr;
const struct filter *filter; const struct filter *filter;
const char *filename; const char *filename;
}; };
@ -60,7 +60,7 @@ struct mrt_table_dump_state {
/* Configuration information */ /* Configuration information */
const char *table_expr; /* Wildcard for table name (or NULL) */ const char *table_expr; /* Wildcard for table name (or NULL) */
struct rtable *table_ptr; /* Explicit table (or NULL) */ rtable *table_ptr; /* Explicit table (or NULL) */
const struct filter *filter; /* Optional filter */ const struct filter *filter; /* Optional filter */
const char *filename; /* Filename pattern */ const char *filename; /* Filename pattern */
int always_add_path; /* Always use *_ADDPATH message subtypes */ int always_add_path; /* Always use *_ADDPATH message subtypes */
@ -73,7 +73,7 @@ struct mrt_table_dump_state {
HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */ HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */
struct rtable *table; /* Processed table, NULL initially */ rtable *table; /* Processed table, NULL initially */
struct fib_iterator fit; /* Iterator in processed table */ struct fib_iterator fit; /* Iterator in processed table */
int table_open; /* Whether iterator is linked */ int table_open; /* Whether iterator is linked */

View File

@ -198,7 +198,9 @@ perf_loop(void *data)
p->exp++; p->exp++;
} }
rt_schedule_prune(P->main_channel->table); RT_LOCK(P->main_channel->table);
rt_schedule_prune(RT_PRIV(P->main_channel->table));
RT_UNLOCK(P->main_channel->table);
ev_schedule(p->loop); ev_schedule(p->loop);
} }

View File

@ -555,7 +555,10 @@ radv_check_active(struct radv_proto *p)
return 1; return 1;
struct channel *c = p->p.main_channel; struct channel *c = p->p.main_channel;
return rt_examine(c->table, &cf->trigger, c, c->out_filter); RT_LOCK(c->table);
int active = rt_examine(RT_PRIV(c->table), &cf->trigger, c, c->out_filter);
RT_UNLOCK(c->table);
return active;
} }
static void static void

View File

@ -491,10 +491,12 @@ static_start(struct proto *P)
static_lp = lp_new(&root_pool, LP_GOOD_SIZE(1024)); static_lp = lp_new(&root_pool, LP_GOOD_SIZE(1024));
if (p->igp_table_ip4) if (p->igp_table_ip4)
rt_lock_table(p->igp_table_ip4); RT_LOCKED(p->igp_table_ip4, t)
rt_lock_table(t);
if (p->igp_table_ip6) if (p->igp_table_ip6)
rt_lock_table(p->igp_table_ip6); RT_LOCKED(p->igp_table_ip6, t)
rt_lock_table(t);
p->event = ev_new_init(p->p.pool, static_announce_marked, p); p->event = ev_new_init(p->p.pool, static_announce_marked, p);
@ -521,10 +523,12 @@ static_shutdown(struct proto *P)
static_reset_rte(p, r); static_reset_rte(p, r);
if (p->igp_table_ip4) if (p->igp_table_ip4)
rt_unlock_table(p->igp_table_ip4); RT_LOCKED(p->igp_table_ip4, t)
rt_unlock_table(t);
if (p->igp_table_ip6) if (p->igp_table_ip6)
rt_unlock_table(p->igp_table_ip6); RT_LOCKED(p->igp_table_ip6, t)
rt_unlock_table(t);
return PS_DOWN; return PS_DOWN;
} }

View File

@ -427,6 +427,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
#endif #endif
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
RT_LOCK(p->p.main_channel->table);
/* Deleting all routes if flush is requested */ /* Deleting all routes if flush is requested */
if (p->flush_routes) if (p->flush_routes)
goto delete; goto delete;
@ -435,7 +436,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
if (!p->ready) if (!p->ready)
goto ignore; goto ignore;
net *net = net_find(p->p.main_channel->table, e->net); net *net = net_find(RT_PRIV(p->p.main_channel->table), e->net);
if (!net || !krt_is_installed(p, net)) if (!net || !krt_is_installed(p, net))
goto delete; goto delete;
@ -481,6 +482,7 @@ delete:
goto done; goto done;
done: done:
RT_UNLOCK(p->p.main_channel->table);
lp_flush(krt_filter_lp); lp_flush(krt_filter_lp);
} }
@ -498,7 +500,8 @@ krt_init_scan(struct krt_proto *p)
static void static void
krt_prune(struct krt_proto *p) krt_prune(struct krt_proto *p)
{ {
struct rtable *t = p->p.main_channel->table; RT_LOCK(p->p.main_channel->table);
rtable_private *t = RT_PRIV(p->p.main_channel->table);
KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
FIB_WALK(&t->fib, net, n) FIB_WALK(&t->fib, net, n)
@ -518,6 +521,8 @@ krt_prune(struct krt_proto *p)
} }
FIB_WALK_END; FIB_WALK_END;
RT_UNLOCK(p->p.main_channel->table);
#ifdef KRT_ALLOW_LEARN #ifdef KRT_ALLOW_LEARN
if (KRT_CF->learn) if (KRT_CF->learn)
channel_refresh_end(p->p.main_channel); channel_refresh_end(p->p.main_channel);