From: Vincent Bernat Date: Thu, 18 May 2023 13:25:35 +0000 (+0200) Subject: daemon: use monotonic clock for age X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=df28002f84052fdd8426b4340d3459fefb5720ab;p=thirdparty%2Flldpd.git daemon: use monotonic clock for age Fix #572. However, this break two things: - existing client comparing the age to the non-monotonic clock - SNMP agent which should report time since start time which is not monotonic either --- diff --git a/NEWS b/NEWS index 6fda933e..ceeeb104 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ lldpd (1.0.17) * Fix: + Read overflow when parsing CDP addresses. Thanks to Matteo Memelli. + Don't output empty lines on configure commands. + + Use monotonic clock for age (this may break some clients). lldpd (1.0.16) * Fix: diff --git a/configure.ac b/configure.ac index 65e828aa..42fccd84 100644 --- a/configure.ac +++ b/configure.ac @@ -239,6 +239,7 @@ fi AC_REPLACE_FUNCS([setproctitle]) AC_CHECK_FUNCS([setproctitle_init]) # Other functions +AC_SEARCH_LIBS([clock_gettime], [rt]) AC_REPLACE_FUNCS([strlcpy strnlen strndup @@ -246,7 +247,8 @@ AC_REPLACE_FUNCS([strlcpy getline asprintf vsyslog - daemon]) + daemon + clock_gettime]) # Optional functions AC_CHECK_FUNCS([setresuid setresgid]) diff --git a/src/Makefile.am b/src/Makefile.am index 19644f3e..ebdaa083 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,8 +9,9 @@ libcommon_daemon_lib_la_SOURCES = \ log.c log.h version.c \ marshal.c marshal.h \ ctl.c ctl.h \ + now.c now.h \ lldpd-structs.c lldpd-structs.h lldp-const.h libcommon_daemon_lib_la_LIBADD = compat/libcompat.la -libcommon_daemon_client_la_SOURCES = log.c log.h version.c lldp-const.h +libcommon_daemon_client_la_SOURCES = log.c log.h now.c now.h version.c lldp-const.h libcommon_daemon_client_la_LIBADD = compat/libcompat.la diff --git a/src/client/display.c b/src/client/display.c index c59c4788..c6825200 100644 --- a/src/client/display.c +++ b/src/client/display.c @@ -28,6 +28,7 @@ #include #include "../log.h" +#include "../now.h" #include "client.h" static void @@ -684,7 +685,7 @@ static const char * display_age(time_t lastchange) { static char sage[30]; - int age = (int)(time(NULL) - lastchange); + int age = (int)(monotonic_now() - lastchange); if (snprintf(sage, sizeof(sage), "%d day%s, %02d:%02d:%02d", age / (60 * 60 * 24), (age / (60 * 60 * 24) > 1) ? "s" : "", (age / (60 * 60)) % 24, (age / 60) % 60, age % 60) >= sizeof(sage)) diff --git a/src/compat/clock_gettime.c b/src/compat/clock_gettime.c new file mode 100644 index 00000000..b687bafb --- /dev/null +++ b/src/compat/clock_gettime.c @@ -0,0 +1,27 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2023 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "compat.h" +#include + +int +clock_gettime(clockid_t clk_id, struct timespec *ts) +{ + ts->tv_sec = time(NULL); + ts->tv_nsec = 0; + return 0; +} diff --git a/src/compat/compat.h b/src/compat/compat.h index 91ff4ade..fde975af 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -42,6 +42,7 @@ #include #include #include +#include #undef getopt @@ -90,4 +91,13 @@ void *malloc(size_t size); void *realloc(void *ptr, size_t size); #endif +#ifndef CLOCK_MONOTONIC +# define CLOCK_MONOTONIC -1 +#endif + +#if !HAVE_CLOCK_GETTIME +typedef int clockid_t; +int clock_gettime(clockid_t, struct timespec *); +#endif + #endif diff --git a/src/daemon/event.c b/src/daemon/event.c index 971500f2..90593d41 100644 --- a/src/daemon/event.c +++ b/src/daemon/event.c @@ -775,7 +775,7 @@ levent_schedule_cleanup(struct lldpd *cfg) /* Compute the next TTL event */ struct timeval tv = { cfg->g_config.c_ttl, 0 }; - time_t now = time(NULL); + time_t now = monotonic_now(); time_t next; struct lldpd_hardware *hardware; struct lldpd_port *port; diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index c7f1082f..57ca4933 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -575,7 +575,7 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardw (memcmp(oport->p_lastframe->frame, frame, s) == 0)) { /* Already received the same frame */ log_debug("decode", "duplicate frame, no need to decode"); - oport->p_lastupdate = time(NULL); + oport->p_lastupdate = monotonic_now(); return; } } @@ -684,7 +684,8 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardw log_debug("decode", "%d different systems are known", i); } /* Add port */ - port->p_lastchange = port->p_lastupdate = time(NULL); + + port->p_lastchange = port->p_lastupdate = monotonic_now(); if ((port->p_lastframe = (struct lldpd_frame *)malloc( s + sizeof(struct lldpd_frame))) != NULL) { port->p_lastframe->size = s; diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index b8952945..25bf7332 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -54,6 +54,7 @@ #include "../marshal.h" #include "../log.h" #include "../ctl.h" +#include "../now.h" #include "../lldpd-structs.h" /* We don't want to import event2/event.h. We only need those as diff --git a/src/daemon/protocols/lldp.c b/src/daemon/protocols/lldp.c index 4f689a0c..fe172b44 100644 --- a/src/daemon/protocols/lldp.c +++ b/src/daemon/protocols/lldp.c @@ -496,7 +496,7 @@ end: frame->size) != 0)) { free(hardware->h_lport.p_lastframe); hardware->h_lport.p_lastframe = frame; - hardware->h_lport.p_lastchange = time(NULL); + hardware->h_lport.p_lastchange = monotonic_now(); } else free(frame); } diff --git a/src/lib/lldpctl.h b/src/lib/lldpctl.h index f1cb1d04..dd9792a6 100644 --- a/src/lib/lldpctl.h +++ b/src/lib/lldpctl.h @@ -738,7 +738,8 @@ typedef enum { lldpctl_k_port_neighbors = 1200, lldpctl_k_port_protocol, /**< `(IS)` The protocol that was used to retrieve this information. */ - lldpctl_k_port_age, /**< `(I)` Age of information, seconds from epoch. */ + lldpctl_k_port_age, /**< `(I)` Age of information (using system monotonic + clock) */ lldpctl_k_port_id_subtype, /**< `(IS)` The subtype ID of this port. */ lldpctl_k_port_id, /**< `(BS,WO)` The ID of this port. */ lldpctl_k_port_descr, /**< `(S,WO)` The description of this port. */ diff --git a/src/lldpd-structs.c b/src/lldpd-structs.c index 6b42713c..5a4f70de 100644 --- a/src/lldpd-structs.c +++ b/src/lldpd-structs.c @@ -20,6 +20,7 @@ #include #include "lldpd-structs.h" #include "log.h" +#include "now.h" void lldpd_chassis_mgmt_cleanup(struct lldpd_chassis *chassis) @@ -154,7 +155,7 @@ lldpd_remote_cleanup(struct lldpd_hardware *hardware, { struct lldpd_port *port, *port_next; int del; - time_t now = time(NULL); + time_t now = monotonic_now(); log_debug("alloc", "cleanup remote port on %s", hardware->h_ifname); for (port = TAILQ_FIRST(&hardware->h_rports); port != NULL; port = port_next) { @@ -175,7 +176,7 @@ lldpd_remote_cleanup(struct lldpd_hardware *hardware, hardware->h_delete_cnt++; /* Register last removal to be able to report * lldpStatsRemTablesLastChangeTime */ - hardware->h_lport.p_lastremove = time(NULL); + hardware->h_lport.p_lastremove = monotonic_now(); lldpd_port_cleanup(port, 1); free(port); } diff --git a/src/now.c b/src/now.c new file mode 100644 index 00000000..166c80a4 --- /dev/null +++ b/src/now.c @@ -0,0 +1,31 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2023 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "now.h" +#include "compat/compat.h" + +time_t +monotonic_now() +{ + struct timespec tp; + if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) { + return time(NULL); + } + return tp.tv_sec; +} diff --git a/src/now.h b/src/now.h new file mode 100644 index 00000000..2a5becfb --- /dev/null +++ b/src/now.h @@ -0,0 +1,29 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2023 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _NOW_H +#define _NOW_H + +#if HAVE_CONFIG_H +# include +#endif + +#include + +time_t monotonic_now(); + +#endif