ntp: add options for compensating HW timestamping errors
This commit is contained in:
parent
8efec1d640
commit
cacbe9976f
5 changed files with 108 additions and 36 deletions
63
conf.c
63
conf.c
|
@ -223,7 +223,13 @@ static char *leapsec_tz = NULL;
|
|||
/* Name of the user to which will be dropped root privileges. */
|
||||
static char *user;
|
||||
|
||||
/* Array of strings for interfaces with HW timestamping */
|
||||
typedef struct {
|
||||
char *name;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
} HwTs_Interface;
|
||||
|
||||
/* Array of HwTs_Interface */
|
||||
static ARR_Instance hwts_interfaces;
|
||||
|
||||
typedef struct {
|
||||
|
@ -327,7 +333,7 @@ CNF_Initialise(int r)
|
|||
{
|
||||
restarted = r;
|
||||
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (char *));
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (HwTs_Interface));
|
||||
|
||||
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
||||
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
||||
|
@ -354,7 +360,7 @@ CNF_Finalise(void)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
|
||||
Free(*(char **)ARR_GetElement(hwts_interfaces, i));
|
||||
Free(((HwTs_Interface *)ARR_GetElement(hwts_interfaces, i))->name);
|
||||
ARR_DestroyInstance(hwts_interfaces);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
||||
|
@ -1245,8 +1251,39 @@ parse_tempcomp(char *line)
|
|||
static void
|
||||
parse_hwtimestamp(char *line)
|
||||
{
|
||||
check_number_of_args(line, 1);
|
||||
*(char **)ARR_GetNewElement(hwts_interfaces) = Strdup(line);
|
||||
HwTs_Interface *iface;
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
if (!*line) {
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
|
||||
p = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
iface = ARR_GetNewElement(hwts_interfaces);
|
||||
iface->name = Strdup(p);
|
||||
iface->tx_comp = 0.0;
|
||||
iface->rx_comp = 0.0;
|
||||
|
||||
for (p = line; *p; line += n, p = line) {
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(p, "rxcomp")) {
|
||||
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "txcomp")) {
|
||||
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p)
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -1930,8 +1967,18 @@ CNF_GetInitStepThreshold(void)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
ARR_Instance
|
||||
CNF_GetHwTsInterfaces(void)
|
||||
int
|
||||
CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp)
|
||||
{
|
||||
return hwts_interfaces;
|
||||
HwTs_Interface *iface;
|
||||
|
||||
if (index >= ARR_GetSize(hwts_interfaces))
|
||||
return 0;
|
||||
|
||||
iface = ARR_GetElement(hwts_interfaces, index);
|
||||
*name = iface->name;
|
||||
*tx_comp = iface->tx_comp;
|
||||
*rx_comp = iface->rx_comp;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
3
conf.h
3
conf.h
|
@ -29,7 +29,6 @@
|
|||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "array.h"
|
||||
#include "reference.h"
|
||||
|
||||
extern void CNF_Initialise(int restarted);
|
||||
|
@ -120,6 +119,6 @@ extern char *CNF_GetHwclockFile(void);
|
|||
extern int CNF_GetInitSources(void);
|
||||
extern double CNF_GetInitStepThreshold(void);
|
||||
|
||||
extern ARR_Instance CNF_GetHwTsInterfaces(void);
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
|
|
@ -1776,7 +1776,7 @@ sendmail binary.
|
|||
|
||||
=== Miscellaneous
|
||||
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_::
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
|
||||
This directive enables hardware timestamping of NTP packets sent to and
|
||||
received from the specified network interface. The network interface controller
|
||||
(NIC) uses its own clock to accurately timestamp the actual transmissions and
|
||||
|
@ -1807,10 +1807,25 @@ and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
|
|||
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
||||
on all available interfaces.
|
||||
+
|
||||
An example of the directive is:
|
||||
The *hwtimestamp* directive has the following options:
|
||||
+
|
||||
*txcomp* _compensation_:::
|
||||
This option specifies the difference in seconds between the actual transmission
|
||||
time at the physical layer and the reported transmit timestamp. This value will
|
||||
be added to transmit timestamps obtained from the NIC. The default value is 0.
|
||||
*rxcomp* _compensation_:::
|
||||
This option specifies the difference in seconds between the reported receive
|
||||
timestamp and the actual reception time at the physical layer. This value will
|
||||
be subtracted from receive timestamps obtained from the NIC. The default value
|
||||
is 0.
|
||||
::
|
||||
+
|
||||
Examples of the directive are:
|
||||
+
|
||||
----
|
||||
hwtimestamp eth0
|
||||
hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
|
||||
hwtimestamp *
|
||||
----
|
||||
|
||||
[[include]]*include* _pattern_::
|
||||
|
|
6
ntp_io.c
6
ntp_io.c
|
@ -364,8 +364,12 @@ NIO_Initialise(int family)
|
|||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_Initialise();
|
||||
#else
|
||||
if (ARR_GetSize(CNF_GetHwTsInterfaces()))
|
||||
if (1) {
|
||||
double tx_comp, rx_comp;
|
||||
char *name;
|
||||
if (CNF_GetHwTsInterface(0, &name, &tx_comp, &rx_comp))
|
||||
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
recv_messages = ARR_CreateInstance(sizeof (struct Message));
|
||||
|
|
|
@ -66,6 +66,9 @@ struct Interface {
|
|||
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
||||
int l2_udp4_ntp_start;
|
||||
int l2_udp6_ntp_start;
|
||||
/* Compensation of errors in TX and RX timestamping */
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
HCL_Instance clock;
|
||||
};
|
||||
|
||||
|
@ -88,7 +91,7 @@ static int permanent_ts_options;
|
|||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_interface(const char *name)
|
||||
add_interface(const char *name, double tx_comp, double rx_comp)
|
||||
{
|
||||
struct ethtool_ts_info ts_info;
|
||||
struct hwtstamp_config ts_config;
|
||||
|
@ -169,6 +172,9 @@ add_interface(const char *name)
|
|||
iface->l2_udp4_ntp_start = 42;
|
||||
iface->l2_udp6_ntp_start = 62;
|
||||
|
||||
iface->tx_comp = tx_comp;
|
||||
iface->rx_comp = rx_comp;
|
||||
|
||||
iface->clock = HCL_CreateInstance();
|
||||
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", name);
|
||||
|
@ -179,7 +185,7 @@ add_interface(const char *name)
|
|||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_all_interfaces(void)
|
||||
add_all_interfaces(double tx_comp, double rx_comp)
|
||||
{
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int r;
|
||||
|
@ -190,7 +196,7 @@ add_all_interfaces(void)
|
|||
}
|
||||
|
||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
if (add_interface(ifa->ifa_name))
|
||||
if (add_interface(ifa->ifa_name, tx_comp, rx_comp))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
|
@ -236,34 +242,30 @@ update_interface_speed(struct Interface *iface)
|
|||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
ARR_Instance config_hwts_ifaces;
|
||||
char *if_name;
|
||||
double tx_comp, rx_comp;
|
||||
char *name;
|
||||
unsigned int i;
|
||||
int wildcard, hwts;
|
||||
int hwts;
|
||||
|
||||
interfaces = ARR_CreateInstance(sizeof (struct Interface));
|
||||
|
||||
config_hwts_ifaces = CNF_GetHwTsInterfaces();
|
||||
|
||||
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
||||
all interfaces. If no interface was specified, enable SW timestamping. */
|
||||
|
||||
for (i = wildcard = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
|
||||
if (!strcmp("*", *(char **)ARR_GetElement(config_hwts_ifaces, i)))
|
||||
wildcard = 1;
|
||||
for (i = hwts = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
|
||||
if (!strcmp("*", name))
|
||||
continue;
|
||||
if (!add_interface(name, tx_comp, rx_comp))
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", name);
|
||||
hwts = 1;
|
||||
}
|
||||
|
||||
if (!wildcard && ARR_GetSize(config_hwts_ifaces)) {
|
||||
for (i = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
|
||||
if_name = *(char **)ARR_GetElement(config_hwts_ifaces, i);
|
||||
if (!add_interface(if_name))
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", if_name);
|
||||
}
|
||||
for (i = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
|
||||
if (strcmp("*", name))
|
||||
continue;
|
||||
if (add_all_interfaces(tx_comp, rx_comp))
|
||||
hwts = 1;
|
||||
} else if (wildcard && add_all_interfaces()) {
|
||||
hwts = 1;
|
||||
} else {
|
||||
hwts = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hwts) {
|
||||
|
@ -447,6 +449,11 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
|||
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
|
||||
}
|
||||
|
||||
if (!rx_ntp_length && iface->tx_comp)
|
||||
UTI_AddDoubleToTimespec(hw_ts, iface->tx_comp, hw_ts);
|
||||
else if (rx_ntp_length && iface->rx_comp)
|
||||
UTI_AddDoubleToTimespec(hw_ts, -iface->rx_comp, hw_ts);
|
||||
|
||||
if (!HCL_CookTime(iface->clock, hw_ts, &ts, &err))
|
||||
return;
|
||||
|
||||
|
|
Loading…
Reference in a new issue