mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 16:35:06 -05:00
refclock_phc: support ethernet ifname as specifier
This commit allows the user to select a PHC refclock associated with an Ethernet interface by specifying the interface name. This allows the user to handle situations where multiple NICs are exposing PHC devices (or non-NIC PHC device files exist in the system) in a more streamline manner.
This commit is contained in:
committed by
Miroslav Lichvar
parent
81362fa201
commit
6e541afbe9
@@ -557,8 +557,9 @@ refclock SHM 1:perm=0644 refid GPS2
|
||||
----
|
||||
+
|
||||
*PHC*:::
|
||||
PTP hardware clock (PHC) driver. The parameter is the path to the device of
|
||||
the PTP clock which should be used as a time source. If the clock is kept in
|
||||
PTP hardware clock (PHC) driver. The parameter is the absolute path to the
|
||||
device of the PTP clock which should be used as a time source, or the name of
|
||||
the network interface whose PTP clock should be used. If the clock is kept in
|
||||
TAI instead of UTC (e.g. it is synchronised by a PTP daemon), the current
|
||||
UTC-TAI offset needs to be specified by the *offset* option. Alternatively, the
|
||||
*pps* refclock option can be enabled to treat the PHC as a PPS refclock, using
|
||||
|
||||
@@ -220,7 +220,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
|
||||
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||
phc_fd = SYS_Linux_OpenPHC(req.ifr_name);
|
||||
if (phc_fd < 0)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ static int phc_initialise(RCL_Instance instance)
|
||||
|
||||
path = RCL_GetDriverParameter(instance);
|
||||
|
||||
phc_fd = SYS_Linux_OpenPHC(path, 0);
|
||||
phc_fd = SYS_Linux_OpenPHC(path);
|
||||
if (phc_fd < 0)
|
||||
LOG_FATAL("Could not open PHC");
|
||||
|
||||
|
||||
113
sys_linux.c
113
sys_linux.c
@@ -38,6 +38,12 @@
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SCFILTER
|
||||
#include <sys/prctl.h>
|
||||
#include <seccomp.h>
|
||||
@@ -48,9 +54,6 @@
|
||||
#ifdef FEAT_RTC
|
||||
#include <linux/rtc.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
#include <linux/sockios.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
@@ -64,6 +67,7 @@
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "privops.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Frequency scale to convert from ppm to the timex freq */
|
||||
@@ -902,33 +906,100 @@ get_precise_phc_readings(int phc_fd, int max_samples, struct timespec ts[][3])
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_OpenPHC(const char *path, int phc_index)
|
||||
/* Make sure an FD is a PHC. Return the FD if it is, or close the FD
|
||||
and return -1 if it is not. */
|
||||
|
||||
static int
|
||||
verify_fd_is_phc(int phc_fd)
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
char phc_path[64];
|
||||
int phc_fd;
|
||||
|
||||
if (!path) {
|
||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||
return -1;
|
||||
path = phc_path;
|
||||
}
|
||||
|
||||
phc_fd = open(path, O_RDONLY);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open %s : %s", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure it is a PHC */
|
||||
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
LOG(LOGS_ERR, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
|
||||
close(phc_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
return phc_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_phc_by_iface_name(const char *iface)
|
||||
{
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
struct ethtool_ts_info ts_info;
|
||||
char phc_device[PATH_MAX];
|
||||
struct ifreq req;
|
||||
int sock_fd;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&ts_info, 0, sizeof (ts_info));
|
||||
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", iface) >=
|
||||
sizeof (req.ifr_name)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ts_info.cmd = ETHTOOL_GET_TS_INFO;
|
||||
req.ifr_data = (char *)&ts_info;
|
||||
|
||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Simplify failure paths by closing the socket as early as possible */
|
||||
SCK_CloseSocket(sock_fd);
|
||||
sock_fd = -1;
|
||||
|
||||
if (ts_info.phc_index < 0) {
|
||||
DEBUG_LOG("PHC missing on %s", req.ifr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (snprintf(phc_device, sizeof (phc_device),
|
||||
"/dev/ptp%d", ts_info.phc_index) >= sizeof (phc_device))
|
||||
return -1;
|
||||
|
||||
return open(phc_device, O_RDONLY);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_OpenPHC(const char *device)
|
||||
{
|
||||
int phc_fd = -1;
|
||||
|
||||
if (device[0] == '/') {
|
||||
phc_fd = open(device, O_RDONLY);
|
||||
if (phc_fd >= 0)
|
||||
phc_fd = verify_fd_is_phc(phc_fd);
|
||||
}
|
||||
|
||||
if (phc_fd < 0) {
|
||||
phc_fd = open_phc_by_iface_name(device);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open PHC of iface %s : %s",
|
||||
device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
phc_fd = verify_fd_is_phc(phc_fd);
|
||||
}
|
||||
|
||||
if (phc_fd >= 0)
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
return phc_fd;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ extern void SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext conte
|
||||
|
||||
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
|
||||
|
||||
extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
|
||||
extern int SYS_Linux_OpenPHC(const char *device);
|
||||
|
||||
extern int SYS_Linux_GetPHCReadings(int fd, int nocrossts, int *reading_mode, int max_readings,
|
||||
struct timespec tss[][3]);
|
||||
|
||||
Reference in New Issue
Block a user