Skip to content

Commit

Permalink
ptp: Support late timestamp determination
Browse files Browse the repository at this point in the history
If a physical clock supports a free running cycle counter, then
timestamps shall be based on this time too. For TX it is known in
advance before the transmission if a timestamp based on the free running
cycle counter is needed. For RX it is impossible to know which timestamp
is needed before the packet is received and assigned to a socket.

Support late timestamp determination by a network device. Therefore, an
address/cookie is stored within the new netdev_data field of struct
skb_shared_hwtstamps. This address/cookie is provided to a new network
device function called ndo_get_tstamp(), which returns a timestamp based
on the normal/adjustable time or based on the free running cycle
counter. If function is not supported, then timestamp handling is not
changed.

This mechanism is intended for RX, but TX use is also possible.

Signed-off-by: Gerhard Engleder <[email protected]>
Acked-by: Jonathan Lemon <[email protected]>
Acked-by: Richard Cochran <[email protected]>
Signed-off-by: Paolo Abeni <[email protected]>
  • Loading branch information
Gerhard Engleder authored and Paolo Abeni committed May 10, 2022
1 parent d58809d commit 97dc7cd
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 13 deletions.
21 changes: 21 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,12 @@ struct netdev_net_notifier {
* The caller must be under RCU read context.
* int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
* Get the forwarding path to reach the real device from the HW destination address
* ktime_t (*ndo_get_tstamp)(struct net_device *dev,
* const struct skb_shared_hwtstamps *hwtstamps,
* bool cycles);
* Get hardware timestamp based on normal/adjustable time or free running
* cycle counter. This function is required if physical clock supports a
* free running cycle counter.
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
Expand Down Expand Up @@ -1578,6 +1584,9 @@ struct net_device_ops {
struct net_device * (*ndo_get_peer_dev)(struct net_device *dev);
int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
struct net_device_path *path);
ktime_t (*ndo_get_tstamp)(struct net_device *dev,
const struct skb_shared_hwtstamps *hwtstamps,
bool cycles);
};

/**
Expand Down Expand Up @@ -4761,6 +4770,18 @@ static inline void netdev_rx_csum_fault(struct net_device *dev,
void net_enable_timestamp(void);
void net_disable_timestamp(void);

static inline ktime_t netdev_get_tstamp(struct net_device *dev,
const struct skb_shared_hwtstamps *hwtstamps,
bool cycles)
{
const struct net_device_ops *ops = dev->netdev_ops;

if (ops->ndo_get_tstamp)
return ops->ndo_get_tstamp(dev, hwtstamps, cycles);

return hwtstamps->hwtstamp;
}

static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
struct sk_buff *skb, struct net_device *dev,
bool more)
Expand Down
14 changes: 11 additions & 3 deletions include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,10 @@ static inline bool skb_frag_must_loop(struct page *p)

/**
* struct skb_shared_hwtstamps - hardware time stamps
* @hwtstamp: hardware time stamp transformed into duration
* since arbitrary point in time
* @hwtstamp: hardware time stamp transformed into duration
* since arbitrary point in time
* @netdev_data: address/cookie of network device driver used as
* reference to actual hardware time stamp
*
* Software time stamps generated by ktime_get_real() are stored in
* skb->tstamp.
Expand All @@ -601,7 +603,10 @@ static inline bool skb_frag_must_loop(struct page *p)
* &skb_shared_info. Use skb_hwtstamps() to get a pointer.
*/
struct skb_shared_hwtstamps {
ktime_t hwtstamp;
union {
ktime_t hwtstamp;
void *netdev_data;
};
};

/* Definitions for tx_flags in struct skb_shared_info */
Expand All @@ -621,6 +626,9 @@ enum {
/* generate wifi status information (where possible) */
SKBTX_WIFI_STATUS = 1 << 4,

/* determine hardware time stamp based on time or cycles */
SKBTX_HW_TSTAMP_NETDEV = 1 << 5,

/* generate software time stamp when entering packet scheduling */
SKBTX_SCHED_TSTAMP = 1 << 6,
};
Expand Down
49 changes: 39 additions & 10 deletions net/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,28 @@ static bool skb_is_swtx_tstamp(const struct sk_buff *skb, int false_tstamp)
return skb->tstamp && !false_tstamp && skb_is_err_queue(skb);
}

static void put_ts_pktinfo(struct msghdr *msg, struct sk_buff *skb)
static ktime_t get_timestamp(struct sock *sk, struct sk_buff *skb, int *if_index)
{
bool cycles = sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC;
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
struct net_device *orig_dev;
ktime_t hwtstamp;

rcu_read_lock();
orig_dev = dev_get_by_napi_id(skb_napi_id(skb));
if (orig_dev) {
*if_index = orig_dev->ifindex;
hwtstamp = netdev_get_tstamp(orig_dev, shhwtstamps, cycles);
} else {
hwtstamp = shhwtstamps->hwtstamp;
}
rcu_read_unlock();

return hwtstamp;
}

static void put_ts_pktinfo(struct msghdr *msg, struct sk_buff *skb,
int if_index)
{
struct scm_ts_pktinfo ts_pktinfo;
struct net_device *orig_dev;
Expand All @@ -815,11 +836,14 @@ static void put_ts_pktinfo(struct msghdr *msg, struct sk_buff *skb)

memset(&ts_pktinfo, 0, sizeof(ts_pktinfo));

rcu_read_lock();
orig_dev = dev_get_by_napi_id(skb_napi_id(skb));
if (orig_dev)
ts_pktinfo.if_index = orig_dev->ifindex;
rcu_read_unlock();
if (!if_index) {
rcu_read_lock();
orig_dev = dev_get_by_napi_id(skb_napi_id(skb));
if (orig_dev)
if_index = orig_dev->ifindex;
rcu_read_unlock();
}
ts_pktinfo.if_index = if_index;

ts_pktinfo.pkt_length = skb->len - skb_mac_offset(skb);
put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPING_PKTINFO,
Expand All @@ -839,6 +863,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
int empty = 1, false_tstamp = 0;
struct skb_shared_hwtstamps *shhwtstamps =
skb_hwtstamps(skb);
int if_index;
ktime_t hwtstamp;

/* Race occurred between timestamp enabling and packet
Expand Down Expand Up @@ -887,18 +912,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
if (shhwtstamps &&
(sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
!skb_is_swtx_tstamp(skb, false_tstamp)) {
if (sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC)
hwtstamp = ptp_convert_timestamp(&shhwtstamps->hwtstamp,
sk->sk_bind_phc);
if_index = 0;
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV)
hwtstamp = get_timestamp(sk, skb, &if_index);
else
hwtstamp = shhwtstamps->hwtstamp;

if (sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC)
hwtstamp = ptp_convert_timestamp(&hwtstamp,
sk->sk_bind_phc);

if (ktime_to_timespec64_cond(hwtstamp, tss.ts + 2)) {
empty = 0;

if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&
!skb_is_err_queue(skb))
put_ts_pktinfo(msg, skb);
put_ts_pktinfo(msg, skb, if_index);
}
}
if (!empty) {
Expand Down

0 comments on commit 97dc7cd

Please sign in to comment.