/* 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 {
{
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));
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++)
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();
}
/* ================================================== */
/* ================================================== */
-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;
}
#define GOT_CONF_H
#include "addressing.h"
-#include "array.h"
#include "reference.h"
extern void CNF_Initialise(int restarted);
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 */
=== 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
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_::
#ifdef HAVE_LINUX_TIMESTAMPING
NIO_Linux_Initialise();
#else
- if (ARR_GetSize(CNF_GetHwTsInterfaces()))
- LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
+ 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));
/* 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;
};
/* ================================================== */
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;
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);
/* ================================================== */
static int
-add_all_interfaces(void)
+add_all_interfaces(double tx_comp, double rx_comp)
{
struct ifaddrs *ifaddr, *ifa;
int r;
}
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;
}
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);
- }
- hwts = 1;
- } else if (wildcard && add_all_interfaces()) {
- hwts = 1;
- } else {
- hwts = 0;
+ 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;
+ break;
}
if (hwts) {
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;