timesyncd-manager.c revision 69f0081748fb4be1b7b772815e5c4202cdb88d3d
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 Kay Sievers, Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* expected accuracy of time synchronization; used to adjust the poll interval */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * "A client MUST NOT under any conditions use a poll interval less
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * than 15 seconds."
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Maximum delta in seconds which the system clock is gradually adjusted
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * (slew) to approach the network time. Deltas larger that this are set by
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * letting the system time jump. The kernel's limit for adjtime is 0.5s.
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen/* NTP protocol, packet header */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define NTP_FIELD_VERSION(f) (((f) >> 3) & 7)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define NTP_FIELD(l, v, m) (((l) << 6) | ((v) << 3) | (m))
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen/* Maximum acceptable root distance in seconds. */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen/* Maximum number of missed replies before selecting another source. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * "NTP timestamps are represented as a 64-bit unsigned fixed-point number,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * in seconds relative to 0h on 1 January 1900."
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#define RATELIMIT_INTERVAL_USEC (10*USEC_PER_SEC)
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poetteringstatic int manager_arm_timer(Manager *m, usec_t next);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int manager_clock_watch_setup(Manager *m);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic double ntp_ts_to_d(const struct ntp_ts *ts) {
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return be32toh(ts->sec) + ((double)be32toh(ts->frac) / UINT_MAX);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic double ts_to_d(const struct timespec *ts) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return ts->tv_sec + (1.0e-9 * ts->tv_nsec);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poetteringstatic double square(double d) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poetteringstatic int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering server_address_pretty(m->current_server_address, &pretty);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering log_info("Timed out waiting for reply from %s (%s).", strna(pretty), m->current_server_name->string);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringstatic int manager_send_request(Manager *m) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * "The client initializes the NTP message header, sends the request
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * to the server, and strips the time of day from the Transmit
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * Timestamp field of the reply. For this purpose, all the NTP
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * header fields are set to 0, except the Mode, VN, and optional
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * Transmit Timestamp fields."
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering .field = NTP_FIELD(0, 4, NTP_MODE_CLIENT),
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering m->event_timeout = sd_event_source_unref(m->event_timeout);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * Set transmit timestamp, remember it; the server will send that back
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * as the origin timestamp and we have an indication that this is the
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * matching answer to our request.
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * The actual value does not matter, We do not care about the correct
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * NTP UINT_MAX fraction; we just pass the plain nanosecond value.
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering assert_se(clock_gettime(clock_boottime_or_monotonic(), &m->trans_time_mon) >= 0);
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering server_address_pretty(m->current_server_address, &pretty);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering len = sendto(m->server_socket, &ntpmsg, sizeof(ntpmsg), MSG_DONTWAIT, &m->current_server_address->sockaddr.sa, m->current_server_address->socklen);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering log_debug("Sent NTP request to %s (%s).", strna(pretty), m->current_server_name->string);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering log_debug("Sending NTP request to %s (%s) failed: %m", strna(pretty), m->current_server_name->string);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* re-arm timer with increasing timeout, in case the packets never arrive back */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (m->retry_interval < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = manager_arm_timer(m, m->retry_interval);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering log_error("Failed to rearm timer: %s", strerror(-r));
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (m->missed_replies > NTP_MAX_MISSED_REPLIES) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0,
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering log_error("Failed to arm timeout timer: %s", strerror(-r));
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringstatic int manager_timer(sd_event_source *source, usec_t usec, void *userdata) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringstatic int manager_arm_timer(Manager *m, usec_t next) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering m->event_timer = sd_event_source_unref(m->event_timer);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = sd_event_source_set_time(m->event_timer, now(clock_boottime_or_monotonic()) + next);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return sd_event_source_set_enabled(m->event_timer, SD_EVENT_ONESHOT);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering now(clock_boottime_or_monotonic()) + next, 0,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int manager_clock_watch(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* rearm timer */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* skip our own jumps */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering log_info("System time changed. Resyncing.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* wake up when the system time changes underneath us */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int manager_clock_watch_setup(Manager *m) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->clock_watch_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create timerfd: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (timerfd_settime(m->clock_watch_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to set up timerfd: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = sd_event_add_io(m->event, &m->event_clock_watch, m->clock_watch_fd, EPOLLIN, manager_clock_watch, m);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create clock watch event source: %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * For small deltas, tell the kernel to gradually adjust the system
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * clock to the NTP time, larger deltas are just directly set.
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering log_debug(" adjust (slew): %+.3f sec\n", offset);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* ADJ_NANO uses nanoseconds in the microseconds field */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* the kernel expects -0.3s as {-1, 7000.000.000} */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_debug(" adjust (jump): %+.3f sec\n", offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * An unset STA_UNSYNC will enable the kernel's 11-minute mode,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * which syncs the system time periodically to the RTC.
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * In case the RTC runs in local time, never touch the RTC,
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * we have no way to properly handle daylight saving changes and
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * mobile devices moving between time zones.
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering " time now : %li.%03llu\n"
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering " constant : %li\n"
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering " offset : %+.3f sec\n"
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering " freq offset : %+li (%i ppm)\n",
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering tmx.status, tmx.status & STA_UNSYNC ? "unsync" : "sync",
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers tmx.time.tv_sec, (unsigned long long) (tmx.time.tv_usec / NSEC_PER_MSEC),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic bool manager_sample_spike_detection(Manager *m, double offset, double delay) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* ignore initial sample */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* store the current data in our samples array */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers idx_new = (idx_cur + 1) % ELEMENTSOF(m->samples);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* calculate new jitter value from the RMS differences relative to the lowest delay sample */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering for (idx_min = idx_cur, i = 0; i < ELEMENTSOF(m->samples); i++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (m->samples[i].delay > 0 && m->samples[i].delay < m->samples[idx_min].delay)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers j += square(m->samples[i].offset - m->samples[idx_min].offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->samples_jitter = sqrt(j / (ELEMENTSOF(m->samples) - 1));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* ignore samples when resyncing */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return false;
27e72d6b22890ba4a8cbc05c49667cd1cccf1461Simon Peeters /* always accept offset if we are farther off than the round-trip delay */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return false;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering /* we need a few samples before looking at them */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* do not accept anything worse than the maximum possible error of the best sample */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return true;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* compare the difference between the current offset to the previous offset and jitter */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return fabs(offset - m->samples[idx_cur].offset) > 3 * jitter;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void manager_adjust_poll(Manager *m, double offset, bool spike) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* set to minimal poll interval */
8c841f21f5042b11acc91cc1b039cb162cbbe8f4Djalal Harouni if (!spike && fabs(offset) > NTP_ACCURACY_SEC) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* increase polling interval */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fabs(offset) < NTP_ACCURACY_SEC * 0.25) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* decrease polling interval */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (spike || fabs(offset) > NTP_ACCURACY_SEC * 0.75) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (m->poll_interval_usec > NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int manager_receive_response(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint8_t buf[CMSG_SPACE(sizeof(struct timeval))];
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_warning("Server connection returned error.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering len = recvmsg(fd, &msghdr, MSG_DONTWAIT);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering log_warning("Error receiving message. Disconnecting.");
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering if (iov.iov_len < sizeof(struct ntp_msg)) {
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering log_warning("Invalid response from server. Disconnecting.");
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering !sockaddr_equal(&server_addr, &m->current_server_address->sockaddr)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Response from unknown server.");
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering recv_time = (struct timespec *) CMSG_DATA(cmsg);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering log_debug("Unexpected reply. Ignoring.");
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering /* check our "time cookie" (we just stored nanoseconds in the fraction field) */
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 ||
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) {
3d94f76c99da13e5603831d0b278f8c8c21bcb02Lennart Poettering log_debug("Invalid reply; not our transmit time. Ignoring.");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering m->event_timeout = sd_event_source_unref(m->event_timeout);
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek if (be32toh(ntpmsg.recv_time.sec) < TIME_EPOCH + OFFSET_1900_1970 ||
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek be32toh(ntpmsg.trans_time.sec) < TIME_EPOCH + OFFSET_1900_1970) {
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek log_debug("Invalid reply, returned times before epoch. Ignoring.");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC ||
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ntpmsg.stratum == 0 || ntpmsg.stratum >= 16) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_debug("Server is not synchronized. Disconnecting.");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!IN_SET(NTP_FIELD_VERSION(ntpmsg.field), 3, 4)) {
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering log_debug("Response NTPv%d. Disconnecting.", NTP_FIELD_VERSION(ntpmsg.field));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (NTP_FIELD_MODE(ntpmsg.field) != NTP_MODE_SERVER) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_debug("Unsupported mode %d. Disconnecting.", NTP_FIELD_MODE(ntpmsg.field));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (root_distance > NTP_MAX_ROOT_DISTANCE) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_debug("Server has too large root distance. Disconnecting.");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* valid packet */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* announce leap seconds */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering else if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_MINUSSEC)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * "Timestamp Name ID When Generated
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * ------------------------------------------------------------
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * Originate Timestamp T1 time request sent by client
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * Receive Timestamp T2 time request received by server
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering * Transmit Timestamp T3 time reply sent by server
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * Destination Timestamp T4 time reply received by client
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * The round-trip delay, d, and system clock offset, t, are defined as:
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2"
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering origin = ts_to_d(&m->trans_time) + OFFSET_1900_1970;
fbadf04511389c4a0687ba5e9baf0ecebdbb07f1Lennart Poettering receive = ntp_ts_to_d(&ntpmsg.recv_time);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering dest = ts_to_d(recv_time) + OFFSET_1900_1970;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering offset = ((receive - origin) + (trans - dest)) / 2;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering delay = (dest - origin) - (trans - receive);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering spike = manager_sample_spike_detection(m, offset, delay);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " leap : %u\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " version : %u\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " mode : %u\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " stratum : %u\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " precision : %.6f sec (%d)\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " root distance: %.6f sec\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " reference : %.4s\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " origin : %.3f\n"
6261f11fc3d0a8b63c5afa5313d96607a008b54eLennart Poettering " receive : %.3f\n"
6261f11fc3d0a8b63c5afa5313d96607a008b54eLennart Poettering " transmit : %.3f\n"
6261f11fc3d0a8b63c5afa5313d96607a008b54eLennart Poettering " dest : %.3f\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " offset : %+.3f sec\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " delay : %+.3f sec\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering " jitter : %.3f%s\n"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering exp2(ntpmsg.precision), ntpmsg.precision,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a",
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering m->samples_jitter, spike ? " spike" : "",
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = manager_adjust_clock(m, offset, leap_sec);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Failed to call clock_adjtime(): %m");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_info("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s",
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = manager_arm_timer(m, m->poll_interval_usec);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("Failed to rearm timer: %s", strerror(-r));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic int manager_listen_setup(Manager *m) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering addr.sa.sa_family = m->current_server_address->sockaddr.sa.sa_family;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering m->server_socket = socket(addr.sa.sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = bind(m->server_socket, &addr.sa, m->current_server_address->socklen);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(on));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering (void) setsockopt(m->server_socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return sd_event_add_io(m->event, &m->event_receive, m->server_socket, EPOLLIN, manager_receive_response, m);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert_return(m->current_server_name, -EHOSTUNREACH);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert_return(m->current_server_address, -EHOSTUNREACH);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering m->missed_replies = NTP_MAX_MISSED_REPLIES;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering server_address_pretty(m->current_server_address, &pretty);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering sd_notifyf(false, "STATUS=Using Time Server %s (%s).", strna(pretty), m->current_server_name->string);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_warning("Failed to setup connection socket: %s", strerror(-r));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringvoid manager_set_server_name(Manager *m, ServerName *n) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_debug("Selected server %s.", n->string);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringvoid manager_set_server_address(Manager *m, ServerAddress *a) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* If a is NULL, we are just clearing the address, without
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * changing the name. Keep the existing name in that case. */
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen _cleanup_free_ char *pretty = NULL;
53755121e1c8ebd3db0330bc82965ecf9a986449Lennart Poettering log_debug("Selected address %s of server %s.", strna(pretty), a->name->string);
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poetteringstatic int manager_resolve_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering m->resolve_query = sd_resolve_query_unref(m->resolve_query);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Failed to resolve %s: %s", m->current_server_name->string, gai_strerror(ret));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Try next host */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(ai->ai_addrlen >= offsetof(struct sockaddr, sa_data));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!IN_SET(ai->ai_addr->sa_family, AF_INET, AF_INET6)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_warning("Unsuitable address protocol for %s", m->current_server_name->string);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = server_address_new(m->current_server_name, &a, (const union sockaddr_union*) ai->ai_addr, ai->ai_addrlen);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to add server address: %s", strerror(-r));
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering log_debug("Resolved address %s for %s.", pretty, m->current_server_name->string);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!m->current_server_name->addresses) {
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering log_error("Failed to find suitable address for host %s.", m->current_server_name->string);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Try next host */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering manager_set_server_address(m, m->current_server_name->addresses);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int manager_retry_connect(sd_event_source *source, usec_t usec, void *userdata) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->event_retry = sd_event_source_unref(m->event_retry);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Slowing down attempts to contact servers.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + RETRY_USEC, 0, manager_retry_connect, m);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create retry timer: %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If we already are operating on some address, switch to the
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen if (m->current_server_address && m->current_server_address->addresses_next)
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen manager_set_server_address(m, m->current_server_address->addresses_next);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Hmm, we are through all addresses, let's look for the next host instead */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (m->current_server_name && m->current_server_name->names_next)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering manager_set_server_name(m, m->current_server_name->names_next);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Our current server name list is exhausted,
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering * let's find the next one to iterate. First
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * we try the system list, then the link list.
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * After having processed the link list we
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * jump back to the system list. However, if
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * both lists are empty, we change to the
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering * fallback list. */
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (!m->current_server_name || m->current_server_name->type == SERVER_LINK) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (restart && !m->exhausted_servers && m->poll_interval_usec) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Waiting after exhausting servers.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + m->poll_interval_usec, 0, manager_retry_connect, m);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create retry timer: %s", strerror(-r));
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering /* Increase the polling interval */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (m->poll_interval_usec < NTP_POLL_INTERVAL_MAX_SEC * USEC_PER_SEC)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Tell the resolver to reread /etc/resolv.conf, in
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * case it changed. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Flush out any previously resolved addresses */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering server_name_flush_addresses(m->current_server_name);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Resolving %s...", m->current_server_name->string);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = sd_resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, m);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to create resolver: %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->resolve_query = sd_resolve_query_unref(m->resolve_query);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->event_timer = sd_event_source_unref(m->event_timer);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->event_receive = sd_event_source_unref(m->event_receive);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->server_socket = safe_close(m->server_socket);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->clock_watch_fd = safe_close(m->clock_watch_fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering m->event_timeout = sd_event_source_unref(m->event_timeout);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringvoid manager_flush_server_names(Manager *m, ServerType t) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering manager_flush_server_names(m, SERVER_SYSTEM);
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering manager_flush_server_names(m, SERVER_LINK);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen manager_flush_server_names(m, SERVER_FALLBACK);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_event_source_unref(m->network_event_source);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering sd_network_monitor_unref(m->network_monitor);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int manager_network_read_link_servers(Manager *m) {
assert(m);
goto clear;
n->marked = true;
bool found = false;
n->marked = false;
found = true;
if (!found) {
goto clear;
if (n->marked)
server_name_free(n);
static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
assert(m);
if (m->current_server_address)
r = manager_begin(m);
r = manager_connect(m);
assert(m);
if (fd < 0)
return fd;
if (events < 0)
return events;
r = sd_event_add_io(m->event, &m->network_event_source, fd, events, manager_network_event_handler, m);
return -ENOMEM;
r = manager_network_monitor_listen(m);
*ret = m;
m = NULL;