netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Patrick Ohly <patrick.ohly@intel.com>
To: netdev@vger.kernel.org
Cc: Octavian Purdila <opurdila@ixiacom.com>,
	Stephen Hemminger <shemminger@vyatta.com>,
	Ingo Oeser <netdev@axxeo.de>, Andi Kleen <ak@linux.intel.com>,
	John Ronciak <john.ronciak@intel.com>,
	Eric Dumazet <dada1@cosmosbay.com>,
	Oliver Hartkopp <oliver@hartkopp.net>
Subject: [RFC PATCH 13/13] skbuff: optionally store hardware time stamps in new field
Date: Fri, 7 Nov 2008 10:26:01 +0100	[thread overview]
Message-ID: <1226415456.31699.12.camel@ecld0pohly> (raw)
In-Reply-To: <1226414697.17450.852.camel@ecld0pohly>

Because of performance reasons, adding a new field to struct sk_buff
was avoided. Hardware time stamps are stored in the existing field, but
in order to not break other code, they must have been transformed to
the system time base.

To obtain the original hardware time stamp before the transformation,
a network device driver must implement the inverse transformation.
The clocksync code has no support for that yet and it would be
difficult to implement 100% accurately (rounding errors, updated
offset/skew values).

Instead of implementing this inverse transformation, this patch
adds another field for hardware time stamps. It is off by default
and mainstream Linux distributions should leave it off (PTP time
synchronization doesn't need it), but special distributions/users
could enable it if needed without having to patch the mainline
kernel source.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
---
 drivers/net/igb/igb_main.c |    3 +-
 include/linux/skbuff.h     |   48 ++++++++++++++++++++++++++++++++++---------
 net/Kconfig                |   16 ++++++++++++++
 net/core/skbuff.c          |   18 +++++++++++++--
 4 files changed, 71 insertions(+), 14 deletions(-)

diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index b320fec..2fed508 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -4116,7 +4116,8 @@ send_up:
 			clocksync_update(&adapter->sync, tstamp);
 			skb_hwtstamp_set(skb,
 					ns_to_ktime(clocksource_cyc2time(&adapter->clock,
-										tstamp)));
+										tstamp)),
+					ns_to_ktime(tstamp));
 		}
 
 		if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index bcca8fc..123711d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -203,6 +203,7 @@ typedef unsigned char *sk_buff_data_t;
  *               thus is recorded in system time. If the lowest bit is set,
  *               then the value was originally generated by a different clock
  *               in the receiving hardware and then transformed to system time.
+ *      @hwtstamp: raw, unmodified hardware time stamp (optional)
  *	@dev: Device we arrived on/are leaving by
  *	@transport_header: Transport layer header
  *	@network_header: Network layer header
@@ -260,6 +261,9 @@ struct sk_buff {
 
 	struct sock		*sk;
 	ktime_t			tstamp;
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+	union ktime		hwtstamp;
+#endif
 	struct net_device	*dev;
 
 	union {
@@ -1530,11 +1534,15 @@ extern void skb_init(void);
 /** returns skb->tstamp without the bit which marks hardware time stamps */
 static inline union ktime skb_get_ktime(const struct sk_buff *skb)
 {
-#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+	return skb->tstamp;
+#else
+# if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
 	return ktime_set(skb->tstamp.tv.sec,
 			skb->tstamp.tv.nsec & ~1);
-#else
+# else
 	return (ktime_t) { .tv64 = skb->tstamp.tv64 & ~1UL };
+# endif
 #endif
 }
 
@@ -1564,15 +1572,19 @@ static inline void __net_timestamp(struct sk_buff *skb)
 {
 	skb->tstamp = ktime_get_real();
 
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+	skb->hwtstamp.tv64 = 0;
+#else
 	/*
 	 * make sure that lowest bit is never set: it marks hardware
 	 * time stamps
 	 */
-#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+# if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
 	skb->tstamp.tv.sec = skb->tstamp.tv.sec / 2 * 2;
-#else
+# else
 	skb->tstamp.tv64 = skb->tstamp.tv64 / 2 * 2;
-#endif
+# endif
+#endif /* CONFIG_NET_SKBUFF_HWTSTAMPS */
 }
 
 static inline ktime_t net_timedelta(ktime_t t)
@@ -1591,18 +1603,34 @@ static inline ktime_t net_invalid_timestamp(void)
  */
 static inline int skb_hwtstamp_available(const struct sk_buff *skb)
 {
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+	return skb->hwtstamp.tv64 != 0;
+#else
 	return skb->tstamp.tv64 & 1;
+#endif
 }
 
+/**
+ * skb_hwtstamp_set - stores a time stamp generated by hardware in the skb
+ * @skb:	time stamp is stored here
+ * @stamp:	hardware time stamp transformed to system time
+ * @hwtstamp:	original, untransformed hardware time stamp
+ */
 static inline void skb_hwtstamp_set(struct sk_buff *skb,
-				union ktime stamp)
-{
-#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+				union ktime stamp,
+				union ktime hwtstamp)
+{
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+	skb->tstamp = stamp;
+	skb->hwtstamp = hwtstamp;
+#else /* CONFIG_NET_SKBUFF_HWTSTAMPS */
+# if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
 	skb->tstamp.tv.sec = stamp.tv.sec;
 	skb->tstamp.tv.nsec = stamp.tv.nsec | 1;
-#else
+# else
 	skb->tstamp.tv64 = stamp.tv64 | 1;
-#endif
+# endif
+#endif /* CONFIG_NET_SKBUFF_HWTSTAMPS */
 }
 
 /**
diff --git a/net/Kconfig b/net/Kconfig
index 7612cc8..b37b891 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -32,6 +32,22 @@ config NET_NS
 	  Allow user space to create what appear to be multiple instances
 	  of the network stack.
 
+config NET_SKBUFF_HWTSTAMPS
+       bool "Additional hardware time stamp field in struct sk_buff"
+       default n
+       depends on EXPERIMENTAL
+       help
+         Increase the size of sk_buff by 64 bits to store a raw hardware
+         time stamp in addition to the system time stamp. This is only
+         necessary when a) there is a network device which supports
+         hardware time stamping and b) access to these raw, unmodified values
+         is required.
+
+         Usually it is sufficient to convert the raw time stamps into system
+         time and store that in the existing time stamp value. Increasing
+         the size of sk_buff can have a performance impact, so if in doubt
+         say N here.
+
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 7d9f1dd..8b7960e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2326,6 +2326,12 @@ EXPORT_SYMBOL_GPL(skb_segment);
 
 int skb_hwtstamp_raw(const struct sk_buff *skb, struct timespec *stamp)
 {
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+	if (skb_hwtstamp_available(skb)) {
+		*stamp = ktime_to_timespec(skb->hwtstamp);
+		return 1;
+	}
+#else
 	struct rtable *rt;
 	struct in_device *idev;
 	struct net_device *netdev;
@@ -2342,6 +2348,7 @@ int skb_hwtstamp_raw(const struct sk_buff *skb, struct timespec *stamp)
 			return 1;
 		}
 	}
+#endif
 
 	return 0;
 }
@@ -2592,14 +2599,19 @@ void skb_hwtstamp_tx(struct sk_buff *orig_skb,
 		skb_hwtstamp_set(skb,
 				dev->hwtstamp_raw2sys ?
 				dev->hwtstamp_raw2sys(dev, stamp) :
+				stamp,
 				stamp);
 	} else {
 		skb->tstamp = stamp;
-#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
-		skb->tstamp.tv.sec = skb->tstamp.tv.sec / 2 * 2;
+#ifdef CONFIG_NET_SKBUFF_HWTSTAMPS
+		skb->hwtstamp.tv64 = 0;
 #else
+# if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+		skb->tstamp.tv.sec = skb->tstamp.tv.sec / 2 * 2;
+# else
 		skb->tstamp.tv64 = skb->tstamp.tv64 / 2 * 2;
-#endif
+# endif
+#endif /* CONFIG_NET_SKBUFF_HWTSTAMPS */
 	}
 
 	err = sock_queue_err_skb(sk, skb);
-- 
1.6.0.4


  parent reply	other threads:[~2008-11-11 14:57 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-11 14:44 [RFC PATCH 00/13] hardware time stamping + igb example implementation Patrick Ohly
2008-10-22  8:17 ` [RFC PATCH 02/13] extended semantic of sk_buff::tstamp: lowest bit marks hardware time stamps Patrick Ohly
2008-11-12  7:41   ` Eric Dumazet
2008-11-12  8:09     ` Patrick Ohly
2008-11-12 10:09       ` David Miller
2008-11-12  9:58   ` David Miller
2008-11-19 12:50     ` Patrick Ohly
2008-10-22 12:46 ` [RFC PATCH 01/13] put_cmsg_compat + SO_TIMESTAMP[NS]: use same name for value as caller Patrick Ohly
2008-11-12  9:55   ` David Miller
2008-10-22 15:01 ` [RFC PATCH 03/13] user space API for time stamping of incoming and outgoing packets Patrick Ohly
2008-11-12 10:02   ` David Miller
2008-10-24 13:41 ` [RFC PATCH 04/13] net: implement generic SOF_TIMESTAMPING_TX_* support Patrick Ohly
2008-11-11 23:15   ` Octavian Purdila
2008-11-12  8:38     ` Patrick Ohly
2008-10-24 13:49 ` [RFC PATCH 05/13] ip: support for TX timestamps on UDP and RAW sockets Patrick Ohly
2008-11-12  9:59   ` David Miller
2008-10-29 14:48 ` [RFC PATCH 06/13] workaround: detect time stamp when command flags are expected Patrick Ohly
2008-11-12 10:00   ` David Miller
2008-10-31 11:43 ` [RFC PATCH 07/13] net: add SIOCSHWTSTAMP - hardware time stamping of packets Patrick Ohly
2008-10-31 12:21 ` [RFC PATCH 08/13] igb: stub support for SIOCSHWTSTAMP Patrick Ohly
2008-11-04  9:23 ` [RFC PATCH 09/13] clocksource: allow usage independent of timekeeping.c Patrick Ohly
2008-11-12 10:04   ` David Miller
2008-11-04  9:27 ` [RFC PATCH 10/13] igb: infrastructure for hardware time stamping Patrick Ohly
2008-11-05  9:58 ` [RFC PATCH 11/13] time sync: generic infrastructure to map between time stamps generated by a clock source and system time Patrick Ohly
2008-11-11 16:18   ` Andi Kleen
2008-11-12  8:01     ` Patrick Ohly
2008-11-12 10:08       ` David Miller
2008-11-12 16:14         ` Patrick Ohly
2008-11-12 16:28           ` Eric Dumazet
2008-11-12 10:05   ` David Miller
2008-11-06 11:13 ` [RFC PATCH 12/13] igb: use clocksync to implement hardware time stamping Patrick Ohly
2008-11-07  9:26 ` Patrick Ohly [this message]
2008-11-12 16:06 ` [RFC PATCH 00/13] hardware time stamping + igb example implementation Andi Kleen
2008-11-12 16:25   ` Patrick Ohly
2008-11-12 18:44     ` Oliver Hartkopp
2008-11-12 19:22       ` Eric Dumazet
2008-11-12 20:23         ` Andi Kleen
2008-11-12 20:23         ` Andi Kleen
2008-11-12 20:56           ` Eric Dumazet
2008-11-12 21:34             ` Andi Kleen
2008-11-12 22:26               ` Oliver Hartkopp
2008-11-13 15:53                 ` Ohly, Patrick
2008-11-13  6:15               ` Oliver Hartkopp
2008-11-13  6:29                 ` Eric Dumazet
2008-11-13 16:05                 ` Ohly, Patrick
2008-11-16  8:15               ` Andrew Shewmaker
2008-11-12 22:17           ` David Miller
2008-11-19 12:39       ` Patrick Ohly

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1226415456.31699.12.camel@ecld0pohly \
    --to=patrick.ohly@intel.com \
    --cc=ak@linux.intel.com \
    --cc=dada1@cosmosbay.com \
    --cc=john.ronciak@intel.com \
    --cc=netdev@axxeo.de \
    --cc=netdev@vger.kernel.org \
    --cc=oliver@hartkopp.net \
    --cc=opurdila@ixiacom.com \
    --cc=shemminger@vyatta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).