Skip to contentSkip to conversation

CLOCK_MONOTONIC datagram timestamps by the kernel

PATCH In review John 6 participants 34 messages Feb 28, 2007 – Mar 9, 2007

Subsystems (14)
lore
Share & tools
lore

John

author
#0 lore raw

Hello,

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

As far as I understand, one can either do

  const int on = 1;
  setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof on);

then use recvmsg()

or not set the SO_TIMESTAMP socket option and just call

  ioctl(sock, SIOCGSTAMP, &tv);

after each datagram has been received.

SIOCGSTAMP
Return a struct timeval with the receive timestamp of the last
packet passed to the user. This is useful for accurate round trip time measurements. See setitimer(2) for a description of struct timeval.

As far as I understand, this timestamp is given by the CLOCK_REALTIME clock. However, I would like to obtain a timestamp given by the CLOCK_MONOTONIC clock.

Relevant parts of the code (I think):

net/core/dev.c

void net_enable_timestamp(void)
{
atomic_inc(&netstamp_needed);
}

void __net_timestamp(struct sk_buff *skb)
{
struct timeval tv;

do_gettimeofday(&tv);
skb_set_timestamp(skb, &tv);
}

static inline void net_timestamp(struct sk_buff *skb) {
if (atomic_read(&netstamp_needed))

    __net_timestamp(skb);
  else {
    skb->tstamp.off_sec = 0;
    skb->tstamp.off_usec = 0;

}
}

do_gettimeofday() just calls __get_realtime_clock_ts()

Would it be possible to replace do_gettimeofday() by ktime_get_ts() with the appropriate division by 1000 to convert the struct timespec back into a struct timeval?

void __net_timestamp(struct sk_buff *skb)
{
struct timespec now;
struct timeval tv;

ktime_get_ts(&ts);
tv.tv_sec = now.tv_sec;
tv->tv_usec = now.tv_nsec/1000;
skb_set_timestamp(skb, &tv);
}

How many apps / drivers would this break?

Is there perhaps a different way to achieve this?

Regards.

author
#1 lore raw
Quoted 3 lines · John

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

Has it ever been proposed to modify struct skb_timeval to hold nanosecond stamps instead of just microsecond stamps? Then make the improved precision somehow available to user space.

On a related note, the comment for skb_set_timestamp() states:

/**
* 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.
*/

But there is no mention of an offset in the code:

static inline void skb_set_timestamp(
struct sk_buff *skb, const struct timeval *stamp)
{
skb->tstamp.off_sec = stamp->tv_sec; skb->tstamp.off_usec = stamp->tv_usec;
}

Likewise for skb_get_timestamp:

/**
* skb_get_timestamp - get timestamp from a skb
* @skb: skb to get stamp from
* @stamp: pointer to struct timeval to store stamp in
*
* Timestamps are stored in the skb as offsets to a base timestamp.
* This function converts the offset back to a struct timeval and stores
* it in stamp.
*/

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;
}

Are the comments related to code that has since been modified?

Regards.

#2 lore raw
Quoted 8 lines · John
Quoted 3 lines · John

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

Has it ever been proposed to modify struct skb_timeval to hold nanosecond stamps instead of just microsecond stamps? Then make the improved precision somehow available to user space.

John,

Most modern NICS are able to delay packet delivery, in order to reduce number of interrupts and benefit from better cache hits.

tg3 for example are able to delay up to 1024 us.

Then kernel is not realtime and some delays can occur between the hardware interrupt and the very moment we timestamp the packet. If CPU caches are cold, even the instruction fetches could easily add some us.

Enabling nanosecond stamps would be a lie to users, because real accuracy is not nanosecond, but in the order of 10 us (at least)

If you depend on a < 50 us precision, then linux might be the wrong OS for your application. Or maybe you need a NIC that is able to provide a timestamp in the packet itself (well... along with the packet...) , so that kernel latencies are not a problem.

Eric

author
#3 lore raw
Quoted 10 lines · Eric Dumazet
Quoted 8 lines
Quoted 3 lines · John

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

Has it ever been proposed to modify struct skb_timeval to hold nanosecond stamps instead of just microsecond stamps? Then make the improved precision somehow available to user space.

Most modern NICS are able to delay packet delivery, in order to reduce number of interrupts and benefit from better cache hits.

You are referring to NAPI interrupt mitigation, right?

AFAIU, it is possible to disable this feature.

I'm dealing with 200-4000 packets per second. I don't think I'd save much with interrupt mitigation. Please correct any misconception.

Quoted 1 line

Then kernel is not realtime and some delays can occur between the hardware interrupt and the very moment we timestamp the packet. If CPU caches are cold, even the instruction fetches could easily add some us.

I've applied the real-time patch.
http://rt.wiki.kernel.org/index.php/Main_Page
This doesn't make Linux hard real-time, but the interrupt handlers can run with the highest priority (even kernel threads are preempted).

Quoted 1 line

Enabling nanosecond stamps would be a lie to users, because real accuracy is not nanosecond, but in the order of 10 us (at least)

POSIX is moving to nanoseconds interfaces.
http://www.opengroup.org/onlinepubs/009695399/functions/clock_settime.html

struct timeval and struct timespec take as much space (64 bits).

If the hardware can indeed manage sub-microsecond accuracy, a struct timeval forces the kernel to discard valuable information.

Quoted 1 line

If you depend on a < 50 us precision, then linux might be the wrong OS for your application. Or maybe you need a NIC that is able to provide a timestamp in the packet itself (well... along with the packet...) , so that kernel latencies are not a problem.

Does Linux support NICs that can do that?

Regards.

#4 lore raw
Quoted 6 lines · John
Quoted 5 lines · Eric Dumazet
Quoted 5 lines
Quoted 3 lines · John

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

Has it ever been proposed to modify struct skb_timeval to hold nanosecond stamps instead of just microsecond stamps? Then make the improved precision somehow available to user space.

Most modern NICS are able to delay packet delivery, in order to reduce number of interrupts and benefit from better cache hits.

You are referring to NAPI interrupt mitigation, right?

Nope; I am referring to hardware features. NAPI is software.

See ethtool -c eth0

# ethtool -c eth0
Coalesce parameters for eth0:
Adaptive RX: off  TX: off
stats-block-usecs: 1000000
sample-interval: 0
pkt-rate-low: 0
pkt-rate-high: 0

rx-usecs: 300
rx-frames: 60
rx-usecs-irq: 300
rx-frames-irq: 60

tx-usecs: 200
tx-frames: 53
tx-usecs-irq: 200
tx-frames-irq: 53

You can see on this setup, rx interrupts can be delayed up to 300 us (up to 60 packets might be delayed)

Quoted 3 lines

POSIX is moving to nanoseconds interfaces.
http://www.opengroup.org/onlinepubs/009695399/functions/clock_settime.html

The fact that you are able to give nanosecond timestamps inside kernel is not sufficient. It is necessary of course, but not sufficient. This precision is OK to time locally generated events. The moment you ask a 'nanosecond' timestamp, it's usually long before/after the real event.

If you rely on nanosecond precision on network packets, then something is wrong with your algo. Even rt patches wont make sure your cpu caches are pre-filled, or that the routers/links between your machines are not busy. A cache miss cost 40 ns for example. A typical interrupt handler or rx processing can trigger 100 cache misses, or not at all if cache is hot.

You said that rt gives highest priority to interrupt handlers :
If you have several nics, what will happen if you receive packets on both nics, or if the NIC interrupt happens in the same time than timer interrupt ? One timestamp will be wrong for sure.

For sure we could timestamp packets with nanosecond resolution, and eventually with MONOTONIC value too, but it will give you (and others) false confidence on the real precision. us timestamps are already wrong...

author
#5 lore raw
Quoted 31 lines · Eric Dumazet
Quoted 5 lines · John
Quoted 4 lines · Eric Dumazet
Quoted 4 lines
Quoted 3 lines · John

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Has it ever been proposed to modify struct skb_timeval to hold nanosecond stamps instead of just microsecond stamps? Then make the improved precision somehow available to user space.

Most modern NICS are able to delay packet delivery, in order to reduce number of interrupts and benefit from better cache hits.

You are referring to NAPI interrupt mitigation, right?

Nope; I am referring to hardware features. NAPI is software.

See ethtool -c eth0

# ethtool -c eth0
Coalesce parameters for eth0:
Adaptive RX: off  TX: off
stats-block-usecs: 1000000
sample-interval: 0
pkt-rate-low: 0
pkt-rate-high: 0

rx-usecs: 300
rx-frames: 60
rx-usecs-irq: 300
rx-frames-irq: 60

Quoted 7 lines

tx-usecs: 200
tx-frames: 53
tx-usecs-irq: 200
tx-frames-irq: 53

You can see on this setup, rx interrupts can be delayed up to 300 us (up to 60 packets might be delayed)

One can disable interrupt mitigation. Your argument that it introduces latency therefore becomes irrelevant.

Quoted 2 lines
Quoted 2 lines

POSIX is moving to nanoseconds interfaces.
http://www.opengroup.org/onlinepubs/009695399/functions/clock_settime.html

You snipped too much. I also wrote:

struct timeval and struct timespec take as much space (64 bits).

If the hardware can indeed manage sub-microsecond accuracy, a struct timeval forces the kernel to discard valuable information.

Quoted 4 lines

The fact that you are able to give nanosecond timestamps inside kernel is not sufficient. It is necessary of course, but not sufficient. This precision is OK to time locally generated events. The moment you ask a 'nanosecond' timestamp, it's usually long before/after the real event.

If you rely on nanosecond precision on network packets, then something is wrong with your algo. Even rt patches wont make sure your cpu caches are pre-filled, or that the routers/links between your machines are not busy. A cache miss cost 40 ns for example. A typical interrupt handler or rx processing can trigger 100 cache misses, or not at all if cache is hot.

Consider an idle Linux 2.6.20-rt8 system, equipped with a single PCI-E gigabit Ethernet NIC, running on a modern CPU (e.g. Core 2 Duo E6700). All this system does is time stamp 1000 packets per second.

Are you claiming that this platform *cannot* handle most packets within less than 1 microsecond of their arrival?

If there are platforms that can achieve sub-microsecond precision, and if it is not more expensive to support nanosecond resolution (I said resolution not precision), then it makes sense to support nanosecond resolution in Linux. Right?

Quoted 2 lines

You said that rt gives highest priority to interrupt handlers :
If you have several nics, what will happen if you receive packets on both nics, or if the NIC interrupt happens in the same time than timer interrupt ? One timestamp will be wrong for sure.

Again, this is irrelevant. We are discussing whether it would make sense to support sub-microsecond resolution. If there is one platform that can achieve sub-microsecond precision, there is a need for sub-microsecond resolution. As long as we are changing the resolution, we might as well use something standard like struct timespec.

Quoted 1 line

For sure we could timestamp packets with nanosecond resolution, and eventually with MONOTONIC value too, but it will give you (and others) false confidence on the real precision. us timestamps are already wrong...

IMHO, this is not true for all platforms.

Regards.

#6 lore raw
Quoted 5 lines · John

Again, this is irrelevant. We are discussing whether it would make sense to support sub-microsecond resolution. If there is one platform that can achieve sub-microsecond precision, there is a need for sub-microsecond resolution. As long as we are changing the resolution, we might as well use something standard like struct timespec.

You can not blindly change skb timestamps to different entities - you need to change all users (at least in kernel).
Exporting it to userspace must require new socket option and old one ust be changed accordingly, but there is nothing wrong in having nanosecond resolution in packet timestamp except that it might not be 100% correct receiving time.

Signature · 1 line
	Evgeniy Polyakov
#7 lore raw
In reply to John
Quoted 7 lines · John

Consider an idle Linux 2.6.20-rt8 system, equipped with a single PCI-E gigabit Ethernet NIC, running on a modern CPU (e.g. Core 2 Duo E6700). All this system does is time stamp 1000 packets per second.

Are you claiming that this platform *cannot* handle most packets within less than 1 microsecond of their arrival?

Yes I claim it.

You expect too much of this platform, unless "most" means 10 % for you ;)

If you replace "1 us" by "50 us", then yes, it probably can do it, if "most" means 99%, (not 99.999 %)

Anyway, if you want to play, you can apply this patch on top of linux-2.6.21-rc2 (nanosecond resolution infrastruture needs 2.6.21) I let you do the adjustments for rt kernel.

I compiled it on my i386 machine, and tested it with a patched libpcap/tcpdump

[PATCH] NET : introduce nanosecond time infrastructure and SIOCGSTAMPNS

It appears some machines are *really* fast and that micro second resolution is a limiting factor.

This patch converts sk_buff timestamp to use new nanosecond infra (added in 2.6.21), and introduces a new ioctl SIOCGSTAMPNS to let applications access nanosecond resolution (ie a timespec instead of timeval)

 fs/compat_ioctl.c                       |   17 ++++++++
 include/asm-alpha/sockios.h             |    1 
 include/asm-arm26/sockios.h             |    3 +
 include/asm-avr32/sockios.h             |    3 +
 include/asm-cris/sockios.h              |    3 +
 include/asm-frv/sockios.h               |    3 +
 include/asm-h8300/sockios.h             |    3 +
 include/asm-i386/sockios.h              |    3 +
 include/asm-ia64/sockios.h              |    3 +
 include/asm-m32r/sockios.h              |    3 +
 include/asm-m68k/sockios.h              |    3 +
 include/asm-mips/sockios.h              |    3 +
 include/asm-parisc/sockios.h            |    3 +
 include/asm-powerpc/sockios.h           |    3 +
 include/asm-s390/sockios.h              |    3 +
 include/asm-sh/sockios.h                |    1 
 include/asm-sh64/sockios.h              |    1 
 include/asm-sparc/sockios.h             |    3 +
 include/asm-sparc64/sockios.h           |    3 +
 include/asm-v850/sockios.h              |    3 +
 include/asm-x86_64/sockios.h            |    3 +
 include/asm-xtensa/sockios.h            |    3 +
 include/linux/skbuff.h                  |   42 +++++++++++++++-------
 include/net/compat.h                    |    1 
 include/net/sock.h                      |   16 +++++---
 net/appletalk/ddp.c                     |    3 +
 net/atm/ioctl.c                         |    3 +
 net/ax25/af_ax25.c                      |    4 ++
 net/bridge/netfilter/ebt_ulog.c         |    2 -
 net/compat.c                            |   31 +++++++++++++---
 net/core/dev.c                          |   14 +++----
 net/core/skbuff.c                       |    4 +-
 net/core/sock.c                         |   28 +++++++++++---
 net/econet/af_econet.c                  |    4 +-
 net/ipv4/af_inet.c                      |    3 +
 net/ipv4/ip_fragment.c                  |    6 +--
 net/ipv4/tcp_output.c                   |    2 -
 net/ipv6/af_inet6.c                     |    3 +
 net/ipv6/netfilter/nf_conntrack_reasm.c |    6 +--
 net/ipv6/reassembly.c                   |    6 +--
 net/ipx/af_ipx.c                        |    2 -
 net/netrom/af_netrom.c                  |    5 ++
 net/packet/af_packet.c                  |    8 ++--
 net/rose/af_rose.c                      |    2 +
 net/sunrpc/svcsock.c                    |    9 ++--
 net/wanrouter/af_wanpipe.c              |    3 +
 net/x25/af_x25.c                        |   12 ++++++
 47 files changed, 216 insertions(+), 77 deletions(-)
include/linux/skbuff.h +30 -12
@@ -156,9 +156,13 @@ struct skb_shared_info {
 #define SKB_DATAREF_SHIFT 16
 #define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
 
-struct skb_timeval {
+/*
+ * We use a special timespec like structure, because ABI constraints 
+ * make 'struct timespec' being 16 bytes on 64bit platforms.
+ */
+struct skb_timespec {
 	u32	off_sec;
-	u32	off_usec;
+	u32	off_nsec;
 };
 
 
@@ -186,7 +190,7 @@ enum {
  *	@next: Next buffer in list
  *	@prev: Previous buffer in list
  *	@sk: Socket we are owned by
- *	@tstamp: Time we arrived
+ *	@tstampns: Time we arrived
  *	@dev: Device we arrived on/are leaving by
  *	@input_dev: Device we arrived on
  *	@h: Transport layer header
@@ -233,7 +237,7 @@ struct sk_buff {
 	struct sk_buff		*prev;
 
 	struct sock		*sk;
-	struct skb_timeval	tstamp;
+	struct skb_timespec	tstampns;
 	struct net_device	*dev;
 	struct net_device	*input_dev;
 
@@ -1350,6 +1354,20 @@ extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
 
 /**
+ *	skb_get_timestampns - get timestamp from a skb
+ *	@skb: skb to get stamp from
+ *	@stampns: pointer to struct timespec to store stamp in
+ *
+ *	Timestamps are stored in the skb as offsets to a base timestamp.
+ *	This function converts the offset back to a struct timespec and stores
+ *	it in stamp.
+ */
+static inline void skb_get_timestampns(const struct sk_buff *skb, struct timespec *stampns)
+{
+	stampns->tv_sec  = skb->tstampns.off_sec;
+	stampns->tv_nsec = skb->tstampns.off_nsec;
+}
+/**
  *	skb_get_timestamp - get timestamp from a skb
  *	@skb: skb to get stamp from
  *	@stamp: pointer to struct timeval to store stamp in
@@ -1360,23 +1378,23 @@ 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->tv_sec  = skb->tstampns.off_sec;
+	stamp->tv_usec = skb->tstampns.off_nsec/1000;
 }
 
 /**
- * 	skb_set_timestamp - set timestamp of a skb
+ * 	skb_set_timestampns - set timestamp of a skb
  *	@skb: skb to set stamp of
- *	@stamp: pointer to struct timeval to get stamp from
+ *	@stamp: pointer to struct timespec 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
+ *	This function converts a struct timespec 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 skb_set_timestampns(struct sk_buff *skb, const struct timespec *stampns)
 {
-	skb->tstamp.off_sec  = stamp->tv_sec;
-	skb->tstamp.off_usec = stamp->tv_usec;
+	skb->tstampns.off_sec  = stampns->tv_sec;
+	skb->tstampns.off_nsec = stampns->tv_nsec;
 }
 
 extern void __net_timestamp(struct sk_buff *skb);
include/net/sock.h +10 -6
@@ -244,7 +244,7 @@ struct sock {
 	struct sk_filter      	*sk_filter;
 	void			*sk_protinfo;
 	struct timer_list	sk_timer;
-	struct timeval		sk_stamp;
+	struct timespec		sk_stampns;
 	struct socket		*sk_socket;
 	void			*sk_user_data;
 	struct page		*sk_sndmsg_page;
@@ -1307,19 +1307,22 @@ static inline int sock_intr_errno(long t
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
+	struct timespec stampns;
 	struct timeval stamp;
 
-	skb_get_timestamp(skb, &stamp);
+	skb_get_timestampns(skb, &stampns);
 	if (sock_flag(sk, SOCK_RCVTSTAMP)) {
 		/* 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);
+		if (stampns.tv_sec == 0)
+			getnstimeofday(&stampns);
+		skb_set_timestampns(skb, &stampns);
+		stamp.tv_sec = stampns.tv_sec;
+		stamp.tv_usec = stampns.tv_nsec/1000;
 		put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(struct timeval),
 			 &stamp);
 	} else
-		sk->sk_stamp = stamp;
+		sk->sk_stampns = stampns;
 }
 
 /**
@@ -1350,6 +1353,7 @@ static inline void sk_eat_skb(struct soc
 
 extern void sock_enable_timestamp(struct sock *sk);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int sock_get_timestampns(struct sock *, struct timespec __user *);
 
 /* 
  *	Enable debug/info messages 
include/net/compat.h +1 -0
@@ -25,6 +25,7 @@ struct compat_cmsghdr {
 };
 
 extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
 
 #else /* defined(CONFIG_COMPAT) */
 #define compat_msghdr	msghdr		/* to avoid compiler warnings */
net/core/sock.c +22 -6
@@ -1512,8 +1512,8 @@ void sock_init_data(struct socket *sock,
 	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
 	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
 
-	sk->sk_stamp.tv_sec     = -1L;
-	sk->sk_stamp.tv_usec    = -1L;
+	sk->sk_stampns.tv_sec     = -1L;
+	sk->sk_stampns.tv_nsec    = -1L;
 
 	atomic_set(&sk->sk_refcnt, 1);
 }
@@ -1554,17 +1554,33 @@ EXPORT_SYMBOL(release_sock);
 
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
+	struct timeval tstamp;
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk);
-	if (sk->sk_stamp.tv_sec == -1)
+	if (sk->sk_stampns.tv_sec == -1)
 		return -ENOENT;
-	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
-	return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ?
+	if (sk->sk_stampns.tv_sec == 0)
+		getnstimeofday(&sk->sk_stampns);
+	tstamp.tv_sec = sk->sk_stampns.tv_sec;
+	tstamp.tv_usec = sk->sk_stampns.tv_nsec/1000;
+	return copy_to_user(userstamp, &tstamp, sizeof(struct timeval)) ?
 		-EFAULT : 0;
 }
 EXPORT_SYMBOL(sock_get_timestamp);
 
+int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	if (sk->sk_stampns.tv_sec == -1)
+		return -ENOENT;
+	if (sk->sk_stampns.tv_sec == 0)
+		getnstimeofday(&sk->sk_stampns);
+	return copy_to_user(userstamp, &sk->sk_stampns, sizeof(struct timespec)) ?
+		-EFAULT : 0;
+}
+EXPORT_SYMBOL(sock_get_timestampns);
+
 void sock_enable_timestamp(struct sock *sk)
 {
 	if (!sock_flag(sk, SOCK_TIMESTAMP)) {
net/core/dev.c +7 -7
@@ -1036,10 +1036,10 @@ void net_disable_timestamp(void)
 
 void __net_timestamp(struct sk_buff *skb)
 {
-	struct timeval tv;
+	struct timespec ts;
 
-	do_gettimeofday(&tv);
-	skb_set_timestamp(skb, &tv);
+	getnstimeofday(&ts);
+	skb_set_timestampns(skb, &ts);
 }
 EXPORT_SYMBOL(__net_timestamp);
 
@@ -1048,8 +1048,8 @@ static inline void net_timestamp(struct 
 	if (atomic_read(&netstamp_needed))
 		__net_timestamp(skb);
 	else {
-		skb->tstamp.off_sec = 0;
-		skb->tstamp.off_usec = 0;
+		skb->tstampns.off_sec = 0;
+		skb->tstampns.off_nsec = 0;
 	}
 }
 
@@ -1580,7 +1580,7 @@ int netif_rx(struct sk_buff *skb)
 	if (netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstampns.off_sec)
 		net_timestamp(skb);
 
 	/*
@@ -1772,7 +1772,7 @@ int netif_receive_skb(struct sk_buff *sk
 	if (skb->dev->poll && netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstampns.off_sec)
 		net_timestamp(skb);
 
 	if (!skb->input_dev)
net/core/skbuff.c +2 -2
@@ -449,7 +449,7 @@ struct sk_buff *skb_clone(struct sk_buff
 
 	n->next = n->prev = NULL;
 	n->sk = NULL;
-	C(tstamp);
+	C(tstampns);
 	C(dev);
 	C(h);
 	C(nh);
@@ -534,7 +534,7 @@ static void copy_skb_header(struct sk_bu
 	new->local_df	= old->local_df;
 	new->fclone	= SKB_FCLONE_UNAVAILABLE;
 	new->pkt_type	= old->pkt_type;
-	new->tstamp	= old->tstamp;
+	new->tstampns	= old->tstampns;
 	new->destructor = NULL;
 	new->mark	= old->mark;
 #ifdef CONFIG_NETFILTER
net/ipv4/ip_fragment.c +3 -3
@@ -92,7 +92,7 @@ struct ipq {
 	spinlock_t	lock;
 	atomic_t	refcnt;
 	struct timer_list timer;	/* when will this queue expire?		*/
-	struct timeval	stamp;
+	struct timespec	stampns;
 	int             iif;
 	unsigned int    rid;
 	struct inet_peer *peer;
@@ -592,7 +592,7 @@ static void ip_frag_queue(struct ipq *qp
 	if (skb->dev)
 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &qp->stamp);
+	skb_get_timestampns(skb, &qp->stampns);
 	qp->meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
@@ -674,7 +674,7 @@ static struct sk_buff *ip_frag_reasm(str
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &qp->stamp);
+	skb_set_timestampns(head, &qp->stampns);
 
 	iph = head->nh.iph;
 	iph->frag_off = 0;
net/ipv4/af_inet.c +3 -0
@@ -755,6 +755,9 @@ int inet_ioctl(struct socket *sock, unsi
 		case SIOCGSTAMP:
 			err = sock_get_timestamp(sk, (struct timeval __user *)arg);
 			break;
+		case SIOCGSTAMPNS:
+			err = sock_get_timestampns(sk, (struct timespec __user *)arg);
+			break;
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCRTMSG:
net/ipv4/tcp_output.c +1 -1
@@ -661,7 +661,7 @@ int tcp_fragment(struct sock *sk, struct
 	 * skbs, which it never sent before. --ANK
 	 */
 	TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
-	buff->tstamp = skb->tstamp;
+	buff->tstampns = skb->tstampns;
 
 	old_factor = tcp_skb_pcount(skb);
 
net/ipv6/af_inet6.c +3 -0
@@ -437,6 +437,9 @@ int inet6_ioctl(struct socket *sock, uns
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 	case SIOCADDRT:
 	case SIOCDELRT:
 
net/packet/af_packet.c +5 -3
@@ -656,12 +656,12 @@ static int tpacket_rcv(struct sk_buff *s
 	h->tp_snaplen = snaplen;
 	h->tp_mac = macoff;
 	h->tp_net = netoff;
-	if (skb->tstamp.off_sec == 0) {
+	if (skb->tstampns.off_sec == 0) {
 		__net_timestamp(skb);
 		sock_enable_timestamp(sk);
 	}
-	h->tp_sec = skb->tstamp.off_sec;
-	h->tp_usec = skb->tstamp.off_usec;
+	h->tp_sec = skb->tstampns.off_sec;
+	h->tp_usec = skb->tstampns.off_nsec/1000;
 
 	sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
 	sll->sll_halen = 0;
@@ -1543,6 +1543,8 @@ static int packet_ioctl(struct socket *s
 		}
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
 
 #ifdef CONFIG_INET
 		case SIOCADDRT:
net/sunrpc/svcsock.c +4 -5
@@ -806,15 +806,14 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
 	if (skb->tstamp.off_sec == 0) {
-		struct timeval tv;
+		struct timespec ts;
 
-		tv.tv_sec = xtime.tv_sec;
-		tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
-		skb_set_timestamp(skb, &tv);
+		ts = current_kernel_time();
+		skb_set_timestampns(skb, &ts);
 		/* Don't enable netstamp, sunrpc doesn't
 		   need that much accuracy */
 	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	skb_get_timestampns(skb, &svsk->sk_sk->sk_stampns);
 	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/*
net/compat.c +26 -5
@@ -545,20 +545,41 @@ int compat_sock_get_timestamp(struct soc
 	struct compat_timeval __user *ctv =
 			(struct compat_timeval __user*) userstamp;
 	int err = -ENOENT;
+	long usec;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk);
-	if (sk->sk_stamp.tv_sec == -1)
+	if (sk->sk_stampns.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 (sk->sk_stampns.tv_sec == 0)
+		getnstimeofday(&sk->sk_stampns);
+	usec = sk->sk_stampns.tv_nsec / 1000;
+	if (put_user(sk->sk_stampns.tv_sec, &ctv->tv_sec) ||
+			put_user(usec, &ctv->tv_usec))
 		err = -EFAULT;
 	return err;
 }
 EXPORT_SYMBOL(compat_sock_get_timestamp);
 
+int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	struct compat_timespec __user *ctv =
+			(struct compat_timespec __user*) userstamp;
+	int err = -ENOENT;
+
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	if (sk->sk_stampns.tv_sec == -1)
+		return err;
+	if (sk->sk_stampns.tv_sec == 0)
+		getnstimeofday(&sk->sk_stampns);
+	if (put_user(sk->sk_stampns.tv_sec, &ctv->tv_sec) ||
+			put_user(sk->sk_stampns.tv_nsec, &ctv->tv_nsec))
+		err = -EFAULT;
+	return err;
+}
+EXPORT_SYMBOL(compat_sock_get_timestampns);
+
 asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
fs/compat_ioctl.c +17 -0
@@ -265,6 +265,22 @@ static int do_siocgstamp(unsigned int fd
 	}
 	return err;
 }
+static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct compat_timespec __user *up = compat_ptr(arg);
+	struct timespec ktv;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+	set_fs(old_fs);
+	if(!err) {
+		err = put_user(ktv.tv_sec, &up->tv_sec);
+		err |= __put_user(ktv.tv_nsec, &up->tv_nsec);
+	}
+	return err;
+}
 
 struct ifmap32 {
 	compat_ulong_t mem_start;
@@ -2437,6 +2453,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns)
 #endif
 #ifdef CONFIG_BLOCK
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
net/appletalk/ddp.c +3 -0
@@ -1768,6 +1768,9 @@ static int atalk_ioctl(struct socket *so
 		case SIOCGSTAMP:
 			rc = sock_get_timestamp(sk, argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = sock_get_timestampns(sk, argp);
+			break;
 		/* Routing */
 		case SIOCADDRT:
 		case SIOCDELRT:
net/ax25/af_ax25.c +4 -0
@@ -1711,6 +1711,10 @@ static int ax25_ioctl(struct socket *soc
 		res = sock_get_timestamp(sk, argp);
 		break;
 
+	case SIOCGSTAMPNS:
+		res = sock_get_timestampns(sk, argp);
+		break;
+
 	case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */
 	case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */
 	case SIOCAX25GETUID: {
net/atm/ioctl.c +3 -0
@@ -82,6 +82,9 @@ int vcc_ioctl(struct socket *sock, unsig
 		case SIOCGSTAMP: /* borrowed from IP */
 			error = sock_get_timestamp(sk, argp);
 			goto done;
+		case SIOCGSTAMPNS: /* borrowed from IP */
+			error = sock_get_timestampns(sk, argp);
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
 			error = 0;
net/econet/af_econet.c +3 -1
@@ -162,7 +162,7 @@ static int econet_recvmsg(struct kiocb *
 	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
 	if (err)
 		goto out_free;
-	skb_get_timestamp(skb, &sk->sk_stamp);
+	skb_get_timestampns(skb, &sk->sk_stampns);
 
 	if (msg->msg_name)
 		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
@@ -726,6 +726,8 @@ static int econet_ioctl(struct socket *s
 	switch(cmd) {
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, argp);
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, argp);
 
 		case SIOCSIFADDR:
 		case SIOCGIFADDR:
net/ipx/af_ipx.c +1 -1
@@ -1808,7 +1808,7 @@ static int ipx_recvmsg(struct kiocb *ioc
 	if (rc)
 		goto out_free;
 	if (skb->tstamp.off_sec)
-		skb_get_timestamp(skb, &sk->sk_stamp);
+		skb_get_timestampns(skb, &sk->sk_stampns);
 
 	msg->msg_namelen = sizeof(*sipx);
 
net/netrom/af_netrom.c +5 -0
@@ -1208,6 +1208,11 @@ static int nr_ioctl(struct socket *sock,
 		ret = sock_get_timestamp(sk, argp);
 		release_sock(sk);
 		return ret;
+	case SIOCGSTAMPNS:
+		lock_sock(sk);
+		ret = sock_get_timestampns(sk, argp);
+		release_sock(sk);
+		return ret;
 
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
net/rose/af_rose.c +2 -0
@@ -1271,6 +1271,8 @@ static int rose_ioctl(struct socket *soc
 
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *) argp);
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *) argp);
 
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
net/wanrouter/af_wanpipe.c +3 -0
@@ -1770,6 +1770,9 @@ static int wanpipe_ioctl(struct socket *
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 		case SIOC_WANPIPE_CHECK_TX:
 
 			return atomic_read(&sk->sk_wmem_alloc);
net/x25/af_x25.c +12 -0
@@ -1280,6 +1280,12 @@ static int x25_ioctl(struct socket *sock
 				rc = sock_get_timestamp(sk,
 						(struct timeval __user *)argp);
 			break;
+		case SIOCGSTAMP:
+			rc = -EINVAL;
+			if (sk)
+				rc = sock_get_timestampns(sk,
+						(struct timespec __user *)argp);
+			break;
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -1521,6 +1527,12 @@ static int compat_x25_ioctl(struct socke
 			rc = compat_sock_get_timestamp(sk,
 					(struct timeval __user*)argp);
 		break;
+	case SIOCGSTAMP:
+		rc = -EINVAL;
+		if (sk)
+			rc = compat_sock_get_timestampns(sk,
+					(struct timespec __user*)argp);
+		break;
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
net/bridge/netfilter/ebt_ulog.c +1 -1
@@ -166,7 +166,7 @@ static void ebt_ulog_packet(unsigned int
 	pm->version = EBT_ULOG_VERSION;
 	do_gettimeofday(&pm->stamp);
 	if (ub->qlen == 1)
-		skb_set_timestamp(ub->skb, &pm->stamp);
+		skb_set_timestampus(ub->skb, &pm->stamp);
 	pm->data_len = copy_len;
 	pm->mark = skb->mark;
 	pm->hook = hooknr;
net/ipv6/netfilter/nf_conntrack_reasm.c +3 -3
@@ -82,7 +82,7 @@ struct nf_ct_frag6_queue
 	struct sk_buff		*fragments;
 	int			len;
 	int			meat;
-	struct timeval		stamp;
+	struct timespec		stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -542,7 +542,7 @@ static int nf_ct_frag6_queue(struct nf_c
 		fq->fragments = skb;
 
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	skb_get_timestampns(skb, &fq->stamp);
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &nf_ct_frag6_mem);
 
@@ -648,7 +648,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	skb_set_timestampns(head, &fq->stamp);
 	head->nh.ipv6h->payload_len = htons(payload_len);
 
 	/* Yes, and fold redundant checksum back. 8) */
net/ipv6/reassembly.c +3 -3
@@ -88,7 +88,7 @@ struct frag_queue
 	int			len;
 	int			meat;
 	int			iif;
-	struct timeval		stamp;
+	struct timespec		stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -562,7 +562,7 @@ static void ip6_frag_queue(struct frag_q
 	if (skb->dev)
 		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	skb_get_timestampns(skb, &fq->stamp);
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -663,7 +663,7 @@ static int ip6_frag_reasm(struct frag_qu
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	skb_set_timestampns(head, &fq->stamp);
 	head->nh.ipv6h->payload_len = htons(payload_len);
 	IP6CB(head)->nhoff = nhoff;
 
include/asm-i386/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-x86_64/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-alpha/sockios.h +1 -0
@@ -11,5 +11,6 @@
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
 #define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_ALPHA_SOCKIOS_H */
include/asm-arm26/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-avr32/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ASM_AVR32_SOCKIOS_H */
include/asm-cris/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-frv/sockios.h +2 -1
@@ -7,7 +7,8 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS__ */
 
include/asm-h8300/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_H8300_SOCKIOS__ */
include/asm-ia64/sockios.h +2 -1
@@ -14,6 +14,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_IA64_SOCKIOS_H */
include/asm-m32r/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif  /* _ASM_M32R_SOCKIOS_H */
include/asm-m68k/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_M68K_SOCKIOS__ */
include/asm-mips/sockios.h +2 -1
@@ -20,6 +20,7 @@
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906			/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS_H */
include/asm-parisc/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-powerpc/sockios.h +2 -1
@@ -14,6 +14,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _ASM_POWERPC_SOCKIOS_H */
include/asm-s390/sockios.h +2 -1
@@ -15,6 +15,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-sh/sockios.h +1 -0
@@ -10,4 +10,5 @@
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
 #define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp - linux-specific */
 #endif /* __ASM_SH_SOCKIOS_H */
include/asm-sh64/sockios.h +1 -0
@@ -21,4 +21,5 @@
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
 #define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp - linux-specific */
 #endif /* __ASM_SH64_SOCKIOS_H */
include/asm-sparc/sockios.h +2 -1
@@ -7,7 +7,8 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC_SOCKIOS_H) */
 
include/asm-sparc64/sockios.h +2 -1
@@ -7,7 +7,8 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC64_SOCKIOS_H) */
 
include/asm-v850/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __V850_SOCKIOS_H__ */
include/asm-xtensa/sockios.h +2 -1
@@ -25,6 +25,7 @@
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _XTENSA_SOCKIOS_H */
#8 lore raw
Quoted 11 lines · Eric Dumazet
Quoted 7 lines · John

Consider an idle Linux 2.6.20-rt8 system, equipped with a single PCI-E gigabit Ethernet NIC, running on a modern CPU (e.g. Core 2 Duo E6700). All this system does is time stamp 1000 packets per second.

Are you claiming that this platform *cannot* handle most packets within less than 1 microsecond of their arrival?

Quoted 10 lines

Yes I claim it.

You expect too much of this platform, unless "most" means 10 % for you ;)

If you replace "1 us" by "50 us", then yes, it probably can do it, if "most" means 99%, (not 99.999 %)

Anyway, if you want to play, you can apply this patch on top of linux-2.6.21-rc2 (nanosecond resolution infrastruture needs 2.6.21) I let you do the adjustments for rt kernel.

I like it except changing stamp to stampns all over the place is unnecessary, just change the type.

Quoted 3 lines

I compiled it on my i386 machine, and tested it with a patched libpcap/tcpdump

I assume old tcpdump works as expected.

#9 lore raw
Quoted 4 lines · Stephen Hemminger

I like it except changing stamp to stampns all over the place is unnecessary, just change the
type.

Well... After seeing the compat code using casts, I felt some external users could try to cast it as well and not detect the new type...

Quoted 2 lines

I assume old tcpdump works as expected.

Yes, of course...

#10 lore raw

PATCH 1/1 NET : convert network timestamps to ktime_t

In reply to Stephen Hemminger

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)

CC Stephen Hemminger <[email protected]>
CC John find <[email protected]>
 include/linux/skbuff.h                  |   26 ++++------------------
 include/net/sock.h                      |   18 +++++++--------
 net/bridge/netfilter/ebt_ulog.c         |    6 +++--
 net/compat.c                            |   15 ++++++++----
 net/core/dev.c                          |   19 +++-------------
 net/core/sock.c                         |   16 +++++++------
 net/econet/af_econet.c                  |    2 -
 net/ipv4/ip_fragment.c                  |    6 ++---
 net/ipv4/netfilter/ip_queue.c           |    6 +++--
 net/ipv4/netfilter/ipt_ULOG.c           |    8 ++++--
 net/ipv6/exthdrs.c                      |    2 -
 net/ipv6/netfilter/ip6_queue.c          |    6 +++--
 net/ipv6/netfilter/nf_conntrack_reasm.c |    6 ++---
 net/ipv6/reassembly.c                   |    6 ++---
 net/ipx/af_ipx.c                        |    4 +--
 net/netfilter/nfnetlink_log.c           |    8 +++---
 net/netfilter/nfnetlink_queue.c         |    8 +++---
 net/packet/af_packet.c                  |    8 ++++--
 18 files changed, 80 insertions(+), 90 deletions(-)
include/linux/skbuff.h +5 -21
index 4ff3940..24dcbb3 100644
@@ -27,6 +27,7 @@ #include <linux/textsearch.h>
 #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;
 	struct net_device	*input_dev;
 
@@ -1360,26 +1356,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);
 
include/net/sock.h +9 -9
index 2c7d60c..19f6540 100644
@@ -244,7 +244,7 @@ #define sk_prot			__sk_common.skc_prot
 	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 t
 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;
 }
 
 /**
net/bridge/netfilter/ebt_ulog.c +4 -2
index 8e15cc4..259f5c3 100644
@@ -130,6 +130,7 @@ static void ebt_ulog_packet(unsigned int
 	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
 
 	/* 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;
net/compat.c +10 -5
index 1f32866..17c2710 100644
@@ -545,15 +545,20 @@ int compat_sock_get_timestamp(struct soc
 	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;
 }
net/core/dev.c +4 -15
index cf71614..833ca92 100644
@@ -1034,23 +1034,12 @@ void net_disable_timestamp(void)
 	atomic_dec(&netstamp_needed);
 }
 
-void __net_timestamp(struct sk_buff *skb)
-{
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	skb_set_timestamp(skb, &tv);
-}
-EXPORT_SYMBOL(__net_timestamp);
-
 static inline void net_timestamp(struct sk_buff *skb)
 {
 	if (atomic_read(&netstamp_needed))
 		__net_timestamp(skb);
-	else {
-		skb->tstamp.off_sec = 0;
-		skb->tstamp.off_usec = 0;
-	}
+	else
+		skb->tstamp.tv64 = 0;
 }
 
 /*
@@ -1580,7 +1569,7 @@ int netif_rx(struct sk_buff *skb)
 	if (netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstamp.tv64)
 		net_timestamp(skb);
 
 	/*
@@ -1772,7 +1761,7 @@ int netif_receive_skb(struct sk_buff *sk
 	if (skb->dev->poll && netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstamp.tv64)
 		net_timestamp(skb);
 
 	if (!skb->input_dev)
net/core/sock.c +9 -7
index e9986ac..5c50693 100644
@@ -1512,8 +1512,7 @@ #endif
 	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
 	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
 
-	sk->sk_stamp.tv_sec     = -1L;
-	sk->sk_stamp.tv_usec    = -1L;
+	sk->sk_stamp = ktime_set(-1L, -1L);
 
 	atomic_set(&sk->sk_refcnt, 1);
 }
@@ -1554,14 +1553,17 @@ EXPORT_SYMBOL(release_sock);
 
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
+	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 -ENOENT;
-	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
-	return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ?
-		-EFAULT : 0;
+	if (tv.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		tv = ktime_to_timeval(sk->sk_stamp);
+	}
+	return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0;
 }
 EXPORT_SYMBOL(sock_get_timestamp);
 
net/econet/af_econet.c +1 -1
index bc12e36..f573edd 100644
@@ -162,7 +162,7 @@ static int econet_recvmsg(struct kiocb *
 	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
 	if (err)
 		goto out_free;
-	skb_get_timestamp(skb, &sk->sk_stamp);
+	sk->sk_stamp = skb->tstamp;
 
 	if (msg->msg_name)
 		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
net/ipv4/ip_fragment.c +3 -3
index b6f0553..08ff3ff 100644
@@ -92,7 +92,7 @@ #define LAST_IN			1
 	spinlock_t	lock;
 	atomic_t	refcnt;
 	struct timer_list timer;	/* when will this queue expire?		*/
-	struct timeval	stamp;
+	ktime_t		stamp;
 	int             iif;
 	unsigned int    rid;
 	struct inet_peer *peer;
@@ -592,7 +592,7 @@ static void ip_frag_queue(struct ipq *qp
 	if (skb->dev)
 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &qp->stamp);
+	qp->stamp = skb->tstamp;
 	qp->meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
@@ -674,7 +674,7 @@ static struct sk_buff *ip_frag_reasm(str
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &qp->stamp);
+	head->tstamp = qp->stamp;
 
 	iph = head->nh.iph;
 	iph->frag_off = 0;
net/ipv4/netfilter/ip_queue.c +4 -2
index a14798a..5842f1a 100644
@@ -197,6 +197,7 @@ ipq_build_packet_message(struct ipq_queu
 	struct sk_buff *skb;
 	struct ipq_packet_msg *pmsg;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	read_lock_bh(&queue_lock);
 
@@ -241,8 +242,9 @@ ipq_build_packet_message(struct ipq_queu
 
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
-	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	tv = ktime_to_timeval(entry->skb->tstamp);
+	pmsg->timestamp_sec   = tv.tv_sec;
+	pmsg->timestamp_usec  = tv.tv_usec;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
net/ipv4/netfilter/ipt_ULOG.c +5 -3
index a26404d..e78c9d7 100644
@@ -186,6 +186,7 @@ static void ipt_ulog_packet(unsigned int
 	ulog_packet_msg_t *pm;
 	size_t size, copy_len;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	/* ffs == find first bit set, necessary because userspace
 	 * is already shifting groupnumber, but we need unshifted.
@@ -231,13 +232,14 @@ static void ipt_ulog_packet(unsigned int
 	pm = NLMSG_DATA(nlh);
 
 	/* We might not have a timestamp, get one */
-	if (skb->tstamp.off_sec == 0)
+	if (skb->tstamp.tv64 == 0)
 		__net_timestamp((struct sk_buff *)skb);
 
 	/* copy hook, prefix, timestamp, payload, etc. */
 	pm->data_len = copy_len;
-	pm->timestamp_sec = skb->tstamp.off_sec;
-	pm->timestamp_usec = skb->tstamp.off_usec;
+	tv = ktime_to_timeval(skb->tstamp);
+	pm->timestamp_sec = tv.tv_sec;
+	pm->timestamp_usec = tv.tv_usec;
 	pm->mark = skb->mark;
 	pm->hook = hooknum;
 	if (prefix != NULL)
net/ipv6/exthdrs.c +1 -1
index 28e0c65..0dc0ca0 100644
@@ -255,7 +255,7 @@ static int ipv6_dest_hao(struct sk_buff 
 	ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
 	ipv6_addr_copy(&hao->addr, &tmp_addr);
 
-	if (skb->tstamp.off_sec == 0)
+	if (skb->tstamp.tv64 == 0)
 		__net_timestamp(skb);
 
 	return 1;
net/ipv6/netfilter/ip6_queue.c +4 -2
index fdb30a5..66a2c41 100644
@@ -195,6 +195,7 @@ ipq_build_packet_message(struct ipq_queu
 	struct sk_buff *skb;
 	struct ipq_packet_msg *pmsg;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	read_lock_bh(&queue_lock);
 
@@ -239,8 +240,9 @@ ipq_build_packet_message(struct ipq_queu
 
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
-	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	tv = ktime_to_timeval(entry->skb->tstamp);
+	pmsg->timestamp_sec   = tv.tv_sec;
+	pmsg->timestamp_usec  = tv.tv_usec;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
net/ipv6/netfilter/nf_conntrack_reasm.c +3 -3
index 15ab1e3..c311b9a 100644
@@ -82,7 +82,7 @@ struct nf_ct_frag6_queue
 	struct sk_buff		*fragments;
 	int			len;
 	int			meat;
-	struct timeval		stamp;
+	ktime_t			stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -542,7 +542,7 @@ static int nf_ct_frag6_queue(struct nf_c
 		fq->fragments = skb;
 
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	fq->stamp = skb->tstamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &nf_ct_frag6_mem);
 
@@ -648,7 +648,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	head->tstamp = fq->stamp;
 	head->nh.ipv6h->payload_len = htons(payload_len);
 
 	/* Yes, and fold redundant checksum back. 8) */
net/ipv6/reassembly.c +3 -3
index 7034c54..1dde449 100644
@@ -88,7 +88,7 @@ struct frag_queue
 	int			len;
 	int			meat;
 	int			iif;
-	struct timeval		stamp;
+	ktime_t			stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -562,7 +562,7 @@ static void ip6_frag_queue(struct frag_q
 	if (skb->dev)
 		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	fq->stamp = skb->tstamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -663,7 +663,7 @@ static int ip6_frag_reasm(struct frag_qu
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	head->tstamp = fq->stamp;
 	head->nh.ipv6h->payload_len = htons(payload_len);
 	IP6CB(head)->nhoff = nhoff;
 
net/ipx/af_ipx.c +2 -2
index cac35a7..6c6c0a3 100644
@@ -1807,8 +1807,8 @@ #endif	/* CONFIG_IPX_INTERN */
 				     copied);
 	if (rc)
 		goto out_free;
-	if (skb->tstamp.off_sec)
-		skb_get_timestamp(skb, &sk->sk_stamp);
+	if (skb->tstamp.tv64)
+		sk->sk_stamp = skb->tstamp;
 
 	msg->msg_namelen = sizeof(*sipx);
 
net/netfilter/nfnetlink_log.c +4 -4
index b8eab0d..2f7872e 100644
@@ -510,11 +510,11 @@ #endif
 		NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
 	}
 
-	if (skb->tstamp.off_sec) {
+	if (skb->tstamp.tv64) {
 		struct nfulnl_msg_packet_timestamp ts;
-
-		ts.sec = cpu_to_be64(skb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(skb->tstamp.off_usec);
+		struct timeval tv = ktime_to_timeval(skb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
 
 		NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
 	}
net/netfilter/nfnetlink_queue.c +4 -4
index d9ce4a7..cfbee39 100644
@@ -495,11 +495,11 @@ #endif
 		NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
 	}
 
-	if (entskb->tstamp.off_sec) {
+	if (entskb->tstamp.tv64) {
 		struct nfqnl_msg_packet_timestamp ts;
-
-		ts.sec = cpu_to_be64(entskb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(entskb->tstamp.off_usec);
+		struct timeval tv = ktime_to_timeval(entskb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
 
 		NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
 	}
net/packet/af_packet.c +5 -3
index 28d47e8..f9866a8 100644
@@ -582,6 +582,7 @@ static int tpacket_rcv(struct sk_buff *s
 	unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
 	unsigned short macoff, netoff;
 	struct sk_buff *copy_skb = NULL;
+	struct timeval tv;
 
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		goto drop;
@@ -656,12 +657,13 @@ static int tpacket_rcv(struct sk_buff *s
 	h->tp_snaplen = snaplen;
 	h->tp_mac = macoff;
 	h->tp_net = netoff;
-	if (skb->tstamp.off_sec == 0) {
+	if (skb->tstamp.tv64 == 0) {
 		__net_timestamp(skb);
 		sock_enable_timestamp(sk);
 	}
-	h->tp_sec = skb->tstamp.off_sec;
-	h->tp_usec = skb->tstamp.off_usec;
+	tv = ktime_to_timeval(skb->tstamp);
+	h->tp_sec = tv.tv_sec;
+	h->tp_usec = tv.tv_usec;
 
 	sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
 	sll->sll_halen = 0;
#11 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

Quoted 7 lines · On Fri, 2 Mar 2007 15:38:41 +0100 Eric Dumazet <[email protected]> wrote:

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

Quoted 7 lines

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, ...)

This is even better. Also comparing ktime_t's is easier if some code needs to do that.

#12 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

In reply to Eric Dumazet
Quoted 7 lines · On Fri, 2 Mar 2007 15:38:41 +0100 Eric Dumazet <[email protected]> wrote:

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

Quoted 9 lines

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, ...)

You missed a couple of spots.

net/sunrpc/svcsock.c +2 -9
@@ -805,16 +805,9 @@
 		/* possibly an icmp error */
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
-	if (skb->tstamp.off_sec == 0) {
-		struct timeval tv;
 
-		tv.tv_sec = xtime.tv_sec;
-		tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
-		skb_set_timestamp(skb, &tv);
-		/* Don't enable netstamp, sunrpc doesn't
-		   need that much accuracy */
-	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	svsk->sk_sk->sk_stamp = (skb->tstamp.tv64 != 0) ? skb->tstamp
+		: ktime_get_real();
 	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/*
kernel/time.c +2 -0
@@ -469,6 +469,8 @@
 
 	return tv;
 }
+EXPORT_SYMBOL(ns_to_timeval);
+
 
 /*
  * Convert jiffies to milliseconds and back.
Signature · 1 line
Stephen Hemminger <[email protected]>
#13 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

Quoted 9 lines · Stephen Hemminger
Quoted 6 lines · On Fri, 2 Mar 2007 15:38:41 +0100 Eric Dumazet <[email protected]> wrote:

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

Quoted 7 lines
Quoted 5 lines

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, ...)

You missed a couple of spots.

Arg yes...

Quoted 9 lines
net/sunrpc/svcsock.c +0 -2
@@ -805,16 +805,9 @@
 		/* possibly an icmp error */
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
-	if (skb->tstamp.off_sec == 0) {
-		struct timeval tv;

net/sunrpc/svcsock.c line 810

Quoted 10 lines
net/sunrpc/svcsock.c +2 -7
 
-		tv.tv_sec = xtime.tv_sec;
-		tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
-		skb_set_timestamp(skb, &tv);
-		/* Don't enable netstamp, sunrpc doesn't
-		   need that much accuracy */
-	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	svsk->sk_sk->sk_stamp = (skb->tstamp.tv64 != 0) ? skb->tstamp
+		: ktime_get_real();

Well, if we want to stay in the spirit of old code, we probably want to use current_kernel_time() (+ timespec_to_ktime()), because its less expensive.

And also setting the skb tstamp, no ?

maintainer
#14 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

From: Eric Dumazet <[email protected]>
Date: Fri, 02 Mar 2007 23:46:14 +0100

Quoted 4 lines
Quoted 1 line · Stephen Hemminger

You missed a couple of spots.

Arg yes...

...

Quoted 9 lines

net/sunrpc/svcsock.c line 810

Quoted 4 lines
net/sunrpc/svcsock.c +2 -2
-	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	svsk->sk_sk->sk_stamp = (skb->tstamp.tv64 != 0) ? skb->tstamp
+		: ktime_get_real();

Well, if we want to stay in the spirit of old code, we probably want to use current_kernel_time() (+ timespec_to_ktime()), because its less expensive.

And also setting the skb tstamp, no ?

Can you guys cook up an integrated patch with all the missing cases fixed up as desired, so I can add this to net-2.6.22, thanks?

#15 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

Quoted 13 lines · David Miller

From: Eric Dumazet <[email protected]>
Date: Fri, 02 Mar 2007 23:46:14 +0100

Quoted 3 lines
Quoted 1 line · Stephen Hemminger

You missed a couple of spots.

Arg yes...

...

Quoted 6 lines

net/sunrpc/svcsock.c line 810

Quoted 4 lines
net/sunrpc/svcsock.c +2 -2
-	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	svsk->sk_sk->sk_stamp = (skb->tstamp.tv64 != 0) ? skb->tstamp
+		: ktime_get_real();

Well, if we want to stay in the spirit of old code, we probably want to use current_kernel_time() (+ timespec_to_ktime()), because its less expensive.

Quoted 4 lines
Quoted 1 line

And also setting the skb tstamp, no ?

Can you guys cook up an integrated patch with all the missing cases fixed up as desired, so I can add this to net-2.6.22, thanks?

Yes, I will send the patch against net-2.6.22 this morning.

#16 lore raw

PATCH 1/1 NET : convert network timestamps to ktime_t

Hi David

Here is the second version of this patch, including missing bits spoted by Stephen. This is against net-2.6.22

Thank you

[PATCH] 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)

CC Stephen Hemminger <[email protected]>
CC John find <[email protected]>
 include/linux/skbuff.h                  |   26 ++++------------------
 include/net/sock.h                      |   18 +++++++--------
 kernel/time.c                           |    1
 net/bridge/netfilter/ebt_ulog.c         |    6 +++--
 net/compat.c                            |   15 ++++++++----
 net/core/dev.c                          |   19 +++-------------
 net/core/sock.c                         |   16 +++++++------
 net/econet/af_econet.c                  |    2 -
 net/ipv4/ip_fragment.c                  |    8 +++---
 net/ipv4/netfilter/ip_queue.c           |    6 +++--
 net/ipv4/netfilter/ipt_ULOG.c           |    8 ++++--
 net/ipv6/exthdrs.c                      |    2 -
 net/ipv6/netfilter/ip6_queue.c          |    6 +++--
 net/ipv6/netfilter/nf_conntrack_reasm.c |    6 ++---
 net/ipv6/reassembly.c                   |    6 ++---
 net/ipx/af_ipx.c                        |    4 +--
 net/netfilter/nfnetlink_log.c           |    8 +++---
 net/netfilter/nfnetlink_queue.c         |    8 +++---
 net/packet/af_packet.c                  |    8 ++++--
 net/sunrpc/svcsock.c                    |   10 ++------
 20 files changed, 85 insertions(+), 98 deletions(-)
include/linux/skbuff.h +5 -21
index 4ff3940..24dcbb3 100644
@@ -27,6 +27,7 @@ #include <linux/textsearch.h>
 #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;
 	struct net_device	*input_dev;
 
@@ -1360,26 +1356,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);
 
include/net/sock.h +9 -9
index f352d22..59af9fc 100644
@@ -244,7 +244,7 @@ #define sk_prot			__sk_common.skc_prot
 	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 t
 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;
 }
 
 /**
kernel/time.c +1 -0
index c6c80ea..ec5b10c 100644
@@ -469,6 +469,7 @@ struct timeval ns_to_timeval(const s64 n
 
 	return tv;
 }
+EXPORT_SYMBOL(ns_to_timeval);
 
 /*
  * Convert jiffies to milliseconds and back.
net/bridge/netfilter/ebt_ulog.c +4 -2
index 8e15cc4..259f5c3 100644
@@ -130,6 +130,7 @@ static void ebt_ulog_packet(unsigned int
 	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
 
 	/* 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;
net/compat.c +10 -5
index 1f32866..17c2710 100644
@@ -545,15 +545,20 @@ int compat_sock_get_timestamp(struct soc
 	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;
 }
net/core/dev.c +4 -15
index cf71614..833ca92 100644
@@ -1034,23 +1034,12 @@ void net_disable_timestamp(void)
 	atomic_dec(&netstamp_needed);
 }
 
-void __net_timestamp(struct sk_buff *skb)
-{
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	skb_set_timestamp(skb, &tv);
-}
-EXPORT_SYMBOL(__net_timestamp);
-
 static inline void net_timestamp(struct sk_buff *skb)
 {
 	if (atomic_read(&netstamp_needed))
 		__net_timestamp(skb);
-	else {
-		skb->tstamp.off_sec = 0;
-		skb->tstamp.off_usec = 0;
-	}
+	else
+		skb->tstamp.tv64 = 0;
 }
 
 /*
@@ -1580,7 +1569,7 @@ int netif_rx(struct sk_buff *skb)
 	if (netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstamp.tv64)
 		net_timestamp(skb);
 
 	/*
@@ -1772,7 +1761,7 @@ int netif_receive_skb(struct sk_buff *sk
 	if (skb->dev->poll && netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstamp.tv64)
 		net_timestamp(skb);
 
 	if (!skb->input_dev)
net/core/sock.c +9 -7
index 16ef004..95062a7 100644
@@ -1512,8 +1512,7 @@ #endif
 	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
 	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
 
-	sk->sk_stamp.tv_sec     = -1L;
-	sk->sk_stamp.tv_usec    = -1L;
+	sk->sk_stamp = ktime_set(-1L, -1L);
 
 	atomic_set(&sk->sk_refcnt, 1);
 }
@@ -1554,14 +1553,17 @@ EXPORT_SYMBOL(release_sock);
 
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
+	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 -ENOENT;
-	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
-	return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ?
-		-EFAULT : 0;
+	if (tv.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		tv = ktime_to_timeval(sk->sk_stamp);
+	}
+	return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0;
 }
 EXPORT_SYMBOL(sock_get_timestamp);
 
net/econet/af_econet.c +1 -1
index bc12e36..f573edd 100644
@@ -162,7 +162,7 @@ static int econet_recvmsg(struct kiocb *
 	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
 	if (err)
 		goto out_free;
-	skb_get_timestamp(skb, &sk->sk_stamp);
+	sk->sk_stamp = skb->tstamp;
 
 	if (msg->msg_name)
 		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
net/ipv4/ip_fragment.c +4 -4
index b6f0553..e10be7d 100644
@@ -92,7 +92,7 @@ #define LAST_IN			1
 	spinlock_t	lock;
 	atomic_t	refcnt;
 	struct timer_list timer;	/* when will this queue expire?		*/
-	struct timeval	stamp;
+	ktime_t		stamp;
 	int             iif;
 	unsigned int    rid;
 	struct inet_peer *peer;
@@ -592,7 +592,7 @@ static void ip_frag_queue(struct ipq *qp
 	if (skb->dev)
 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &qp->stamp);
+	qp->stamp = skb->tstamp;
 	qp->meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
@@ -674,7 +674,7 @@ static struct sk_buff *ip_frag_reasm(str
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &qp->stamp);
+	head->tstamp = qp->stamp;
 
 	iph = head->nh.iph;
 	iph->frag_off = 0;
@@ -734,7 +734,7 @@ struct sk_buff *ip_defrag(struct sk_buff
 	return NULL;
 }
 
-void ipfrag_init(void)
+void __init ipfrag_init(void)
 {
 	ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
 				 (jiffies ^ (jiffies >> 6)));
net/ipv4/netfilter/ip_queue.c +4 -2
index a14798a..5842f1a 100644
@@ -197,6 +197,7 @@ ipq_build_packet_message(struct ipq_queu
 	struct sk_buff *skb;
 	struct ipq_packet_msg *pmsg;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	read_lock_bh(&queue_lock);
 
@@ -241,8 +242,9 @@ ipq_build_packet_message(struct ipq_queu
 
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
-	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	tv = ktime_to_timeval(entry->skb->tstamp);
+	pmsg->timestamp_sec   = tv.tv_sec;
+	pmsg->timestamp_usec  = tv.tv_usec;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
net/ipv4/netfilter/ipt_ULOG.c +5 -3
index a26404d..e78c9d7 100644
@@ -186,6 +186,7 @@ static void ipt_ulog_packet(unsigned int
 	ulog_packet_msg_t *pm;
 	size_t size, copy_len;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	/* ffs == find first bit set, necessary because userspace
 	 * is already shifting groupnumber, but we need unshifted.
@@ -231,13 +232,14 @@ static void ipt_ulog_packet(unsigned int
 	pm = NLMSG_DATA(nlh);
 
 	/* We might not have a timestamp, get one */
-	if (skb->tstamp.off_sec == 0)
+	if (skb->tstamp.tv64 == 0)
 		__net_timestamp((struct sk_buff *)skb);
 
 	/* copy hook, prefix, timestamp, payload, etc. */
 	pm->data_len = copy_len;
-	pm->timestamp_sec = skb->tstamp.off_sec;
-	pm->timestamp_usec = skb->tstamp.off_usec;
+	tv = ktime_to_timeval(skb->tstamp);
+	pm->timestamp_sec = tv.tv_sec;
+	pm->timestamp_usec = tv.tv_usec;
 	pm->mark = skb->mark;
 	pm->hook = hooknum;
 	if (prefix != NULL)
net/ipv6/exthdrs.c +1 -1
index 28e0c65..0dc0ca0 100644
@@ -255,7 +255,7 @@ static int ipv6_dest_hao(struct sk_buff 
 	ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
 	ipv6_addr_copy(&hao->addr, &tmp_addr);
 
-	if (skb->tstamp.off_sec == 0)
+	if (skb->tstamp.tv64 == 0)
 		__net_timestamp(skb);
 
 	return 1;
net/ipv6/netfilter/ip6_queue.c +4 -2
index fdb30a5..66a2c41 100644
@@ -195,6 +195,7 @@ ipq_build_packet_message(struct ipq_queu
 	struct sk_buff *skb;
 	struct ipq_packet_msg *pmsg;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	read_lock_bh(&queue_lock);
 
@@ -239,8 +240,9 @@ ipq_build_packet_message(struct ipq_queu
 
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
-	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	tv = ktime_to_timeval(entry->skb->tstamp);
+	pmsg->timestamp_sec   = tv.tv_sec;
+	pmsg->timestamp_usec  = tv.tv_usec;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
net/ipv6/netfilter/nf_conntrack_reasm.c +3 -3
index 15ab1e3..c311b9a 100644
@@ -82,7 +82,7 @@ struct nf_ct_frag6_queue
 	struct sk_buff		*fragments;
 	int			len;
 	int			meat;
-	struct timeval		stamp;
+	ktime_t			stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -542,7 +542,7 @@ static int nf_ct_frag6_queue(struct nf_c
 		fq->fragments = skb;
 
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	fq->stamp = skb->tstamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &nf_ct_frag6_mem);
 
@@ -648,7 +648,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	head->tstamp = fq->stamp;
 	head->nh.ipv6h->payload_len = htons(payload_len);
 
 	/* Yes, and fold redundant checksum back. 8) */
net/ipv6/reassembly.c +3 -3
index 7034c54..1dde449 100644
@@ -88,7 +88,7 @@ struct frag_queue
 	int			len;
 	int			meat;
 	int			iif;
-	struct timeval		stamp;
+	ktime_t			stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -562,7 +562,7 @@ static void ip6_frag_queue(struct frag_q
 	if (skb->dev)
 		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	fq->stamp = skb->tstamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -663,7 +663,7 @@ static int ip6_frag_reasm(struct frag_qu
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	head->tstamp = fq->stamp;
 	head->nh.ipv6h->payload_len = htons(payload_len);
 	IP6CB(head)->nhoff = nhoff;
 
net/ipx/af_ipx.c +2 -2
index cac35a7..6c6c0a3 100644
@@ -1807,8 +1807,8 @@ #endif	/* CONFIG_IPX_INTERN */
 				     copied);
 	if (rc)
 		goto out_free;
-	if (skb->tstamp.off_sec)
-		skb_get_timestamp(skb, &sk->sk_stamp);
+	if (skb->tstamp.tv64)
+		sk->sk_stamp = skb->tstamp;
 
 	msg->msg_namelen = sizeof(*sipx);
 
net/netfilter/nfnetlink_log.c +4 -4
index b8eab0d..2f7872e 100644
@@ -510,11 +510,11 @@ #endif
 		NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
 	}
 
-	if (skb->tstamp.off_sec) {
+	if (skb->tstamp.tv64) {
 		struct nfulnl_msg_packet_timestamp ts;
-
-		ts.sec = cpu_to_be64(skb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(skb->tstamp.off_usec);
+		struct timeval tv = ktime_to_timeval(skb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
 
 		NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
 	}
net/netfilter/nfnetlink_queue.c +4 -4
index d9ce4a7..cfbee39 100644
@@ -495,11 +495,11 @@ #endif
 		NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
 	}
 
-	if (entskb->tstamp.off_sec) {
+	if (entskb->tstamp.tv64) {
 		struct nfqnl_msg_packet_timestamp ts;
-
-		ts.sec = cpu_to_be64(entskb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(entskb->tstamp.off_usec);
+		struct timeval tv = ktime_to_timeval(entskb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
 
 		NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
 	}
net/packet/af_packet.c +5 -3
index 28d47e8..f9866a8 100644
@@ -582,6 +582,7 @@ static int tpacket_rcv(struct sk_buff *s
 	unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
 	unsigned short macoff, netoff;
 	struct sk_buff *copy_skb = NULL;
+	struct timeval tv;
 
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		goto drop;
@@ -656,12 +657,13 @@ static int tpacket_rcv(struct sk_buff *s
 	h->tp_snaplen = snaplen;
 	h->tp_mac = macoff;
 	h->tp_net = netoff;
-	if (skb->tstamp.off_sec == 0) {
+	if (skb->tstamp.tv64 == 0) {
 		__net_timestamp(skb);
 		sock_enable_timestamp(sk);
 	}
-	h->tp_sec = skb->tstamp.off_sec;
-	h->tp_usec = skb->tstamp.off_usec;
+	tv = ktime_to_timeval(skb->tstamp);
+	h->tp_sec = tv.tv_sec;
+	h->tp_usec = tv.tv_usec;
 
 	sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
 	sll->sll_halen = 0;
net/sunrpc/svcsock.c +3 -7
index 63ae947..a90e57a 100644
@@ -805,16 +805,12 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
 		/* possibly an icmp error */
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
-	if (skb->tstamp.off_sec == 0) {
-		struct timeval tv;
-
-		tv.tv_sec = xtime.tv_sec;
-		tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
-		skb_set_timestamp(skb, &tv);
+	if (skb->tstamp.tv64 == 0) {
+		skb->tstamp = ktime_get_real();
 		/* Don't enable netstamp, sunrpc doesn't
 		   need that much accuracy */
 	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	svsk->sk_sk->sk_stamp = skb->tstamp;
 	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/*
maintainer Applied
#17 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

From: Eric Dumazet <[email protected]>
Date: Mon, 05 Mar 2007 08:40:03 +0100

Quoted 2 lines

Here is the second version of this patch, including missing bits spoted by Stephen. This is against net-2.6.22

Applied, thanks a lot.

Quoted 3 lines

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)

Grrr, good spotting. Eric can you send me a version of just this bug fix against 2.6.21? I'll push that to Linus and 2.6.x-stable.

I guess most applications don't even bother to check the getsockopt() return value. :-)

Thanks a lot!

#18 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

Quoted 5 lines · David Miller

From: Eric Dumazet <[email protected]>
Date: Mon, 05 Mar 2007 08:40:03 +0100

Quoted 1 line

Here is the second version of this patch, including missing bits spoted by Stephen. This is against net-2.6.22

Quoted 8 lines

Applied, thanks a lot.

Quoted 3 lines

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)

Grrr, good spotting. Eric can you send me a version of just this bug fix against 2.6.21? I'll push that to Linus and 2.6.x-stable.

Yes I will do it. But, are your sure its really used ?

I dont know very much this compat stuff, but I found compat_sock_get_timestamp() only called from net/x25/af_x25.c

I wonder how a 32 bit task on x86_64 can enter this compat code on other sockets ?

maintainer
#19 lore raw

Re: [PATCH] NET : convert network timestamps to ktime_t

From: Eric Dumazet <[email protected]>
Date: Mon, 05 Mar 2007 09:21:30 +0100

Quoted 2 lines

I dont know very much this compat stuff, but I found compat_sock_get_timestamp() only called from net/x25/af_x25.c

Good point, I thought for some reason that this function was used for all SO_TIMESTAMP handling, but looking again I see that the main stuff is handled in put_cmsg() compat code.

#20 lore raw

PATCH 1/1 NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

In reply to Eric Dumazet

Hi David

This patch is for net-2.6.22 git tree.

A separate patch will follow for SO_TIMESTAMPNS / SCM_TIMESTAMPNS support.

Thank you

[PATCH] NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

Now network timestamps use ktime_t infrastructure, we can add a new ioctl() SIOCGSTAMPNS command to get timestamps in 'struct timespec'. User programs can thus access to nanosecond resolution.

CC Stephen Hemminger <[email protected]>
 fs/compat_ioctl.c             |   18 ++++++++++++++++++
 include/asm-alpha/sockios.h   |    3 ++-
 include/asm-arm/sockios.h     |    3 ++-
 include/asm-arm26/sockios.h   |    3 ++-
 include/asm-avr32/sockios.h   |    3 ++-
 include/asm-cris/sockios.h    |    3 ++-
 include/asm-frv/sockios.h     |    3 ++-
 include/asm-h8300/sockios.h   |    3 ++-
 include/asm-i386/sockios.h    |    3 ++-
 include/asm-ia64/sockios.h    |    3 ++-
 include/asm-m32r/sockios.h    |    3 ++-
 include/asm-m68k/sockios.h    |    3 ++-
 include/asm-mips/sockios.h    |    3 ++-
 include/asm-parisc/sockios.h  |    3 ++-
 include/asm-powerpc/sockios.h |    3 ++-
 include/asm-s390/sockios.h    |    3 ++-
 include/asm-sh/sockios.h      |    3 ++-
 include/asm-sh64/sockios.h    |    3 ++-
 include/asm-sparc/sockios.h   |    3 ++-
 include/asm-sparc64/sockios.h |    3 ++-
 include/asm-v850/sockios.h    |    3 ++-
 include/asm-x86_64/sockios.h  |    3 ++-
 include/asm-xtensa/sockios.h  |    3 ++-
 include/net/compat.h          |    1 +
 include/net/sock.h            |    1 +
 net/appletalk/ddp.c           |    3 +++
 net/atm/ioctl.c               |    3 +++
 net/ax25/af_ax25.c            |    4 ++++
 net/compat.c                  |   24 ++++++++++++++++++++++++
 net/core/sock.c               |   16 ++++++++++++++++
 net/econet/af_econet.c        |    3 +++
 net/ipv4/af_inet.c            |    3 +++
 net/ipv6/af_inet6.c           |    3 +++
 net/netrom/af_netrom.c        |    6 ++++++
 net/packet/af_packet.c        |    2 ++
 net/rose/af_rose.c            |    3 +++
 net/wanrouter/af_wanpipe.c    |    3 +++
 net/x25/af_x25.c              |   12 ++++++++++++
 38 files changed, 149 insertions(+), 22 deletions(-)
fs/compat_ioctl.c +18 -0
index c81c958..e9e5965 100644
@@ -266,6 +266,23 @@ static int do_siocgstamp(unsigned int fd
 	return err;
 }
 
+static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct compat_timespec __user *up = compat_ptr(arg);
+	struct timespec kts;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kts);
+	set_fs(old_fs);
+	if (!err) {
+		err = put_user(kts.tv_sec, &up->tv_sec);
+		err |= __put_user(kts.tv_nsec, &up->tv_nsec);
+	}
+	return err;
+}
+
 struct ifmap32 {
 	compat_ulong_t mem_start;
 	compat_ulong_t mem_end;
@@ -2437,6 +2454,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns)
 #endif
 #ifdef CONFIG_BLOCK
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
include/asm-alpha/sockios.h +2 -1
index e4961a7..7932c7a 100644
@@ -10,6 +10,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_ALPHA_SOCKIOS_H */
include/asm-arm/sockios.h +2 -1
index 77c3408..a2588a2 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-arm26/sockios.h +2 -1
index 77c3408..a2588a2 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-avr32/sockios.h +2 -1
index 84f3d65..0802d74 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ASM_AVR32_SOCKIOS_H */
include/asm-cris/sockios.h +2 -1
index 6c4012f..cfe7bfe 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-frv/sockios.h +2 -1
index 8a6e4b2..5dbdd13 100644
@@ -7,7 +7,8 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS__ */
 
include/asm-h8300/sockios.h +2 -1
index d005d95..e9c7ec8 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_H8300_SOCKIOS__ */
include/asm-i386/sockios.h +2 -1
index 6b747f8..ff528c7 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-ia64/sockios.h +2 -1
index cf94857..15c9246 100644
@@ -14,6 +14,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_IA64_SOCKIOS_H */
include/asm-m32r/sockios.h +2 -1
index f89962e..6c1fb9b 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif  /* _ASM_M32R_SOCKIOS_H */
include/asm-m68k/sockios.h +2 -1
index 9b9ed97..c04a239 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_M68K_SOCKIOS__ */
include/asm-mips/sockios.h +2 -1
index 87a50bf..ed1a5f7 100644
@@ -20,6 +20,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS_H */
include/asm-parisc/sockios.h +2 -1
index aace496..dabfbc7 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-powerpc/sockios.h +2 -1
index 590078d..55cef76 100644
@@ -14,6 +14,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _ASM_POWERPC_SOCKIOS_H */
include/asm-s390/sockios.h +2 -1
index 412aeb4..f4fc16c 100644
@@ -15,6 +15,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-sh/sockios.h +2 -1
index 08a71df..cf8b96b 100644
@@ -9,5 +9,6 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp (timespec) */
 #endif /* __ASM_SH_SOCKIOS_H */
include/asm-sh64/sockios.h +2 -1
index 1ae23ae..419e76f 100644
@@ -20,5 +20,6 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp (timespec) */
 #endif /* __ASM_SH64_SOCKIOS_H */
include/asm-sparc/sockios.h +2 -1
index 0c01b59..990ea74 100644
@@ -7,7 +7,8 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC_SOCKIOS_H) */
 
include/asm-sparc64/sockios.h +2 -1
index 6735bab..c7d9900 100644
@@ -7,7 +7,8 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC64_SOCKIOS_H) */
 
include/asm-v850/sockios.h +2 -1
index cf4874c..823e106 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __V850_SOCKIOS_H__ */
include/asm-x86_64/sockios.h +2 -1
index 2eefd10..d726ba2 100644
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-xtensa/sockios.h +2 -1
index 20d2ba1..efe0af3 100644
@@ -25,6 +25,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _XTENSA_SOCKIOS_H */
include/net/compat.h +1 -0
index 9859b60..406db24 100644
@@ -25,6 +25,7 @@ struct compat_cmsghdr {
 };
 
 extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
 
 #else /* defined(CONFIG_COMPAT) */
 #define compat_msghdr	msghdr		/* to avoid compiler warnings */
include/net/sock.h +1 -0
index 2974bac..d093e49 100644
@@ -1329,6 +1329,7 @@ #endif
 
 extern void sock_enable_timestamp(struct sock *sk);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int sock_get_timestampns(struct sock *, struct timespec __user *);
 
 /* 
  *	Enable debug/info messages 
net/appletalk/ddp.c +3 -0
index 113c175..53247be 100644
@@ -1768,6 +1768,9 @@ static int atalk_ioctl(struct socket *so
 		case SIOCGSTAMP:
 			rc = sock_get_timestamp(sk, argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = sock_get_timestampns(sk, argp);
+			break;
 		/* Routing */
 		case SIOCADDRT:
 		case SIOCDELRT:
net/atm/ioctl.c +3 -0
index 8ccee45..7afd8e7 100644
@@ -82,6 +82,9 @@ int vcc_ioctl(struct socket *sock, unsig
 		case SIOCGSTAMP: /* borrowed from IP */
 			error = sock_get_timestamp(sk, argp);
 			goto done;
+		case SIOCGSTAMPNS: /* borrowed from IP */
+			error = sock_get_timestampns(sk, argp);
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
 			error = 0;
net/ax25/af_ax25.c +4 -0
index 1c07c6a..62605dc 100644
@@ -1711,6 +1711,10 @@ static int ax25_ioctl(struct socket *soc
 		res = sock_get_timestamp(sk, argp);
 		break;
 
+	case SIOCGSTAMPNS:
+		res = sock_get_timestampns(sk, argp);
+		break;
+
 	case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */
 	case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */
 	case SIOCAX25GETUID: {
net/compat.c +24 -0
index 17c2710..2fc6d9b 100644
@@ -564,6 +564,30 @@ int compat_sock_get_timestamp(struct soc
 }
 EXPORT_SYMBOL(compat_sock_get_timestamp);
 
+int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	struct compat_timespec __user *ctv =
+			(struct compat_timespec __user*) userstamp;
+	int err = -ENOENT;
+	struct timespec ts;
+
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	ts = ktime_to_timespec(sk->sk_stamp);
+	if (ts.tv_sec == -1)
+		return err;
+	if (ts.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		ts = ktime_to_timespec(sk->sk_stamp);
+	}
+	err = 0;
+	if (put_user(ts.tv_sec, &ctv->tv_sec) ||
+			put_user(ts.tv_nsec, &ctv->tv_nsec))
+		err = -EFAULT;
+	return err;
+}
+EXPORT_SYMBOL(compat_sock_get_timestampns);
+
 asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
net/core/sock.c +16 -0
index 6c92ec4..c1fc8cc 100644
@@ -1567,6 +1567,22 @@ int sock_get_timestamp(struct sock *sk, 
 }
 EXPORT_SYMBOL(sock_get_timestamp);
 
+int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	struct timespec ts;
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	ts = ktime_to_timespec(sk->sk_stamp);
+	if (ts.tv_sec == -1)
+		return -ENOENT;
+	if (ts.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		ts = ktime_to_timespec(sk->sk_stamp);
+	}
+	return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(sock_get_timestampns);
+
 void sock_enable_timestamp(struct sock *sk)
 {
 	if (!sock_flag(sk, SOCK_TIMESTAMP)) {
net/econet/af_econet.c +3 -0
index f573edd..487f879 100644
@@ -727,6 +727,9 @@ static int econet_ioctl(struct socket *s
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, argp);
 
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, argp);
+
 		case SIOCSIFADDR:
 		case SIOCGIFADDR:
 			return ec_dev_ioctl(sock, cmd, argp);
net/ipv4/af_inet.c +3 -0
index cf358c8..df41856 100644
@@ -755,6 +755,9 @@ int inet_ioctl(struct socket *sock, unsi
 		case SIOCGSTAMP:
 			err = sock_get_timestamp(sk, (struct timeval __user *)arg);
 			break;
+		case SIOCGSTAMPNS:
+			err = sock_get_timestampns(sk, (struct timespec __user *)arg);
+			break;
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCRTMSG:
net/ipv6/af_inet6.c +3 -0
index fed3758..2ff0704 100644
@@ -443,6 +443,9 @@ int inet6_ioctl(struct socket *sock, uns
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 	case SIOCADDRT:
 	case SIOCDELRT:
 
net/netrom/af_netrom.c +6 -0
index bf9837d..a54e7ef 100644
@@ -1209,6 +1209,12 @@ static int nr_ioctl(struct socket *sock,
 		release_sock(sk);
 		return ret;
 
+	case SIOCGSTAMPNS:
+		lock_sock(sk);
+		ret = sock_get_timestampns(sk, argp);
+		release_sock(sk);
+		return ret;
+
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
net/packet/af_packet.c +2 -0
index f9866a8..6f8c72d 100644
@@ -1545,6 +1545,8 @@ static int packet_ioctl(struct socket *s
 		}
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
 
 #ifdef CONFIG_INET
 		case SIOCADDRT:
net/rose/af_rose.c +3 -0
index 8c34f1c..8fa7e47 100644
@@ -1272,6 +1272,9 @@ static int rose_ioctl(struct socket *soc
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *) argp);
 
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *) argp);
+
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
net/wanrouter/af_wanpipe.c +3 -0
index 41d7e32..02c09e7 100644
@@ -1770,6 +1770,9 @@ static int wanpipe_ioctl(struct socket *
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 		case SIOC_WANPIPE_CHECK_TX:
 
 			return atomic_read(&sk->sk_wmem_alloc);
net/x25/af_x25.c +12 -0
index e62ba41..a198843 100644
@@ -1280,6 +1280,12 @@ static int x25_ioctl(struct socket *sock
 				rc = sock_get_timestamp(sk,
 						(struct timeval __user *)argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = -EINVAL;
+			if (sk)
+				rc = sock_get_timestampns(sk,
+						(struct timespec __user *)argp);
+			break;
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -1521,6 +1527,12 @@ static int compat_x25_ioctl(struct socke
 			rc = compat_sock_get_timestamp(sk,
 					(struct timeval __user*)argp);
 		break;
+	case SIOCGSTAMPNS:
+		rc = -EINVAL;
+		if (sk)
+			rc = compat_sock_get_timestampns(sk,
+					(struct timespec __user*)argp);
+		break;
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
#21 lore raw

Re: [PATCH] NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

include/asm-mips/sockios.h #define SIOCATMARK _IOR('s', 7, int) · line 24

Quoted 9 lines · Eric Dumazet
include/asm-mips/sockios.h +2 -1
@@ -20,6 +20,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */

You might want to CC linux-arch or the architecture maintainers. Last time I changed something in this area I got complaints because it affected syscall emulation for non-Linux binaries or something like that.

#22 lore raw

Re: [PATCH] NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

Quoted 7 lines · Patrick McHardy
Quoted 6 lines · Eric Dumazet
include/asm-mips/sockios.h +0 -0
@@ -20,6 +20,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
Quoted 8 lines

include/asm-mips/sockios.h #define SIOCATMARK _IOR('s', 7, int) · line 24

Quoted 3 lines
include/asm-mips/sockios.h +2 -1
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */

You might want to CC linux-arch or the architecture maintainers. Last time I changed something in this area I got complaints because it affected syscall emulation for non-Linux binaries or something like that.

I really dont see how this change could break syscall emulation for non-Linux binaries. SIOCGSTAMP{NS} is linux specific.

Could you please give the context of your past problems ?

Thank you

#23 lore raw

Re: [PATCH] NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

Quoted 17 lines · Eric Dumazet
Quoted 6 lines · Patrick McHardy
Quoted 6 lines
include/asm-mips/sockios.h +0 -0
@@ -20,6 +20,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
Quoted 8 lines

include/asm-mips/sockios.h #define SIOCATMARK _IOR('s', 7, int) · line 24

Quoted 3 lines
include/asm-mips/sockios.h +2 -1
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */

You might want to CC linux-arch or the architecture maintainers. Last time I changed something in this area I got complaints because it affected syscall emulation for non-Linux binaries or something like that.

Quoted 4 lines

I really dont see how this change could break syscall emulation for non-Linux binaries. SIOCGSTAMP{NS} is linux specific.

Could you please give the context of your past problems ?

It was when I added the SO_SNDBUFFORCE/SO_RCVBUFFORCE setsockopt options. IIRC the values I chose where already used differently for non-Linux MIPS binaries.

maintainer Applied
#24 lore raw

Re: [PATCH] NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

In reply to Eric Dumazet

From: Eric Dumazet <[email protected]>
Date: Thu, 8 Mar 2007 15:17:57 +0100

Quoted 9 lines

[PATCH] NET : Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution

Now network timestamps use ktime_t infrastructure, we can add a new ioctl() SIOCGSTAMPNS command to get timestamps in 'struct timespec'. User programs can thus access to nanosecond resolution.

CC Stephen Hemminger <[email protected]>

Applied, thanks Eric.

This patch points out a potential compat layer problem which sh64. It defines the SIOCGSTAMP (and not SIOCGSTAMPNS) ioctls as not constants, but rather constant values that depend upon the size of the structure passed in.

But the compat bridges for these timestamp ioctls simply match on the native ioctl value and then pass it in unchanged to the real handler. That won't work for sh64 compat layer for 32-bit sh applications.

That's what they get for being different :-)

#25 lore raw

PATCH 1/1 NET : Adding SO_TIMESTAMPNS / SCM_TIMESTAMPNS support

In reply to Eric Dumazet

Hi David

This patch is against net-2.6.22 git tree.

Thank you

[PATCH] NET : Adding SO_TIMESTAMPNS / SCM_TIMESTAMPNS support

Now that network timestamps use ktime_t infrastructure, we can add a new SOL_SOCKET sockopt SO_TIMESTAMPNS.

This command is similar to SO_TIMESTAMP, but permits transmission of a 'timespec struct' instead of a 'timeval struct' control message. (nanosecond resolution instead of microsecond)

Control message is labelled SCM_TIMESTAMPNS instead of SCM_TIMESTAMP

A socket cannot mix SO_TIMESTAMP and SO_TIMESTAMPNS : the two modes are mutually exclusive.

sock_recv_timestamp() became too big to be fully inlined so I added a __sock_recv_timestamp() helper function.

include/net/sock.h +7 -10
index 5124657..390c047 100644
@@ -390,6 +390,7 @@ enum sock_flags {
 	SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */
 	SOCK_DBG, /* %SO_DEBUG setting */
 	SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */
+	SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */
 	SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */
 	SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */
 };
@@ -1283,21 +1284,17 @@ static inline int sock_intr_errno(long t
 	return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR;
 }
 
+extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
+	struct sk_buff *skb);
+
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
 	ktime_t kt = skb->tstamp;
 
-	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 (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
+	if (sock_flag(sk, SOCK_RCVTSTAMP))
+		__sock_recv_timestamp(msg, sk, skb);
+	else
 		sk->sk_stamp = kt;
 }
 
net/compat.c +9 -1
index 0e40756..9a0f5f2 100644
@@ -215,6 +215,7 @@ Efault:
 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 {
 	struct compat_timeval ctv;
+	struct compat_timespec cts;
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
@@ -229,7 +230,14 @@ int put_cmsg_compat(struct msghdr *kmsg,
 		ctv.tv_sec = tv->tv_sec;
 		ctv.tv_usec = tv->tv_usec;
 		data = &ctv;
-		len = sizeof(struct compat_timeval);
+		len = sizeof(ctv);
+	}
+	if (level == SOL_SOCKET && type == SO_TIMESTAMPNS) {
+		struct timespec *ts = (struct timespec *)data;
+		cts.tv_sec = ts->tv_sec;
+		cts.tv_nsec = ts->tv_nsec;
+		data = &cts;
+		len = sizeof(cts);
 	}
 
 	cmlen = CMSG_COMPAT_LEN(len);
net/core/sock.c +14 -2
index a016661..d4c89f8 100644
@@ -521,11 +521,18 @@ #endif
 		break;
 
 	case SO_TIMESTAMP:
+	case SO_TIMESTAMPNS:
 		if (valbool)  {
+			if (optname == SO_TIMESTAMP)
+				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+			else
+				sock_set_flag(sk, SOCK_RCVTSTAMPNS);
 			sock_set_flag(sk, SOCK_RCVTSTAMP);
 			sock_enable_timestamp(sk);
-		} else
+		} else {
 			sock_reset_flag(sk, SOCK_RCVTSTAMP);
+			sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+		}
 		break;
 
 	case SO_RCVLOWAT:
@@ -715,7 +722,12 @@ int sock_getsockopt(struct socket *sock,
 		break;
 
 	case SO_TIMESTAMP:
-		v.val = sock_flag(sk, SOCK_RCVTSTAMP);
+		v.val = sock_flag(sk, SOCK_RCVTSTAMP) &&
+				!sock_flag(sk, SOCK_RCVTSTAMPNS);
+		break;
+
+	case SO_TIMESTAMPNS:
+		v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);
 		break;
 
 	case SO_RCVTIMEO:
net/socket.c +29 -0
index 724b9cd..15e4327 100644
@@ -585,6 +585,35 @@ int kernel_sendmsg(struct socket *sock, 
 	return result;
 }
 
+/*
+ * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
+ */
+void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
+	struct sk_buff *skb)
+{
+	ktime_t kt = skb->tstamp;
+
+	if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
+		struct timeval tv;
+		/* Race occurred between timestamp enabling and packet
+		   receiving.  Fill in the current time for now. */
+		if (kt.tv64 == 0)
+			kt = ktime_get_real();
+		skb->tstamp = kt;
+		tv = ktime_to_timeval(kt);
+		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv);
+	} else {
+		struct timespec ts;
+		/* Race occurred between timestamp enabling and packet
+		   receiving.  Fill in the current time for now. */
+		if (kt.tv64 == 0)
+			kt = ktime_get_real();
+		skb->tstamp = kt;
+		ts = ktime_to_timespec(kt);
+		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(ts), &ts);
+	}
+}
+
 static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 				 struct msghdr *msg, size_t size, int flags)
 {
include/asm-alpha/socket.h +2 -0
index d22ab97..1fede7f 100644
@@ -52,6 +52,8 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		30
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		19
include/asm-arm/socket.h +2 -0
index 19f7df7..65a1a64 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-arm26/socket.h +2 -0
index 19f7df7..65a1a64 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-avr32/socket.h +2 -0
index 543229d..a0d0507 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __ASM_AVR32_SOCKET_H */
include/asm-cris/socket.h +2 -0
index 01cfdf1..5b18dfd 100644
@@ -51,6 +51,8 @@ #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
 
include/asm-frv/socket.h +2 -0
index 31db18f..a823bef 100644
@@ -49,6 +49,8 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
 
include/asm-h8300/socket.h +2 -0
index ebc830f..39911d8 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-i386/socket.h +2 -0
index 5755d57..99ca648 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-ia64/socket.h +2 -0
index d638ef3..9e42ce4 100644
@@ -58,5 +58,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_IA64_SOCKET_H */
include/asm-m32r/socket.h +2 -0
index acdf748..793d5d3 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_M32R_SOCKET_H */
include/asm-m68k/socket.h +2 -0
index a5966ec..6d21b90 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-mips/socket.h +2 -0
index 36ebe4e..9594568 100644
@@ -70,6 +70,8 @@ #define SO_PEERSEC		30
 #define SO_SNDBUFFORCE		31
 #define SO_RCVBUFFORCE		33
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #ifdef __KERNEL__
 
include/asm-parisc/socket.h +2 -0
index ce2eae1..99e868f 100644
@@ -33,6 +33,8 @@ #define SO_PASSCRED	0x4010
 #define SO_PEERCRED	0x4011
 #define SO_TIMESTAMP	0x4012
 #define SCM_TIMESTAMP	SO_TIMESTAMP
+#define SO_TIMESTAMPNS	0x4013
+#define SCM_TIMESTAMPNS	SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x4016
include/asm-powerpc/socket.h +2 -0
index c8b1da5..403e9fd 100644
@@ -56,5 +56,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif	/* _ASM_POWERPC_SOCKET_H */
include/asm-s390/socket.h +2 -0
index 1778a49..1161ebe 100644
@@ -57,5 +57,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-sh/socket.h +2 -0
index ca70362..c48d6fc 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __ASM_SH_SOCKET_H */
include/asm-sparc/socket.h +2 -0
index f6c4e5b..d77768e 100644
@@ -49,6 +49,8 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
+#define SO_TIMESTAMPNS		0x0020
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
include/asm-sparc64/socket.h +2 -0
index 754d46a..1bd9f52 100644
@@ -49,6 +49,8 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
+#define SO_TIMESTAMPNS		0x0020
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
include/asm-v850/socket.h +2 -0
index 0dfe55a..a4c2493 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __V850_SOCKET_H__ */
include/asm-x86_64/socket.h +2 -0
index b467026..90af60c 100644
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-xtensa/socket.h +2 -0
index 971d231..1f5aeac 100644
@@ -60,5 +60,7 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 #define SO_ACCEPTCONN		30
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif	/* _XTENSA_SOCKET_H */
maintainer Applied
#26 lore raw

Re: [PATCH] NET : Adding SO_TIMESTAMPNS / SCM_TIMESTAMPNS support

From: Eric Dumazet <[email protected]>
Date: Fri, 9 Mar 2007 19:39:42 +0100

Quoted 11 lines

[PATCH] NET : Adding SO_TIMESTAMPNS / SCM_TIMESTAMPNS support

Now that network timestamps use ktime_t infrastructure, we can add a new SOL_SOCKET sockopt SO_TIMESTAMPNS.

This command is similar to SO_TIMESTAMP, but permits transmission of a 'timespec struct' instead of a 'timeval struct' control message. (nanosecond resolution instead of microsecond)

Control message is labelled SCM_TIMESTAMPNS instead of SCM_TIMESTAMP

Quoted 9 lines

A socket cannot mix SO_TIMESTAMP and SO_TIMESTAMPNS : the two modes are mutually exclusive.

sock_recv_timestamp() became too big to be fully inlined so I added a __sock_recv_timestamp() helper function.

Applied, thanks for following up on all of this nanosecond timestamp work.

#27 lore raw
In reply to Eric Dumazet
Quoted 29 lines · On Thu, 1 Mar 2007 12:30:50 +0100 Eric Dumazet <[email protected]> wrote:
Quoted 7 lines · John

Consider an idle Linux 2.6.20-rt8 system, equipped with a single PCI-E gigabit Ethernet NIC, running on a modern CPU (e.g. Core 2 Duo E6700). All this system does is time stamp 1000 packets per second.

Are you claiming that this platform *cannot* handle most packets within less than 1 microsecond of their arrival?

Yes I claim it.

You expect too much of this platform, unless "most" means 10 % for you ;)

If you replace "1 us" by "50 us", then yes, it probably can do it, if "most" means 99%, (not 99.999 %)

Anyway, if you want to play, you can apply this patch on top of linux-2.6.21-rc2 (nanosecond resolution infrastruture needs 2.6.21) I let you do the adjustments for rt kernel.

I compiled it on my i386 machine, and tested it with a patched libpcap/tcpdump

[PATCH] NET : introduce nanosecond time infrastructure and SIOCGSTAMPNS

It appears some machines are *really* fast and that micro second resolution is a limiting factor.

Quoted 7 lines

This patch converts sk_buff timestamp to use new nanosecond infra (added in 2.6.21), and introduces a new ioctl SIOCGSTAMPNS to let applications access nanosecond resolution (ie a timespec instead of timeval)

You probably want to add a SO_TIMESTAMPNS setsockopt() value like existing SO_TIMESTAMP

Also use NSEC_PER_USEC rather than hardcoded 1000.

Signature · 1 line
Stephen Hemminger <[email protected]>
#28 lore raw
Quoted 2 lines · Stephen Hemminger

You probably want to add a SO_TIMESTAMPNS setsockopt() value like existing SO_TIMESTAMP

You mean an alias like this ?

#define SO_TIMESTAMPNS SO_TIMESTAMP

Or should we really use another value ?

Quoted 4 lines

Also use NSEC_PER_USEC rather than hardcoded 1000.

Yes I will resubmit a patch including your suggestions (I discovered some missing bits after a make allyesconfig)

Thank you

#29 lore raw
Quoted 10 lines · On Fri, 02 Mar 2007 00:14:37 +0100 Eric Dumazet <[email protected]> wrote:
Quoted 2 lines · Stephen Hemminger

You probably want to add a SO_TIMESTAMPNS setsockopt() value like existing SO_TIMESTAMP

You mean an alias like this ?

#define SO_TIMESTAMPNS SO_TIMESTAMP

Or should we really use another value ?

Another value since if someone turns on SO_TIMESTAMP they want usec (timeval) and SO_TIMESTAMPNS would be for nanosecond values. Trying to set both flags would be not allowed.

- original -

If the SO_TIMESTAMP option is enabled on a SOCK_DGRAM socket, the recvmsg(2) call will return a timestamp corresponding to when the data- gram was received. The msg_control field in the msghdr structure points to a buffer that contains a cmsghdr structure followed by a struct timeval. The cmsghdr fields have the following values:

cmsg_len = sizeof(struct timeval)
cmsg_level = SOL_SOCKET
cmsg_type = SCM_TIMESTAMP

- add -
If the SO_TIMESTAMPNS option is enabled on a SOCK_DGRAM socket,
...
cmsg_len = sizeof(struct timespec)
cmsg_level = SOL_SOCKET
cmsg_type = SCM_TIMESTAMPNS

Signature · 1 line
Stephen Hemminger <[email protected]>
#30 lore raw
Quoted 16 lines · Stephen Hemminger

Another value since if someone turns on SO_TIMESTAMP they want usec (timeval) and SO_TIMESTAMPNS would be for nanosecond values. Trying to set both flags would be not allowed.

- original -

If the SO_TIMESTAMP option is enabled on a SOCK_DGRAM socket, the recvmsg(2) call will return a timestamp corresponding to when the data- gram was received. The msg_control field in the msghdr structure points to a buffer that contains a cmsghdr structure followed by a struct timeval. The cmsghdr fields have the following values:

cmsg_len = sizeof(struct timeval)
cmsg_level = SOL_SOCKET
cmsg_type = SCM_TIMESTAMP

Quoted 6 lines

- add -
If the SO_TIMESTAMPNS option is enabled on a SOCK_DGRAM socket,
...
cmsg_len = sizeof(struct timespec)
cmsg_level = SOL_SOCKET
cmsg_type = SCM_TIMESTAMPNS

I got it now, thank you :)

Here is the second version of the patch.

[NET] : introduce nanosecond time infrastructure for packet timestamping

It appears some machines are *really* fast and that micro second resolution is a limiting factor.

This patch converts sk_buff timestamp to use new nanosecond infra (added in 2.6.21), and introduces a new ioctl SIOCGSTAMPNS to let applications access nanosecond resolution (ie a timespec instead of timeval)

SO_TIMESTAMPNS is also introduced so that a recvmsg() on SOCK_DGRAM socket may
transfer a struct timespec (cmsg_type = SCM_TIMESTAMPNS). SO_TIMESTAMP and
SO_TIMESTAMPNS are mutually exclusive.

 fs/compat_ioctl.c                       |   17 +++++++++
 include/asm-alpha/socket.h              |    2 +
 include/asm-alpha/sockios.h             |    1
 include/asm-arm/socket.h                |    2 +
 include/asm-arm26/socket.h              |    2 +
 include/asm-arm26/sockios.h             |    3 +
 include/asm-avr32/socket.h              |    2 +
 include/asm-avr32/sockios.h             |    3 +
 include/asm-cris/sockios.h              |    3 +
 include/asm-frv/socket.h                |    2 +
 include/asm-frv/sockios.h               |    3 +
 include/asm-h8300/socket.h              |    2 +
 include/asm-h8300/sockios.h             |    3 +
 include/asm-i386/socket.h               |    2 +
 include/asm-i386/sockios.h              |    3 +
 include/asm-ia64/socket.h               |    2 +
 include/asm-ia64/sockios.h              |    3 +
 include/asm-m32r/socket.h               |    2 +
 include/asm-m32r/sockios.h              |    3 +
 include/asm-m68k/socket.h               |    2 +
 include/asm-m68k/sockios.h              |    3 +
 include/asm-mips/socket.h               |    2 +
 include/asm-mips/sockios.h              |    3 +
 include/asm-parisc/socket.h             |    2 +
 include/asm-parisc/sockios.h            |    3 +
 include/asm-powerpc/socket.h            |    2 +
 include/asm-powerpc/sockios.h           |    3 +
 include/asm-s390/socket.h               |    2 -
 include/asm-s390/sockios.h              |    3 +
 include/asm-sh/socket.h                 |    2 -
 include/asm-sh/sockios.h                |    1
 include/asm-sh64/sockios.h              |    1
 include/asm-sparc/socket.h              |    2 +
 include/asm-sparc/sockios.h             |    3 +
 include/asm-sparc64/socket.h            |    2 +
 include/asm-sparc64/sockios.h           |    3 +
 include/asm-v850/socket.h               |    2 +
 include/asm-v850/sockios.h              |    3 +
 include/asm-x86_64/socket.h             |    2 +
 include/asm-x86_64/sockios.h            |    3 +
 include/asm-xtensa/socket.h             |    2 +
 include/asm-xtensa/sockios.h            |    3 +
 include/linux/skbuff.h                  |   38 ++++++++++++++++------
 include/net/compat.h                    |    1
 include/net/sock.h                      |   31 ++++++++++++-----
 net/appletalk/ddp.c                     |    3 +
 net/atm/ioctl.c                         |    3 +
 net/ax25/af_ax25.c                      |    4 ++
 net/bridge/netfilter/ebt_ulog.c         |    7 ++--
 net/compat.c                            |   33 +++++++++++++++++--
 net/core/dev.c                          |    8 ++--
 net/core/sock.c                         |   36 +++++++++++++++++++-
 net/econet/af_econet.c                  |    5 ++
 net/ipv4/af_inet.c                      |    3 +
 net/ipv4/ip_fragment.c                  |    6 +--
 net/ipv4/netfilter/ip_queue.c           |    2 -
 net/ipv4/netfilter/ipt_ULOG.c           |    2 -
 net/ipv6/af_inet6.c                     |    3 +
 net/ipv6/netfilter/ip6_queue.c          |    2 -
 net/ipv6/netfilter/nf_conntrack_reasm.c |    6 +--
 net/ipv6/reassembly.c                   |    6 +--
 net/ipx/af_ipx.c                        |    2 -
 net/netfilter/nfnetlink_log.c           |    2 -
 net/netfilter/nfnetlink_queue.c         |    2 -
 net/netrom/af_netrom.c                  |    5 ++
 net/packet/af_packet.c                  |    4 +-
 net/rose/af_rose.c                      |    2 +
 net/sunrpc/svcsock.c                    |    9 ++---
 net/wanrouter/af_wanpipe.c              |    3 +
 net/x25/af_x25.c                        |   12 ++++++
 70 files changed, 280 insertions(+), 74 deletions(-)
include/linux/skbuff.h +28 -10
@@ -156,9 +156,13 @@ struct skb_shared_info {
 #define SKB_DATAREF_SHIFT 16
 #define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
 
-struct skb_timeval {
+/*
+ * We use a special timespec like structure, because ABI constraints 
+ * make 'struct timespec' being 16 bytes on 64bit platforms.
+ */
+struct skb_timespec {
 	u32	off_sec;
-	u32	off_usec;
+	u32	off_nsec;
 };
 
 
@@ -233,7 +237,7 @@ struct sk_buff {
 	struct sk_buff		*prev;
 
 	struct sock		*sk;
-	struct skb_timeval	tstamp;
+	struct skb_timespec	tstamp;
 	struct net_device	*dev;
 	struct net_device	*input_dev;
 
@@ -1350,6 +1354,20 @@ extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
 
 /**
+ *	skb_get_timestampns - get timestamp from a skb
+ *	@skb: skb to get stamp from
+ *	@stampns: pointer to struct timespec to store stamp in
+ *
+ *	Timestamps are stored in the skb as offsets to a base timestamp.
+ *	This function converts the offset back to a struct timespec and stores
+ *	it in stamp.
+ */
+static inline void skb_get_timestampns(const struct sk_buff *skb, struct timespec *stampns)
+{
+	stampns->tv_sec  = skb->tstamp.off_sec;
+	stampns->tv_nsec = skb->tstamp.off_nsec;
+}
+/**
  *	skb_get_timestamp - get timestamp from a skb
  *	@skb: skb to get stamp from
  *	@stamp: pointer to struct timeval to store stamp in
@@ -1361,22 +1379,22 @@ 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->tv_usec = skb->tstamp.off_nsec / NSEC_PER_USEC;
 }
 
 /**
- * 	skb_set_timestamp - set timestamp of a skb
+ * 	skb_set_timestampns - set timestamp of a skb
  *	@skb: skb to set stamp of
- *	@stamp: pointer to struct timeval to get stamp from
+ *	@stamp: pointer to struct timespec 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
+ *	This function converts a struct timespec 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 skb_set_timestampns(struct sk_buff *skb, const struct timespec *stampns)
 {
-	skb->tstamp.off_sec  = stamp->tv_sec;
-	skb->tstamp.off_usec = stamp->tv_usec;
+	skb->tstamp.off_sec  = stampns->tv_sec;
+	skb->tstamp.off_nsec = stampns->tv_nsec;
 }
 
 extern void __net_timestamp(struct sk_buff *skb);
include/net/sock.h +22 -9
@@ -244,7 +244,7 @@ struct sock {
 	struct sk_filter      	*sk_filter;
 	void			*sk_protinfo;
 	struct timer_list	sk_timer;
-	struct timeval		sk_stamp;
+	struct timespec		sk_stamp;
 	struct socket		*sk_socket;
 	void			*sk_user_data;
 	struct page		*sk_sndmsg_page;
@@ -390,6 +390,7 @@ enum sock_flags {
 	SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */
 	SOCK_DBG, /* %SO_DEBUG setting */
 	SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */
+	SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */
 	SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */
 	SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */
 };
@@ -1307,19 +1308,30 @@ static inline int sock_intr_errno(long t
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
-	struct timeval stamp;
+	struct timespec ts;
+	struct timeval tv;
 
-	skb_get_timestamp(skb, &stamp);
+	skb_get_timestampns(skb, &ts);
 	if (sock_flag(sk, SOCK_RCVTSTAMP)) {
 		/* 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 (ts.tv_sec == 0)
+			getnstimeofday(&ts);
+		skb_set_timestampns(skb, &ts);
+		tv.tv_sec = ts.tv_sec;
+		tv.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(struct timeval),
+			 &tv);
+	} else if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
+		/* Race occurred between timestamp enabling and packet
+		   receiving.  Fill in the current time for now. */
+		if (ts.tv_sec == 0)
+			getnstimeofday(&ts);
+		skb_set_timestampns(skb, &ts);
+		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(struct timespec),
+			 &ts);
 	} else
-		sk->sk_stamp = stamp;
+		sk->sk_stamp = ts;
 }
 
 /**
@@ -1350,6 +1362,7 @@ static inline void sk_eat_skb(struct soc
 
 extern void sock_enable_timestamp(struct sock *sk);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int sock_get_timestampns(struct sock *, struct timespec __user *);
 
 /* 
  *	Enable debug/info messages 
include/net/compat.h +1 -0
@@ -25,6 +25,7 @@ struct compat_cmsghdr {
 };
 
 extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
 
 #else /* defined(CONFIG_COMPAT) */
 #define compat_msghdr	msghdr		/* to avoid compiler warnings */
net/core/sock.c +33 -3
@@ -524,12 +524,22 @@ set_rcvbuf:
 
 		case SO_TIMESTAMP:
 			if (valbool)  {
+				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
 				sock_set_flag(sk, SOCK_RCVTSTAMP);
 				sock_enable_timestamp(sk);
 			} else
 				sock_reset_flag(sk, SOCK_RCVTSTAMP);
 			break;
 
+		case SO_TIMESTAMPNS:
+			if (valbool)  {
+				sock_reset_flag(sk, SOCK_RCVTSTAMP);
+				sock_set_flag(sk, SOCK_RCVTSTAMPNS);
+				sock_enable_timestamp(sk);
+			} else
+				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+			break;
+
 		case SO_RCVLOWAT:
 			if (val < 0)
 				val = INT_MAX;
@@ -722,6 +732,10 @@ int sock_getsockopt(struct socket *sock,
 			v.val = sock_flag(sk, SOCK_RCVTSTAMP);
 			break;
 
+		case SO_TIMESTAMPNS:
+			v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);
+			break;
+
 		case SO_RCVTIMEO:
 			lv=sizeof(struct timeval);
 			if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
@@ -1513,7 +1527,7 @@ void sock_init_data(struct socket *sock,
 	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
 
 	sk->sk_stamp.tv_sec     = -1L;
-	sk->sk_stamp.tv_usec    = -1L;
+	sk->sk_stamp.tv_nsec    = -1L;
 
 	atomic_set(&sk->sk_refcnt, 1);
 }
@@ -1554,17 +1568,33 @@ EXPORT_SYMBOL(release_sock);
 
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
+	struct timeval tstamp;
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk);
 	if (sk->sk_stamp.tv_sec == -1)
 		return -ENOENT;
 	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
-	return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ?
+		getnstimeofday(&sk->sk_stamp);
+	tstamp.tv_sec = sk->sk_stamp.tv_sec;
+	tstamp.tv_usec = sk->sk_stamp.tv_nsec / NSEC_PER_USEC;
+	return copy_to_user(userstamp, &tstamp, sizeof(struct timeval)) ?
 		-EFAULT : 0;
 }
 EXPORT_SYMBOL(sock_get_timestamp);
 
+int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	if (sk->sk_stamp.tv_sec == -1)
+		return -ENOENT;
+	if (sk->sk_stamp.tv_sec == 0)
+		getnstimeofday(&sk->sk_stamp);
+	return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timespec)) ?
+		-EFAULT : 0;
+}
+EXPORT_SYMBOL(sock_get_timestampns);
+
 void sock_enable_timestamp(struct sock *sk)
 {
 	if (!sock_flag(sk, SOCK_TIMESTAMP)) {
net/core/dev.c +4 -4
@@ -1036,10 +1036,10 @@ void net_disable_timestamp(void)
 
 void __net_timestamp(struct sk_buff *skb)
 {
-	struct timeval tv;
+	struct timespec ts;
 
-	do_gettimeofday(&tv);
-	skb_set_timestamp(skb, &tv);
+	getnstimeofday(&ts);
+	skb_set_timestampns(skb, &ts);
 }
 EXPORT_SYMBOL(__net_timestamp);
 
@@ -1049,7 +1049,7 @@ static inline void net_timestamp(struct 
 		__net_timestamp(skb);
 	else {
 		skb->tstamp.off_sec = 0;
-		skb->tstamp.off_usec = 0;
+		skb->tstamp.off_nsec = 0;
 	}
 }
 
net/ipv4/ip_fragment.c +3 -3
@@ -92,7 +92,7 @@ struct ipq {
 	spinlock_t	lock;
 	atomic_t	refcnt;
 	struct timer_list timer;	/* when will this queue expire?		*/
-	struct timeval	stamp;
+	struct timespec	stamp;
 	int             iif;
 	unsigned int    rid;
 	struct inet_peer *peer;
@@ -592,7 +592,7 @@ static void ip_frag_queue(struct ipq *qp
 	if (skb->dev)
 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &qp->stamp);
+	skb_get_timestampns(skb, &qp->stamp);
 	qp->meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
@@ -674,7 +674,7 @@ static struct sk_buff *ip_frag_reasm(str
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &qp->stamp);
+	skb_set_timestampns(head, &qp->stamp);
 
 	iph = head->nh.iph;
 	iph->frag_off = 0;
net/ipv4/af_inet.c +3 -0
@@ -755,6 +755,9 @@ int inet_ioctl(struct socket *sock, unsi
 		case SIOCGSTAMP:
 			err = sock_get_timestamp(sk, (struct timeval __user *)arg);
 			break;
+		case SIOCGSTAMPNS:
+			err = sock_get_timestampns(sk, (struct timespec __user *)arg);
+			break;
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCRTMSG:
net/ipv6/af_inet6.c +3 -0
@@ -437,6 +437,9 @@ int inet6_ioctl(struct socket *sock, uns
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 	case SIOCADDRT:
 	case SIOCDELRT:
 
net/packet/af_packet.c +3 -1
@@ -661,7 +661,7 @@ static int tpacket_rcv(struct sk_buff *s
 		sock_enable_timestamp(sk);
 	}
 	h->tp_sec = skb->tstamp.off_sec;
-	h->tp_usec = skb->tstamp.off_usec;
+	h->tp_usec = skb->tstamp.off_nsec / NSEC_PER_USEC;
 
 	sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
 	sll->sll_halen = 0;
@@ -1543,6 +1543,8 @@ static int packet_ioctl(struct socket *s
 		}
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
 
 #ifdef CONFIG_INET
 		case SIOCADDRT:
net/sunrpc/svcsock.c +4 -5
@@ -806,15 +806,14 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
 	if (skb->tstamp.off_sec == 0) {
-		struct timeval tv;
+		struct timespec ts;
 
-		tv.tv_sec = xtime.tv_sec;
-		tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
-		skb_set_timestamp(skb, &tv);
+		ts = current_kernel_time();
+		skb_set_timestampns(skb, &ts);
 		/* Don't enable netstamp, sunrpc doesn't
 		   need that much accuracy */
 	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	skb_get_timestampns(skb, &svsk->sk_sk->sk_stamp);
 	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/*
net/compat.c +31 -2
@@ -215,6 +215,7 @@ Efault:
 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 {
 	struct compat_timeval ctv;
+	struct compat_timespec cts;
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
@@ -231,6 +232,13 @@ int put_cmsg_compat(struct msghdr *kmsg,
 		data = &ctv;
 		len = sizeof(struct compat_timeval);
 	}
+	if (level == SOL_SOCKET && type == SO_TIMESTAMPNS) {
+		struct timespec *ts = (struct timespec *)data;
+		cts.tv_sec = ts->tv_sec;
+		cts.tv_nsec = ts->tv_nsec;
+		data = &cts;
+		len = sizeof(struct compat_timespec);
+	}
 
 	cmlen = CMSG_COMPAT_LEN(len);
 	if(kmsg->msg_controllen < cmlen) {
@@ -545,20 +553,41 @@ int compat_sock_get_timestamp(struct soc
 	struct compat_timeval __user *ctv =
 			(struct compat_timeval __user*) userstamp;
 	int err = -ENOENT;
+	long usec;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk);
 	if (sk->sk_stamp.tv_sec == -1)
 		return err;
 	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
+		getnstimeofday(&sk->sk_stamp);
+	usec = sk->sk_stamp.tv_nsec / NSEC_PER_USEC;
 	if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) ||
-			put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec))
+			put_user(usec, &ctv->tv_usec))
 		err = -EFAULT;
 	return err;
 }
 EXPORT_SYMBOL(compat_sock_get_timestamp);
 
+int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	struct compat_timespec __user *ctv =
+			(struct compat_timespec __user*) userstamp;
+	int err = -ENOENT;
+
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	if (sk->sk_stamp.tv_sec == -1)
+		return err;
+	if (sk->sk_stamp.tv_sec == 0)
+		getnstimeofday(&sk->sk_stamp);
+	if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) ||
+			put_user(sk->sk_stamp.tv_nsec, &ctv->tv_nsec))
+		err = -EFAULT;
+	return err;
+}
+EXPORT_SYMBOL(compat_sock_get_timestampns);
+
 asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
fs/compat_ioctl.c +17 -0
@@ -265,6 +265,22 @@ static int do_siocgstamp(unsigned int fd
 	}
 	return err;
 }
+static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct compat_timespec __user *up = compat_ptr(arg);
+	struct timespec ktv;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+	set_fs(old_fs);
+	if(!err) {
+		err = put_user(ktv.tv_sec, &up->tv_sec);
+		err |= __put_user(ktv.tv_nsec, &up->tv_nsec);
+	}
+	return err;
+}
 
 struct ifmap32 {
 	compat_ulong_t mem_start;
@@ -2437,6 +2453,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns)
 #endif
 #ifdef CONFIG_BLOCK
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
net/appletalk/ddp.c +3 -0
@@ -1768,6 +1768,9 @@ static int atalk_ioctl(struct socket *so
 		case SIOCGSTAMP:
 			rc = sock_get_timestamp(sk, argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = sock_get_timestampns(sk, argp);
+			break;
 		/* Routing */
 		case SIOCADDRT:
 		case SIOCDELRT:
net/ax25/af_ax25.c +4 -0
@@ -1711,6 +1711,10 @@ static int ax25_ioctl(struct socket *soc
 		res = sock_get_timestamp(sk, argp);
 		break;
 
+	case SIOCGSTAMPNS:
+		res = sock_get_timestampns(sk, argp);
+		break;
+
 	case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */
 	case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */
 	case SIOCAX25GETUID: {
net/atm/ioctl.c +3 -0
@@ -82,6 +82,9 @@ int vcc_ioctl(struct socket *sock, unsig
 		case SIOCGSTAMP: /* borrowed from IP */
 			error = sock_get_timestamp(sk, argp);
 			goto done;
+		case SIOCGSTAMPNS: /* borrowed from IP */
+			error = sock_get_timestampns(sk, argp);
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
 			error = 0;
net/econet/af_econet.c +4 -1
@@ -162,7 +162,7 @@ static int econet_recvmsg(struct kiocb *
 	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
 	if (err)
 		goto out_free;
-	skb_get_timestamp(skb, &sk->sk_stamp);
+	skb_get_timestampns(skb, &sk->sk_stamp);
 
 	if (msg->msg_name)
 		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
@@ -727,6 +727,9 @@ static int econet_ioctl(struct socket *s
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, argp);
 
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, argp);
+
 		case SIOCSIFADDR:
 		case SIOCGIFADDR:
 			return ec_dev_ioctl(sock, cmd, argp);
net/ipx/af_ipx.c +1 -1
@@ -1808,7 +1808,7 @@ static int ipx_recvmsg(struct kiocb *ioc
 	if (rc)
 		goto out_free;
 	if (skb->tstamp.off_sec)
-		skb_get_timestamp(skb, &sk->sk_stamp);
+		skb_get_timestampns(skb, &sk->sk_stamp);
 
 	msg->msg_namelen = sizeof(*sipx);
 
net/netrom/af_netrom.c +5 -0
@@ -1208,6 +1208,11 @@ static int nr_ioctl(struct socket *sock,
 		ret = sock_get_timestamp(sk, argp);
 		release_sock(sk);
 		return ret;
+	case SIOCGSTAMPNS:
+		lock_sock(sk);
+		ret = sock_get_timestampns(sk, argp);
+		release_sock(sk);
+		return ret;
 
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
net/rose/af_rose.c +2 -0
@@ -1271,6 +1271,8 @@ static int rose_ioctl(struct socket *soc
 
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *) argp);
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *) argp);
 
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
net/wanrouter/af_wanpipe.c +3 -0
@@ -1770,6 +1770,9 @@ static int wanpipe_ioctl(struct socket *
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 		case SIOC_WANPIPE_CHECK_TX:
 
 			return atomic_read(&sk->sk_wmem_alloc);
net/x25/af_x25.c +12 -0
@@ -1280,6 +1280,12 @@ static int x25_ioctl(struct socket *sock
 				rc = sock_get_timestamp(sk,
 						(struct timeval __user *)argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = -EINVAL;
+			if (sk)
+				rc = sock_get_timestampns(sk,
+						(struct timespec __user *)argp);
+			break;
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -1521,6 +1527,12 @@ static int compat_x25_ioctl(struct socke
 			rc = compat_sock_get_timestamp(sk,
 					(struct timeval __user*)argp);
 		break;
+	case SIOCGSTAMPNS:
+		rc = -EINVAL;
+		if (sk)
+			rc = compat_sock_get_timestampns(sk,
+					(struct timespec __user*)argp);
+		break;
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
net/bridge/netfilter/ebt_ulog.c +5 -2
@@ -130,6 +130,7 @@ static void ebt_ulog_packet(unsigned int
 	unsigned int group = uloginfo->nlgroup;
 	ebt_ulog_buff_t *ub = &ulog_buffers[group];
 	spinlock_t *lock = &ub->lock;
+	struct timespec ts;
 
 	if ((uloginfo->cprange == 0) ||
 	    (uloginfo->cprange > skb->len + ETH_HLEN))
@@ -164,9 +165,11 @@ static void ebt_ulog_packet(unsigned int
 
 	/* Fill in the ulog data */
 	pm->version = EBT_ULOG_VERSION;
-	do_gettimeofday(&pm->stamp);
+	getnstimeofday(&ts);
+	pm->stamp.tv_sec = ts.tv_sec;
+	pm->stamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 	if (ub->qlen == 1)
-		skb_set_timestamp(ub->skb, &pm->stamp);
+		skb_set_timestampns(ub->skb, &ts);
 	pm->data_len = copy_len;
 	pm->mark = skb->mark;
 	pm->hook = hooknr;
net/ipv4/netfilter/ipt_ULOG.c +1 -1
@@ -237,7 +237,7 @@ static void ipt_ulog_packet(unsigned int
 	/* copy hook, prefix, timestamp, payload, etc. */
 	pm->data_len = copy_len;
 	pm->timestamp_sec = skb->tstamp.off_sec;
-	pm->timestamp_usec = skb->tstamp.off_usec;
+	pm->timestamp_usec = skb->tstamp.off_nsec / NSEC_PER_USEC;
 	pm->mark = skb->mark;
 	pm->hook = hooknum;
 	if (prefix != NULL)
net/ipv4/netfilter/ip_queue.c +1 -1
@@ -242,7 +242,7 @@ ipq_build_packet_message(struct ipq_queu
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
 	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	pmsg->timestamp_usec  = entry->skb->tstamp.off_nsec / NSEC_PER_USEC;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
net/ipv6/netfilter/ip6_queue.c +1 -1
@@ -240,7 +240,7 @@ ipq_build_packet_message(struct ipq_queu
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
 	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	pmsg->timestamp_usec  = entry->skb->tstamp.off_nsec / NSEC_PER_USEC;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
net/netfilter/nfnetlink_queue.c +1 -1
@@ -499,7 +499,7 @@ nfqnl_build_packet_message(struct nfqnl_
 		struct nfqnl_msg_packet_timestamp ts;
 
 		ts.sec = cpu_to_be64(entskb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(entskb->tstamp.off_usec);
+		ts.usec = cpu_to_be64(entskb->tstamp.off_nsec / NSEC_PER_USEC);
 
 		NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
 	}
net/netfilter/nfnetlink_log.c +1 -1
@@ -514,7 +514,7 @@ __build_packet_message(struct nfulnl_ins
 		struct nfulnl_msg_packet_timestamp ts;
 
 		ts.sec = cpu_to_be64(skb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(skb->tstamp.off_usec);
+		ts.usec = cpu_to_be64(skb->tstamp.off_nsec / NSEC_PER_USEC);
 
 		NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
 	}
net/ipv6/netfilter/nf_conntrack_reasm.c +3 -3
@@ -82,7 +82,7 @@ struct nf_ct_frag6_queue
 	struct sk_buff		*fragments;
 	int			len;
 	int			meat;
-	struct timeval		stamp;
+	struct timespec		stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -542,7 +542,7 @@ static int nf_ct_frag6_queue(struct nf_c
 		fq->fragments = skb;
 
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	skb_get_timestampns(skb, &fq->stamp);
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &nf_ct_frag6_mem);
 
@@ -648,7 +648,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	skb_set_timestampns(head, &fq->stamp);
 	head->nh.ipv6h->payload_len = htons(payload_len);
 
 	/* Yes, and fold redundant checksum back. 8) */
net/ipv6/reassembly.c +3 -3
@@ -88,7 +88,7 @@ struct frag_queue
 	int			len;
 	int			meat;
 	int			iif;
-	struct timeval		stamp;
+	struct timespec		stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -562,7 +562,7 @@ static void ip6_frag_queue(struct frag_q
 	if (skb->dev)
 		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	skb_get_timestampns(skb, &fq->stamp);
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -663,7 +663,7 @@ static int ip6_frag_reasm(struct frag_qu
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
+	skb_set_timestampns(head, &fq->stamp);
 	head->nh.ipv6h->payload_len = htons(payload_len);
 	IP6CB(head)->nhoff = nhoff;
 
include/asm-i386/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-i386/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-x86_64/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-x86_64/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-alpha/socket.h +2 -0
@@ -52,6 +52,8 @@
 
 #define SO_PEERSEC		30
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		19
include/asm-alpha/sockios.h +1 -0
@@ -11,5 +11,6 @@
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
 #define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_ALPHA_SOCKIOS_H */
include/asm-arm/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-arm26/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-arm26/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-avr32/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __ASM_AVR32_SOCKET_H */
include/asm-avr32/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ASM_AVR32_SOCKIOS_H */
include/asm-cris/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-frv/socket.h +2 -0
@@ -49,6 +49,8 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
 
include/asm-frv/sockios.h +2 -1
@@ -7,7 +7,8 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS__ */
 
include/asm-h8300/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-h8300/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_H8300_SOCKIOS__ */
include/asm-ia64/socket.h +2 -0
@@ -58,5 +58,7 @@
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_IA64_SOCKET_H */
include/asm-ia64/sockios.h +2 -1
@@ -14,6 +14,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_IA64_SOCKIOS_H */
include/asm-m32r/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_M32R_SOCKET_H */
include/asm-m32r/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif  /* _ASM_M32R_SOCKIOS_H */
include/asm-m68k/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-m68k/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_M68K_SOCKIOS__ */
include/asm-mips/socket.h +2 -0
@@ -70,6 +70,8 @@ To add: #define SO_REUSEPORT 0x0200	/* A
 #define SO_SNDBUFFORCE		31
 #define SO_RCVBUFFORCE		33
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #ifdef __KERNEL__
 
include/asm-mips/sockios.h +2 -1
@@ -20,6 +20,7 @@
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906			/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS_H */
include/asm-parisc/socket.h +2 -0
@@ -33,6 +33,8 @@
 #define SO_PEERCRED	0x4011
 #define SO_TIMESTAMP	0x4012
 #define SCM_TIMESTAMP	SO_TIMESTAMP
+#define SO_TIMESTAMPNS	0x4013
+#define SCM_TIMESTAMPNS	SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x4016
include/asm-parisc/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-powerpc/socket.h +2 -0
@@ -56,5 +56,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif	/* _ASM_POWERPC_SOCKET_H */
include/asm-powerpc/sockios.h +2 -1
@@ -14,6 +14,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _ASM_POWERPC_SOCKIOS_H */
include/asm-s390/socket.h +0 -2
@@ -57,7 +57,5 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
-#define SO_TIMESTAMPNS		35
-#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
include/asm-s390/sockios.h +2 -1
@@ -15,6 +15,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
include/asm-sh/socket.h +0 -2
@@ -49,7 +49,5 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
-#define SO_TIMESTAMPNS		35
-#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __ASM_SH_SOCKET_H */
include/asm-sh/sockios.h +1 -0
@@ -10,4 +10,5 @@
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
 #define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp - linux-specific */
 #endif /* __ASM_SH_SOCKIOS_H */
include/asm-sh64/sockios.h +1 -0
@@ -21,4 +21,5 @@
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
 #define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp - linux-specific */
 #endif /* __ASM_SH64_SOCKIOS_H */
include/asm-sparc/socket.h +2 -0
@@ -49,6 +49,8 @@
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
+#define SO_TIMESTAMPNS		0x0020
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
include/asm-sparc/sockios.h +2 -1
@@ -7,7 +7,8 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC_SOCKIOS_H) */
 
include/asm-sparc64/socket.h +2 -0
@@ -49,6 +49,8 @@
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
+#define SO_TIMESTAMPNS		0x0020
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
include/asm-sparc64/sockios.h +2 -1
@@ -7,7 +7,8 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC64_SOCKIOS_H) */
 
include/asm-v850/socket.h +2 -0
@@ -49,5 +49,7 @@
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __V850_SOCKET_H__ */
include/asm-v850/sockios.h +2 -1
@@ -7,6 +7,7 @@
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __V850_SOCKIOS_H__ */
include/asm-xtensa/socket.h +2 -0
@@ -60,5 +60,7 @@
 #define SO_ACCEPTCONN		30
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif	/* _XTENSA_SOCKET_H */
include/asm-xtensa/sockios.h +2 -1
@@ -25,6 +25,7 @@
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _XTENSA_SOCKIOS_H */
author
#31 lore raw
In reply to Eric Dumazet
Quoted 11 lines · Eric Dumazet
Quoted 6 lines · John

Consider an idle Linux 2.6.20-rt8 system, equipped with a single PCI-E gigabit Ethernet NIC, running on a modern CPU (e.g. Core 2 Duo E6700). All this system does is time stamp 1000 packets per second.

Are you claiming that this platform *cannot* handle most packets within less than 1 microsecond of their arrival?

Yes I claim it. You expect too much of this platform, unless "most" means 10 % for you ;)

By "most" I meant more than 50%.

Has someone tried to measure interrupt latency in Linux? I'd like to plot the distribution of network IRQ to interrupt handler latencies.

Quoted 1 line

If you replace "1 us" by "50 us", then yes, it probably can do it, if "most" means 99%, (not 99.999 %)

I think we need cold, hard numbers at this point :-)

Quoted 2 lines

Anyway, if you want to play, you can apply this patch on top of linux-2.6.21-rc2 (nanosecond resolution infrastructure needs 2.6.21) I let you do the adjustments for rt kernel.

Why does it require 2.6.21?

Quoted 2 lines

This patch converts sk_buff timestamp to use new nanosecond infra (added in 2.6.21)

Is this mentioned somewhere in the 2.6.21-rc1 ChangeLog?
http://kernel.org/pub/linux/kernel/v2.6/testing/ChangeLog-2.6.21-rc1

Regards.

#32 lore raw
Quoted 7 lines · John
Quoted 3 lines · Eric Dumazet

Anyway, if you want to play, you can apply this patch on top of linux-2.6.21-rc2 (nanosecond resolution infrastructure needs 2.6.21) I let you do the adjustments for rt kernel.

Why does it require 2.6.21?

Well, this patch was done on top of the latest kernel for obvious practical reasons, but you probably can adapt it on the kernel of your choice.

#33 lore raw
In reply to John
Quoted 10 lines · On Wed, 28 Feb 2007 14:37:49 +0100 John <[email protected]> wrote:
Quoted 3 lines · John

I know it's possible to have Linux timestamp incoming datagrams as soon as they are received, then for one to retrieve this timestamp later with an ioctl command or a recvmsg call.

Has it ever been proposed to modify struct skb_timeval to hold nanosecond stamps instead of just microsecond stamps? Then make the improved precision somehow available to user space.

I am playing with a couple of possible future changes.
1. Change skb timestamp to be a timespec instead of timeval, for ABI compatiablity the existing SO_TIMESTAMP has to stay microseconds, but add a new SO_TIMESPEC to get the nanosecond version.

The change gets non trivial because of other uses of timestamp (like vegas) so I gave up for now.

2. Use hardware receive timestamp in Yukon2 to put actual receive time into skb timestamp. Works, but still figuring out how to manage clock skew/resync.