socket: Add SO_TIMESTAMP[NS]_NEW
authorDeepa Dinamani <deepa.kernel@gmail.com>
Sat, 2 Feb 2019 15:34:50 +0000 (07:34 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 3 Feb 2019 19:17:31 +0000 (11:17 -0800)
Add SO_TIMESTAMP_NEW and SO_TIMESTAMPNS_NEW variants of
socket timestamp options.
These are the y2038 safe versions of the SO_TIMESTAMP_OLD
and SO_TIMESTAMPNS_OLD for all architectures.

Note that the format of scm_timestamping.ts[0] is not changed
in this patch.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Cc: jejb@parisc-linux.org
Cc: ralf@linux-mips.org
Cc: rth@twiddle.net
Cc: linux-alpha@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: linux-parisc@vger.kernel.org
Cc: linux-rdma@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
12 files changed:
arch/alpha/include/uapi/asm/socket.h
arch/mips/include/uapi/asm/socket.h
arch/parisc/include/uapi/asm/socket.h
arch/sparc/include/uapi/asm/socket.h
include/linux/skbuff.h
include/net/sock.h
include/uapi/asm-generic/socket.h
net/core/sock.c
net/ipv4/tcp.c
net/rds/af_rds.c
net/rds/recv.c
net/socket.c

index 992a0a6dcea1aed1b20377bd337297396b82e624..aab11eec7c22ef36206591760057e0ded89869c2 100644 (file)
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 /*
 #define SO_TIMESTAMPNS_OLD      35
 #define SO_TIMESTAMPING_OLD     37
 
+#define SO_TIMESTAMP_NEW        63
+#define SO_TIMESTAMPNS_NEW      64
+
 #if !defined(__KERNEL__)
 
-#define SO_TIMESTAMP            SO_TIMESTAMP_OLD
-#define SO_TIMESTAMPNS          SO_TIMESTAMPNS_OLD
+#if __BITS_PER_LONG == 64
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#else
+#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
+#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
+#endif
+
 #define SO_TIMESTAMPING         SO_TIMESTAMPING_OLD
 
 #define SCM_TIMESTAMP           SO_TIMESTAMP
index 0f4516c34df2308bd0137ac14731e78dc3e839d7..11014f684d9fc84560d0077ca3f1d3f5e148c728 100644 (file)
@@ -11,6 +11,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /*
  * For setsockopt(2)
 #define SO_TIMESTAMPNS_OLD      35
 #define SO_TIMESTAMPING_OLD     37
 
+#define SO_TIMESTAMP_NEW        63
+#define SO_TIMESTAMPNS_NEW      64
+
 #if !defined(__KERNEL__)
 
-#define SO_TIMESTAMP            SO_TIMESTAMP_OLD
-#define SO_TIMESTAMPNS          SO_TIMESTAMPNS_OLD
+#if __BITS_PER_LONG == 64
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#else
+#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
+#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
+#endif
+
 #define SO_TIMESTAMPING         SO_TIMESTAMPING_OLD
 
 #define SCM_TIMESTAMP           SO_TIMESTAMP
index 7c180321ebd6f25cc50a7f6964b18ce6ca621348..cbc4b89c2fe49758e3dec88f7cb7b02b34b6dca9 100644 (file)
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 #define SOL_SOCKET     0xffff
 #define SO_TIMESTAMPNS_OLD      0x4013
 #define SO_TIMESTAMPING_OLD     0x4020
 
+#define SO_TIMESTAMP_NEW        0x4038
+#define SO_TIMESTAMPNS_NEW      0x4039
+
 #if !defined(__KERNEL__)
 
-#define SO_TIMESTAMP            SO_TIMESTAMP_OLD
-#define SO_TIMESTAMPNS          SO_TIMESTAMPNS_OLD
+#if __BITS_PER_LONG == 64
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#else
+#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
+#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
+#endif
+
 #define SO_TIMESTAMPING         SO_TIMESTAMPING_OLD
 
 #define SCM_TIMESTAMP           SO_TIMESTAMP
index d8a1bbc3e6c4df4b9e7ed0504416f93142df9d89..85127425b2948f2e663d962bb219114acb47519e 100644 (file)
@@ -3,6 +3,7 @@
 #define _ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 #define SOL_SOCKET     0xffff
 #define SO_TIMESTAMPNS_OLD       0x0021
 #define SO_TIMESTAMPING_OLD      0x0023
 
+#define SO_TIMESTAMP_NEW         0x0041
+#define SO_TIMESTAMPNS_NEW       0x0042
+
 #if !defined(__KERNEL__)
 
-#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
-#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#if __BITS_PER_LONG == 64
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#else
+#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
+#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
+#endif
+
 #define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
 
 #define SCM_TIMESTAMP          SO_TIMESTAMP
index 4001611a4c9fbf6b40e40005744fbeb3cc596c7b..831846617d07934503a21c39e512ecf023552698 100644 (file)
@@ -3498,12 +3498,30 @@ static inline void skb_get_timestamp(const struct sk_buff *skb,
        *stamp = ns_to_kernel_old_timeval(skb->tstamp);
 }
 
+static inline void skb_get_new_timestamp(const struct sk_buff *skb,
+                                        struct __kernel_sock_timeval *stamp)
+{
+       struct timespec64 ts = ktime_to_timespec64(skb->tstamp);
+
+       stamp->tv_sec = ts.tv_sec;
+       stamp->tv_usec = ts.tv_nsec / 1000;
+}
+
 static inline void skb_get_timestampns(const struct sk_buff *skb,
                                       struct timespec *stamp)
 {
        *stamp = ktime_to_timespec(skb->tstamp);
 }
 
+static inline void skb_get_new_timestampns(const struct sk_buff *skb,
+                                          struct __kernel_timespec *stamp)
+{
+       struct timespec64 ts = ktime_to_timespec64(skb->tstamp);
+
+       stamp->tv_sec = ts.tv_sec;
+       stamp->tv_nsec = ts.tv_nsec;
+}
+
 static inline void __net_timestamp(struct sk_buff *skb)
 {
        skb->tstamp = ktime_get_real();
index 2b229f7be8ebbc160706012f7ed03db85c5689d0..6679f3c120b0e26bf734a61b975b66b588e5f8e4 100644 (file)
@@ -805,6 +805,7 @@ enum sock_flags {
        SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */
        SOCK_TXTIME,
        SOCK_XDP, /* XDP is attached */
+       SOCK_TSTAMP_NEW, /* Indicates 64 bit timestamps always */
 };
 
 #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
index 4ef3aed31fb7923e26d568a786c5ff60fe556074..f22d3f7162f8a49fd903f4af5244f0e88dbe52d4 100644 (file)
@@ -3,6 +3,7 @@
 #define __ASM_GENERIC_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 #define SOL_SOCKET     1
 #define SO_TIMESTAMPNS_OLD      35
 #define SO_TIMESTAMPING_OLD     37
 
+#define SO_TIMESTAMP_NEW        63
+#define SO_TIMESTAMPNS_NEW      64
+
 #if !defined(__KERNEL__)
 
-#define SO_TIMESTAMP            SO_TIMESTAMP_OLD
-#define SO_TIMESTAMPNS          SO_TIMESTAMPNS_OLD
+#if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
+/* on 64-bit and x32, avoid the ?: operator */
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#else
+#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
+#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
+#endif
+
 #define SO_TIMESTAMPING         SO_TIMESTAMPING_OLD
 
 #define SCM_TIMESTAMP           SO_TIMESTAMP
index d5ca8641968fb15250dabf2ec2ada009647cbb88..14b987eab10c647818b702d248921676b56f849f 100644 (file)
@@ -868,9 +868,16 @@ set_rcvbuf:
                break;
 
        case SO_TIMESTAMP_OLD:
+       case SO_TIMESTAMP_NEW:
        case SO_TIMESTAMPNS_OLD:
+       case SO_TIMESTAMPNS_NEW:
                if (valbool)  {
-                       if (optname == SO_TIMESTAMP_OLD)
+                       if (optname == SO_TIMESTAMP_NEW || optname == SO_TIMESTAMPNS_NEW)
+                               sock_set_flag(sk, SOCK_TSTAMP_NEW);
+                       else
+                               sock_reset_flag(sk, SOCK_TSTAMP_NEW);
+
+                       if (optname == SO_TIMESTAMP_OLD || optname == SO_TIMESTAMP_NEW)
                                sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
                        else
                                sock_set_flag(sk, SOCK_RCVTSTAMPNS);
@@ -879,6 +886,7 @@ set_rcvbuf:
                } else {
                        sock_reset_flag(sk, SOCK_RCVTSTAMP);
                        sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+                       sock_reset_flag(sk, SOCK_TSTAMP_NEW);
                }
                break;
 
@@ -1245,11 +1253,20 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 
        case SO_TIMESTAMP_OLD:
                v.val = sock_flag(sk, SOCK_RCVTSTAMP) &&
+                               !sock_flag(sk, SOCK_TSTAMP_NEW) &&
                                !sock_flag(sk, SOCK_RCVTSTAMPNS);
                break;
 
        case SO_TIMESTAMPNS_OLD:
-               v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);
+               v.val = sock_flag(sk, SOCK_RCVTSTAMPNS) && !sock_flag(sk, SOCK_TSTAMP_NEW);
+               break;
+
+       case SO_TIMESTAMP_NEW:
+               v.val = sock_flag(sk, SOCK_RCVTSTAMP) && sock_flag(sk, SOCK_TSTAMP_NEW);
+               break;
+
+       case SO_TIMESTAMPNS_NEW:
+               v.val = sock_flag(sk, SOCK_RCVTSTAMPNS) && sock_flag(sk, SOCK_TSTAMP_NEW);
                break;
 
        case SO_TIMESTAMPING_OLD:
index 3ce41b04c0f0abfc5e6613cda6e225f7125b8132..4e9388bf104a42cda8d0a203b904a17e5ef419f6 100644 (file)
@@ -1861,20 +1861,37 @@ static void tcp_update_recv_tstamps(struct sk_buff *skb,
 static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
                               struct scm_timestamping *tss)
 {
-       struct __kernel_old_timeval tv;
+       int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
        bool has_timestamping = false;
 
        if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) {
                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
                        if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
-                                        sizeof(tss->ts[0]), &tss->ts[0]);
+                               if (new_tstamp) {
+                                       struct __kernel_timespec kts = {tss->ts[0].tv_sec, tss->ts[0].tv_nsec};
+
+                                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
+                                                sizeof(kts), &kts);
+                               } else {
+                                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
+                                                sizeof(tss->ts[0]), &tss->ts[0]);
+                               }
                        } else {
-                               tv.tv_sec = tss->ts[0].tv_sec;
-                               tv.tv_usec = tss->ts[0].tv_nsec / 1000;
-
-                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
-                                        sizeof(tv), &tv);
+                               if (new_tstamp) {
+                                       struct __kernel_sock_timeval stv;
+
+                                       stv.tv_sec = tss->ts[0].tv_sec;
+                                       stv.tv_usec = tss->ts[0].tv_nsec / 1000;
+                                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
+                                                sizeof(stv), &stv);
+                               } else {
+                                       struct __kernel_old_timeval tv;
+
+                                       tv.tv_sec = tss->ts[0].tv_sec;
+                                       tv.tv_usec = tss->ts[0].tv_nsec / 1000;
+                                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
+                                                sizeof(tv), &tv);
+                               }
                        }
                }
 
index eeb4639adbe5c8e914baafc577a5c2de3237fa39..65571a6273c320b60bef16c8921fa80fe389648f 100644 (file)
@@ -348,7 +348,7 @@ static int rds_set_transport(struct rds_sock *rs, char __user *optval,
 }
 
 static int rds_enable_recvtstamp(struct sock *sk, char __user *optval,
-                                int optlen)
+                                int optlen, int optname)
 {
        int val, valbool;
 
@@ -360,6 +360,9 @@ static int rds_enable_recvtstamp(struct sock *sk, char __user *optval,
 
        valbool = val ? 1 : 0;
 
+       if (optname == SO_TIMESTAMP_NEW)
+               sock_set_flag(sk, SOCK_TSTAMP_NEW);
+
        if (valbool)
                sock_set_flag(sk, SOCK_RCVTSTAMP);
        else
@@ -431,8 +434,9 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
                release_sock(sock->sk);
                break;
        case SO_TIMESTAMP_OLD:
+       case SO_TIMESTAMP_NEW:
                lock_sock(sock->sk);
-               ret = rds_enable_recvtstamp(sock->sk, optval, optlen);
+               ret = rds_enable_recvtstamp(sock->sk, optval, optlen, optname);
                release_sock(sock->sk);
                break;
        case SO_RDS_MSG_RXPATH_LATENCY:
index 435bf2320cd3aa5b968c6d02e44a6ae71614a62f..6bb6b16ca270aaa89975e5fcf639edd7b2ee82f8 100644 (file)
@@ -550,8 +550,20 @@ static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg,
        if ((inc->i_rx_tstamp != 0) &&
            sock_flag(rds_rs_to_sk(rs), SOCK_RCVTSTAMP)) {
                struct __kernel_old_timeval tv = ns_to_kernel_old_timeval(inc->i_rx_tstamp);
-               ret = put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
-                              sizeof(tv), &tv);
+
+               if (!sock_flag(rds_rs_to_sk(rs), SOCK_TSTAMP_NEW)) {
+                       ret = put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
+                                      sizeof(tv), &tv);
+               } else {
+                       struct __kernel_sock_timeval sk_tv;
+
+                       sk_tv.tv_sec = tv.tv_sec;
+                       sk_tv.tv_usec = tv.tv_usec;
+
+                       ret = put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
+                                      sizeof(sk_tv), &sk_tv);
+               }
+
                if (ret)
                        goto out;
        }
index 9cc281cdb9d94b08eaba1c89fc506c53b34317a7..1de96abd78d3e55100100088991dacf876997846 100644 (file)
@@ -705,6 +705,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb)
 {
        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
+       int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
        struct scm_timestamping tss;
        int empty = 1, false_tstamp = 0;
        struct skb_shared_hwtstamps *shhwtstamps =
@@ -719,15 +720,33 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 
        if (need_software_tstamp) {
                if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-                       struct __kernel_old_timeval tv;
-                       skb_get_timestamp(skb, &tv);
-                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
-                                sizeof(tv), &tv);
+                       if (new_tstamp) {
+                               struct __kernel_sock_timeval tv;
+
+                               skb_get_new_timestamp(skb, &tv);
+                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
+                                        sizeof(tv), &tv);
+                       } else {
+                               struct __kernel_old_timeval tv;
+
+                               skb_get_timestamp(skb, &tv);
+                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
+                                        sizeof(tv), &tv);
+                       }
                } else {
-                       struct timespec ts;
-                       skb_get_timestampns(skb, &ts);
-                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
-                                sizeof(ts), &ts);
+                       if (new_tstamp) {
+                               struct __kernel_timespec ts;
+
+                               skb_get_new_timestampns(skb, &ts);
+                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
+                                        sizeof(ts), &ts);
+                       } else {
+                               struct timespec ts;
+
+                               skb_get_timestampns(skb, &ts);
+                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
+                                        sizeof(ts), &ts);
+                       }
                }
        }