Skip to contentSkip to conversation

net: y2038-safe socket timestamps

PATCH Superseded Deepa Dinamani 4 participants 23 messages Dec 11, 2018 – Dec 18, 2018

Subsystems (20)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover net: y2038-safe socket timestamps

The series introduces new socket timestamps that are y2038 safe.

The time data types used for the existing socket timestamp
options: SO_TIMESTAMP, SO_TIMESTAMPNS and SO_TIMESTAMPING are not y2038 safe. The series introduces SO_TIMESTAMP_NEW, SO_TIMESTAMPNS_NEW and SO_TIMESTAMPING_NEW to replace these. These new timestamps can be used on all architectures.

The alternative considered was to extend the sys_setsockopt() by using the flags. We did not receive any strong opinions about either of the approaches. Hence, this was chosen, as glibc folks preferred this.

The series does not deal with updating the internal kernel socket calls like rxrpc to make them y2038 safe. This will be dealt with separately.

Note that the timestamps behavior already does not match the man page specific behavior:
SIOCGSTAMP
This ioctl should only be used if the socket option SO_TIMESTAMP
is not set on the socket. Otherwise, it returns the timestamp of the last packet that was received while SO_TIMESTAMP was not set, or it fails if no such packet has been received, (i.e., ioctl(2) returns -1 with errno set to ENOENT).

The recommendation is to update the man page to remove the above statement.

The overview of the series is as below:
1. Delete asm specific socket.h when possible.
2. Support SO/SCM_TIMESTAMP* options only in userspace.
3. Rename current SO/SCM_TIMESTAMP* to SO/SCM_TIMESTAMP*_OLD.
3. Alter socket options so that SOCK_RCVTSTAMPNS does not rely on SOCK_RCVTSTAMP.
4. Introduce y2038 safe types for socket timestamp.
5. Introduce new y2038 safe socket options SO/SCM_TIMESTAMP*_NEW.

Changes since v1:
* Dropped the change to disentangle sock flags
* Renamed sock_timeval to __kernel_sock_timeval
* Updated a few comments
* Added documentation changes

Deepa Dinamani (8):
arch: Use asm-generic/socket.h when possible
sockopt: Rename SO_TIMESTAMP* to SO_TIMESTAMP*_OLD
arch: sparc: Override struct __kernel_old_timeval
socket: Use old_timeval types for socket timestamps
socket: Add struct __kernel_sock_timeval
socket: Add SO_TIMESTAMP[NS]_NEW
socket: Add SO_TIMESTAMPING_NEW
socket: Update timestamping Documentation

 Documentation/networking/timestamping.txt |  43 ++++++-
 arch/alpha/include/uapi/asm/socket.h      |  35 ++++--
 arch/ia64/include/uapi/asm/Kbuild         |   1 +
 arch/ia64/include/uapi/asm/socket.h       | 120 -------------------
 arch/mips/include/uapi/asm/socket.h       |  34 ++++--
 arch/parisc/include/uapi/asm/socket.h     |  34 ++++--
 arch/s390/include/uapi/asm/Kbuild         |   1 +
 arch/s390/include/uapi/asm/socket.h       | 117 ------------------
 arch/sparc/include/uapi/asm/posix_types.h |  10 ++
 arch/sparc/include/uapi/asm/socket.h      |  36 ++++--
 arch/x86/include/uapi/asm/Kbuild          |   1 +
 arch/x86/include/uapi/asm/socket.h        |   1 -
 arch/xtensa/include/asm/Kbuild            |   1 +
 arch/xtensa/include/uapi/asm/Kbuild       |   1 +
 arch/xtensa/include/uapi/asm/socket.h     | 122 -------------------
 drivers/isdn/mISDN/socket.c               |   2 +-
 include/linux/skbuff.h                    |  24 +++-
 include/linux/socket.h                    |   7 ++
 include/net/sock.h                        |   1 +
 include/uapi/asm-generic/socket.h         |  35 ++++--
 include/uapi/linux/errqueue.h             |   4 +
 include/uapi/linux/time.h                 |   7 ++
 net/bluetooth/hci_sock.c                  |   4 +-
 net/compat.c                              |  12 +-
 net/core/scm.c                            |  27 +++++
 net/core/sock.c                           | 138 ++++++++++++++--------
 net/ipv4/tcp.c                            |  82 ++++++++-----
 net/rds/af_rds.c                          |  10 +-
 net/rds/recv.c                            |  18 ++-
 net/rxrpc/local_object.c                  |   2 +-
 net/smc/af_smc.c                          |   3 +-
 net/socket.c                              |  64 +++++++---
 32 files changed, 478 insertions(+), 519 deletions(-)
 delete mode 100644 arch/ia64/include/uapi/asm/socket.h
 delete mode 100644 arch/s390/include/uapi/asm/socket.h
 delete mode 100644 arch/x86/include/uapi/asm/socket.h
 delete mode 100644 arch/xtensa/include/uapi/asm/socket.h

base-commit: b124b524bc97868cc2b5656e6ffa21a9b752b7e0

Signature · 25 lines
2.17.1

Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]

Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
#1 lore raw

PATCH v2 1/8 arch: Use asm-generic/socket.h when possible

Many architectures maintain an arch specific copy of the file even though there are no differences with the asm-generic one. Allow these architectures to use the generic one instead.

---
 arch/ia64/include/uapi/asm/Kbuild     |   1 +
 arch/ia64/include/uapi/asm/socket.h   | 120 -------------------------
 arch/s390/include/uapi/asm/Kbuild     |   1 +
 arch/s390/include/uapi/asm/socket.h   | 117 ------------------------
 arch/x86/include/uapi/asm/Kbuild      |   1 +
 arch/x86/include/uapi/asm/socket.h    |   1 -
 arch/xtensa/include/asm/Kbuild        |   1 +
 arch/xtensa/include/uapi/asm/Kbuild   |   1 +
 arch/xtensa/include/uapi/asm/socket.h | 122 --------------------------
 9 files changed, 5 insertions(+), 360 deletions(-)
 delete mode 100644 arch/ia64/include/uapi/asm/socket.h
 delete mode 100644 arch/s390/include/uapi/asm/socket.h
 delete mode 100644 arch/x86/include/uapi/asm/socket.h
 delete mode 100644 arch/xtensa/include/uapi/asm/socket.h
arch/ia64/include/uapi/asm/Kbuild +1 -0
index ccce0ea65e05..37ea5ec1b94d 100644
@@ -9,3 +9,4 @@ generic-y += msgbuf.h
 generic-y += poll.h
 generic-y += sembuf.h
 generic-y += shmbuf.h
+generic-y += socket.h
arch/ia64/include/uapi/asm/socket.h deleted +0 -120

120 lines not on this page · raw message

arch/s390/include/uapi/asm/Kbuild +1 -0
index dc38a90cf091..15bb61228b74 100644
@@ -15,6 +15,7 @@ generic-y += poll.h
 generic-y += resource.h
 generic-y += sembuf.h
 generic-y += shmbuf.h
+generic-y += socket.h
 generic-y += sockios.h
 generic-y += swab.h
 generic-y += termbits.h
arch/s390/include/uapi/asm/socket.h deleted +0 -117

117 lines not on this page · raw message

arch/x86/include/uapi/asm/Kbuild +1 -0
index 322681622d1e..a400e71a13ce 100644
@@ -6,3 +6,4 @@ generated-y += unistd_32.h
 generated-y += unistd_64.h
 generated-y += unistd_x32.h
 generic-y += poll.h
+generic-y += socket.h
arch/x86/include/uapi/asm/socket.h deleted +0 -1
deleted file mode 100644
index 6b71384b9d8b..000000000000
@@ -1 +0,0 @@
-#include <asm-generic/socket.h>
arch/xtensa/include/asm/Kbuild +1 -0
index e255683cd520..809f39ce08c0 100644
@@ -25,6 +25,7 @@ generic-y += percpu.h
 generic-y += preempt.h
 generic-y += rwsem.h
 generic-y += sections.h
+generic-y += socket.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += vga.h
arch/xtensa/include/uapi/asm/Kbuild +1 -0
index f95cad300369..fc2680dace55 100644
@@ -10,5 +10,6 @@ generic-y += ioctl.h
 generic-y += kvm_para.h
 generic-y += resource.h
 generic-y += siginfo.h
+generic-y += socket.h
 generic-y += statfs.h
 generic-y += termios.h
arch/xtensa/include/uapi/asm/socket.h deleted +0 -122

122 lines not on this page · raw message

Signature · 1 line
2.17.1
#2 lore raw

PATCH v2 2/8 sockopt: Rename SO_TIMESTAMP* to SO_TIMESTAMP*_OLD

In reply to Deepa Dinamani

SO_TIMESTAMP, SO_TIMESTAMPNS and SO_TIMESTAMPING options, the way they are currently defined, are not y2038 safe. Subsequent patches in the series add new y2038 safe versions of these options which provide 64 bit timestamps on all architectures uniformly.
Hence, rename existing options with OLD tag suffixes.

Also note that kernel will not use the untagged SO_TIMESTAMP* and SCM_TIMESTAMP* options internally anymore.

---
 arch/alpha/include/uapi/asm/socket.h  | 23 ++++++++++++++++-------
 arch/mips/include/uapi/asm/socket.h   | 23 ++++++++++++++++-------
 arch/parisc/include/uapi/asm/socket.h | 23 ++++++++++++++++-------
 arch/sparc/include/uapi/asm/socket.h  | 24 ++++++++++++++++--------
 include/uapi/asm-generic/socket.h     | 23 ++++++++++++++++-------
 net/compat.c                          |  6 +++---
 net/core/sock.c                       | 16 ++++++++--------
 net/ipv4/tcp.c                        |  6 +++---
 net/rds/af_rds.c                      |  2 +-
 net/rds/recv.c                        |  2 +-
 net/rxrpc/local_object.c              |  2 +-
 net/socket.c                          |  8 ++++----
 12 files changed, 101 insertions(+), 57 deletions(-)
arch/alpha/include/uapi/asm/socket.h +16 -7
index 065fb372e355..00e45c80e574 100644
@@ -51,13 +51,9 @@
 #define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
-#define SO_TIMESTAMP		29
-#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
@@ -66,9 +62,6 @@
 
 #define SO_MARK			36
 
-#define SO_TIMESTAMPING		37
-#define SCM_TIMESTAMPING	SO_TIMESTAMPING
-
 #define SO_RXQ_OVFL             40
 
 #define SO_WIFI_STATUS		41
@@ -115,4 +108,20 @@
 #define SO_TXTIME		61
 #define SCM_TXTIME		SO_TXTIME
 
+#define SO_TIMESTAMP_OLD         29
+#define SO_TIMESTAMPNS_OLD       35
+#define SO_TIMESTAMPING_OLD      37
+
+#if !defined(__KERNEL__)
+
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
+
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+#define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif
+
 #endif /* _UAPI_ASM_SOCKET_H */
arch/mips/include/uapi/asm/socket.h +16 -7
index 71370fb3ceef..b9553f770346 100644
@@ -65,21 +65,14 @@
 #define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
-#define SO_TIMESTAMP		29
-#define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #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
 
 #define SO_MARK			36
 
-#define SO_TIMESTAMPING		37
-#define SCM_TIMESTAMPING	SO_TIMESTAMPING
-
 #define SO_RXQ_OVFL		40
 
 #define SO_WIFI_STATUS		41
@@ -126,4 +119,20 @@
 #define SO_TXTIME		61
 #define SCM_TXTIME		SO_TXTIME
 
+#define SO_TIMESTAMP_OLD         29
+#define SO_TIMESTAMPNS_OLD       35
+#define SO_TIMESTAMPING_OLD      37
+
+#if !defined(__KERNEL__)
+
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
+
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+#define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif
+
 #endif /* _UAPI_ASM_SOCKET_H */
arch/parisc/include/uapi/asm/socket.h +16 -7
index 061b9cf2a779..37cdfe64bb27 100644
@@ -34,10 +34,6 @@
 #define SO_BSDCOMPAT	0x400e
 #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
@@ -58,9 +54,6 @@
 
 #define SO_MARK			0x401f
 
-#define SO_TIMESTAMPING		0x4020
-#define SCM_TIMESTAMPING	SO_TIMESTAMPING
-
 #define SO_RXQ_OVFL             0x4021
 
 #define SO_WIFI_STATUS		0x4022
@@ -107,4 +100,20 @@
 #define SO_TXTIME		0x4036
 #define SCM_TXTIME		SO_TXTIME
 
+#define SO_TIMESTAMP_OLD         0x4012
+#define SO_TIMESTAMPNS_OLD       0x4013
+#define SO_TIMESTAMPING_OLD      0x4020
+
+#if !defined(__KERNEL__)
+
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
+
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+#define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif
+
 #endif /* _UAPI_ASM_SOCKET_H */
arch/sparc/include/uapi/asm/socket.h +16 -8
index 7ea35e5601b6..ca573641fc6c 100644
@@ -33,7 +33,6 @@
 #define SO_PROTOCOL	0x1028
 #define SO_DOMAIN	0x1029
 
-
 /* Linux specific, keep the same. */
 #define SO_NO_CHECK	0x000b
 #define SO_PRIORITY	0x000c
@@ -45,19 +44,12 @@
 #define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		0x001c
-#define SO_TIMESTAMP		0x001d
-#define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
-#define SO_TIMESTAMPNS		0x0021
-#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			0x0022
 
-#define SO_TIMESTAMPING		0x0023
-#define SCM_TIMESTAMPING	SO_TIMESTAMPING
-
 #define SO_RXQ_OVFL             0x0024
 
 #define SO_WIFI_STATUS		0x0025
@@ -109,4 +101,20 @@
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002
 #define SO_SECURITY_ENCRYPTION_NETWORK		0x5004
 
+#define SO_TIMESTAMP_OLD         0x001d
+#define SO_TIMESTAMPNS_OLD       0x0021
+#define SO_TIMESTAMPING_OLD      0x0023
+
+#if !defined(__KERNEL__)
+
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
+
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+#define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif
+
 #endif /* _ASM_SOCKET_H */
include/uapi/asm-generic/socket.h +16 -7
index a12692e5f7a8..dc704e41203d 100644
@@ -46,21 +46,14 @@
 #define SO_GET_FILTER		SO_ATTACH_FILTER
 
 #define SO_PEERNAME		28
-#define SO_TIMESTAMP		29
-#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
 
 #define SO_MARK			36
 
-#define SO_TIMESTAMPING		37
-#define SCM_TIMESTAMPING	SO_TIMESTAMPING
-
 #define SO_PROTOCOL		38
 #define SO_DOMAIN		39
 
@@ -110,4 +103,20 @@
 #define SO_TXTIME		61
 #define SCM_TXTIME		SO_TXTIME
 
+#define SO_TIMESTAMP_OLD         29
+#define SO_TIMESTAMPNS_OLD       35
+#define SO_TIMESTAMPING_OLD      37
+
+#if !defined(__KERNEL__)
+
+#define SO_TIMESTAMP           SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
+
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+#define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif
+
 #endif /* __ASM_GENERIC_SOCKET_H */
net/compat.c +3 -3
index 47a614b370cd..720ab07276b0 100644
@@ -219,7 +219,7 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
 	}
 
 	if (!COMPAT_USE_64BIT_TIME) {
-		if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
+		if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) {
 			struct timeval *tv = (struct timeval *)data;
 			ctv.tv_sec = tv->tv_sec;
 			ctv.tv_usec = tv->tv_usec;
@@ -227,8 +227,8 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
 			len = sizeof(ctv);
 		}
 		if (level == SOL_SOCKET &&
-		    (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
-			int count = type == SCM_TIMESTAMPNS ? 1 : 3;
+		    (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) {
+			int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3;
 			int i;
 			struct timespec *ts = (struct timespec *)data;
 			for (i = 0; i < count; i++) {
net/core/sock.c +8 -8
index 6d7e189e3cd9..cf990db9b2a0 100644
@@ -814,10 +814,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
 			clear_bit(SOCK_PASSCRED, &sock->flags);
 		break;
 
-	case SO_TIMESTAMP:
-	case SO_TIMESTAMPNS:
+	case SO_TIMESTAMP_OLD:
+	case SO_TIMESTAMPNS_OLD:
 		if (valbool)  {
-			if (optname == SO_TIMESTAMP)
+			if (optname == SO_TIMESTAMP_OLD)
 				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
 			else
 				sock_set_flag(sk, SOCK_RCVTSTAMPNS);
@@ -829,7 +829,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
 		}
 		break;
 
-	case SO_TIMESTAMPING:
+	case SO_TIMESTAMPING_OLD:
 		if (val & ~SOF_TIMESTAMPING_MASK) {
 			ret = -EINVAL;
 			break;
@@ -1182,16 +1182,16 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 		sock_warn_obsolete_bsdism("getsockopt");
 		break;
 
-	case SO_TIMESTAMP:
+	case SO_TIMESTAMP_OLD:
 		v.val = sock_flag(sk, SOCK_RCVTSTAMP) &&
 				!sock_flag(sk, SOCK_RCVTSTAMPNS);
 		break;
 
-	case SO_TIMESTAMPNS:
+	case SO_TIMESTAMPNS_OLD:
 		v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);
 		break;
 
-	case SO_TIMESTAMPING:
+	case SO_TIMESTAMPING_OLD:
 		v.val = sk->sk_tsflags;
 		break;
 
@@ -2118,7 +2118,7 @@ int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
 			return -EINVAL;
 		sockc->mark = *(u32 *)CMSG_DATA(cmsg);
 		break;
-	case SO_TIMESTAMPING:
+	case SO_TIMESTAMPING_OLD:
 		if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32)))
 			return -EINVAL;
 
net/ipv4/tcp.c +3 -3
index 252048776dbb..496848ab0269 100644
@@ -1870,13 +1870,13 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
 	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, SCM_TIMESTAMPNS,
+				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, SCM_TIMESTAMP,
+				put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
 					 sizeof(tv), &tv);
 			}
 		}
@@ -1896,7 +1896,7 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
 
 	if (has_timestamping) {
 		tss->ts[1] = (struct timespec) {0};
-		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPING,
+		put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD,
 			 sizeof(*tss), tss);
 	}
 }
net/rds/af_rds.c +1 -1
index 65387e1e6964..eeb4639adbe5 100644
@@ -430,7 +430,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
 		ret = rds_set_transport(rs, optval, optlen);
 		release_sock(sock->sk);
 		break;
-	case SO_TIMESTAMP:
+	case SO_TIMESTAMP_OLD:
 		lock_sock(sock->sk);
 		ret = rds_enable_recvtstamp(sock->sk, optval, optlen);
 		release_sock(sock->sk);
net/rds/recv.c +1 -1
index 727639dac8a7..04e30d63a159 100644
@@ -550,7 +550,7 @@ 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 timeval tv = ktime_to_timeval(inc->i_rx_tstamp);
-		ret = put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
+		ret = put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
 			       sizeof(tv), &tv);
 		if (ret)
 			goto out;
net/rxrpc/local_object.c +1 -1
index 0906e51d3cfb..15cf42d5b53a 100644
@@ -202,7 +202,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
 
 		/* We want receive timestamps. */
 		opt = 1;
-		ret = kernel_setsockopt(local->socket, SOL_SOCKET, SO_TIMESTAMPNS,
+		ret = kernel_setsockopt(local->socket, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
 					(char *)&opt, sizeof(opt));
 		if (ret < 0) {
 			_debug("setsockopt failed");
net/socket.c +4 -4
index f1ede2a64985..dfc5742ccfbb 100644
@@ -670,7 +670,7 @@ static bool skb_is_err_queue(const struct sk_buff *skb)
  * before the software timestamp is received, a hardware TX timestamp may be
  * returned only if there is no software TX timestamp. Ignore false software
  * timestamps, which may be made in the __sock_recv_timestamp() call when the
- * option SO_TIMESTAMP(NS) is enabled on the socket, even when the skb has a
+ * option SO_TIMESTAMP_OLD(NS) is enabled on the socket, even when the skb has a
  * hardware timestamp.
  */
 static bool skb_is_swtx_tstamp(const struct sk_buff *skb, int false_tstamp)
@@ -722,12 +722,12 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 		if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
 			struct timeval tv;
 			skb_get_timestamp(skb, &tv);
-			put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
+			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, SCM_TIMESTAMPNS,
+			put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
 				 sizeof(ts), &ts);
 		}
 	}
@@ -747,7 +747,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 	}
 	if (!empty) {
 		put_cmsg(msg, SOL_SOCKET,
-			 SCM_TIMESTAMPING, sizeof(tss), &tss);
+			 SO_TIMESTAMPING_OLD, sizeof(tss), &tss);
 
 		if (skb_is_err_queue(skb) && skb->len &&
 		    SKB_EXT_ERR(skb)->opt_stats)
Signature · 1 line
2.17.1
#3 lore raw

PATCH v2 3/8 arch: sparc: Override struct __kernel_old_timeval

In reply to Deepa Dinamani

struct __kernel_old_timeval is supposed to have the same layout as struct timeval. But, it was inadvarently missed that __kernel_suseconds has a different definition for sparc64.
Provide an asm-specific override that fixes it.

---
 arch/sparc/include/uapi/asm/posix_types.h | 10 ++++++++++
 include/uapi/linux/time.h                 |  2 ++
 2 files changed, 12 insertions(+)
arch/sparc/include/uapi/asm/posix_types.h +10 -0
index fec499d6efb7..f139e0048628 100644
@@ -19,6 +19,16 @@ typedef unsigned short         __kernel_old_gid_t;
 typedef int		       __kernel_suseconds_t;
 #define __kernel_suseconds_t __kernel_suseconds_t
 
+typedef long		__kernel_long_t;
+typedef unsigned long	__kernel_ulong_t;
+#define __kernel_long_t __kernel_long_t
+
+struct __kernel_old_timeval {
+	__kernel_long_t tv_sec;
+	__kernel_suseconds_t tv_usec;
+};
+#define __kernel_old_timeval __kernel_old_timeval
+
 #else
 /* sparc 32 bit */
 
include/uapi/linux/time.h +2 -0
index 6b56a2208be7..04d5587f30d3 100644
@@ -63,10 +63,12 @@ struct __kernel_itimerspec {
  * here, this is probably because it is not y2038 safe and needs to
  * be changed to use another interface.
  */
+#ifndef __kernel_old_timeval
 struct __kernel_old_timeval {
 	__kernel_long_t tv_sec;
 	__kernel_long_t tv_usec;
 };
+#endif
 
 /*
  * The IDs of the various system clocks (for POSIX.1b interval timers):
Signature · 1 line
2.17.1
#4 lore raw

PATCH v2 4/8 socket: Use old_timeval types for socket timestamps

In reply to Deepa Dinamani

As part of y2038 solution, all internal uses of struct timeval are replaced by struct __kernel_old_timeval and struct compat_timeval by struct old_timeval32. Make socket timestamps use these new types.

This is mainly to be able to verify that the kernel build is y2038 safe when such non y2038 safe types are not supported anymore.

---
 drivers/isdn/mISDN/socket.c | 2 +-
 include/linux/skbuff.h      | 6 +++---
 net/bluetooth/hci_sock.c    | 4 ++--
 net/compat.c                | 6 +++---
 net/ipv4/tcp.c              | 2 +-
 net/rds/recv.c              | 2 +-
 net/socket.c                | 2 +-
 7 files changed, 12 insertions(+), 12 deletions(-)
drivers/isdn/mISDN/socket.c +1 -1
index 15d3ca37669a..4ab8b1b6608f 100644
@@ -103,7 +103,7 @@ mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
 static inline void
 mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
 {
-	struct timeval	tv;
+	struct __kernel_old_timeval	tv;
 
 	if (_pms(sk)->cmask & MISDN_TIME_STAMP) {
 		skb_get_timestamp(skb, &tv);
include/linux/skbuff.h +3 -3
index a2e8297a5b00..e2dc01330cb1 100644
@@ -3453,16 +3453,16 @@ static inline ktime_t skb_get_ktime(const struct sk_buff *skb)
 /**
  *	skb_get_timestamp - get timestamp from a skb
  *	@skb: skb to get stamp from
- *	@stamp: pointer to struct timeval to store stamp in
+ *	@stamp: pointer to struct __kernel_old_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)
+				     struct __kernel_old_timeval *stamp)
 {
-	*stamp = ktime_to_timeval(skb->tstamp);
+	*stamp = ns_to_kernel_old_timeval(skb->tstamp);
 }
 
 static inline void skb_get_timestampns(const struct sk_buff *skb,
net/bluetooth/hci_sock.c +2 -2
index 10dfd20c748e..32aff3755480 100644
@@ -1400,9 +1400,9 @@ static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
 
 	if (mask & HCI_CMSG_TSTAMP) {
 #ifdef CONFIG_COMPAT
-		struct compat_timeval ctv;
+		struct old_timeval32 ctv;
 #endif
-		struct timeval tv;
+		struct __kernel_old_timeval tv;
 		void *data;
 		int len;
 
net/compat.c +3 -3
index 720ab07276b0..8dea66c96926 100644
@@ -209,8 +209,8 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
 {
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
-	struct compat_timeval ctv;
-	struct compat_timespec cts[3];
+	struct old_timeval32 ctv;
+	struct old_timespec32 cts[3];
 	int cmlen;
 
 	if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
@@ -220,7 +220,7 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
 
 	if (!COMPAT_USE_64BIT_TIME) {
 		if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) {
-			struct timeval *tv = (struct timeval *)data;
+			struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data;
 			ctv.tv_sec = tv->tv_sec;
 			ctv.tv_usec = tv->tv_usec;
 			data = &ctv;
net/ipv4/tcp.c +1 -1
index 496848ab0269..5a86ce0bdf32 100644
@@ -1864,7 +1864,7 @@ 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 timeval tv;
+	struct __kernel_old_timeval tv;
 	bool has_timestamping = false;
 
 	if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) {
net/rds/recv.c +1 -1
index 04e30d63a159..435bf2320cd3 100644
@@ -549,7 +549,7 @@ 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 timeval tv = ktime_to_timeval(inc->i_rx_tstamp);
+		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 (ret)
net/socket.c +1 -1
index dfc5742ccfbb..c92f0e97ae58 100644
@@ -720,7 +720,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 
 	if (need_software_tstamp) {
 		if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-			struct timeval tv;
+			struct __kernel_old_timeval tv;
 			skb_get_timestamp(skb, &tv);
 			put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
 				 sizeof(tv), &tv);
Signature · 1 line
2.17.1
#5 lore raw

PATCH v2 5/8 socket: Add struct __kernel_sock_timeval

In reply to Deepa Dinamani

The new type is meant to be used as a y2038 safe structure to be used as part of cmsg data.
Presently the SO_TIMESTAMP socket option uses struct timeval for timestamps. This is not y2038 safe.
Subsequent patches in the series add new y2038 safe socket option to be used in the place of SO_TIMESTAMP_OLD. struct __kernel_sock_timeval will be used as the timestamp format at that time.

struct __kernel_sock_timeval also maintains the same layout across 32 bit and 64 bit ABIs.

---
 include/uapi/linux/time.h | 5 +++++
 1 file changed, 5 insertions(+)
include/uapi/linux/time.h +5 -0
index 04d5587f30d3..b8ad1b86b942 100644
@@ -70,6 +70,11 @@ struct __kernel_old_timeval {
 };
 #endif
 
+struct __kernel_sock_timeval {
+	__s64 tv_sec;
+	__s64 tv_usec;
+};
+
 /*
  * The IDs of the various system clocks (for POSIX.1b interval timers):
  */
Signature · 1 line
2.17.1
#6 lore raw

PATCH v2 6/8 socket: Add SO_TIMESTAMP[NS]_NEW

In reply to Deepa Dinamani

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.

---
 arch/alpha/include/uapi/asm/socket.h  | 15 ++++++-
 arch/mips/include/uapi/asm/socket.h   | 14 ++++++-
 arch/parisc/include/uapi/asm/socket.h | 14 ++++++-
 arch/sparc/include/uapi/asm/socket.h  | 14 ++++++-
 include/linux/skbuff.h                | 18 +++++++++
 include/net/sock.h                    |  1 +
 include/uapi/asm-generic/socket.h     | 15 ++++++-
 net/core/sock.c                       | 51 ++++++++++++++++++------
 net/ipv4/tcp.c                        | 57 +++++++++++++++++++--------
 net/rds/af_rds.c                      |  8 +++-
 net/rds/recv.c                        | 16 +++++++-
 net/socket.c                          | 47 ++++++++++++++++------
 12 files changed, 216 insertions(+), 54 deletions(-)
arch/alpha/include/uapi/asm/socket.h +13 -2
index 00e45c80e574..352e3dc0b3d9 100644
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 /*
@@ -110,12 +111,22 @@
 
 #define SO_TIMESTAMP_OLD         29
 #define SO_TIMESTAMPNS_OLD       35
+
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #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
arch/mips/include/uapi/asm/socket.h +12 -2
index b9553f770346..d1752e3f1248 100644
@@ -11,6 +11,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /*
  * For setsockopt(2)
@@ -123,10 +124,19 @@
 #define SO_TIMESTAMPNS_OLD       35
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #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
arch/parisc/include/uapi/asm/socket.h +12 -2
index 37cdfe64bb27..0a45b668abd1 100644
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
@@ -104,10 +105,19 @@
 #define SO_TIMESTAMPNS_OLD       0x4013
 #define SO_TIMESTAMPING_OLD      0x4020
 
+#define SO_TIMESTAMP_NEW         0x4037
+#define SO_TIMESTAMPNS_NEW       0x4038
+
 #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
arch/sparc/include/uapi/asm/socket.h +12 -2
index ca573641fc6c..dc8527cae5a7 100644
@@ -3,6 +3,7 @@
 #define _ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
@@ -105,10 +106,19 @@
 #define SO_TIMESTAMPNS_OLD       0x0021
 #define SO_TIMESTAMPING_OLD      0x0023
 
+#define SO_TIMESTAMP_NEW         0x0040
+#define SO_TIMESTAMPNS_NEW       0x0041
+
 #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
include/linux/skbuff.h +18 -0
index e2dc01330cb1..1d583c3e7f89 100644
@@ -3465,12 +3465,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();
include/net/sock.h +1 -0
index f665d74ae509..3c666a12cf6c 100644
@@ -801,6 +801,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))
include/uapi/asm-generic/socket.h +13 -2
index dc704e41203d..0b0fae6b57a9 100644
@@ -3,6 +3,7 @@
 #define __ASM_GENERIC_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 #define SOL_SOCKET	1
@@ -107,10 +108,20 @@
 #define SO_TIMESTAMPNS_OLD       35
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #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
net/core/sock.c +40 -11

70 lines not on this page · raw message

net/ipv4/tcp.c +41 -16

73 lines not on this page · raw message

net/rds/af_rds.c +6 -2
index eeb4639adbe5..65571a6273c3 100644
@@ -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:
net/rds/recv.c +14 -2
index 435bf2320cd3..6bb6b16ca270 100644
@@ -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;
 	}
net/socket.c +34 -13

59 lines not on this page · raw message

Signature · 1 line
2.17.1
#7 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 58 lines · Deepa Dinamani

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.

---
 arch/alpha/include/uapi/asm/socket.h  | 15 ++++++-
 arch/mips/include/uapi/asm/socket.h   | 14 ++++++-
 arch/parisc/include/uapi/asm/socket.h | 14 ++++++-
 arch/sparc/include/uapi/asm/socket.h  | 14 ++++++-
 include/linux/skbuff.h                | 18 +++++++++
 include/net/sock.h                    |  1 +
 include/uapi/asm-generic/socket.h     | 15 ++++++-
 net/core/sock.c                       | 51 ++++++++++++++++++------
 net/ipv4/tcp.c                        | 57 +++++++++++++++++++--------
 net/rds/af_rds.c                      |  8 +++-
 net/rds/recv.c                        | 16 +++++++-
 net/socket.c                          | 47 ++++++++++++++++------
 12 files changed, 216 insertions(+), 54 deletions(-)
arch/alpha/include/uapi/asm/socket.h +5 -0
index 00e45c80e574..352e3dc0b3d9 100644
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 /*
@@ -110,12 +111,22 @@
 
 #define SO_TIMESTAMP_OLD         29
 #define SO_TIMESTAMPNS_OLD       35
+
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #if !defined(__KERNEL__)
 

arch/alpha/include/uapi/asm/socket.h line 129

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +8 -2
-#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
+

This is not platform specific. Perhaps it can be deduplicated. The interface expects callers to include <linux/socket.h>, not <asm/socket.h> directly. So perhaps it can go there?

Quoted 60 lines
arch/alpha/include/uapi/asm/socket.h +34 -16
-/* Similar to __sock_recv_timestamp, but does not require an skb */
-static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
-                              struct scm_timestamping *tss)
+static void tcp_recv_sw_timestamp(struct msghdr *msg, const struct sock *sk, struct timespec64 *ts)
 {
-       struct __kernel_old_timeval tv;
-       bool has_timestamping = false;
+       int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
+
+       if (ts->tv_sec || ts->tv_nsec) {
+               if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
+                       if (new_tstamp) {
+                               struct __kernel_timespec kts = {ts->tv_sec, ts->tv_nsec};
+
+                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
+                                        sizeof(kts), &kts);
+                       } else {
+                               struct timespec ts_old = timespec64_to_timespec(*ts);
 
-       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]);
+                                        sizeof(ts), &ts_old);
+                       }
+               } else if (sock_flag(sk, SOCK_RCVTSTAMP)) {
+                       if (new_tstamp) {
+                               struct __kernel_sock_timeval stv;
+
+                               stv.tv_sec = ts->tv_sec;
+                               stv.tv_usec = ts->tv_nsec / 1000;
+
+                               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
+                                        sizeof(stv), &stv);
                        } else {
-                               tv.tv_sec = tss->ts[0].tv_sec;
-                               tv.tv_usec = tss->ts[0].tv_nsec / 1000;
+                               struct __kernel_old_timeval tv;
 
+                               tv.tv_sec = ts->tv_sec;
+                               tv.tv_usec = ts->tv_nsec / 1000;
                                put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
                                         sizeof(tv), &tv);
                        }
                }
-
-               if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
-                       has_timestamping = true;
-               else
-                       tss->ts[0] = (struct timespec) {0};
        }
+}
+
+/* Similar to __sock_recv_timestamp, but does not require an skb */
+static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
+                              struct scm_timestamping *tss)
+{
+       bool has_timestamping = false;
+       struct timespec64 ts = timespec_to_timespec64(tss->ts[0]);

arch/alpha/include/uapi/asm/socket.h

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +7 -0
+
+       tcp_recv_sw_timestamp(msg, sk, &ts);
+
+       if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
+               has_timestamping = true;
+       else
+               tss->ts[0] = (struct timespec) {0};
 
        if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
                if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)

This did not address yet the previous comments on consistency and unnecessary code churn.

The existing logic to differentiate SO_TIMESTAMP from SO_TIMESTAMPNS in both tcp_recv_timestamp and __sock_recv_timestamp is

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_RCVTSTAMPNS))
          /* timespec case */
      else
          /* timeval case */
  }

A new level of nesting needs to be added to differentiate .._OLD from .._NEW.

Even if massively changing the original functions, please do so consistently, either

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_TSTAMP_NEW) {
          /* new code */
      } else {
          if (sock_flag(sk, SOCK_RCVTSTAMPNS))
              /* timespec case */
          else
              /* timeval case */
     }
  }

or

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_TSTAMP_NEW) {
          if (sock_flag(sk, SOCK_RCVTSTAMPNS))
              /* new timespec case */
          else
              /* timespec case */
      } else {
           if (sock_flag(sk, SOCK_RCVTSTAMPNS))
               /* new timespec case */
           else
               /* timespec case */
      }
  }

But not one variant in one function and one in the other.

Deep nesting is hard to follow and, once again, massive code changes (even indentations) make git blame harder to use. So where possible, try to avoid both and just insert a branch to a new function for the .._NEW cases instead:

if (sock_flag(sk, SOCK_RCVTSTAMP)) {
+ if (sock_flag(sk, SOCK_TSTAMP_NEW)
+ __sock_recv_timestamp_new(..);
- if (sock_flag(sk, SOCK_RCVTSTAMPNS))
+ else if (sock_flag(sk, SOCK_RCVTSTAMPNS))

          /* timespec case */
      else
          /* timeval case */

}

and leave the rest of the function unmodified.

Quoted 8 lines
arch/alpha/include/uapi/asm/socket.h +8 -0
+static void sock_recv_sw_timestamp(struct msghdr *msg, struct sock *sk,
+                                  struct sk_buff *skb)
+{
+       if (sock_flag(sk, SOCK_TSTAMP_NEW)) {
+               if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
+                       struct __kernel_sock_timeval tv;
+
+                       skb_get_new_timestamp(skb, &tv);

arch/alpha/include/uapi/asm/socket.h

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +10 -0
+                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
+                                sizeof(tv), &tv);
+               } else {
+                       struct __kernel_timespec ts;
+
+                       skb_get_new_timestampns(skb, &ts);
+                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
+                                sizeof(ts), &ts);
+               }
+       }

In relation to previous: note the different branching approach to tcp_recv_timestamp.

Quoted 42 lines
arch/alpha/include/uapi/asm/socket.h +16 -14
+       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);
+       } else {
+               struct timespec ts;
+
+               skb_get_timestampns(skb, &ts);
+               put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
+                        sizeof(ts), &ts);
+       }
+}
 /*
  * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
  */
@@ -718,19 +750,8 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
                false_tstamp = 1;
        }
 
-       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);
-               } else {
-                       struct timespec ts;
-                       skb_get_timestampns(skb, &ts);
-                       put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
-                                sizeof(ts), &ts);
-               }
-       }
+       if (need_software_tstamp)
+               sock_recv_sw_timestamp(msg, sk, skb);
 
        memset(&tss, 0, sizeof(tss));
        if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
--

2.17.1

#8 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 18 lines

This did not address yet the previous comments on consistency and unnecessary code churn.

The existing logic to differentiate SO_TIMESTAMP from SO_TIMESTAMPNS in both tcp_recv_timestamp and __sock_recv_timestamp is

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_RCVTSTAMPNS))
          /* timespec case */
      else
          /* timeval case */
  }

A new level of nesting needs to be added to differentiate .._OLD from .._NEW.

Even if massively changing the original functions, please do so consistently, either

Quoted 10 lines
  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_TSTAMP_NEW) {
          /* new code */
      } else {
          if (sock_flag(sk, SOCK_RCVTSTAMPNS))
              /* timespec case */
          else
              /* timeval case */
     }
  }

This first example is wrong. I meant

   if (sock_flag(sk, SOCK_RCVTSTAMP)) {
       if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
           if (sock_flag(sk, SOCK_TSTAMP_NEW)
                /* new code */
          else
                /* timespec case */
       } else {
           if (sock_flag(sk, SOCK_TSTAMP_NEW)
                /* new code */
          else
                /* timeval case */
        }
   }
#9 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

In reply to Willem de Bruijn
Quoted 24 lines
Quoted 24 lines
arch/alpha/include/uapi/asm/socket.h +5 -0
index 00e45c80e574..352e3dc0b3d9 100644
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 /*
@@ -110,12 +111,22 @@
 
 #define SO_TIMESTAMP_OLD         29
 #define SO_TIMESTAMPNS_OLD       35
+
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #if !defined(__KERNEL__)
 
Quoted 14 lines

arch/alpha/include/uapi/asm/socket.h line 129

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +8 -2
-#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
+

This is not platform specific. Perhaps it can be deduplicated. The interface expects callers to include <linux/socket.h>, not <asm/socket.h> directly. So perhaps it can go there?

I'm not following what you are saying here.

Are you talking about in kernel users or userspace interface?

Userspace should always include sys/socket.h according to the man page. I'm not sure if userspace can even include linux/socket.h directly. On my distribution this includes bits/socket.h which in turn includes asm/socket.h.

Which file gets installed as asm/socket.h is defined per architecture in the kbuild file such as arch/ia64/include/uapi/asm/Kbuild (without series applied):

generic-y += poll.h
generic-y += sembuf.h
generic-y += shmbuf.h
generic-y += socket.h

Also the new timestamp numbers being added are not the same for all architectures.

So I'm not sure how this can be moved to linux/socket.h.

Quoted 62 lines

This did not address yet the previous comments on consistency and unnecessary code churn.

The existing logic to differentiate SO_TIMESTAMP from SO_TIMESTAMPNS in both tcp_recv_timestamp and __sock_recv_timestamp is

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_RCVTSTAMPNS))
          /* timespec case */
      else
          /* timeval case */
  }

A new level of nesting needs to be added to differentiate .._OLD from .._NEW.

Even if massively changing the original functions, please do so consistently, either

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_TSTAMP_NEW) {
          /* new code */
      } else {
          if (sock_flag(sk, SOCK_RCVTSTAMPNS))
              /* timespec case */
          else
              /* timeval case */
     }
  }

or

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
      if (sock_flag(sk, SOCK_TSTAMP_NEW) {
          if (sock_flag(sk, SOCK_RCVTSTAMPNS))
              /* new timespec case */
          else
              /* timespec case */
      } else {
           if (sock_flag(sk, SOCK_RCVTSTAMPNS))
               /* new timespec case */
           else
               /* timespec case */
      }
  }

But not one variant in one function and one in the other.

Deep nesting is hard to follow and, once again, massive code changes (even indentations) make git blame harder to use. So where possible, try to avoid both and just insert a branch to a new function for the .._NEW cases instead:

  if (sock_flag(sk, SOCK_RCVTSTAMP)) {
(quoted diff) +3 -1
+      if (sock_flag(sk, SOCK_TSTAMP_NEW)
+          __sock_recv_timestamp_new(..);
-      if (sock_flag(sk, SOCK_RCVTSTAMPNS))
+      else if (sock_flag(sk, SOCK_RCVTSTAMPNS))
          /* timespec case */
      else
          /* timeval case */
  }
Quoted 1 line

and leave the rest of the function unmodified.

Ok, I will keep the functions consistent.

-Deepa

#10 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 40 lines · Deepa Dinamani
Quoted 25 lines
Quoted 25 lines
arch/alpha/include/uapi/asm/socket.h +5 -0
index 00e45c80e574..352e3dc0b3d9 100644
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 /*
@@ -110,12 +111,22 @@
 
 #define SO_TIMESTAMP_OLD         29
 #define SO_TIMESTAMPNS_OLD       35
+
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #if !defined(__KERNEL__)
 
Quoted 14 lines

arch/alpha/include/uapi/asm/socket.h line 129

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +8 -2
-#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
+

This is not platform specific. Perhaps it can be deduplicated. The interface expects callers to include <linux/socket.h>, not <asm/socket.h> directly. So perhaps it can go there?

Quoted 8 lines

I'm not following what you are saying here.

Are you talking about in kernel users or userspace interface?

Userspace should always include sys/socket.h according to the man page. I'm not sure if userspace can even include linux/socket.h directly. On my distribution this includes bits/socket.h which in turn includes asm/socket.h.

I meant include/uapi/linux/socket.h.

But you're right that that is not referenced from sys/socket.h.

I do see a reference to it in my bits/socket.h

    /* Socket level message types.  This must match the definitions in
       <linux/socket.h>.  */

so perhaps the logic could be both there and in libc bits/socket.h.

Quoted 9 lines

Which file gets installed as asm/socket.h is defined per architecture in the kbuild file such as arch/ia64/include/uapi/asm/Kbuild (without series applied):

generic-y += poll.h
generic-y += sembuf.h
generic-y += shmbuf.h
generic-y += socket.h

Quoted 4 lines

Also the new timestamp numbers being added are not the same for all architectures.

So I'm not sure how this can be moved to linux/socket.h.

Does that matter, as long as they are defined? This basic block is the same between all archs:

-#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

It might be too complex to coordinate changes between kernel and libc headers, in which case you're right that this just has to live in (each arch's) asm/socket.h directly.

#11 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 53 lines · Willem de Bruijn
Quoted 40 lines · Deepa Dinamani
Quoted 25 lines
Quoted 25 lines
arch/alpha/include/uapi/asm/socket.h +5 -0
index 00e45c80e574..352e3dc0b3d9 100644
@@ -3,6 +3,7 @@
 #define _UAPI_ASM_SOCKET_H
 
 #include <asm/sockios.h>
+#include <asm/bitsperlong.h>
 
 /* For setsockopt(2) */
 /*
@@ -110,12 +111,22 @@
 
 #define SO_TIMESTAMP_OLD         29
 #define SO_TIMESTAMPNS_OLD       35
+
 #define SO_TIMESTAMPING_OLD      37
 
+#define SO_TIMESTAMP_NEW         62
+#define SO_TIMESTAMPNS_NEW       63
+
 #if !defined(__KERNEL__)
 
Quoted 14 lines

arch/alpha/include/uapi/asm/socket.h line 129

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +8 -2
-#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
+

This is not platform specific. Perhaps it can be deduplicated. The interface expects callers to include <linux/socket.h>, not <asm/socket.h> directly. So perhaps it can go there?

Quoted 8 lines

I'm not following what you are saying here.

Are you talking about in kernel users or userspace interface?

Userspace should always include sys/socket.h according to the man page. I'm not sure if userspace can even include linux/socket.h directly. On my distribution this includes bits/socket.h which in turn includes asm/socket.h.

I meant include/uapi/linux/socket.h.

Quoted 8 lines

But you're right that that is not referenced from sys/socket.h.

I do see a reference to it in my bits/socket.h

    /* Socket level message types.  This must match the definitions in
       <linux/socket.h>.  */

so perhaps the logic could be both there and in libc bits/socket.h.

bits/socket.h cannot be included directly, and it's just how one of the libc implementations decided to do it.
It doesn't even have to exist.

Quoted 9 lines
Quoted 9 lines

Which file gets installed as asm/socket.h is defined per architecture in the kbuild file such as arch/ia64/include/uapi/asm/Kbuild (without series applied):

generic-y += poll.h
generic-y += sembuf.h
generic-y += shmbuf.h
generic-y += socket.h

Quoted 7 lines
Quoted 4 lines

Also the new timestamp numbers being added are not the same for all architectures.

So I'm not sure how this can be moved to linux/socket.h.

Does that matter, as long as they are defined? This basic block is the same between all archs:

3 reasons for not doing this:

1. We do not want to break userspace. If we move this to linux/socket.h all the userspace programs now have to include linux/socket.h or get this definition through a new libc.
2. All the socket options are together in the file asm/socket.h. It doesn't seem good for maintainability to move just a few bits elsewhere.
3. There are only 4 arches (after the series is applied) that have their own asm/socket.h. And, this is because there seems to be significant differences to asm-generic/socket.h that don't seem logically obvious to group and eliminate some of the defines.

Also for the other comment. The reason the conditionals were not consistent is because they were not consistent to begin with. I'm trying to follow your request to keep code churn to minimal. It's just that I moved to a different function as that seemed logical to me. Do you prefer me to remove that refactoring?

-Deepa
_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038

#12 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 12 lines

3 reasons for not doing this:

1. We do not want to break userspace. If we move this to linux/socket.h all the userspace programs now have to include linux/socket.h or get this definition through a new libc.
2. All the socket options are together in the file asm/socket.h. It doesn't seem good for maintainability to move just a few bits elsewhere.
3. There are only 4 arches (after the series is applied) that have their own asm/socket.h. And, this is because there seems to be significant differences to asm-generic/socket.h that don't seem logically obvious to group and eliminate some of the defines.

Agreed. All good reasons to leave as is.

Quoted 2 lines

Also for the other comment. The reason the conditionals were not consistent is because they were not consistent to begin with.

The only difference I see is an inversion of the test. Nesting order is the same:

        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
        ...
        if (need_software_tstamp) {
                if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }
        }

vs

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
                        if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }
                }

I suggest just adding something like

        if (need_software_tstamp) {

+ if (sock_uses_new_tstamp(sk) {
+ __sock_recv_timestamp_new(msg, sk,
ktime_to_timespec64(skb->tstamp));
+ } else if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {

-               if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }

and

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
+                      if (sock_uses_new_tstamp(sk) {
+                           __sock_recv_timestamp_new(msg, sk, ts);
+                      else if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-                       if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }

I think we can use the same helper for both the sock and tcp variant. The only intended difference between the two functions, as described in the tcp_recv_timestamp function comment, is the absence of an skb in the tcp case. That is immaterial at this level.

Note also (2) tentative helper function sock_uses_new_tstamp(const struct sock *sk) instead of testing sock_flag(sk, SOCK_TSTAMP_NEW) directly. Since the .._NEW variants are equivalent to .._OLD on 64-bit, I wonder if we can just compile out the branch. Something like

    static inline bool sock_uses_new_tstamp(const struct sock *sk) {
            return (sizeof(time_t) != sizeof(__kernel_long_t)) &&
                       sock_flag(sk, SOCK_TSTAMP_NEW);
    }
Quoted 3 lines

I'm trying to follow your request to keep code churn to minimal. It's just that I moved to a different function as that seemed logical to me. Do you prefer me to remove that refactoring?

Yes, please avoid rearranging existing code as much as possible.

If there is any refactoring to be done, I think it would be to deduplicate the shared logic between __sock_recv_timestamp and tcp_recv_timestamp. I think the first can be rewritten to reuse the second, if the only difference really is that the first takes an skb with embedded timestamps, while the second directly takes a pointer to struct scm_timestamping.

Either way, that's out of scope for this patchset.

#13 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 43 lines
Quoted 2 lines

Also for the other comment. The reason the conditionals were not consistent is because they were not consistent to begin with.

The only difference I see is an inversion of the test. Nesting order is the same:

        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
        ...
        if (need_software_tstamp) {
                if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }
        }

vs

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
                        if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }
                }

I suggest just adding something like

        if (need_software_tstamp) {
(quoted diff) +2 -0
+              if (sock_uses_new_tstamp(sk) {
+                   __sock_recv_timestamp_new(msg, sk,

ktime_to_timespec64(skb->tstamp));

net/ipv4/tcp.c +1 -1
+              } else if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-               if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }

and

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
net/ipv4/tcp.c +3 -1
+                      if (sock_uses_new_tstamp(sk) {
+                           __sock_recv_timestamp_new(msg, sk, ts);
+                      else if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-                       if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }
Quoted 4 lines

I think we can use the same helper for both the sock and tcp variant. The only intended difference between the two functions, as described in the tcp_recv_timestamp function comment, is the absence of an skb in the tcp case. That is immaterial at this level.

I will just not refactor things into a function: __sock_rescv_timestamp_new(). I will just add new conditionals for the new timestamps.
When you guys refactor the other timestamp stuff like you mentioned below maybe you can move the new timestamps to a new funtcion as you see fit.

The helper functions in skbuff.h might first need to be refactored first. But I again leave this to you guys.

Quoted 10 lines

Note also (2) tentative helper function sock_uses_new_tstamp(const struct sock *sk) instead of testing sock_flag(sk, SOCK_TSTAMP_NEW) directly. Since the .._NEW variants are equivalent to .._OLD on 64-bit, I wonder if we can just compile out the branch. Something like

    static inline bool sock_uses_new_tstamp(const struct sock *sk) {
            return (sizeof(time_t) != sizeof(__kernel_long_t)) &&
                       sock_flag(sk, SOCK_TSTAMP_NEW);
    }

You could just ifdef CONFIG_64BIT if you are worried about branching. Note that SO_TIMESTAMP is by default SO_TIMESTAMP_OLD on 64 bit machines. But, I will again leave the optimization to you. I will implement in a straight forward way and you guys can deicde how you want to optimize the fast path or what should it even be.

-Deepa

maintainer
#14 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

In reply to Willem de Bruijn
Quoted 52 lines · Willem de Bruijn
Quoted 13 lines

3 reasons for not doing this:

1. We do not want to break userspace. If we move this to linux/socket.h all the userspace programs now have to include linux/socket.h or get this definition through a new libc.
2. All the socket options are together in the file asm/socket.h. It doesn't seem good for maintainability to move just a few bits elsewhere.
3. There are only 4 arches (after the series is applied) that have their own asm/socket.h. And, this is because there seems to be significant differences to asm-generic/socket.h that don't seem logically obvious to group and eliminate some of the defines.

Agreed. All good reasons to leave as is.

Quoted 2 lines

Also for the other comment. The reason the conditionals were not consistent is because they were not consistent to begin with.

The only difference I see is an inversion of the test. Nesting order is the same:

        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
        ...
        if (need_software_tstamp) {
                if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }
        }

vs

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
                        if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }
                }

I suggest just adding something like

        if (need_software_tstamp) {
(quoted diff) +2 -0
+              if (sock_uses_new_tstamp(sk) {
+                   __sock_recv_timestamp_new(msg, sk,

ktime_to_timespec64(skb->tstamp));

net/ipv4/tcp.c +1 -1
+              } else if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-               if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }

and

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {

net/ipv4/tcp.c static void tcp_update_recv_tstamps(struct sk_buff *skb, · line 1896

Quoted 6 lines
net/ipv4/tcp.c +3 -1
+                      if (sock_uses_new_tstamp(sk) {
+                           __sock_recv_timestamp_new(msg, sk, ts);
+                      else if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-                       if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }

Generally speaking, I think we want the new time handling to be written as the default case rather than have it hidden away in a separate function. If we didn't have the sparc64 quirk with its unusual timeval definition, we'd only need a special flag for the old 32-bit format, but that doesn't work as long we have to support two different 64-bit formats for 64-bit timeval on sparc64 (32 or 64 bit microseconds).

Quoted 9 lines

Note also (2) tentative helper function sock_uses_new_tstamp(const struct sock *sk) instead of testing sock_flag(sk, SOCK_TSTAMP_NEW) directly. Since the .._NEW variants are equivalent to .._OLD on 64-bit, I wonder if we can just compile out the branch. Something like

    static inline bool sock_uses_new_tstamp(const struct sock *sk) {
            return (sizeof(time_t) != sizeof(__kernel_long_t)) &&
                       sock_flag(sk, SOCK_TSTAMP_NEW);
    }

I think that would break compat handling: when we have a 32-bit user space process, the difference between old and new timestamps is meaningful even on 64-bit kernels, but the distinction is only made all the way down in put_cmsg_compat().

Arnd

#15 lore raw

Re: [PATCH v2 6/8] socket: Add SO_TIMESTAMP[NS]_NEW

Quoted 80 lines · Arnd Bergmann
Quoted 52 lines · Willem de Bruijn
Quoted 13 lines

3 reasons for not doing this:

1. We do not want to break userspace. If we move this to linux/socket.h all the userspace programs now have to include linux/socket.h or get this definition through a new libc.
2. All the socket options are together in the file asm/socket.h. It doesn't seem good for maintainability to move just a few bits elsewhere.
3. There are only 4 arches (after the series is applied) that have their own asm/socket.h. And, this is because there seems to be significant differences to asm-generic/socket.h that don't seem logically obvious to group and eliminate some of the defines.

Agreed. All good reasons to leave as is.

Quoted 2 lines

Also for the other comment. The reason the conditionals were not consistent is because they were not consistent to begin with.

The only difference I see is an inversion of the test. Nesting order is the same:

        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
        ...
        if (need_software_tstamp) {
                if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }
        }

vs

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {
                        if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }
                }

I suggest just adding something like

        if (need_software_tstamp) {
(quoted diff) +2 -0
+              if (sock_uses_new_tstamp(sk) {
+                   __sock_recv_timestamp_new(msg, sk,

ktime_to_timespec64(skb->tstamp));

(quoted diff) +1 -1
+              } else if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-               if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                } else {
                }

and

                if (sock_flag(sk, SOCK_RCVTSTAMP)) {

Review

Quoted 6 lines
(quoted diff) +3 -1
+                      if (sock_uses_new_tstamp(sk) {
+                           __sock_recv_timestamp_new(msg, sk, ts);
+                      else if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-                       if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
                        } else {
                        }

Generally speaking, I think we want the new time handling to be written as the default case rather than have it hidden away in a separate function. If we didn't have the sparc64 quirk with its unusual timeval definition, we'd only need a special flag for the old 32-bit format, but that doesn't work as long we have to support two different 64-bit formats for 64-bit timeval on sparc64 (32 or 64 bit microseconds).

Quoted 9 lines

Note also (2) tentative helper function sock_uses_new_tstamp(const struct sock *sk) instead of testing sock_flag(sk, SOCK_TSTAMP_NEW) directly. Since the .._NEW variants are equivalent to .._OLD on 64-bit, I wonder if we can just compile out the branch. Something like

    static inline bool sock_uses_new_tstamp(const struct sock *sk) {
            return (sizeof(time_t) != sizeof(__kernel_long_t)) &&
                       sock_flag(sk, SOCK_TSTAMP_NEW);
    }
Quoted 4 lines

I think that would break compat handling: when we have a 32-bit user space process, the difference between old and new timestamps is meaningful even on 64-bit kernels, but the distinction is only made all the way down in put_cmsg_compat().

As I mentioned previously, I have refrained from adding these optimizations for now.
The old timestamps are as is and the new timestamps are not yet being used anywhere as we have not switched any of the architectures to use y2038 syscalls and data structures yet.
So even if these optimizations are needed these can be added as separate patches.
Let me know if this is acceptable for everyone and I can post the update.

-Deepa

#16 lore raw

PATCH v2 7/8 socket: Add SO_TIMESTAMPING_NEW

In reply to Deepa Dinamani

Add SO_TIMESTAMPING_NEW variant of socket timestamp options. This is the y2038 safe versions of the SO_TIMESTAMPING_OLD for all architectures.

---
 arch/alpha/include/uapi/asm/socket.h  |  5 +-
 arch/mips/include/uapi/asm/socket.h   |  5 +-
 arch/parisc/include/uapi/asm/socket.h |  5 +-
 arch/sparc/include/uapi/asm/socket.h  |  8 +--
 include/linux/socket.h                |  7 +++
 include/uapi/asm-generic/socket.h     |  5 +-
 include/uapi/linux/errqueue.h         |  4 ++
 net/core/scm.c                        | 27 ++++++++++
 net/core/sock.c                       | 73 +++++++++++++++------------
 net/ipv4/tcp.c                        | 29 ++++++-----
 net/smc/af_smc.c                      |  3 +-
 net/socket.c                          | 15 ++++--
 12 files changed, 122 insertions(+), 64 deletions(-)
arch/alpha/include/uapi/asm/socket.h +3 -2
index 352e3dc0b3d9..8b9f6f7f8087 100644
@@ -116,19 +116,20 @@
 
 #define SO_TIMESTAMP_NEW         62
 #define SO_TIMESTAMPNS_NEW       63
+#define SO_TIMESTAMPING_NEW      64
 
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
 #define SO_TIMESTAMP		SO_TIMESTAMP_OLD
 #define SO_TIMESTAMPNS		SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING		SO_TIMESTAMPING_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)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
 #endif
 
-#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
-
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 #define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
 #define SCM_TIMESTAMPING       SO_TIMESTAMPING
arch/mips/include/uapi/asm/socket.h +3 -2
index d1752e3f1248..9fc80c5d54e4 100644
@@ -126,19 +126,20 @@
 
 #define SO_TIMESTAMP_NEW         62
 #define SO_TIMESTAMPNS_NEW       63
+#define SO_TIMESTAMPING_NEW      64
 
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
 #define SO_TIMESTAMP		SO_TIMESTAMP_OLD
 #define SO_TIMESTAMPNS		SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING		SO_TIMESTAMPING_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)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
 #endif
 
-#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
-
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 #define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
 #define SCM_TIMESTAMPING       SO_TIMESTAMPING
arch/parisc/include/uapi/asm/socket.h +3 -2
index 0a45b668abd1..82f1c9447d6b 100644
@@ -107,19 +107,20 @@
 
 #define SO_TIMESTAMP_NEW         0x4037
 #define SO_TIMESTAMPNS_NEW       0x4038
+#define SO_TIMESTAMPING_NEW      0x4039
 
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
 #define SO_TIMESTAMP		SO_TIMESTAMP_OLD
 #define SO_TIMESTAMPNS		SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING		SO_TIMESTAMPING_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)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
 #endif
 
-#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
-
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 #define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
 #define SCM_TIMESTAMPING       SO_TIMESTAMPING
arch/sparc/include/uapi/asm/socket.h +5 -3
index dc8527cae5a7..5bdbb25c28d2 100644
@@ -106,20 +106,22 @@
 #define SO_TIMESTAMPNS_OLD       0x0021
 #define SO_TIMESTAMPING_OLD      0x0023
 
-#define SO_TIMESTAMP_NEW         0x0040
-#define SO_TIMESTAMPNS_NEW       0x0041
+#define SO_TIMESTAMP_NEW         0x0041
+#define SO_TIMESTAMPNS_NEW       0x0042
+#define SO_TIMESTAMPING_NEW      0x0043
 
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
 #define SO_TIMESTAMP		SO_TIMESTAMP_OLD
 #define SO_TIMESTAMPNS		SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING		SO_TIMESTAMPING_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)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
 #endif
 
-#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
 
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 #define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
include/linux/socket.h +7 -0
index 8b571e9b9f76..372fd77698a2 100644
@@ -350,6 +350,13 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
 
 struct timespec64;
 
+struct scm_timestamping_internal {
+	struct timespec64 ts[3];
+};
+
+extern void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss);
+extern void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss);
+
 /* The __sys_...msg variants allow MSG_CMSG_COMPAT iff
  * forbid_cmsg_compat==false
  */
include/uapi/asm-generic/socket.h +3 -2
index 0b0fae6b57a9..2fdfb6126246 100644
@@ -110,6 +110,7 @@
 
 #define SO_TIMESTAMP_NEW         62
 #define SO_TIMESTAMPNS_NEW       63
+#define SO_TIMESTAMPING_NEW         64
 
 #if !defined(__KERNEL__)
 
@@ -117,13 +118,13 @@
 /* on 64-bit and x32, avoid the ?: operator */
 #define SO_TIMESTAMP		SO_TIMESTAMP_OLD
 #define SO_TIMESTAMPNS		SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING		SO_TIMESTAMPING_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)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
 #endif
 
-#define SO_TIMESTAMPING        SO_TIMESTAMPING_OLD
-
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 #define SCM_TIMESTAMPNS        SO_TIMESTAMPNS
 #define SCM_TIMESTAMPING       SO_TIMESTAMPING
include/uapi/linux/errqueue.h +4 -0
index c0151200f7d1..d955b9e32288 100644
@@ -41,6 +41,10 @@ struct scm_timestamping {
 	struct timespec ts[3];
 };
 
+struct scm_timestamping64 {
+	struct __kernel_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].
net/core/scm.c +27 -0
index b1ff8a441748..52ef219cf6df 100644
@@ -29,6 +29,7 @@
 #include <linux/pid.h>
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
+#include <linux/errqueue.h>
 
 #include <linux/uaccess.h>
 
@@ -252,6 +253,32 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
 }
 EXPORT_SYMBOL(put_cmsg);
 
+void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss_internal)
+{
+	struct scm_timestamping64 tss;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tss.ts); i++) {
+		tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec;
+		tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec;
+	}
+
+	put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_NEW, sizeof(tss), &tss);
+}
+EXPORT_SYMBOL(put_cmsg_scm_timestamping64);
+
+void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss_internal)
+{
+	struct scm_timestamping tss;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tss.ts); i++)
+		tss.ts[i] = timespec64_to_timespec(tss_internal->ts[i]);
+
+	put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, sizeof(tss), &tss);
+}
+EXPORT_SYMBOL(put_cmsg_scm_timestamping);
+
 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
 {
 	struct cmsghdr __user *cm
net/core/sock.c +40 -33

85 lines not on this page · raw message

net/ipv4/tcp.c +15 -14
index 73e1628a3946..bc9907648cf5 100644
@@ -1847,17 +1847,17 @@ static int tcp_zerocopy_receive(struct sock *sk,
 #endif
 
 static void tcp_update_recv_tstamps(struct sk_buff *skb,
-				    struct scm_timestamping *tss)
+				    struct scm_timestamping_internal *tss)
 {
 	if (skb->tstamp)
-		tss->ts[0] = ktime_to_timespec(skb->tstamp);
+		tss->ts[0] = ktime_to_timespec64(skb->tstamp);
 	else
-		tss->ts[0] = (struct timespec) {0};
+		tss->ts[0] = (struct timespec64) {0};
 
 	if (skb_hwtstamps(skb)->hwtstamp)
-		tss->ts[2] = ktime_to_timespec(skb_hwtstamps(skb)->hwtstamp);
+		tss->ts[2] = ktime_to_timespec64(skb_hwtstamps(skb)->hwtstamp);
 	else
-		tss->ts[2] = (struct timespec) {0};
+		tss->ts[2] = (struct timespec64) {0};
 }
 
 static void tcp_recv_sw_timestamp(struct msghdr *msg, const struct sock *sk, struct timespec64 *ts)
@@ -1900,29 +1900,30 @@ static void tcp_recv_sw_timestamp(struct msghdr *msg, const struct sock *sk, str
 
 /* Similar to __sock_recv_timestamp, but does not require an skb */
 static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
-			       struct scm_timestamping *tss)
+			       struct scm_timestamping_internal *tss)
 {
 	bool has_timestamping = false;
-	struct timespec64 ts = timespec_to_timespec64(tss->ts[0]);
 
-	tcp_recv_sw_timestamp(msg, sk, &ts);
+	tcp_recv_sw_timestamp(msg, sk, &tss->ts[0]);
 
 	if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
 		has_timestamping = true;
 	else
-		tss->ts[0] = (struct timespec) {0};
+		tss->ts[0] = (struct timespec64) {0};
 
 	if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
 		if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)
 			has_timestamping = true;
 		else
-			tss->ts[2] = (struct timespec) {0};
+			tss->ts[2] = (struct timespec64) {0};
 	}
 
 	if (has_timestamping) {
-		tss->ts[1] = (struct timespec) {0};
-		put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD,
-			 sizeof(*tss), tss);
+		tss->ts[1] = (struct timespec64) {0};
+		if (sock_flag(sk, SOCK_TSTAMP_NEW))
+			put_cmsg_scm_timestamping64(msg, tss);
+		else
+			put_cmsg_scm_timestamping(msg, tss);
 	}
 }
 
@@ -1963,7 +1964,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
 	long timeo;
 	struct sk_buff *skb, *last;
 	u32 urg_hole = 0;
-	struct scm_timestamping tss;
+	struct scm_timestamping_internal tss;
 	bool has_tss = false;
 	bool has_cmsg;
 
net/smc/af_smc.c +2 -1
index 80e2119f1c70..e588305e9cf4 100644
@@ -280,7 +280,8 @@ static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk,
 			     (1UL << SOCK_RXQ_OVFL) | \
 			     (1UL << SOCK_WIFI_STATUS) | \
 			     (1UL << SOCK_NOFCS) | \
-			     (1UL << SOCK_FILTER_LOCKED))
+			     (1UL << SOCK_FILTER_LOCKED) | \
+			     (1UL << SOCK_TSTAMP_NEW))
 /* copy only relevant settings and flags of SOL_SOCKET level from smc to
  * clc socket (since smc is not called for these options from net/core)
  */
net/socket.c +10 -5
index 96fe831b79ad..d0c018645900 100644
@@ -731,14 +731,17 @@ static void sock_recv_sw_timestamp(struct msghdr *msg, struct sock *sk,
 			 sizeof(ts), &ts);
 	}
 }
+
 /*
  * 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)
 {
+
 	int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
-	struct scm_timestamping tss;
+	struct scm_timestamping_internal tss;
+
 	int empty = 1, false_tstamp = 0;
 	struct skb_shared_hwtstamps *shhwtstamps =
 		skb_hwtstamps(skb);
@@ -755,20 +758,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 
 	memset(&tss, 0, sizeof(tss));
 	if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
-	    ktime_to_timespec_cond(skb->tstamp, tss.ts + 0))
+	    ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0))
 		empty = 0;
 	if (shhwtstamps &&
 	    (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
 	    !skb_is_swtx_tstamp(skb, false_tstamp) &&
-	    ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) {
+	    ktime_to_timespec64_cond(shhwtstamps->hwtstamp, tss.ts + 2)) {
 		empty = 0;
 		if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&
 		    !skb_is_err_queue(skb))
 			put_ts_pktinfo(msg, skb);
 	}
 	if (!empty) {
-		put_cmsg(msg, SOL_SOCKET,
-			 SO_TIMESTAMPING_OLD, sizeof(tss), &tss);
+		if (sock_flag(sk, SOCK_TSTAMP_NEW))
+			put_cmsg_scm_timestamping64(msg, &tss);
+		else
+			put_cmsg_scm_timestamping(msg, &tss);
 
 		if (skb_is_err_queue(skb) && skb->len &&
 		    SKB_EXT_ERR(skb)->opt_stats)
Signature · 1 line
2.17.1
#17 lore raw

Re: [PATCH v2 7/8] socket: Add SO_TIMESTAMPING_NEW

Quoted 44 lines · Deepa Dinamani

Add SO_TIMESTAMPING_NEW variant of socket timestamp options. This is the y2038 safe versions of the SO_TIMESTAMPING_OLD for all architectures.

---
 arch/alpha/include/uapi/asm/socket.h  |  5 +-
 arch/mips/include/uapi/asm/socket.h   |  5 +-
 arch/parisc/include/uapi/asm/socket.h |  5 +-
 arch/sparc/include/uapi/asm/socket.h  |  8 +--
 include/linux/socket.h                |  7 +++
 include/uapi/asm-generic/socket.h     |  5 +-
 include/uapi/linux/errqueue.h         |  4 ++
 net/core/scm.c                        | 27 ++++++++++
 net/core/sock.c                       | 73 +++++++++++++++------------
 net/ipv4/tcp.c                        | 29 ++++++-----
 net/smc/af_smc.c                      |  3 +-
 net/socket.c                          | 15 ++++--
 12 files changed, 122 insertions(+), 64 deletions(-)
arch/alpha/include/uapi/asm/socket.h +1 -0
index 352e3dc0b3d9..8b9f6f7f8087 100644
@@ -116,19 +116,20 @@
 
 #define SO_TIMESTAMP_NEW         62
 #define SO_TIMESTAMPNS_NEW       63
+#define SO_TIMESTAMPING_NEW      64
 
 #if !defined(__KERNEL__)

arch/alpha/include/uapi/asm/socket.h line 131

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +2 -0
 
 #if __BITS_PER_LONG == 64
 #define SO_TIMESTAMP           SO_TIMESTAMP_OLD
 #define SO_TIMESTAMPNS         SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING                SO_TIMESTAMPING_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)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
 #endif

If the previous patch moves this block to a platform-independent header, that allows this patch to shrink considerably, too.

Quoted 70 lines
arch/alpha/include/uapi/asm/socket.h +39 -24
+static int setsockopt_timestamping(struct sock *sk, int type, int val)
+{
+       if (type == SO_TIMESTAMPING_NEW)
+               sock_set_flag(sk, SOCK_TSTAMP_NEW);
+
+       if (val & ~SOF_TIMESTAMPING_MASK)
+               return -EINVAL;
+
+       if (val & SOF_TIMESTAMPING_OPT_ID &&
+           !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) {
+               if (sk->sk_protocol == IPPROTO_TCP &&
+                   sk->sk_type == SOCK_STREAM) {
+                       if ((1 << sk->sk_state) &
+                           (TCPF_CLOSE | TCPF_LISTEN))
+                               return -EINVAL;
+                       sk->sk_tskey = tcp_sk(sk)->snd_una;
+               } else {
+                       sk->sk_tskey = 0;
+               }
+       }
+
+       if (val & SOF_TIMESTAMPING_OPT_STATS &&
+           !(val & SOF_TIMESTAMPING_OPT_TSONLY))
+               return -EINVAL;
+
+       sk->sk_tsflags = val;
+       if (val & SOF_TIMESTAMPING_RX_SOFTWARE) {
+               sock_enable_timestamp(sk,
+                                     SOCK_TIMESTAMPING_RX_SOFTWARE);
+       } else {
+               if (type == SO_TIMESTAMPING_NEW)
+                       sock_reset_flag(sk, SOCK_TSTAMP_NEW);
+               sock_disable_timestamp(sk,
+                                      (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE));
+       }
+
+       return 0;
+}
+
 /*
  *     This is meant for all protocols to use and covers goings on
  *     at the socket level. Everything here is generic.
@@ -851,39 +890,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_TIMESTAMPING_OLD:
-               if (val & ~SOF_TIMESTAMPING_MASK) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (val & SOF_TIMESTAMPING_OPT_ID &&
-                   !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) {
-                       if (sk->sk_protocol == IPPROTO_TCP &&
-                           sk->sk_type == SOCK_STREAM) {
-                               if ((1 << sk->sk_state) &
-                                   (TCPF_CLOSE | TCPF_LISTEN)) {
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                               sk->sk_tskey = tcp_sk(sk)->snd_una;
-                       } else {
-                               sk->sk_tskey = 0;
-                       }
-               }
-
-               if (val & SOF_TIMESTAMPING_OPT_STATS &&
-                   !(val & SOF_TIMESTAMPING_OPT_TSONLY)) {
-                       ret = -EINVAL;
-                       break;

arch/alpha/include/uapi/asm/socket.h int sock_setsockopt(struct socket *sock, int level, int optname, · line 893

Quoted 10 lines
arch/alpha/include/uapi/asm/socket.h +1 -9
-               }
-
-               sk->sk_tsflags = val;
-               if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
-                       sock_enable_timestamp(sk,
-                                             SOCK_TIMESTAMPING_RX_SOFTWARE);
-               else
-                       sock_disable_timestamp(sk,
-                                              (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE));
+               ret = setsockopt_timestamping(sk, optname, val);

Once again a lot of needless code churn. The only functional change is adding

+ if (type == SO_TIMESTAMPING_NEW)
+ sock_set_flag(sk, SOCK_TSTAMP_NEW);

arch/alpha/include/uapi/asm/socket.h int sock_setsockopt(struct socket *sock, int level, int optname,

Quoted 8 lines
arch/alpha/include/uapi/asm/socket.h +3 -1
 void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb)
 {
+
        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
-       struct scm_timestamping tss;
+       struct scm_timestamping_internal tss;
+

Unnecessary whitespace line

Quoted 5 lines
        int empty = 1, false_tstamp = 0;
        struct skb_shared_hwtstamps *shhwtstamps =
                skb_hwtstamps(skb);
arch/alpha/include/uapi/asm/socket.h +0 -0
@@ -755,20 +758,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 
maintainer
#18 lore raw

Re: [PATCH v2 7/8] socket: Add SO_TIMESTAMPING_NEW

Quoted 34 lines · Willem de Bruijn
Quoted 32 lines · Deepa Dinamani
net/core/sock.c +0 -28
@@ -851,39 +890,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_TIMESTAMPING_OLD:
-               if (val & ~SOF_TIMESTAMPING_MASK) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (val & SOF_TIMESTAMPING_OPT_ID &&
-                   !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) {
-                       if (sk->sk_protocol == IPPROTO_TCP &&
-                           sk->sk_type == SOCK_STREAM) {
-                               if ((1 << sk->sk_state) &
-                                   (TCPF_CLOSE | TCPF_LISTEN)) {
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                               sk->sk_tskey = tcp_sk(sk)->snd_una;
-                       } else {
-                               sk->sk_tskey = 0;
-                       }
-               }
-
-               if (val & SOF_TIMESTAMPING_OPT_STATS &&
-                   !(val & SOF_TIMESTAMPING_OPT_TSONLY)) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               sk->sk_tsflags = val;
-               if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
Quoted 8 lines

net/core/sock.c int sock_setsockopt(struct socket *sock, int level, int optname, · line 893

Quoted 6 lines
net/core/sock.c +1 -5
-                       sock_enable_timestamp(sk,
-                                             SOCK_TIMESTAMPING_RX_SOFTWARE);
-               else
-                       sock_disable_timestamp(sk,
-                                              (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE));
+               ret = setsockopt_timestamping(sk, optname, val);

Once again a lot of needless code churn. The only functional change is adding

I think moving the code out into a separate function is a useful cleanup, but if we want to do that, it may be better done in another patch, to make it easier to review.

Arnd

#19 lore raw

Re: [PATCH v2 7/8] socket: Add SO_TIMESTAMPING_NEW

Quoted 46 lines · Arnd Bergmann
Quoted 34 lines · Willem de Bruijn
Quoted 32 lines · Deepa Dinamani
net/core/sock.c +0 -28
@@ -851,39 +890,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_TIMESTAMPING_OLD:
-               if (val & ~SOF_TIMESTAMPING_MASK) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (val & SOF_TIMESTAMPING_OPT_ID &&
-                   !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) {
-                       if (sk->sk_protocol == IPPROTO_TCP &&
-                           sk->sk_type == SOCK_STREAM) {
-                               if ((1 << sk->sk_state) &
-                                   (TCPF_CLOSE | TCPF_LISTEN)) {
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                               sk->sk_tskey = tcp_sk(sk)->snd_una;
-                       } else {
-                               sk->sk_tskey = 0;
-                       }
-               }
-
-               if (val & SOF_TIMESTAMPING_OPT_STATS &&
-                   !(val & SOF_TIMESTAMPING_OPT_TSONLY)) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               sk->sk_tsflags = val;
-               if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
Quoted 8 lines

net/core/sock.c int sock_setsockopt(struct socket *sock, int level, int optname, · line 893

Quoted 6 lines
net/core/sock.c +1 -5
-                       sock_enable_timestamp(sk,
-                                             SOCK_TIMESTAMPING_RX_SOFTWARE);
-               else
-                       sock_disable_timestamp(sk,
-                                              (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE));
+               ret = setsockopt_timestamping(sk, optname, val);

Once again a lot of needless code churn. The only functional change is adding

Quoted 3 lines

I think moving the code out into a separate function is a useful cleanup, but if we want to do that, it may be better done in another patch, to make it easier to review.

I already removed this addition of function. I have open coded all the logic here and in the patch 6.
I will post an update.

-Deepa

#20 lore raw

PATCH v2 8/8 socket: Update timestamping Documentation

In reply to Deepa Dinamani

With the new y2038 safe timestamping options added, update the documentation to reflect the changes.

---
 Documentation/networking/timestamping.txt | 43 ++++++++++++++++++++---
 1 file changed, 38 insertions(+), 5 deletions(-)
Documentation/networking/timestamping.txt +38 -5
index 1be0b6f9e0cb..67e4ab3cdb86 100644
@@ -6,11 +6,21 @@ The interfaces for receiving network packages timestamps are:
 * SO_TIMESTAMP
   Generates a timestamp for each incoming packet in (not necessarily
   monotonic) system time. Reports the timestamp via recvmsg() in a
-  control message as struct timeval (usec resolution).
+  control message in usec resolution.
+  SO_TIMESTAMP is defined as SO_TIMESTAMP_NEW or SO_TIMESTAMP_OLD
+  based on the architecture type and time_t representation of libc.
+  Control message format is in struct __kernel_old_timeval for
+  SO_TIMESTAMP_OLD and in struct __kernel_sock_timeval for
+  SO_TIMESTAMP_NEW options respectively.
 
 * SO_TIMESTAMPNS
   Same timestamping mechanism as SO_TIMESTAMP, but reports the
-  timestamp as struct timespec (nsec resolution).
+  timestamp as struct timespec in nsec resolution.
+  SO_TIMESTAMPNS is defined as SO_TIMESTAMPNS_NEW or SO_TIMESTAMPNS_OLD
+  based on the architecture type and time_t representation of libc.
+  Control message format is in struct timespec for SO_TIMESTAMPNS_OLD
+  and in struct __kernel_timespec for SO_TIMESTAMPNS_NEW options
+  respectively.
 
 * IP_MULTICAST_LOOP + SO_TIMESTAMP[NS]
   Only for multicast:approximate transmit timestamp obtained by
@@ -22,7 +32,7 @@ The interfaces for receiving network packages timestamps are:
   timestamps for stream sockets.
 
 
-1.1 SO_TIMESTAMP:
+1.1 SO_TIMESTAMP (also SO_TIMESTAMP_OLD and SO_TIMESTAMP_NEW):
 
 This socket option enables timestamping of datagrams on the reception
 path. Because the destination socket, if any, is not known early in
@@ -31,15 +41,25 @@ same is true for all early receive timestamp options.
 
 For interface details, see `man 7 socket`.
 
+Always use SO_TIMESTAMP_NEW timestamp to always get timestamp in
+struct __kernel_sock_timeval format.
 
-1.2 SO_TIMESTAMPNS:
+SO_TIMESTAMP_OLD returns incorrect timestamps after the year 2038
+on 32 bit machines.
+
+1.2 SO_TIMESTAMPNS (also SO_TIMESTAMPNS_OLD and SO_TIMESTAMPNS_NEW):
 
 This option is identical to SO_TIMESTAMP except for the returned data type.
 Its struct timespec allows for higher resolution (ns) timestamps than the
 timeval of SO_TIMESTAMP (ms).
 
+Always use SO_TIMESTAMPNS_NEW timestamp to always get timestamp in
+struct __kernel_timespec format.
+
+SO_TIMESTAMPNS_OLD returns incorrect timestamps after the year 2038
+on 32 bit machines.
 
-1.3 SO_TIMESTAMPING:
+1.3 SO_TIMESTAMPING (also SO_TIMESTAMPING_OLD and SO_TIMESTAMPING_NEW):
 
 Supports multiple types of timestamp requests. As a result, this
 socket option takes a bitmap of flags, not a boolean. In
@@ -323,10 +343,23 @@ SO_TIMESTAMP and SO_TIMESTAMPNS records can be retrieved.
 These timestamps are returned in a control message with cmsg_level
 SOL_SOCKET, cmsg_type SCM_TIMESTAMPING, and payload of type
 
+For SO_TIMESTAMPING_OLD:
+
 struct scm_timestamping {
 	struct timespec ts[3];
 };
 
+For SO_TIMESTAMPING_NEW:
+
+struct scm_timestamping64 {
+	struct __kernel_timespec ts[3];
+
+Always use SO_TIMESTAMPING_NEW timestamp to always get timestamp in
+struct scm_timestamping64 format.
+
+SO_TIMESTAMPING_OLD returns incorrect timestamps after the year 2038
+on 32 bit machines.
+
 The structure can return up to three timestamps. This is a legacy
 feature. At least one field is non-zero at any time. Most timestamps
 are passed in ts[0]. Hardware timestamps are passed in ts[2].
Signature · 1 line
2.17.1
Acked-by on v2 8/8
#21 lore raw

Re: [PATCH v2 8/8] socket: Update timestamping Documentation

Quoted 5 lines · Deepa Dinamani

With the new y2038 safe timestamping options added, update the documentation to reflect the changes.

Thanks for adding documentation.

One suggestion below if this patchset is respun.

Quoted 9 lines
---
 Documentation/networking/timestamping.txt | 43 ++++++++++++++++++++---
 1 file changed, 38 insertions(+), 5 deletions(-)
Documentation/networking/timestamping.txt +0 -0
index 1be0b6f9e0cb..67e4ab3cdb86 100644

Documentation/networking/timestamping.txt The interfaces for receiving network packages timestamps are: · line 14

Quoted 10 lines
Documentation/networking/timestamping.txt +6 -1
@@ -6,11 +6,21 @@ The interfaces for receiving network packages timestamps are:
 * SO_TIMESTAMP
   Generates a timestamp for each incoming packet in (not necessarily
   monotonic) system time. Reports the timestamp via recvmsg() in a
-  control message as struct timeval (usec resolution).
+  control message in usec resolution.
+  SO_TIMESTAMP is defined as SO_TIMESTAMP_NEW or SO_TIMESTAMP_OLD
+  based on the architecture type and time_t representation of libc.
+  Control message format is in struct __kernel_old_timeval for
+  SO_TIMESTAMP_OLD and in struct __kernel_sock_timeval for
+  SO_TIMESTAMP_NEW options respectively.

Perhaps add one sentence to explain why this matters and how the sizeof(time_t) trick works:

on 64-bit old and new are the same. All fields are 64-bit wide. On 32-bit the old variant uses a signed 32-bit integer for time_t that will overflow in 2038.