From: Claudio Jeker Subject: bgpctl: print absolute timestamps for mrt dumps To: tech@openbsd.org Date: Thu, 21 May 2026 15:22:24 +0200 bgpctl show mrt detail currently show entries with Last update: Never ago This comes from the fact that most mrt dumps come from the past and bgpctl tries to print the Last update as a relative timeframe based on the monotonic clock. So for 'show mrt' switch fmt_monotime() to absolute timestamps. Remove the 'ago' from the Last update line and print the timestamp using monotime_to_time, gmtime and strftime("%FT%TZ") to get a ISO format timestamp string. While there also adjust get_rel_monotime() to be more like monotime_to_time() and stop treating negative numbers as error. In fmt_monotime() instead compare the time against 0 to print Never. With this the mrt dump I have now shows this: Last update: 2019-05-08T20:03:06Z -- :wq Claudio Index: bgpctl.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v diff -u -p -r1.321 bgpctl.c --- bgpctl.c 18 May 2026 18:37:22 -0000 1.321 +++ bgpctl.c 21 May 2026 13:12:58 -0000 @@ -66,6 +66,7 @@ struct mrt_parser net_mrt = { network_mr const struct output *output = &show_output; int tableid; int nodescr; +int abs_time; __dead void usage(void) @@ -134,6 +135,7 @@ main(int argc, char *argv[]) if (pledge("stdio", NULL) == -1) err(1, "pledge"); + abs_time = 1; memset(&ribreq, 0, sizeof(ribreq)); if (res->as.type != AS_UNDEF) ribreq.as = res->as; @@ -588,14 +590,10 @@ show(struct imsg *imsg, struct parse_res } time_t -get_rel_monotime(monotime_t t) +get_rel_monotime(monotime_t mt) { - monotime_t now; - - if (!monotime_valid(t)) - return 0; - now = getmonotime(); - return monotime_to_sec(monotime_sub(now, t)); + mt = monotime_sub(getmonotime(), mt); + return monotime_to_sec(mt); } char * @@ -644,7 +642,7 @@ fmt_auth_method(enum auth_method method) } } -#define TF_LEN 16 +#define TF_LEN 64 static const char * fmt_timeframe(time_t t) @@ -670,7 +668,7 @@ fmt_timeframe(time_t t) week /= 7; if (week >= 1000) - snprintf(buf, sizeof(buf), "%s%02lluw", due, week); + snprintf(buf, sizeof(buf), "%s%lluw", due, week); else if (week > 0) snprintf(buf, sizeof(buf), "%s%02lluw%01ud%02uh", due, week, day, hrs); @@ -688,12 +686,23 @@ const char * fmt_monotime(monotime_t mt) { time_t t; + monotime_t z = monotime_clear(); - if (!monotime_valid(mt)) - return ("Never"); - - t = get_rel_monotime(mt); - return (fmt_timeframe(t)); + if (abs_time) { + struct tm *tm; + static char buf[TF_LEN]; + + t = monotime_to_time(mt); + if ((tm = gmtime(&t)) == NULL) + return "invalid"; + strftime(buf, sizeof(buf), "%FT%TZ", tm); + return (buf); + } else { + if (monotime_cmp(mt, z) == 0) + return ("Never"); + t = get_rel_monotime(mt); + return (fmt_timeframe(t)); + } } const char * Index: output.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v diff -u -p -r1.76 output.c --- output.c 18 May 2026 09:22:09 -0000 1.76 +++ output.c 21 May 2026 12:49:51 -0000 @@ -1045,7 +1045,7 @@ show_rib_detail(struct ctl_show_rib *r, printf("avs %s, %s", fmt_avs(r->aspa_validation_state, 0), fmt_flags(r->flags, 0)); - printf("%c Last update: %s ago%c", EOL0(flag0), + printf("%c Last update: %s%c", EOL0(flag0), fmt_monotime(r->lastchange), EOL0(flag0)); }