0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Partial import reload

This commit is contained in:
Katerina Kubecova 2023-10-12 13:16:54 +02:00
parent a532146886
commit 10bf227de7
4 changed files with 152 additions and 27 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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 <addr> */
TE_ADDR_FOR, /* Longest prefix match - show route for <addr> */
TE_ADDR_IN, /* Interval query - show route in <addr> */
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 <addr> */
TE_ADDR_FOR, /* Longest prefix match - show route for <addr> */
TE_ADDR_IN, /* Interval query - show route in <addr> */
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 */