mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Resource pools are now bound with domains.
Memory allocation is a fragile part of BIRD and we need checking that everybody is using the resource pools in an appropriate way. To assure this, all the resource pools are associated with locking domains and every resource manipulation is thoroughly checked whether the appropriate locking domain is locked. With transitive resource manipulation like resource dumping or mass free operations, domains are locked and unlocked on the go, thus we require pool domains to have higher order than their parent to allow for this transitive operations. Adding pool locking revealed some cases of insecure memory manipulation and this commit fixes that as well.
This commit is contained in:
parent
6230d87c74
commit
22f54eaee6
@ -90,7 +90,7 @@ int undo_available; /* Undo was not requested from last reconfiguration */
|
|||||||
struct config *
|
struct config *
|
||||||
config_alloc(const char *name)
|
config_alloc(const char *name)
|
||||||
{
|
{
|
||||||
pool *p = rp_new(config_pool, "Config");
|
pool *p = rp_new(config_pool, the_bird_domain.the_bird, "Config");
|
||||||
linpool *l = lp_new_default(p);
|
linpool *l = lp_new_default(p);
|
||||||
struct config *c = lp_allocz(l, sizeof(struct config));
|
struct config *c = lp_allocz(l, sizeof(struct config));
|
||||||
|
|
||||||
@ -515,7 +515,7 @@ config_timeout(timer *t UNUSED)
|
|||||||
void
|
void
|
||||||
config_init(void)
|
config_init(void)
|
||||||
{
|
{
|
||||||
config_pool = rp_new(&root_pool, "Configurations");
|
config_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Configurations");
|
||||||
|
|
||||||
config_event = ev_new(config_pool);
|
config_event = ev_new(config_pool);
|
||||||
config_event->hook = config_done;
|
config_event->hook = config_done;
|
||||||
|
@ -61,7 +61,7 @@ dump_nodes(void)
|
|||||||
static void
|
static void
|
||||||
init_hash_(uint order)
|
init_hash_(uint order)
|
||||||
{
|
{
|
||||||
my_pool = rp_new(&root_pool, "Test pool");
|
my_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Test pool");
|
||||||
|
|
||||||
HASH_INIT(hash, my_pool, order);
|
HASH_INIT(hash, my_pool, order);
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ event_list *birdloop_event_list(struct birdloop *loop);
|
|||||||
|
|
||||||
/* Get birdloop's time heap */
|
/* Get birdloop's time heap */
|
||||||
struct timeloop *birdloop_time_loop(struct birdloop *loop);
|
struct timeloop *birdloop_time_loop(struct birdloop *loop);
|
||||||
|
#define birdloop_domain(l) (birdloop_time_loop((l))->domain)
|
||||||
|
|
||||||
/* Get birdloop's pool */
|
/* Get birdloop's pool */
|
||||||
pool *birdloop_pool(struct birdloop *loop);
|
pool *birdloop_pool(struct birdloop *loop);
|
||||||
|
@ -13,8 +13,8 @@ struct domain_generic;
|
|||||||
|
|
||||||
/* Here define the global lock order; first to last. */
|
/* Here define the global lock order; first to last. */
|
||||||
struct lock_order {
|
struct lock_order {
|
||||||
struct domain_generic *meta;
|
|
||||||
struct domain_generic *the_bird;
|
struct domain_generic *the_bird;
|
||||||
|
struct domain_generic *meta;
|
||||||
struct domain_generic *control;
|
struct domain_generic *control;
|
||||||
struct domain_generic *proto;
|
struct domain_generic *proto;
|
||||||
struct domain_generic *service;
|
struct domain_generic *service;
|
||||||
|
139
lib/resource.c
139
lib/resource.c
@ -46,6 +46,16 @@ static struct resclass pool_class = {
|
|||||||
|
|
||||||
pool root_pool;
|
pool root_pool;
|
||||||
|
|
||||||
|
static void
|
||||||
|
rp_init(pool *z, struct domain_generic *dom, const char *name)
|
||||||
|
{
|
||||||
|
ASSERT_DIE(DG_IS_LOCKED(dom));
|
||||||
|
|
||||||
|
z->name = name;
|
||||||
|
z->domain = dom;
|
||||||
|
z->inside = (TLIST_LIST(resource)) {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rp_new - create a resource pool
|
* rp_new - create a resource pool
|
||||||
* @p: parent pool
|
* @p: parent pool
|
||||||
@ -55,77 +65,106 @@ pool root_pool;
|
|||||||
* parent pool.
|
* parent pool.
|
||||||
*/
|
*/
|
||||||
pool *
|
pool *
|
||||||
rp_new(pool *p, const char *name)
|
rp_new(pool *p, struct domain_generic *dom, const char *name)
|
||||||
{
|
{
|
||||||
pool *z = ralloc(p, &pool_class);
|
pool *z = ralloc(p, &pool_class);
|
||||||
z->name = name;
|
|
||||||
init_list(&z->inside);
|
if (dg_order(p->domain) > dg_order(dom))
|
||||||
|
bug("Requested reverse order pool creation: %s (%d) can't be a parent of %s (%d)",
|
||||||
|
domain_name(p->domain), dg_order(p->domain),
|
||||||
|
domain_name(dom), dg_order(dom));
|
||||||
|
|
||||||
|
if ((dg_order(p->domain) == dg_order(dom)) && (p->domain != dom))
|
||||||
|
bug("Requested incomparable order pool creation: %s (%d) can't be a parent of %s (%d)",
|
||||||
|
domain_name(p->domain), dg_order(p->domain),
|
||||||
|
domain_name(dom), dg_order(dom));
|
||||||
|
|
||||||
|
rp_init(z, dom, name);
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool *
|
pool *
|
||||||
rp_vnewf(pool *p, const char *fmt, va_list args)
|
rp_vnewf(pool *p, struct domain_generic *dom, const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
pool *z = rp_new(p, NULL);
|
pool *z = rp_new(p, dom, NULL);
|
||||||
z->name = mb_vsprintf(p, fmt, args);
|
z->name = mb_vsprintf(p, fmt, args);
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool *
|
pool *
|
||||||
rp_newf(pool *p, const char *fmt, ...)
|
rp_newf(pool *p, struct domain_generic *dom, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
pool *z = rp_vnewf(p, fmt, args);
|
pool *z = rp_vnewf(p, dom, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define POOL_LOCK \
|
||||||
|
struct domain_generic *dom = p->domain; \
|
||||||
|
int locking = !DG_IS_LOCKED(dom); \
|
||||||
|
if (locking) \
|
||||||
|
DG_LOCK(dom); \
|
||||||
|
|
||||||
|
#define POOL_UNLOCK if (locking) DG_UNLOCK(dom);\
|
||||||
|
|
||||||
|
void rp_free(pool *p)
|
||||||
|
{
|
||||||
|
ASSERT_DIE(DG_IS_LOCKED(p->domain));
|
||||||
|
rfree(p);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pool_free(resource *P)
|
pool_free(resource *P)
|
||||||
{
|
{
|
||||||
pool *p = (pool *) P;
|
pool *p = (pool *) P;
|
||||||
resource *r, *rr;
|
|
||||||
|
|
||||||
r = HEAD(p->inside);
|
POOL_LOCK;
|
||||||
while (rr = (resource *) r->n.next)
|
WALK_TLIST_DELSAFE(resource, r, &p->inside)
|
||||||
{
|
{
|
||||||
r->class->free(r);
|
r->class->free(r);
|
||||||
xfree(r);
|
xfree(r);
|
||||||
r = rr;
|
|
||||||
}
|
}
|
||||||
|
POOL_UNLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pool_dump(resource *P, unsigned indent)
|
pool_dump(resource *P, unsigned indent)
|
||||||
{
|
{
|
||||||
pool *p = (pool *) P;
|
pool *p = (pool *) P;
|
||||||
resource *r;
|
|
||||||
|
POOL_LOCK;
|
||||||
|
|
||||||
debug("%s\n", p->name);
|
debug("%s\n", p->name);
|
||||||
WALK_LIST(r, p->inside)
|
WALK_TLIST_DELSAFE(resource, r, &p->inside)
|
||||||
rdump(r, indent + 3);
|
rdump(r, indent + 3);
|
||||||
|
|
||||||
|
POOL_UNLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct resmem
|
static struct resmem
|
||||||
pool_memsize(resource *P)
|
pool_memsize(resource *P)
|
||||||
{
|
{
|
||||||
pool *p = (pool *) P;
|
pool *p = (pool *) P;
|
||||||
resource *r;
|
|
||||||
struct resmem sum = {
|
struct resmem sum = {
|
||||||
.effective = 0,
|
.effective = 0,
|
||||||
.overhead = sizeof(pool) + ALLOC_OVERHEAD,
|
.overhead = sizeof(pool) + ALLOC_OVERHEAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
WALK_LIST(r, p->inside)
|
POOL_LOCK;
|
||||||
|
|
||||||
|
WALK_TLIST(resource, r, &p->inside)
|
||||||
{
|
{
|
||||||
struct resmem add = rmemsize(r);
|
struct resmem add = rmemsize(r);
|
||||||
sum.effective += add.effective;
|
sum.effective += add.effective;
|
||||||
sum.overhead += add.overhead;
|
sum.overhead += add.overhead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POOL_UNLOCK;
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,14 +172,25 @@ static resource *
|
|||||||
pool_lookup(resource *P, unsigned long a)
|
pool_lookup(resource *P, unsigned long a)
|
||||||
{
|
{
|
||||||
pool *p = (pool *) P;
|
pool *p = (pool *) P;
|
||||||
resource *r, *q;
|
resource *q = NULL;
|
||||||
|
|
||||||
WALK_LIST(r, p->inside)
|
POOL_LOCK;
|
||||||
|
|
||||||
|
WALK_TLIST(resource, r, &p->inside)
|
||||||
if (r->class->lookup && (q = r->class->lookup(r, a)))
|
if (r->class->lookup && (q = r->class->lookup(r, a)))
|
||||||
return q;
|
break;
|
||||||
return NULL;
|
|
||||||
|
POOL_UNLOCK;
|
||||||
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pool *
|
||||||
|
resource_parent(resource *r)
|
||||||
|
{
|
||||||
|
return SKIP_BACK(pool, inside, resource_enlisted(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rmove - move a resource
|
* rmove - move a resource
|
||||||
* @res: resource
|
* @res: resource
|
||||||
@ -152,13 +202,13 @@ pool_lookup(resource *P, unsigned long a)
|
|||||||
void rmove(void *res, pool *p)
|
void rmove(void *res, pool *p)
|
||||||
{
|
{
|
||||||
resource *r = res;
|
resource *r = res;
|
||||||
|
pool *orig = resource_parent(r);
|
||||||
|
|
||||||
if (r)
|
ASSERT_DIE(DG_IS_LOCKED(orig->domain));
|
||||||
{
|
ASSERT_DIE(DG_IS_LOCKED(p->domain));
|
||||||
if (r->n.next)
|
|
||||||
rem_node(&r->n);
|
resource_rem_node(&orig->inside, r);
|
||||||
add_tail(&p->inside, &r->n);
|
resource_add_tail(&p->inside, r);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,8 +229,10 @@ rfree(void *res)
|
|||||||
if (!r)
|
if (!r)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (r->n.next)
|
pool *orig = resource_parent(r);
|
||||||
rem_node(&r->n);
|
ASSERT_DIE(DG_IS_LOCKED(orig->domain));
|
||||||
|
resource_rem_node(&orig->inside, r);
|
||||||
|
|
||||||
r->class->free(r);
|
r->class->free(r);
|
||||||
r->class = NULL;
|
r->class = NULL;
|
||||||
xfree(r);
|
xfree(r);
|
||||||
@ -239,12 +291,14 @@ rmemsize(void *res)
|
|||||||
void *
|
void *
|
||||||
ralloc(pool *p, struct resclass *c)
|
ralloc(pool *p, struct resclass *c)
|
||||||
{
|
{
|
||||||
|
ASSERT_DIE(DG_IS_LOCKED(p->domain));
|
||||||
|
|
||||||
resource *r = xmalloc(c->size);
|
resource *r = xmalloc(c->size);
|
||||||
bzero(r, c->size);
|
bzero(r, c->size);
|
||||||
|
|
||||||
r->class = c;
|
r->class = c;
|
||||||
if (p)
|
resource_add_tail(&p->inside, r);
|
||||||
add_tail(&p->inside, &r->n);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,28 +338,29 @@ resource_init(void)
|
|||||||
rcu_init();
|
rcu_init();
|
||||||
resource_sys_init();
|
resource_sys_init();
|
||||||
|
|
||||||
root_pool.r.class = &pool_class;
|
rp_init(&root_pool, the_bird_domain.the_bird, "Root");
|
||||||
root_pool.name = "Root";
|
tmp_init(&root_pool, the_bird_domain.the_bird);
|
||||||
init_list(&root_pool.inside);
|
|
||||||
tmp_init(&root_pool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_Thread_local struct tmp_resources tmp_res;
|
_Thread_local struct tmp_resources tmp_res;
|
||||||
|
|
||||||
void
|
void
|
||||||
tmp_init(pool *p)
|
tmp_init(pool *p, struct domain_generic *dom)
|
||||||
{
|
{
|
||||||
tmp_res.lp = lp_new_default(p);
|
tmp_res.lp = lp_new_default(p);
|
||||||
tmp_res.parent = p;
|
tmp_res.parent = p;
|
||||||
tmp_res.pool = rp_new(p, "TMP");
|
tmp_res.pool = rp_new(p, dom, "TMP");
|
||||||
|
tmp_res.domain = dom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tmp_flush(void)
|
tmp_flush(void)
|
||||||
{
|
{
|
||||||
|
ASSERT_DIE(DG_IS_LOCKED(tmp_res.domain));
|
||||||
|
|
||||||
lp_flush(tmp_linpool);
|
lp_flush(tmp_linpool);
|
||||||
rp_free(tmp_res.pool);
|
rp_free(tmp_res.pool);
|
||||||
tmp_res.pool = rp_new(tmp_res.parent, "TMP");
|
tmp_res.pool = rp_new(tmp_res.parent, tmp_res.domain, "TMP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -385,11 +440,13 @@ static struct resclass mb_class = {
|
|||||||
void *
|
void *
|
||||||
mb_alloc(pool *p, unsigned size)
|
mb_alloc(pool *p, unsigned size)
|
||||||
{
|
{
|
||||||
|
ASSERT_DIE(DG_IS_LOCKED(p->domain));
|
||||||
|
|
||||||
struct mblock *b = xmalloc(sizeof(struct mblock) + size);
|
struct mblock *b = xmalloc(sizeof(struct mblock) + size);
|
||||||
|
|
||||||
b->r.class = &mb_class;
|
b->r.class = &mb_class;
|
||||||
b->r.n = (node) {};
|
b->r.n = (struct resource_node) {};
|
||||||
add_tail(&p->inside, &b->r.n);
|
resource_add_tail(&p->inside, &b->r);
|
||||||
b->size = size;
|
b->size = size;
|
||||||
return b->data;
|
return b->data;
|
||||||
}
|
}
|
||||||
@ -434,10 +491,14 @@ void *
|
|||||||
mb_realloc(void *m, unsigned size)
|
mb_realloc(void *m, unsigned size)
|
||||||
{
|
{
|
||||||
struct mblock *b = SKIP_BACK(struct mblock, data, m);
|
struct mblock *b = SKIP_BACK(struct mblock, data, m);
|
||||||
|
struct pool *p = resource_parent(&b->r);
|
||||||
|
|
||||||
|
ASSERT_DIE(DG_IS_LOCKED(p->domain));
|
||||||
|
|
||||||
b = xrealloc(b, sizeof(struct mblock) + size);
|
b = xrealloc(b, sizeof(struct mblock) + size);
|
||||||
update_node(&b->r.n);
|
|
||||||
b->size = size;
|
b->size = size;
|
||||||
|
|
||||||
|
resource_update_node(&p->inside, &b->r);
|
||||||
return b->data;
|
return b->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
#ifndef _BIRD_RESOURCE_H_
|
#ifndef _BIRD_RESOURCE_H_
|
||||||
#define _BIRD_RESOURCE_H_
|
#define _BIRD_RESOURCE_H_
|
||||||
|
|
||||||
#include "lib/lists.h"
|
#include "lib/locking.h"
|
||||||
|
#include "lib/tlists.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
@ -21,11 +22,20 @@ struct resmem {
|
|||||||
|
|
||||||
/* Resource */
|
/* Resource */
|
||||||
|
|
||||||
|
#define TLIST_PREFIX resource
|
||||||
|
#define TLIST_TYPE struct resource
|
||||||
|
#define TLIST_ITEM n
|
||||||
|
#define TLIST_WANT_WALK
|
||||||
|
#define TLIST_WANT_ADD_TAIL
|
||||||
|
#define TLIST_WANT_UPDATE_NODE
|
||||||
|
|
||||||
typedef struct resource {
|
typedef struct resource {
|
||||||
node n; /* Inside resource pool */
|
TLIST_DEFAULT_NODE; /* Inside resource pool */
|
||||||
struct resclass *class; /* Resource class */
|
const struct resclass *class; /* Resource class */
|
||||||
} resource;
|
} resource;
|
||||||
|
|
||||||
|
#include "lib/tlists.h"
|
||||||
|
|
||||||
/* Resource class */
|
/* Resource class */
|
||||||
|
|
||||||
struct resclass {
|
struct resclass {
|
||||||
@ -44,14 +54,13 @@ struct resclass {
|
|||||||
|
|
||||||
typedef struct pool {
|
typedef struct pool {
|
||||||
resource r;
|
resource r;
|
||||||
list inside;
|
TLIST_LIST(resource) inside;
|
||||||
|
struct domain_generic *domain;
|
||||||
const char *name;
|
const char *name;
|
||||||
} pool;
|
} pool;
|
||||||
|
|
||||||
|
|
||||||
void resource_init(void);
|
void resource_init(void);
|
||||||
pool *rp_new(pool *, const char *); /* Create new pool */
|
|
||||||
pool *rp_newf(pool *, const char *, ...); /* Create a new pool with a formatted string as its name */
|
|
||||||
void rfree(void *); /* Free single resource */
|
void rfree(void *); /* Free single resource */
|
||||||
void rdump(void *, unsigned indent); /* Dump to debug output */
|
void rdump(void *, unsigned indent); /* Dump to debug output */
|
||||||
struct resmem rmemsize(void *res); /* Return size of memory used by the resource */
|
struct resmem rmemsize(void *res); /* Return size of memory used by the resource */
|
||||||
@ -60,12 +69,10 @@ void rmove(void *, pool *); /* Move to a different pool */
|
|||||||
|
|
||||||
void *ralloc(pool *, struct resclass *);
|
void *ralloc(pool *, struct resclass *);
|
||||||
|
|
||||||
pool *rp_new(pool *, const char *); /* Create a new pool */
|
pool *rp_new(pool *, struct domain_generic *, const char *); /* Create a new pool */
|
||||||
pool *rp_newf(pool *, const char *, ...); /* Create a new pool with a formatted string as its name */
|
pool *rp_newf(pool *, struct domain_generic *, const char *, ...); /* Create a new pool with a formatted string as its name */
|
||||||
pool *rp_vnewf(pool *, const char *, va_list); /* Create a new pool with a formatted string as its name */
|
pool *rp_vnewf(pool *, struct domain_generic *, const char *, va_list); /* Create a new pool with a formatted string as its name */
|
||||||
void rp_init(pool *, const char *); /* Init a new pool */
|
void rp_free(pool *p); /* Free the whole pool */
|
||||||
void rp_initf(pool *, const char *, ...); /* Init a new pool with a formatted string as its name */
|
|
||||||
static inline void rp_free(pool *p) { rfree(&p->r); } /* Free the whole pool */
|
|
||||||
|
|
||||||
extern pool root_pool;
|
extern pool root_pool;
|
||||||
|
|
||||||
@ -97,6 +104,7 @@ void lp_restore(linpool *m, lp_state *p); /* Restore state */
|
|||||||
struct tmp_resources {
|
struct tmp_resources {
|
||||||
pool *pool, *parent;
|
pool *pool, *parent;
|
||||||
linpool *lp;
|
linpool *lp;
|
||||||
|
struct domain_generic *domain;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern _Thread_local struct tmp_resources tmp_res;
|
extern _Thread_local struct tmp_resources tmp_res;
|
||||||
@ -106,7 +114,7 @@ extern _Thread_local struct tmp_resources tmp_res;
|
|||||||
#define tmp_allocu(sz) lp_allocu(tmp_linpool, sz)
|
#define tmp_allocu(sz) lp_allocu(tmp_linpool, sz)
|
||||||
#define tmp_allocz(sz) lp_allocz(tmp_linpool, sz)
|
#define tmp_allocz(sz) lp_allocz(tmp_linpool, sz)
|
||||||
|
|
||||||
void tmp_init(pool *p);
|
void tmp_init(pool *p, struct domain_generic *dg);
|
||||||
void tmp_flush(void);
|
void tmp_flush(void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ cli_command(struct cli *c)
|
|||||||
log(L_TRACE "CLI: %s", c->rx_buf);
|
log(L_TRACE "CLI: %s", c->rx_buf);
|
||||||
bzero(&f, sizeof(f));
|
bzero(&f, sizeof(f));
|
||||||
f.mem = c->parser_pool;
|
f.mem = c->parser_pool;
|
||||||
f.pool = rp_new(c->pool, "Config");
|
f.pool = rp_new(c->pool, the_bird_domain.the_bird, "Config");
|
||||||
init_list(&f.symbols);
|
init_list(&f.symbols);
|
||||||
cf_read_hook = cli_cmd_read_hook;
|
cf_read_hook = cli_cmd_read_hook;
|
||||||
cli_rh_pos = c->rx_buf;
|
cli_rh_pos = c->rx_buf;
|
||||||
@ -309,7 +309,7 @@ cli_event(void *data)
|
|||||||
cli *
|
cli *
|
||||||
cli_new(struct birdsock *sock)
|
cli_new(struct birdsock *sock)
|
||||||
{
|
{
|
||||||
pool *p = rp_new(cli_pool, "CLI");
|
pool *p = rp_new(cli_pool, the_bird_domain.the_bird, "CLI");
|
||||||
cli *c = mb_alloc(p, sizeof(cli));
|
cli *c = mb_alloc(p, sizeof(cli));
|
||||||
|
|
||||||
bzero(c, sizeof(cli));
|
bzero(c, sizeof(cli));
|
||||||
@ -433,7 +433,7 @@ cli_free(cli *c)
|
|||||||
void
|
void
|
||||||
cli_init(void)
|
cli_init(void)
|
||||||
{
|
{
|
||||||
cli_pool = rp_new(&root_pool, "CLI");
|
cli_pool = rp_new(&root_pool, the_bird_domain.the_bird, "CLI");
|
||||||
init_list(&cli_log_hooks);
|
init_list(&cli_log_hooks);
|
||||||
cli_log_inited = 1;
|
cli_log_inited = 1;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define _BIRD_CLI_H_
|
#define _BIRD_CLI_H_
|
||||||
|
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
|
#include "lib/lists.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
|
||||||
#define CLI_RX_BUF_SIZE 4096
|
#define CLI_RX_BUF_SIZE 4096
|
||||||
|
@ -1018,12 +1018,15 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id)
|
|||||||
void
|
void
|
||||||
if_init(void)
|
if_init(void)
|
||||||
{
|
{
|
||||||
if_pool = rp_new(&root_pool, "Interfaces");
|
iface_domain = DOMAIN_NEW(attrs, "Interfaces");
|
||||||
|
|
||||||
|
IFACE_LOCK;
|
||||||
|
if_pool = rp_new(&root_pool, iface_domain.attrs, "Interfaces");
|
||||||
init_list(&global_iface_list);
|
init_list(&global_iface_list);
|
||||||
iface_sub_slab = sl_new(if_pool, sizeof(struct iface_notification));
|
iface_sub_slab = sl_new(if_pool, sizeof(struct iface_notification));
|
||||||
strcpy(default_vrf.name, "default");
|
strcpy(default_vrf.name, "default");
|
||||||
neigh_init(if_pool);
|
neigh_init(if_pool);
|
||||||
iface_domain = DOMAIN_NEW(attrs, "Interfaces");
|
IFACE_UNLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define _BIRD_LOCKS_H_
|
#define _BIRD_LOCKS_H_
|
||||||
|
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
|
#include "lib/lists.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#ifndef PASSWORD_H
|
#ifndef PASSWORD_H
|
||||||
#define PASSWORD_H
|
#define PASSWORD_H
|
||||||
|
|
||||||
|
#include "lib/lists.h"
|
||||||
|
|
||||||
struct password_item {
|
struct password_item {
|
||||||
node n;
|
node n;
|
||||||
const char *password; /* Key data, null terminated */
|
const char *password; /* Key data, null terminated */
|
||||||
|
12
nest/proto.c
12
nest/proto.c
@ -367,6 +367,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
|
|||||||
.name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
|
.name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
|
||||||
c->proto->name, c->name, dir ? "in" : "out", tab->name),
|
c->proto->name, c->name, dir ? "in" : "out", tab->name),
|
||||||
.list = proto_work_list(c->proto),
|
.list = proto_work_list(c->proto),
|
||||||
|
.pool = c->proto->pool,
|
||||||
.trace_routes = c->debug | c->proto->debug,
|
.trace_routes = c->debug | c->proto->debug,
|
||||||
.dump_req = channel_dump_roa_req,
|
.dump_req = channel_dump_roa_req,
|
||||||
.export_one = channel_export_one_roa,
|
.export_one = channel_export_one_roa,
|
||||||
@ -495,6 +496,7 @@ channel_start_export(struct channel *c)
|
|||||||
c->out_req = (struct rt_export_request) {
|
c->out_req = (struct rt_export_request) {
|
||||||
.name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
|
.name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
|
||||||
.list = proto_work_list(c->proto),
|
.list = proto_work_list(c->proto),
|
||||||
|
.pool = c->proto->pool,
|
||||||
.addr = c->out_subprefix,
|
.addr = c->out_subprefix,
|
||||||
.addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
|
.addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
|
||||||
.trace_routes = c->debug | c->proto->debug,
|
.trace_routes = c->debug | c->proto->debug,
|
||||||
@ -685,6 +687,7 @@ channel_setup_in_table(struct channel *c)
|
|||||||
c->reload_req = (struct rt_export_request) {
|
c->reload_req = (struct rt_export_request) {
|
||||||
.name = mb_sprintf(c->proto->pool, "%s.%s.import", c->proto->name, c->name),
|
.name = mb_sprintf(c->proto->pool, "%s.%s.import", c->proto->name, c->name),
|
||||||
.list = proto_work_list(c->proto),
|
.list = proto_work_list(c->proto),
|
||||||
|
.pool = c->proto->pool,
|
||||||
.trace_routes = c->debug | c->proto->debug,
|
.trace_routes = c->debug | c->proto->debug,
|
||||||
.export_bulk = channel_reload_export_bulk,
|
.export_bulk = channel_reload_export_bulk,
|
||||||
.dump_req = channel_reload_dump_req,
|
.dump_req = channel_reload_dump_req,
|
||||||
@ -1132,15 +1135,14 @@ proto_loop_stopped(void *ptr)
|
|||||||
{
|
{
|
||||||
struct proto *p = ptr;
|
struct proto *p = ptr;
|
||||||
|
|
||||||
birdloop_enter(&main_birdloop);
|
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
||||||
|
ASSERT_DIE(p->loop != &main_birdloop);
|
||||||
|
|
||||||
p->pool = NULL; /* is freed by birdloop_free() */
|
p->pool = NULL; /* is freed by birdloop_free() */
|
||||||
birdloop_free(p->loop);
|
birdloop_free(p->loop);
|
||||||
p->loop = &main_birdloop;
|
p->loop = &main_birdloop;
|
||||||
|
|
||||||
proto_cleanup(p);
|
proto_cleanup(p);
|
||||||
|
|
||||||
birdloop_leave(&main_birdloop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1228,7 +1230,7 @@ proto_start(struct proto *p)
|
|||||||
p->pool = birdloop_pool(p->loop);
|
p->pool = birdloop_pool(p->loop);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
p->pool = rp_newf(proto_pool, "Protocol %s", p->cf->name);
|
p->pool = rp_newf(proto_pool, the_bird_domain.the_bird, "Protocol %s", p->cf->name);
|
||||||
|
|
||||||
p->iface_sub.target = proto_event_list(p);
|
p->iface_sub.target = proto_event_list(p);
|
||||||
|
|
||||||
@ -1859,7 +1861,7 @@ protos_build(void)
|
|||||||
{
|
{
|
||||||
protos_build_gen();
|
protos_build_gen();
|
||||||
|
|
||||||
proto_pool = rp_new(&root_pool, "Protocols");
|
proto_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Protocols");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,6 +280,8 @@ struct proto *proto_iterate_named(struct symbol *sym, struct protocol *proto, st
|
|||||||
|
|
||||||
#define PROTO_LOCKED_FROM_MAIN(p) for (struct birdloop *_proto_loop = PROTO_ENTER_FROM_MAIN(p); _proto_loop; PROTO_LEAVE_FROM_MAIN(_proto_loop), (_proto_loop = NULL))
|
#define PROTO_LOCKED_FROM_MAIN(p) for (struct birdloop *_proto_loop = PROTO_ENTER_FROM_MAIN(p); _proto_loop; PROTO_LEAVE_FROM_MAIN(_proto_loop), (_proto_loop = NULL))
|
||||||
|
|
||||||
|
static inline struct domain_generic *proto_domain(struct proto *p)
|
||||||
|
{ return birdloop_domain(p->loop); }
|
||||||
|
|
||||||
#define CMD_RELOAD 0
|
#define CMD_RELOAD 0
|
||||||
#define CMD_RELOAD_IN 1
|
#define CMD_RELOAD_IN 1
|
||||||
|
@ -605,9 +605,16 @@ ea_register(pool *p, struct ea_class *def)
|
|||||||
struct ea_class_ref *
|
struct ea_class_ref *
|
||||||
ea_register_alloc(pool *p, struct ea_class cl)
|
ea_register_alloc(pool *p, struct ea_class cl)
|
||||||
{
|
{
|
||||||
|
struct ea_class_ref *ref;
|
||||||
|
|
||||||
|
RTA_LOCK;
|
||||||
struct ea_class *clp = ea_class_find_by_name(cl.name);
|
struct ea_class *clp = ea_class_find_by_name(cl.name);
|
||||||
if (clp && clp->type == cl.type)
|
if (clp && clp->type == cl.type)
|
||||||
return ea_ref_class(p, clp);
|
{
|
||||||
|
ref = ea_ref_class(p, clp);
|
||||||
|
RTA_UNLOCK;
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
uint namelen = strlen(cl.name) + 1;
|
uint namelen = strlen(cl.name) + 1;
|
||||||
|
|
||||||
@ -619,14 +626,18 @@ ea_register_alloc(pool *p, struct ea_class cl)
|
|||||||
memcpy(cla->name, cl.name, namelen);
|
memcpy(cla->name, cl.name, namelen);
|
||||||
cla->cl.name = cla->name;
|
cla->cl.name = cla->name;
|
||||||
|
|
||||||
return ea_register(p, &cla->cl);
|
ref = ea_register(p, &cla->cl);
|
||||||
|
RTA_UNLOCK;
|
||||||
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ea_register_init(struct ea_class *clp)
|
ea_register_init(struct ea_class *clp)
|
||||||
{
|
{
|
||||||
|
RTA_LOCK;
|
||||||
ASSERT_DIE(!ea_class_find_by_name(clp->name));
|
ASSERT_DIE(!ea_class_find_by_name(clp->name));
|
||||||
ea_register(&root_pool, clp);
|
ea_register(&root_pool, clp);
|
||||||
|
RTA_UNLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ea_class *
|
struct ea_class *
|
||||||
@ -1598,7 +1609,8 @@ rta_init(void)
|
|||||||
{
|
{
|
||||||
attrs_domain = DOMAIN_NEW(attrs, "Attributes");
|
attrs_domain = DOMAIN_NEW(attrs, "Attributes");
|
||||||
|
|
||||||
rta_pool = rp_new(&root_pool, "Attributes");
|
RTA_LOCK;
|
||||||
|
rta_pool = rp_new(&root_pool, attrs_domain.attrs, "Attributes");
|
||||||
|
|
||||||
for (uint i=0; i<ARRAY_SIZE(ea_slab_sizes); i++)
|
for (uint i=0; i<ARRAY_SIZE(ea_slab_sizes); i++)
|
||||||
ea_slab[i] = sl_new(rta_pool, ea_slab_sizes[i]);
|
ea_slab[i] = sl_new(rta_pool, ea_slab_sizes[i]);
|
||||||
@ -1607,6 +1619,8 @@ rta_init(void)
|
|||||||
rte_src_init();
|
rte_src_init();
|
||||||
ea_class_init();
|
ea_class_init();
|
||||||
|
|
||||||
|
RTA_UNLOCK;
|
||||||
|
|
||||||
/* These attributes are required to be first for nice "show route" output */
|
/* These attributes are required to be first for nice "show route" output */
|
||||||
ea_register_init(&ea_gen_nexthop);
|
ea_register_init(&ea_gen_nexthop);
|
||||||
ea_register_init(&ea_gen_hostentry);
|
ea_register_init(&ea_gen_hostentry);
|
||||||
|
@ -288,6 +288,7 @@ rt_show_cont(struct rt_show_data *d)
|
|||||||
.addr = d->addr,
|
.addr = d->addr,
|
||||||
.name = "CLI Show Route",
|
.name = "CLI Show Route",
|
||||||
.list = &global_work_list,
|
.list = &global_work_list,
|
||||||
|
.pool = c->pool,
|
||||||
.export_bulk = rt_show_net_export_bulk,
|
.export_bulk = rt_show_net_export_bulk,
|
||||||
.dump_req = rt_show_dump_req,
|
.dump_req = rt_show_dump_req,
|
||||||
.log_state_change = rt_show_log_state_change,
|
.log_state_change = rt_show_log_state_change,
|
||||||
|
@ -2131,7 +2131,7 @@ rt_table_export_start_locked(struct rtable_private *tab, struct rt_export_reques
|
|||||||
struct rt_exporter *re = &tab->exporter.e;
|
struct rt_exporter *re = &tab->exporter.e;
|
||||||
rt_lock_table(tab);
|
rt_lock_table(tab);
|
||||||
|
|
||||||
req->hook = rt_alloc_export(re, sizeof(struct rt_table_export_hook));
|
req->hook = rt_alloc_export(re, req->pool, sizeof(struct rt_table_export_hook));
|
||||||
req->hook->req = req;
|
req->hook->req = req;
|
||||||
|
|
||||||
struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, req->hook);
|
struct rt_table_export_hook *hook = SKIP_BACK(struct rt_table_export_hook, h, req->hook);
|
||||||
@ -2212,9 +2212,9 @@ rt_request_export_other(struct rt_exporter *re, struct rt_export_request *req)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct rt_export_hook *
|
struct rt_export_hook *
|
||||||
rt_alloc_export(struct rt_exporter *re, uint size)
|
rt_alloc_export(struct rt_exporter *re, pool *pp, uint size)
|
||||||
{
|
{
|
||||||
pool *p = rp_new(re->rp, "Export hook");
|
pool *p = rp_new(pp, pp->domain, "Export hook");
|
||||||
struct rt_export_hook *hook = mb_allocz(p, size);
|
struct rt_export_hook *hook = mb_allocz(p, size);
|
||||||
|
|
||||||
hook->pool = p;
|
hook->pool = p;
|
||||||
@ -2709,13 +2709,14 @@ rt_flowspec_link(rtable *src_pub, rtable *dst_pub)
|
|||||||
|
|
||||||
if (!ln)
|
if (!ln)
|
||||||
{
|
{
|
||||||
pool *p = src->rp;
|
pool *p = birdloop_pool(dst_pub->loop);
|
||||||
ln = mb_allocz(p, sizeof(struct rt_flowspec_link));
|
ln = mb_allocz(p, sizeof(struct rt_flowspec_link));
|
||||||
ln->src = src_pub;
|
ln->src = src_pub;
|
||||||
ln->dst = dst_pub;
|
ln->dst = dst_pub;
|
||||||
ln->req = (struct rt_export_request) {
|
ln->req = (struct rt_export_request) {
|
||||||
.name = mb_sprintf(p, "%s.flowspec.notifier", dst_pub->name),
|
.name = mb_sprintf(p, "%s.flowspec.notifier", dst_pub->name),
|
||||||
.list = birdloop_event_list(dst_pub->loop),
|
.list = birdloop_event_list(dst_pub->loop),
|
||||||
|
.pool = p,
|
||||||
.trace_routes = src->config->debug,
|
.trace_routes = src->config->debug,
|
||||||
.dump_req = rt_flowspec_dump_req,
|
.dump_req = rt_flowspec_dump_req,
|
||||||
.log_state_change = rt_flowspec_log_state_change,
|
.log_state_change = rt_flowspec_log_state_change,
|
||||||
@ -2781,8 +2782,6 @@ rt_free(resource *_r)
|
|||||||
{
|
{
|
||||||
struct rtable_private *r = SKIP_BACK(struct rtable_private, r, _r);
|
struct rtable_private *r = SKIP_BACK(struct rtable_private, r, _r);
|
||||||
|
|
||||||
DOMAIN_FREE(rtable, r->lock);
|
|
||||||
|
|
||||||
DBG("Deleting routing table %s\n", r->name);
|
DBG("Deleting routing table %s\n", r->name);
|
||||||
ASSERT_DIE(r->use_count == 0);
|
ASSERT_DIE(r->use_count == 0);
|
||||||
|
|
||||||
@ -2847,13 +2846,20 @@ rt_setup(pool *pp, struct rtable_config *cf)
|
|||||||
|
|
||||||
/* Start the service thread */
|
/* Start the service thread */
|
||||||
struct birdloop *loop = birdloop_new(pp, DOMAIN_ORDER(service), 0, "Routing table service %s", cf->name);
|
struct birdloop *loop = birdloop_new(pp, DOMAIN_ORDER(service), 0, "Routing table service %s", cf->name);
|
||||||
|
birdloop_enter(loop);
|
||||||
pool *sp = birdloop_pool(loop);
|
pool *sp = birdloop_pool(loop);
|
||||||
pool *p = rp_newf(sp, "Routing table data %s", cf->name);
|
|
||||||
|
/* Create the table domain and pool */
|
||||||
|
DOMAIN(rtable) dom = DOMAIN_NEW(rtable, cf->name);
|
||||||
|
LOCK_DOMAIN(rtable, dom);
|
||||||
|
|
||||||
|
pool *p = rp_newf(sp, dom.rtable, "Routing table data %s", cf->name);
|
||||||
|
|
||||||
/* Create the actual table */
|
/* Create the actual table */
|
||||||
struct rtable_private *t = ralloc(p, &rt_class);
|
struct rtable_private *t = ralloc(p, &rt_class);
|
||||||
t->rp = p;
|
t->rp = p;
|
||||||
t->loop = loop;
|
t->loop = loop;
|
||||||
|
t->lock = dom;
|
||||||
|
|
||||||
t->rte_slab = sl_new(p, sizeof(struct rte_storage));
|
t->rte_slab = sl_new(p, sizeof(struct rte_storage));
|
||||||
|
|
||||||
@ -2864,8 +2870,6 @@ rt_setup(pool *pp, struct rtable_config *cf)
|
|||||||
if (t->id >= rtable_max_id)
|
if (t->id >= rtable_max_id)
|
||||||
rtable_max_id = t->id + 1;
|
rtable_max_id = t->id + 1;
|
||||||
|
|
||||||
t->lock = DOMAIN_NEW(rtable, t->name);
|
|
||||||
|
|
||||||
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
|
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
|
||||||
|
|
||||||
if (cf->trie_used)
|
if (cf->trie_used)
|
||||||
@ -2911,8 +2915,9 @@ rt_setup(pool *pp, struct rtable_config *cf)
|
|||||||
t->flowspec_trie->ipv4 = (t->addr_type == NET_FLOW4);
|
t->flowspec_trie->ipv4 = (t->addr_type == NET_FLOW4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNLOCK_DOMAIN(rtable, dom);
|
||||||
|
|
||||||
/* Setup the service thread flag handler */
|
/* Setup the service thread flag handler */
|
||||||
birdloop_enter(t->loop);
|
|
||||||
birdloop_flag_set_handler(t->loop, &t->fh);
|
birdloop_flag_set_handler(t->loop, &t->fh);
|
||||||
birdloop_leave(t->loop);
|
birdloop_leave(t->loop);
|
||||||
|
|
||||||
@ -2929,7 +2934,7 @@ void
|
|||||||
rt_init(void)
|
rt_init(void)
|
||||||
{
|
{
|
||||||
rta_init();
|
rta_init();
|
||||||
rt_table_pool = rp_new(&root_pool, "Routing tables");
|
rt_table_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Routing tables");
|
||||||
init_list(&routing_tables);
|
init_list(&routing_tables);
|
||||||
init_list(&deleted_routing_tables);
|
init_list(&deleted_routing_tables);
|
||||||
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
|
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
|
||||||
@ -4067,13 +4072,14 @@ rt_shutdown(void *tab_)
|
|||||||
static void
|
static void
|
||||||
rt_delete(void *tab_)
|
rt_delete(void *tab_)
|
||||||
{
|
{
|
||||||
birdloop_enter(&main_birdloop);
|
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
||||||
|
|
||||||
/* We assume that nobody holds the table reference now as use_count is zero.
|
/* We assume that nobody holds the table reference now as use_count is zero.
|
||||||
* Anyway the last holder may still hold the lock. Therefore we lock and
|
* Anyway the last holder may still hold the lock. Therefore we lock and
|
||||||
* unlock it the last time to be sure that nobody is there. */
|
* unlock it the last time to be sure that nobody is there. */
|
||||||
struct rtable_private *tab = RT_LOCK((rtable *) tab_);
|
struct rtable_private *tab = RT_LOCK((rtable *) tab_);
|
||||||
struct config *conf = tab->deleted;
|
struct config *conf = tab->deleted;
|
||||||
|
DOMAIN(rtable) dom = tab->lock;
|
||||||
|
|
||||||
RT_UNLOCK(RT_PUB(tab));
|
RT_UNLOCK(RT_PUB(tab));
|
||||||
|
|
||||||
@ -4081,7 +4087,8 @@ rt_delete(void *tab_)
|
|||||||
birdloop_free(tab->loop);
|
birdloop_free(tab->loop);
|
||||||
config_del_obstacle(conf);
|
config_del_obstacle(conf);
|
||||||
|
|
||||||
birdloop_leave(&main_birdloop);
|
/* Also drop the domain */
|
||||||
|
DOMAIN_FREE(rtable, dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4636,18 +4643,9 @@ rt_init_hostcache(struct rtable_private *tab)
|
|||||||
.data = tab,
|
.data = tab,
|
||||||
};
|
};
|
||||||
|
|
||||||
hc->req = (struct rt_export_request) {
|
|
||||||
.name = mb_sprintf(tab->rp, "%s.hcu.notifier", tab->name),
|
|
||||||
.list = birdloop_event_list(tab->loop),
|
|
||||||
.trace_routes = tab->config->debug,
|
|
||||||
.dump_req = hc_notify_dump_req,
|
|
||||||
.log_state_change = hc_notify_log_state_change,
|
|
||||||
.export_one = hc_notify_export_one,
|
|
||||||
};
|
|
||||||
|
|
||||||
rt_table_export_start_locked(tab, &hc->req);
|
|
||||||
|
|
||||||
tab->hostcache = hc;
|
tab->hostcache = hc;
|
||||||
|
|
||||||
|
ev_send_loop(tab->loop, &hc->update);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -4775,9 +4773,24 @@ rt_update_hostcache(void *data)
|
|||||||
|
|
||||||
RT_LOCKED((rtable *) data, tab)
|
RT_LOCKED((rtable *) data, tab)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct hostcache *hc = tab->hostcache;
|
struct hostcache *hc = tab->hostcache;
|
||||||
|
|
||||||
|
/* Finish initialization */
|
||||||
|
if (!hc->req.name)
|
||||||
|
{
|
||||||
|
hc->req = (struct rt_export_request) {
|
||||||
|
.name = mb_sprintf(tab->rp, "%s.hcu.notifier", tab->name),
|
||||||
|
.list = birdloop_event_list(tab->loop),
|
||||||
|
.pool = tab->rp,
|
||||||
|
.trace_routes = tab->config->debug,
|
||||||
|
.dump_req = hc_notify_dump_req,
|
||||||
|
.log_state_change = hc_notify_log_state_change,
|
||||||
|
.export_one = hc_notify_export_one,
|
||||||
|
};
|
||||||
|
|
||||||
|
rt_table_export_start_locked(tab, &hc->req);
|
||||||
|
}
|
||||||
|
|
||||||
/* Shutdown shortcut */
|
/* Shutdown shortcut */
|
||||||
if (!hc->req.hook)
|
if (!hc->req.hook)
|
||||||
RT_RETURN(tab);
|
RT_RETURN(tab);
|
||||||
|
@ -294,6 +294,7 @@ struct rt_export_request {
|
|||||||
u8 addr_mode; /* Network prefilter mode (TE_ADDR_*) */
|
u8 addr_mode; /* Network prefilter mode (TE_ADDR_*) */
|
||||||
|
|
||||||
event_list *list; /* Where to schedule export events */
|
event_list *list; /* Where to schedule export events */
|
||||||
|
pool *pool; /* Pool to use for allocations */
|
||||||
|
|
||||||
/* There are two methods of export. You can either request feeding every single change
|
/* There are two methods of export. You can either request feeding every single change
|
||||||
* or feeding the whole route feed. In case of regular export, &export_one is preferred.
|
* or feeding the whole route feed. In case of regular export, &export_one is preferred.
|
||||||
@ -438,7 +439,7 @@ int rpe_get_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook);
|
void rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook);
|
||||||
struct rt_export_hook *rt_alloc_export(struct rt_exporter *re, uint size);
|
struct rt_export_hook *rt_alloc_export(struct rt_exporter *re, pool *pool, uint size);
|
||||||
void rt_stop_export_common(struct rt_export_hook *hook);
|
void rt_stop_export_common(struct rt_export_hook *hook);
|
||||||
void rt_export_stopped(struct rt_export_hook *hook);
|
void rt_export_stopped(struct rt_export_hook *hook);
|
||||||
void rt_exporter_init(struct rt_exporter *re);
|
void rt_exporter_init(struct rt_exporter *re);
|
||||||
|
@ -1826,7 +1826,7 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
|
|||||||
|
|
||||||
TRACE(D_EVENTS, "Adding interface %s", new->name);
|
TRACE(D_EVENTS, "Adding interface %s", new->name);
|
||||||
|
|
||||||
pool *pool = rp_new(p->p.pool, new->name);
|
pool *pool = rp_new(p->p.pool, proto_domain(&p->p), new->name);
|
||||||
|
|
||||||
ifa = mb_allocz(pool, sizeof(struct babel_iface));
|
ifa = mb_allocz(pool, sizeof(struct babel_iface));
|
||||||
ifa->proto = p;
|
ifa->proto = p;
|
||||||
|
@ -1073,7 +1073,7 @@ bfd_start(struct proto *P)
|
|||||||
|
|
||||||
pthread_spin_init(&p->lock, PTHREAD_PROCESS_PRIVATE);
|
pthread_spin_init(&p->lock, PTHREAD_PROCESS_PRIVATE);
|
||||||
|
|
||||||
p->tpool = rp_new(P->pool, "BFD loop pool");
|
p->tpool = birdloop_pool(P->loop);
|
||||||
|
|
||||||
p->session_slab = sl_new(P->pool, sizeof(struct bfd_session));
|
p->session_slab = sl_new(P->pool, sizeof(struct bfd_session));
|
||||||
HASH_INIT(p->session_hash_id, P->pool, 8);
|
HASH_INIT(p->session_hash_id, P->pool, 8);
|
||||||
|
@ -1853,7 +1853,7 @@ bgp_init_pending_tx(struct bgp_channel *c)
|
|||||||
{
|
{
|
||||||
ASSERT_DIE(!c->ptx);
|
ASSERT_DIE(!c->ptx);
|
||||||
|
|
||||||
pool *p = rp_new(c->pool, "BGP Pending TX");
|
pool *p = rp_new(c->pool, proto_domain(c->c.proto), "BGP Pending TX");
|
||||||
c->ptx = ralloc(p, &bgp_pending_tx_class);
|
c->ptx = ralloc(p, &bgp_pending_tx_class);
|
||||||
c->ptx->pool = p;
|
c->ptx->pool = p;
|
||||||
|
|
||||||
@ -1981,7 +1981,7 @@ bgp_out_table_feed(void *data)
|
|||||||
static void
|
static void
|
||||||
bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req)
|
bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req)
|
||||||
{
|
{
|
||||||
req->hook = rt_alloc_export(re, sizeof(struct bgp_out_export_hook));
|
req->hook = rt_alloc_export(re, req->pool, sizeof(struct bgp_out_export_hook));
|
||||||
req->hook->req = req;
|
req->hook->req = req;
|
||||||
|
|
||||||
struct bgp_out_export_hook *hook = SKIP_BACK(struct bgp_out_export_hook, h, req->hook);
|
struct bgp_out_export_hook *hook = SKIP_BACK(struct bgp_out_export_hook, h, req->hook);
|
||||||
|
@ -922,7 +922,8 @@ bgp_graceful_restart_feed(struct bgp_channel *c)
|
|||||||
{
|
{
|
||||||
c->stale_feed = (struct rt_export_request) {
|
c->stale_feed = (struct rt_export_request) {
|
||||||
.name = "BGP-GR",
|
.name = "BGP-GR",
|
||||||
.list = &global_work_list,
|
.list = proto_event_list(c->c.proto),
|
||||||
|
.pool = c->c.proto->pool,
|
||||||
.trace_routes = c->c.debug | c->c.proto->debug,
|
.trace_routes = c->c.debug | c->c.proto->debug,
|
||||||
.dump_req = bgp_graceful_restart_feed_dump_req,
|
.dump_req = bgp_graceful_restart_feed_dump_req,
|
||||||
.log_state_change = bgp_graceful_restart_feed_log_state_change,
|
.log_state_change = bgp_graceful_restart_feed_log_state_change,
|
||||||
|
@ -567,7 +567,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
|
|||||||
OSPF_TRACE(D_EVENTS, "Adding interface %s (%N) to area %R",
|
OSPF_TRACE(D_EVENTS, "Adding interface %s (%N) to area %R",
|
||||||
iface->name, &addr->prefix, oa->areaid);
|
iface->name, &addr->prefix, oa->areaid);
|
||||||
|
|
||||||
pool = rp_new(p->p.pool, "OSPF Interface");
|
pool = rp_new(p->p.pool, proto_domain(&p->p), "OSPF Interface");
|
||||||
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
|
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
|
||||||
ifa->iface = iface;
|
ifa->iface = iface;
|
||||||
ifa->addr = addr;
|
ifa->addr = addr;
|
||||||
@ -690,7 +690,7 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
|
|||||||
|
|
||||||
/* Vlink ifname is stored just after the ospf_iface structure */
|
/* Vlink ifname is stored just after the ospf_iface structure */
|
||||||
|
|
||||||
pool = rp_new(p->p.pool, "OSPF Vlink");
|
pool = rp_new(p->p.pool, proto_domain(&p->p), "OSPF Vlink");
|
||||||
ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
|
ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
|
||||||
ifa->oa = p->backbone;
|
ifa->oa = p->backbone;
|
||||||
ifa->cf = ip;
|
ifa->cf = ip;
|
||||||
|
@ -80,7 +80,7 @@ struct ospf_neighbor *
|
|||||||
ospf_neighbor_new(struct ospf_iface *ifa)
|
ospf_neighbor_new(struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
struct ospf_proto *p = ifa->oa->po;
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor");
|
struct pool *pool = rp_new(p->p.pool, proto_domain(&p->p), "OSPF Neighbor");
|
||||||
struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
|
struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
|
||||||
|
|
||||||
n->pool = pool;
|
n->pool = pool;
|
||||||
|
@ -287,7 +287,7 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf
|
|||||||
|
|
||||||
RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
|
RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
|
||||||
|
|
||||||
pool *pool = rp_new(p->p.pool, iface->name);
|
pool *pool = rp_new(p->p.pool, proto_domain(&p->p), iface->name);
|
||||||
ifa = mb_allocz(pool, sizeof(struct radv_iface));
|
ifa = mb_allocz(pool, sizeof(struct radv_iface));
|
||||||
ifa->pool = pool;
|
ifa->pool = pool;
|
||||||
ifa->ra = p;
|
ifa->ra = p;
|
||||||
|
@ -599,7 +599,7 @@ rpki_check_expire_interval(uint seconds)
|
|||||||
static struct rpki_cache *
|
static struct rpki_cache *
|
||||||
rpki_init_cache(struct rpki_proto *p, struct rpki_config *cf)
|
rpki_init_cache(struct rpki_proto *p, struct rpki_config *cf)
|
||||||
{
|
{
|
||||||
pool *pool = rp_new(p->p.pool, cf->hostname);
|
pool *pool = rp_new(p->p.pool, proto_domain(&p->p), cf->hostname);
|
||||||
|
|
||||||
struct rpki_cache *cache = mb_allocz(pool, sizeof(struct rpki_cache));
|
struct rpki_cache *cache = mb_allocz(pool, sizeof(struct rpki_cache));
|
||||||
|
|
||||||
|
@ -503,12 +503,14 @@ sockets_fire(struct birdloop *loop)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
DEFINE_DOMAIN(resource);
|
DEFINE_DOMAIN(resource);
|
||||||
|
static void bird_thread_start_event(void *_data);
|
||||||
|
|
||||||
struct birdloop_pickup_group {
|
struct birdloop_pickup_group {
|
||||||
DOMAIN(resource) domain;
|
DOMAIN(resource) domain;
|
||||||
list loops;
|
list loops;
|
||||||
list threads;
|
list threads;
|
||||||
btime max_latency;
|
btime max_latency;
|
||||||
|
event start_threads;
|
||||||
} pickup_groups[2] = {
|
} pickup_groups[2] = {
|
||||||
{
|
{
|
||||||
/* all zeroes */
|
/* all zeroes */
|
||||||
@ -516,6 +518,8 @@ struct birdloop_pickup_group {
|
|||||||
{
|
{
|
||||||
/* FIXME: make this dynamic, now it copies the loop_max_latency value from proto/bfd/config.Y */
|
/* FIXME: make this dynamic, now it copies the loop_max_latency value from proto/bfd/config.Y */
|
||||||
.max_latency = 10 MS,
|
.max_latency = 10 MS,
|
||||||
|
.start_threads.hook = bird_thread_start_event,
|
||||||
|
.start_threads.data = &pickup_groups[1],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -630,13 +634,11 @@ bird_thread_main(void *arg)
|
|||||||
rcu_thread_start(&thr->rcu);
|
rcu_thread_start(&thr->rcu);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
tmp_init(thr->pool);
|
|
||||||
init_list(&thr->loops);
|
|
||||||
|
|
||||||
thr->meta = birdloop_new_no_pickup(thr->pool, DOMAIN_ORDER(meta), "Thread Meta");
|
|
||||||
thr->meta->thread = thr;
|
|
||||||
birdloop_enter(thr->meta);
|
birdloop_enter(thr->meta);
|
||||||
|
|
||||||
|
tmp_init(thr->pool, birdloop_domain(thr->meta));
|
||||||
|
init_list(&thr->loops);
|
||||||
|
|
||||||
thr->sock_changed = 1;
|
thr->sock_changed = 1;
|
||||||
|
|
||||||
struct pfd pfd;
|
struct pfd pfd;
|
||||||
@ -759,15 +761,20 @@ static struct bird_thread *
|
|||||||
bird_thread_start(struct birdloop_pickup_group *group)
|
bird_thread_start(struct birdloop_pickup_group *group)
|
||||||
{
|
{
|
||||||
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
||||||
ASSERT_DIE(DOMAIN_IS_LOCKED(resource, group->domain));
|
|
||||||
|
|
||||||
pool *p = rp_new(&root_pool, "Thread");
|
struct birdloop *meta = birdloop_new_no_pickup(&root_pool, DOMAIN_ORDER(meta), "Thread Meta");
|
||||||
|
pool *p = birdloop_pool(meta);
|
||||||
|
|
||||||
|
birdloop_enter(meta);
|
||||||
|
LOCK_DOMAIN(resource, group->domain);
|
||||||
|
|
||||||
struct bird_thread *thr = mb_allocz(p, sizeof(*thr));
|
struct bird_thread *thr = mb_allocz(p, sizeof(*thr));
|
||||||
thr->pool = p;
|
thr->pool = p;
|
||||||
thr->cleanup_event = (event) { .hook = bird_thread_cleanup, .data = thr, };
|
thr->cleanup_event = (event) { .hook = bird_thread_cleanup, .data = thr, };
|
||||||
thr->group = group;
|
thr->group = group;
|
||||||
thr->max_latency_ns = (group->max_latency ?: 5 S) TO_NS;
|
thr->max_latency_ns = (group->max_latency ?: 5 S) TO_NS;
|
||||||
|
thr->meta = meta;
|
||||||
|
thr->meta->thread = thr;
|
||||||
|
|
||||||
wakeup_init(thr);
|
wakeup_init(thr);
|
||||||
ev_init_list(&thr->priority_events, NULL, "Thread direct event list");
|
ev_init_list(&thr->priority_events, NULL, "Thread direct event list");
|
||||||
@ -790,9 +797,18 @@ bird_thread_start(struct birdloop_pickup_group *group)
|
|||||||
if (e = pthread_create(&thr->thread_id, &thr->thread_attr, bird_thread_main, thr))
|
if (e = pthread_create(&thr->thread_id, &thr->thread_attr, bird_thread_main, thr))
|
||||||
die("pthread_create() failed: %M", e);
|
die("pthread_create() failed: %M", e);
|
||||||
|
|
||||||
|
UNLOCK_DOMAIN(resource, group->domain);
|
||||||
|
birdloop_leave(meta);
|
||||||
return thr;
|
return thr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bird_thread_start_event(void *_data)
|
||||||
|
{
|
||||||
|
struct birdloop_pickup_group *group = _data;
|
||||||
|
bird_thread_start(group);
|
||||||
|
}
|
||||||
|
|
||||||
static struct birdloop *thread_dropper;
|
static struct birdloop *thread_dropper;
|
||||||
static event *thread_dropper_event;
|
static event *thread_dropper_event;
|
||||||
static uint thread_dropper_goal;
|
static uint thread_dropper_goal;
|
||||||
@ -880,15 +896,14 @@ bird_thread_commit(struct config *new, struct config *old UNUSED)
|
|||||||
int dif = list_length(&group->threads) - (thread_dropper_goal = new->thread_count);
|
int dif = list_length(&group->threads) - (thread_dropper_goal = new->thread_count);
|
||||||
_Bool thread_dropper_running = !!thread_dropper;
|
_Bool thread_dropper_running = !!thread_dropper;
|
||||||
|
|
||||||
|
UNLOCK_DOMAIN(resource, group->domain);
|
||||||
|
|
||||||
if (dif < 0)
|
if (dif < 0)
|
||||||
{
|
{
|
||||||
bird_thread_start(group);
|
bird_thread_start(group);
|
||||||
UNLOCK_DOMAIN(resource, group->domain);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK_DOMAIN(resource, group->domain);
|
|
||||||
|
|
||||||
if ((dif > 0) && !thread_dropper_running)
|
if ((dif > 0) && !thread_dropper_running)
|
||||||
{
|
{
|
||||||
struct birdloop *tdl = birdloop_new(&root_pool, DOMAIN_ORDER(control), group->max_latency, "Thread dropper");
|
struct birdloop *tdl = birdloop_new(&root_pool, DOMAIN_ORDER(control), group->max_latency, "Thread dropper");
|
||||||
@ -1006,12 +1021,13 @@ bird_thread_show(void *data)
|
|||||||
void
|
void
|
||||||
cmd_show_threads(int show_loops)
|
cmd_show_threads(int show_loops)
|
||||||
{
|
{
|
||||||
pool *p = rp_new(&root_pool, "Show Threads");
|
DOMAIN(control) lock = DOMAIN_NEW(control, "Show Threads");
|
||||||
|
pool *p = rp_new(&root_pool, lock.control, "Show Threads");
|
||||||
|
|
||||||
struct bird_thread_show_data *tsd = mb_allocz(p, sizeof(struct bird_thread_show_data));
|
struct bird_thread_show_data *tsd = mb_allocz(p, sizeof(struct bird_thread_show_data));
|
||||||
tsd->lock = DOMAIN_NEW(control, "Show Threads");
|
|
||||||
tsd->cli = this_cli;
|
tsd->cli = this_cli;
|
||||||
tsd->pool = p;
|
tsd->pool = p;
|
||||||
|
tsd->lock = lock;
|
||||||
tsd->show_loops = show_loops;
|
tsd->show_loops = show_loops;
|
||||||
|
|
||||||
this_cli->cont = bird_thread_show_cli_cont;
|
this_cli->cont = bird_thread_show_cli_cont;
|
||||||
@ -1112,8 +1128,10 @@ birdloop_stop_internal(struct birdloop *loop)
|
|||||||
/* Request local socket reload */
|
/* Request local socket reload */
|
||||||
this_thread->sock_changed++;
|
this_thread->sock_changed++;
|
||||||
|
|
||||||
/* Tail-call the stopped hook */
|
/* Call the stopped hook from the main loop */
|
||||||
loop->stopped(loop->stop_data);
|
loop->event.hook = loop->stopped;
|
||||||
|
loop->event.data = loop->stop_data;
|
||||||
|
ev_send_loop(&main_birdloop, &loop->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1187,8 +1205,9 @@ static struct birdloop *
|
|||||||
birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group, const char *name, va_list args)
|
birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group, const char *name, va_list args)
|
||||||
{
|
{
|
||||||
struct domain_generic *dg = domain_new(name, order);
|
struct domain_generic *dg = domain_new(name, order);
|
||||||
|
DG_LOCK(dg);
|
||||||
|
|
||||||
pool *p = rp_vnewf(pp, name, args);
|
pool *p = rp_vnewf(pp, dg, name, args);
|
||||||
struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop));
|
struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop));
|
||||||
loop->pool = p;
|
loop->pool = p;
|
||||||
|
|
||||||
@ -1197,7 +1216,7 @@ birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group
|
|||||||
|
|
||||||
atomic_store_explicit(&loop->thread_transition, 0, memory_order_relaxed);
|
atomic_store_explicit(&loop->thread_transition, 0, memory_order_relaxed);
|
||||||
|
|
||||||
birdloop_enter(loop);
|
birdloop_enter_locked(loop);
|
||||||
|
|
||||||
ev_init_list(&loop->event_list, loop, name);
|
ev_init_list(&loop->event_list, loop, name);
|
||||||
timers_init(&loop->time, p);
|
timers_init(&loop->time, p);
|
||||||
@ -1211,8 +1230,7 @@ birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group
|
|||||||
LOCK_DOMAIN(resource, group->domain);
|
LOCK_DOMAIN(resource, group->domain);
|
||||||
add_tail(&group->loops, &loop->n);
|
add_tail(&group->loops, &loop->n);
|
||||||
if (EMPTY_LIST(group->threads))
|
if (EMPTY_LIST(group->threads))
|
||||||
bird_thread_start(group);
|
ev_send(&global_event_list, &group->start_threads);
|
||||||
|
|
||||||
wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
|
wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
|
||||||
UNLOCK_DOMAIN(resource, group->domain);
|
UNLOCK_DOMAIN(resource, group->domain);
|
||||||
}
|
}
|
||||||
@ -1277,8 +1295,11 @@ birdloop_free(struct birdloop *loop)
|
|||||||
{
|
{
|
||||||
ASSERT_DIE(loop->thread == NULL);
|
ASSERT_DIE(loop->thread == NULL);
|
||||||
|
|
||||||
domain_free(loop->time.domain);
|
struct domain_generic *dg = loop->time.domain;
|
||||||
|
DG_LOCK(dg);
|
||||||
rp_free(loop->pool);
|
rp_free(loop->pool);
|
||||||
|
DG_UNLOCK(dg);
|
||||||
|
domain_free(dg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -74,7 +74,7 @@ static list krt_proto_list;
|
|||||||
void
|
void
|
||||||
krt_io_init(void)
|
krt_io_init(void)
|
||||||
{
|
{
|
||||||
krt_pool = rp_new(&root_pool, "Kernel Syncer");
|
krt_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Kernel Syncer");
|
||||||
krt_filter_lp = lp_new_default(krt_pool);
|
krt_filter_lp = lp_new_default(krt_pool);
|
||||||
init_list(&krt_proto_list);
|
init_list(&krt_proto_list);
|
||||||
krt_sys_io_init();
|
krt_sys_io_init();
|
||||||
|
Loading…
Reference in New Issue
Block a user