diff options
author | Thomas Haller <thaller@redhat.com> | 2019-12-15 10:33:28 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-12-15 13:50:45 +0100 |
commit | a1771c738dd2e1437bd9f7c73805fd8a1b1b3d1d (patch) | |
tree | 4d877ec7ad2248e8350ae4d2962e10179df0a68d | |
parent | 6c716912eb6ddcbf56feee1913bf9235deae20c0 (diff) | |
download | NetworkManager-a1771c738dd2e1437bd9f7c73805fd8a1b1b3d1d.tar.gz |
client: fallback to CLOCK_MONOTONIC for timerfd
RHEL7 supports clock_gettime(CLOCK_BOOTIME), but it does not support
timerfd_create(CLOCK_BOOTIME). Creating a timerfd will fail with EINVAL.
Fallback to CLOCK_MONOTONIC.
Compare this to n-acd which also has compatibility code to fallback to
CLOCK_MONOTONIC. However when n-acd falls back to CLOCK_MONOTONIC, it uses
monotonic clock also for clock_gettime().
For n-dhcp4, the timestamps are also exposed in the public API
(n_dhcp4_client_lease_get_lifetime()). Hence, for timestamps n-dhcp4
still uses and requires clock_gettime(CLOCK_BOOTIME). Only the internal
timeout handling with the timerfd falls back to CLOCK_MONOTONIC.
https://github.com/nettools/n-dhcp4/pull/13
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/362
-rw-r--r-- | shared/n-dhcp4/src/n-dhcp4-client.c | 30 | ||||
-rw-r--r-- | shared/n-dhcp4/src/n-dhcp4-private.h | 1 |
2 files changed, 27 insertions, 4 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c index 5449106a9b..0bfe48ee95 100644 --- a/shared/n-dhcp4/src/n-dhcp4-client.c +++ b/shared/n-dhcp4/src/n-dhcp4-client.c @@ -388,8 +388,14 @@ _c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *co return -errno; client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK); - if (client->fd_timer < 0) - return -errno; + if (client->fd_timer < 0) { + if (errno != EINVAL) + return -errno; + client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + if (client->fd_timer < 0) + return -errno; + client->timerfd_is_monotonic = true; + } ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER; r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev); @@ -499,8 +505,24 @@ void n_dhcp4_client_arm_timer(NDhcp4Client *client) { n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout); if (timeout != client->scheduled_timeout) { + uint64_t scheduled_timeout = timeout; + int flags = TFD_TIMER_ABSTIME; + + if ( timeout != 0 + && client->timerfd_is_monotonic) { + uint64_t now; + + /* the timerfd ticks with CLOCK_MONOTONIC. Calculate and set the relative + * timeout. */ + now = n_dhcp4_gettime(CLOCK_BOOTTIME); + if (timeout <= now) + timeout = 1; + else + timeout = timeout - now; + flags = 0; + } r = timerfd_settime(client->fd_timer, - TFD_TIMER_ABSTIME, + flags, &(struct itimerspec){ .it_value = { .tv_sec = timeout / UINT64_C(1000000000), @@ -510,7 +532,7 @@ void n_dhcp4_client_arm_timer(NDhcp4Client *client) { NULL); c_assert(r >= 0); - client->scheduled_timeout = timeout; + client->scheduled_timeout = scheduled_timeout; } } diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h index fa2fda38de..1cf5f25e55 100644 --- a/shared/n-dhcp4/src/n-dhcp4-private.h +++ b/shared/n-dhcp4/src/n-dhcp4-private.h @@ -332,6 +332,7 @@ struct NDhcp4Client { uint64_t scheduled_timeout; bool preempted : 1; + bool timerfd_is_monotonic : 1; }; #define N_DHCP4_CLIENT_NULL(_x) { \ |