From e425da2f1704d2ec1677af36e900518993d9f98d Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 25 Oct 2013 14:45:33 +0200 Subject: [PATCH 1/3] Add random delay to announce timeout. According to 9.2.6.11 of the spec the ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES timeout in addition to announceReceiptTimeoutInterval includes a random number up to one announceInterval. Add a new function for setting random timeout and use it in port_set_announce_tmo(). Signed-off-by: Miroslav Lichvar --- port.c | 27 +++++++++++++++++++++++++-- port.h | 15 +++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/port.c b/port.c index bd10d0a..dcd3f00 100644 --- a/port.c +++ b/port.c @@ -231,6 +231,29 @@ int set_tmo_lin(int fd, int seconds) return timerfd_settime(fd, 0, &tmo, NULL); } +int set_tmo_random(int fd, int min, int span, int log_seconds) +{ + uint64_t value_ns, min_ns, span_ns; + struct itimerspec tmo = { + {0, 0}, {0, 0} + }; + + if (log_seconds >= 0) { + min_ns = min * NS_PER_SEC << log_seconds; + span_ns = span * NS_PER_SEC << log_seconds; + } else { + min_ns = min * NS_PER_SEC >> -log_seconds; + span_ns = span * NS_PER_SEC >> -log_seconds; + } + + value_ns = min_ns + (span_ns * (random() % (1 << 15) + 1) >> 15); + + tmo.it_value.tv_sec = value_ns / NS_PER_SEC; + tmo.it_value.tv_nsec = value_ns % NS_PER_SEC; + + return timerfd_settime(fd, 0, &tmo, NULL); +} + static void fc_clear(struct foreign_clock *fc) { struct ptp_message *m; @@ -786,8 +809,8 @@ static void port_nrate_initialize(struct port *p) static int port_set_announce_tmo(struct port *p) { - return set_tmo_log(p->fda.fd[FD_ANNOUNCE_TIMER], - p->announceReceiptTimeout, p->logAnnounceInterval); + return set_tmo_random(p->fda.fd[FD_ANNOUNCE_TIMER], + p->announceReceiptTimeout, 1, p->logAnnounceInterval); } static int port_set_delay_tmo(struct port *p) diff --git a/port.h b/port.h index 5fef028..e781f24 100644 --- a/port.h +++ b/port.h @@ -173,6 +173,21 @@ enum port_state port_state(struct port *port); */ int set_tmo_log(int fd, unsigned int scale, int log_seconds); +/** + * Utility function for setting a file descriptor timer. + * + * This function sets the timer 'fd' to a random value between M * 2^N and + * (M + S) * 2^N, where M is the value of the 'min' parameter, S is the value + * of the 'span' parameter, and N in the value of the 'log_seconds' parameter. + * + * @param fd A file descriptor previously opened with timerfd_create(2). + * @param min The minimum value for the timer. + * @param span The span value for the timer. Must be a positive value. + * @param log_seconds The exponential factor for the timer. + * @return Zero on success, non-zero otherwise. + */ +int set_tmo_random(int fd, int min, int span, int log_seconds); + /** * Utility function for setting or resetting a file descriptor timer. * From 23d31d090ebb3a077d3dbbb86175818b23e9b0a7 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 25 Oct 2013 14:45:34 +0200 Subject: [PATCH 2/3] Drop tmtab module. Instead of maintaining a table of precalculated values, use the newly added set_tmo_random() function to set the delay request timeout. It saves some memory and improves the timeout granularity, but has a higher computational cost. It follows the requirements from section 9.5.11.2 of the spec. Signed-off-by: Miroslav Lichvar --- makefile | 2 +- port.c | 15 +++------------ tmtab.c | 54 ------------------------------------------------------ tmtab.h | 56 -------------------------------------------------------- 4 files changed, 4 insertions(+), 123 deletions(-) delete mode 100644 tmtab.c delete mode 100644 tmtab.h diff --git a/makefile b/makefile index 3f7ec90..021e3d7 100644 --- a/makefile +++ b/makefile @@ -25,7 +25,7 @@ LDLIBS = -lm -lrt $(EXTRA_LDFLAGS) PRG = ptp4l pmc phc2sys hwstamp_ctl OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o fault.o \ fsm.o ptp4l.o mave.o msg.o phc.o pi.o port.o print.o raw.o servo.o \ - sk.o stats.o tlv.o tmtab.o transport.o udp.o udp6.o uds.o util.o version.o + sk.o stats.o tlv.o transport.o udp.o udp6.o uds.o util.o version.o OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o SRC = $(OBJECTS:.o=.c) diff --git a/port.c b/port.c index dcd3f00..de813bc 100644 --- a/port.c +++ b/port.c @@ -32,7 +32,6 @@ #include "print.h" #include "sk.h" #include "tlv.h" -#include "tmtab.h" #include "tmv.h" #include "util.h" @@ -80,7 +79,6 @@ struct port { UInteger16 delayreq; UInteger16 sync; } seqnum; - struct tmtab tmtab; tmv_t peer_delay; struct mave *avg_delay; int log_sync_interval; @@ -815,17 +813,13 @@ static int port_set_announce_tmo(struct port *p) static int port_set_delay_tmo(struct port *p) { - struct itimerspec tmo = { - {0, 0}, {0, 0} - }; - int index; if (p->delayMechanism == DM_P2P) { return set_tmo_log(p->fda.fd[FD_DELAY_TIMER], 1, p->logMinPdelayReqInterval); + } else { + return set_tmo_random(p->fda.fd[FD_DELAY_TIMER], 0, 2, + p->logMinDelayReqInterval); } - index = random() % TMTAB_MAX; - tmo.it_value = p->tmtab.ts[index]; - return timerfd_settime(p->fda.fd[FD_DELAY_TIMER], 0, &tmo, NULL); } static int port_set_manno_tmo(struct port *p) @@ -1327,8 +1321,6 @@ static int port_initialize(struct port *p) p->logMinPdelayReqInterval = p->pod.logMinPdelayReqInterval; p->neighborPropDelayThresh = p->pod.neighborPropDelayThresh; - tmtab_init(&p->tmtab, 1 + p->logMinDelayReqInterval); - for (i = 0; i < N_TIMER_FDS; i++) { fd[i] = -1; } @@ -1534,7 +1526,6 @@ static void process_delay_resp(struct port *p, struct ptp_message *m) p->logMinDelayReqInterval = rsp->hdr.logMessageInterval; pr_notice("port %hu: minimum delay request interval 2^%d", portnum(p), p->logMinDelayReqInterval); - tmtab_init(&p->tmtab, 1 + p->logMinDelayReqInterval); } } diff --git a/tmtab.c b/tmtab.c deleted file mode 100644 index 7fa9f50..0000000 --- a/tmtab.c +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file tmtab.c - * @note Copyright (C) 2011 Richard Cochran - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#include "tmtab.h" -#include "tmv.h" - -void tmtab_init(struct tmtab *tt, int log_seconds) -{ - int i; - struct timespec incr, ts = {0, 0}; - uint64_t max, min; - - if (log_seconds < 0) { - log_seconds *= -1; - for (i = 1, max = 500000000ULL; i < log_seconds; i++) { - max >>= 1; - } - } else { - for (i = 0, max = 1000000000ULL; i < log_seconds; i++) { - max <<= 1; - } - } - - min = max / (TMTAB_MAX - 1ULL); - - incr.tv_sec = min / 1000000000ULL; - incr.tv_nsec = min % 1000000000ULL; - - for (i = 0; i < TMTAB_MAX; i++) { - ts.tv_sec += incr.tv_sec; - ts.tv_nsec += incr.tv_nsec; - while (ts.tv_nsec >= NS_PER_SEC) { - ts.tv_nsec -= NS_PER_SEC; - ts.tv_sec++; - } - tt->ts[i] = ts; - } -} - diff --git a/tmtab.h b/tmtab.h deleted file mode 100644 index 9b80cc6..0000000 --- a/tmtab.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file tmtab.h - * @brief Implements a table of time out values. - * @note Copyright (C) 2011 Richard Cochran - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef HAVE_TMTAB_H -#define HAVE_TMTAB_H - -#include - -/* - * Let 'D' be the logMinDelayReqInterval - * and 'S' be the logSyncInterval. - * - * The delay request interval ranges from zero to 2^{D+1} seconds. - * The standard requires that - * - * S <= D <= S+5 - * - * and the timeout granularity not more than 2^{S-4} seconds. - * Thus, the minimum required number of grains is given by - * - * 2^{D+1} / 2^{S-4} = 2^{D-S+5} - * - * and finds a minimum of 2^5 and a maximum of 2^10. - * - * The timeout table allows for the maximum number of grains required. - * - * Note that the table is made to be biased so that when sampling the - * table randomly, the average delay value will be slightly larger - * than logMinDelayReqInterval, in order to satisfy the wording of the - * standard. - */ -#define TMTAB_MAX 1024 - -struct tmtab { - struct timespec ts[TMTAB_MAX]; -}; - -void tmtab_init(struct tmtab *tt, int log_seconds); - -#endif From ab84eade0a946e094f0852430d47625e38a6a3c5 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 25 Oct 2013 14:45:35 +0200 Subject: [PATCH 3/3] Make random() more random between machines. Include also nanoseconds from the current time in the srandom() call. This should significantly decrease the chance of two machines using the same random sequence. Signed-off-by: Miroslav Lichvar --- clock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clock.c b/clock.c index 74d5c77..f6bad00 100644 --- a/clock.c +++ b/clock.c @@ -576,12 +576,14 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, struct clock *c = &the_clock; char phc[32]; struct interface udsif; + struct timespec ts; memset(&udsif, 0, sizeof(udsif)); snprintf(udsif.name, sizeof(udsif.name), "%s", uds_path); udsif.transport = TRANS_UDS; - srandom(time(NULL)); + clock_gettime(CLOCK_REALTIME, &ts); + srandom(ts.tv_sec ^ ts.tv_nsec); if (c->nports) clock_destroy(c);