From: Katerina Kubecova Date: Thu, 12 Oct 2023 11:16:54 +0000 (+0200) Subject: Partial import reload X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10bf227de7807d0f6e5a8c3fe5f56a34637ed623;p=thirdparty%2Fbird.git Partial import reload --- diff --git a/nest/proto.c b/nest/proto.c index 38228c12c..318aaac45 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -52,6 +52,7 @@ static void channel_init_limit(struct channel *c, struct limit *l, int dir, stru static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf); static void channel_reset_limit(struct channel *c, struct limit *l, int dir); static int channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n); +static int channel_import_prefilter(const struct rt_prefilter *p, const net_addr *n); static void channel_feed_end(struct channel *c); static void channel_stop_export(struct channel *c); static void channel_export_stopped(struct rt_export_request *req); @@ -557,6 +558,10 @@ channel_start_import(struct channel *c) .dump_req = channel_dump_import_req, .log_state_change = channel_import_log_state_change, .preimport = channel_preimport, + .prefilter = { + .mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE, + .addr = c->out_subprefix, + }, }; ASSERT(c->channel_state == CS_UP); @@ -752,11 +757,30 @@ channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n) for (struct channel_feeding_request *cfr = c->refeeding; cfr; cfr = cfr->next) if (!cfr->trie || trie_match_net(cfr->trie, n)) + { + log(L_TRACE "Export this one"); return 1; - + } + log(L_TRACE "%N filtered out of export", n); return 0; } +static int +channel_import_prefilter(const struct rt_prefilter *p, const net_addr *n) +{ + const struct channel *c = + SKIP_BACK(struct channel, reload_req, + SKIP_BACK(struct rt_export_request, prefilter, p) + ); + for (struct channel_import_request *cir = c->importing; cir; cir = cir->next) + if (!cir->trie || trie_match_net(cir->trie, n)) + { + log(L_TRACE "Export this one"); + return 1; + } + log(L_TRACE "%N filtered out of import", n); + return 0; +} static void channel_feed_end(struct channel *c) @@ -808,18 +832,44 @@ channel_feed_end(struct channel *c) /* Called by protocol for reload from in_table */ void -channel_schedule_reload(struct channel *c) +channel_schedule_reload(struct channel *c, struct channel_import_request *cir) { + log(L_TRACE "channel_schedule_reload %i %i",cir, (cir && cir->trie)); ASSERT(c->in_req.hook); - - if (c->reload_req.hook) + int no_trie = 0; + if (cir) + { + struct channel_import_request* last = c->import_pending; + while (last) + { + if (!last->trie) + no_trie = 1; + last = last->next; + } + last = cir; + no_trie = !last->trie; + } + if (c->reload_req.hook) { CD(c, "Reload triggered before the previous one has finished"); c->reload_pending = 1; return; } + c->importing = c->import_pending; + c->import_pending = NULL; + + if (no_trie) + { + c->reload_req.prefilter.mode = TE_ADDR_NONE; + c->reload_req.prefilter.hook = NULL; + } + else + { + CD(c, "Import with trie"); + c->reload_req.prefilter.mode = TE_ADDR_HOOK; + c->reload_req.prefilter.hook = channel_import_prefilter; + } - rt_refresh_begin(&c->in_req); rt_request_export(c->table, &c->reload_req); } @@ -1081,12 +1131,32 @@ channel_request_reload(struct channel *c) CD(c, "Reload requested"); - if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER) - channel_schedule_reload(c); + if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER) { + struct channel_import_request* cir = mb_alloc(c->proto->pool, sizeof *cir);; + cir->trie = NULL; + channel_schedule_reload(c, cir); + } else c->proto->reload_routes(c); } +static void +channel_request_partial_reload(struct channel *c, struct channel_import_request *cir) +{ + ASSERT(c->in_req.hook); + ASSERT(channel_reloadable(c)); + + CD(c, "Partial import reload requested"); + + if ((c->in_keep & RIK_PREFILTER) == RIK_PREFILTER) + channel_schedule_reload(c, cir); + /* TODO*/ + else + CD(c, "Partial import reload requested, but with ric cosi"); + /*c->proto->reload_routes(c); + */ +} + const struct channel_class channel_basic = { .channel_size = sizeof(struct channel), .config_size = sizeof(struct channel_config) @@ -2681,6 +2751,11 @@ struct channel_cmd_reload_feeding_request { struct proto_reload_request *prr; }; +struct channel_cmd_reload_import_request { + struct channel_import_request cir; + struct proto_reload_request *prr; +}; + static void channel_reload_out_done_main(void *_prr) { @@ -2698,6 +2773,14 @@ channel_reload_out_done(struct channel_feeding_request *cfr) ev_send_loop(&main_birdloop, &ccrfr->prr->ev); } +static void +channel_reload_in_done(struct channel_import_request *cir) +{ + struct channel_cmd_reload_import_request *ccrir = SKIP_BACK(struct channel_cmd_reload_import_request, cir, cir); + if (atomic_fetch_sub_explicit(&ccrir->prr->counter, 1, memory_order_acq_rel) == 1) + ev_send_loop(&main_birdloop, &ccrir->prr->ev); +} + void proto_cmd_reload(struct proto *p, uintptr_t _prr, int cnt UNUSED) { @@ -2729,7 +2812,37 @@ proto_cmd_reload(struct proto *p, uintptr_t _prr, int cnt UNUSED) if (prr->dir != CMD_RELOAD_OUT) WALK_LIST(c, p->channels) if (c->channel_state == CS_UP) - channel_request_reload(c); + { + if (prr->trie) + { + /* Increase the refeed counter */ + if (atomic_fetch_add_explicit(&prr->counter, 1, memory_order_relaxed) == 0) + { + /* First occurence */ + ASSERT_DIE(this_cli->parser_pool == prr->trie->lp); + rmove(this_cli->parser_pool, &root_pool); + this_cli->parser_pool = lp_new(this_cli->pool); + prr->ev = (event) { + .hook = channel_reload_out_done_main, + .data = prr, + }; + } + else + ASSERT_DIE(this_cli->parser_pool != prr->trie->lp); + + struct channel_cmd_reload_import_request *req = lp_alloc(prr->trie->lp, sizeof *req); + *req = (struct channel_cmd_reload_import_request) { + .cir = { + .done = channel_reload_in_done, + .trie = prr->trie, + }, + .prr = prr, + }; + channel_request_partial_reload(c, &req->cir); + } + else + channel_request_reload(c); + } /* re-exporting routes */ if (prr->dir != CMD_RELOAD_IN) diff --git a/nest/protocol.h b/nest/protocol.h index a95e1c046..00021654d 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -581,6 +581,8 @@ struct channel { struct f_trie *refeed_trie; /* Auxiliary refeed trie */ struct channel_feeding_request *refeeding; /* Refeeding the channel */ struct channel_feeding_request *refeed_pending; /* Scheduled refeeds */ + struct channel_import_request *importing; /* Importing the channel */ + struct channel_import_request *import_pending; /* Scheduled imports */ uint feed_block_size; /* How many routes to feed at once */ @@ -677,7 +679,7 @@ 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); void channel_set_state(struct channel *c, uint state); -void channel_schedule_reload(struct channel *c); +void channel_schedule_reload(struct channel *c, struct channel_import_request *cir); static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); } static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); } @@ -698,6 +700,12 @@ struct channel_feeding_request { } state; }; +struct channel_import_request { + struct channel_import_request *next; /* Next in request chain */ + void (*done)(struct channel_import_request *); /* Called when import finishes */ + const struct f_trie *trie; /* Reload only matching nets */ +}; + struct channel *channel_from_export_request(struct rt_export_request *req); void channel_request_feeding(struct channel *c, struct channel_feeding_request *); void channel_request_feeding_dynamic(struct channel *c, enum channel_feeding_request_type); diff --git a/nest/rt-table.c b/nest/rt-table.c index 160d24b1d..5cf7b2ee6 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2212,7 +2212,7 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho { struct rt_exporter *re = &tab->exporter.e; struct rt_export_request *req = hook->h.req; - + log("Hook is %x", hook); /* stats zeroed by mb_allocz */ switch (req->prefilter.mode) { @@ -2230,6 +2230,7 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho case TE_ADDR_NONE: case TE_ADDR_TRIE: case TE_ADDR_HOOK: + log(L_TRACE "hook - we will feed by fib, not trie?"); FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); hook->h.event.hook = rt_feed_by_fib; break; @@ -4403,6 +4404,7 @@ rt_process_feed(struct rt_table_export_hook *c, rt_feed_block *b) static void rt_feed_by_fib(void *data) { + log(L_TRACE "rt_feed_by_fib_function - here filtering starts"); struct rt_table_export_hook *c = data; struct fib_iterator *fit = &c->feed_fit; rt_feed_block block = {}; @@ -4546,6 +4548,7 @@ void channel_reload_export_bulk(struct rt_export_request *req, const net_addr *n while (new.attrs->next) new.attrs = new.attrs->next; + log(L_TRACE "chanel_reload_export_bulk %N", net); /* And reload the route */ rte_update(c, net, &new, new.src); } diff --git a/nest/rt.h b/nest/rt.h index bd9f9363e..721a7325a 100644 --- a/nest/rt.h +++ b/nest/rt.h @@ -253,10 +253,28 @@ struct rte_storage { /* Table-channel connections */ +struct rt_prefilter { + union { + const struct f_trie *trie; + const net_addr *addr; /* Network prefilter address */ + int (*hook)(const struct rt_prefilter *, const net_addr *); + }; + /* Network prefilter mode (TE_ADDR_*) */ + enum { + TE_ADDR_NONE = 0, /* No address matching */ + TE_ADDR_EQUAL, /* Exact query - show route */ + TE_ADDR_FOR, /* Longest prefix match - show route for */ + TE_ADDR_IN, /* Interval query - show route in */ + TE_ADDR_TRIE, /* Query defined by trie */ + TE_ADDR_HOOK, /* Query processed by supplied custom hook */ + } mode; +} PACKED; + struct rt_import_request { struct rt_import_hook *hook; /* The table part of importer */ char *name; u8 trace_routes; + struct rt_prefilter prefilter; event_list *list; /* Where to schedule announce events */ @@ -300,23 +318,6 @@ struct rt_pending_export { u64 seq; /* Sequential ID (table-local) of the pending export */ }; -struct rt_prefilter { - union { - const struct f_trie *trie; - const net_addr *addr; /* Network prefilter address */ - int (*hook)(const struct rt_prefilter *, const net_addr *); - }; - /* Network prefilter mode (TE_ADDR_*) */ - enum { - TE_ADDR_NONE = 0, /* No address matching */ - TE_ADDR_EQUAL, /* Exact query - show route */ - TE_ADDR_FOR, /* Longest prefix match - show route for */ - TE_ADDR_IN, /* Interval query - show route in */ - TE_ADDR_TRIE, /* Query defined by trie */ - TE_ADDR_HOOK, /* Query processed by supplied custom hook */ - } mode; -} PACKED; - struct rt_export_request { struct rt_export_hook *hook; /* Table part of the export */ char *name; /* Network prefilter address */