diff --git a/clock.c b/clock.c index f608236..6e0b0d9 100644 --- a/clock.c +++ b/clock.c @@ -79,6 +79,7 @@ struct clock { int freq_est_interval; int utc_timescale; int leap_set; + int kernel_leap; enum servo_state servo_state; tmv_t master_offset; tmv_t path_delay; @@ -498,7 +499,8 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress) clock_leap = leap_second_status(ts, c->leap_set, &leap, &utc_offset); if (c->leap_set != clock_leap) { - clockadj_set_leap(c->clkid, clock_leap); + if (c->kernel_leap) + clockadj_set_leap(c->clkid, clock_leap); c->leap_set = clock_leap; } } @@ -559,6 +561,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, c->free_running = dds->free_running; c->freq_est_interval = dds->freq_est_interval; + c->kernel_leap = dds->kernel_leap; c->desc = dds->clock_desc; if (c->free_running) { diff --git a/config.c b/config.c index dd96fc1..7991378 100644 --- a/config.c +++ b/config.c @@ -383,6 +383,11 @@ static enum parser_result parse_global_setting(const char *option, return BAD_VALUE; cfg->dds.stats_interval = val; + } else if (!strcmp(option, "kernel_leap")) { + if (1 != sscanf(value, "%d", &val)) + return BAD_VALUE; + cfg->dds.kernel_leap = val; + } else return NOT_PARSED; diff --git a/default.cfg b/default.cfg index 7b3e2f7..12878c5 100644 --- a/default.cfg +++ b/default.cfg @@ -33,6 +33,7 @@ tx_timestamp_retries 100 use_syslog 1 verbose 0 summary_interval 0 +kernel_leap 1 # # Servo Options # diff --git a/ds.h b/ds.h index 06cb30a..555bc19 100644 --- a/ds.h +++ b/ds.h @@ -52,6 +52,7 @@ struct default_ds { int free_running; int freq_est_interval; /*log seconds*/ int stats_interval; /*log seconds*/ + int kernel_leap; struct clock_description clock_desc; }; diff --git a/gPTP.cfg b/gPTP.cfg index ecd5f71..cfb388b 100644 --- a/gPTP.cfg +++ b/gPTP.cfg @@ -32,6 +32,7 @@ tx_timestamp_retries 100 use_syslog 1 verbose 0 summary_interval 0 +kernel_leap 1 # # Servo options # diff --git a/phc2sys.8 b/phc2sys.8 index 10faea9..67b2f27 100644 --- a/phc2sys.8 +++ b/phc2sys.8 @@ -31,6 +31,8 @@ phc2sys \- synchronize two clocks ] [ .B \-w ] [ +.B \-x +] [ .BI \-l " print-level" ] [ .B \-m @@ -127,6 +129,13 @@ option is not used, also keep the offset between the slave and master times updated according to the currentUtcOffset value obtained from ptp4l and the direction of the clock synchronization. .TP +.B \-x +When a leap second is announced, don't apply it in the kernel by stepping the +clock, but let the servo correct the one-second offset slowly by changing the +clock frequency (unless the +.B \-S +option is used). +.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 678b0f3..1f851f7 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -124,6 +124,7 @@ struct clock { int sync_offset_direction; int leap; int leap_set; + int kernel_leap; struct pmc *pmc; int pmc_ds_idx; int pmc_ds_requested; @@ -500,7 +501,7 @@ static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) if (clock->leap_set != clock_leap) { /* Only the system clock can leap. */ - if (clock->clkid == CLOCK_REALTIME) + if (clock->clkid == CLOCK_REALTIME && clock->kernel_leap) clockadj_set_leap(clock->clkid, clock_leap); clock->leap_set = clock_leap; } @@ -525,6 +526,7 @@ static void usage(char *progname) " -O [offset] slave-master time offset (0)\n" " -u [num] number of clock updates in summary stats (0)\n" " -w wait for ptp4l\n" + " -x apply leap seconds by servo instead of kernel\n" " -h prints this message and exits\n" " -v prints the software version and exits\n" "\n", @@ -542,6 +544,7 @@ int main(int argc, char *argv[]) struct clock dst_clock = { .clkid = CLOCK_REALTIME, .servo_state = SERVO_UNLOCKED, + .kernel_leap = 1, }; configured_pi_kp = KP; @@ -551,7 +554,7 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; while (EOF != (c = getopt(argc, argv, - "c:d:hs:P:I:S:R:N:O:i:u:wl:mqv"))) { + "c:d:hs:P:I:S:R:N:O:i:u:wxl:mqv"))) { switch (c) { case 'c': dst_clock.clkid = clock_open(optarg); @@ -596,6 +599,9 @@ int main(int argc, char *argv[]) case 'w': wait_sync = 1; break; + case 'x': + dst_clock.kernel_leap = 0; + break; case 'l': print_level = atoi(optarg); break; diff --git a/ptp4l.8 b/ptp4l.8 index 3ee222d..a0d223d 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -340,6 +340,14 @@ empty string. .B manufacturerIdentity The manufacturer id which should be an OUI owned by the manufacturer. The default is 00:00:00. +.TP +.B kernel_leap +When a leap second is announced, let the kernel apply it by stepping the clock +instead of correcting the one-second offset with servo, which would correct the +one-second offset slowly by changing the clock frequency (unless the +.B pi_offset_const +option is set to correct such offset by stepping). +Relevant only with software time stamping. The default is 1 (enabled). .SH SEE ALSO .BR pmc (8), diff --git a/ptp4l.c b/ptp4l.c index 32b69d0..dffaad0 100644 --- a/ptp4l.c +++ b/ptp4l.c @@ -53,6 +53,7 @@ static struct config cfg_settings = { .free_running = 0, .freq_est_interval = 1, .stats_interval = 0, + .kernel_leap = 1, .clock_desc = { .productDescription = { .max_symbols = 64,