From e6f414e7880992e8d060a2c3a3b1ae80eea5201d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 14 2020 22:29:04 +0000 Subject: import linuxptp-2.0-5.el8 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b71a5b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +SOURCES/clknetsim-8b4842.tar.gz +SOURCES/linuxptp-2.0.tgz +SOURCES/linuxptp-testsuite-a7f6e1.tar.gz diff --git a/.linuxptp.metadata b/.linuxptp.metadata new file mode 100644 index 0000000..03e8cd2 --- /dev/null +++ b/.linuxptp.metadata @@ -0,0 +1,3 @@ +b674017c26433870107fb18e160c7d88d7d2eb86 SOURCES/clknetsim-8b4842.tar.gz +592ca42c6146a79c1fcabed7c19fa7af4803d4f6 SOURCES/linuxptp-2.0.tgz +2b8edc55e4967660a0c4a3892c817c0e8f55c3bc SOURCES/linuxptp-testsuite-a7f6e1.tar.gz diff --git a/SOURCES/linuxptp-addreq.patch b/SOURCES/linuxptp-addreq.patch new file mode 100644 index 0000000..284f7ee --- /dev/null +++ b/SOURCES/linuxptp-addreq.patch @@ -0,0 +1,12 @@ +diff -up linuxptp-2.0/util.c.addreq linuxptp-2.0/util.c +--- linuxptp-2.0/util.c.addreq 2019-03-25 11:43:55.878146767 +0100 ++++ linuxptp-2.0/util.c 2019-03-25 11:44:38.215244483 +0100 +@@ -78,7 +78,7 @@ int addreq(enum transport_type type, str + case TRANS_UDP_IPV4: + bufa = &a->sin.sin_addr; + bufb = &b->sin.sin_addr; +- len = sizeof(a->sin); ++ len = sizeof(a->sin.sin_addr); + break; + case TRANS_IEEE_802_3: + bufa = &a->sll.sll_addr; diff --git a/SOURCES/linuxptp-headers.patch b/SOURCES/linuxptp-headers.patch new file mode 100644 index 0000000..c1aca97 --- /dev/null +++ b/SOURCES/linuxptp-headers.patch @@ -0,0 +1,51 @@ +commit d663a483c40939bad58301c256d86da1f3da6cc0 +Author: Miroslav Lichvar +Date: Tue Nov 13 13:16:08 2018 +0100 + + Fix building with new kernel headers. + + net_tstamp.h in recent kernel versions requires time.h for clockid_t. + + Signed-off-by: Miroslav Lichvar + +diff --git a/clock.c b/clock.c +index 9c493c3..8533b39 100644 +--- a/clock.c ++++ b/clock.c +@@ -17,11 +17,11 @@ + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include ++#include + #include + #include + #include + #include +-#include + #include + + #include "address.h" +diff --git a/sk.c b/sk.c +index e2b1f28..30162eb 100644 +--- a/sk.c ++++ b/sk.c +@@ -18,6 +18,7 @@ + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include ++#include + #include + #include + #include +diff --git a/timemaster.c b/timemaster.c +index 058678f..00db59f 100644 +--- a/timemaster.c ++++ b/timemaster.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/SOURCES/linuxptp-hwtsfilter.patch b/SOURCES/linuxptp-hwtsfilter.patch new file mode 100644 index 0000000..3c3bc72 --- /dev/null +++ b/SOURCES/linuxptp-hwtsfilter.patch @@ -0,0 +1,228 @@ +commit 399907db7f9dc3f57c3f9831b3b4da705a2c51a3 +Author: Erez Geva +Date: Tue Aug 28 22:05:28 2018 +0200 + + config: Add hardware time stamp filter setting mode + + Add global option for the hardware time stamp setting. + The function could: + Normally set the filters as the PTP daemon require. + Check that the filters are proper but do not change them. + Full, set the RX filter to all and the TX filter as the PTP daemon require. + + [ RC: added missing extern keyword and fixed indentation. ] + + Signed-off-by: Erez Geva + Signed-off-by: Erez Geva + +diff --git a/config.c b/config.c +index 7914ba4..3530ce6 100644 +--- a/config.c ++++ b/config.c +@@ -164,6 +164,13 @@ static struct config_enum delay_mech_enu[] = { + { NULL, 0 }, + }; + ++static struct config_enum hwts_filter_enu[] = { ++ { "normal", HWTS_FILTER_NORMAL }, ++ { "check", HWTS_FILTER_CHECK }, ++ { "full", HWTS_FILTER_FULL }, ++ { NULL, 0 }, ++}; ++ + static struct config_enum nw_trans_enu[] = { + { "L2", TRANS_IEEE_802_3 }, + { "UDPv4", TRANS_UDP_IPV4 }, +@@ -215,6 +222,7 @@ struct config_item config_tab[] = { + GLOB_ITEM_INT("G.8275.defaultDS.localPriority", 128, 1, UINT8_MAX), + PORT_ITEM_INT("G.8275.portDS.localPriority", 128, 1, UINT8_MAX), + GLOB_ITEM_INT("gmCapable", 1, 0, 1), ++ GLOB_ITEM_ENU("hwts_filter", HWTS_FILTER_NORMAL, hwts_filter_enu), + PORT_ITEM_INT("hybrid_e2e", 0, 0, 1), + PORT_ITEM_INT("ignore_transport_specific", 0, 0, 1), + PORT_ITEM_INT("ingressLatency", 0, INT_MIN, INT_MAX), +diff --git a/ptp4l.8 b/ptp4l.8 +index 10c5c2f..39bf36e 100644 +--- a/ptp4l.8 ++++ b/ptp4l.8 +@@ -661,6 +661,15 @@ The time source is a single byte code that gives an idea of the kind + of local clock in use. The value is purely informational, having no + effect on the outcome of the Best Master Clock algorithm, and is + advertised when the clock becomes grand master. ++.TP ++.B hwts_filter ++Select the hardware time stamp filter setting mode. ++Possible values are normal, check, full. ++Normal mode set the filters as needed. ++Check mode only check but do not set. ++Full mode set the receive filter to mark all packets with hardware time stamp, ++ so all applications can get them. ++The default is normal. + + .SH UNICAST DISCOVERY OPTIONS + +diff --git a/ptp4l.c b/ptp4l.c +index 9ef8169..3a9f084 100644 +--- a/ptp4l.c ++++ b/ptp4l.c +@@ -191,6 +191,7 @@ int main(int argc, char *argv[]) + assume_two_step = config_get_int(cfg, NULL, "assume_two_step"); + sk_check_fupsync = config_get_int(cfg, NULL, "check_fup_sync"); + sk_tx_timeout = config_get_int(cfg, NULL, "tx_timestamp_timeout"); ++ sk_hwts_filter_mode = config_get_int(cfg, NULL, "hwts_filter"); + + if (config_get_int(cfg, NULL, "clock_servo") == CLOCK_SERVO_NTPSHM) { + config_set_int(cfg, "kernel_leap", 0); +diff --git a/sk.c b/sk.c +index f18b2bf..43f1800 100644 +--- a/sk.c ++++ b/sk.c +@@ -40,39 +40,76 @@ + + int sk_tx_timeout = 1; + int sk_check_fupsync; ++enum hwts_filter_mode sk_hwts_filter_mode = HWTS_FILTER_NORMAL; + + /* private methods */ + +-static int hwts_init(int fd, const char *device, int rx_filter, int tx_type) ++static void init_ifreq(struct ifreq *ifreq, struct hwtstamp_config *cfg, ++ const char *device) + { +- struct ifreq ifreq; +- struct hwtstamp_config cfg, req; +- int err; ++ memset(ifreq, 0, sizeof(*ifreq)); ++ memset(cfg, 0, sizeof(*cfg)); + +- memset(&ifreq, 0, sizeof(ifreq)); +- memset(&cfg, 0, sizeof(cfg)); ++ strncpy(ifreq->ifr_name, device, sizeof(ifreq->ifr_name) - 1); + +- strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1); ++ ifreq->ifr_data = (void *) cfg; ++} + +- ifreq.ifr_data = (void *) &cfg; +- cfg.tx_type = tx_type; +- cfg.rx_filter = rx_filter; +- req = cfg; +- err = ioctl(fd, SIOCSHWTSTAMP, &ifreq); +- if (err < 0) +- return err; ++static int hwts_init(int fd, const char *device, int rx_filter, ++ int rx_filter2, int tx_type) ++{ ++ struct ifreq ifreq; ++ struct hwtstamp_config cfg; ++ int err; + +- if (memcmp(&cfg, &req, sizeof(cfg))) { ++ init_ifreq(&ifreq, &cfg, device); + +- pr_debug("driver changed our HWTSTAMP options"); +- pr_debug("tx_type %d not %d", cfg.tx_type, req.tx_type); +- pr_debug("rx_filter %d not %d", cfg.rx_filter, req.rx_filter); ++ switch (sk_hwts_filter_mode) { ++ case HWTS_FILTER_CHECK: ++ err = ioctl(fd, SIOCGHWTSTAMP, &ifreq); ++ if (err < 0) { ++ pr_err("ioctl SIOCGHWTSTAMP failed: %m"); ++ return err; ++ } ++ break; ++ case HWTS_FILTER_FULL: ++ cfg.tx_type = tx_type; ++ cfg.rx_filter = HWTSTAMP_FILTER_ALL; ++ err = ioctl(fd, SIOCSHWTSTAMP, &ifreq); ++ if (err < 0) { ++ pr_err("ioctl SIOCSHWTSTAMP failed: %m"); ++ return err; ++ } ++ break; ++ case HWTS_FILTER_NORMAL: ++ cfg.tx_type = tx_type; ++ cfg.rx_filter = rx_filter; ++ err = ioctl(fd, SIOCSHWTSTAMP, &ifreq); ++ if (err < 0) { ++ pr_info("driver rejected most general HWTSTAMP filter"); + +- if (cfg.tx_type != req.tx_type || +- (cfg.rx_filter != HWTSTAMP_FILTER_ALL && +- cfg.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT)) { +- return -1; ++ init_ifreq(&ifreq, &cfg, device); ++ cfg.tx_type = tx_type; ++ cfg.rx_filter = rx_filter2; ++ ++ err = ioctl(fd, SIOCSHWTSTAMP, &ifreq); ++ if (err < 0) { ++ pr_err("ioctl SIOCSHWTSTAMP failed: %m"); ++ return err; ++ } + } ++ break; ++ } ++ ++ if (cfg.tx_type != tx_type || ++ (cfg.rx_filter != rx_filter && ++ cfg.rx_filter != rx_filter2 && ++ cfg.rx_filter != HWTSTAMP_FILTER_ALL)) { ++ pr_debug("tx_type %d not %d", cfg.tx_type, tx_type); ++ pr_debug("rx_filter %d not %d or %d", cfg.rx_filter, rx_filter, ++ rx_filter2); ++ pr_err("The current filter does not match the required"); ++ return -1; + } + + return 0; +@@ -450,15 +487,9 @@ int sk_timestamping_init(int fd, const char *device, enum timestamp_type type, + case TRANS_UDS: + return -1; + } +- err = hwts_init(fd, device, filter1, tx_type); +- if (err) { +- pr_info("driver rejected most general HWTSTAMP filter"); +- err = hwts_init(fd, device, filter2, tx_type); +- if (err) { +- pr_err("ioctl SIOCSHWTSTAMP failed: %m"); +- return err; +- } +- } ++ err = hwts_init(fd, device, filter1, filter2, tx_type); ++ if (err) ++ return err; + } + + if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, +diff --git a/sk.h b/sk.h +index d91d5d8..fd4d820 100644 +--- a/sk.h ++++ b/sk.h +@@ -23,6 +23,16 @@ + #include "address.h" + #include "transport.h" + ++/** ++ * Defines the available Hardware time-stamp setting modes. ++ */ ++ ++enum hwts_filter_mode { ++ HWTS_FILTER_NORMAL, /* set hardware filters in normal way */ ++ HWTS_FILTER_CHECK, /* check filters but do not change them */ ++ HWTS_FILTER_FULL, /* Use time-stamp on all received packets */ ++}; ++ + /** + * Contains timestamping information returned by the GET_TS_INFO ioctl. + * @valid: set to non-zero when the info struct contains valid data. +@@ -131,4 +141,9 @@ extern int sk_tx_timeout; + */ + extern int sk_check_fupsync; + ++/** ++ * Hardware time-stamp setting mode ++ */ ++extern enum hwts_filter_mode sk_hwts_filter_mode; ++ + #endif diff --git a/SOURCES/linuxptp-msgput.patch b/SOURCES/linuxptp-msgput.patch new file mode 100644 index 0000000..0fab821 --- /dev/null +++ b/SOURCES/linuxptp-msgput.patch @@ -0,0 +1,20 @@ +commit 86723cfc6a7ac1d9b1bff5e90b7f4696d6460a0e +Author: Miroslav Lichvar +Date: Thu Mar 21 17:12:03 2019 +0100 + + pmc: Don't leak memory when msg_tlv_append() fails. + + Signed-off-by: Miroslav Lichvar + +diff --git a/pmc_common.c b/pmc_common.c +index 4a160f6..4d48e3a 100644 +--- a/pmc_common.c ++++ b/pmc_common.c +@@ -546,6 +546,7 @@ int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize) + } + extra = msg_tlv_append(msg, sizeof(*mgt) + datasize); + if (!extra) { ++ msg_put(msg); + return -ENOMEM; + } + mgt = (struct management_tlv *) extra->tlv; diff --git a/SOURCES/linuxptp-sysoff.patch b/SOURCES/linuxptp-sysoff.patch new file mode 100644 index 0000000..ce1e410 --- /dev/null +++ b/SOURCES/linuxptp-sysoff.patch @@ -0,0 +1,486 @@ +commit c0e49c708814ec783726fe92202371847703c5ed +Author: Miroslav Lichvar +Date: Mon Nov 12 17:27:58 2018 +0100 + + sysoff: Initialize data for ioctl(PTP_SYS_OFFSET). + + This fixes valgrind errors. + + Signed-off-by: Miroslav Lichvar + +diff --git a/sysoff.c b/sysoff.c +index f7b6240..407a01c 100644 +--- a/sysoff.c ++++ b/sysoff.c +@@ -18,6 +18,7 @@ + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + #include ++#include + #include + #include + +@@ -76,6 +77,7 @@ int sysoff_measure(int fd, int n_samples, + int64_t *result, uint64_t *ts, int64_t *delay) + { + struct ptp_sys_offset pso; ++ memset(&pso, 0, sizeof(pso)); + pso.n_samples = n_samples; + if (ioctl(fd, PTP_SYS_OFFSET, &pso)) { + perror("ioctl PTP_SYS_OFFSET"); + +commit 93baf34adb81046a5e1c3b9a3e685029f2046993 +Author: Miroslav Lichvar +Date: Mon Nov 12 17:27:59 2018 +0100 + + sysoff: Extend API for different sysoff methods. + + The kernel supports different PTP_SYS_OFFSET* ioctls. Use the sysoff + enum to allow selecting between them in sysoff_measure(). + + Signed-off-by: Miroslav Lichvar + +diff --git a/phc2sys.c b/phc2sys.c +index 15f8d75..2cd477a 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -74,7 +74,7 @@ struct clock { + LIST_ENTRY(clock) dst_list; + clockid_t clkid; + int phc_index; +- int sysoff_supported; ++ int sysoff_method; + int is_utc; + int dest_only; + int state; +@@ -255,9 +255,8 @@ static struct clock *clock_add(struct node *node, char *device) + c->servo = servo_add(node, c); + + if (clkid != CLOCK_INVALID && clkid != CLOCK_REALTIME) +- c->sysoff_supported = (SYSOFF_SUPPORTED == +- sysoff_probe(CLOCKID_TO_FD(clkid), +- node->phc_readings)); ++ c->sysoff_method = sysoff_probe(CLOCKID_TO_FD(clkid), ++ node->phc_readings); + + LIST_INSERT_HEAD(&node->clocks, c, list); + return c; +@@ -784,11 +783,12 @@ static int do_loop(struct node *node, int subscriptions) + continue; + + if (clock->clkid == CLOCK_REALTIME && +- node->master->sysoff_supported) { ++ node->master->sysoff_method >= 0) { + /* use sysoff */ + if (sysoff_measure(CLOCKID_TO_FD(node->master->clkid), ++ node->master->sysoff_method, + node->phc_readings, +- &offset, &ts, &delay)) ++ &offset, &ts, &delay) < 0) + return -1; + } else { + /* use phc */ +diff --git a/phc_ctl.c b/phc_ctl.c +index 4a78a19..b9a9cf4 100644 +--- a/phc_ctl.c ++++ b/phc_ctl.c +@@ -367,10 +367,12 @@ static int do_cmp(clockid_t clkid, int cmdc, char *cmdv[]) + struct timespec ts, rta, rtb; + int64_t sys_offset, delay = 0, offset; + uint64_t sys_ts; ++ int method; + +- if (SYSOFF_SUPPORTED == +- sysoff_measure(CLOCKID_TO_FD(clkid), +- 9, &sys_offset, &sys_ts, &delay)) { ++ method = sysoff_probe(CLOCKID_TO_FD(clkid), 9); ++ ++ if (method >= 0 && sysoff_measure(CLOCKID_TO_FD(clkid), method, 9, ++ &sys_offset, &sys_ts, &delay) >= 0) { + pr_notice( "offset from CLOCK_REALTIME is %"PRId64"ns\n", + sys_offset); + return 0; +diff --git a/sysoff.c b/sysoff.c +index 407a01c..f709a9b 100644 +--- a/sysoff.c ++++ b/sysoff.c +@@ -73,8 +73,8 @@ static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, + return samples[0].offset; + } + +-int sysoff_measure(int fd, int n_samples, +- int64_t *result, uint64_t *ts, int64_t *delay) ++static int sysoff_basic(int fd, int n_samples, ++ int64_t *result, uint64_t *ts, int64_t *delay) + { + struct ptp_sys_offset pso; + memset(&pso, 0, sizeof(pso)); +@@ -84,13 +84,24 @@ int sysoff_measure(int fd, int n_samples, + return SYSOFF_RUN_TIME_MISSING; + } + *result = sysoff_estimate(pso.ts, n_samples, ts, delay); +- return SYSOFF_SUPPORTED; ++ return SYSOFF_BASIC; ++} ++ ++int sysoff_measure(int fd, int method, int n_samples, ++ int64_t *result, uint64_t *ts, int64_t *delay) ++{ ++ switch (method) { ++ case SYSOFF_BASIC: ++ return sysoff_basic(fd, n_samples, result, ts, delay); ++ } ++ return SYSOFF_COMPILE_TIME_MISSING; + } + + int sysoff_probe(int fd, int n_samples) + { + int64_t junk, delay; + uint64_t ts; ++ int i; + + if (n_samples > PTP_MAX_SAMPLES) { + fprintf(stderr, "warning: %d exceeds kernel max readings %d\n", +@@ -99,7 +110,13 @@ int sysoff_probe(int fd, int n_samples) + return SYSOFF_RUN_TIME_MISSING; + } + +- return sysoff_measure(fd, n_samples, &junk, &ts, &delay); ++ for (i = 0; i < SYSOFF_LAST; i++) { ++ if (sysoff_measure(fd, i, n_samples, &junk, &ts, &delay) < 0) ++ continue; ++ return i; ++ } ++ ++ return SYSOFF_RUN_TIME_MISSING; + } + + #else /* !PTP_SYS_OFFSET */ +diff --git a/sysoff.h b/sysoff.h +index cb70265..02ecdfa 100644 +--- a/sysoff.h ++++ b/sysoff.h +@@ -21,13 +21,14 @@ + #include + + enum { +- SYSOFF_SUPPORTED, +- SYSOFF_COMPILE_TIME_MISSING, +- SYSOFF_RUN_TIME_MISSING, ++ SYSOFF_COMPILE_TIME_MISSING = -2, ++ SYSOFF_RUN_TIME_MISSING = -1, ++ SYSOFF_BASIC, ++ SYSOFF_LAST, + }; + + /** +- * Check to see if the PTP_SYS_OFFSET ioctl is supported. ++ * Check to see if a PTP_SYS_OFFSET ioctl is supported. + * @param fd An open file descriptor to a PHC device. + * @return One of the SYSOFF_ enumeration values. + */ +@@ -36,11 +37,12 @@ int sysoff_probe(int fd, int n_samples); + /** + * Measure the offset between a PHC and the system time. + * @param fd An open file descriptor to a PHC device. ++ * @param method A non-negative SYSOFF_ value returned by sysoff_probe(). + * @param n_samples The number of consecutive readings to make. + * @param result The estimated offset in nanoseconds. + * @param ts The system time corresponding to the 'result'. + * @param delay The delay in reading of the clock in nanoseconds. + * @return One of the SYSOFF_ enumeration values. + */ +-int sysoff_measure(int fd, int n_samples, ++int sysoff_measure(int fd, int method, int n_samples, + int64_t *result, uint64_t *ts, int64_t *delay); + +commit 192b8e315c4585489d7aa7f59683035998805e40 +Author: Miroslav Lichvar +Date: Mon Nov 12 17:28:00 2018 +0100 + + sysoff: Add support for PTP_SYS_OFFSET_PRECISE ioctl. + + This ioctl uses cross timestamping for a more accurate measurement of + the offset. It is supported on some onboard Intel NICs using the e1000e + driver and a virtual PHC with the ptp_kvm driver. + + Signed-off-by: Miroslav Lichvar + +diff --git a/sysoff.c b/sysoff.c +index f709a9b..9f65d95 100644 +--- a/sysoff.c ++++ b/sysoff.c +@@ -22,6 +22,7 @@ + #include + #include + ++#include "print.h" + #include "sysoff.h" + + #define NS_PER_SEC 1000000000LL +@@ -39,6 +40,23 @@ static struct { + uint64_t timestamp; + } samples[PTP_MAX_SAMPLES]; + ++static int sysoff_precise(int fd, int64_t *result, uint64_t *ts) ++{ ++#ifdef PTP_SYS_OFFSET_PRECISE ++ struct ptp_sys_offset_precise pso; ++ memset(&pso, 0, sizeof(pso)); ++ if (ioctl(fd, PTP_SYS_OFFSET_PRECISE, &pso)) { ++ pr_debug("ioctl PTP_SYS_OFFSET_PRECISE: %m"); ++ return SYSOFF_RUN_TIME_MISSING; ++ } ++ *result = pctns(&pso.sys_realtime) - pctns(&pso.device); ++ *ts = pctns(&pso.sys_realtime); ++ return SYSOFF_PRECISE; ++#else ++ return SYSOFF_COMPILE_TIME_MISSING; ++#endif ++} ++ + static void insertion_sort(int length, int64_t interval, int64_t offset, uint64_t ts) + { + int i = length - 1; +@@ -91,6 +109,9 @@ int sysoff_measure(int fd, int method, int n_samples, + int64_t *result, uint64_t *ts, int64_t *delay) + { + switch (method) { ++ case SYSOFF_PRECISE: ++ *delay = 0; ++ return sysoff_precise(fd, result, ts); + case SYSOFF_BASIC: + return sysoff_basic(fd, n_samples, result, ts, delay); + } +diff --git a/sysoff.h b/sysoff.h +index 02ecdfa..37f7353 100644 +--- a/sysoff.h ++++ b/sysoff.h +@@ -23,6 +23,7 @@ + enum { + SYSOFF_COMPILE_TIME_MISSING = -2, + SYSOFF_RUN_TIME_MISSING = -1, ++ SYSOFF_PRECISE, + SYSOFF_BASIC, + SYSOFF_LAST, + }; + +commit 68a9011c9d7d859920da339ba59c14dc1d617a45 +Author: Miroslav Lichvar +Date: Mon Nov 12 17:28:01 2018 +0100 + + sysoff: Add support for PTP_SYS_OFFSET_EXTENDED ioctl. + + This is a more accurate variant of the the PTP_SYS_OFFSET ioctl, which + will probably be supported in future kernel versions. + + Signed-off-by: Miroslav Lichvar + +diff --git a/sysoff.c b/sysoff.c +index 9f65d95..b993ee9 100644 +--- a/sysoff.c ++++ b/sysoff.c +@@ -71,17 +71,23 @@ static void insertion_sort(int length, int64_t interval, int64_t offset, uint64_ + samples[i+1].timestamp = ts; + } + +-static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, +- uint64_t *ts, int64_t *delay) ++static int64_t sysoff_estimate(struct ptp_clock_time *pct, int extended, ++ int n_samples, uint64_t *ts, int64_t *delay) + { + int64_t t1, t2, tp; + int64_t interval, offset; + int i; + + for (i = 0; i < n_samples; i++) { +- t1 = pctns(&pct[2*i]); +- tp = pctns(&pct[2*i+1]); +- t2 = pctns(&pct[2*i+2]); ++ if (extended) { ++ t1 = pctns(&pct[3*i]); ++ tp = pctns(&pct[3*i+1]); ++ t2 = pctns(&pct[3*i+2]); ++ } else { ++ t1 = pctns(&pct[2*i]); ++ tp = pctns(&pct[2*i+1]); ++ t2 = pctns(&pct[2*i+2]); ++ } + interval = t2 - t1; + offset = (t2 + t1) / 2 - tp; + insertion_sort(i, interval, offset, (t2 + t1) / 2); +@@ -91,6 +97,24 @@ static int64_t sysoff_estimate(struct ptp_clock_time *pct, int n_samples, + return samples[0].offset; + } + ++static int sysoff_extended(int fd, int n_samples, ++ int64_t *result, uint64_t *ts, int64_t *delay) ++{ ++#ifdef PTP_SYS_OFFSET_EXTENDED ++ struct ptp_sys_offset_extended pso; ++ memset(&pso, 0, sizeof(pso)); ++ pso.n_samples = n_samples; ++ if (ioctl(fd, PTP_SYS_OFFSET_EXTENDED, &pso)) { ++ pr_debug("ioctl PTP_SYS_OFFSET_EXTENDED: %m"); ++ return SYSOFF_RUN_TIME_MISSING; ++ } ++ *result = sysoff_estimate(&pso.ts[0][0], 1, n_samples, ts, delay); ++ return SYSOFF_EXTENDED; ++#else ++ return SYSOFF_COMPILE_TIME_MISSING; ++#endif ++} ++ + static int sysoff_basic(int fd, int n_samples, + int64_t *result, uint64_t *ts, int64_t *delay) + { +@@ -101,7 +125,7 @@ static int sysoff_basic(int fd, int n_samples, + perror("ioctl PTP_SYS_OFFSET"); + return SYSOFF_RUN_TIME_MISSING; + } +- *result = sysoff_estimate(pso.ts, n_samples, ts, delay); ++ *result = sysoff_estimate(pso.ts, 0, n_samples, ts, delay); + return SYSOFF_BASIC; + } + +@@ -112,6 +136,8 @@ int sysoff_measure(int fd, int method, int n_samples, + case SYSOFF_PRECISE: + *delay = 0; + return sysoff_precise(fd, result, ts); ++ case SYSOFF_EXTENDED: ++ return sysoff_extended(fd, n_samples, result, ts, delay); + case SYSOFF_BASIC: + return sysoff_basic(fd, n_samples, result, ts, delay); + } +diff --git a/sysoff.h b/sysoff.h +index 37f7353..79d2290 100644 +--- a/sysoff.h ++++ b/sysoff.h +@@ -24,6 +24,7 @@ enum { + SYSOFF_COMPILE_TIME_MISSING = -2, + SYSOFF_RUN_TIME_MISSING = -1, + SYSOFF_PRECISE, ++ SYSOFF_EXTENDED, + SYSOFF_BASIC, + SYSOFF_LAST, + }; + +commit 8142da41b61fb5b9ee4ad8f5ab56adb0447cd37b +Author: Miroslav Lichvar +Date: Mon Nov 12 17:28:02 2018 +0100 + + phc2sys: Use reversed sysoff when synchronizing to system clock. + + If synchronizing a PHC to the system clock, use one of the + PTP_SYS_OFFSET ioctls (if supported) to measure the offset between the + two clocks. Negate the offset and switch the timestamp before passing + them to the servo. + + This makes the synchronization between PHC and system clock symmetric. + + Signed-off-by: Miroslav Lichvar + +diff --git a/phc2sys.c b/phc2sys.c +index 2cd477a..b8f1ea0 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -790,6 +790,16 @@ static int do_loop(struct node *node, int subscriptions) + node->phc_readings, + &offset, &ts, &delay) < 0) + return -1; ++ } else if (node->master->clkid == CLOCK_REALTIME && ++ clock->sysoff_method >= 0) { ++ /* use reversed sysoff */ ++ if (sysoff_measure(CLOCKID_TO_FD(clock->clkid), ++ clock->sysoff_method, ++ node->phc_readings, ++ &offset, &ts, &delay) < 0) ++ return -1; ++ ts += offset; ++ offset = -offset; + } else { + /* use phc */ + if (!read_phc(node->master->clkid, clock->clkid, +commit e0580929f451e685d92cd10d80b76f39e9b09a97 +Author: Richard Cochran +Date: Tue Dec 24 11:09:34 2019 -0800 + + phc2sys: Fix frequency estimation when synchronizing a PHC to the system clock. + + When synchronizing a PHC to the Linux system clock (CLOCK_REALTIME), + the phc2sys uses the sysoff method, reversing the master and slave + roles. + + The offset between a master clock and a slave clock is given by + + offset = slave_ts - master_ts, + + and the call to sysoff_measure() provides the 'offset' and 'slave_ts' + values. The needed local time stamp on the 'master' is given by + + master_ts = slave_ts - offset, + + but the code calcuates + + master_ts = slave_ts + offset. + + When passed to the servo, the local time stamp is used to estimate the + frequency offset between the two clocks before starting the main + synchronization loop. The effect of the bug may be seen with a simple + test. Here is a sample output with the existing code. + + $ sudo testptp -d /dev/ptp1 -f 62400000 + frequency adjustment okay + $ sudo ./phc2sys -m -q -c eth6 -s CLOCK_REALTIME -O0 + phc2sys[90221.239]: eth6 sys offset 191001318 s0 freq -62400000 delay 5547 + phc2sys[90222.239]: eth6 sys offset 253380897 s1 freq +8265884 delay 5507 + phc2sys[90223.239]: eth6 sys offset -8301685 s2 freq -35801 delay 5487 + phc2sys[90224.239]: eth6 sys offset -8297136 s2 freq -2521757 delay 5531 + phc2sys[90225.239]: eth6 sys offset -5806117 s2 freq -2519879 delay 5542 + phc2sys[90226.239]: eth6 sys offset -3317009 s2 freq -1772606 delay 5495 + phc2sys[90227.240]: eth6 sys offset -1575231 s2 freq -1025931 delay 5505 + phc2sys[90228.240]: eth6 sys offset -580249 s2 freq -503518 delay 5524 + phc2sys[90229.240]: eth6 sys offset -107770 s2 freq -205114 delay 5519 + phc2sys[90230.240]: eth6 sys offset 66298 s2 freq -63377 delay 5490 + phc2sys[90230.881]: eth6 sys offset 86942 s2 freq -22844 delay 5495 + + And this is the output with the bug fix in place. + + $ sudo testptp -d /dev/ptp1 -f 62400000 + frequency adjustment okay + $ sudo ./phc2sys -m -q -c eth6 -s CLOCK_REALTIME -O0 + phc2sys[90365.624]: eth6 sys offset 311912675 s0 freq -62400000 delay 5490 + phc2sys[90366.624]: eth6 sys offset 374292766 s1 freq -31098 delay 5642 + phc2sys[90367.624]: eth6 sys offset -3825 s2 freq -34923 delay 5617 + phc2sys[90368.625]: eth6 sys offset 6 s2 freq -32240 delay 5564 + phc2sys[90369.625]: eth6 sys offset 1241 s2 freq -31003 delay 5605 + phc2sys[90370.625]: eth6 sys offset 1131 s2 freq -30741 delay 5600 + phc2sys[90371.625]: eth6 sys offset 801 s2 freq -30732 delay 5621 + phc2sys[90372.625]: eth6 sys offset 458 s2 freq -30834 delay 5640 + phc2sys[90373.626]: eth6 sys offset 186 s2 freq -30969 delay 5598 + phc2sys[90374.626]: eth6 sys offset 134 s2 freq -30965 delay 5599 + phc2sys[90375.626]: eth6 sys offset 43 s2 freq -31016 delay 5595 + phc2sys[90375.681]: eth6 sys offset -32 s2 freq -31078 delay 5541 + + This patch fixes the issue by correcting the calculation of the local + time stamp value. + + Fixes: 8142da41b61f ("phc2sys: Use reversed sysoff when synchronizing to system clock.") + Signed-off-by: Richard Cochran + Reported-by: Cliff Spradlin + Tested-by: Vladimir Oltean + +diff --git a/phc2sys.c b/phc2sys.c +index 28c657a..c0b7b3d 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -770,8 +770,8 @@ static int do_loop(struct node *node, int subscriptions) + node->phc_readings, + &offset, &ts, &delay) < 0) + return -1; +- ts += offset; + offset = -offset; ++ ts += offset; + } else { + /* use phc */ + if (!read_phc(node->master->clkid, clock->clkid, diff --git a/SOURCES/linuxptp-team.patch b/SOURCES/linuxptp-team.patch new file mode 100644 index 0000000..7bb7000 --- /dev/null +++ b/SOURCES/linuxptp-team.patch @@ -0,0 +1,437 @@ +commit 9c4d9ce0347ec35b2ff2babfc9ed9f8e6e51ac91 +Author: Hangbin Liu +Date: Fri Mar 22 15:02:46 2019 +0800 + + rtnl: add team activebackup support + + This patch add team interface activebackup mode support. As linux team use + genl netlink message, when we get a rtnl link change notify, we have to setup + a new genl socket and request the current active port. + + v2: check nlmsg_len before copy rta_data + v3: a) Do not make rtnl_buf global as it may be freed by calling rtnl_close() + while we are using it in rtnl_link_status() + b) Reorder declarations of variables as reversed Christmas tree for + function rtnl_link_status() + c) remove rtnl_len + v4: Remove the first !rtnl_buf check in rtnl_link_status as it's alway true + v5: a) Re-order {nl, rtnl}_open and add function nl_close() + b) revert the v3_{a,c}, v4 changes, use nl_close to close genl fd + c) do not use len in get_team_active_iface() as it may mislead reader + v6: Return index at the end to fix fd leak in get_team_active_iface() + + Signed-off-by: Hangbin Liu + +diff --git a/missing.h b/missing.h +index 2f7adb9..8f92079 100644 +--- a/missing.h ++++ b/missing.h +@@ -118,6 +118,22 @@ enum { + #define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) + #endif /*IFLA_BOND_MAX*/ + ++#ifndef NLA_TYPE_MAX ++enum { ++ NLA_UNSPEC, ++ NLA_U8, ++ NLA_U16, ++ NLA_U32, ++ NLA_U64, ++ NLA_STRING, ++ NLA_FLAG, ++ NLA_MSECS, ++ NLA_NESTED, ++ __NLA_TYPE_MAX, ++}; ++#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) ++#endif /*NLA_TYPE_MAX*/ ++ + #ifdef __UCLIBC__ + + #if (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L) && \ +diff --git a/phc2sys.8 b/phc2sys.8 +index 45cb0e3..b3a3de3 100644 +--- a/phc2sys.8 ++++ b/phc2sys.8 +@@ -108,9 +108,9 @@ together with the + option, the master clock is used only to correct the offset by whole number of + seconds, which cannot be fixed with PPS alone. Not compatible with the + .B \-a +-option. This option does not support bonded interface (e.g. bond0). If ++option. This option does not support bonded interface (e.g. bond0, team0). If + .B ptp4l +-has a port on an active-backup bond interface, the ++has a port on an active-backup bond or team interface, the + .B \-a + option can be used to track the active interface. + .TP +diff --git a/rtnl.c b/rtnl.c +index f9a572b..59ed0ec 100644 +--- a/rtnl.c ++++ b/rtnl.c +@@ -20,6 +20,8 @@ + #include /* Must come before linux/netlink.h on some systems. */ + #include + #include ++#include ++#include + #include + #include + #include +@@ -30,8 +32,39 @@ + #include "print.h" + #include "rtnl.h" + ++#define BUF_SIZE 4096 ++#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) ++ + static int rtnl_len; + static char *rtnl_buf; ++static int get_team_active_iface(int master_index); ++ ++static int nl_close(int fd) ++{ ++ return close(fd); ++} ++ ++static int nl_open(int family) ++{ ++ int fd; ++ struct sockaddr_nl sa; ++ ++ memset(&sa, 0, sizeof(sa)); ++ sa.nl_family = AF_NETLINK; ++ sa.nl_groups = RTNLGRP_LINK; ++ ++ fd = socket(AF_NETLINK, SOCK_RAW, family); ++ if (fd < 0) { ++ pr_err("failed to open netlink socket: %m"); ++ return -1; ++ } ++ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa))) { ++ pr_err("failed to bind netlink socket: %m"); ++ close(fd); ++ return -1; ++ } ++ return fd; ++} + + int rtnl_close(int fd) + { +@@ -40,7 +73,12 @@ int rtnl_close(int fd) + rtnl_buf = NULL; + rtnl_len = 0; + } +- return close(fd); ++ return nl_close(fd); ++} ++ ++int rtnl_open(void) ++{ ++ return nl_open(NETLINK_ROUTE); + } + + static void rtnl_get_ts_device_callback(void *ctx, int linkup, int ts_index) +@@ -116,14 +154,24 @@ int rtnl_link_query(int fd, char *device) + return 0; + } + +-static inline __u32 rta_getattr_u32(const struct rtattr *rta) ++static inline __u8 rta_getattr_u8(struct rtattr *rta) ++{ ++ return *(__u8 *)RTA_DATA(rta); ++} ++ ++static inline __u16 rta_getattr_u16(struct rtattr *rta) ++{ ++ return *(__u16 *)RTA_DATA(rta); ++} ++ ++static inline __u32 rta_getattr_u32(struct rtattr *rta) + { + return *(__u32 *)RTA_DATA(rta); + } + +-static inline const char *rta_getattr_str(const struct rtattr *rta) ++static inline char *rta_getattr_str(struct rtattr *rta) + { +- return (const char *)RTA_DATA(rta); ++ return (char *)RTA_DATA(rta); + } + + static int rtnl_rtattr_parse(struct rtattr *tb[], int max, struct rtattr *rta, int len) +@@ -150,12 +198,12 @@ static inline int rtnl_nested_rtattr_parse(struct rtattr *tb[], int max, struct + return rtnl_rtattr_parse(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); + } + +-static int rtnl_linkinfo_parse(struct rtattr *rta) ++static int rtnl_linkinfo_parse(int master_index, struct rtattr *rta) + { +- int index = -1; +- const char *kind; + struct rtattr *linkinfo[IFLA_INFO_MAX]; + struct rtattr *bond[IFLA_BOND_MAX]; ++ int index = -1; ++ char *kind; + + if (rtnl_nested_rtattr_parse(linkinfo, IFLA_INFO_MAX, rta) < 0) + return -1; +@@ -172,6 +220,8 @@ static int rtnl_linkinfo_parse(struct rtattr *rta) + if (bond[IFLA_BOND_ACTIVE_SLAVE]) { + index = rta_getattr_u32(bond[IFLA_BOND_ACTIVE_SLAVE]); + } ++ } else if (kind && !strncmp(kind, "team", 4)) { ++ index = get_team_active_iface(master_index); + } + } + return index; +@@ -179,18 +229,18 @@ static int rtnl_linkinfo_parse(struct rtattr *rta) + + int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx) + { ++ struct rtattr *tb[IFLA_MAX+1]; ++ struct ifinfomsg *info = NULL; + int index, len, link_up; +- int slave_index = -1; +- struct iovec iov; + struct sockaddr_nl sa; +- struct msghdr msg; ++ int slave_index = -1; + struct nlmsghdr *nh; +- struct ifinfomsg *info = NULL; +- struct rtattr *tb[IFLA_MAX+1]; ++ struct msghdr msg; ++ struct iovec iov; + + index = if_nametoindex(device); + if (!rtnl_buf) { +- rtnl_len = 4096; ++ rtnl_len = BUF_SIZE; + rtnl_buf = malloc(rtnl_len); + if (!rtnl_buf) { + pr_err("rtnl: low memory"); +@@ -246,7 +296,7 @@ int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx) + IFLA_PAYLOAD(nh)); + + if (tb[IFLA_LINKINFO]) +- slave_index = rtnl_linkinfo_parse(tb[IFLA_LINKINFO]); ++ slave_index = rtnl_linkinfo_parse(index, tb[IFLA_LINKINFO]); + + if (cb) + cb(ctx, link_up, slave_index); +@@ -255,24 +305,163 @@ int rtnl_link_status(int fd, char *device, rtnl_callback cb, void *ctx) + return 0; + } + +-int rtnl_open(void) ++static int genl_send_msg(int fd, int family_id, int genl_cmd, int genl_version, ++ int rta_type, void *rta_data, int rta_len) + { +- int fd; +- struct sockaddr_nl sa; ++ struct sockaddr_nl daddr; ++ struct genlmsghdr *gnlh; ++ struct nlmsghdr *nlh; ++ struct rtattr *attr; ++ char msg[BUF_SIZE]; + +- memset(&sa, 0, sizeof(sa)); +- sa.nl_family = AF_NETLINK; +- sa.nl_groups = RTNLGRP_LINK; ++ memset(&daddr, 0, sizeof(daddr)); ++ daddr.nl_family = AF_NETLINK; + +- fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); +- if (fd < 0) { +- pr_err("failed to open netlink socket: %m"); ++ memset(&msg, 0, sizeof(msg)); ++ nlh = (struct nlmsghdr *) msg; ++ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); ++ nlh->nlmsg_type = family_id; ++ nlh->nlmsg_flags = NLM_F_REQUEST; ++ ++ gnlh = (struct genlmsghdr *) NLMSG_DATA(nlh); ++ gnlh->cmd = genl_cmd; ++ gnlh->version = genl_version; ++ ++ if (rta_data && rta_len > 0) { ++ attr = (struct rtattr *) GENLMSG_DATA(msg); ++ attr->rta_type = rta_type; ++ attr->rta_len = RTA_LENGTH(rta_len); ++ nlh->nlmsg_len += NLMSG_ALIGN(attr->rta_len); ++ if (nlh->nlmsg_len < sizeof(msg)) ++ memcpy(RTA_DATA(attr), rta_data, rta_len); ++ else ++ return -1; ++ } ++ ++ return sendto(fd, &msg, nlh->nlmsg_len, 0, ++ (struct sockaddr *)&daddr, sizeof(daddr)); ++} ++ ++static int genl_get_family_id(int fd, void *family_name) ++{ ++ struct rtattr *tb[CTRL_ATTR_MAX+1]; ++ struct nlmsghdr *nlh; ++ struct rtattr *attr; ++ char msg[BUF_SIZE]; ++ int len, gf_id; ++ ++ len = genl_send_msg(fd, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1, ++ CTRL_ATTR_FAMILY_NAME, family_name, ++ strlen(family_name) + 1); ++ if (len < 0) ++ return len; ++ ++ len = recv(fd, &msg, sizeof(msg), 0); ++ if (len < 0) ++ return len; ++ ++ nlh = (struct nlmsghdr *) msg; ++ if (nlh->nlmsg_type == NLMSG_ERROR || !NLMSG_OK(nlh, len)) + return -1; ++ ++ attr = (struct rtattr *) GENLMSG_DATA(msg); ++ rtnl_rtattr_parse(tb, CTRL_ATTR_MAX, attr, NLMSG_PAYLOAD(nlh, GENL_HDRLEN)); ++ ++ if (tb[CTRL_ATTR_FAMILY_ID]) ++ gf_id = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]); ++ else ++ gf_id = -1; ++ ++ return gf_id; ++} ++ ++static int parase_team_list_option(struct rtattr *attr) ++{ ++ struct rtattr *tb[TEAM_ATTR_OPTION_MAX+1]; ++ int len = RTA_PAYLOAD(attr); ++ const char *optname = ""; ++ const char *mode = ""; ++ int active_index = -1; ++ ++ for (attr = RTA_DATA(attr); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { ++ rtnl_nested_rtattr_parse(tb, TEAM_ATTR_OPTION_MAX, attr); ++ ++ if (tb[TEAM_ATTR_OPTION_NAME]) ++ optname = rta_getattr_str(tb[TEAM_ATTR_OPTION_NAME]); ++ ++ if (!strcmp(optname, "mode") && tb[TEAM_ATTR_OPTION_TYPE] && ++ rta_getattr_u8(tb[TEAM_ATTR_OPTION_TYPE]) == NLA_STRING) ++ mode = rta_getattr_str(tb[TEAM_ATTR_OPTION_DATA]); ++ ++ if (!strcmp(optname, "activeport") && tb[TEAM_ATTR_OPTION_TYPE] && ++ rta_getattr_u8(tb[TEAM_ATTR_OPTION_TYPE]) == NLA_U32) ++ active_index = rta_getattr_u32(tb[TEAM_ATTR_OPTION_DATA]); + } +- if (bind(fd, (struct sockaddr *) &sa, sizeof(sa))) { +- pr_err("failed to bind netlink socket: %m"); +- close(fd); ++ ++ if (strcmp(mode, "activebackup")) { ++ pr_err("team supported only in activebackup mode"); + return -1; ++ } else { ++ return active_index; + } +- return fd; ++} ++ ++static int get_team_active_iface(int master_index) ++{ ++ struct rtattr *tb[TEAM_ATTR_MAX+1]; ++ struct genlmsghdr *gnlh; ++ struct nlmsghdr *nlh; ++ char msg[BUF_SIZE]; ++ int fd, gf_id, len; ++ int index = -1; ++ ++ fd = nl_open(NETLINK_GENERIC); ++ if (fd < 0) ++ return fd; ++ ++ gf_id = genl_get_family_id(fd, TEAM_GENL_NAME); ++ if (gf_id < 0) { ++ pr_err("get genl family failed"); ++ goto no_info; ++ } ++ ++ len = genl_send_msg(fd, gf_id, TEAM_CMD_OPTIONS_GET, ++ TEAM_GENL_VERSION, TEAM_ATTR_TEAM_IFINDEX, ++ &master_index, sizeof(master_index)); ++ if (len < 0) { ++ pr_err("send team info request failed: %m"); ++ goto no_info; ++ } ++ ++ len = recv(fd, msg, sizeof(msg), 0); ++ if (len < 0) { ++ pr_err("recv team info failed: %m"); ++ goto no_info; ++ } ++ ++ nlh = (struct nlmsghdr *) msg; ++ for ( ; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) { ++ if (nlh->nlmsg_type != gf_id) ++ continue; ++ ++ gnlh = (struct genlmsghdr *) NLMSG_DATA(nlh); ++ if (gnlh->cmd != TEAM_CMD_OPTIONS_GET) ++ continue; ++ ++ rtnl_rtattr_parse(tb, TEAM_ATTR_MAX, (struct rtattr *)GENLMSG_DATA(msg), ++ NLMSG_PAYLOAD(nlh, GENL_HDRLEN)); ++ ++ if (tb[TEAM_ATTR_TEAM_IFINDEX] && ++ master_index != rta_getattr_u32(tb[TEAM_ATTR_TEAM_IFINDEX])) ++ continue; ++ ++ if (tb[TEAM_ATTR_LIST_OPTION]) { ++ index = parase_team_list_option(tb[TEAM_ATTR_LIST_OPTION]); ++ break; ++ } ++ } ++ ++no_info: ++ nl_close(fd); ++ return index; + } +commit 51d76bdfb7423947dbb3e250c86d83f9edb0a15b +Author: Hangbin Liu +Date: Wed Mar 20 14:44:13 2019 +0800 + + port: should check the new phc_index before switching + + In logic, when we want to switch phc, we should check if the new phc + index is valid instead of checking the previous one. + + In reality, if we use linux team interface with activebackup mode. As + teamd is a userspace tool, it sets the new slave as active port after + receiving link change message. If we set current active port down and + another slave up. There is a race that we receive the new slave's link + up message while active port(ts_index) is still the old one. This means + we may use a link down interface as ts_index and get phc_index with -1. + + If we update the p->phc_index to -1, there will be no possibility to + change it back to other value as we swith phc only when p->phc_index >= 0. + + With this fix, we will not switch phc_index until receiving the real + active port(p->iface->ts_info.phc_index >= 0) update message. + + Reported-by: Miroslav Lichvar + Fixes: 536a71031d5c ("ptp4l: use ts label to get ts info") + Signed-off-by: Hangbin Liu + +diff --git a/port.c b/port.c +index 9264211..facebd2 100644 +--- a/port.c ++++ b/port.c +@@ -2442,7 +2442,7 @@ void port_link_status(void *ctx, int linkup, int ts_index) + sk_get_ts_info(p->iface->ts_label, &p->iface->ts_info); + + /* Only switch phc with HW time stamping mode */ +- if (p->phc_index >= 0 && p->iface->ts_info.valid) { ++ if (p->iface->ts_info.valid && p->iface->ts_info.phc_index >= 0) { + required_modes = clock_required_modes(p->clock); + if ((p->iface->ts_info.so_timestamping & required_modes) != required_modes) { + pr_err("interface '%s' does not support requested " diff --git a/SOURCES/linuxptp-timeout.patch b/SOURCES/linuxptp-timeout.patch new file mode 100644 index 0000000..b104787 --- /dev/null +++ b/SOURCES/linuxptp-timeout.patch @@ -0,0 +1,24 @@ +commit 241d8a064efa535029e28b87a8995add3cca8c0c +Author: Miroslav Lichvar +Date: Tue Sep 25 18:16:19 2018 +0200 + + unicast: Process timeouts equal to current time. + + Don't postpone processing of a timeout if it is equal to the current + time. This prevents an infinite loop with a simulated clock. + + Signed-off-by: Miroslav Lichvar + +diff --git a/unicast_service.c b/unicast_service.c +index ad0e06a..9c9b95b 100644 +--- a/unicast_service.c ++++ b/unicast_service.c +@@ -502,7 +502,7 @@ int unicast_service_timer(struct port *p) + pr_debug("peek i={2^%d} tmo={%ld,%ld}", interval->log_period, + interval->tmo.tv_sec, interval->tmo.tv_nsec); + +- if (timespec_compare(&now, &interval->tmo) >= 0) { ++ if (timespec_compare(&now, &interval->tmo) > 0) { + break; + } + interval = pqueue_extract(p->unicast_service->queue); diff --git a/SOURCES/linuxptp-ucastrate.patch b/SOURCES/linuxptp-ucastrate.patch new file mode 100644 index 0000000..77fad5c --- /dev/null +++ b/SOURCES/linuxptp-ucastrate.patch @@ -0,0 +1,45 @@ +commit a36602f1e65cd6bace6ed9405b0ce359de4a27d1 +Author: Miroslav Lichvar +Date: Thu Jan 3 15:23:54 2019 +0100 + + unicast: limit message rate and grant duration + + Deny service requests with logInterMessagePeriod smaller than -7 (128 + packets per second) or larger than 16. This limits the network and CPU + consumption per address and prevents undefined shifts in the calculation + of the interval. + + Also, limit the maximum grant duration to one hour. + + Signed-off-by: Miroslav Lichvar + +diff --git a/unicast_service.c b/unicast_service.c +index 9c9b95b..c6c17c6 100644 +--- a/unicast_service.c ++++ b/unicast_service.c +@@ -31,6 +31,9 @@ + #include "unicast_service.h" + #include "util.h" + ++#define MIN_LOG_INTER_MESSAGE_PERIOD -7 ++#define MAX_LOG_INTER_MESSAGE_PERIOD 16 ++#define MAX_DURATION 3600 + #define QUEUE_LEN 16 + + struct unicast_client_address { +@@ -289,6 +292,15 @@ int unicast_service_add(struct port *p, struct ptp_message *m, + return SERVICE_DENIED; + } + ++ if (req->logInterMessagePeriod < MIN_LOG_INTER_MESSAGE_PERIOD || ++ req->logInterMessagePeriod > MAX_LOG_INTER_MESSAGE_PERIOD) { ++ return SERVICE_DENIED; ++ } ++ ++ if (req->durationField > MAX_DURATION) { ++ req->durationField = MAX_DURATION; ++ } ++ + LIST_FOREACH(itmp, &p->unicast_service->intervals, list) { + /* + * Remember the interval of interest. diff --git a/SOURCES/linuxptp-zerolength.patch b/SOURCES/linuxptp-zerolength.patch new file mode 100644 index 0000000..8be7d1e --- /dev/null +++ b/SOURCES/linuxptp-zerolength.patch @@ -0,0 +1,46 @@ +commit 6b61ba29c78e26109426429c6d6b354f6e4443cd +Author: David Mirabito via Linuxptp-devel +Date: Tue Mar 19 13:42:48 2019 +1100 + + Avoid fault when receiving zero length packets + + The manpage for recvmsg says -1 will be returned on error, Zero indicates an + "orderly shutdown", presumably only in case of stream sockets. + Further, UNIX Network Programming, Vol 1 says ".. a return value of 0 from + recvfrom is acceptable for a datagram protocol" + + Such packets have been observed in the wild, aimed at PTP's multicast + address and port, possibly related to malformed management queries. + + Patch to properly check return from recvmesg and not trigger the fault + codepath. Instead, such packets are treated as "Bad Message" the same as + non-zero but still too-short UDP payloads. + + Signed-off-by: David Mirabito + +diff --git a/port.c b/port.c +index ad9554f..9264211 100644 +--- a/port.c ++++ b/port.c +@@ -2563,7 +2563,7 @@ static enum fsm_event bc_event(struct port *p, int fd_index) + msg->hwts.type = p->timestamping; + + cnt = transport_recv(p->trp, fd, msg); +- if (cnt <= 0) { ++ if (cnt < 0) { + pr_err("port %hu: recv message failed", portnum(p)); + msg_put(msg); + return EV_FAULT_DETECTED; +diff --git a/sk.c b/sk.c +index 30162eb..93ba77a 100644 +--- a/sk.c ++++ b/sk.c +@@ -359,7 +359,7 @@ int sk_receive(int fd, void *buf, int buflen, + } + + cnt = recvmsg(fd, &msg, flags); +- if (cnt < 1) ++ if (cnt < 0) + pr_err("recvmsg%sfailed: %m", + flags == MSG_ERRQUEUE ? " tx timestamp " : " "); + diff --git a/SOURCES/phc2sys.service b/SOURCES/phc2sys.service new file mode 100644 index 0000000..ff2f77e --- /dev/null +++ b/SOURCES/phc2sys.service @@ -0,0 +1,11 @@ +[Unit] +Description=Synchronize system clock or PTP hardware clock (PHC) +After=ntpdate.service ptp4l.service + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/phc2sys +ExecStart=/usr/sbin/phc2sys $OPTIONS + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/ptp4l.service b/SOURCES/ptp4l.service new file mode 100644 index 0000000..fbb26d1 --- /dev/null +++ b/SOURCES/ptp4l.service @@ -0,0 +1,12 @@ +[Unit] +Description=Precision Time Protocol (PTP) service +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/ptp4l +ExecStart=/usr/sbin/ptp4l $OPTIONS + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/timemaster.conf b/SOURCES/timemaster.conf new file mode 100644 index 0000000..fd8e77e --- /dev/null +++ b/SOURCES/timemaster.conf @@ -0,0 +1,33 @@ +# Configuration file for timemaster + +#[ntp_server ntp-server.local] +#minpoll 4 +#maxpoll 4 + +#[ptp_domain 0] +#interfaces eth0 +#delay 10e-6 + +[timemaster] +ntp_program chronyd + +[chrony.conf] +include /etc/chrony.conf + +[ntp.conf] +includefile /etc/ntp.conf + +[ptp4l.conf] + +[chronyd] +path /usr/sbin/chronyd + +[ntpd] +path /usr/sbin/ntpd +options -u ntp:ntp -g + +[phc2sys] +path /usr/sbin/phc2sys + +[ptp4l] +path /usr/sbin/ptp4l diff --git a/SOURCES/timemaster.service b/SOURCES/timemaster.service new file mode 100644 index 0000000..a6bda33 --- /dev/null +++ b/SOURCES/timemaster.service @@ -0,0 +1,12 @@ +[Unit] +Description=Synchronize system clock to NTP and PTP time sources +After=chronyd.service ntpd.service ntpdate.service sntp.service network-online.target +Conflicts=chronyd.service ntpd.service phc2sys.service ptp4l.service +Wants=network-online.target + +[Service] +Type=simple +ExecStart=/usr/sbin/timemaster -f /etc/timemaster.conf + +[Install] +WantedBy=multi-user.target diff --git a/SPECS/linuxptp.spec b/SPECS/linuxptp.spec new file mode 100644 index 0000000..f2c4481 --- /dev/null +++ b/SPECS/linuxptp.spec @@ -0,0 +1,234 @@ +%global _hardened_build 1 +%global testsuite_ver a7f6e1 +%global clknetsim_ver 8b4842 + +Name: linuxptp +Version: 2.0 +Release: 5%{?dist} +Summary: PTP implementation for Linux + +Group: System Environment/Base +License: GPLv2+ +URL: http://linuxptp.sourceforge.net/ + +Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz +Source1: phc2sys.service +Source2: ptp4l.service +Source3: timemaster.service +Source4: timemaster.conf +# external test suite +Source10: https://github.com/mlichvar/linuxptp-testsuite/archive/%{testsuite_ver}/linuxptp-testsuite-%{testsuite_ver}.tar.gz +# simulator for test suite +Source11: https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/clknetsim-%{clknetsim_ver}.tar.gz + +# fix building with new kernel headers +Patch1: linuxptp-headers.patch +# fix timeout handling to work with simulated clock +Patch2: linuxptp-timeout.patch +# add support for more accurate synchronization to phc2sys +Patch3: linuxptp-sysoff.patch +# limit unicast message rate per address and grant duration +Patch4: linuxptp-ucastrate.patch +# add support for active-backup team interface +Patch5: linuxptp-team.patch +# fix comparing of unicast addresses +Patch6: linuxptp-addreq.patch +# don't leak memory when allocation fails +Patch7: linuxptp-msgput.patch +# add hwts_filter option to ptp4l +Patch8: linuxptp-hwtsfilter.patch +# fix handling of zero-length messages +Patch9: linuxptp-zerolength.patch + +BuildRequires: kernel-headers > 4.18.0-87 +BuildRequires: systemd + +%{?systemd_requires} + +%description +This software is an implementation of the Precision Time Protocol (PTP) +according to IEEE standard 1588 for Linux. The dual design goals are to provide +a robust implementation of the standard and to use the most relevant and modern +Application Programming Interfaces (API) offered by the Linux kernel. +Supporting legacy APIs and other platforms is not a goal. + +%prep +%setup -q -a 10 -a 11 -n %{name}-%{!?gitfullver:%{version}}%{?gitfullver} +%patch1 -p1 -b .headers +%patch2 -p1 -b .timeout +%patch3 -p1 -b .sysoff +%patch4 -p1 -b .ucastrate +%patch5 -p1 -b .team +%patch6 -p1 -b .addreq +%patch7 -p1 -b .msgput +%patch8 -p1 -b .hwtsfilter +%patch9 -p1 -b .zerolength +mv linuxptp-testsuite-%{testsuite_ver}* testsuite +mv clknetsim-%{clknetsim_ver}* testsuite/clknetsim + +%build +make %{?_smp_mflags} \ + EXTRA_CFLAGS="$RPM_OPT_FLAGS" \ + EXTRA_LDFLAGS="$RPM_LD_FLAGS" + +%install +%makeinstall + +mkdir -p $RPM_BUILD_ROOT{%{_sysconfdir}/sysconfig,%{_unitdir},%{_mandir}/man5} +install -m 644 -p configs/default.cfg $RPM_BUILD_ROOT%{_sysconfdir}/ptp4l.conf +install -m 644 -p %{SOURCE1} %{SOURCE2} %{SOURCE3} $RPM_BUILD_ROOT%{_unitdir} +install -m 644 -p %{SOURCE4} $RPM_BUILD_ROOT%{_sysconfdir} + +echo 'OPTIONS="-f /etc/ptp4l.conf -i eth0"' > \ + $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/ptp4l +echo 'OPTIONS="-a -r"' > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/phc2sys + +echo '.so man8/ptp4l.8' > $RPM_BUILD_ROOT%{_mandir}/man5/ptp4l.conf.5 +echo '.so man8/timemaster.8' > $RPM_BUILD_ROOT%{_mandir}/man5/timemaster.conf.5 + +%check +cd testsuite +# set random seed to get deterministic results +export CLKNETSIM_RANDOM_SEED=26743 +make %{?_smp_mflags} -C clknetsim +PATH=..:$PATH ./run + +%post +%systemd_post phc2sys.service ptp4l.service timemaster.service + +%preun +%systemd_preun phc2sys.service ptp4l.service timemaster.service + +%postun +%systemd_postun_with_restart phc2sys.service ptp4l.service timemaster.service + +%files +%doc COPYING README.org configs +%config(noreplace) %{_sysconfdir}/ptp4l.conf +%config(noreplace) %{_sysconfdir}/sysconfig/phc2sys +%config(noreplace) %{_sysconfdir}/sysconfig/ptp4l +%config(noreplace) %{_sysconfdir}/timemaster.conf +%{_unitdir}/phc2sys.service +%{_unitdir}/ptp4l.service +%{_unitdir}/timemaster.service +%{_sbindir}/hwstamp_ctl +%{_sbindir}/nsm +%{_sbindir}/phc2sys +%{_sbindir}/phc_ctl +%{_sbindir}/pmc +%{_sbindir}/ptp4l +%{_sbindir}/timemaster +%{_mandir}/man5/*.5* +%{_mandir}/man8/*.8* + +%changelog +* Mon Apr 27 2020 Miroslav Lichvar 2.0-5 +- fix sample timestamps when synchronizing PHC to system clock (#1787376) +- fix handling of zero-length messages (#1827275) + +* Thu May 16 2019 Miroslav Lichvar 2.0-4 +- rebuild with enabled gating (#1680888) + +* Wed May 15 2019 Miroslav Lichvar 2.0-3 +- add support for active-backup team interface (#1685467) +- add support for more accurate synchronization to phc2sys (#1677217) +- add hwts_filter option to ptp4l (#1708554) +- limit unicast message rate per address and grant duration (#1707395) +- fix comparing of unicast addresses (#1707395) +- fix building with new kernel headers (#1707395) +- update testsuite (#1707395) +- don't leak memory when allocation fails (#1707395) + +* Tue Nov 13 2018 Miroslav Lichvar 2.0-2 +- start ptp4l, timemaster and phc2sys after network-online target (#1632282) + +* Mon Aug 13 2018 Miroslav Lichvar 2.0-1 +- update to 2.0 (#1614300) + +* Mon Apr 09 2018 Miroslav Lichvar 1.9.2-1 +- update to 1.9.2 + +* Wed Feb 07 2018 Fedora Release Engineering - 1.8-7.20180101git303b08 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Tue Jan 30 2018 Miroslav Lichvar 1.8-6.20180101git303b08 +- use macro for systemd scriptlet dependencies + +* Thu Jan 11 2018 Miroslav Lichvar 1.8-5.20180101git303b08 +- update to 20180101git303b08 + +* Thu Aug 03 2017 Fedora Release Engineering - 1.8-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1.8-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Feb 10 2017 Fedora Release Engineering - 1.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Nov 07 2016 Miroslav Lichvar 1.8-1 +- update to 1.8 + +* Fri Jul 22 2016 Miroslav Lichvar 1.7-1 +- update to 1.7 +- add delay option to default timemaster.conf + +* Thu Feb 04 2016 Fedora Release Engineering - 1.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Tue Sep 22 2015 Miroslav Lichvar 1.6-1 +- update to 1.6 +- set random seed in testing to get deterministic results +- remove trailing whitespace in default timemaster.conf + +* Wed Jun 17 2015 Fedora Release Engineering - 1.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Mon Jan 05 2015 Miroslav Lichvar 1.5-1 +- update to 1.5 + +* Sun Aug 17 2014 Fedora Release Engineering - 1.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 1.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri Feb 21 2014 Miroslav Lichvar 1.4-1 +- update to 1.4 +- replace hardening build flags with _hardened_build +- include test suite + +* Fri Aug 02 2013 Miroslav Lichvar 1.3-1 +- update to 1.3 + +* Tue Jul 30 2013 Miroslav Lichvar 1.2-3.20130730git7789f0 +- update to 20130730git7789f0 + +* Fri Jul 19 2013 Miroslav Lichvar 1.2-2.20130719git46db40 +- update to 20130719git46db40 +- drop old systemd scriptlets +- add man page link for ptp4l.conf + +* Mon Apr 22 2013 Miroslav Lichvar 1.2-1 +- update to 1.2 + +* Mon Feb 18 2013 Miroslav Lichvar 1.1-1 +- update to 1.1 +- log phc2sys output + +* Thu Feb 14 2013 Fedora Release Engineering - 1.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Dec 13 2012 Miroslav Lichvar 1.0-1 +- update to 1.0 + +* Fri Nov 09 2012 Miroslav Lichvar 0-0.3.20121109git4e8107 +- update to 20121109git4e8107 +- install unchanged default.cfg as ptp4l.conf +- drop conflicts from phc2sys service + +* Fri Sep 21 2012 Miroslav Lichvar 0-0.2.20120920git6ce135 +- fix issues found in package review (#859193) + +* Thu Sep 20 2012 Miroslav Lichvar 0-0.1.20120920git6ce135 +- initial release