diff options
-rw-r--r-- | conf/confbase.Y | 10 | ||||
-rw-r--r-- | doc/bird.sgml | 17 | ||||
-rw-r--r-- | lib/settle.h | 64 | ||||
-rw-r--r-- | nest/config.Y | 6 | ||||
-rw-r--r-- | nest/proto.c | 53 | ||||
-rw-r--r-- | nest/protocol.h | 7 |
6 files changed, 110 insertions, 47 deletions
diff --git a/conf/confbase.Y b/conf/confbase.Y index 241c332d..8e5da9e3 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -14,6 +14,7 @@ CF_HDR #include "conf/conf.h" #include "lib/resource.h" #include "lib/socket.h" +#include "lib/settle.h" #include "lib/timer.h" #include "lib/string.h" #include "nest/protocol.h" @@ -93,6 +94,7 @@ CF_DECLS struct proto_spec ps; struct channel_limit cl; struct timeformat *tf; + struct settle_config settle; struct adata *ad; struct bytestring *bs; } @@ -111,6 +113,7 @@ CF_DECLS %type <i> expr bool pxlen4 %type <time> expr_us time +%type <settle> settle %type <a> ipa %type <net> net_ip4_ net_ip4 net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ @@ -386,6 +389,13 @@ time: } ; +/* Settle timer configuration */ +settle: expr_us expr_us { + if ($1 > $2) cf_error("Minimum settle time %t is bigger than maximum settle time %t", $1, $2); + $$.min = $1; + $$.max = $2; +}; + text: TEXT | CF_SYM_KNOWN { diff --git a/doc/bird.sgml b/doc/bird.sgml index 2bce3d57..54d67e89 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -965,14 +965,15 @@ inherited from templates can be updated by new definitions. <ref id="bgp-export-table" name="export table"> (for respective direction). Default: on. - <tag><label id="rtable-min-settle-time">min settle time <m/time/</tag> - Minimum settle time is a delay from the last ROA table change to wait - for more updates before triggering automatic reload. Default: 1 s. - - <tag><label id="rtable-min-settle-time">min settle time <m/time/</tag> - Maximum settle time is an upper limit to the settle time from the - initial ROA table change even if there are consecutive updates gradually - renewing the settle time. Default: 20 s. + <tag><label id="rtable-min-settle-time">roa settle time <m/time/ <m/time/</tag> + Minimum and maximum settle times, respectively, for ROA table changes. + The automatic reload is triggered after the minimum time after the last + ROA table change has been received but not later than the maximum time after + first unprocessed ROA table change. Therefore with default values, the + automatic reload happens 1 second after the ROA table stops updating, yet if it + were to be later than 20 seconds after the ROA table starts updating, + the automatic reload is triggered anyway. Default values: <cf/1 s 20 s/. + You have to always provide both values. <tag><label id="proto-import-limit">import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag> Specify an import route limit (a maximum number of routes imported from diff --git a/lib/settle.h b/lib/settle.h new file mode 100644 index 00000000..d274599d --- /dev/null +++ b/lib/settle.h @@ -0,0 +1,64 @@ +/* + * BIRD -- Settle timer + * + * (c) 2022 Maria Matejka <mq@jmq.cz> + * (c) 2022 CZ.NIC z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_SETTLE_H_ +#define _BIRD_SETTLE_H_ + +#include "lib/birdlib.h" +#include "lib/timer.h" + +struct settle_config { + btime min, max; +}; + +struct settle { + union { + /* Timer hook polymorphism. */ + struct { + resource _r; + void (*hook)(struct settle *); + }; + timer tm; + }; + struct settle_config cf; + btime started; +}; + +STATIC_ASSERT(OFFSETOF(struct settle, hook) == OFFSETOF(struct settle, tm) + OFFSETOF(timer, hook)); + +#define SETTLE_INIT(_cfp, _hook, _data) (struct settle) { .tm = { .data = (_data), }, .hook = (_hook), .cf = ({ASSERT_DIE((_cfp)->min <= (_cfp)->max); *(_cfp); }), } + + +static inline void settle_init(struct settle *s, struct settle_config *cf, void (*hook)(struct settle *), void *data) +{ + *s = SETTLE_INIT(cf, hook, data); +} + +#define settle_active(s) tm_active(&(s)->tm) + +static inline void settle_kick(struct settle *s, struct birdloop *loop) +{ + if (!tm_active(&s->tm)) + { + s->started = current_time(); + tm_set_in(&s->tm, s->started + s->cf.min, loop); + } + else + { + btime now = current_time(); + tm_set_in(&s->tm, MIN_(now + s->cf.min, s->started + s->cf.max), loop); + } +} + +static inline void settle_cancel(struct settle *s) +{ + tm_stop(&s->tm); +} + +#endif diff --git a/nest/config.Y b/nest/config.Y index 84c76ae9..52f5aedb 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -125,7 +125,7 @@ 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) CF_KEYWORDS(CHECK, LINK) -CF_KEYWORDS(CORK, SORTED, TRIE, MIN, MAX, SETTLE, TIME, GC, THRESHOLD, PERIOD) +CF_KEYWORDS(CORK, SORTED, TRIE, MIN, MAX, ROA, SETTLE, TIME, GC, THRESHOLD, PERIOD) /* For r_args_channel */ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC) @@ -321,8 +321,7 @@ channel_item_: | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; } | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; } | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; } - | MIN SETTLE TIME expr_us { this_channel->min_settle_time = $4; } - | MAX SETTLE TIME expr_us { this_channel->max_settle_time = $4; } + | ROA SETTLE TIME settle { this_channel->roa_settle = $4; } | PREFERENCE expr { this_channel->preference = $2; check_u16($2); } | IMPORT KEEP FILTERED bool { if ($4) @@ -424,7 +423,6 @@ timeformat_base: TIMEFORMAT timeformat_spec ';' ; - /* Interface patterns */ iface_patt_node_init: diff --git a/nest/proto.c b/nest/proto.c index 783a936c..8c8daa0a 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -315,16 +315,15 @@ proto_remove_channels(struct proto *p) struct roa_subscription { node roa_node; - timer t; - btime base_settle_time; /* Start of settling interval */ + struct settle settle; struct channel *c; struct rt_export_request req; }; static void -channel_roa_in_changed(struct timer *t) +channel_roa_in_changed(struct settle *se) { - struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t); + struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se); struct channel *c = s->c; int active = !!c->reload_req.hook; @@ -337,9 +336,9 @@ channel_roa_in_changed(struct timer *t) } static void -channel_roa_out_changed(struct timer *t) +channel_roa_out_changed(struct settle *se) { - struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t); + struct roa_subscription *s = SKIP_BACK(struct roa_subscription, settle, se); struct channel *c = s->c; CD(c, "Feeding triggered by RPKI change"); @@ -356,17 +355,7 @@ channel_export_one_roa(struct rt_export_request *req, const net_addr *net UNUSED struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req); /* TODO: use the information about what roa has changed */ - - if (!tm_active(&s->t)) - { - s->base_settle_time = current_time(); - tm_start(&s->t, s->base_settle_time + s->c->min_settle_time); - } - else - tm_set(&s->t, - MIN(s->base_settle_time + s->c->max_settle_time, - current_time() + s->c->min_settle_time)); - + settle_kick(&s->settle, &main_birdloop); rpe_mark_seen_all(req->hook, first, NULL); } @@ -380,14 +369,14 @@ channel_dump_roa_req(struct rt_export_request *req) debug(" Channel %s.%s ROA %s change notifier from table %s request %p\n", c->proto->name, c->name, - (s->t.hook == channel_roa_in_changed) ? "import" : "export", + (s->settle.hook == channel_roa_in_changed) ? "import" : "export", tab->name, req); } static int channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir) { - void (*hook)(struct timer *) = + void (*hook)(struct settle *) = dir ? channel_roa_in_changed : channel_roa_out_changed; struct roa_subscription *s; @@ -395,7 +384,7 @@ channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir) WALK_LIST2(s, n, c->roa_subscriptions, roa_node) if ((tab == SKIP_BACK(rtable, priv.exporter.e, s->req.hook->table)) - && (s->t.hook == hook)) + && (s->settle.hook == hook)) return 1; return 0; @@ -410,7 +399,7 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir) struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription)); *s = (struct roa_subscription) { - .t = { .hook = dir ? channel_roa_in_changed : channel_roa_out_changed, }, + .settle = SETTLE_INIT(&c->roa_settle, dir ? channel_roa_in_changed : channel_roa_out_changed, NULL), .c = c, .req = { .name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s", @@ -934,8 +923,10 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty cf->debug = new_config->channel_default_debug; cf->rpki_reload = 1; - cf->min_settle_time = 1 S; - cf->max_settle_time = 20 S; + cf->roa_settle = (struct settle_config) { + .min = 1 S, + .max = 20 S, + }; add_tail(&proto->channels, &cf->n); @@ -1017,20 +1008,20 @@ channel_reconfigure(struct channel *c, struct channel_config *cf) c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug; c->rpki_reload = cf->rpki_reload; - if ( (c->min_settle_time != cf->min_settle_time) - || (c->max_settle_time != cf->max_settle_time)) + if ( (c->roa_settle.min != cf->roa_settle.min) + || (c->roa_settle.max != cf->roa_settle.max)) { - c->min_settle_time = cf->min_settle_time; - c->max_settle_time = cf->max_settle_time; + c->roa_settle = cf->roa_settle; struct roa_subscription *s; node *n; WALK_LIST2(s, n, c->roa_subscriptions, roa_node) - if (tm_active(&s->t)) - tm_set(&s->t, - MIN(s->base_settle_time + c->max_settle_time, - current_time() + c->min_settle_time)); + { + s->settle.cf = cf->roa_settle; + if (settle_active(&s->settle)) + settle_kick(&s->settle, &main_birdloop); + } } /* Execute channel-specific reconfigure hook */ diff --git a/nest/protocol.h b/nest/protocol.h index e9461d41..0bf894f8 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -12,6 +12,7 @@ #include "lib/lists.h" #include "lib/resource.h" #include "lib/event.h" +#include "lib/settle.h" #include "nest/rt.h" #include "nest/limit.h" #include "conf/conf.h" @@ -462,8 +463,7 @@ struct channel_config { struct channel_limit in_limit; /* Limit for importing routes from protocol */ struct channel_limit out_limit; /* Limit for exporting routes to protocol */ - btime min_settle_time; /* Minimum settle time for ROA-induced reload */ - btime max_settle_time; /* Maximum settle time for ROA-induced reload */ + struct settle_config roa_settle; /* Settle times for ROA-induced reload */ u8 net_type; /* Routing table network type (NET_*), 0 for undefined */ u8 ra_mode; /* Mode of received route advertisements (RA_*) */ @@ -492,8 +492,7 @@ struct channel { struct limit in_limit; /* Input limit */ struct limit out_limit; /* Output limit */ - btime min_settle_time; /* Minimum settle time for ROA-induced reload */ - btime max_settle_time; /* Maximum settle time for ROA-induced reload */ + struct settle_config roa_settle; /* Settle times for ROA-induced reload */ u8 limit_actions[PLD_MAX]; /* Limit actions enum */ u8 limit_active; /* Flags for active limits */ |