gluon-radv-filterd: Use monotonic time source

The value returned by time is not monotonic. It can jump around because it
depends on a user configurable clock. This can lead to hangs in the
processing of routers.

A monotonic clock must be used instead to avoid this problem.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
Sven Eckelmann 2017-12-20 13:08:16 +01:00 committed by Jan-Philipp Litza
parent 8251de682a
commit dc70f244c8
No known key found for this signature in database
GPG Key ID: 1FB658053CE27196

View File

@ -101,7 +101,7 @@
struct router {
struct router *next;
struct ether_addr src;
time_t eol;
struct timespec eol;
struct ether_addr originator;
uint16_t tq;
};
@ -133,6 +133,20 @@ static void error_message(int status, int errnum, char *message, ...) {
exit(status);
}
static int timespec_diff(struct timespec *tv1, struct timespec *tv2,
struct timespec *tvdiff)
{
tvdiff->tv_sec = tv1->tv_sec - tv2->tv_sec;
if (tv1->tv_nsec < tv2->tv_nsec) {
tvdiff->tv_nsec = 1000000000 + tv1->tv_nsec - tv2->tv_nsec;
tvdiff->tv_sec -= 1;
} else {
tvdiff->tv_nsec = tv1->tv_nsec - tv2->tv_nsec;
}
return (tvdiff->tv_sec >= 0);
}
static void cleanup(void) {
struct router *router;
close(G.sock);
@ -298,7 +312,8 @@ static struct router *router_add(const struct ether_addr *mac) {
router->src = *mac;
router->next = G.routers;
G.routers = router;
router->eol = 0;
router->eol.tv_sec = 0;
router->eol.tv_nsec = 0;
return router;
}
@ -312,7 +327,8 @@ static void router_update(const struct ether_addr *mac, uint16_t timeout) {
if (!router)
return;
router->eol = time(NULL) + timeout;
clock_gettime(CLOCK_MONOTONIC, &router->eol);
router->eol.tv_sec += timeout;
}
static void handle_ra(int sock) {
@ -345,10 +361,13 @@ static void expire_routers(void) {
struct router **prev_ptr = &G.routers;
struct router *router;
struct router *safe;
time_t now = time(NULL);
struct timespec now;
struct timespec diff;
clock_gettime(CLOCK_MONOTONIC, &now);
foreach_safe(router, safe, G.routers) {
if (router->eol < now) {
if (timespec_diff(&now, &router->eol, &diff)) {
DEBUG_MSG("router " F_MAC " expired", F_MAC_VAR(router->src));
*prev_ptr = router->next;
if (G.best_router == router)
@ -593,7 +612,12 @@ int main(int argc, char *argv[]) {
int retval;
fd_set rfds;
struct timeval tv;
time_t last_update = time(NULL);
struct timespec next_update;
struct timespec now;
struct timespec diff;
clock_gettime(CLOCK_MONOTONIC, &next_update);
next_update.tv_sec += MIN_INTERVAL;
parse_cmdline(argc, argv);
@ -621,14 +645,18 @@ int main(int argc, char *argv[]) {
else
DEBUG_MSG("select() timeout expired");
if (G.routers != NULL && last_update <= time(NULL) - MIN_INTERVAL) {
clock_gettime(CLOCK_MONOTONIC, &now);
if (G.routers != NULL &&
timespec_diff(&now, &next_update, &diff)) {
expire_routers();
// all routers could have expired, check again
if (G.routers != NULL) {
update_tqs();
update_ebtables();
last_update = time(NULL);
next_update = now;
next_update.tv_sec += MIN_INTERVAL;
}
}
}