Currently the user space can't tell which delay mechanism
(E2E/P3P) or transport is needed in the ioctl(). Therefore,
PTP silently fails when the hardware doesn't support a
certain delay mechanism or transport.
This patch uses the ioctl flags field to pass that information
from the user space to kernel. If the hardware supports all
the desired features, the ioctl continues as before, otherwise
the unsupported bits are reseted to 0 and this information is
returned to user space.
It's backwards compatible. If an older ptp4l calls the ioctl(),
the flags field will be zero, so it should work as before.
It's forwards compatible. If the new ptp4l calls the ioctl(),
the old kernel will return -EINVAL and ptp4l will try again
without requiring any feature, as before the change.
Signed-off-by: Flavio Leitner <***@redhat.com>
---
dm.h | 2 ++
pmc_common.c | 2 +-
port.c | 6 +++--
raw.c | 7 ++---
sk.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++-----
sk.h | 1 +
transport.c | 6 +++--
transport.h | 4 ++-
transport_private.h | 2 +-
udp.c | 5 ++--
udp6.c | 5 ++--
uds.c | 3 ++-
12 files changed, 95 insertions(+), 22 deletions(-)
diff --git a/dm.h b/dm.h
index 2491c63..06a967a 100644
--- a/dm.h
+++ b/dm.h
@@ -24,6 +24,8 @@
* Defines the possible delay mechanisms.
*/
enum delay_mechanism {
+ /** None */
+ DM_NONE,
/** Start as E2E, but switch to P2P if a peer is detected. */
DM_AUTO,
diff --git a/pmc_common.c b/pmc_common.c
index ed3c5da..3c245b2 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -90,7 +90,7 @@ struct pmc *pmc_create(enum transport_type transport_type, char *iface_name,
goto failed;
}
if (transport_open(pmc->transport, iface_name,
- &pmc->fdarray, TS_SOFTWARE)) {
+ &pmc->fdarray, DM_NONE, TS_SOFTWARE)) {
pr_err("failed to open transport");
goto failed;
}
diff --git a/port.c b/port.c
index bd10d0a..868f77c 100644
--- a/port.c
+++ b/port.c
@@ -1316,7 +1316,8 @@ static int port_initialize(struct port *p)
goto no_timers;
}
}
- if (transport_open(p->trp, p->name, &p->fda, p->timestamping))
+ if (transport_open(p->trp, p->name, &p->fda, p->timestamping,
+ p->delayMechanism))
goto no_tropen;
for (i = 0; i < N_TIMER_FDS; i++) {
@@ -1349,7 +1350,8 @@ static int port_renew_transport(struct port *p)
}
clock_remove_fda(p->clock, p, p->fda);
transport_close(p->trp, &p->fda);
- if (transport_open(p->trp, p->name, &p->fda, p->timestamping)) {
+ if (transport_open(p->trp, p->name, &p->fda, p->timestamping,
+ p->delayMechanism)) {
return -1;
}
clock_install_fda(p->clock, p, p->fda);
diff --git a/raw.c b/raw.c
index d87edbf..957a351 100644
--- a/raw.c
+++ b/raw.c
@@ -42,6 +42,7 @@
#include "raw.h"
#include "sk.h"
#include "transport_private.h"
+#include "dm.h"
struct raw {
struct transport t;
@@ -184,8 +185,8 @@ no_socket:
return -1;
}
-static int raw_open(struct transport *t, char *name,
- struct fdarray *fda, enum timestamp_type ts_type)
+static int raw_open(struct transport *t, char *name, struct fdarray *fda,
+ enum timestamp_type ts_type, enum delay_mechanism dm)
{
struct raw *raw = container_of(t, struct raw, t);
int efd, gfd;
@@ -206,7 +207,7 @@ static int raw_open(struct transport *t, char *name,
if (gfd < 0)
goto no_general;
- if (sk_timestamping_init(efd, name, ts_type, TRANS_IEEE_802_3))
+ if (sk_timestamping_init(efd, name, ts_type, dm, TRANS_IEEE_802_3))
goto no_timestamping;
if (sk_general_init(gfd))
diff --git a/sk.c b/sk.c
index fe74164..d1a878a 100644
--- a/sk.c
+++ b/sk.c
@@ -32,6 +32,7 @@
#include "print.h"
#include "sk.h"
+#include "dm.h"
/* globals */
@@ -40,10 +41,13 @@ int sk_check_fupsync;
/* private methods */
-static int hwts_init(int fd, char *device, int rx_filter, int one_step)
+static int hwts_init(int fd, char *device, int hwflags, int rx_filter,
+ int one_step)
{
struct ifreq ifreq;
struct hwtstamp_config cfg, req;
+ int unsupported_flags;
+ int check_hwflags = 1;
int err;
memset(&ifreq, 0, sizeof(ifreq));
@@ -52,16 +56,52 @@ static int hwts_init(int fd, char *device, int rx_filter, int one_step)
strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name));
ifreq.ifr_data = (void *) &cfg;
+ cfg.flags = hwflags & HWTSTAMP_FEATURE_FLAGS_MASK;
cfg.tx_type = one_step ? HWTSTAMP_TX_ONESTEP_SYNC : HWTSTAMP_TX_ON;
cfg.rx_filter = rx_filter;
req = cfg;
err = ioctl(fd, SIOCSHWTSTAMP, &ifreq);
- if (err < 0)
- return err;
+ if (err < 0) {
+ /* older linux kernels required flags to be zero
+ * disable hwflags checking */
+ if (errno == EINVAL) {
+ check_hwflags = 0;
+ req.flags = cfg.flags = 0;
+ err = ioctl(fd, SIOCSHWTSTAMP, &ifreq);
+ if (err < 0)
+ return err;
+ }
+ else
+ return err;
+ }
if (memcmp(&cfg, &req, sizeof(cfg))) {
pr_warning("driver changed our HWTSTAMP options");
+ unsupported_flags = cfg.flags ^ req.flags;
+ unsupported_flags &= HWTSTAMP_FEATURE_FLAGS_MASK;
+ if (check_hwflags && unsupported_flags) {
+ if (unsupported_flags & HWTSTAMP_DM_E2E)
+ pr_warning("End-to-End is not supported");
+ if (unsupported_flags & HWTSTAMP_DM_P2P)
+ pr_warning("Peer-to-Peer is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_UDS)
+ pr_warning("UDS is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_UDP_IPV4)
+ pr_warning("UDP over IPv4 is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_UDP_IPV6)
+ pr_warning("UDP over IPv6 is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_IEEE_802_3)
+ pr_warning("IEEE 802.3 is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_DEVICENET)
+ pr_warning("DeviceNet is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_CONTROLNET)
+ pr_warning("End-to-End is not supported");
+ if (unsupported_flags & HWTSTAMP_TRANS_PROFINET)
+ pr_warning("End-to-End is not supported");
+ return -1;
+ }
+ pr_warning("flags %d not %d", cfg.flags, req.flags);
pr_warning("tx_type %d not %d", cfg.tx_type, req.tx_type);
pr_warning("rx_filter %d not %d", cfg.rx_filter, req.rx_filter);
@@ -284,9 +324,9 @@ int sk_receive(int fd, void *buf, int buflen,
}
int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
- enum transport_type transport)
+ enum delay_mechanism dm, enum transport_type transport)
{
- int err, filter1, filter2 = 0, flags, one_step;
+ int err, filter1, filter2 = 0, flags, one_step, hwflags = 0;
switch (type) {
case TS_SOFTWARE:
@@ -312,12 +352,32 @@ int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
if (type != TS_SOFTWARE) {
filter1 = HWTSTAMP_FILTER_PTP_V2_EVENT;
one_step = type == TS_ONESTEP ? 1 : 0;
+ switch (dm) {
+ case DM_AUTO:
+ hwflags |= (HWTSTAMP_DM_P2P | HWTSTAMP_DM_E2E);
+ break;
+ case DM_E2E:
+ hwflags |= HWTSTAMP_DM_E2E;
+ break;
+ case DM_P2P:
+ hwflags |= HWTSTAMP_DM_P2P;
+ case DM_NONE:
+ break;
+ default:
+ return -1;
+ }
+
switch (transport) {
case TRANS_UDP_IPV4:
+ hwflags |= HWTSTAMP_TRANS_UDP_IPV4;
+ filter2 = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+ break;
case TRANS_UDP_IPV6:
+ hwflags |= HWTSTAMP_TRANS_UDP_IPV6;
filter2 = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
break;
case TRANS_IEEE_802_3:
+ hwflags |= HWTSTAMP_TRANS_IEEE_802_3;
filter2 = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
break;
case TRANS_DEVICENET:
@@ -326,10 +386,10 @@ int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
case TRANS_UDS:
return -1;
}
- err = hwts_init(fd, device, filter1, one_step);
+ err = hwts_init(fd, device, hwflags, filter1, one_step);
if (err) {
pr_info("driver rejected most general HWTSTAMP filter");
- err = hwts_init(fd, device, filter2, one_step);
+ err = hwts_init(fd, device, hwflags, filter2, one_step);
if (err) {
pr_err("ioctl SIOCSHWTSTAMP failed: %m");
return err;
diff --git a/sk.h b/sk.h
index 895840f..02a5326 100644
--- a/sk.h
+++ b/sk.h
@@ -101,6 +101,7 @@ int sk_receive(int fd, void *buf, int buflen,
* @return Zero on success, non-zero otherwise.
*/
int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
+ enum delay_mechanism dm,
enum transport_type transport);
/**
diff --git a/transport.c b/transport.c
index 3c70b2b..52d89bc 100644
--- a/transport.c
+++ b/transport.c
@@ -23,6 +23,7 @@
#include "udp.h"
#include "udp6.h"
#include "uds.h"
+#include "dm.h"
int transport_close(struct transport *t, struct fdarray *fda)
{
@@ -30,9 +31,10 @@ int transport_close(struct transport *t, struct fdarray *fda)
}
int transport_open(struct transport *t, char *name,
- struct fdarray *fda, enum timestamp_type tt)
+ struct fdarray *fda, enum timestamp_type tt,
+ enum delay_mechanism dm)
{
- return t->open(t, name, fda, tt);
+ return t->open(t, name, fda, tt, dm);
}
int transport_recv(struct transport *t, int fd,
diff --git a/transport.h b/transport.h
index 34934fe..7e04c0c 100644
--- a/transport.h
+++ b/transport.h
@@ -60,12 +60,14 @@ struct hw_timestamp {
struct timespec sw;
};
+enum delay_mechanism;
struct transport;
int transport_close(struct transport *t, struct fdarray *fda);
int transport_open(struct transport *t, char *name,
- struct fdarray *fda, enum timestamp_type tt);
+ struct fdarray *fda, enum timestamp_type tt,
+ enum delay_mechanism dm);
int transport_recv(struct transport *t, int fd,
void *buf, int buflen, struct hw_timestamp *hwts);
diff --git a/transport_private.h b/transport_private.h
index 0c553e1..9f133cd 100644
--- a/transport_private.h
+++ b/transport_private.h
@@ -31,7 +31,7 @@ struct transport {
int (*close)(struct transport *t, struct fdarray *fda);
int (*open)(struct transport *t, char *name, struct fdarray *fda,
- enum timestamp_type tt);
+ enum timestamp_type tt, enum delay_mechanism dm);
int (*recv)(struct transport *t, int fd, void *buf, int buflen,
struct hw_timestamp *hwts);
diff --git a/udp.c b/udp.c
index be7f2b7..7b402a8 100644
--- a/udp.c
+++ b/udp.c
@@ -34,6 +34,7 @@
#include "sk.h"
#include "ether.h"
#include "transport_private.h"
+#include "dm.h"
#include "udp.h"
#define EVENT_PORT 319
@@ -149,7 +150,7 @@ enum { MC_PRIMARY, MC_PDELAY };
static struct in_addr mcast_addr[2];
static int udp_open(struct transport *t, char *name, struct fdarray *fda,
- enum timestamp_type ts_type)
+ enum timestamp_type ts_type, enum delay_mechanism dm)
{
struct udp *udp = container_of(t, struct udp, t);
int efd, gfd;
@@ -176,7 +177,7 @@ static int udp_open(struct transport *t, char *name, struct fdarray *fda,
if (gfd < 0)
goto no_general;
- if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4))
+ if (sk_timestamping_init(efd, name, ts_type, dm, TRANS_UDP_IPV4))
goto no_timestamping;
if (sk_general_init(gfd))
diff --git a/udp6.c b/udp6.c
index e0d1256..8dbeaa2 100644
--- a/udp6.c
+++ b/udp6.c
@@ -34,6 +34,7 @@
#include "sk.h"
#include "ether.h"
#include "transport_private.h"
+#include "dm.h"
#include "udp6.h"
#define EVENT_PORT 319
@@ -159,7 +160,7 @@ enum { MC_PRIMARY, MC_PDELAY };
static struct in6_addr mc6_addr[2];
static int udp6_open(struct transport *t, char *name, struct fdarray *fda,
- enum timestamp_type ts_type)
+ enum timestamp_type ts_type, enum delay_mechanism dm)
{
struct udp6 *udp6 = container_of(t, struct udp6, t);
int efd, gfd;
@@ -188,7 +189,7 @@ static int udp6_open(struct transport *t, char *name, struct fdarray *fda,
if (gfd < 0)
goto no_general;
- if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6))
+ if (sk_timestamping_init(efd, name, ts_type, dm, TRANS_UDP_IPV6))
goto no_timestamping;
if (sk_general_init(gfd))
diff --git a/uds.c b/uds.c
index 1dbfd6c..17bacee 100644
--- a/uds.c
+++ b/uds.c
@@ -28,6 +28,7 @@
#include "contain.h"
#include "print.h"
#include "transport_private.h"
+#include "dm.h"
#include "uds.h"
char uds_path[MAX_IFNAME_SIZE + 1] = "/var/run/ptp4l";
@@ -47,7 +48,7 @@ static int uds_close(struct transport *t, struct fdarray *fda)
}
static int uds_open(struct transport *t, char *name, struct fdarray *fda,
- enum timestamp_type tt)
+ enum timestamp_type tt, enum delay_mechanism dm)
{
int fd, err;
struct sockaddr_un sa;
--
1.8.3.1