Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7aa0bf7 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

[NET]: convert network timestamps to ktime_t



We currently use a special structure (struct skb_timeval) and plain
'struct timeval' to store packet timestamps in sk_buffs and struct
sock.

This has some drawbacks :
- Fixed resolution of micro second.
- Waste of space on 64bit platforms where sizeof(struct timeval)=16

I suggest using ktime_t that is a nice abstraction of high resolution
time services, currently capable of nanosecond resolution.

As sizeof(ktime_t) is 8 bytes, using ktime_t in 'struct sock' permits
a 8 byte shrink of this structure on 64bit architectures. Some other
structures also benefit from this size reduction (struct ipq in
ipv4/ip_fragment.c, struct frag_queue in ipv6/reassembly.c, ...)

Once this ktime infrastructure adopted, we can more easily provide
nanosecond resolution on top of it. (ioctl SIOCGSTAMPNS and/or
SO_TIMESTAMPNS/SCM_TIMESTAMPNS)

Note : this patch includes a bug correction in
compat_sock_get_timestamp() where a "err = 0;" was missing (so this
syscall returned -ENOENT instead of 0)

Signed-off-by: default avatarEric Dumazet <dada1@cosmosbay.com>
CC: Stephen Hemminger <shemminger@linux-foundation.org>
CC: John find <linux.kernel@free.fr>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3927f2e8
Loading
Loading
Loading
Loading
+5 −21
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <net/checksum.h>
#include <linux/rcupdate.h>
#include <linux/dmaengine.h>
#include <linux/hrtimer.h>

#define HAVE_ALLOC_SKB		/* For the drivers to know */
#define HAVE_ALIGNABLE_SKB	/* Ditto 8)		   */
@@ -156,11 +157,6 @@ struct skb_shared_info {
#define SKB_DATAREF_SHIFT 16
#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)

struct skb_timeval {
	u32	off_sec;
	u32	off_usec;
};


enum {
	SKB_FCLONE_UNAVAILABLE,
@@ -233,7 +229,7 @@ struct sk_buff {
	struct sk_buff		*prev;

	struct sock		*sk;
	struct skb_timeval	tstamp;
	ktime_t			tstamp;
	struct net_device	*dev;
	int			iif;
	/* 4 byte hole on 64 bit*/
@@ -1365,26 +1361,14 @@ extern void skb_add_mtu(int mtu);
 */
static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
{
	stamp->tv_sec  = skb->tstamp.off_sec;
	stamp->tv_usec = skb->tstamp.off_usec;
	*stamp = ktime_to_timeval(skb->tstamp);
}

/**
 * 	skb_set_timestamp - set timestamp of a skb
 *	@skb: skb to set stamp of
 *	@stamp: pointer to struct timeval to get stamp from
 *
 *	Timestamps are stored in the skb as offsets to a base timestamp.
 *	This function converts a struct timeval to an offset and stores
 *	it in the skb.
 */
static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
static inline void __net_timestamp(struct sk_buff *skb)
{
	skb->tstamp.off_sec  = stamp->tv_sec;
	skb->tstamp.off_usec = stamp->tv_usec;
	skb->tstamp = ktime_get_real();
}

extern void __net_timestamp(struct sk_buff *skb);

extern __sum16 __skb_checksum_complete(struct sk_buff *skb);

+9 −9
Original line number Diff line number Diff line
@@ -244,7 +244,7 @@ struct sock {
	struct sk_filter      	*sk_filter;
	void			*sk_protinfo;
	struct timer_list	sk_timer;
	struct timeval		sk_stamp;
	ktime_t			sk_stamp;
	struct socket		*sk_socket;
	void			*sk_user_data;
	struct page		*sk_sndmsg_page;
@@ -1307,19 +1307,19 @@ static inline int sock_intr_errno(long timeo)
static __inline__ void
sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
{
	struct timeval stamp;
	ktime_t kt = skb->tstamp;

	skb_get_timestamp(skb, &stamp);
	if (sock_flag(sk, SOCK_RCVTSTAMP)) {
		struct timeval tv;
		/* Race occurred between timestamp enabling and packet
		   receiving.  Fill in the current time for now. */
		if (stamp.tv_sec == 0)
			do_gettimeofday(&stamp);
		skb_set_timestamp(skb, &stamp);
		put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(struct timeval),
			 &stamp);
		if (kt.tv64 == 0)
			kt = ktime_get_real();
		skb->tstamp = kt;
		tv = ktime_to_timeval(kt);
		put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(tv), &tv);
	} else
		sk->sk_stamp = stamp;
		sk->sk_stamp = kt;
}

/**
+1 −0
Original line number Diff line number Diff line
@@ -469,6 +469,7 @@ struct timeval ns_to_timeval(const s64 nsec)

	return tv;
}
EXPORT_SYMBOL(ns_to_timeval);

/*
 * Convert jiffies to milliseconds and back.
+4 −2
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
	unsigned int group = uloginfo->nlgroup;
	ebt_ulog_buff_t *ub = &ulog_buffers[group];
	spinlock_t *lock = &ub->lock;
	ktime_t kt;

	if ((uloginfo->cprange == 0) ||
	    (uloginfo->cprange > skb->len + ETH_HLEN))
@@ -164,9 +165,10 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,

	/* Fill in the ulog data */
	pm->version = EBT_ULOG_VERSION;
	do_gettimeofday(&pm->stamp);
	kt = ktime_get_real();
	pm->stamp = ktime_to_timeval(kt);
	if (ub->qlen == 1)
		skb_set_timestamp(ub->skb, &pm->stamp);
		ub->skb->tstamp = kt;
	pm->data_len = copy_len;
	pm->mark = skb->mark;
	pm->hook = hooknr;
+10 −5
Original line number Diff line number Diff line
@@ -545,15 +545,20 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
	struct compat_timeval __user *ctv =
			(struct compat_timeval __user*) userstamp;
	int err = -ENOENT;
	struct timeval tv;

	if (!sock_flag(sk, SOCK_TIMESTAMP))
		sock_enable_timestamp(sk);
	if (sk->sk_stamp.tv_sec == -1)
	tv = ktime_to_timeval(sk->sk_stamp);
	if (tv.tv_sec == -1)
		return err;
	if (sk->sk_stamp.tv_sec == 0)
		do_gettimeofday(&sk->sk_stamp);
	if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) ||
			put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec))
	if (tv.tv_sec == 0) {
		sk->sk_stamp = ktime_get_real();
		tv = ktime_to_timeval(sk->sk_stamp);
	}
	err = 0;
	if (put_user(tv.tv_sec, &ctv->tv_sec) ||
			put_user(tv.tv_usec, &ctv->tv_usec))
		err = -EFAULT;
	return err;
}
Loading