net-timestamp: extend SCM_TIMESTAMPING ancillary data struct
authorWillem de Bruijn <willemb@google.com>
Tue, 5 Aug 2014 02:11:45 +0000 (22:11 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 5 Aug 2014 23:35:53 +0000 (16:35 -0700)
Applications that request kernel tx timestamps with SO_TIMESTAMPING
read timestamps as recvmsg() ancillary data. The response is defined
implicitly as timespec[3].

1) define struct scm_timestamping explicitly and

2) add support for new tstamp types. On tx, scm_timestamping always
   accompanies a sock_extended_err. Define previously unused field
   ee_info to signal the type of ts[0]. Introduce SCM_TSTAMP_SND to
   define the existing behavior.

The reception path is not modified. On rx, no struct similar to
sock_extended_err is passed along with SCM_TIMESTAMPING.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/skbuff.h
include/net/sock.h
include/uapi/linux/errqueue.h
net/core/skbuff.c
net/socket.c

index 281deced7469e5ff6c46ebae46c8138cfd35fada..477f0f60db45a84295a394a9c7b714f7f19eeb03 100644 (file)
@@ -249,6 +249,9 @@ enum {
        SKBTX_SHARED_FRAG = 1 << 5,
 };
 
+#define SKBTX_ANY_SW_TSTAMP    SKBTX_SW_TSTAMP
+#define SKBTX_ANY_TSTAMP       (SKBTX_HW_TSTAMP | SKBTX_ANY_SW_TSTAMP)
+
 /*
  * The callback notifies userspace to release buffers when skb DMA is done in
  * lower device, the skb last reference should be 0 when calling this.
index b91c8868ab8d66e173f7695d36e2c6aef1ce75dc..02f5b35e65f18675d758322f4d0be9b91cf7fcd1 100644 (file)
@@ -2169,7 +2169,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
         */
        if (sock_flag(sk, SOCK_RCVTSTAMP) ||
            sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) ||
-           (kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) ||
+           (kt.tv64 &&
+            (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) ||
+             skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP)) ||
            (hwtstamps->hwtstamp.tv64 &&
             sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)))
                __sock_recv_timestamp(msg, sk, skb);
index aacd4fb7102a1c8d63c71d75775b7fddd19a9a91..accee72cae7cc640ada78ac9f6d95aeb4d57e88f 100644 (file)
@@ -22,5 +22,23 @@ struct sock_extended_err {
 
 #define SO_EE_OFFENDER(ee)     ((struct sockaddr*)((ee)+1))
 
+/**
+ *     struct scm_timestamping - timestamps exposed through cmsg
+ *
+ *     The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_*
+ *     communicate network timestamps by passing this struct in a cmsg with
+ *     recvmsg(). See Documentation/networking/timestamping.txt for details.
+ */
+struct scm_timestamping {
+       struct timespec ts[3];
+};
+
+/* The type of scm_timestamping, passed in sock_extended_err ee_info.
+ * This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0]
+ * is zero, then this is a hardware timestamp and recorded in ts[2].
+ */
+enum {
+       SCM_TSTAMP_SND,         /* driver passed skb to NIC, or HW */
+};
 
 #endif /* _UAPI_LINUX_ERRQUEUE_H */
index c1a33033cbe2563da3204035adb623580b78cbad..c9f68802e99295254cb474cb08abcb2034784cbf 100644 (file)
@@ -3521,6 +3521,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
        memset(serr, 0, sizeof(*serr));
        serr->ee.ee_errno = ENOMSG;
        serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+       serr->ee.ee_info = SCM_TSTAMP_SND;
 
        err = sock_queue_err_skb(sk, skb);
 
index d8222c0250618a64197d5a4aba89313859b8d4eb..dc0cc5d95ee5fb37ca5be9c4bf011e11166bd2fa 100644 (file)
 #include <linux/sockios.h>
 #include <linux/atalk.h>
 #include <net/busy_poll.h>
+#include <linux/errqueue.h>
 
 #ifdef CONFIG_NET_RX_BUSY_POLL
 unsigned int sysctl_net_busy_read __read_mostly;
@@ -697,7 +698,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb)
 {
        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
-       struct timespec ts[3];
+       struct scm_timestamping tss;
        int empty = 1;
        struct skb_shared_hwtstamps *shhwtstamps =
                skb_hwtstamps(skb);
@@ -714,24 +715,25 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
                                 sizeof(tv), &tv);
                } else {
-                       skb_get_timestampns(skb, &ts[0]);
+                       struct timespec ts;
+                       skb_get_timestampns(skb, &ts);
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
-                                sizeof(ts[0]), &ts[0]);
+                                sizeof(ts), &ts);
                }
        }
 
-
-       memset(ts, 0, sizeof(ts));
-       if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) &&
-           ktime_to_timespec_cond(skb->tstamp, ts + 0))
+       memset(&tss, 0, sizeof(tss));
+       if ((sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) ||
+            skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) &&
+           ktime_to_timespec_cond(skb->tstamp, tss.ts + 0))
                empty = 0;
        if (shhwtstamps &&
            sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) &&
-           ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2))
+           ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2))
                empty = 0;
        if (!empty)
                put_cmsg(msg, SOL_SOCKET,
-                        SCM_TIMESTAMPING, sizeof(ts), &ts);
+                        SCM_TIMESTAMPING, sizeof(tss), &tss);
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);