From 385b3ea3956aefc2868cdd838fc0a90f1d8a7857 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 30 Nov 2021 18:16:49 +0100 Subject: [PATCH] For safer memory allocations, resources are bound to loops. Also all loops have their basic resource pool for allocations which are auto-freed when the loop is stopping. --- conf/conf.c | 4 +- filter/tree_test.c | 2 +- lib/event_test.c | 2 +- lib/flowspec_test.c | 8 ++- lib/hash_test.c | 6 +- lib/io-loop.h | 13 +++-- lib/resource.c | 132 ++++++++++++++++++++++++++++++++++++------ lib/resource.h | 15 ++++- nest/a-path_test.c | 12 ++-- nest/a-set_test.c | 13 ++--- nest/cli.c | 8 +-- nest/cmds.c | 8 +-- nest/config.Y | 2 +- nest/iface.c | 2 +- nest/proto.c | 41 +++++++------ nest/route.h | 4 +- nest/rt-attr.c | 4 +- nest/rt-table.c | 69 +++++++++------------- proto/babel/babel.c | 2 +- proto/bfd/bfd.c | 8 +-- proto/bfd/bfd.h | 2 - proto/mrt/mrt.c | 5 +- proto/mrt/mrt.h | 1 + proto/ospf/iface.c | 6 +- proto/ospf/neighbor.c | 4 +- proto/radv/radv.c | 4 +- proto/rpki/rpki.c | 2 +- sysdep/unix/io-loop.c | 74 ++++++++++++++++++----- sysdep/unix/io-loop.h | 3 + sysdep/unix/krt.c | 2 +- sysdep/unix/main.c | 2 +- test/bt-utils.c | 2 +- 32 files changed, 303 insertions(+), 159 deletions(-) diff --git a/conf/conf.c b/conf/conf.c index 58abcde1..c6837a07 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -89,7 +89,7 @@ int undo_available; /* Undo was not requested from last reconfiguration */ struct config * config_alloc(const char *name) { - pool *p = rp_new(&root_pool, "Config"); + pool *p = rp_new(&root_pool, &main_birdloop, "Config"); linpool *l = lp_new_default(p); struct config *c = lp_allocz(l, sizeof(struct config)); @@ -196,7 +196,7 @@ void config_free(struct config *c) { if (c) - rfree(c->pool); + rp_free(c->pool, &root_pool); } void diff --git a/filter/tree_test.c b/filter/tree_test.c index 6472d17e..883d13bf 100644 --- a/filter/tree_test.c +++ b/filter/tree_test.c @@ -20,7 +20,7 @@ start_conf_env(void) { bt_bird_init(); - pool *p = rp_new(&root_pool, "helper_pool"); + pool *p = rp_new(&root_pool, &main_birdloop, "helper_pool"); linpool *l = lp_new_default(p); cfg_mem = l; } diff --git a/lib/event_test.c b/lib/event_test.c index 9dda3e2a..f8bb303b 100644 --- a/lib/event_test.c +++ b/lib/event_test.c @@ -57,8 +57,8 @@ t_ev_run_list(void) resource_sys_init(); resource_init(); - olock_init(); birdloop_init(); + olock_init(); io_init(); rt_init(); if_init(); diff --git a/lib/flowspec_test.c b/lib/flowspec_test.c index f7f70982..518b8fc7 100644 --- a/lib/flowspec_test.c +++ b/lib/flowspec_test.c @@ -8,6 +8,7 @@ #include "test/birdtest.h" #include "lib/flowspec.h" +#include "lib/io-loop.h" #define NET_ADDR_FLOW4_(what,prefix,pxlen,data_) \ do \ @@ -446,8 +447,6 @@ t_validation6(void) static int t_builder4(void) { - resource_init(); - struct flow_builder *fb = flow_builder_init(&root_pool); linpool *lp = lp_new_default(&root_pool); @@ -529,7 +528,6 @@ t_builder6(void) { net_addr_ip6 ip; - resource_init(); linpool *lp = lp_new_default(&root_pool); struct flow_builder *fb = flow_builder_init(&root_pool); fb->ipv6 = 1; @@ -673,6 +671,9 @@ main(int argc, char *argv[]) { bt_init(argc, argv); resource_sys_init(); + resource_init(); + the_bird_lock(); + birdloop_init(); bt_test_suite(t_read_length, "Testing get NLRI length"); bt_test_suite(t_write_length, "Testing set NLRI length"); @@ -688,5 +689,6 @@ main(int argc, char *argv[]) bt_test_suite(t_formatting4, "Formatting Flow Specification (IPv4) into text representation"); bt_test_suite(t_formatting6, "Formatting Flow Specification (IPv6) into text representation"); + the_bird_unlock(); return bt_exit_value(); } diff --git a/lib/hash_test.c b/lib/hash_test.c index 59beb7c0..7ef54662 100644 --- a/lib/hash_test.c +++ b/lib/hash_test.c @@ -9,7 +9,9 @@ #undef LOCAL_DEBUG #include "test/birdtest.h" +#include "test/bt-utils.h" +#include "lib/io-loop.h" #include "lib/hash.h" struct test_node { @@ -61,8 +63,7 @@ dump_nodes(void) static void init_hash_(uint order) { - resource_init(); - my_pool = rp_new(&root_pool, "Test pool"); + my_pool = rp_new(&root_pool, &main_birdloop, "Test pool"); HASH_INIT(hash, my_pool, order); @@ -290,6 +291,7 @@ int main(int argc, char *argv[]) { bt_init(argc, argv); + bt_bird_init(); bt_test_suite(t_insert_find, "HASH_INSERT and HASH_FIND"); bt_test_suite(t_insert_find_random, "HASH_INSERT pseudo-random keys and HASH_FIND"); diff --git a/lib/io-loop.h b/lib/io-loop.h index 25f1b2a3..386a31d5 100644 --- a/lib/io-loop.h +++ b/lib/io-loop.h @@ -20,15 +20,15 @@ void sk_reloop(sock *s, struct birdloop *loop); extern struct birdloop main_birdloop; -/* Start a new birdloop owned by given pool and domain */ +/* Start a new birdloop owned by given pool and domain. + * The loop allocates its internal pool for local allocations + * which is freed when the loop itself is stopped. */ struct birdloop *birdloop_new(pool *p, uint order, const char *name); -/* Stop the loop. At the end, the @stopped callback is called unlocked in tail - * position to finish cleanup. Run birdloop_free() from that callback to free - * the loop itself. */ +/* Stop the loop. At the end, the @stopped callback is called with locked + * parent to finish cleanup. The loop then frees itself together with its pool. */ void birdloop_stop(struct birdloop *loop, void (*stopped)(void *data), void *data); void birdloop_stop_self(struct birdloop *loop, void (*stopped)(void *data), void *data); -void birdloop_free(struct birdloop *loop); /* Get birdloop's event list */ event_list *birdloop_event_list(struct birdloop *loop); @@ -36,6 +36,9 @@ event_list *birdloop_event_list(struct birdloop *loop); /* Get birdloop's time heap */ struct timeloop *birdloop_time_loop(struct birdloop *loop); +/* Get birdloop's resource pool */ +pool *birdloop_pool(struct birdloop *loop); + /* Enter and exit the birdloop */ void birdloop_enter(struct birdloop *loop); void birdloop_leave(struct birdloop *loop); diff --git a/lib/resource.c b/lib/resource.c index 0651406f..c847d41a 100644 --- a/lib/resource.c +++ b/lib/resource.c @@ -14,6 +14,7 @@ #include "lib/resource.h" #include "lib/string.h" #include "lib/rcu.h" +#include "lib/io-loop.h" /** * DOC: Resource pools @@ -29,13 +30,6 @@ * is freed upon shutdown of the module. */ -struct pool { - resource r; - list inside; - struct pool_pages *pages; - const char *name; -}; - struct pool_pages { uint free; uint used; @@ -68,26 +62,39 @@ static int indent; /** * rp_new - create a resource pool * @p: parent pool + * @l: loop to assign * @name: pool name (to be included in debugging dumps) * * rp_new() creates a new resource pool inside the specified * parent pool. */ pool * -rp_new(pool *p, const char *name) +rp_new(pool *p, struct birdloop *loop, const char *name) { + ASSERT_DIE(birdloop_inside(p->loop)); + ASSERT_DIE(birdloop_inside(loop)); + pool *z = ralloc(p, &pool_class); + z->loop = loop; z->name = name; init_list(&z->inside); return z; } +_Thread_local static pool *pool_parent = NULL; + static void pool_free(resource *P) { - pool *p = (pool *) P; - resource *r, *rr; + ASSERT_DIE(pool_parent); + pool *p = (pool *) P; + ASSERT_DIE(birdloop_inside(p->loop)); + + pool *parent = pool_parent; + pool_parent = p; + + resource *r, *rr; r = HEAD(p->inside); while (rr = (resource *) r->n.next) { @@ -105,14 +112,25 @@ pool_free(resource *P) free_sys_page(p->pages); } + + pool_parent = parent; +} + +void +rp_free(pool *p, pool *parent) +{ + ASSERT_DIE(pool_parent == NULL); + pool_parent = parent; + rfree(p); + ASSERT_DIE(pool_parent == parent); + pool_parent = NULL; } static void -pool_dump(resource *P) +pool_dump_locked(pool *p) { - pool *p = (pool *) P; resource *r; - + debug("%s\n", p->name); indent += 3; WALK_LIST(r, p->inside) @@ -120,10 +138,47 @@ pool_dump(resource *P) indent -= 3; } -static size_t -pool_memsize(resource *P) +static void +pool_dump(resource *P) { pool *p = (pool *) P; + + if (p->loop != pool_parent->loop) + birdloop_enter(p->loop); + + pool *parent = pool_parent; + pool_parent = p; + + pool_dump_locked(p); + + pool_parent = parent; + + if (p->loop != pool_parent->loop) + birdloop_leave(p->loop); +} + +void +rp_dump(pool *p) +{ + int inside = birdloop_inside(p->loop); + if (!inside) + birdloop_enter(p->loop); + + ASSERT_DIE(pool_parent == NULL); + pool_parent = p; + + pool_dump_locked(p); + + ASSERT_DIE(pool_parent == p); + pool_parent = NULL; + + if (!inside) + birdloop_leave(p->loop); +} + +static size_t +pool_memsize_locked(pool *p) +{ resource *r; size_t sum = sizeof(pool) + ALLOC_OVERHEAD; @@ -136,6 +191,46 @@ pool_memsize(resource *P) return sum; } +static size_t +pool_memsize(resource *P) +{ + pool *p = (pool *) P; + + pool *parent = pool_parent; + pool_parent = p; + + if (p->loop != parent->loop) + birdloop_enter(p->loop); + + size_t sum = pool_memsize_locked(p); + + if (p->loop != parent->loop) + birdloop_leave(p->loop); + + pool_parent = parent; + + return sum; +} + +size_t +rp_memsize(pool *p) +{ + int inside = birdloop_inside(p->loop); + if (!inside) + birdloop_enter(p->loop); + + ASSERT_DIE(pool_parent == NULL); + pool_parent = p; + size_t sum = pool_memsize_locked(p); + ASSERT_DIE(pool_parent == p); + pool_parent = NULL; + + if (!inside) + birdloop_leave(p->loop); + + return sum; +} + static resource * pool_lookup(resource *P, unsigned long a) { @@ -243,12 +338,15 @@ rmemsize(void *res) void * ralloc(pool *p, struct resclass *c) { + ASSERT_DIE(p); + ASSERT_DIE(birdloop_inside(p->loop)); + resource *r = xmalloc(c->size); bzero(r, c->size); r->class = c; - if (p) - add_tail(&p->inside, &r->n); + add_tail(&p->inside, &r->n); + return r; } diff --git a/lib/resource.h b/lib/resource.h index 26030aea..7adde493 100644 --- a/lib/resource.h +++ b/lib/resource.h @@ -34,10 +34,16 @@ struct resclass { /* Generic resource manipulation */ -typedef struct pool pool; +typedef struct pool { + resource r; + list inside; + struct pool_pages *pages; + struct birdloop *loop; + const char *name; +} pool; void resource_init(void); -pool *rp_new(pool *, const char *); /* Create new pool */ + void rfree(void *); /* Free single resource */ void rdump(void *); /* Dump to debug output */ size_t rmemsize(void *res); /* Return size of memory used by the resource */ @@ -46,6 +52,11 @@ void rmove(void *, pool *); /* Move to a different pool */ void *ralloc(pool *, struct resclass *); +pool *rp_new(pool *, struct birdloop *loop, const char *); /* Create new pool */ +void rp_free(pool *p, pool *parent); /* Free parent pool */ +size_t rp_memsize(pool *p); /* Return size of memory used by the pool */ +void rp_dump(pool *p); /* Dump pool to debug output */ + extern pool root_pool; /* Normal memory blocks */ diff --git a/nest/a-path_test.c b/nest/a-path_test.c index 2e6e4956..2e6683f2 100644 --- a/nest/a-path_test.c +++ b/nest/a-path_test.c @@ -12,6 +12,7 @@ #include "nest/route.h" #include "nest/attrs.h" #include "lib/resource.h" +#include "lib/io-loop.h" #define TESTS_NUM 30 #define AS_PATH_LENGTH 1000 @@ -23,8 +24,6 @@ static int t_as_path_match(void) { - resource_init(); - int round; for (round = 0; round < TESTS_NUM; round++) { @@ -70,8 +69,6 @@ t_as_path_match(void) static int t_path_format(void) { - resource_init(); - struct adata empty_as_path = {}; struct adata *as_path = &empty_as_path; struct linpool *lp = lp_new_default(&root_pool); @@ -116,8 +113,6 @@ count_asn_in_array(const u32 *array, u32 asn) static int t_path_include(void) { - resource_init(); - struct adata empty_as_path = {}; struct adata *as_path = &empty_as_path; struct linpool *lp = lp_new_default(&root_pool); @@ -161,8 +156,6 @@ t_path_include(void) static int t_as_path_converting(void) { - resource_init(); - struct adata empty_as_path = {}; struct adata *as_path = &empty_as_path; struct linpool *lp = lp_new_default(&root_pool); @@ -211,6 +204,9 @@ main(int argc, char *argv[]) { bt_init(argc, argv); resource_sys_init(); + resource_init(); + the_bird_lock(); + birdloop_init(); bt_test_suite(t_as_path_match, "Testing AS path matching and some a-path utilities."); bt_test_suite(t_path_format, "Testing formating as path into byte buffer"); diff --git a/nest/a-set_test.c b/nest/a-set_test.c index efd1b67d..f8f6e781 100644 --- a/nest/a-set_test.c +++ b/nest/a-set_test.c @@ -13,6 +13,7 @@ #include "nest/route.h" #include "nest/attrs.h" #include "lib/resource.h" +#include "lib/io-loop.h" #define SET_SIZE 10 static const struct adata *set_sequence; /* <0; SET_SIZE) */ @@ -71,7 +72,6 @@ t_set_int_contains(void) { int i; - resource_init(); generate_set_sequence(SET_TYPE_INT, SET_SIZE); bt_assert(int_set_get_size(set_sequence) == SET_SIZE); @@ -92,7 +92,6 @@ t_set_int_contains(void) static int t_set_int_union(void) { - resource_init(); generate_set_sequence(SET_TYPE_INT, SET_SIZE); const struct adata *set_union; @@ -111,7 +110,6 @@ t_set_int_union(void) static int t_set_int_format(void) { - resource_init(); generate_set_sequence(SET_TYPE_INT, SET_SIZE_FOR_FORMAT_OUTPUT); bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0); @@ -132,7 +130,6 @@ t_set_int_format(void) static int t_set_int_delete(void) { - resource_init(); generate_set_sequence(SET_TYPE_INT, SET_SIZE); const struct adata *deleting_sequence = set_sequence; @@ -160,7 +157,6 @@ t_set_ec_contains(void) { u32 i; - resource_init(); generate_set_sequence(SET_TYPE_EC, SET_SIZE); bt_assert(ec_set_get_size(set_sequence) == SET_SIZE); @@ -181,7 +177,6 @@ t_set_ec_contains(void) static int t_set_ec_union(void) { - resource_init(); generate_set_sequence(SET_TYPE_EC, SET_SIZE); const struct adata *set_union; @@ -200,8 +195,6 @@ t_set_ec_union(void) static int t_set_ec_format(void) { - resource_init(); - const struct adata empty_as_path = {}; set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path; lp = lp_new_default(&root_pool); @@ -222,7 +215,6 @@ t_set_ec_format(void) static int t_set_ec_delete(void) { - resource_init(); generate_set_sequence(SET_TYPE_EC, SET_SIZE); const struct adata *deleting_sequence = set_sequence; @@ -248,6 +240,9 @@ main(int argc, char *argv[]) { bt_init(argc, argv); resource_sys_init(); + resource_init(); + the_bird_lock(); + birdloop_init(); bt_test_suite(t_set_int_contains, "Testing sets of integers: contains, get_data"); bt_test_suite(t_set_int_format, "Testing sets of integers: format"); diff --git a/nest/cli.c b/nest/cli.c index b54a0d76..7e5d2151 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -262,7 +262,7 @@ cli_command(struct cli *c) log(L_TRACE "CLI: %s", c->rx_buf); bzero(&f, sizeof(f)); f.mem = c->parser_pool; - f.pool = rp_new(c->pool, "Config"); + f.pool = rp_new(c->pool, &main_birdloop, "Config"); init_list(&f.symbols); cf_read_hook = cli_cmd_read_hook; cli_rh_pos = c->rx_buf; @@ -308,7 +308,7 @@ cli_event(void *data) cli * cli_new(void *priv) { - pool *p = rp_new(cli_pool, "CLI"); + pool *p = rp_new(cli_pool, &main_birdloop, "CLI"); cli *c = mb_alloc(p, sizeof(cli)); bzero(c, sizeof(cli)); @@ -413,7 +413,7 @@ cli_free(cli *c) c->cleanup(c); if (c == cmd_reconfig_stored_cli) cmd_reconfig_stored_cli = NULL; - rfree(c->pool); + rp_free(c->pool, &root_pool); } /** @@ -425,7 +425,7 @@ cli_free(cli *c) void cli_init(void) { - cli_pool = rp_new(&root_pool, "CLI"); + cli_pool = rp_new(&root_pool, &main_birdloop, "CLI"); init_list(&cli_log_hooks); cli_log_inited = 1; } diff --git a/nest/cmds.c b/nest/cmds.c index 18f39eb5..2f2ad94c 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -88,10 +88,10 @@ void cmd_show_memory(void) { cli_msg(-1018, "BIRD memory usage"); - print_size("Routing tables:", rmemsize(rt_table_pool)); - print_size("Route attributes:", rmemsize(rta_pool)); - print_size("Protocols:", rmemsize(proto_pool)); - print_size("Total:", rmemsize(&root_pool)); + print_size("Routing tables:", rp_memsize(rt_table_pool)); + print_size("Route attributes:", rp_memsize(rta_pool)); + print_size("Protocols:", rp_memsize(proto_pool)); + print_size("Total:", rp_memsize(&root_pool)); cli_msg(0, ""); } diff --git a/nest/config.Y b/nest/config.Y index 0914048b..f9ed0e69 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -810,7 +810,7 @@ sym_args: CF_CLI_HELP(DUMP, ..., [[Dump debugging information]]) CF_CLI(DUMP RESOURCES,,, [[Dump all allocated resource]]) -{ rdump(&root_pool); cli_msg(0, ""); } ; +{ rp_dump(&root_pool); cli_msg(0, ""); } ; CF_CLI(DUMP SOCKETS,,, [[Dump open sockets]]) { sk_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP EVENTS,,, [[Dump event log]]) diff --git a/nest/iface.c b/nest/iface.c index 5cb9e814..dd4af243 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -713,7 +713,7 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id) void if_init(void) { - if_pool = rp_new(&root_pool, "Interfaces"); + if_pool = rp_new(&root_pool, &main_birdloop, "Interfaces"); init_list(&iface_list); strcpy(default_vrf.name, "default"); neigh_init(if_pool); diff --git a/nest/proto.c b/nest/proto.c index 2d30e640..a18d9332 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -666,7 +666,10 @@ static uint channel_aux_imex(struct channel_aux_table *cat) static void channel_aux_stopped(void *data) { - struct channel_aux_table *cat = data; + struct channel_aux_table *cat; + RT_LOCKED((rtable *) data, t) + cat = t->config->owner; + struct channel *c = cat->c; if (channel_aux_imex(cat)) @@ -674,7 +677,6 @@ channel_aux_stopped(void *data) else c->in_table = NULL; - rfree(cat->tab->priv.rp); mb_free(cat); channel_check_stopped(c); } @@ -694,7 +696,7 @@ channel_aux_export_stopped(struct rt_export_request *req) int del; RT_LOCKED(cat->tab, t) - del = !!t->delete_event; + del = !!t->delete; if (del) return; @@ -708,10 +710,7 @@ static void channel_aux_stop(struct channel_aux_table *cat) { 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); - } + t->delete = channel_aux_stopped; cat->push_stopped = (event) { .hook = channel_aux_import_stopped, @@ -889,6 +888,7 @@ channel_setup_in_table(struct channel *c, int best) bsprintf(cat->name, "%s.%s.import", c->proto->name, c->name); + cat->tab_cf.owner = cat; cat->tab_cf.name = cat->name; cat->tab_cf.addr_type = c->net_type; cat->tab_cf.cork_limit = 4 * page_size / sizeof(struct rt_pending_export); @@ -933,6 +933,7 @@ channel_setup_out_table(struct channel *c) bsprintf(cat->name, "%s.%s.export", c->proto->name, c->name); + cat->tab_cf.owner = cat; cat->tab_cf.name = cat->name; cat->tab_cf.addr_type = c->net_type; cat->tab_cf.cork_limit = 4 * page_size / sizeof(struct rt_pending_export); @@ -1387,9 +1388,6 @@ proto_configure_channel(struct proto *p, struct channel **pc, struct channel_con static void proto_cleanup(struct proto *p) { - rfree(p->pool); - p->pool = NULL; - p->active = 0; proto_log_state_change(p); proto_rethink_goal(p); @@ -1400,13 +1398,13 @@ proto_loop_stopped(void *ptr) { struct proto *p = ptr; - birdloop_enter(&main_birdloop); + ASSERT_DIE(birdloop_inside(&main_birdloop)); p->loop = &main_birdloop; + p->pool = NULL; p->event->list = NULL; - proto_cleanup(p); - birdloop_leave(&main_birdloop); + proto_cleanup(p); } static void @@ -1426,7 +1424,11 @@ proto_event(void *ptr) if (p->loop != &main_birdloop) birdloop_stop_self(p->loop, proto_loop_stopped, p); else + { + rp_free(p->pool, proto_pool); + p->pool = NULL; proto_cleanup(p); + } } @@ -1490,13 +1492,16 @@ proto_start(struct proto *p) void *nb = mb_alloc(proto_pool, ns); ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Protocol %s", p->cf->name)); - p->pool = rp_new(proto_pool, nb); - if (graceful_restart_state == GRS_INIT) p->gr_recovery = 1; - if (p->cf->loop_order != DOMAIN_ORDER(the_bird)) - p->loop = birdloop_new(p->pool, p->cf->loop_order, nb); + if (p->cf->loop_order == DOMAIN_ORDER(the_bird)) + p->pool = rp_new(proto_pool, &main_birdloop, nb); + else + { + p->loop = birdloop_new(proto_pool, p->cf->loop_order, nb); + p->pool = birdloop_pool(p->loop); + } p->event->list = proto_event_list(p); @@ -2177,7 +2182,7 @@ protos_build(void) proto_build(&proto_perf); #endif - proto_pool = rp_new(&root_pool, "Protocols"); + proto_pool = rp_new(&root_pool, &main_birdloop, "Protocols"); proto_shutdown_timer = tm_new(proto_pool); proto_shutdown_timer->hook = proto_shutdown_loop; } diff --git a/nest/route.h b/nest/route.h index b5d44040..f060ad63 100644 --- a/nest/route.h +++ b/nest/route.h @@ -174,7 +174,7 @@ typedef struct rtable_private { 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 */ + void (*delete)(void *); /* Delete callback (in parent loop context) */ 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 */ @@ -212,7 +212,7 @@ typedef union { struct rtable_config { node n; char *name; - struct config *config; + void *owner; /* Main config if global table, channel_aux_table if channel table */ rtable *table; struct proto_config *krt_attached; /* Kernel syncer attached to this table */ uint addr_type; /* Type of address data stored in table (NET_*) */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 9a5498ed..357cd216 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -117,7 +117,7 @@ static void rte_src_init(void) { src_domain = DOMAIN_NEW(attrs, "Route sources"); - src_pool = rp_new(&root_pool, "Route sources"); + src_pool = rp_new(&root_pool, &main_birdloop, "Route sources"); rte_src_slab = sl_new(src_pool, sizeof(struct rte_src)); idm_init(&src_ids, src_pool, SRC_ID_INIT_SIZE); @@ -1534,7 +1534,7 @@ rta_init(void) { attrs_domain = DOMAIN_NEW(attrs, "Attributes"); - rta_pool = rp_new(&root_pool, "Attributes"); + rta_pool = rp_new(&root_pool, &main_birdloop, "Attributes"); rta_slab_[0] = sl_new(rta_pool, sizeof(rta)); rta_slab_[1] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)); diff --git a/nest/rt-table.c b/nest/rt-table.c index 8566fbf8..cd0d6291 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1695,7 +1695,7 @@ rt_export_stopped(void *data) RT_LOCKED(hook->table, tab) { /* Free the hook together with its coroutine. */ - rfree(hook->pool); + rp_free(hook->pool, tab->rp); rt_unlock_table(tab); DBG("Export hook %p in table %s finished uc=%u\n", hook, tab->name, tab->use_count); @@ -1777,7 +1777,7 @@ rt_request_export(rtable *t, struct rt_export_request *req) rtable_private *tab = RT_PRIV(t); rt_lock_table(tab); - pool *p = rp_new(tab->rp, "Export hook"); + pool *p = rp_new(tab->rp, tab->loop, "Export hook"); struct rt_export_hook *hook = req->hook = mb_allocz(p, sizeof(struct rt_export_hook)); hook->pool = p; @@ -1935,7 +1935,7 @@ 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)" : ""); + debug("Dump of routing table <%s>%s\n", t->name, t->delete ? " (deleted)" : ""); #ifdef DEBUGGING fib_check(&t->fib); #endif @@ -1969,7 +1969,7 @@ 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("Dump of hooks in routing table <%s>%s\n", tab->name, tab->delete ? " (deleted)" : ""); debug(" nhu_state=%u hcu_scheduled=%u use_count=%d rt_count=%u\n", 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", @@ -2142,6 +2142,9 @@ rt_free(resource *_r) ASSERT_DIE(EMPTY_LIST(r->imports)); ASSERT_DIE(EMPTY_LIST(r->exports)); + if (r->hostcache) + rt_free_hostcache(r); + /* Freed automagically by the resource pool fib_free(&r->fib); hmap_free(&r->id_map); @@ -2175,10 +2178,14 @@ rt_setup(pool *pp, struct rtable_config *cf) void *nb = mb_alloc(pp, ns); ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name)); - pool *p = rp_new(pp, nb); + struct birdloop *l = birdloop_new(pp, DOMAIN_ORDER(rtable), nb); + pool *p = birdloop_pool(l); + + birdloop_enter(l); rtable_private *t = ralloc(p, &rt_class); t->rp = p; + t->loop = l; t->rte_slab = sl_new(p, sizeof(struct rte_storage)); @@ -2197,8 +2204,6 @@ 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->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); @@ -2216,6 +2221,8 @@ rt_setup(pool *pp, struct rtable_config *cf) t->nhu_lp = lp_new_default(p); mb_move(nb, p); + birdloop_leave(l); + return (rtable *) t; } @@ -2229,7 +2236,7 @@ void rt_init(void) { rta_init(); - rt_table_pool = rp_new(&root_pool, "Routing tables"); + rt_table_pool = rp_new(&root_pool, &main_birdloop, "Routing tables"); init_list(&routing_tables); ev_init_cork(&rt_cork, "Route Table Cork"); } @@ -2819,7 +2826,7 @@ rt_new_table(struct symbol *s, uint addr_type) c->min_rr_settle_time = 30 S; c->max_rr_settle_time = 90 S; c->cork_limit = 4 * page_size / sizeof(struct rt_pending_export); - c->config = new_config; + c->owner = new_config; add_tail(&new_config->tables, &c->n); @@ -2844,18 +2851,6 @@ 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; - r->announce_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 @@ -2867,10 +2862,9 @@ rt_loop_stopped(void *data) void rt_unlock_table(rtable_private *r) { - if (!--r->use_count && r->delete_event && + if (!--r->use_count && r->delete && !r->prune_state && !atomic_load_explicit(&r->nhu_state, memory_order_acquire)) - /* Delete the routing table by freeing its pool */ - birdloop_stop_self(r->loop, rt_loop_stopped, r); + birdloop_stop_self(r->loop, r->delete, r); } static struct rtable_config * @@ -2883,22 +2877,16 @@ rt_find_table_config(struct config *cf, char *name) static void rt_done(void *data) { - rtable_private *t = data; - ASSERT_DIE(t->loop == NULL); + RT_LOCKED((rtable *) data, t) + { + struct rtable_config *tc = t->config; + struct config *c = tc->owner; - struct rtable_config *tc = t->config; - struct config *c = tc->config; + tc->table = NULL; + rem_node(&t->n); - tc->table = NULL; - rem_node(&t->n); - - if (t->hostcache) - rt_free_hostcache(t); - - rfree(t->delete_event); - rfree(t->rp); - - config_del_obstacle(c); + config_del_obstacle(c); + } } /** @@ -2925,7 +2913,7 @@ rt_commit(struct config *new, struct config *old) { RT_LOCK(o->table); rtable_private *ot = RT_PRIV(o->table); - if (!ot->delete_event) + if (!ot->delete) { r = rt_find_table_config(new, o->name); if (r && (r->addr_type == o->addr_type) && !new->shutdown) @@ -2941,8 +2929,7 @@ 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(&root_pool, rt_done, ot); - ot->delete_event->list = &global_event_list; + ot->delete = rt_done; config_add_obstacle(old); rt_unlock_table(ot); } diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 40e85a16..515b27e5 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -1747,7 +1747,7 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con TRACE(D_EVENTS, "Adding interface %s", new->name); - pool *pool = rp_new(p->p.pool, new->name); + pool *pool = rp_new(p->p.pool, p->p.loop, new->name); ifa = mb_allocz(pool, sizeof(struct babel_iface)); ifa->proto = p; diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index dd3488d4..c9b12aa1 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -452,8 +452,8 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface * s->passive = s->cf.passive; s->tx_csn = random_u32(); - s->tx_timer = tm_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0); - s->hold_timer = tm_new_init(p->tpool, bfd_hold_timer_hook, s, 0, 0); + s->tx_timer = tm_new_init(p->p.pool, bfd_tx_timer_hook, s, 0, 0); + s->hold_timer = tm_new_init(p->p.pool, bfd_hold_timer_hook, s, 0, 0); bfd_session_update_tx_interval(s); bfd_session_control_tx_timer(s, 1); @@ -581,7 +581,7 @@ bfd_get_iface(struct bfd_proto *p, ip_addr local, struct iface *iface) struct bfd_config *cf = (struct bfd_config *) (p->p.cf); struct bfd_iface_config *ic = bfd_find_iface_config(cf, iface); - ifa = mb_allocz(p->tpool, sizeof(struct bfd_iface)); + ifa = mb_allocz(p->p.pool, sizeof(struct bfd_iface)); ifa->local = local; ifa->iface = iface; ifa->cf = ic; @@ -1062,8 +1062,6 @@ bfd_start(struct proto *P) pthread_spin_init(&p->lock, PTHREAD_PROCESS_PRIVATE); - p->tpool = rp_new(P->pool, "BFD loop pool"); - 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_ip, P->pool, 8); diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h index 8430064b..475b3a11 100644 --- a/proto/bfd/bfd.h +++ b/proto/bfd/bfd.h @@ -90,8 +90,6 @@ struct bfd_proto pthread_spinlock_t lock; - pool *tpool; - node bfd_node; slab *session_slab; diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index b40592d2..e12f7743 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -561,10 +561,11 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) static struct mrt_table_dump_state * mrt_table_dump_init(pool *pp) { - pool *pool = rp_new(pp, "MRT Table Dump"); + pool *pool = rp_new(pp, &main_birdloop, "MRT Table Dump"); struct mrt_table_dump_state *s = mb_allocz(pool, sizeof(struct mrt_table_dump_state)); s->pool = pool; + s->parent = pp; s->linpool = lp_new(pool, 4080); s->peer_lp = lp_new(pool, 4080); mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE); @@ -601,7 +602,7 @@ mrt_table_dump_free(struct mrt_table_dump_state *s) config_del_obstacle(s->config); - rfree(s->pool); + rp_free(s->pool, s->parent); } diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h index 04865089..2e616f6f 100644 --- a/proto/mrt/mrt.h +++ b/proto/mrt/mrt.h @@ -67,6 +67,7 @@ struct mrt_table_dump_state { /* Allocated by mrt_table_dump_init() */ pool *pool; /* Pool for table dump */ + pool *parent; /* Parent pool for cleanup */ linpool *linpool; /* Temporary linear pool */ linpool *peer_lp; /* Linear pool for peer entries in peer_hash */ buffer buf; /* Buffer for MRT messages */ diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 4cd45033..2aae341a 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -311,7 +311,7 @@ ospf_iface_remove(struct ospf_iface *ifa) ospf_iface_sm(ifa, ISM_DOWN); rem_node(NODE ifa); - rfree(ifa->pool); + rp_free(ifa->pool, p->p.pool); } void @@ -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", iface->name, &addr->prefix, oa->areaid); - pool = rp_new(p->p.pool, "OSPF Interface"); + pool = rp_new(p->p.pool, p->p.loop, "OSPF Interface"); ifa = mb_allocz(pool, sizeof(struct ospf_iface)); ifa->iface = iface; ifa->addr = addr; @@ -687,7 +687,7 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip) /* Vlink ifname is stored just after the ospf_iface structure */ - pool = rp_new(p->p.pool, "OSPF Vlink"); + pool = rp_new(p->p.pool, p->p.loop, "OSPF Vlink"); ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16); ifa->oa = p->backbone; ifa->cf = ip; diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index ca369819..48e38556 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -80,7 +80,7 @@ struct ospf_neighbor * ospf_neighbor_new(struct ospf_iface *ifa) { 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, p->p.loop, "OSPF Neighbor"); struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor)); n->pool = pool; @@ -120,7 +120,7 @@ ospf_neigh_down(struct ospf_neighbor *n) s_get(&(n->dbsi)); release_lsrtl(p, n); rem_node(NODE n); - rfree(n->pool); + rp_free(n->pool, p->p.pool); OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", rid, ifa->ifname); } diff --git a/proto/radv/radv.c b/proto/radv/radv.c index d572c1b7..b0f15514 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -284,7 +284,7 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf 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, p->p.loop, iface->name); ifa = mb_allocz(pool, sizeof(struct radv_iface)); ifa->pool = pool; ifa->ra = p; @@ -317,7 +317,7 @@ radv_iface_remove(struct radv_iface *ifa) rem_node(NODE ifa); - rfree(ifa->pool); + rp_free(ifa->pool, p->p.pool); } static void diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index cc86ab6a..afba2216 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -596,7 +596,7 @@ rpki_check_expire_interval(uint seconds) static struct rpki_cache * 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, p->p.loop, cf->hostname); struct rpki_cache *cache = mb_allocz(pool, sizeof(struct rpki_cache)); diff --git a/sysdep/unix/io-loop.c b/sysdep/unix/io-loop.c index c7cf4ad2..769f01ba 100644 --- a/sysdep/unix/io-loop.c +++ b/sysdep/unix/io-loop.c @@ -48,6 +48,12 @@ birdloop_time_loop(struct birdloop *loop) return &loop->time; } +pool * +birdloop_pool(struct birdloop *loop) +{ + return loop->pool; +} + _Bool birdloop_inside(struct birdloop *loop) { @@ -333,31 +339,59 @@ birdloop_init(void) times_update(); timers_init(&main_birdloop.time, &root_pool); + root_pool.loop = &main_birdloop; + birdloop_enter_locked(&main_birdloop); } static void birdloop_main(void *arg); +void +birdloop_free(resource *r) +{ + struct birdloop *loop = (void *) r; + + ASSERT_DIE(loop->links == 0); + domain_free(loop->time.domain); +} + +void +birdloop_dump(resource *r) +{ + struct birdloop *loop = (void *) r; + + debug("%s\n", loop->pool->name); +} + +struct resclass birdloop_class = { + .name = "IO Loop", + .size = sizeof(struct birdloop), + .free = birdloop_free, + .dump = birdloop_dump, +}; + struct birdloop * birdloop_new(pool *pp, uint order, const char *name) { struct domain_generic *dg = domain_new(name, order); - pool *p = rp_new(pp, name); - struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop)); - loop->pool = p; + struct birdloop *loop = ralloc(pp, &birdloop_class); loop->time.domain = dg; loop->time.loop = loop; birdloop_enter(loop); + loop->pool = rp_new(pp, loop, name); + loop->parent = pp; + rmove(&loop->r, loop->pool); + wakeup_init(loop); ev_init_list(&loop->event_list, loop, name); - timers_init(&loop->time, p); + timers_init(&loop->time, loop->pool); sockets_init(loop); - loop->time.coro = coro_run(p, birdloop_main, loop); + loop->time.coro = coro_run(loop->pool, birdloop_main, loop); birdloop_leave(loop); @@ -389,14 +423,6 @@ birdloop_stop_self(struct birdloop *loop, void (*stopped)(void *data), void *dat birdloop_do_stop(loop, stopped, data); } -void -birdloop_free(struct birdloop *loop) -{ - ASSERT_DIE(loop->links == 0); - domain_free(loop->time.domain); - rfree(loop->pool); -} - static void birdloop_enter_locked(struct birdloop *loop) { @@ -529,7 +555,25 @@ birdloop_main(void *arg) ASSERT_DIE(loop->sock_num == 0); birdloop_leave(loop); + + /* Lock parent loop */ + pool *parent = loop->parent; + birdloop_enter(parent->loop); + + /* Move the loop temporarily to parent pool */ + birdloop_enter(loop); + rmove(&loop->r, parent); + birdloop_leave(loop); + + /* Announce loop stop */ loop->stopped(loop->stop_data); + + /* Free the pool and loop */ + birdloop_enter(loop); + rp_free(loop->pool, parent); + birdloop_leave(loop); + rfree(&loop->r); + + /* And finally leave the parent loop before finishing */ + birdloop_leave(parent->loop); } - - diff --git a/sysdep/unix/io-loop.h b/sysdep/unix/io-loop.h index 4024b6c5..3fccd520 100644 --- a/sysdep/unix/io-loop.h +++ b/sysdep/unix/io-loop.h @@ -9,7 +9,10 @@ struct birdloop { + resource r; + pool *pool; + pool *parent; struct timeloop time; event_list event_list; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 98c56391..c0f2e930 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -74,7 +74,7 @@ static list krt_proto_list; void krt_io_init(void) { - krt_pool = rp_new(&root_pool, "Kernel Syncer"); + krt_pool = rp_new(&root_pool, &main_birdloop, "Kernel Syncer"); krt_filter_lp = lp_new_default(krt_pool); init_list(&krt_proto_list); krt_sys_io_init(); diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 5da27cb6..ca06611f 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -52,7 +52,7 @@ async_dump(void) { debug("INTERNAL STATE DUMP\n\n"); - rdump(&root_pool); + rp_dump(&root_pool); sk_dump_all(); // XXXX tm_dump_all(); if_dump_all(); diff --git a/test/bt-utils.c b/test/bt-utils.c index 90815e77..98aaed3d 100644 --- a/test/bt-utils.c +++ b/test/bt-utils.c @@ -65,8 +65,8 @@ bt_bird_init(void) the_bird_lock(); resource_init(); - olock_init(); birdloop_init(); + olock_init(); io_init(); rt_init(); if_init();