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));
+}
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
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)
{
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)
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)
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
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;
#include "lib/type.h"
#include "lib/fib.h"
#include "lib/route.h"
+#include "lib/timer.h"
struct ea_list;
struct protocol;
*/
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 */
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;