const struct filter *f;
struct f_tree *e;
struct f_trie *trie;
+ const struct f_trie *const_trie;
struct f_val v;
struct password_item *p;
struct rt_show_data *ra;
this_proto = NULL;
}
+static inline void
+proto_call_cmd_reload(struct proto_spec ps, int dir, const struct f_trie *trie)
+{
+ struct proto_reload_request *prr = cfg_alloc(sizeof *prr);
+ *prr = (struct proto_reload_request) {
+ .trie = trie,
+ .dir = dir,
+ };
+
+ proto_apply_cmd(ps, proto_cmd_reload, 1, (uintptr_t) prr);
+}
#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, BLAKE2S128, BLAKE2S256, BLAKE2B256, BLAKE2B512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION)
-CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, CLASS, DSCP)
+CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, CLASS, DSCP, PARTIAL)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
%type <net_ptr> r_args_for
%type <t> channel_sym
%type <c> channel_arg
+%type <const_trie> partial_opt
CF_GRAMMAR
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
{ cmd_eval(f_linearize($2, 1)); } ;
+partial_opt:
+ PARTIAL term {
+ struct f_val val;
+ if (f_eval(f_linearize($2, 1), &val) > F_RETURN) cf_error("Runtime error");
+ if (val.type != T_PREFIX_SET) cf_error("Partial spec must be trie");
+ $$ = val.val.ti;
+ }
+ | /* empty */ { $$ = NULL; }
+ ;
+
CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]])
{ proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]])
{ proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]])
{ proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
-CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
-{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
-CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
-{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
-CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
-{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
+CF_CLI(RELOAD, proto_patt partial_opt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
+{ proto_call_cmd_reload($2, CMD_RELOAD, $3); } ;
+CF_CLI(RELOAD IN, proto_patt partial_opt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
+{ proto_call_cmd_reload($3, CMD_RELOAD_IN, $4); } ;
+CF_CLI(RELOAD OUT, proto_patt partial_opt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
+{ proto_call_cmd_reload($3, CMD_RELOAD_OUT, $4); } ;
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
CF_CLI(DEBUG, debug_args, (<protocol> | <channel> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
struct settle settle;
struct channel *c;
struct rt_export_request req;
- struct f_trie* trie;
- struct channel_feeding_request cfr[2];
+ struct f_trie *trie;
};
static void
struct channel *c = s->c;
CD(c, "Feeding triggered by RPKI change");
+
+ /* Get config.Y global var */
struct channel_feeding_request *cfr = lp_alloc(s->trie->lp, sizeof *cfr);
*cfr = (struct channel_feeding_request) {
};
channel_request_feeding(c, cfr);
- s->trie = f_new_trie(lp_new(c->proto->pool), 0);
}
static void
c->refeed_req.dump_req = channel_dump_refeed_req;
c->refeed_req.log_state_change = channel_refeed_log_state_change;
c->refeed_req.mark_seen = channel_rpe_mark_seen_refeed;
- c->refeed_req.prefilter.hook = channel_refeed_prefilter;
DBG("%s.%s: Channel start export req=%p\n", c->proto->name, c->name, &c->out_req);
rt_request_export(c->table, &c->out_req);
static void
channel_init_feeding(struct channel *c)
{
+ int no_trie = 0;
+
for (struct channel_feeding_request *cfrp = c->refeed_pending; cfrp; cfrp = cfrp->next)
if (cfrp->type == CFRT_DIRECT)
{
channel_stop_export(c);
return;
}
+ else if (!cfrp->trie)
+ no_trie = 1;
/* No direct feeding, running auxiliary refeed. */
c->refeeding = c->refeed_pending;
c->refeed_pending = NULL;
c->refeed_trie = f_new_trie(lp_new(c->proto->pool), 0);
+ if (no_trie)
+ {
+ c->refeed_req.prefilter.mode = TE_ADDR_NONE;
+ c->refeed_req.prefilter.hook = NULL;
+ }
+ else
+ {
+ c->refeed_req.prefilter.mode = TE_ADDR_HOOK;
+ c->refeed_req.prefilter.hook = channel_refeed_prefilter;
+ }
+
rt_request_export(c->table, &c->refeed_req);
}
void
channel_request_feeding(struct channel *c, struct channel_feeding_request *cfr)
{
- ASSERT(c->out_req.hook);
+ ASSERT_DIE(c->out_req.hook);
+
+ CD(c, "Feeding requested (%s)",
+ cfr->type == CFRT_DIRECT ? "direct" :
+ (cfr->trie ? "partial" : "auxiliary"));
/* Enqueue the request */
cfr->next = c->refeed_pending;
cli_msg(-12, "%s: restarted", p->name);
}
+struct channel_cmd_reload_feeding_request {
+ struct channel_feeding_request cfr;
+ struct proto_reload_request *prr;
+};
+
+static void
+channel_reload_out_done_main(void *_prr)
+{
+ struct proto_reload_request *prr = _prr;
+ ASSERT_THE_BIRD_LOCKED;
+
+ rfree(prr->trie->lp);
+}
+
+static void
+channel_reload_out_done(struct channel_feeding_request *cfr)
+{
+ struct channel_cmd_reload_feeding_request *ccrfr = SKIP_BACK(struct channel_cmd_reload_feeding_request, cfr, cfr);
+ if (atomic_fetch_sub_explicit(&ccrfr->prr->counter, 1, memory_order_acq_rel) == 1)
+ ev_send_loop(&main_birdloop, &ccrfr->prr->ev);
+}
+
void
-proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
+proto_cmd_reload(struct proto *p, uintptr_t _prr, int cnt UNUSED)
{
+ struct proto_reload_request *prr = (void *) _prr;
struct channel *c;
if (p->disabled)
return;
/* All channels must support reload */
- if (dir != CMD_RELOAD_OUT)
+ if (prr->dir != CMD_RELOAD_OUT)
WALK_LIST(c, p->channels)
if ((c->channel_state == CS_UP) && !channel_reloadable(c))
{
log(L_INFO "Reloading protocol %s", p->name);
/* re-importing routes */
- if (dir != CMD_RELOAD_OUT)
+ if (prr->dir != CMD_RELOAD_OUT)
WALK_LIST(c, p->channels)
if (c->channel_state == CS_UP)
channel_request_reload(c);
/* re-exporting routes */
- if (dir != CMD_RELOAD_IN)
+ if (prr->dir != CMD_RELOAD_IN)
WALK_LIST(c, p->channels)
if (c->channel_state == CS_UP)
- channel_request_feeding_dynamic(c, CFRT_AUXILIARY);
+ 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);
+
+ /* Request actually the feeding */
+
+ struct channel_cmd_reload_feeding_request *req = lp_alloc(prr->trie->lp, sizeof *req);
+ *req = (struct channel_cmd_reload_feeding_request) {
+ .cfr = {
+ .type = CFRT_AUXILIARY,
+ .done = channel_reload_out_done,
+ .trie = prr->trie,
+ },
+ .prr = prr,
+ };
+
+ channel_request_feeding(c, &req->cfr);
+ }
+ else
+ channel_request_feeding_dynamic(c, CFRT_AUXILIARY);
cli_msg(-15, "%s: reloading", p->name);
}
#define PROTO_WALK_CMD(sym,pr,p) for(struct proto *p = NULL; p = proto_iterate_named(sym, pr, p); )
+/* Request from CLI to reload multiple protocols */
+struct proto_reload_request {
+ const struct f_trie *trie; /* Trie to apply */
+ _Atomic uint counter; /* How many channels remaining */
+ uint dir; /* Direction of reload */
+ event ev; /* Event to run when finished */
+};
+
#define PROTO_ENTER_FROM_MAIN(p) ({ \
ASSERT_DIE(birdloop_inside(&main_birdloop)); \
struct birdloop *_loop = (p)->loop; \
struct channel_feeding_request {
struct channel_feeding_request *next; /* Next in request chain */
void (*done)(struct channel_feeding_request *); /* Called when refeed finishes */
- struct f_trie *trie; /* Reload only matching nets */
+ const struct f_trie *trie; /* Reload only matching nets */
PACKED enum channel_feeding_request_type {
CFRT_DIRECT = 1, /* Refeed by export restart */
CFRT_AUXILIARY, /* Refeed by auxiliary request */
--- /dev/null
+log "bird.log" all;
+
+debug protocols all;
+debug channels all;
+debug tables all;
+
+ipv4 table master1;
+ipv4 table master2;
+
+protocol device {
+ scan time 10;
+}
+
+protocol static static1 {
+ ipv4 { table master1; };
+ route 10.0.0.0/16 unreachable;
+ route 12.0.0.0/16 unreachable;
+ route 127.0.0.0/8 unreachable;
+ route 192.0.0.0/8 unreachable;
+ route 192.168.0.0/16 unreachable;
+ route 195.113.26.206/32 unreachable;
+ route 1.1.1.1/32 unreachable;
+}
+
+ipv4 table ct_4;
+protocol pipe {
+ table master1;
+ peer table master2;
+ import filter {
+ print net;
+ accept;
+ };
+ export filter {
+ print net;
+ accept;
+ };
+}
+