diff --git a/lib/timer.c b/lib/timer.c index c47e0bbc..ec8dd3e3 100644 --- a/lib/timer.c +++ b/lib/timer.c @@ -376,3 +376,74 @@ tm_format_real_time(char *x, size_t max, const char *fmt, btime t) return 1; } + + +/* + * Settle timer + */ + +static btime +settled_time(struct settle_timer *st) +{ + return MIN_(st->last_change + *(st->min_settle_time), + st->base_settle_time + *(st->max_settle_time)); +} + +void +settle_timer_changed(struct settle_timer *st) +{ + st->last_change = current_time(); +} + +void +settle_timer(timer *t) +{ + log(L_INFO "settle_timer()"); + struct settle_timer *st = (void *) t; + + if (!st->base_settle_time) + return; + + btime settled_t = settled_time(st); + if (current_time() < settled_t) + { + tm_set((timer *) st, settled_t); + return; + } + + /* Settled */ + st->base_settle_time = 0; + + if (st->class->action) + st->class->action(st); +} + +struct settle_timer * +stm_new_timer(pool *p, void *data, struct settle_timer_class *class) +{ + log(L_INFO "stm_new_timer() creating new timer"); + struct settle_timer *st; + st = mb_allocz(p, sizeof(struct settle_timer)); + st->class = class; + + /* timer option randomize and recurrent are set to zero */ + timer *t = (void *) st; + t->index = -1; + t->hook = settle_timer; + t->data = data; + + return st; +} + +void +kick_settle_timer(struct settle_timer *st) +{ + log(L_INFO "kick_settle_timer()"); + ASSUME(st != NULL); + + st->base_settle_time = current_time(); + + timer *t = (void *) st; + if (!tm_active(t)) + tm_set(t, settled_time(st)); +} diff --git a/lib/timer.h b/lib/timer.h index c5ea430c..89663ec4 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -124,4 +124,26 @@ btime tm_parse_time(const char *x); void tm_format_time(char *x, struct timeformat *fmt, btime t); int tm_format_real_time(char *x, size_t max, const char *fmt, btime t); +/* + * Settle timer + */ + +struct settle_timer { + timer tm; + btime *min_settle_time; + btime *max_settle_time; + btime base_settle_time; + btime last_change; + const struct settle_timer_class *class; +}; + +struct settle_timer_class { + void (*action)(struct settle_timer *st); + void (*changed)(struct settle_timer *st); + void (*kick)(struct settle_timer *st); +}; + +struct settle_timer *stm_new_timer(pool *p, void *data, struct settle_timer_class *class); +void kick_settle_timer(struct settle_timer *st); + #endif diff --git a/nest/rt-table.c b/nest/rt-table.c index ed294c39..3d11c7dc 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1365,7 +1365,7 @@ rte_recalculate(struct rt_import_hook *c, net *net, rte *new, struct rte_src *sr stats->withdraws_ignored++; if (old_ok || new_ok) - table->last_rt_change = current_time(); + table->settle_timer->last_change = current_time(); if (table->config->sorted) { @@ -2019,7 +2019,7 @@ rt_dump_hooks(rtable *tab) debug(" nhu_state=%u hcu_scheduled=%u use_count=%d rt_count=%u\n", tab->nhu_state, tab->hcu_scheduled, tab->use_count, tab->rt_count); debug(" last_rt_change=%t gc_time=%t gc_counter=%d prune_state=%u\n", - tab->last_rt_change, tab->gc_time, tab->gc_counter, tab->prune_state); + tab->settle_timer->last_change, tab->gc_time, tab->gc_counter, tab->prune_state); struct rt_import_hook *ih; WALK_LIST(ih, tab->imports) @@ -2133,50 +2133,21 @@ rt_kick_prune_timer(rtable *tab) tm_start(tab->prune_timer, gc_period); } - -static inline btime -rt_settled_time(rtable *tab) -{ - ASSUME(tab->base_settle_time != 0); - - return MIN(tab->last_rt_change + tab->config->min_settle_time, - tab->base_settle_time + tab->config->max_settle_time); -} - static void -rt_settle_timer(timer *t) +rt_settle_timer(struct settle_timer *st) { + timer *t = (void *) st; rtable *tab = t->data; - if (!tab->base_settle_time) - return; - - btime settled_time = rt_settled_time(tab); - if (current_time() < settled_time) - { - tm_set(tab->settle_timer, settled_time); - return; - } - - /* Settled */ - tab->base_settle_time = 0; - struct rt_subscription *s; WALK_LIST(s, tab->subscribers) s->hook(s); } -static void -rt_kick_settle_timer(rtable *tab) -{ - tab->base_settle_time = current_time(); - - if (!tab->settle_timer) - tab->settle_timer = tm_new_init(tab->rp, rt_settle_timer, tab, 0, 0); - - if (!tm_active(tab->settle_timer)) - tm_set(tab->settle_timer, rt_settled_time(tab)); -} +static struct settle_timer_class rt_settle_class = { + .action = rt_settle_timer, + .kick = NULL, +}; static inline void rt_schedule_notify(rtable *tab) @@ -2184,10 +2155,10 @@ rt_schedule_notify(rtable *tab) if (EMPTY_LIST(tab->subscribers)) return; - if (tab->base_settle_time) + if (tab->settle_timer->base_settle_time) return; - rt_kick_settle_timer(tab); + kick_settle_timer(tab->settle_timer); } void @@ -2373,7 +2344,9 @@ rt_setup(pool *pp, struct rtable_config *cf) t->rt_event = ev_new_init(p, rt_event, t); t->prune_timer = tm_new_init(p, rt_prune_timer, t, 0, 0); - t->last_rt_change = t->gc_time = current_time(); + t->settle_timer = stm_new_timer(p, t, &rt_settle_class); + + t->settle_timer->last_change = t->gc_time = current_time(); t->rl_pipe = (struct tbf) TBF_DEFAULT_LOG_LIMITS; diff --git a/nest/rt.h b/nest/rt.h index b13c06be..6c19677b 100644 --- a/nest/rt.h +++ b/nest/rt.h @@ -17,6 +17,7 @@ #include "lib/type.h" #include "lib/fib.h" #include "lib/route.h" +#include "lib/timer.h" struct ea_list; struct protocol; @@ -90,8 +91,6 @@ typedef struct rtable { */ struct event *rt_event; /* Routing table event */ struct timer *prune_timer; /* Timer for periodic pruning / GC */ - 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 */ uint gc_counter; /* Number of operations since last GC */ byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */ @@ -107,7 +106,7 @@ typedef struct rtable { struct tbf rl_pipe; /* Rate limiting token buffer for pipe collisions */ list subscribers; /* Subscribers for notifications */ - struct timer *settle_timer; /* Settle time for notifications */ + struct settle_timer *settle_timer; /* Settle time for notifications */ list flowspec_links; /* List of flowspec links, src for NET_IPx and dst for NET_FLOWx */ struct f_trie *flowspec_trie; /* Trie for evaluation of flowspec notifications */ } rtable;