Ed uses the ptp_kvm driver with phc2sys, and Debian 10 has an udev rule
which creates a symlink for this device called /dev/ptp_kvm.

/lib/udev/rules.d/50-udev-default.rules:

SUBSYSTEM=="ptp", ATTR{clock_name}=="KVM virtual PTP", SYMLINK += "ptp_kvm"

Since the blamed patch, posix_clock_open(), called from a variety of
places including the phc2sys clock_add(), returns an error which states
that it cannot deduce the PHC index from this char device symlink.

It appears that phc2sys supports, to some extent, synchronizing PTP
clocks specified by path to the char device, for which the PHC index is
not known. In fact, there are some places in phc2sys where clocks are
compared by PHC number, but almost miraculously, it manages to not trip
over the fact that the PHC number is missing.

For example:

- find_dst_clock() finds clocks by PHC index, but it is only called from
  the "automatic" (phc2sys -a) code path. In that mode, phc2sys finds
  the PHC through this algorithm:
  - send a PORT_PROPERTIES_NP management TLV to ptp4l which contains the
    port interface name as string ("eth0" etc)
  - retrieve the PHC device through ethtool ioctls and compute the device
    path as /dev/ptpN as discussed
  So it manages to find the char device path in the reverse direction
  (the PHC number is already known).

- do_loop() has this logic:

        /* don't try to synchronize the clock to itself */
        if (clock->clkid == priv->master->clkid ||
            (clock->phc_index >= 0 &&
             clock->phc_index == priv->master->phc_index) ||
            !strcmp(clock->device, priv->master->device))
                continue;

  which again, magically manages to not trip over a comparison between
  the priv->master_phc_index (CLOCK_REALTIME, has phc_index == -1) and
  clock->phc_index (/dev/ptp_kvm, also has phc_index == -1), simply
  because the slave clock first has to have a valid phc_index before the
  comparison is even been done.

Otherwise said, for phc2sys it is an actual regression to require that
the path to the PTP char device be in the "/dev/ptpN" format. It
doesn't strictly require having a PHC index, but leaving the data
structures like that, now that we are aware of this corner case, is
prone to breakage introduced by future changes.

To fix the problem, we maintain that the PTP clock char device must
contain a number, if its path begins with /dev/ptp. But this time, we
follow any symbolic links that might exist, before attempting to deduce
the number from the path string.

Fixes: 380d023abb1f ("posix_clock_open: derive PHC index from device name if 
possible")
Reported-by: Ed Branch <bra...@arlut.utexas.edu>
Signed-off-by: Vladimir Oltean <olte...@gmail.com>
---
 util.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/util.c b/util.c
index cc4f11008be2..686ed5e2f110 100644
--- a/util.c
+++ b/util.c
@@ -18,6 +18,7 @@
  */
 #include <arpa/inet.h>
 #include <errno.h>
+#include <linux/limits.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -200,6 +201,7 @@ void posix_clock_close(clockid_t clock)
 
 clockid_t posix_clock_open(const char *device, int *phc_index)
 {
+       char phc_device_path[PATH_MAX];
        struct sk_ts_info ts_info;
        char phc_device[19];
        int clkid;
@@ -208,21 +210,28 @@ clockid_t posix_clock_open(const char *device, int 
*phc_index)
        if (!strcasecmp(device, "CLOCK_REALTIME")) {
                return CLOCK_REALTIME;
        }
-       /* check if device is valid phc device */
-       clkid = phc_open(device);
-       if (clkid != CLOCK_INVALID) {
-               if (!strncmp(device, "/dev/ptp", strlen("/dev/ptp"))) {
-                       int r = get_ranged_int(device + strlen("/dev/ptp"),
+
+       /* if the device name resolves so a plausible filesystem path, we
+        * assume it is the path to a PHC char device, and treat it as such
+        */
+       if (realpath(device, phc_device_path)) {
+               clkid = phc_open(device);
+               if (clkid == CLOCK_INVALID)
+                       return clkid;
+
+               if (!strncmp(phc_device_path, "/dev/ptp", strlen("/dev/ptp"))) {
+                       int r = get_ranged_int(phc_device_path + 
strlen("/dev/ptp"),
                                               phc_index, 0, 65535);
                        if (r) {
                                fprintf(stderr,
                                        "failed to parse PHC index from %s\n",
-                                       device);
+                                       phc_device_path);
                                return -1;
                        }
                }
                return clkid;
        }
+
        /* check if device is a valid ethernet device */
        if (sk_get_ts_info(device, &ts_info) || !ts_info.valid) {
                pr_err("unknown clock %s: %m", device);
-- 
2.25.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to