diff --git a/.gitignore b/.gitignore index 987eddf..8069dde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -SOURCES/clknetsim-e63178.tar.gz -SOURCES/linuxptp-20140718gitbdb6a3.tar.gz -SOURCES/testsuite-7c523f.tar.gz +SOURCES/clknetsim-ce89a1.tar.gz +SOURCES/linuxptp-1.8.tgz +SOURCES/linuxptp-testsuite-502e82.tar.gz diff --git a/.linuxptp.metadata b/.linuxptp.metadata index 8beb86f..bb51355 100644 --- a/.linuxptp.metadata +++ b/.linuxptp.metadata @@ -1,3 +1,3 @@ -29583b9a274e1d89e9fdcd400ce427a513a666c9 SOURCES/clknetsim-e63178.tar.gz -3bbf8fbe1db7b344d5d465728a83abf877a6032f SOURCES/linuxptp-20140718gitbdb6a3.tar.gz -1d4505f7bac98e143d22b2d84c812f4ec92bb127 SOURCES/testsuite-7c523f.tar.gz +922f475728383b56b03eeadaf990c9231a51a9e3 SOURCES/clknetsim-ce89a1.tar.gz +449cf190347d24846440bd757570e391dd7dff96 SOURCES/linuxptp-1.8.tgz +1b6395c22a47a4af60db6963d063697ef6daae08 SOURCES/linuxptp-testsuite-502e82.tar.gz diff --git a/SOURCES/linuxptp-closesocket.patch b/SOURCES/linuxptp-closesocket.patch new file mode 100644 index 0000000..6b27b99 --- /dev/null +++ b/SOURCES/linuxptp-closesocket.patch @@ -0,0 +1,38 @@ +commit a3500e14ca4af38034d5ad2115ca7ac271c8c5b4 +Author: Miroslav Lichvar +Date: Mon Feb 6 15:43:00 2017 +0100 + + Fix leaks of sockets on errors. + + Signed-off-by: Miroslav Lichvar + +diff --git a/clock.c b/clock.c +index a6a1a1a..9481606 100644 +--- a/clock.c ++++ b/clock.c +@@ -824,11 +824,13 @@ static int clock_add_port(struct clock *c, int phc_index, + } + index = sk_interface_index(fd, iface->name); + if (index < 0) { ++ close(fd); + return -1; + } + snprintf(key, sizeof(key), "%d", index); + if (hash_insert(c->index2port, key, p)) { + pr_err("failed to add port with index %d twice!", index); ++ close(fd); + return -1; + } + close(fd); +diff --git a/rtnl.c b/rtnl.c +index 7f5dc45..251b5f3 100644 +--- a/rtnl.c ++++ b/rtnl.c +@@ -160,6 +160,7 @@ int rtnl_open(void) + } + if (bind(fd, (struct sockaddr *) &sa, sizeof(sa))) { + pr_err("failed to bind netlink socket: %m"); ++ close(fd); + return -1; + } + return fd; diff --git a/SOURCES/linuxptp-linkdown.patch b/SOURCES/linuxptp-linkdown.patch new file mode 100644 index 0000000..34d1ae3 --- /dev/null +++ b/SOURCES/linuxptp-linkdown.patch @@ -0,0 +1,75 @@ +Backport of commit 73318c5b99571c8da01474ad665e2e2e06ab12bb +Author: Richard Cochran +Date: Sun Feb 5 18:31:27 2017 +0100 + + clock: Force a BMC election when a port link goes down. + + Having one fewer port may affect the result of the BMCA. This patch + changes the main loop so that a link down event also causes a state + decision event. + + Signed-off-by: Richard Cochran + Reported-by: Henry Jesuiter + +diff -up linuxptp-1.8/clock.c.linkdown linuxptp-1.8/clock.c +--- linuxptp-1.8/clock.c.linkdown 2017-03-15 08:37:03.017542152 +0100 ++++ linuxptp-1.8/clock.c 2017-03-15 08:42:53.238682318 +0100 +@@ -96,6 +96,7 @@ struct clock { + int pollfd_valid; + int nports; /* does not include the UDS port */ + int last_port_number; ++ int sde; + struct hash *index2port; + int free_running; + int freq_est_interval; +@@ -341,6 +342,11 @@ static void clock_link_status(void *ctx, + port_dispatch(p, EV_FAULT_CLEARED, 0); + } else { + port_dispatch(p, EV_FAULT_DETECTED, 0); ++ /* ++ * A port going down can affect the BMCA result. ++ * Force a state decision event. ++ */ ++ c->sde = 1; + } + } + +@@ -1465,7 +1471,7 @@ struct PortIdentity clock_parent_identit + + int clock_poll(struct clock *c) + { +- int cnt, err, i, sde = 0; ++ int cnt, err, i; + enum fsm_event event; + struct pollfd *cur; + struct port *p; +@@ -1496,9 +1502,9 @@ int clock_poll(struct clock *c) + if (cur[i].revents & (POLLIN|POLLPRI)) { + event = port_event(p, i); + if (EV_STATE_DECISION_EVENT == event) +- sde = 1; ++ c->sde = 1; + if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event) +- sde = 1; ++ c->sde = 1; + err = port_dispatch(p, event, 0); + /* Clear any fault after a little while. */ + if (PS_FAULTY == port_state(p)) { +@@ -1527,13 +1533,14 @@ int clock_poll(struct clock *c) + if (cur[i].revents & (POLLIN|POLLPRI)) { + event = port_event(c->uds_port, i); + if (EV_STATE_DECISION_EVENT == event) +- sde = 1; ++ c->sde = 1; + } + } + +- if (sde) ++ if (c->sde) { + handle_state_decision_event(c); +- ++ c->sde = 0; ++ } + clock_prune_subscriptions(c); + return 0; + } diff --git a/SOURCES/linuxptp-linreg_reset.patch b/SOURCES/linuxptp-linreg_reset.patch deleted file mode 100644 index 24eb16c..0000000 --- a/SOURCES/linuxptp-linreg_reset.patch +++ /dev/null @@ -1,25 +0,0 @@ -commit 37459fd1ad1ac48a121ab0edae331090fb8e2833 -Author: Miroslav Lichvar -Date: Thu Nov 20 17:30:28 2014 +0100 - - linreg: fix servo resetting - - The stats for the maximum size were not reset, which caused the - the servo to reuse old data instead of returning with unlocked - state. - - Signed-off-by: Miroslav Lichvar - -diff --git a/linreg.c b/linreg.c -index b94c44e..fde604d 100644 ---- a/linreg.c -+++ b/linreg.c -@@ -294,7 +294,7 @@ static void linreg_reset(struct servo *servo) - s->last_update = 0; - s->frequency_ratio = 1.0; - -- for (i = MIN_SIZE; i < MAX_SIZE; i++) { -+ for (i = MIN_SIZE; i <= MAX_SIZE; i++) { - s->results[i - MIN_SIZE].slope = 0.0; - s->results[i - MIN_SIZE].err_updates = 0; - } diff --git a/SOURCES/linuxptp-messagetag.patch b/SOURCES/linuxptp-messagetag.patch new file mode 100644 index 0000000..dc9caa8 --- /dev/null +++ b/SOURCES/linuxptp-messagetag.patch @@ -0,0 +1,553 @@ +commit 4e8dbd84925d36f1193a7339a542677d884d3ba1 +Author: Richard Cochran +Date: Tue Dec 6 19:40:36 2016 +0100 + + ptp4l: Accept any configuration option as a command line argument. + + This patch provides a way to use the entire table of configuration options + as "long" command line switches. + + Signed-off-by: Richard Cochran + +diff --git a/config.c b/config.c +index 5da5ecc..384b437 100644 +--- a/config.c ++++ b/config.c +@@ -329,6 +329,7 @@ static enum parser_result parse_section_line(char *s, enum config_section *secti + } + + static enum parser_result parse_item(struct config *cfg, ++ int commandline, + const char *section, + const char *option, + const char *value) +@@ -387,7 +388,7 @@ static enum parser_result parse_item(struct config *cfg, + return NOT_PARSED; + } + } +- } else if (cgi->flags & CFG_ITEM_LOCKED) { ++ } else if (!commandline && cgi->flags & CFG_ITEM_LOCKED) { + /* This global option was set on the command line. */ + return PARSED_OK; + } else { +@@ -415,6 +416,10 @@ static enum parser_result parse_item(struct config *cfg, + dst->flags |= CFG_ITEM_DYNSTR; + break; + } ++ ++ if (commandline) { ++ dst->flags &= CFG_ITEM_LOCKED; ++ } + return PARSED_OK; + } + +@@ -490,6 +495,25 @@ static void check_deprecated_options(const char **option) + } + } + ++static struct option *config_alloc_longopts(struct config *cfg) ++{ ++ struct config_item *ci; ++ struct option *opts; ++ int i; ++ ++ opts = calloc(1, (1 + N_CONFIG_ITEMS) * sizeof(*opts)); ++ if (!opts) { ++ return NULL; ++ } ++ for (i = 0; i < N_CONFIG_ITEMS; i++) { ++ ci = &config_tab[i]; ++ opts[i].name = ci->label; ++ opts[i].has_arg = required_argument; ++ } ++ ++ return opts; ++} ++ + int config_read(char *name, struct config *cfg) + { + enum config_section current_section = UNKNOWN_SECTION; +@@ -554,7 +578,7 @@ int config_read(char *name, struct config *cfg) + + check_deprecated_options(&option); + +- parser_res = parse_item(cfg, current_section == GLOBAL_SECTION ? ++ parser_res = parse_item(cfg, 0, current_section == GLOBAL_SECTION ? + NULL : current_port->name, option, value); + + switch (parser_res) { +@@ -627,8 +651,15 @@ struct config *config_create(void) + } + STAILQ_INIT(&cfg->interfaces); + ++ cfg->opts = config_alloc_longopts(cfg); ++ if (!cfg->opts) { ++ free(cfg); ++ return NULL; ++ } ++ + cfg->htab = hash_create(); + if (!cfg->htab) { ++ free(cfg->opts); + free(cfg); + return NULL; + } +@@ -657,6 +688,7 @@ struct config *config_create(void) + return cfg; + fail: + hash_destroy(cfg->htab, NULL); ++ free(cfg->opts); + free(cfg); + return NULL; + } +@@ -670,6 +702,7 @@ void config_destroy(struct config *cfg) + free(iface); + } + hash_destroy(cfg->htab, config_item_free); ++ free(cfg->opts); + free(cfg); + } + +@@ -720,6 +753,33 @@ char *config_get_string(struct config *cfg, const char *section, + return ci->val.s; + } + ++int config_parse_option(struct config *cfg, const char *opt, const char *val) ++{ ++ enum parser_result result; ++ ++ result = parse_item(cfg, 1, NULL, opt, val); ++ ++ switch (result) { ++ case PARSED_OK: ++ return 0; ++ case NOT_PARSED: ++ fprintf(stderr, "unknown option %s\n", opt); ++ break; ++ case BAD_VALUE: ++ fprintf(stderr, "%s is a bad value for option %s\n", val, opt); ++ break; ++ case MALFORMED: ++ fprintf(stderr, "%s is a malformed value for option %s\n", ++ val, opt); ++ break; ++ case OUT_OF_RANGE: ++ fprintf(stderr, "%s is an out of range value for option %s\n", ++ val, opt); ++ break; ++ } ++ return -1; ++} ++ + int config_set_double(struct config *cfg, const char *option, double val) + { + struct config_item *ci = config_find_item(cfg, NULL, option); +diff --git a/config.h b/config.h +index b02bde6..1cc7051 100644 +--- a/config.h ++++ b/config.h +@@ -20,6 +20,7 @@ + #ifndef HAVE_CONFIG_H + #define HAVE_CONFIG_H + ++#include + #include + + #include "ds.h" +@@ -43,6 +44,9 @@ struct config { + STAILQ_HEAD(interfaces_head, interface) interfaces; + int n_interfaces; + ++ /* for parsing command line options */ ++ struct option *opts; ++ + /* hash of all non-legacy items */ + struct hash *htab; + }; +@@ -64,6 +68,13 @@ int config_get_int(struct config *cfg, const char *section, + char *config_get_string(struct config *cfg, const char *section, + const char *option); + ++static inline struct option *config_long_options(struct config *cfg) ++{ ++ return cfg->opts; ++} ++ ++int config_parse_option(struct config *cfg, const char *opt, const char *val); ++ + int config_set_double(struct config *cfg, const char *option, double val); + + int config_set_section_int(struct config *cfg, const char *section, +diff --git a/ptp4l.c b/ptp4l.c +index a87e7e6..e90fcb2 100644 +--- a/ptp4l.c ++++ b/ptp4l.c +@@ -73,8 +73,9 @@ static void usage(char *progname) + int main(int argc, char *argv[]) + { + char *config = NULL, *req_phc = NULL, *progname; +- int c, err = -1, print_level; ++ int c, err = -1, index, print_level; + struct clock *clock = NULL; ++ struct option *opts; + struct config *cfg; + + if (handle_term_signals()) +@@ -84,12 +85,18 @@ int main(int argc, char *argv[]) + if (!cfg) { + return -1; + } ++ opts = config_long_options(cfg); + + /* Process the command line arguments. */ + progname = strrchr(argv[0], '/'); + progname = progname ? 1+progname : argv[0]; +- while (EOF != (c = getopt(argc, argv, "AEP246HSLf:i:p:sl:mqvh"))) { ++ while (EOF != (c = getopt_long(argc, argv, "AEP246HSLf:i:p:sl:mqvh", ++ opts, &index))) { + switch (c) { ++ case 0: ++ if (config_parse_option(cfg, opts[index].name, optarg)) ++ goto out; ++ break; + case 'A': + if (config_set_int(cfg, "delay_mechanism", DM_AUTO)) + goto out; + +commit e658982624bfd5cd998066fdf35b93cdcf8797ca +Author: Richard Cochran +Date: Tue Dec 13 19:55:39 2016 +0100 + + config: Fix bitwise copy-and-pasto for command line items. + + The recent change allowing every configuration option to appear on the + command line wrongly used bitwise AND to set a flag. This patch fixes + the bug by using the proper bitwise OR idiom. + + Signed-off-by: Richard Cochran + Reported-by: Miroslav Lichvar + Fixes: 4e8dbd8 ("ptp4l: Accept any configuration option as a command line argument.") + +diff --git a/config.c b/config.c +index 384b437..b19f3ad 100644 +--- a/config.c ++++ b/config.c +@@ -418,7 +418,7 @@ static enum parser_result parse_item(struct config *cfg, + } + + if (commandline) { +- dst->flags &= CFG_ITEM_LOCKED; ++ dst->flags |= CFG_ITEM_LOCKED; + } + return PARSED_OK; + } + +commit 4e966536c6253d73e1a3202e8b562ab0f518e33b +Author: Richard Cochran +Date: Tue Dec 13 20:49:22 2016 +0100 + + ptp4l: Document the "long" command line options in the man page. + + Signed-off-by: Richard Cochran + +diff --git a/ptp4l.8 b/ptp4l.8 +index 63e9abd..f53fc6e 100644 +--- a/ptp4l.8 ++++ b/ptp4l.8 +@@ -1,4 +1,4 @@ +-.TH PTP4l 8 "July 2016" "linuxptp" ++.TH PTP4l 8 "December 2016" "linuxptp" + .SH NAME + ptp4l - PTP Boundary/Ordinary Clock + +@@ -15,6 +15,8 @@ ptp4l - PTP Boundary/Ordinary Clock + ] + [ + .BI \-i " interface" ++] [ ++.I long-options + ] + .I .\|.\|. + +@@ -94,6 +96,19 @@ Prints the software version and exits. + .BI \-h + Display a help message. + ++.SH LONG OPTIONS ++ ++Each and every configuration file option (see below) may also appear ++as a "long" style command line argument. For example, the slaveOnly ++option may be set using either of these two forms. ++ ++.RS ++\f(CW\-\-slaveOnly 1 \-\-slaveOnly=1\fP ++.RE ++ ++Option values given on the command line override values in the global ++section of the configuration file. ++ + .SH CONFIGURATION FILE + + The configuration file is divided into sections. Each section starts with a + +commit 0f6c6972c791813e0b9618e9158da3951a099737 +Author: Miroslav Lichvar +Date: Tue Jan 17 14:17:39 2017 +0100 + + Add options to tag ptp4l and phc2sys log messages. + + When running multiple instances of ptp4l or phc2sys, it's difficult to + tell which log message belongs to which instance. Add new options to + ptp4l and phc2sys which can specify a tag for all messages printed to + the standard output or system log, so messages from different instances + can have different tags. + + Signed-off-by: Miroslav Lichvar + +diff --git a/config.c b/config.c +index 7bb949d..e6fe676 100644 +--- a/config.c ++++ b/config.c +@@ -199,6 +199,7 @@ struct config_item config_tab[] = { + PORT_ITEM_INT("logMinPdelayReqInterval", 0, INT8_MIN, INT8_MAX), + PORT_ITEM_INT("logSyncInterval", 0, INT8_MIN, INT8_MAX), + GLOB_ITEM_INT("logging_level", LOG_INFO, PRINT_LEVEL_MIN, PRINT_LEVEL_MAX), ++ GLOB_ITEM_STR("message_tag", NULL), + GLOB_ITEM_STR("manufacturerIdentity", "00:00:00"), + GLOB_ITEM_INT("max_frequency", 900000000, 0, INT_MAX), + PORT_ITEM_INT("min_neighbor_prop_delay", -20000000, INT_MIN, -1), +diff --git a/phc2sys.8 b/phc2sys.8 +index 22d02c2..2559c74 100644 +--- a/phc2sys.8 ++++ b/phc2sys.8 +@@ -206,6 +206,10 @@ The default is /var/run/ptp4l. + Set the maximum syslog level of messages which should be printed or sent to + the system logger. The default is 6 (LOG_INFO). + .TP ++.BI \-t " message-tag" ++Specify the tag which is added to all messages printed to the standard output ++or system log. The default is an empty string. ++.TP + .B \-m + Print messages to the standard output. + .TP +diff --git a/phc2sys.c b/phc2sys.c +index 35cf6fa..aa4186b 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -1209,6 +1209,7 @@ static void usage(char *progname) + " -x apply leap seconds by servo instead of kernel\n" + " -z [path] server address for UDS (/var/run/ptp4l)\n" + " -l [num] set the logging level to 'num' (6)\n" ++ " -t [tag] add tag to log messages\n" + " -m print messages to stdout\n" + " -q do not print messages to the syslog\n" + " -v prints the software version and exits\n" +@@ -1219,7 +1220,7 @@ static void usage(char *progname) + + int main(int argc, char *argv[]) + { +- char *progname; ++ char *progname, *message_tag = NULL; + char *src_name = NULL, *dst_name = NULL; + struct clock *src, *dst; + struct config *cfg; +@@ -1251,7 +1252,7 @@ int main(int argc, char *argv[]) + progname = strrchr(argv[0], '/'); + progname = progname ? 1+progname : argv[0]; + while (EOF != (c = getopt(argc, argv, +- "arc:d:s:E:P:I:S:F:R:N:O:L:M:i:u:wn:xz:l:mqvh"))) { ++ "arc:d:s:E:P:I:S:F:R:N:O:L:M:i:u:wn:xz:l:t:mqvh"))) { + switch (c) { + case 'a': + autocfg = 1; +@@ -1363,6 +1364,9 @@ int main(int argc, char *argv[]) + PRINT_LEVEL_MIN, PRINT_LEVEL_MAX)) + goto end; + break; ++ case 't': ++ message_tag = optarg; ++ break; + case 'm': + verbose = 1; + break; +@@ -1405,6 +1409,7 @@ int main(int argc, char *argv[]) + } + + print_set_progname(progname); ++ print_set_tag(message_tag); + print_set_verbose(verbose); + print_set_syslog(use_syslog); + print_set_level(print_level); +diff --git a/print.c b/print.c +index a82d0e7..6c48e1e 100644 +--- a/print.c ++++ b/print.c +@@ -28,12 +28,18 @@ static int verbose = 0; + static int print_level = LOG_INFO; + static int use_syslog = 1; + static const char *progname; ++static const char *message_tag; + + void print_set_progname(const char *name) + { + progname = name; + } + ++void print_set_tag(const char *tag) ++{ ++ message_tag = tag; ++} ++ + void print_set_syslog(int value) + { + use_syslog = value ? 1 : 0; +@@ -67,13 +73,17 @@ void print(int level, char const *format, ...) + + if (verbose) { + f = level >= LOG_NOTICE ? stdout : stderr; +- fprintf(f, "%s[%ld.%03ld]: %s\n", ++ fprintf(f, "%s[%ld.%03ld]: %s%s%s\n", + progname ? progname : "", +- ts.tv_sec, ts.tv_nsec / 1000000, buf); ++ ts.tv_sec, ts.tv_nsec / 1000000, ++ message_tag ? message_tag : "", message_tag ? " " : "", ++ buf); + fflush(f); + } + if (use_syslog) { +- syslog(level, "[%ld.%03ld] %s", +- ts.tv_sec, ts.tv_nsec / 1000000, buf); ++ syslog(level, "[%ld.%03ld] %s%s%s", ++ ts.tv_sec, ts.tv_nsec / 1000000, ++ message_tag ? message_tag : "", message_tag ? " " : "", ++ buf); + } + } +diff --git a/print.h b/print.h +index e8f2c8e..1723d8a 100644 +--- a/print.h ++++ b/print.h +@@ -33,6 +33,7 @@ __attribute__ ((format (printf, 2, 3))) + void print(int level, char const *format, ...); + + void print_set_progname(const char *name); ++void print_set_tag(const char *tag); + void print_set_syslog(int value); + void print_set_level(int level); + void print_set_verbose(int value); +diff --git a/ptp4l.8 b/ptp4l.8 +index 53d5f28..a724151 100644 +--- a/ptp4l.8 ++++ b/ptp4l.8 +@@ -485,6 +485,12 @@ is 0. + The maximum logging level of messages which should be printed. + The default is 6 (LOG_INFO). + .TP ++.B message_tag ++The tag which is added to all messages printed to the standard output or system ++log. ++The default is an empty string (which cannot be set in the configuration file ++as the option requires an argument). ++.TP + .B verbose + Print messages to the standard output if enabled. + The default is 0 (disabled). +diff --git a/ptp4l.c b/ptp4l.c +index e90fcb2..f01ff6f 100644 +--- a/ptp4l.c ++++ b/ptp4l.c +@@ -183,6 +183,7 @@ int main(int argc, char *argv[]) + } + + print_set_progname(progname); ++ print_set_tag(config_get_string(cfg, NULL, "message_tag")); + print_set_verbose(config_get_int(cfg, NULL, "verbose")); + print_set_syslog(config_get_int(cfg, NULL, "use_syslog")); + print_set_level(config_get_int(cfg, NULL, "logging_level")); + +commit e54158195b1eadfdb6275646bc3dfb7611dba5b6 +Author: Miroslav Lichvar +Date: Tue Jan 17 14:17:40 2017 +0100 + + timemaster: tag ptp4l and phc2sys messages. + + Use the new options of ptp4l and phc2sys to tag their log messages with + the PTP domain number and name(s) of interface(s) in the domain. + + Signed-off-by: Miroslav Lichvar + +diff --git a/timemaster.c b/timemaster.c +index 66ac521..880b2ab 100644 +--- a/timemaster.c ++++ b/timemaster.c +@@ -599,7 +599,8 @@ static char **get_ptp4l_command(struct program_config *config, + } + + static char **get_phc2sys_command(struct program_config *config, int domain, +- int poll, int shm_segment, char *uds_path) ++ int poll, int shm_segment, char *uds_path, ++ char *message_tag) + { + char **command = (char **)parray_new(); + +@@ -610,6 +611,7 @@ static char **get_phc2sys_command(struct program_config *config, int domain, + xstrdup("-R"), string_newf("%.2f", poll > 0 ? + 1.0 / (1 << poll) : 1 << -poll), + xstrdup("-z"), xstrdup(uds_path), ++ xstrdup("-t"), xstrdup(message_tag), + xstrdup("-n"), string_newf("%d", domain), + xstrdup("-E"), xstrdup("ntpshm"), + xstrdup("-M"), string_newf("%d", shm_segment), NULL); +@@ -671,7 +673,7 @@ static int add_ptp_source(struct ptp_domain *source, + struct script *script) + { + struct config_file *config_file; +- char **command, *uds_path, **interfaces; ++ char **command, *uds_path, **interfaces, *message_tag; + int i, j, num_interfaces, *phc, *phcs, hw_ts; + struct sk_ts_info ts_info; + +@@ -749,6 +751,12 @@ static int add_ptp_source(struct ptp_domain *source, + uds_path = string_newf("%s/ptp4l.%d.socket", + config->rundir, *shm_segment); + ++ message_tag = string_newf("[%d", source->domain); ++ for (j = 0; interfaces[j]; j++) ++ string_appendf(&message_tag, "%s%s", j ? "+" : ":", ++ interfaces[j]); ++ string_appendf(&message_tag, "]"); ++ + config_file = xmalloc(sizeof(*config_file)); + config_file->path = string_newf("%s/ptp4l.%d.conf", + config->rundir, *shm_segment); +@@ -760,8 +768,9 @@ static int add_ptp_source(struct ptp_domain *source, + string_appendf(&config_file->content, + "slaveOnly 1\n" + "domainNumber %d\n" +- "uds_address %s\n", +- source->domain, uds_path); ++ "uds_address %s\n" ++ "message_tag %s\n", ++ source->domain, uds_path, message_tag); + + if (phcs[i] >= 0) { + /* HW time stamping */ +@@ -772,7 +781,8 @@ static int add_ptp_source(struct ptp_domain *source, + command = get_phc2sys_command(&config->phc2sys, + source->domain, + source->phc2sys_poll, +- *shm_segment, uds_path); ++ *shm_segment, uds_path, ++ message_tag); + parray_append((void ***)&script->commands, command); + } else { + /* SW time stamping */ +@@ -793,6 +803,7 @@ static int add_ptp_source(struct ptp_domain *source, + + (*shm_segment)++; + ++ free(message_tag); + free(uds_path); + free(interfaces); + } diff --git a/SOURCES/linuxptp-peeraddress.patch b/SOURCES/linuxptp-peeraddress.patch deleted file mode 100644 index db6f335..0000000 --- a/SOURCES/linuxptp-peeraddress.patch +++ /dev/null @@ -1,65 +0,0 @@ -commit 6b05b4e7d3255a3bbf49e20abccb511290b6196d -Author: Richard Cochran -Date: Thu Oct 9 22:09:06 2014 +0200 - - Restore the peer addresses in P2P mode. - - Commit ea7a7882 removed the calls to transport_peer(), inadvertently - substituting them with transport_send(), resulting in PDelay messages - being sent with an incorrect destination address. - - This patch fixes the issue by introducing peer_prepare_and_send(), - analogous to the port_prepare_and_send() function. - - Signed-off-by: Richard Cochran - Acked-by: Jiri Benc - -diff --git a/port.c b/port.c -index 18405c6..caea891 100644 ---- a/port.c -+++ b/port.c -@@ -484,6 +484,17 @@ static int path_trace_ignore(struct port *p, struct ptp_message *m) - return 0; - } - -+static int peer_prepare_and_send(struct port *p, struct ptp_message *msg, -+ int event) -+{ -+ int cnt; -+ if (msg_pre_send(msg)) { -+ return -1; -+ } -+ cnt = transport_peer(p->trp, &p->fda, event, msg); -+ return cnt <= 0 ? -1 : 0; -+} -+ - static int port_capable(struct port *p) - { - if (!port_is_ieee8021as(p)) { -@@ -1114,7 +1125,7 @@ static int port_pdelay_request(struct port *p) - msg->header.logMessageInterval = port_is_ieee8021as(p) ? - p->logMinPdelayReqInterval : 0x7f; - -- err = port_prepare_and_send(p, msg, 1); -+ err = peer_prepare_and_send(p, msg, 1); - if (err) { - pr_err("port %hu: send peer delay request failed", portnum(p)); - goto out; -@@ -1728,7 +1739,7 @@ static int process_pdelay_req(struct port *p, struct ptp_message *m) - - fup->pdelay_resp_fup.requestingPortIdentity = m->header.sourcePortIdentity; - -- err = port_prepare_and_send(p, rsp, 1); -+ err = peer_prepare_and_send(p, rsp, 1); - if (err) { - pr_err("port %hu: send peer delay response failed", portnum(p)); - goto out; -@@ -1741,7 +1752,7 @@ static int process_pdelay_req(struct port *p, struct ptp_message *m) - ts_to_timestamp(&rsp->hwts.ts, - &fup->pdelay_resp_fup.responseOriginTimestamp); - -- err = port_prepare_and_send(p, fup, 0); -+ err = peer_prepare_and_send(p, fup, 0); - if (err) - pr_err("port %hu: send pdelay_resp_fup failed", portnum(p)); - diff --git a/SOURCES/linuxptp-phc2sys_state.patch b/SOURCES/linuxptp-phc2sys_state.patch deleted file mode 100644 index f0989f5..0000000 --- a/SOURCES/linuxptp-phc2sys_state.patch +++ /dev/null @@ -1,35 +0,0 @@ -commit 7455c241485e01da12d107f5b665e10794330967 -Author: Jiri Benc -Date: Thu Nov 13 18:18:12 2014 +0100 - - phc2sys: fix overwriting of the clock state - - The reconfigure function is missing a check whether state for the given - clock actually changed or not. This caused state for all unchanged ports to - be zeroed. - - Reported-by: Richard Cochran - Signed-off-by: Jiri Benc - -diff --git a/phc2sys.c b/phc2sys.c -index 22eb9c9..67d8a58 100644 ---- a/phc2sys.c -+++ b/phc2sys.c -@@ -305,11 +305,13 @@ static void reconfigure(struct node *node) - continue; - } - -- if (c->new_state == PS_MASTER) -- clock_reinit(c); -+ if (c->new_state) { -+ if (c->new_state == PS_MASTER) -+ clock_reinit(c); - -- c->state = c->new_state; -- c->new_state = 0; -+ c->state = c->new_state; -+ c->new_state = 0; -+ } - - if (c->state == PS_SLAVE) { - src = c; diff --git a/SOURCES/linuxptp-shm.patch b/SOURCES/linuxptp-shm.patch deleted file mode 100644 index 317c94c..0000000 --- a/SOURCES/linuxptp-shm.patch +++ /dev/null @@ -1,140 +0,0 @@ -commit 3760f8b6537ec4f614d9aa07d957716ee2e51059 -Author: Miroslav Lichvar -Date: Wed Jul 9 16:25:08 2014 +0200 - - Add option to set NTP SHM segment number. - - Instead of setting it to the PTP domain number, add a new option to - ptp4l and phc2sys to set it as needed. The default value is 0. This - allows multiple ptp4l/phc2sys instances running in the same domain. - - Signed-off-by: Miroslav Lichvar - -diff --git a/config.c b/config.c -index 0bc85c1..0983c62 100644 ---- a/config.c -+++ b/config.c -@@ -284,7 +284,6 @@ static enum parser_result parse_global_setting(const char *option, - if (r != PARSED_OK) - return r; - dds->domainNumber = uval; -- *cfg->ntpshm_segment = uval; - - } else if (!strcmp(option, "clockClass")) { - r = get_ranged_uint(value, &uval, 0, UINT8_MAX); -@@ -408,6 +407,12 @@ static enum parser_result parse_global_setting(const char *option, - return r; - cfg->dds.sanity_freq_limit = val; - -+ } else if (!strcmp(option, "ntpshm_segment")) { -+ r = get_ranged_int(value, &val, INT_MIN, INT_MAX); -+ if (r != PARSED_OK) -+ return r; -+ *cfg->ntpshm_segment = val; -+ - } else if (!strcmp(option, "ptp_dst_mac")) { - if (MAC_LEN != sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) -diff --git a/default.cfg b/default.cfg -index 9f01eda..9e794ba 100644 ---- a/default.cfg -+++ b/default.cfg -@@ -53,6 +53,7 @@ first_step_threshold 0.00002 - max_frequency 900000000 - clock_servo pi - sanity_freq_limit 200000000 -+ntpshm_segment 0 - # - # Transport options - # -diff --git a/gPTP.cfg b/gPTP.cfg -index 4d0a38c..e15a05a 100644 ---- a/gPTP.cfg -+++ b/gPTP.cfg -@@ -53,6 +53,7 @@ first_step_threshold 0.00002 - max_frequency 900000000 - clock_servo pi - sanity_freq_limit 200000000 -+ntpshm_segment 0 - # - # Transport options - # -diff --git a/phc2sys.8 b/phc2sys.8 -index c4fb6f6..22d02c2 100644 ---- a/phc2sys.8 -+++ b/phc2sys.8 -@@ -116,7 +116,7 @@ option. - Specify which clock servo should be used. Valid values are pi for a PI - controller, linreg for an adaptive controller using linear regression, and - ntpshm for the NTP SHM reference clock to allow another process to synchronize --the local clock (the SHM segment number is set to the domain number). -+the local clock. - The default is pi. - .TP - .BI \-P " kp" -@@ -166,6 +166,10 @@ the synchronized clock. When a larger offset is measured, a warning message - will be printed and the servo will be reset. When set to 0, the sanity check is - disabled. The default is 200000000 (20%). - .TP -+.BI \-M " segment" -+The number of the SHM segment used by ntpshm servo. -+The default is 0. -+.TP - .BI \-u " summary-updates" - Specify the number of clock updates included in summary statistics. The - statistics include offset root mean square (RMS), maximum absolute offset, -diff --git a/phc2sys.c b/phc2sys.c -index 391ae62..22eb9c9 100644 ---- a/phc2sys.c -+++ b/phc2sys.c -@@ -1159,6 +1159,7 @@ static void usage(char *progname) - " -R [rate] slave clock update rate in HZ (1.0)\n" - " -N [num] number of master clock readings per update (5)\n" - " -L [limit] sanity frequency limit in ppb (200000000)\n" -+ " -M [num] NTP SHM segment number (0)\n" - " -u [num] number of clock updates in summary stats (0)\n" - " -n [num] domain number (0)\n" - " -x apply leap seconds by servo instead of kernel\n" -@@ -1199,7 +1200,7 @@ int main(int argc, char *argv[]) - progname = strrchr(argv[0], '/'); - progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, -- "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xz:l:mqvh"))) { -+ "arc:d:s:E:P:I:S:F:R:N:O:L:M:i:u:wn:xz:l:mqvh"))) { - switch (c) { - case 'a': - autocfg = 1; -@@ -1276,6 +1277,10 @@ int main(int argc, char *argv[]) - if (get_arg_val_i(c, optarg, &node.sanity_freq_limit, 0, INT_MAX)) - return -1; - break; -+ case 'M': -+ if (get_arg_val_i(c, optarg, &ntpshm_segment, INT_MIN, INT_MAX)) -+ return -1; -+ break; - case 'u': - if (get_arg_val_ui(c, optarg, &node.stats_max_count, - 0, UINT_MAX)) -@@ -1287,7 +1292,6 @@ int main(int argc, char *argv[]) - case 'n': - if (get_arg_val_i(c, optarg, &domain_number, 0, 255)) - return -1; -- ntpshm_segment = domain_number; - break; - case 'x': - node.kernel_leap = 0; -diff --git a/ptp4l.8 b/ptp4l.8 -index 1bae78c..687beb6 100644 ---- a/ptp4l.8 -+++ b/ptp4l.8 -@@ -376,6 +376,10 @@ the synchronized clock. When a larger offset is measured, a warning message - will be printed and the servo will be reset. When set to 0, the sanity check is - disabled. The default is 200000000 (20%). - .TP -+.B ntpshm_segment -+The number of the SHM segment used by ntpshm servo. -+The default is 0. -+.TP - .B ptp_dst_mac - The MAC address where should be PTP messages sent. - Relevant only with L2 transport. The default is 01:1B:19:00:00:00. diff --git a/SOURCES/linuxptp-swtscheck.patch b/SOURCES/linuxptp-swtscheck.patch new file mode 100644 index 0000000..e448dbd --- /dev/null +++ b/SOURCES/linuxptp-swtscheck.patch @@ -0,0 +1,50 @@ +commit 117ed5c2d0f865894dd930d877f0ec28bc23d951 +Author: Miroslav Lichvar +Date: Tue Jan 17 14:17:41 2017 +0100 + + timemaster: check support for SW time stamping. + + When an interface doesn't support HW time stamping, before falling back + to SW time stamping, check if it's actually supported and exit with an + error message if not. + + Signed-off-by: Miroslav Lichvar + +diff --git a/timemaster.c b/timemaster.c +index 880b2ab..cda2d90 100644 +--- a/timemaster.c ++++ b/timemaster.c +@@ -674,13 +674,15 @@ static int add_ptp_source(struct ptp_domain *source, + { + struct config_file *config_file; + char **command, *uds_path, **interfaces, *message_tag; +- int i, j, num_interfaces, *phc, *phcs, hw_ts; ++ int i, j, num_interfaces, *phc, *phcs, hw_ts, sw_ts; + struct sk_ts_info ts_info; + + pr_debug("adding PTP domain %d", source->domain); + + hw_ts = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; ++ sw_ts = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE | ++ SOF_TIMESTAMPING_SOFTWARE; + + for (num_interfaces = 0; + source->interfaces[num_interfaces]; num_interfaces++) +@@ -702,9 +704,14 @@ static int add_ptp_source(struct ptp_domain *source, + return 1; + } + +- if (!ts_info.valid || +- ((ts_info.so_timestamping & hw_ts) != hw_ts)) { ++ if (((ts_info.so_timestamping & hw_ts) != hw_ts)) { + pr_debug("interface %s: no PHC", source->interfaces[i]); ++ if ((ts_info.so_timestamping & sw_ts) != sw_ts) { ++ pr_err("time stamping not supported on %s", ++ source->interfaces[i]); ++ free(phcs); ++ return 1; ++ } + continue; + } + diff --git a/SOURCES/linuxptp-timemaster.patch b/SOURCES/linuxptp-timemaster.patch deleted file mode 100644 index ee23915..0000000 --- a/SOURCES/linuxptp-timemaster.patch +++ /dev/null @@ -1,1887 +0,0 @@ -commit 48046e593efc9583335632f25805153cc2ca8114 -Author: Miroslav Lichvar -Date: Fri Oct 3 14:13:50 2014 +0200 - - Don't include config.h in util.h - - The config module is used by ptp4l only, but util is shared with other - programs. - - Signed-off-by: Miroslav Lichvar - -diff --git a/config.h b/config.h -index 9b74f12..d580496 100644 ---- a/config.h -+++ b/config.h -@@ -51,14 +51,6 @@ struct interface { - #define CFG_IGNORE_USE_SYSLOG (1 << 5) - #define CFG_IGNORE_VERBOSE (1 << 6) - --enum parser_result { -- PARSED_OK, -- NOT_PARSED, -- BAD_VALUE, -- MALFORMED, -- OUT_OF_RANGE, --}; -- - struct config { - /* configuration override */ - int cfg_ignore; -diff --git a/phc_ctl.c b/phc_ctl.c -index dc9c29c..461f2ac 100644 ---- a/phc_ctl.c -+++ b/phc_ctl.c -@@ -43,6 +43,7 @@ - #include "missing.h" - #include "phc.h" - #include "print.h" -+#include "sk.h" - #include "sysoff.h" - #include "util.h" - #include "version.h" -diff --git a/util.h b/util.h -index cf05e49..bb29e11 100644 ---- a/util.h -+++ b/util.h -@@ -20,7 +20,6 @@ - #ifndef HAVE_UTIL_H - #define HAVE_UTIL_H - --#include "config.h" - #include "ddt.h" - - /** -@@ -126,6 +125,17 @@ int is_utc_ambiguous(uint64_t ts); - int leap_second_status(uint64_t ts, int leap_set, int *leap, int *utc_offset); - - /** -+ * Values returned by get_ranged_*(). -+ */ -+enum parser_result { -+ PARSED_OK, -+ NOT_PARSED, -+ BAD_VALUE, -+ MALFORMED, -+ OUT_OF_RANGE, -+}; -+ -+/** - * Get an integer value from string with error checking and range - * specification. - * - -commit 2098d7c1626e934e50da24ef4c5810a5b69064b4 -Author: Miroslav Lichvar -Date: Fri Oct 3 14:13:51 2014 +0200 - - Add string and pointer array utility functions. - - Add some functions to work with strings and arrays of pointers that will - be useful later. - - Signed-off-by: Miroslav Lichvar - -diff --git a/incdefs.sh b/incdefs.sh -index cf00eaf..5bbdcea 100755 ---- a/incdefs.sh -+++ b/incdefs.sh -@@ -23,12 +23,15 @@ - # - user_flags() - { -+ # Needed for vasprintf(). -+ printf " -D_GNU_SOURCE" -+ - dirs=$(echo "" | ${CROSS_COMPILE}cpp -Wp,-v 2>&1 >/dev/null | grep ^" /") - for d in $dirs; do - files=$(find $d -type f -name time.h) - for f in $files; do - if grep -q clock_adjtime $f; then -- printf " -D_GNU_SOURCE -DHAVE_CLOCK_ADJTIME" -+ printf " -DHAVE_CLOCK_ADJTIME" - return - fi - done -diff --git a/util.c b/util.c -index cb428b1..06c3296 100644 ---- a/util.c -+++ b/util.c -@@ -18,6 +18,7 @@ - */ - #include - #include -+#include - #include - #include - #include -@@ -342,3 +343,97 @@ int is_running(void) - { - return running; - } -+ -+char *string_newf(const char *format, ...) -+{ -+ va_list ap; -+ char *s; -+ -+ va_start(ap, format); -+ if (vasprintf(&s, format, ap) < 0) -+ s = NULL; -+ va_end(ap); -+ -+ return s; -+} -+ -+void string_append(char **s, const char *str) -+{ -+ size_t len1, len2; -+ -+ len1 = strlen(*s); -+ len2 = strlen(str); -+ *s = realloc(*s, len1 + len2 + 1); -+ if (*s) -+ memcpy((*s) + len1, str, len2 + 1); -+} -+ -+void string_appendf(char **s, const char *format, ...) -+{ -+ va_list ap; -+ size_t len1, len2; -+ char *s2; -+ -+ len1 = strlen(*s); -+ -+ va_start(ap, format); -+ len2 = vasprintf(&s2, format, ap); -+ va_end(ap); -+ -+ if (len2 < 0) { -+ *s = NULL; -+ return; -+ } -+ -+ *s = realloc(*s, len1 + len2 + 1); -+ if (*s) -+ memcpy((*s) + len1, s2, len2 + 1); -+ free(s2); -+} -+ -+void **parray_new(void) -+{ -+ void **a = malloc(sizeof(*a)); -+ -+ if (a) -+ *a = NULL; -+ return a; -+} -+ -+void parray_append(void ***a, void *p) -+{ -+ parray_extend(a, p, NULL); -+} -+ -+void parray_extend(void ***a, ...) -+{ -+ va_list ap; -+ int ilen, len, alloced; -+ void *p; -+ -+ for (len = 0; (*a)[len]; len++) -+ ; -+ len++; -+ -+ va_start(ap, a); -+ for (ilen = 0; va_arg(ap, void *); ilen++) -+ ; -+ va_end(ap); -+ -+ /* Reallocate in exponentially increasing sizes. */ -+ for (alloced = 1; alloced < len; alloced <<= 1) -+ ; -+ if (alloced < len + ilen) { -+ while (alloced < len + ilen) -+ alloced *= 2; -+ *a = realloc(*a, alloced * sizeof **a); -+ if (!*a) -+ return; -+ } -+ -+ va_start(ap, a); -+ while ((p = va_arg(ap, void *))) -+ (*a)[len++ - 1] = p; -+ va_end(ap); -+ (*a)[len - 1] = NULL; -+} -diff --git a/util.h b/util.h -index bb29e11..98b395b 100644 ---- a/util.h -+++ b/util.h -@@ -236,4 +236,61 @@ int handle_term_signals(void); - */ - int is_running(void); - -+/** -+ * Get an allocated and formatted string. This is a wrapper around asprintf(). -+ * -+ * @param format printf() format string. -+ * @param ... printf() arguments. -+ * @return Pointer to the allocated string, NULL on error. -+ */ -+#ifdef __GNUC__ -+__attribute__ ((format (printf, 1, 2))) -+#endif -+char *string_newf(const char *format, ...); -+ -+/** -+ * Reallocate a string and append another string to it. -+ * -+ * @param s String that should be extended, set to NULL on error. -+ * @param str String appended to s. -+ */ -+void string_append(char **s, const char *str); -+#ifdef __GNUC__ -+__attribute__ ((format (printf, 2, 3))) -+#endif -+/** -+ * Reallocate a string and append a formatted string to it. -+ * -+ * @param s String that should be extended, set to NULL on error. -+ * @param format printf() format string. -+ * @param ... printf() arguments. -+ */ -+void string_appendf(char **s, const char *format, ...); -+ -+/** -+ * Get an empty array of pointers terminated by NULL. -+ * -+ * @return Pointer to the allocated array, NULL on error. -+ */ -+void **parray_new(void); -+ -+/** -+ * Append pointer to a NULL-terminated pointer array. The array is reallocated -+ * in exponentially increasing sizes. -+ * -+ * @param a Pointer to pointer array, set to NULL on error. -+ * @param p Pointer appended to the array. -+ */ -+void parray_append(void ***a, void *p); -+ -+ -+/** -+ * Append pointers to a NULL-terminated pointer array. The array is reallocated -+ * in exponentially increasing sizes. -+ * -+ * @param a Pointer to pointer array, set to NULL on error. -+ * @param ... NULL-terminated list of pointers. -+ */ -+void parray_extend(void ***a, ...); -+ - #endif - -commit 82f13c594a8860274e62bc999520b8a434a80a53 -Author: Miroslav Lichvar -Date: Fri Oct 3 14:13:52 2014 +0200 - - Add timemaster. - - timemaster is a program that uses ptp4l and phc2sys in combination with - chronyd or ntpd to synchronize the system clock to NTP and PTP time - sources. The PTP time is provided by phc2sys and ptp4l via SHM reference - clocks to chronyd/ntpd, which can compare all time sources and use the - best sources to synchronize the system clock. - - Signed-off-by: Miroslav Lichvar - -diff --git a/incdefs.sh b/incdefs.sh -index 5bbdcea..34e227f 100755 ---- a/incdefs.sh -+++ b/incdefs.sh -@@ -19,20 +19,34 @@ - # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - # --# Look for the clock_adjtime functional prototype in the C library. -+# Look for functional prototypes in the C library. - # - user_flags() - { - # Needed for vasprintf(). - printf " -D_GNU_SOURCE" - -+ # Get list of directories searched for header files. - dirs=$(echo "" | ${CROSS_COMPILE}cpp -Wp,-v 2>&1 >/dev/null | grep ^" /") -+ -+ # Look for clock_adjtime(). - for d in $dirs; do - files=$(find $d -type f -name time.h) - for f in $files; do - if grep -q clock_adjtime $f; then - printf " -DHAVE_CLOCK_ADJTIME" -- return -+ break 2 -+ fi -+ done -+ done -+ -+ # Look for posix_spawn(). -+ for d in $dirs; do -+ files=$(find $d -type f -name spawn.h) -+ for f in $files; do -+ if grep -q posix_spawn $f; then -+ printf " -DHAVE_POSIX_SPAWN" -+ break 2 - fi - done - done -diff --git a/makefile b/makefile -index 74a7fe2..5469301 100644 ---- a/makefile -+++ b/makefile -@@ -22,13 +22,14 @@ CC = $(CROSS_COMPILE)gcc - VER = -DVER=$(version) - CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS) - LDLIBS = -lm -lrt $(EXTRA_LDFLAGS) --PRG = ptp4l pmc phc2sys hwstamp_ctl phc_ctl -+PRG = ptp4l pmc phc2sys hwstamp_ctl phc_ctl timemaster - OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o fault.o \ - filter.o fsm.o linreg.o mave.o mmedian.o msg.o ntpshm.o phc.o \ - pi.o port.o print.o ptp4l.o raw.o servo.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 phc_ctl.o -+OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o phc_ctl.o pmc.o pmc_common.o \ -+ sysoff.o timemaster.o - SRC = $(OBJECTS:.o=.c) - DEPEND = $(OBJECTS:.o=.d) - srcdir := $(dir $(lastword $(MAKEFILE_LIST))) -@@ -56,6 +57,8 @@ hwstamp_ctl: hwstamp_ctl.o version.o - - phc_ctl: phc_ctl.o phc.o sk.o util.o clockadj.o sysoff.o print.o version.o - -+timemaster: print.o sk.o timemaster.o util.o version.o -+ - version.o: .version version.sh $(filter-out version.d,$(DEPEND)) - - .version: force -diff --git a/timemaster.8 b/timemaster.8 -new file mode 100644 -index 0000000..9a3ddb4 ---- /dev/null -+++ b/timemaster.8 -@@ -0,0 +1,335 @@ -+.TH TIMEMASTER 8 "October 2014" "linuxptp" -+.SH NAME -+ -+timemaster \- run NTP with PTP as reference clocks -+ -+.SH SYNOPSIS -+ -+.B timemaster -+[ -+.B \-nmqv -+] [ -+.BI \-l " print-level" -+] -+.BI \-f " file" -+ -+.SH DESCRIPTION -+\fBtimemaster\fR is a program that uses \fBptp4l\fR and \fBphc2sys\fR in -+combination with \fBchronyd\fR or \fBntpd\fR to synchronize the system clock to -+NTP and PTP time sources. The PTP time is provided by \fBphc2sys\fR and -+\fBptp4l\fR via SHM reference clocks to \fBchronyd\fR/\fBntpd\fR, which -+can compare all time sources and use the best sources to synchronize the system -+clock. -+ -+On start, \fBtimemaster\fR reads a configuration file that specifies the NTP -+and PTP time sources, checks which network interfaces have and share a PTP -+hardware clock (PHC), generates configuration files for \fBptp4l\fR and -+\fBchronyd\fR/\fBntpd\fR, and start the \fBptp4l\fR, \fBphc2sys\fR, -+\fBchronyd\fR/\fBntpd\fR processes as needed. Then, it waits for a signal to -+kill the processes, remove the generated configuration files and exit. -+ -+.SH OPTIONS -+ -+.TP -+.BI \-f " file" -+Specify the path to the \fBtimemaster\fR configuration file. -+.TP -+.BI \-n -+Don't start the programs, only print their configuration files and the commands -+that would be executed if this option wasn't specified. -+.TP -+.BI \-l " level" -+Set the maximum syslog level of messages which should be printed or sent to -+the system logger. The default value is 6 (LOG_INFO). -+.TP -+.B \-m -+Print messages to the standard output. -+.TP -+.B \-q -+Don't send messages to the system logger. -+.TP -+.B \-v -+Print the software version and exit. -+.TP -+.BI \-h -+Display a help message and exit. -+ -+.SH CONFIGURATION FILE -+ -+The configuration file is divided into sections. Each section starts with a -+line containing its name enclosed in brackets and it follows with settings. -+Each setting is placed on a separate line, it contains the name of the -+option and the value separated by whitespace characters. Empty lines and lines -+starting with # are ignored. -+ -+Sections that can used in the configuration file and options that can be set in -+them are described below. -+ -+.SS [timemaster] -+ -+.TP -+.B ntp_program -+Select which NTP implementation should be used. Possible values are -+\fBchronyd\fR and \fBntpd\fR. The default value is \fBchronyd\fR. Limitations -+of the implementations relevant to the timemaster configuration are listed in -+\fBNOTES\fR. -+ -+.TP -+.B rundir -+Specify the directory where should be generated \fBchronyd\fR, \fBntpd\fR and -+\fBptp4l\fR configuration files and sockets. The directory will be created if -+it doesn't exist. The default value is \fB/var/run/timemaster\fR. -+ -+.SS [ntp_server address] -+ -+The \fBntp_server\fR section specifies an NTP server that should be used as a -+time source. The address of the server is included in the name of the section. -+ -+.TP -+.B minpoll -+.TQ -+.B maxpoll -+Specify the minimum and maximum NTP polling interval as powers of two in -+seconds. The default values are 6 (64 seconds) and 10 (1024 seconds) -+respectively. Shorter polling intervals usually improve the accuracy -+significantly, but they should be used only when allowed by the operators of -+the NTP service (public NTP servers generally don't allow too frequent -+queries). If the NTP server is located on the same LAN, polling intervals -+around 4 (16 seconds) might give best accuracy. -+ -+.TP -+.B iburst -+Enable or disable sending a burst of NTP packets on start to speed up the -+initial synchronization. Possible values are 1 and 0. The default value is 0 -+(disabled). -+ -+.SS [ptp_domain number] -+ -+The \fBptp_domain\fR section specifies a PTP domain that should be used as a -+time source. The PTP domain number is included in the name of the section. The -+\fBptp4l\fR instances are configured to run in the \fBslaveOnly\fR mode. In -+this section at least the \fBinterfaces\fR option needs to be set, other -+options are optional. -+ -+.TP -+.B interfaces -+Specify which network interfaces should be used for this PTP domain. A separate -+\fBptp4l\fR instance will be started for each group of interfaces sharing the -+same PHC and for each interface that supports only SW time stamping. HW time -+stamping is enabled automatically. If an interface with HW time stamping is -+specified also in other PTP domains, only the \fBptp4l\fR instance from the -+first PTP domain will be using HW time stamping. -+ -+.TP -+.B ntp_poll -+Specify the polling interval of the NTP SHM reference clock reading samples -+from \fBptp4l\fR or \fBphc2sys\fR. It's specified as a power of two in seconds. -+The default value is 2 (4 seconds). -+ -+.TP -+.B phc2sys_poll -+Specify the polling interval used by \fBphc2sys\fR to read a PTP clock -+synchronized by \fBptp4l\fR and update the SHM sample for -+\fBchronyd\fR/\fBntpd\fR. It's specified as a power of two in seconds. The -+default value is 0 (1 second). -+ -+.TP -+.B delay -+Specify the maximum assumed roundtrip delay to the primary source of the time -+in this PTP domain. This value is included in the distance used by -+\fBchronyd\fR in the source selection algorithm to detect falsetickers and -+assign weights for source combining. The default value is 1e-4 (100 -+microseconds). With \fBntpd\fR, the \fBtos mindist\fR command can be used to -+set a limit with similar purpose globally for all time sources. -+ -+.TP -+.B ptp4l_option -+Specify an extra \fBptp4l\fR option specific to this PTP domain that should be -+added to the configuration files generated for \fBptp4l\fR. This option may be -+used multiple times in one \fBptp_domain\fR section. -+ -+.SS [chronyd] -+ -+.TP -+.B path -+Specify the path to the \fBchronyd\fR binary. The default value is -+\fBchronyd\fR to search for the binary in \fBPATH\fR. -+ -+.TP -+.B options -+Specify extra options that should be added to the \fBchronyd\fR command line. -+No extra options are added by default. -+ -+.SS [chrony.conf] -+ -+Settings specified in this section are copied directly to the configuration -+file generated for \fBchronyd\fR. If this section is not present in the -+\fBtimemaster\fR configuration file, the following setting will be added: -+ -+.EX -+makestep 1 3 -+.EE -+ -+This configures \fBchronyd\fR to step the system clock in the first three -+updates if the offset is larger than 1 second. -+ -+.SS [ntpd] -+ -+.TP -+.B path -+Specify the path to the \fBntpd\fR binary. The default value is \fBntpd\fR to -+search for the binary in \fBPATH\fR. -+ -+.TP -+.B options -+Specify extra options that should be added to the \fBntpd\fR command line. No -+extra options are added by default. -+ -+.SS [ntp.conf] -+ -+Settings specified in this section are copied directly to the configuration -+file generated for \fBntpd\fR. If this section is not present in the -+\fBtimemaster\fR configuration file, the following settings will be added: -+ -+.EX -+restrict default nomodify notrap nopeer noquery -+restrict 127.0.0.1 -+restrict ::1 -+.EE -+ -+This configures \fBntpd\fR to use safe default restrictions. -+ -+.SS [phc2sys] -+ -+.TP -+.B path -+Specify the path to the \fBphc2sys\fR binary. The default value is -+\fBphc2sys\fR to search for the binary in \fBPATH\fR. -+ -+.TP -+.B options -+Specify extra options that should be added to all \fBphc2sys\fR command lines. -+By default, \fB-l 5\fR is added to the command lines. -+ -+.SS [ptp4l] -+ -+.TP -+.B path -+Specify the path to the \fBptp4l\fR binary. The default value is \fBptp4l\fR to -+search for the binary in \fBPATH\fR. -+ -+.TP -+.B options -+Specify extra options that should be added to all \fBptp4l\fR command lines. By -+default, \fB-l 5\fR is added to the command lines. -+ -+.SS [ptp4l.conf] -+Settings specified in this section are copied directly to the configuration -+files generated for all \fBptp4l\fR instances. There is no default content of -+this section. -+ -+.SH NOTES -+For best accuracy, \fBchronyd\fR is usually preferred over \fBntpd\fR, it also -+synchronizes the system clock faster. Both NTP implementations, however, have -+some limitations that need to be considered before choosing the one to be used -+in a given \fBtimemaster\fR configuration. -+ -+The \fBchronyd\fR limitations are: -+ -+.RS -+In version 1.31 and older, the maximum number of reference clocks used at the -+same time is 8. This limits the number of PHCs and interfaces using SW time -+stamping that can be used for PTP. -+ -+Using polling intervals (\fBminpoll\fR, \fBmaxpoll\fR, \fBntp_poll\fR options) -+shorter than 2 (4 seconds) is not recommended with versions before 1.30. With -+1.30 and later values of 0 or 1 can be used for NTP sources and negative values -+for PTP sources (\fBntp_poll\fR) to specify a subsecond interval. -+.RE -+ -+The \fBntpd\fR limitations are: -+ -+.RS -+Only the first two shared-memory segments created by the SHM refclock driver -+in \fBntpd\fR have owner-only access. Other segments are created with world -+access, possibly allowing any user on the system writing to the segments and -+disrupting the synchronization. -+ -+The shortest polling interval for all sources is 3 (8 seconds). -+ -+Nanosecond resolution in the SHM refclock driver is supported in version -+4.2.7p303 and later, older versions have only microsecond resolution. -+.RE -+ -+.SH EXAMPLES -+ -+A minimal configuration file using one NTP source and two PTP sources would be: -+ -+.EX -+[ntp_server 10.1.1.1] -+ -+[ptp_domain 0] -+interfaces eth0 -+ -+[ptp_domain 1] -+interfaces eth1 -+.EE -+ -+A more complex example using all \fBtimemaster\fR options would be: -+ -+.EX -+[ntp_server 10.1.1.1] -+minpoll 3 -+maxpoll 4 -+iburst 1 -+ -+[ptp_domain 0] -+interfaces eth0 eth1 -+ntp_poll 0 -+phc2sys_poll -2 -+delay 10e-6 -+ptp4l_option clock_servo linreg -+ptp4l_option delay_mechanism P2P -+ -+[timemaster] -+ntp_program chronyd -+rundir /var/run/timemaster -+ -+[chronyd] -+path /usr/sbin/chronyd -+options -+ -+[chrony.conf] -+makestep 1 3 -+logchange 0.5 -+rtcsync -+driftfile /var/lib/chrony/drift -+ -+[ntpd] -+path /usr/sbin/ntpd -+options -u ntp:ntp -+ -+[ntp.conf] -+restrict default nomodify notrap nopeer noquery -+restrict 127.0.0.1 -+restrict ::1 -+driftfile /var/lib/ntp/drift -+ -+[phc2sys] -+path /usr/sbin/phc2sys -+options -l 5 -+ -+[ptp4l] -+path /usr/sbin/ptp4l -+options -+ -+[ptp4l.conf] -+logging_level 5 -+.EE -+ -+.SH SEE ALSO -+ -+.BR chronyd (8), -+.BR ntpd (8), -+.BR phc2sys (8), -+.BR ptp4l (8) -diff --git a/timemaster.c b/timemaster.c -new file mode 100644 -index 0000000..83a5b83 ---- /dev/null -+++ b/timemaster.c -@@ -0,0 +1,1173 @@ -+/** -+ * @file timemaster.c -+ * @brief Program to run NTP with PTP as reference clocks. -+ * @note Copyright (C) 2014 Miroslav Lichvar -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "print.h" -+#include "sk.h" -+#include "util.h" -+#include "version.h" -+ -+#define DEFAULT_RUNDIR "/var/run/timemaster" -+ -+#define DEFAULT_NTP_PROGRAM CHRONYD -+#define DEFAULT_NTP_MINPOLL 6 -+#define DEFAULT_NTP_MAXPOLL 10 -+#define DEFAULT_PTP_DELAY 1e-4 -+#define DEFAULT_PTP_NTP_POLL 2 -+#define DEFAULT_PTP_PHC2SYS_POLL 0 -+ -+#define DEFAULT_CHRONYD_SETTINGS \ -+ "makestep 1 3" -+#define DEFAULT_NTPD_SETTINGS \ -+ "restrict default nomodify notrap nopeer noquery", \ -+ "restrict 127.0.0.1", \ -+ "restrict ::1" -+#define DEFAULT_PTP4L_OPTIONS "-l", "5" -+#define DEFAULT_PHC2SYS_OPTIONS "-l", "5" -+ -+enum source_type { -+ NTP_SERVER, -+ PTP_DOMAIN, -+}; -+ -+enum ntp_program { -+ CHRONYD, -+ NTPD, -+}; -+ -+struct ntp_server { -+ char *address; -+ int minpoll; -+ int maxpoll; -+ int iburst; -+}; -+ -+struct ptp_domain { -+ int domain; -+ int ntp_poll; -+ int phc2sys_poll; -+ double delay; -+ char **interfaces; -+ char **ptp4l_settings; -+}; -+ -+struct source { -+ enum source_type type; -+ union { -+ struct ntp_server ntp; -+ struct ptp_domain ptp; -+ }; -+}; -+ -+struct program_config { -+ char *path; -+ char **options; -+ char **settings; -+}; -+ -+struct timemaster_config { -+ struct source **sources; -+ enum ntp_program ntp_program; -+ char *rundir; -+ struct program_config chronyd; -+ struct program_config ntpd; -+ struct program_config phc2sys; -+ struct program_config ptp4l; -+}; -+ -+struct config_file { -+ char *path; -+ char *content; -+}; -+ -+struct script { -+ struct config_file **configs; -+ char ***commands; -+}; -+ -+static void free_parray(void **a) -+{ -+ void **p; -+ -+ for (p = a; *p; p++) -+ free(*p); -+ free(a); -+} -+ -+static void extend_string_array(char ***a, char **strings) -+{ -+ char **s; -+ -+ for (s = strings; *s; s++) -+ parray_append((void ***)a, strdup(*s)); -+} -+ -+static void extend_config_string(char **s, char **lines) -+{ -+ for (; *lines; lines++) -+ string_appendf(s, "%s\n", *lines); -+} -+ -+static int parse_bool(char *s, int *b) -+{ -+ if (get_ranged_int(s, b, 0, 1) != PARSED_OK) -+ return 1; -+ -+ return 0; -+} -+ -+static int parse_int(char *s, int *i) -+{ -+ if (get_ranged_int(s, i, INT_MIN, INT_MAX) != PARSED_OK) -+ return 1; -+ -+ return 0; -+} -+ -+static int parse_double(char *s, double *d) -+{ -+ if (get_ranged_double(s, d, INT_MIN, INT_MAX) != PARSED_OK) -+ return 1; -+ -+ return 0; -+} -+ -+static char *parse_word(char *s) -+{ -+ while (*s && !isspace(*s)) -+ s++; -+ while (*s && isspace(*s)) -+ *(s++) = '\0'; -+ return s; -+} -+ -+static void parse_words(char *s, char ***a) -+{ -+ char *w; -+ -+ if (**a) { -+ free_parray((void **)(*a)); -+ *a = (char **)parray_new(); -+ } -+ while (*s) { -+ w = s; -+ s = parse_word(s); -+ parray_append((void ***)a, strdup(w)); -+ } -+} -+ -+static void replace_string(char *s, char **str) -+{ -+ if (*str) -+ free(*str); -+ *str = strdup(s); -+} -+ -+static char *parse_section_name(char *s) -+{ -+ char *s1, *s2; -+ -+ s1 = s + 1; -+ for (s2 = s1; *s2 && *s2 != ']'; s2++) -+ ; -+ *s2 = '\0'; -+ -+ return strdup(s1); -+} -+ -+static void parse_setting(char *s, char **name, char **value) -+{ -+ *name = s; -+ for (*value = s; **value && !isspace(**value); (*value)++) -+ ; -+ for (; **value && !isspace(**value); (*value)++) -+ ; -+ for (; **value && isspace(**value); (*value)++) -+ **value = '\0'; -+} -+ -+static void source_destroy(struct source *source) -+{ -+ switch (source->type) { -+ case NTP_SERVER: -+ free(source->ntp.address); -+ break; -+ case PTP_DOMAIN: -+ free_parray((void **)source->ptp.interfaces); -+ free_parray((void **)source->ptp.ptp4l_settings); -+ break; -+ } -+ free(source); -+} -+ -+static struct source *source_ntp_parse(char *parameter, char **settings) -+{ -+ char *name, *value; -+ struct ntp_server ntp_server; -+ struct source *source; -+ int r = 0; -+ -+ if (!*parameter) { -+ pr_err("missing address for ntp_server"); -+ return NULL; -+ } -+ -+ ntp_server.address = parameter; -+ ntp_server.minpoll = DEFAULT_NTP_MINPOLL; -+ ntp_server.maxpoll = DEFAULT_NTP_MAXPOLL; -+ ntp_server.iburst = 0; -+ -+ for (; *settings; settings++) { -+ parse_setting(*settings, &name, &value); -+ if (!strcasecmp(name, "minpoll")) { -+ r = parse_int(value, &ntp_server.minpoll); -+ } else if (!strcasecmp(name, "maxpoll")) { -+ r = parse_int(value, &ntp_server.maxpoll); -+ } else if (!strcasecmp(name, "iburst")) { -+ r = parse_bool(value, &ntp_server.iburst); -+ } else { -+ pr_err("unknown ntp_server setting %s", name); -+ return NULL; -+ } -+ if (r) { -+ pr_err("invalid value %s for %s", value, name); -+ return NULL; -+ } -+ } -+ -+ source = malloc(sizeof(*source)); -+ source->type = NTP_SERVER; -+ source->ntp = ntp_server; -+ source->ntp.address = strdup(source->ntp.address); -+ -+ return source; -+} -+ -+static struct source *source_ptp_parse(char *parameter, char **settings) -+{ -+ char *name, *value; -+ struct source *source; -+ int r = 0; -+ -+ source = malloc(sizeof(*source)); -+ source->type = PTP_DOMAIN; -+ source->ptp.delay = DEFAULT_PTP_DELAY; -+ source->ptp.ntp_poll = DEFAULT_PTP_NTP_POLL; -+ source->ptp.phc2sys_poll = DEFAULT_PTP_PHC2SYS_POLL; -+ source->ptp.interfaces = (char **)parray_new(); -+ source->ptp.ptp4l_settings = (char **)parray_new(); -+ -+ if (parse_int(parameter, &source->ptp.domain)) { -+ pr_err("invalid ptp_domain number %s", parameter); -+ goto failed; -+ } -+ -+ for (; *settings; settings++) { -+ parse_setting(*settings, &name, &value); -+ if (!strcasecmp(name, "delay")) { -+ r = parse_double(value, &source->ptp.delay); -+ } else if (!strcasecmp(name, "ntp_poll")) { -+ r = parse_int(value, &source->ptp.ntp_poll); -+ } else if (!strcasecmp(name, "phc2sys_poll")) { -+ r = parse_int(value, &source->ptp.phc2sys_poll); -+ } else if (!strcasecmp(name, "ptp4l_option")) { -+ parray_append((void ***)&source->ptp.ptp4l_settings, -+ strdup(value)); -+ } else if (!strcasecmp(name, "interfaces")) { -+ parse_words(value, &source->ptp.interfaces); -+ } else { -+ pr_err("unknown ptp_domain setting %s", name); -+ goto failed; -+ } -+ -+ if (r) { -+ pr_err("invalid value %s for %s", value, name); -+ goto failed; -+ } -+ } -+ -+ if (!*source->ptp.interfaces) { -+ pr_err("no interfaces specified for ptp_domain %d", -+ source->ptp.domain); -+ goto failed; -+ } -+ -+ return source; -+failed: -+ source_destroy(source); -+ return NULL; -+} -+ -+static int parse_program_settings(char **settings, -+ struct program_config *config) -+{ -+ char *name, *value; -+ -+ for (; *settings; settings++) { -+ parse_setting(*settings, &name, &value); -+ if (!strcasecmp(name, "path")) { -+ replace_string(value, &config->path); -+ } else if (!strcasecmp(name, "options")) { -+ parse_words(value, &config->options); -+ } else { -+ pr_err("unknown program setting %s", name); -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int parse_timemaster_settings(char **settings, -+ struct timemaster_config *config) -+{ -+ char *name, *value; -+ -+ for (; *settings; settings++) { -+ parse_setting(*settings, &name, &value); -+ if (!strcasecmp(name, "ntp_program")) { -+ if (!strcasecmp(value, "chronyd")) { -+ config->ntp_program = CHRONYD; -+ } else if (!strcasecmp(value, "ntpd")) { -+ config->ntp_program = NTPD; -+ } else { -+ pr_err("unknown ntp program %s", value); -+ return 1; -+ } -+ } else if (!strcasecmp(name, "rundir")) { -+ replace_string(value, &config->rundir); -+ } else { -+ pr_err("unknown timemaster setting %s", name); -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int parse_section(char **settings, char *name, -+ struct timemaster_config *config) -+{ -+ struct source *source = NULL; -+ char ***settings_dst = NULL; -+ char *parameter = parse_word(name); -+ -+ if (!strcasecmp(name, "ntp_server")) { -+ source = source_ntp_parse(parameter, settings); -+ if (!source) -+ return 1; -+ } else if (!strcasecmp(name, "ptp_domain")) { -+ source = source_ptp_parse(parameter, settings); -+ if (!source) -+ return 1; -+ } else if (!strcasecmp(name, "chrony.conf")) { -+ settings_dst = &config->chronyd.settings; -+ } else if (!strcasecmp(name, "ntp.conf")) { -+ settings_dst = &config->ntpd.settings; -+ } else if (!strcasecmp(name, "ptp4l.conf")) { -+ settings_dst = &config->ptp4l.settings; -+ } else if (!strcasecmp(name, "chronyd")) { -+ if (parse_program_settings(settings, &config->chronyd)) -+ return 1; -+ } else if (!strcasecmp(name, "ntpd")) { -+ if (parse_program_settings(settings, &config->ntpd)) -+ return 1; -+ } else if (!strcasecmp(name, "phc2sys")) { -+ if (parse_program_settings(settings, &config->phc2sys)) -+ return 1; -+ } else if (!strcasecmp(name, "ptp4l")) { -+ if (parse_program_settings(settings, &config->ptp4l)) -+ return 1; -+ } else if (!strcasecmp(name, "timemaster")) { -+ if (parse_timemaster_settings(settings, config)) -+ return 1; -+ } else { -+ pr_err("unknown section %s", name); -+ return 1; -+ } -+ -+ if (source) -+ parray_append((void ***)&config->sources, source); -+ -+ if (settings_dst) { -+ free_parray((void **)*settings_dst); -+ *settings_dst = (char **)parray_new(); -+ extend_string_array(settings_dst, settings); -+ } -+ -+ return 0; -+} -+ -+static void init_program_config(struct program_config *config, -+ const char *name, ...) -+{ -+ const char *s; -+ va_list ap; -+ -+ config->path = strdup(name); -+ config->settings = (char **)parray_new(); -+ config->options = (char **)parray_new(); -+ -+ va_start(ap, name); -+ -+ /* add default options and settings */ -+ while ((s = va_arg(ap, const char *))) -+ parray_append((void ***)&config->options, strdup(s)); -+ while ((s = va_arg(ap, const char *))) -+ parray_append((void ***)&config->settings, strdup(s)); -+ -+ va_end(ap); -+} -+ -+static void free_program_config(struct program_config *config) -+{ -+ free(config->path); -+ free_parray((void **)config->settings); -+ free_parray((void **)config->options); -+} -+ -+static void config_destroy(struct timemaster_config *config) -+{ -+ struct source **sources; -+ -+ for (sources = config->sources; *sources; sources++) -+ source_destroy(*sources); -+ free(config->sources); -+ -+ free_program_config(&config->chronyd); -+ free_program_config(&config->ntpd); -+ free_program_config(&config->phc2sys); -+ free_program_config(&config->ptp4l); -+ -+ free(config->rundir); -+ free(config); -+} -+ -+static struct timemaster_config *config_parse(char *path) -+{ -+ struct timemaster_config *config = calloc(1, sizeof(*config)); -+ FILE *f; -+ char buf[4096], *line, *section_name = NULL; -+ char **section_lines = NULL; -+ int ret = 0; -+ -+ config->sources = (struct source **)parray_new(); -+ config->ntp_program = DEFAULT_NTP_PROGRAM; -+ config->rundir = strdup(DEFAULT_RUNDIR); -+ -+ init_program_config(&config->chronyd, "chronyd", -+ NULL, DEFAULT_CHRONYD_SETTINGS, NULL); -+ init_program_config(&config->ntpd, "ntpd", -+ NULL, DEFAULT_NTPD_SETTINGS, NULL); -+ init_program_config(&config->phc2sys, "phc2sys", -+ DEFAULT_PHC2SYS_OPTIONS, NULL, NULL); -+ init_program_config(&config->ptp4l, "ptp4l", -+ DEFAULT_PTP4L_OPTIONS, NULL, NULL); -+ -+ f = fopen(path, "r"); -+ if (!f) { -+ pr_err("failed to open %s: %m", path); -+ free(config); -+ return NULL; -+ } -+ -+ while (fgets(buf, sizeof(buf), f)) { -+ /* remove trailing and leading whitespace */ -+ for (line = buf + strlen(buf) - 1; -+ line >= buf && isspace(*line); line--) -+ *line = '\0'; -+ for (line = buf; *line && isspace(*line); line++) -+ ; -+ /* skip comments and empty lines */ -+ if (!*line || *line == '#') -+ continue; -+ -+ if (*line == '[') { -+ /* parse previous section before starting another */ -+ if (section_name) { -+ if (parse_section(section_lines, section_name, -+ config)) { -+ ret = 1; -+ break; -+ } -+ free_parray((void **)section_lines); -+ free(section_name); -+ } -+ section_name = parse_section_name(line); -+ section_lines = (char **)parray_new(); -+ continue; -+ } -+ -+ if (!section_lines) { -+ pr_err("settings outside section"); -+ ret = 1; -+ break; -+ } -+ -+ parray_append((void ***)§ion_lines, strdup(line)); -+ } -+ -+ if (!ret && section_name && -+ parse_section(section_lines, section_name, config)) { -+ ret = 1; -+ } -+ -+ fclose(f); -+ -+ if (section_name) -+ free(section_name); -+ if (section_lines) -+ free_parray((void **)section_lines); -+ -+ if (ret) { -+ config_destroy(config); -+ return NULL; -+ } -+ -+ return config; -+} -+ -+static char **get_ptp4l_command(struct program_config *config, -+ struct config_file *file, char **interfaces, -+ int hw_ts) -+{ -+ char **command = (char **)parray_new(); -+ -+ parray_append((void ***)&command, strdup(config->path)); -+ extend_string_array(&command, config->options); -+ parray_extend((void ***)&command, -+ strdup("-f"), strdup(file->path), -+ strdup(hw_ts ? "-H" : "-S"), NULL); -+ -+ for (; *interfaces; interfaces++) -+ parray_extend((void ***)&command, -+ strdup("-i"), strdup(*interfaces), NULL); -+ -+ return command; -+} -+ -+static char **get_phc2sys_command(struct program_config *config, int domain, -+ int poll, int shm_segment, char *uds_path) -+{ -+ char **command = (char **)parray_new(); -+ -+ parray_append((void ***)&command, strdup(config->path)); -+ extend_string_array(&command, config->options); -+ parray_extend((void ***)&command, -+ strdup("-a"), strdup("-r"), -+ strdup("-R"), string_newf("%.2f", poll > 0 ? -+ 1.0 / (1 << poll) : 1 << -poll), -+ strdup("-z"), strdup(uds_path), -+ strdup("-n"), string_newf("%d", domain), -+ strdup("-E"), strdup("ntpshm"), -+ strdup("-M"), string_newf("%d", shm_segment), NULL); -+ -+ return command; -+} -+ -+static char *get_refid(char *prefix, unsigned int number) -+{ -+ if (number < 10) -+ return string_newf("%.3s%u", prefix, number); -+ else if (number < 100) -+ return string_newf("%.2s%u", prefix, number); -+ else if (number < 1000) -+ return string_newf("%.1s%u", prefix, number); -+ return NULL; -+}; -+ -+static void add_shm_source(int shm_segment, int poll, int dpoll, double delay, -+ char *prefix, struct timemaster_config *config, -+ char **ntp_config) -+{ -+ char *refid = get_refid(prefix, shm_segment); -+ -+ switch (config->ntp_program) { -+ case CHRONYD: -+ string_appendf(ntp_config, -+ "refclock SHM %d poll %d dpoll %d " -+ "refid %s precision 1.0e-9 delay %.1e\n", -+ shm_segment, poll, dpoll, refid, delay); -+ break; -+ case NTPD: -+ string_appendf(ntp_config, -+ "server 127.127.28.%d minpoll %d maxpoll %d\n" -+ "fudge 127.127.28.%d refid %s\n", -+ shm_segment, poll, poll, shm_segment, refid); -+ break; -+ } -+ -+ free(refid); -+} -+ -+static int add_ntp_source(struct ntp_server *source, char **ntp_config) -+{ -+ pr_debug("adding NTP server %s", source->address); -+ -+ string_appendf(ntp_config, "server %s minpoll %d maxpoll %d%s\n", -+ source->address, source->minpoll, source->maxpoll, -+ source->iburst ? " iburst" : ""); -+ return 0; -+} -+ -+static int add_ptp_source(struct ptp_domain *source, -+ struct timemaster_config *config, int *shm_segment, -+ int ***allocated_phcs, char **ntp_config, -+ struct script *script) -+{ -+ struct config_file *config_file; -+ char **command, *uds_path, **interfaces; -+ int i, j, num_interfaces, *phc, *phcs, hw_ts; -+ struct sk_ts_info ts_info; -+ -+ pr_debug("adding PTP domain %d", source->domain); -+ -+ hw_ts = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | -+ SOF_TIMESTAMPING_RAW_HARDWARE; -+ -+ for (num_interfaces = 0; -+ source->interfaces[num_interfaces]; num_interfaces++) -+ ; -+ -+ if (!num_interfaces) -+ return 0; -+ -+ /* get PHCs used by specified interfaces */ -+ phcs = malloc(num_interfaces * sizeof(int)); -+ for (i = 0; i < num_interfaces; i++) { -+ phcs[i] = -1; -+ -+ /* check if the interface has a usable PHC */ -+ if (sk_get_ts_info(source->interfaces[i], &ts_info)) { -+ pr_err("failed to get time stamping info for %s", -+ source->interfaces[i]); -+ free(phcs); -+ return 1; -+ } -+ -+ if (!ts_info.valid || -+ ((ts_info.so_timestamping & hw_ts) != hw_ts)) { -+ pr_debug("interface %s: no PHC", source->interfaces[i]); -+ continue; -+ } -+ -+ pr_debug("interface %s: PHC %d", source->interfaces[i], -+ ts_info.phc_index); -+ -+ /* and the PHC isn't already used in another source */ -+ for (j = 0; (*allocated_phcs)[j]; j++) { -+ if (*(*allocated_phcs)[j] == ts_info.phc_index) { -+ pr_debug("PHC %d already allocated", -+ ts_info.phc_index); -+ break; -+ } -+ } -+ if (!(*allocated_phcs)[j]) -+ phcs[i] = ts_info.phc_index; -+ } -+ -+ for (i = 0; i < num_interfaces; i++) { -+ /* skip if already used by ptp4l in this domain */ -+ if (phcs[i] == -2) -+ continue; -+ -+ interfaces = (char **)parray_new(); -+ parray_append((void ***)&interfaces, source->interfaces[i]); -+ -+ /* merge all interfaces sharing PHC to one ptp4l command */ -+ if (phcs[i] >= 0) { -+ for (j = i + 1; j < num_interfaces; j++) { -+ if (phcs[i] == phcs[j]) { -+ parray_append((void ***)&interfaces, -+ source->interfaces[j]); -+ /* mark the interface as used */ -+ phcs[j] = -2; -+ } -+ } -+ -+ /* don't use this PHC in other sources */ -+ phc = malloc(sizeof(int)); -+ *phc = phcs[i]; -+ parray_append((void ***)allocated_phcs, phc); -+ } -+ -+ uds_path = string_newf("%s/ptp4l.%d.socket", -+ config->rundir, *shm_segment); -+ -+ config_file = malloc(sizeof(*config_file)); -+ config_file->path = string_newf("%s/ptp4l.%d.conf", -+ config->rundir, *shm_segment); -+ config_file->content = strdup("[global]\n"); -+ extend_config_string(&config_file->content, -+ config->ptp4l.settings); -+ extend_config_string(&config_file->content, -+ source->ptp4l_settings); -+ string_appendf(&config_file->content, -+ "slaveOnly 1\n" -+ "domainNumber %d\n" -+ "uds_address %s\n", -+ source->domain, uds_path); -+ -+ if (phcs[i] >= 0) { -+ /* HW time stamping */ -+ command = get_ptp4l_command(&config->ptp4l, config_file, -+ interfaces, 1); -+ parray_append((void ***)&script->commands, command); -+ -+ command = get_phc2sys_command(&config->phc2sys, -+ source->domain, -+ source->phc2sys_poll, -+ *shm_segment, uds_path); -+ parray_append((void ***)&script->commands, command); -+ } else { -+ /* SW time stamping */ -+ command = get_ptp4l_command(&config->ptp4l, config_file, -+ interfaces, 0); -+ parray_append((void ***)&script->commands, command); -+ -+ string_appendf(&config_file->content, -+ "clock_servo ntpshm\n" -+ "ntpshm_segment %d\n", *shm_segment); -+ } -+ -+ parray_append((void ***)&script->configs, config_file); -+ -+ add_shm_source(*shm_segment, source->ntp_poll, -+ source->phc2sys_poll, source->delay, "PTP", -+ config, ntp_config); -+ -+ (*shm_segment)++; -+ -+ free(uds_path); -+ free(interfaces); -+ } -+ -+ free(phcs); -+ -+ return 0; -+} -+ -+static char **get_chronyd_command(struct program_config *config, -+ struct config_file *file) -+{ -+ char **command = (char **)parray_new(); -+ -+ parray_append((void ***)&command, strdup(config->path)); -+ extend_string_array(&command, config->options); -+ parray_extend((void ***)&command, strdup("-n"), -+ strdup("-f"), strdup(file->path), NULL); -+ -+ return command; -+} -+ -+static char **get_ntpd_command(struct program_config *config, -+ struct config_file *file) -+{ -+ char **command = (char **)parray_new(); -+ -+ parray_append((void ***)&command, strdup(config->path)); -+ extend_string_array(&command, config->options); -+ parray_extend((void ***)&command, strdup("-n"), -+ strdup("-c"), strdup(file->path), NULL); -+ -+ return command; -+} -+ -+static struct config_file *add_ntp_program(struct timemaster_config *config, -+ struct script *script) -+{ -+ struct config_file *ntp_config = malloc(sizeof(*ntp_config)); -+ char **command = NULL; -+ -+ ntp_config->content = strdup(""); -+ -+ switch (config->ntp_program) { -+ case CHRONYD: -+ extend_config_string(&ntp_config->content, -+ config->chronyd.settings); -+ ntp_config->path = string_newf("%s/chrony.conf", -+ config->rundir); -+ command = get_chronyd_command(&config->chronyd, ntp_config); -+ break; -+ case NTPD: -+ extend_config_string(&ntp_config->content, -+ config->ntpd.settings); -+ ntp_config->path = string_newf("%s/ntp.conf", config->rundir); -+ command = get_ntpd_command(&config->ntpd, ntp_config); -+ break; -+ } -+ -+ parray_append((void ***)&script->configs, ntp_config); -+ parray_append((void ***)&script->commands, command); -+ -+ return ntp_config; -+} -+ -+static void script_destroy(struct script *script) -+{ -+ char ***commands, **command; -+ struct config_file *config, **configs; -+ -+ for (configs = script->configs; *configs; configs++) { -+ config = *configs; -+ free(config->path); -+ free(config->content); -+ free(config); -+ } -+ free(script->configs); -+ -+ for (commands = script->commands; *commands; commands++) { -+ for (command = *commands; *command; command++) -+ free(*command); -+ free(*commands); -+ } -+ free(script->commands); -+ -+ free(script); -+} -+ -+static struct script *script_create(struct timemaster_config *config) -+{ -+ struct script *script = malloc(sizeof(*script)); -+ struct source *source, **sources; -+ struct config_file *ntp_config = NULL; -+ int **allocated_phcs = (int **)parray_new(); -+ int ret = 0, shm_segment = 0; -+ -+ script->configs = (struct config_file **)parray_new(); -+ script->commands = (char ***)parray_new(); -+ -+ ntp_config = add_ntp_program(config, script); -+ -+ for (sources = config->sources; (source = *sources); sources++) { -+ switch (source->type) { -+ case NTP_SERVER: -+ if (add_ntp_source(&source->ntp, &ntp_config->content)) -+ ret = 1; -+ break; -+ case PTP_DOMAIN: -+ if (add_ptp_source(&source->ptp, config, &shm_segment, -+ &allocated_phcs, -+ &ntp_config->content, script)) -+ ret = 1; -+ break; -+ } -+ } -+ -+ free_parray((void **)allocated_phcs); -+ -+ if (ret) { -+ script_destroy(script); -+ return NULL; -+ } -+ -+ return script; -+} -+ -+static int start_program(char **command, sigset_t *mask) -+{ -+ char **arg, *s; -+ pid_t pid; -+ -+#ifdef HAVE_POSIX_SPAWN -+ posix_spawnattr_t attr; -+ -+ if (posix_spawnattr_init(&attr)) { -+ pr_err("failed to init spawn attributes: %m"); -+ return 1; -+ } -+ -+ if (posix_spawnattr_setsigmask(&attr, mask) || -+ posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) || -+ posix_spawnp(&pid, command[0], NULL, &attr, command, environ)) { -+ pr_err("failed to spawn %s: %m", command[0]); -+ posix_spawnattr_destroy(&attr); -+ return 1; -+ } -+ -+ posix_spawnattr_destroy(&attr); -+#else -+ pid = fork(); -+ -+ if (pid < 0) { -+ pr_err("fork() failed: %m"); -+ return 1; -+ } -+ -+ if (!pid) { -+ /* restore the signal mask */ -+ if (sigprocmask(SIG_SETMASK, mask, NULL) < 0) { -+ pr_err("sigprocmask() failed: %m"); -+ exit(100); -+ } -+ -+ execvp(command[0], (char **)command); -+ -+ pr_err("failed to execute %s: %m", command[0]); -+ -+ exit(101); -+ } -+#endif -+ -+ for (s = strdup(""), arg = command; *arg; arg++) -+ string_appendf(&s, "%s ", *arg); -+ -+ pr_info("process %d started: %s", pid, s); -+ -+ free(s); -+ -+ return 0; -+} -+ -+static int create_config_files(struct config_file **configs) -+{ -+ struct config_file *config; -+ FILE *file; -+ char *tmp, *dir; -+ struct stat st; -+ -+ for (; (config = *configs); configs++) { -+ tmp = strdup(config->path); -+ dir = dirname(tmp); -+ if (stat(dir, &st) < 0 && errno == ENOENT && -+ mkdir(dir, 0755) < 0) { -+ pr_err("failed to create %s: %m", dir); -+ free(tmp); -+ return 1; -+ } -+ free(tmp); -+ -+ pr_debug("creating %s", config->path); -+ -+ file = fopen(config->path, "w"); -+ if (!file) { -+ pr_err("failed to open %s: %m", config->path); -+ return 1; -+ } -+ -+ if (fwrite(config->content, -+ strlen(config->content), 1, file) != 1) { -+ pr_err("failed to write to %s", config->path); -+ fclose(file); -+ return 1; -+ } -+ -+ fclose(file); -+ } -+ -+ return 0; -+} -+ -+static int remove_config_files(struct config_file **configs) -+{ -+ struct config_file *config; -+ -+ for (; (config = *configs); configs++) { -+ pr_debug("removing %s", config->path); -+ -+ if (unlink(config->path)) -+ pr_err("failed to remove %s: %m", config->path); -+ } -+ -+ return 0; -+} -+ -+static int script_run(struct script *script) -+{ -+ sigset_t mask, old_mask; -+ siginfo_t info; -+ pid_t pid; -+ int status, ret = 0; -+ char ***command; -+ -+ if (create_config_files(script->configs)) -+ return 1; -+ -+ sigemptyset(&mask); -+ sigaddset(&mask, SIGCHLD); -+ sigaddset(&mask, SIGTERM); -+ sigaddset(&mask, SIGQUIT); -+ sigaddset(&mask, SIGINT); -+ -+ /* block the signals */ -+ if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { -+ pr_err("sigprocmask() failed: %m"); -+ return 1; -+ } -+ -+ for (command = script->commands; *command; command++) { -+ if (start_program(*command, &old_mask)) { -+ kill(getpid(), SIGTERM); -+ break; -+ } -+ } -+ -+ /* wait for one of the blocked signals */ -+ while (1) { -+ if (sigwaitinfo(&mask, &info) > 0) -+ break; -+ if (errno != EINTR) { -+ pr_err("sigwaitinfo() failed: %m"); -+ break; -+ } -+ } -+ -+ pr_info("received signal %d", info.si_signo); -+ -+ /* kill the process group */ -+ kill(0, SIGTERM); -+ -+ while ((pid = wait(&status)) >= 0) { -+ if (!WIFEXITED(status)) { -+ pr_info("process %d terminated abnormally", pid); -+ ret = 1; -+ } else { -+ if (WEXITSTATUS(status)) -+ ret = 1; -+ pr_info("process %d terminated with status %d", pid, -+ WEXITSTATUS(status)); -+ } -+ } -+ -+ if (remove_config_files(script->configs)) -+ return 1; -+ -+ return ret; -+} -+ -+static void script_print(struct script *script) -+{ -+ char ***commands, **command; -+ struct config_file *config, **configs; -+ -+ for (configs = script->configs; *configs; configs++) { -+ config = *configs; -+ fprintf(stderr, "%s:\n\n%s\n", config->path, config->content); -+ } -+ -+ fprintf(stderr, "commands:\n\n"); -+ for (commands = script->commands; *commands; commands++) { -+ for (command = *commands; *command; command++) -+ fprintf(stderr, "%s ", *command); -+ fprintf(stderr, "\n"); -+ } -+} -+ -+static void usage(char *progname) -+{ -+ fprintf(stderr, -+ "\nusage: %s [options] -f file\n\n" -+ " -f file specify path to configuration file\n" -+ " -n only print generated files and commands\n" -+ " -l level set logging level (6)\n" -+ " -m print messages to stdout\n" -+ " -q do not print messages to syslog\n" -+ " -v print version and exit\n" -+ " -h print this message and exit\n", -+ progname); -+} -+ -+int main(int argc, char **argv) -+{ -+ struct timemaster_config *config; -+ struct script *script; -+ char *progname, *config_path = NULL; -+ int c, ret = 0, log_stdout = 0, log_syslog = 1, dry_run = 0; -+ -+ progname = strrchr(argv[0], '/'); -+ progname = progname ? progname + 1 : argv[0]; -+ -+ print_set_progname(progname); -+ print_set_verbose(1); -+ print_set_syslog(0); -+ -+ while (EOF != (c = getopt(argc, argv, "f:nl:mqvh"))) { -+ switch (c) { -+ case 'f': -+ config_path = optarg; -+ break; -+ case 'n': -+ dry_run = 1; -+ break; -+ case 'l': -+ print_set_level(atoi(optarg)); -+ break; -+ case 'm': -+ log_stdout = 1; -+ break; -+ case 'q': -+ log_syslog = 0; -+ break; -+ case 'v': -+ version_show(stdout); -+ return 0; -+ case 'h': -+ usage(progname); -+ return 0; -+ default: -+ usage(progname); -+ return 1; -+ } -+ } -+ -+ if (!config_path) { -+ pr_err("no configuration file specified"); -+ return 1; -+ } -+ -+ config = config_parse(config_path); -+ if (!config) -+ return 1; -+ -+ script = script_create(config); -+ config_destroy(config); -+ if (!script) -+ return 1; -+ -+ print_set_verbose(log_stdout); -+ print_set_syslog(log_syslog); -+ -+ if (dry_run) -+ script_print(script); -+ else -+ ret = script_run(script); -+ -+ script_destroy(script); -+ -+ if (!dry_run) -+ pr_info("exiting"); -+ -+ return ret; -+} diff --git a/SOURCES/linuxptp-uds.patch b/SOURCES/linuxptp-uds.patch deleted file mode 100644 index e03c944..0000000 --- a/SOURCES/linuxptp-uds.patch +++ /dev/null @@ -1,511 +0,0 @@ -commit 28865f91df96e83b28bb40565f12e62bd86e451f -Author: Miroslav Lichvar -Date: Tue Jul 8 16:14:18 2014 +0200 - - phc2sys: Add option to set path to ptp4l UDS. - - Signed-off-by: Miroslav Lichvar - -diff --git a/phc2sys.8 b/phc2sys.8 -index a906fb3..c4fb6f6 100644 ---- a/phc2sys.8 -+++ b/phc2sys.8 -@@ -194,6 +194,10 @@ clock frequency (unless the - .B \-S - option is used). - .TP -+.BI \-z " uds-address" -+Specifies the address of the server's UNIX domain socket. -+The default is /var/run/ptp4l. -+.TP - .BI \-l " print-level" - Set the maximum syslog level of messages which should be printed or sent to - the system logger. The default is 6 (LOG_INFO). -diff --git a/phc2sys.c b/phc2sys.c -index 7815a8e..418f4ac 100644 ---- a/phc2sys.c -+++ b/phc2sys.c -@@ -53,6 +53,7 @@ - #include "stats.h" - #include "sysoff.h" - #include "tlv.h" -+#include "uds.h" - #include "util.h" - #include "version.h" - -@@ -1158,6 +1159,7 @@ static void usage(char *progname) - " -u [num] number of clock updates in summary stats (0)\n" - " -n [num] domain number (0)\n" - " -x apply leap seconds by servo instead of kernel\n" -+ " -z [path] server address for UDS (/var/run/ptp4l)\n" - " -l [num] set the logging level to 'num' (6)\n" - " -m print messages to stdout\n" - " -q do not print messages to the syslog\n" -@@ -1192,7 +1194,7 @@ int main(int argc, char *argv[]) - progname = strrchr(argv[0], '/'); - progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, -- "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { -+ "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xz:l:mqvh"))) { - switch (c) { - case 'a': - autocfg = 1; -@@ -1285,6 +1287,14 @@ int main(int argc, char *argv[]) - case 'x': - node.kernel_leap = 0; - break; -+ case 'z': -+ if (strlen(optarg) > MAX_IFNAME_SIZE) { -+ fprintf(stderr, "path %s too long, max is %d\n", -+ optarg, MAX_IFNAME_SIZE); -+ return -1; -+ } -+ strncpy(uds_path, optarg, MAX_IFNAME_SIZE); -+ break; - case 'l': - if (get_arg_val_i(c, optarg, &print_level, - PRINT_LEVEL_MIN, PRINT_LEVEL_MAX)) - -commit 2423357754ae7d64d844fc064c72b8d27adf40c4 -Author: Miroslav Lichvar -Date: Tue Jul 8 16:14:19 2014 +0200 - - Remove socket when closing UDS transport. - - [RC: added cast to sockaddr to avoid compiler warning. ] - - Signed-off-by: Miroslav Lichvar - -diff --git a/uds.c b/uds.c -index e98e32c..97edb97 100644 ---- a/uds.c -+++ b/uds.c -@@ -42,6 +42,14 @@ struct uds { - - static int uds_close(struct transport *t, struct fdarray *fda) - { -+ struct sockaddr_un sa; -+ socklen_t len = sizeof(sa); -+ -+ if (!getsockname(fda->fd[FD_GENERAL], (struct sockaddr *) &sa, &len) && -+ sa.sun_family == AF_LOCAL) { -+ unlink(sa.sun_path); -+ } -+ - close(fda->fd[FD_GENERAL]); - return 0; - } - -commit ca637b2067ae78c9830c38bb5e9a659255b1a4a2 -Author: Miroslav Lichvar -Date: Tue Jul 8 16:14:20 2014 +0200 - - Move signal handling to util.c. - - This will be useful in phc2sys and pmc. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ptp4l.c b/ptp4l.c -index 25270c6..5080a79 100644 ---- a/ptp4l.c -+++ b/ptp4l.c -@@ -18,7 +18,6 @@ - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - #include --#include - #include - #include - #include -@@ -40,8 +39,6 @@ - - int assume_two_step = 0; - --static int running = 1; -- - static struct config cfg_settings = { - .dds = { - .dds = { -@@ -131,12 +128,6 @@ static struct config cfg_settings = { - .cfg_ignore = 0, - }; - --static void handle_int_quit_term(int s) --{ -- pr_notice("caught signal %d", s); -- running = 0; --} -- - static void usage(char *progname) - { - fprintf(stderr, -@@ -184,18 +175,8 @@ int main(int argc, char *argv[]) - struct defaultDS *ds = &cfg_settings.dds.dds; - int phc_index = -1, required_modes = 0; - -- if (SIG_ERR == signal(SIGINT, handle_int_quit_term)) { -- fprintf(stderr, "cannot handle SIGINT\n"); -+ if (handle_term_signals()) - return -1; -- } -- if (SIG_ERR == signal(SIGQUIT, handle_int_quit_term)) { -- fprintf(stderr, "cannot handle SIGQUIT\n"); -- return -1; -- } -- if (SIG_ERR == signal(SIGTERM, handle_int_quit_term)) { -- fprintf(stderr, "cannot handle SIGTERM\n"); -- return -1; -- } - - /* Set fault timeouts to a default value */ - for (i = 0; i < FT_CNT; i++) { -@@ -404,7 +385,7 @@ int main(int argc, char *argv[]) - return -1; - } - -- while (running) { -+ while (is_running()) { - if (clock_poll(clock)) - break; - } -diff --git a/util.c b/util.c -index 1e86040..ae66bb1 100644 ---- a/util.c -+++ b/util.c -@@ -17,11 +17,13 @@ - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - #include -+#include - #include - #include - #include - - #include "address.h" -+#include "print.h" - #include "sk.h" - #include "util.h" - -@@ -29,6 +31,8 @@ - #define NS_PER_HOUR (3600 * NS_PER_SEC) - #define NS_PER_DAY (24 * NS_PER_HOUR) - -+static int running = 1; -+ - const char *ps_str[] = { - "NONE", - "INITIALIZING", -@@ -311,3 +315,31 @@ int get_arg_val_d(int op, const char *optarg, double *val, - } - return 0; - } -+ -+static void handle_int_quit_term(int s) -+{ -+ pr_notice("caught signal %d", s); -+ running = 0; -+} -+ -+int handle_term_signals(void) -+{ -+ if (SIG_ERR == signal(SIGINT, handle_int_quit_term)) { -+ fprintf(stderr, "cannot handle SIGINT\n"); -+ return -1; -+ } -+ if (SIG_ERR == signal(SIGQUIT, handle_int_quit_term)) { -+ fprintf(stderr, "cannot handle SIGQUIT\n"); -+ return -1; -+ } -+ if (SIG_ERR == signal(SIGTERM, handle_int_quit_term)) { -+ fprintf(stderr, "cannot handle SIGTERM\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+int is_running(void) -+{ -+ return running; -+} -diff --git a/util.h b/util.h -index 3fae51c..cf05e49 100644 ---- a/util.h -+++ b/util.h -@@ -212,4 +212,18 @@ int get_arg_val_ui(int op, const char *optarg, unsigned int *val, - int get_arg_val_d(int op, const char *optarg, double *val, - double min, double max); - -+/** -+ * Setup a handler for terminating signals (SIGINT, SIGQUIT, SIGTERM). -+ * -+ * @return 0 on success, -1 on error. -+ */ -+int handle_term_signals(void); -+ -+/** -+ * Check if a terminating signal was received. -+ * -+ * @return 1 if no terminating signal was received, 0 otherwise. -+ */ -+int is_running(void); -+ - #endif - -commit 30841a68495b5e9ba11ff4b056c4a79b0b73d14a -Author: Miroslav Lichvar -Date: Tue Jul 8 16:14:21 2014 +0200 - - Close client UDS transport before exit. - - In pmc and phc2sys handle terminating signals and close the UDS - transport before exit to remove the sockets in /var/run. - - Signed-off-by: Miroslav Lichvar - -diff --git a/phc2sys.c b/phc2sys.c -index 418f4ac..3039e51 100644 ---- a/phc2sys.c -+++ b/phc2sys.c -@@ -526,7 +526,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) - enable_pps_output(node->master->clkid); - } - -- while (1) { -+ while (is_running()) { - if (!read_pps(fd, &pps_offset, &pps_ts)) { - continue; - } -@@ -570,7 +570,7 @@ static int do_loop(struct node *node, int subscriptions) - interval.tv_sec = node->phc_interval; - interval.tv_nsec = (node->phc_interval - interval.tv_sec) * 1e9; - -- while (1) { -+ while (is_running()) { - clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL); - if (update_pmc(node, subscriptions) < 0) - continue; -@@ -611,7 +611,7 @@ static int do_loop(struct node *node, int subscriptions) - update_clock(node, clock, offset, ts, delay); - } - } -- return 0; /* unreachable */ -+ return 0; - } - - static int check_clock_identity(struct node *node, struct ptp_message *msg) -@@ -1187,6 +1187,8 @@ int main(int argc, char *argv[]) - .kernel_leap = 1, - }; - -+ handle_term_signals(); -+ - configured_pi_kp = KP; - configured_pi_ki = KI; - -@@ -1349,7 +1351,8 @@ int main(int argc, char *argv[]) - return -1; - if (auto_init_ports(&node, rt) < 0) - return -1; -- return do_loop(&node, 1); -+ r = do_loop(&node, 1); -+ goto end; - } - - src = clock_add(&node, src_name); -@@ -1377,14 +1380,16 @@ int main(int argc, char *argv[]) - goto bad_usage; - } - -+ r = -1; -+ - if (wait_sync) { - if (init_pmc(&node, domain_number)) -- return -1; -+ goto end; - -- while (1) { -+ while (is_running()) { - r = run_pmc_wait_sync(&node, 1000); - if (r < 0) -- return -1; -+ goto end; - if (r > 0) - break; - else -@@ -1395,7 +1400,7 @@ int main(int argc, char *argv[]) - r = run_pmc_get_utc_offset(&node, 1000); - if (r <= 0) { - pr_err("failed to get UTC offset"); -- return -1; -+ goto end; - } - } - -@@ -1409,11 +1414,16 @@ int main(int argc, char *argv[]) - /* only one destination clock allowed with PPS until we - * implement a mean to specify PTP port to PPS mapping */ - servo_sync_interval(dst->servo, 1.0); -- return do_pps_loop(&node, dst, pps_fd); -+ r = do_pps_loop(&node, dst, pps_fd); -+ } else { -+ r = do_loop(&node, 0); - } - -- return do_loop(&node, 0); -+end: -+ if (node.pmc) -+ close_pmc(&node); - -+ return r; - bad_usage: - usage(progname); - return -1; -diff --git a/pmc.c b/pmc.c -index ba06293..8cfae92 100644 ---- a/pmc.c -+++ b/pmc.c -@@ -714,6 +714,7 @@ int main(int argc, char *argv[]) - const char *iface_name = NULL; - char *progname; - int c, cnt, length, tmo = -1, batch_mode = 0, zero_datalen = 0; -+ int ret = 0; - char line[1024], *command = NULL; - enum transport_type transport_type = TRANS_UDP_IPV4; - UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0; -@@ -721,6 +722,8 @@ int main(int argc, char *argv[]) - #define N_FD 2 - struct pollfd pollfd[N_FD]; - -+ handle_term_signals(); -+ - /* Process the command line arguments. */ - progname = strrchr(argv[0], '/'); - progname = progname ? 1+progname : argv[0]; -@@ -798,7 +801,7 @@ int main(int argc, char *argv[]) - pollfd[0].fd = batch_mode ? -1 : STDIN_FILENO; - pollfd[1].fd = pmc_get_transport_fd(pmc); - -- while (1) { -+ while (is_running()) { - if (batch_mode && !command) { - if (optind < argc) { - command = argv[optind++]; -@@ -823,7 +826,8 @@ int main(int argc, char *argv[]) - continue; - } else { - pr_emerg("poll failed"); -- return -1; -+ ret = -1; -+ break; - } - } else if (!cnt) { - break; -@@ -866,5 +870,5 @@ int main(int argc, char *argv[]) - - pmc_destroy(pmc); - msg_cleanup(); -- return 0; -+ return ret; - } - -commit 1773d21f26eb1aa2da0645af116d6ce27591a9cc -Author: Miroslav Lichvar -Date: Tue Jul 8 16:14:22 2014 +0200 - - Append PID to client UDS paths. - - This allows running multiple phc2sys and pmc instances at the same time. - - Signed-off-by: Miroslav Lichvar - -diff --git a/phc2sys.c b/phc2sys.c -index 3039e51..391ae62 100644 ---- a/phc2sys.c -+++ b/phc2sys.c -@@ -738,8 +738,11 @@ static void send_subscription(struct node *node) - - static int init_pmc(struct node *node, int domain_number) - { -- node->pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0, -- domain_number, 0, 1); -+ char uds_local[MAX_IFNAME_SIZE + 1]; -+ -+ snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d", -+ getpid()); -+ node->pmc = pmc_create(TRANS_UDS, uds_local, 0, domain_number, 0, 1); - if (!node->pmc) { - pr_err("failed to create pmc"); - return -1; -diff --git a/pmc.8 b/pmc.8 -index 0d36354..b113c78 100644 ---- a/pmc.8 -+++ b/pmc.8 -@@ -73,7 +73,7 @@ Specify the boundary hops value in sent messages. The default is 1. - Specify the domain number in sent messages. The default is 0. - .TP - .BI \-i " interface" --Specify the network interface. The default is /var/run/pmc for the Unix Domain -+Specify the network interface. The default is /var/run/pmc.$pid for the Unix Domain - Socket transport and eth0 for the other transports. - .TP - .BI \-s " uds-address" -diff --git a/pmc.c b/pmc.c -index 8cfae92..d58e190 100644 ---- a/pmc.c -+++ b/pmc.c -@@ -700,7 +700,7 @@ static void usage(char *progname) - " -d [num] domain number, default 0\n" - " -h prints this message and exits\n" - " -i [dev] interface device to use, default 'eth0'\n" -- " for network and '/var/run/pmc' for UDS.\n" -+ " for network and '/var/run/pmc.$pid' for UDS.\n" - " -s [path] server address for UDS, default '/var/run/ptp4l'.\n" - " -t [hex] transport specific field, default 0x0\n" - " -v prints the software version and exits\n" -@@ -715,7 +715,7 @@ int main(int argc, char *argv[]) - char *progname; - int c, cnt, length, tmo = -1, batch_mode = 0, zero_datalen = 0; - int ret = 0; -- char line[1024], *command = NULL; -+ char line[1024], *command = NULL, uds_local[MAX_IFNAME_SIZE + 1]; - enum transport_type transport_type = TRANS_UDP_IPV4; - UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0; - struct ptp_message *msg; -@@ -781,7 +781,13 @@ int main(int argc, char *argv[]) - } - - if (!iface_name) { -- iface_name = transport_type == TRANS_UDS ? "/var/run/pmc" : "eth0"; -+ if (transport_type == TRANS_UDS) { -+ snprintf(uds_local, sizeof(uds_local), -+ "/var/run/pmc.%d", getpid()); -+ iface_name = uds_local; -+ } else { -+ iface_name = "eth0"; -+ } - } - if (optind < argc) { - batch_mode = 1; -commit aa24ba58e1901f9397624665c1f19a2432e426d0 -Author: Miroslav Lichvar -Date: Fri Oct 3 14:13:49 2014 +0200 - - Don't print messages in signal handler. - - Only reentrant functions should be called here. - - Signed-off-by: Miroslav Lichvar - -diff --git a/util.c b/util.c -index ae66bb1..cb428b1 100644 ---- a/util.c -+++ b/util.c -@@ -318,7 +318,6 @@ int get_arg_val_d(int op, const char *optarg, double *val, - - static void handle_int_quit_term(int s) - { -- pr_notice("caught signal %d", s); - running = 0; - } - diff --git a/SOURCES/linuxptp-utcoffset.patch b/SOURCES/linuxptp-utcoffset.patch new file mode 100644 index 0000000..b54f800 --- /dev/null +++ b/SOURCES/linuxptp-utcoffset.patch @@ -0,0 +1,130 @@ +commit 0309a880fb4389e869ae0ba431d3d17b1ec5a272 +Author: Miroslav Lichvar +Date: Thu Jan 5 10:15:53 2017 +0100 + + Update TAI-UTC offset + + A leap second was applied to UTC on 2016-12-31 and the offset between + TAI and UTC is now 37 seconds. + + Signed-off-by: Miroslav Lichvar + +diff --git a/ds.h b/ds.h +index b36862d..0e48d05 100644 +--- a/ds.h ++++ b/ds.h +@@ -84,7 +84,7 @@ struct parent_ds { + unsigned int path_length; + }; + +-#define CURRENT_UTC_OFFSET 36 /* 1 Jul 2015 */ ++#define CURRENT_UTC_OFFSET 37 /* 1 Jan 2017 */ + #define INTERNAL_OSCILLATOR 0xA0 + + struct timePropertiesDS { +commit 33e62f992542ac5ce6bdbb8ae6c34dec7011b543 +Author: Viliam Lejcik +Date: Tue Jan 17 18:25:26 2017 +0100 + + ptp4l: Make UTC offset configurable. + + Currently UTC offset is defined as a constant - CURRENT_UTC_OFFSET, and if + a leap second is added, that constant is no longer valid. Ptp4l was + updated to read the UTC offset from configuration instead. + + Signed-off-by: Viliam Lejcik + +diff --git a/clock.c b/clock.c +index c716f01..a6a1a1a 100644 +--- a/clock.c ++++ b/clock.c +@@ -105,6 +105,7 @@ struct clock { + int leap_set; + int kernel_leap; + int utc_offset; /* grand master role */ ++ int current_utc_offset; /* UTC offset fallback */ + int time_flags; /* grand master role */ + int time_source; /* grand master role */ + enum servo_state servo_state; +@@ -681,7 +682,7 @@ static void clock_update_slave(struct clock *c) + if (!(c->tds.flags & PTP_TIMESCALE)) { + pr_warning("foreign master not using PTP timescale"); + } +- if (c->tds.currentUtcOffset < CURRENT_UTC_OFFSET) { ++ if (c->tds.currentUtcOffset < c->current_utc_offset) { + pr_warning("running in a temporal vortex"); + } + } +@@ -697,10 +698,10 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress) + + if (c->tds.flags & UTC_OFF_VALID && c->tds.flags & TIME_TRACEABLE) { + utc_offset = c->tds.currentUtcOffset; +- } else if (c->tds.currentUtcOffset > CURRENT_UTC_OFFSET) { ++ } else if (c->tds.currentUtcOffset > c->current_utc_offset) { + utc_offset = c->tds.currentUtcOffset; + } else { +- utc_offset = CURRENT_UTC_OFFSET; ++ utc_offset = c->current_utc_offset; + } + + if (c->tds.flags & LEAP_61) { +@@ -1035,7 +1036,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, + c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval"); + c->grand_master_capable = config_get_int(config, NULL, "gmCapable"); + c->kernel_leap = config_get_int(config, NULL, "kernel_leap"); +- c->utc_offset = CURRENT_UTC_OFFSET; ++ c->utc_offset = c->current_utc_offset = config_get_int(config, NULL, "utc_offset"); + c->time_source = config_get_int(config, NULL, "timeSource"); + + if (c->free_running) { +diff --git a/config.c b/config.c +index b19f3ad..7bb949d 100644 +--- a/config.c ++++ b/config.c +@@ -237,6 +237,7 @@ struct config_item config_tab[] = { + GLOB_ITEM_STR("uds_address", "/var/run/ptp4l"), + GLOB_ITEM_INT("use_syslog", 1, 0, 1), + GLOB_ITEM_STR("userDescription", ""), ++ GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX), + GLOB_ITEM_INT("verbose", 0, 0, 1), + }; + +diff --git a/default.cfg b/default.cfg +index 12542c0..ebb263a 100644 +--- a/default.cfg ++++ b/default.cfg +@@ -7,6 +7,7 @@ slaveOnly 0 + priority1 128 + priority2 128 + domainNumber 0 ++#utc_offset 37 + clockClass 248 + clockAccuracy 0xFE + offsetScaledLogVariance 0xFFFF +diff --git a/gPTP.cfg b/gPTP.cfg +index 75e996c..142996a 100644 +--- a/gPTP.cfg ++++ b/gPTP.cfg +@@ -7,6 +7,7 @@ gmCapable 1 + priority1 248 + priority2 248 + domainNumber 0 ++#utc_offset 37 + clockClass 248 + clockAccuracy 0xFE + offsetScaledLogVariance 0xFFFF +diff --git a/ptp4l.8 b/ptp4l.8 +index f53fc6e..53d5f28 100644 +--- a/ptp4l.8 ++++ b/ptp4l.8 +@@ -327,6 +327,10 @@ The default is 0xFFFF. + The domain attribute of the local clock. + The default is 0. + .TP ++.B utc_offset ++The current offset between TAI and UTC. ++The default is 37. ++.TP + .B free_running + Don't adjust the local clock if enabled. + The default is 0 (disabled). diff --git a/SOURCES/linuxptp-warnings.patch b/SOURCES/linuxptp-warnings.patch deleted file mode 100644 index e1d99ae..0000000 --- a/SOURCES/linuxptp-warnings.patch +++ /dev/null @@ -1,89 +0,0 @@ -commit 9ddd2a60249eaf2b2a48bf9af3843fa06cf0a095 -Author: Miroslav Lichvar -Date: Wed Sep 17 11:11:15 2014 +0200 - - Fix copying of device name to ifreq. - - Don't overwrite the last NUL with strncpy() and also replace strcpy() - with strncpy(). - - Signed-off-by: Miroslav Lichvar - -diff --git a/hwstamp_ctl.c b/hwstamp_ctl.c -index ec5dd6d..0d21843 100644 ---- a/hwstamp_ctl.c -+++ b/hwstamp_ctl.c -@@ -131,7 +131,7 @@ int main(int argc, char *argv[]) - memset(&ifreq, 0, sizeof(ifreq)); - memset(&cfg, 0, sizeof(cfg)); - -- strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name)); -+ strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1); - - ifreq.ifr_data = (void *) &cfg; - -diff --git a/sk.c b/sk.c -index f694bbd..a9133fd 100644 ---- a/sk.c -+++ b/sk.c -@@ -51,7 +51,7 @@ static int hwts_init(int fd, const char *device, int rx_filter, int one_step) - memset(&ifreq, 0, sizeof(ifreq)); - memset(&cfg, 0, sizeof(cfg)); - -- strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name)); -+ strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1); - - ifreq.ifr_data = (void *) &cfg; - cfg.tx_type = one_step ? HWTSTAMP_TX_ONESTEP_SYNC : HWTSTAMP_TX_ON; -@@ -85,7 +85,7 @@ int sk_interface_index(int fd, const char *name) - int err; - - memset(&ifreq, 0, sizeof(ifreq)); -- strcpy(ifreq.ifr_name, name); -+ strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name) - 1); - err = ioctl(fd, SIOCGIFINDEX, &ifreq); - if (err < 0) { - pr_err("ioctl SIOCGIFINDEX failed: %m"); -@@ -154,7 +154,7 @@ int sk_interface_macaddr(const char *name, struct address *mac) - int err, fd; - - memset(&ifreq, 0, sizeof(ifreq)); -- strcpy(ifreq.ifr_name, name); -+ strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name) - 1); - - fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fd < 0) { - -commit 6b459abc8c54189ec3315404057923c039c1796a -Author: Miroslav Lichvar -Date: Wed Sep 17 11:11:16 2014 +0200 - - Fix Coverity warning in sk_interface_addr(). - - Copy the address directly to struct sockaddr_in or sockaddr_in6 instead - of sockaddr as Coverity doesn't seem to understand the union and reports - a buffer overflow. - - Signed-off-by: Miroslav Lichvar - -diff --git a/sk.c b/sk.c -index a9133fd..c48cf45 100644 ---- a/sk.c -+++ b/sk.c -@@ -191,14 +191,15 @@ int sk_interface_addr(const char *name, int family, struct address *addr) - switch (family) { - case AF_INET: - addr->len = sizeof(addr->sin); -+ memcpy(&addr->sin, i->ifa_addr, addr->len); - break; - case AF_INET6: - addr->len = sizeof(addr->sin6); -+ memcpy(&addr->sin6, i->ifa_addr, addr->len); - break; - default: - continue; - } -- memcpy(&addr->sa, i->ifa_addr, addr->len); - result = 0; - break; - } diff --git a/SPECS/linuxptp.spec b/SPECS/linuxptp.spec index 89a64c2..7ade9b1 100644 --- a/SPECS/linuxptp.spec +++ b/SPECS/linuxptp.spec @@ -1,36 +1,35 @@ %global _hardened_build 1 -%global gitdate 20140718 -%global gitrev bdb6a3 +%global testsuite_ver 502e82 +%global clknetsim_ver ce89a1 Name: linuxptp -Version: 1.4 -Release: 3.%{gitdate}git%{gitrev}%{?dist} +Version: 1.8 +Release: 3%{?dist} Summary: PTP implementation for Linux Group: System Environment/Base License: GPLv2+ URL: http://linuxptp.sourceforge.net/ -#Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz -# git clone git://git.code.sf.net/p/linuxptp/code linuxptp; cd linuxptp -# git archive --prefix=linuxptp-%{version}/ %{gitrev} | \ -# gzip > linuxptp-%{gitdate}git%{gitrev}.tar.gz -Source0: %{name}-%{gitdate}git%{gitrev}.tar.gz +Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz Source1: phc2sys.service Source2: ptp4l.service Source3: timemaster.service Source4: timemaster.conf -# test suite from https://github.com/mlichvar/linuxptp-testsuite.git -Source10: testsuite-7c523f.tar.gz -# simulator for test suite from https://github.com/mlichvar/clknetsim.git -Source11: clknetsim-e63178.tar.gz - -Patch1: linuxptp-warnings.patch -Patch2: linuxptp-uds.patch -Patch3: linuxptp-shm.patch -Patch4: linuxptp-timemaster.patch -Patch5: linuxptp-peeraddress.patch -Patch6: linuxptp-linreg_reset.patch -Patch7: linuxptp-phc2sys_state.patch +# 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 + +# update default TAI-UTC offset and make it configurable +Patch1: linuxptp-utcoffset.patch +# add options to tag ptp4l/phc2sys log messages and use them in timemaster +Patch2: linuxptp-messagetag.patch +# check support for SW timestamping in timemaster +Patch3: linuxptp-swtscheck.patch +# fix leaks of sockets in error handling +Patch4: linuxptp-closesocket.patch +# force BMC election when link goes down +Patch5: linuxptp-linkdown.patch BuildRequires: systemd-units @@ -47,14 +46,13 @@ Supporting legacy APIs and other platforms is not a goal. %prep %setup -q -a 10 -a 11 -%patch1 -p1 -b .warnings -%patch2 -p1 -b .uds -%patch3 -p1 -b .shm -%patch4 -p1 -b .timemaster -%patch5 -p1 -b .peeraddress -%patch6 -p1 -b .linreg_reset -%patch7 -p1 -b .phc2sys_state -mv clknetsim testsuite +%patch1 -p1 -b .utcoffset +%patch2 -p1 -b .messagetag +%patch3 -p1 -b .swtscheck +%patch4 -p1 -b .closesocket +%patch5 -p1 -b .linkdown +mv linuxptp-testsuite-%{testsuite_ver}* testsuite +mv clknetsim-%{clknetsim_ver}* testsuite/clknetsim %build make %{?_smp_mflags} \ @@ -78,6 +76,8 @@ 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 @@ -109,6 +109,15 @@ PATH=..:$PATH ./run %{_mandir}/man8/*.8* %changelog +* Wed Mar 15 2017 Miroslav Lichvar 1.8-3 +- fix backport of linkdown patch + +* Tue Mar 14 2017 Miroslav Lichvar 1.8-2 +- force BMC election when link goes down + +* Tue Feb 07 2017 Miroslav Lichvar 1.8-1 +- update to 1.8 (#1359311 #1353336) + * Tue Nov 25 2014 Miroslav Lichvar 1.4-3.20140718gitbdb6a3 - fix resetting of linreg servo (#1165045) - fix phc2sys automatic mode with multiple interfaces (#1108795)