Commit f047271c authored by Ondřej Zajíček's avatar Ondřej Zajíček

Timers: Parse and format functions for microsecond times

Date/time output (e.g. in logs, show commands) can use %f to specify
subsecond time. By default, millisecond precision is used in output.
parent 02552526
...@@ -102,9 +102,9 @@ config_alloc(const char *name) ...@@ -102,9 +102,9 @@ config_alloc(const char *name)
c->pool = p; c->pool = p;
c->mem = l; c->mem = l;
c->file_name = ndup; c->file_name = ndup;
c->load_time = now; c->load_time = current_time();
c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600}; c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0}; c->tf_base = c->tf_log = TM_ISO_LONG_MS;
c->gr_wait = DEFAULT_GR_WAIT; c->gr_wait = DEFAULT_GR_WAIT;
return c; return c;
......
...@@ -57,7 +57,7 @@ struct config { ...@@ -57,7 +57,7 @@ struct config {
struct config *fallback; /* Link to regular config for CLI parsing */ struct config *fallback; /* Link to regular config for CLI parsing */
int obstacle_count; /* Number of items blocking freeing of this config */ int obstacle_count; /* Number of items blocking freeing of this config */
int shutdown; /* This is a pseudo-config for daemon shutdown */ int shutdown; /* This is a pseudo-config for daemon shutdown */
bird_clock_t load_time; /* When we've got this configuration */ btime load_time; /* When we've got this configuration */
}; };
/* Please don't use these variables in protocols. Use proto_config->global instead. */ /* Please don't use these variables in protocols. Use proto_config->global instead. */
......
...@@ -14,7 +14,7 @@ CF_HDR ...@@ -14,7 +14,7 @@ CF_HDR
#include "conf/conf.h" #include "conf/conf.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/socket.h" #include "lib/socket.h"
#include "sysdep/unix/timer.h" #include "lib/timer.h"
#include "lib/string.h" #include "lib/string.h"
#include "nest/protocol.h" #include "nest/protocol.h"
#include "nest/iface.h" #include "nest/iface.h"
...@@ -60,7 +60,7 @@ CF_DECLS ...@@ -60,7 +60,7 @@ CF_DECLS
struct lsadb_show_data *ld; struct lsadb_show_data *ld;
struct iface *iface; struct iface *iface;
void *g; void *g;
bird_clock_t time; btime time;
struct f_prefix px; struct f_prefix px;
struct proto_spec ps; struct proto_spec ps;
struct channel_limit cl; struct channel_limit cl;
...@@ -81,7 +81,7 @@ CF_DECLS ...@@ -81,7 +81,7 @@ CF_DECLS
%type <i> expr bool pxlen4 %type <i> expr bool pxlen4
%type <i32> expr_us %type <i32> expr_us
%type <time> datetime %type <time> time
%type <a> ipa %type <a> ipa
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa %type <net> 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_ %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_
...@@ -308,11 +308,11 @@ label_stack: ...@@ -308,11 +308,11 @@ label_stack:
} }
; ;
datetime: time:
TEXT { TEXT {
$$ = tm_parse_datetime($1); $$ = tm_parse_time($1);
if (!$$) if (!$$)
cf_error("Invalid date and time"); cf_error("Invalid date/time");
} }
; ;
......
...@@ -456,24 +456,26 @@ protocol rip { ...@@ -456,24 +456,26 @@ protocol rip {
used for other commands and <cf/log/ is used in a log file. used for other commands and <cf/log/ is used in a log file.
"<m/format1/" is a format string using <it/strftime(3)/ notation (see "<m/format1/" is a format string using <it/strftime(3)/ notation (see
<it/man strftime/ for details). <m/limit> and "<m/format2/" allow to <it/man strftime/ for details). It is extended to support sub-second
specify the second format string for times in past deeper than <m/limit/ time part with variable precision (up to microseconds) using "%f"
seconds. There are few shorthands: <cf/iso long/ is a ISO 8601 date/time conversion code (e.g., "%T.%3f" is hh:mm:ss.sss time). <m/limit/ and
format (YYYY-MM-DD hh:mm:ss) that can be also specified using <cf/"%F %T"/. "<m/format2/" allow to specify the second format string for times in
past deeper than <m/limit/ seconds.
There are several shorthands: <cf/iso long/ is a ISO 8601 date/time
format (YYYY-MM-DD hh:mm:ss) that can be also specified using <cf/"%F
%T"/. Similarly, <cf/iso long ms/ and <cf/iso long us/ are ISO 8601
date/time formats with millisecond or microsecond precision.
<cf/iso short/ is a variant of ISO 8601 that uses just the time format <cf/iso short/ is a variant of ISO 8601 that uses just the time format
(hh:mm:ss) for near times (up to 20 hours in the past) and the date (hh:mm:ss) for near times (up to 20 hours in the past) and the date
format (YYYY-MM-DD) for far times. This is a shorthand for format (YYYY-MM-DD) for far times. This is a shorthand for <cf/"%T"
<cf/"%T" 72000 "%F"/. 72000 "%F"/. And there are also <cf/iso short ms/ and <cf/iso short us/
high-precision variants of that.
By default, BIRD uses the <cf/iso short/ format for <cf/route/ and By default, BIRD uses the <cf/iso short ms/ format for <cf/route/ and
<cf/protocol/ times, and the <cf/iso long/ format for <cf/base/ and <cf/protocol/ times, and the <cf/iso long ms/ format for <cf/base/ and
<cf/log/ times. <cf/log/ times.
In pre-1.4.0 versions, BIRD used an short, ad-hoc format for <cf/route/
and <cf/protocol/ times, and a <cf/iso long/ similar format (DD-MM-YYYY
hh:mm:ss) for <cf/base/ and <cf/log/. These timeformats could be set by
<cf/old short/ and <cf/old long/ compatibility shorthands.
<tag><label id="opt-table">table <m/name/ [sorted]</tag> <tag><label id="opt-table">table <m/name/ [sorted]</tag>
Create a new routing table. The default routing table is created Create a new routing table. The default routing table is created
implicitly, other routing tables have to be added by this command. implicitly, other routing tables have to be added by this command.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "nest/bird.h" #include "nest/bird.h"
...@@ -222,3 +223,137 @@ timer_init(void) ...@@ -222,3 +223,137 @@ timer_init(void)
timers_init(&main_timeloop, &root_pool); timers_init(&main_timeloop, &root_pool);
timeloop_init_current(); timeloop_init_current();
} }
/**
* tm_parse_time - parse a date and time
* @x: time string
*
* tm_parse_time() takes a textual representation of a date and time
* (yyyy-mm-dd[ hh:mm:ss[.sss]]) and converts it to the corresponding value of
* type &btime.
*/
btime
tm_parse_time(char *x)
{
struct tm tm;
int usec, n1, n2, n3, r;
r = sscanf(x, "%d-%d-%d%n %d:%d:%d%n.%d%n",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &n1,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n2,
&usec, &n3);
if ((r == 3) && !x[n1])
tm.tm_hour = tm.tm_min = tm.tm_sec = usec = 0;
else if ((r == 6) && !x[n2])
usec = 0;
else if ((r == 7) && !x[n3])
{
/* Convert subsecond digits to proper precision */
int digits = n3 - n2 - 1;
if ((usec < 0) || (usec > 999999) || (digits < 1) || (digits > 6))
return 0;
while (digits++ < 6)
usec *= 10;
}
else
return 0;
tm.tm_mon--;
tm.tm_year -= 1900;
s64 ts = mktime(&tm);
if ((ts == (s64) (time_t) -1) || (ts < 0) || (ts > ((s64) 1 << 40)))
return 0;
return ts S + usec;
}
/**
* tm_format_time - convert date and time to textual representation
* @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
* @fmt: specification of resulting textual representation of the time
* @t: time
*
* This function formats the given relative time value @t to a textual
* date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
*/
void
tm_format_time(char *x, struct timeformat *fmt, btime t)
{
btime dt = current_time() - t;
btime rt = current_real_time() - dt;
int v1 = !fmt->limit || (dt < fmt->limit);
tm_format_real_time(x, v1 ? fmt->fmt1 : fmt->fmt2, rt);
}
/* Replace %f in format string with usec scaled to requested precision */
static int
strfusec(char *buf, int size, const char *fmt, uint usec)
{
char *str = buf;
int parity = 0;
while (*fmt)
{
if (!size)
return 0;
if ((fmt[0] == '%') && (!parity) &&
((fmt[1] == 'f') || (fmt[1] >= '1') && (fmt[1] <= '6') && (fmt[2] == 'f')))
{
int digits = (fmt[1] == 'f') ? 6 : (fmt[1] - '0');
uint d = digits, u = usec;
/* Convert microseconds to requested precision */
while (d++ < 6)
u /= 10;
int num = bsnprintf(str, size, "%0*u", digits, u);
if (num < 0)
return 0;
fmt += (fmt[1] == 'f') ? 2 : 3;
ADVANCE(str, size, num);
}
else
{
/* Handle '%%' expression */
parity = (*fmt == '%') ? !parity : 0;
*str++ = *fmt++;
size--;
}
}
if (!size)
return 0;
*str = 0;
return str - buf;
}
void
tm_format_real_time(char *x, const char *fmt, btime t)
{
s64 t1 = t TO_S;
s64 t2 = t - t1 S;
time_t ts = t1;
struct tm tm;
if (!localtime_r(&ts, &tm))
goto err;
byte tbuf[TM_DATETIME_BUFFER_SIZE];
if (!strfusec(tbuf, TM_DATETIME_BUFFER_SIZE, fmt, t2))
goto err;
if (!strftime(x, TM_DATETIME_BUFFER_SIZE, tbuf, &tm))
goto err;
return;
err:
strcpy(x, "<error>");
}
...@@ -105,4 +105,23 @@ void timers_fire(struct timeloop *loop); ...@@ -105,4 +105,23 @@ void timers_fire(struct timeloop *loop);
void timer_init(void); void timer_init(void);
struct timeformat {
char *fmt1, *fmt2;
btime limit;
};
#define TM_ISO_SHORT_S (struct timeformat){"%T", "%F", (s64) (20*3600) S_}
#define TM_ISO_SHORT_MS (struct timeformat){"%T.%3f", "%F", (s64) (20*3600) S_}
#define TM_ISO_SHORT_US (struct timeformat){"%T.%6f", "%F", (s64) (20*3600) S_}
#define TM_ISO_LONG_S (struct timeformat){"%F %T", NULL, 0}
#define TM_ISO_LONG_MS (struct timeformat){"%F %T.%3f", NULL, 0}
#define TM_ISO_LONG_US (struct timeformat){"%F %T.%6f", NULL, 0}
#define TM_DATETIME_BUFFER_SIZE 32 /* Buffer size required by tm_format_time() */
btime tm_parse_time(char *x);
void tm_format_time(char *x, struct timeformat *fmt, btime t);
void tm_format_real_time(char *x, const char *fmt, btime t);
#endif #endif
...@@ -25,12 +25,12 @@ cmd_show_status(void) ...@@ -25,12 +25,12 @@ cmd_show_status(void)
byte tim[TM_DATETIME_BUFFER_SIZE]; byte tim[TM_DATETIME_BUFFER_SIZE];
cli_msg(-1000, "BIRD " BIRD_VERSION); cli_msg(-1000, "BIRD " BIRD_VERSION);
tm_format_datetime(tim, &config->tf_base, now); tm_format_time(tim, &config->tf_base, current_time());
cli_msg(-1011, "Router ID is %R", config->router_id); cli_msg(-1011, "Router ID is %R", config->router_id);
cli_msg(-1011, "Current server time is %s", tim); cli_msg(-1011, "Current server time is %s", tim);
tm_format_datetime(tim, &config->tf_base, boot_time TO_S); tm_format_time(tim, &config->tf_base, boot_time);
cli_msg(-1011, "Last reboot on %s", tim); cli_msg(-1011, "Last reboot on %s", tim);
tm_format_datetime(tim, &config->tf_base, config->load_time); tm_format_time(tim, &config->tf_base, config->load_time);
cli_msg(-1011, "Last reconfiguration on %s", tim); cli_msg(-1011, "Last reconfiguration on %s", tim);
graceful_restart_show_status(); graceful_restart_show_status();
......
...@@ -73,6 +73,7 @@ CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512) ...@@ -73,6 +73,7 @@ CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED) CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
/* For r_args_channel */ /* For r_args_channel */
...@@ -295,6 +296,7 @@ limit_spec: ...@@ -295,6 +296,7 @@ limit_spec:
| OFF { $$ = (struct channel_limit){}; } | OFF { $$ = (struct channel_limit){}; }
; ;
CF_ADDTO(conf, debug_default) CF_ADDTO(conf, debug_default)
debug_default: debug_default:
...@@ -304,6 +306,31 @@ debug_default: ...@@ -304,6 +306,31 @@ debug_default:
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */ /* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
CF_ADDTO(conf, timeformat_base)
timeformat_which:
ROUTE { $$ = &new_config->tf_route; }
| PROTOCOL { $$ = &new_config->tf_proto; }
| BASE { $$ = &new_config->tf_base; }
| LOG { $$ = &new_config->tf_log; }
;
timeformat_spec:
timeformat_which TEXT { *$1 = (struct timeformat){$2, NULL, 0}; }
| timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, (s64) $3 S_}; }
| timeformat_which ISO SHORT { *$1 = TM_ISO_SHORT_S; }
| timeformat_which ISO SHORT MS { *$1 = TM_ISO_SHORT_MS; }
| timeformat_which ISO SHORT US { *$1 = TM_ISO_SHORT_US; }
| timeformat_which ISO LONG { *$1 = TM_ISO_LONG_S; }
| timeformat_which ISO LONG MS { *$1 = TM_ISO_LONG_MS; }
| timeformat_which ISO LONG US { *$1 = TM_ISO_LONG_US; }
;
timeformat_base:
TIMEFORMAT timeformat_spec ';'
;
/* Interface patterns */ /* Interface patterns */
iface_patt_node_init: iface_patt_node_init:
...@@ -462,12 +489,12 @@ password_item_begin: ...@@ -462,12 +489,12 @@ password_item_begin:
password_item_params: password_item_params:
/* empty */ { } /* empty */ { }
| GENERATE FROM datetime ';' password_item_params { this_p_item->genfrom = $3; } | GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
| GENERATE TO datetime ';' password_item_params { this_p_item->gento = $3; } | GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
| ACCEPT FROM datetime ';' password_item_params { this_p_item->accfrom = $3; } | ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
| ACCEPT TO datetime ';' password_item_params { this_p_item->accto = $3; } | ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
| FROM datetime ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; } | FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
| TO datetime ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; } | TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
| ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); } | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
| ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; } | ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
; ;
......
...@@ -19,12 +19,13 @@ password_find(list *l, int first_fit) ...@@ -19,12 +19,13 @@ password_find(list *l, int first_fit)
{ {
struct password_item *pi; struct password_item *pi;
struct password_item *pf = NULL; struct password_item *pf = NULL;
btime now_ = current_real_time();
if (l) if (l)
{ {
WALK_LIST(pi, *l) WALK_LIST(pi, *l)
{ {
if ((pi->genfrom < now_real) && (pi->gento > now_real)) if ((pi->genfrom < now_) && (pi->gento > now_))
{ {
if (first_fit) if (first_fit)
return pi; return pi;
...@@ -41,12 +42,13 @@ struct password_item * ...@@ -41,12 +42,13 @@ struct password_item *
password_find_by_id(list *l, uint id) password_find_by_id(list *l, uint id)
{ {
struct password_item *pi; struct password_item *pi;
btime now_ = current_real_time();
if (!l) if (!l)
return NULL; return NULL;
WALK_LIST(pi, *l) WALK_LIST(pi, *l)
if ((pi->id == id) && (pi->accfrom <= now_real) && (now_real < pi->accto)) if ((pi->id == id) && (pi->accfrom <= now_) && (now_ < pi->accto))
return pi; return pi;
return NULL; return NULL;
...@@ -56,12 +58,13 @@ struct password_item * ...@@ -56,12 +58,13 @@ struct password_item *
password_find_by_value(list *l, char *pass, uint size) password_find_by_value(list *l, char *pass, uint size)
{ {
struct password_item *pi; struct password_item *pi;
btime now_ = current_real_time();
if (!l) if (!l)
return NULL; return NULL;
WALK_LIST(pi, *l) WALK_LIST(pi, *l)
if (password_verify(pi, pass, size) && (pi->accfrom <= now_real) && (now_real < pi->accto)) if (password_verify(pi, pass, size) && (pi->accfrom <= now_) && (now_ < pi->accto))
return pi; return pi;
return NULL; return NULL;
......
...@@ -10,15 +10,13 @@ ...@@ -10,15 +10,13 @@
#ifndef PASSWORD_H #ifndef PASSWORD_H
#define PASSWORD_H #define PASSWORD_H
#include "sysdep/unix/timer.h"
struct password_item { struct password_item {
node n; node n;
char *password; /* Key data, null terminated */ char *password; /* Key data, null terminated */
uint length; /* Key length, without null */ uint length; /* Key length, without null */
uint id; /* Key ID */ uint id; /* Key ID */
uint alg; /* MAC algorithm */ uint alg; /* MAC algorithm */
bird_clock_t accfrom, accto, genfrom, gento; btime accfrom, accto, genfrom, gento;
}; };
extern struct password_item *last_password_item; extern struct password_item *last_password_item;
......
...@@ -162,7 +162,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf) ...@@ -162,7 +162,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->channel_state = CS_DOWN; c->channel_state = CS_DOWN;
c->export_state = ES_DOWN; c->export_state = ES_DOWN;
c->last_state_change = now; c->last_state_change = current_time();
c->reloadable = 1; c->reloadable = 1;
CALL(c->channel->init, c, cf); CALL(c->channel->init, c, cf);
...@@ -341,7 +341,7 @@ channel_set_state(struct channel *c, uint state) ...@@ -341,7 +341,7 @@ channel_set_state(struct channel *c, uint state)
return; return;
c->channel_state = state; c->channel_state = state;
c->last_state_change = now; c->last_state_change = current_time();
switch (state) switch (state)
{ {
...@@ -672,7 +672,7 @@ proto_init(struct proto_config *c, node *n) ...@@ -672,7 +672,7 @@ proto_init(struct proto_config *c, node *n)
struct proto *p = pr->init(c); struct proto *p = pr->init(c);
p->proto_state = PS_DOWN; p->proto_state = PS_DOWN;
p->last_state_change = now; p->last_state_change = current_time();
insert_node(&p->n, n); insert_node(&p->n, n);
p->event = ev_new(proto_pool); p->event = ev_new(proto_pool);
...@@ -1500,7 +1500,7 @@ proto_notify_state(struct proto *p, uint state) ...@@ -1500,7 +1500,7 @@ proto_notify_state(struct proto *p, uint state)
return; return;
p->proto_state = state; p->proto_state = state;
p->last_state_change = now; p->last_state_change = current_time();
switch (state) switch (state)
{ {
...@@ -1631,7 +1631,7 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt) ...@@ -1631,7 +1631,7 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
buf[0] = 0; buf[0] = 0;
if (p->proto->get_status) if (p->proto->get_status)
p->proto->get_status(p, buf); p->proto->get_status(p, buf);
tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change); tm_format_time(tbuf, &config->tf_proto, p->last_state_change);
cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s", cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s",
p->name, p->name,
p->proto->name, p->proto->name,
......
...@@ -159,7 +159,7 @@ struct proto { ...@@ -159,7 +159,7 @@ struct proto {
byte down_sched; /* Shutdown is scheduled for later (PDS_*) */ byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
byte down_code; /* Reason for shutdown (PDC_* codes) */ byte down_code; /* Reason for shutdown (PDC_* codes) */
u32 hash_key; /* Random key used for hashing of neighbors */ u32 hash_key; /* Random key used for hashing of neighbors */
bird_clock_t last_state_change; /* Time of last state transition */ btime last_state_change; /* Time of last state transition */
char *last_state_name_announced; /* Last state name we've announced to the user */ char *last_state_name_announced; /* Last state name we've announced to the user */
/* /*
...@@ -508,7 +508,7 @@ struct channel { ...@@ -508,7 +508,7 @@ struct channel {
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */ u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */ u8 gr_wait; /* Route export to channel is postponed until graceful restart */
bird_clock_t last_state_change; /* Time of last state transition */ btime last_state_change; /* Time of last state transition */
}; };
......
...@@ -159,8 +159,8 @@ typedef struct rtable { ...@@ -159,8 +159,8 @@ typedef struct rtable {
* obstacle from this routing table. * obstacle from this routing table.
*/ */
struct event *rt_event; /* Routing table event */ struct event *rt_event; /* Routing table event */
btime gc_time; /* Time of last GC */
int gc_counter; /* Number of operations since last GC */ int gc_counter; /* Number of operations since last GC */
bird_clock_t gc_time; /* Time of last GC */
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */ byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte hcu_scheduled; /* Hostcache update is scheduled */ byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */ byte nhu_state; /* Next Hop Update state */
...@@ -213,7 +213,7 @@ typedef struct rte { ...@@ -213,7 +213,7 @@ typedef struct rte {
byte flags; /* Flags (REF_...) */ byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */ byte pflags; /* Protocol-specific flags */
word pref; /* Route preference */ word pref; /* Route preference */
bird_clock_t lastmod; /* Last modified */ btime lastmod; /* Last modified */
union { /* Protocol-dependent data (metrics etc.) */ union { /* Protocol-dependent data (metrics etc.) */
#ifdef CONFIG_RIP #ifdef CONFIG_RIP
struct { struct {
......
...@@ -39,7 +39,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm ...@@ -39,7 +39,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
struct nexthop *nh; struct nexthop *nh;
tm_format_datetime(tm, &config->tf_route, e->lastmod); tm_format_time(tm, &config->tf_route, e->lastmod);
if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw)) if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
bsprintf(from, " from %I", a->from); bsprintf(from, " from %I", a->from);
else else
......
...@@ -1173,7 +1173,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) ...@@ -1173,7 +1173,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
} }
if (new) if (new)
new->lastmod = now; new->lastmod = current_time();
/* Log the route change */ /* Log the route change */
if (p->debug & D_ROUTES) if (p->debug & D_ROUTES)
...@@ -1201,7 +1201,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) ...@@ -1201,7 +1201,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
if (!net->routes && if (!net->routes &&
(table->gc_counter++ >= table->config->gc_max_ops) && (table->gc_counter++ >= table->config->gc_max_ops) &&
(table->gc_time + table->config->gc_min_time <= now)) (table->gc_time + table->config->gc_min_time <= current_time()))
rt_schedule_prune(table); rt_schedule_prune(table);
if (old_ok && p->rte_remove) if (old_ok && p->rte_remove)
...@@ -1497,7 +1497,7 @@ rte_dump(rte *e) ...@@ -1497,7 +1497,7 @@ rte_dump(rte *e)
{ {
net *n = e->net; net *n = e->net;
debug("%-1N ", n->n.addr); debug("%-1N ", n->n.addr);
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod); debug("KF=%02x PF=%02x pref=%d ", n->n.flags, e->pflags, e->pref);
rta_dump(e->attrs); rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs) if (e->attrs->src->proto->proto->dump_attrs)
e->attrs->src->proto->proto->dump_attrs(e); e->attrs->src->proto->proto->dump_attrs(e);
...@@ -1609,7 +1609,7 @@ rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf) ...@@ -1609,7 +1609,7 @@ rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
t->rt_event = ev_new(p); t->rt_event = ev_new(p);
t->rt_event->hook = rt_event; t->rt_event->hook = rt_event;
t->rt_event->data = t; t->rt_event->data = t;
t->gc_time = now; t->gc_time = current_time();
} }
} }
...@@ -1708,7 +1708,7 @@ again: ...@@ -1708,7 +1708,7 @@ again:
#endif #endif
tab->gc_counter = 0; tab->gc_counter = 0;
tab->gc_time = now; tab->gc_time = current_time();
/* state change 2->0, 3->1 */ /* state change 2->0, 3->1 */
tab->prune_state &= 1; tab->prune_state &= 1;
......
...@@ -145,6 +145,7 @@ bfd_session_update_state(struct bfd_session *s, uint state, uint diag) ...@@ -145,6 +145,7 @@ bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
bfd_lock_sessions(p); bfd_lock_sessions(p);
s->loc_state = state; s->loc_state = state;
s->loc_diag = diag; s->loc_diag = diag;
s->last_state_change = current_time();
notify = !NODE_VALID(&s->n); notify = !NODE_VALID(&s->n);
if (notify) if (notify)
...@@ -438,7 +439,7 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface * ...@@ -438,7 +439,7 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
bfd_session_control_tx_timer(s, 1); bfd_session_control_tx_timer(s, 1);
init_list(&s->request_list); init_list(&s->request_list);
s->last_state_change = now; s->last_state_change = current_time();
TRACE(D_EVENTS, "Session to %I added", s->addr<