Introduction:
The series is aimed at transitioning network timestamps to being y2038 safe. All patches can be reviewed and merged independently, except for the [PATCH 2/4], which is dependent on the [PATCH 1/4].
Socket timestamps and ioctl calls will be handled separately.
Thanks to Arnd Bergmann for discussing solution options with me.
Solution:
Data type struct timespec is not y2038 safe. Replace timespec with struct timespec64 which is y2038 safe.
Deepa Dinamani (4): kernel: time: Add current_nw_timestamp() for network timestamps net: ipv4: Use y2038 safe functions and data structures net: ipv4: tcp_probe: Replace timespec with timespec64 net: sctp: Convert log timestamps to be y2038 safe
include/linux/ip.h | 2 ++ include/linux/time64.h | 3 +++ kernel/time/time.c | 26 ++++++++++++++++++++++++++ net/ipv4/icmp.c | 5 +---- net/ipv4/ip_options.c | 13 +++++-------- net/ipv4/tcp_probe.c | 8 ++++---- net/sctp/probe.c | 10 +++++----- 7 files changed, 46 insertions(+), 21 deletions(-)
ICMP timestamp messages and IP source route options require timestamps to be in milliseconds modulo 24 hours from midnight UTC format.
Add a time function to support this. The function returns the required timestamp in network byte order.
The function also uses y2038 safe time functions and data structures.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Cc: John Stultz john.stultz@linaro.org Cc: Thomas Gleixner tglx@linutronix.de Cc: "David S. Miller" davem@davemloft.net Cc: Alexey Kuznetsov kuznet@ms2.inr.ac.ru Cc: James Morris jmorris@namei.org Cc: Hideaki YOSHIFUJI yoshfuji@linux-ipv6.org Cc: Patrick McHardy kaber@trash.net --- include/linux/ip.h | 2 ++ include/linux/time64.h | 3 +++ kernel/time/time.c | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+)
diff --git a/include/linux/ip.h b/include/linux/ip.h index 492bc65..edf923e 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -34,4 +34,6 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) { return (struct iphdr *)skb_transport_header(skb); } + +extern __be32 current_nw_timestamp(void); #endif /* _LINUX_IP_H */ diff --git a/include/linux/time64.h b/include/linux/time64.h index 367d5af..5b5db3b 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -35,6 +35,9 @@ struct itimerspec64 { #define NSEC_PER_SEC 1000000000L #define FSEC_PER_SEC 1000000000000000LL
+#define SECONDS_PER_DAY 86400 +#define MSEC_PER_DAY (SECONDS_PER_DAY * MSEC_PER_SEC) + /* Located here for timespec[64]_valid_strict */ #define TIME64_MAX ((s64)~((u64)1 << 63)) #define KTIME_MAX ((s64)~((u64)1 << 63)) diff --git a/kernel/time/time.c b/kernel/time/time.c index 86751c6..6df15df 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -245,6 +245,32 @@ struct timespec current_fs_time(struct super_block *sb) EXPORT_SYMBOL(current_fs_time);
/* + * current_nw_timestamp - Return network time + * + * Return milliseconds since midnight in network byte order. + */ +__be32 current_nw_timestamp(void) +{ + u64 now; + u32 secs; + u32 msecs; + struct timespec64 ts; + + ktime_get_ts64(&ts); + + /* Get secs since midnight. */ + now = div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs); + /* Convert to msecs. */ + msecs = secs * MSEC_PER_SEC; + /* Convert nsec to msec. */ + msecs += (u32)ts.tv_nsec/NSEC_PER_MSEC; + + /* Convert to network byte order. */ + return htons(msecs); +} +EXPORT_SYMBOL(current_nw_timestamp); + +/* * Convert jiffies to milliseconds and back. * * Avoid unnecessary multiplications/divisions in the
Hi,
Deepa Dinamani wrote:
ICMP timestamp messages and IP source route options require timestamps to be in milliseconds modulo 24 hours from midnight UTC format.
Add a time function to support this. The function returns the required timestamp in network byte order.
The function also uses y2038 safe time functions and data structures.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Cc: John Stultz john.stultz@linaro.org Cc: Thomas Gleixner tglx@linutronix.de Cc: "David S. Miller" davem@davemloft.net Cc: Alexey Kuznetsov kuznet@ms2.inr.ac.ru Cc: James Morris jmorris@namei.org Cc: Hideaki YOSHIFUJI yoshfuji@linux-ipv6.org Cc: Patrick McHardy kaber@trash.net
include/linux/ip.h | 2 ++ include/linux/time64.h | 3 +++ kernel/time/time.c | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+)
diff --git a/include/linux/ip.h b/include/linux/ip.h index 492bc65..edf923e 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -34,4 +34,6 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) { return (struct iphdr *)skb_transport_header(skb); }
+extern __be32 current_nw_timestamp(void); #endif /* _LINUX_IP_H */ diff --git a/include/linux/time64.h b/include/linux/time64.h index 367d5af..5b5db3b 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -35,6 +35,9 @@ struct itimerspec64 { #define NSEC_PER_SEC 1000000000L #define FSEC_PER_SEC 1000000000000000LL +#define SECONDS_PER_DAY 86400 +#define MSEC_PER_DAY (SECONDS_PER_DAY * MSEC_PER_SEC)
/* Located here for timespec[64]_valid_strict */ #define TIME64_MAX ((s64)~((u64)1 << 63)) #define KTIME_MAX ((s64)~((u64)1 << 63)) diff --git a/kernel/time/time.c b/kernel/time/time.c index 86751c6..6df15df 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -245,6 +245,32 @@ struct timespec current_fs_time(struct super_block *sb) EXPORT_SYMBOL(current_fs_time); /*
- current_nw_timestamp - Return network time
- Return milliseconds since midnight in network byte order.
- */
+__be32 current_nw_timestamp(void) +{
- u64 now;
- u32 secs;
- u32 msecs;
- struct timespec64 ts;
- ktime_get_ts64(&ts);
- /* Get secs since midnight. */
- now = div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs);
- /* Convert to msecs. */
- msecs = secs * MSEC_PER_SEC;
- /* Convert nsec to msec. */
- msecs += (u32)ts.tv_nsec/NSEC_PER_MSEC;
- /* Convert to network byte order. */
- return htons(msecs);
+} +EXPORT_SYMBOL(current_nw_timestamp);
+/*
- Convert jiffies to milliseconds and back.
- Avoid unnecessary multiplications/divisions in the
Since net/ipv4/* are the only users, it is enough to put it in under net/ipv4/.
include/linux/ip.h | 2 ++ include/linux/time64.h | 3 +++ kernel/time/time.c | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+)
diff --git a/include/linux/ip.h b/include/linux/ip.h index 492bc65..edf923e 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h @@ -34,4 +34,6 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) { return (struct iphdr *)skb_transport_header(skb); }
+extern __be32 current_nw_timestamp(void); #endif /* _LINUX_IP_H */ diff --git a/include/linux/time64.h b/include/linux/time64.h index 367d5af..5b5db3b 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -35,6 +35,9 @@ struct itimerspec64 { #define NSEC_PER_SEC 1000000000L #define FSEC_PER_SEC 1000000000000000LL
+#define SECONDS_PER_DAY 86400 +#define MSEC_PER_DAY (SECONDS_PER_DAY * MSEC_PER_SEC)
/* Located here for timespec[64]_valid_strict */ #define TIME64_MAX ((s64)~((u64)1 << 63)) #define KTIME_MAX ((s64)~((u64)1 << 63)) diff --git a/kernel/time/time.c b/kernel/time/time.c index 86751c6..6df15df 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -245,6 +245,32 @@ struct timespec current_fs_time(struct super_block *sb) EXPORT_SYMBOL(current_fs_time);
/*
- current_nw_timestamp - Return network time
- Return milliseconds since midnight in network byte order.
- */
+__be32 current_nw_timestamp(void) +{
u64 now;
u32 secs;
u32 msecs;
struct timespec64 ts;
ktime_get_ts64(&ts);
/* Get secs since midnight. */
now = div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs);
/* Convert to msecs. */
msecs = secs * MSEC_PER_SEC;
/* Convert nsec to msec. */
msecs += (u32)ts.tv_nsec/NSEC_PER_MSEC;
/* Convert to network byte order. */
return htons(msecs);
+} +EXPORT_SYMBOL(current_nw_timestamp);
+/*
- Convert jiffies to milliseconds and back.
- Avoid unnecessary multiplications/divisions in the
Since net/ipv4/* are the only users, it is enough to put it in under net/ipv4/.
time.c hosts functions that are used by individual subsystems like current_fs_time() used by filesystems (sometimes used by other subsystems also).
The network timestamp function is used for both source route ip option and timestamp icmp messages. So it makes it difficult for it to be owned by a single layer. This is the reason it was chosen to include here.
Another option is to include it in the lowest layer its used: af_inet.c. Is this what you were suggesting?
-Deepa
Hi,
Deepa Dinamani wrote:
include/linux/ip.h | 2 ++ include/linux/time64.h | 3 +++ kernel/time/time.c | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+)
Since net/ipv4/* are the only users, it is enough to put it in under net/ipv4/.
time.c hosts functions that are used by individual subsystems like current_fs_time() used by filesystems (sometimes used by other subsystems also).
The network timestamp function is used for both source route ip option and timestamp icmp messages. So it makes it difficult for it to be owned by a single layer. This is the reason it was chosen to include here.
Another option is to include it in the lowest layer its used: af_inet.c. Is this what you were suggesting?
Yes, that's right.
--yoshfuji
-Deepa
On Wednesday 24 February 2016 23:07:08 Deepa Dinamani wrote:
ICMP timestamp messages and IP source route options require timestamps to be in milliseconds modulo 24 hours from midnight UTC format.
Add a time function to support this. The function returns the required timestamp in network byte order.
The function also uses y2038 safe time functions and data structures.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com
For the implementation:
Reviewed-by: Arnd Bergmann arnd@arndb.de
For where to put the code, I have no better idea, but I agree with Hideaki Yoshifuji that it's a bit odd to place it in kernel/*.c when it's only used by net/ipv4.
Arnd
ICMP timestamp messages and IP source route options require timestamps to be in milliseconds modulo 24 hours from midnight UT format.
Timestamps are calculated from realtime by making a call to getnstimeofday() which uses struct timespec. timespec is not y2038 safe. Replace the above calls with y2038 safe current_nw_time() to obtain network timestamps which uses y2038 safe struct timespec64.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Cc: "David S. Miller" davem@davemloft.net Cc: Alexey Kuznetsov kuznet@ms2.inr.ac.ru Cc: James Morris jmorris@namei.org Cc: Hideaki YOSHIFUJI yoshfuji@linux-ipv6.org Cc: Patrick McHardy kaber@trash.net --- net/ipv4/icmp.c | 5 +---- net/ipv4/ip_options.c | 13 +++++-------- 2 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 36e2697..e43dfa3 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -931,7 +931,6 @@ static bool icmp_echo(struct sk_buff *skb) */ static bool icmp_timestamp(struct sk_buff *skb) { - struct timespec tv; struct icmp_bxm icmp_param; /* * Too short. @@ -942,9 +941,7 @@ static bool icmp_timestamp(struct sk_buff *skb) /* * Fill in the current time as ms since midnight UT: */ - getnstimeofday(&tv); - icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + - tv.tv_nsec / NSEC_PER_MSEC); + icmp_param.data.times[1] = current_nw_timestamp(); icmp_param.data.times[2] = icmp_param.data.times[1]; if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)) BUG(); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index bd24679..6958e7c 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -58,10 +58,8 @@ void ip_options_build(struct sk_buff *skb, struct ip_options *opt, if (opt->ts_needaddr) ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt); if (opt->ts_needtime) { - struct timespec tv; __be32 midtime; - getnstimeofday(&tv); - midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC); + midtime = current_nw_timestamp(); memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); } return; @@ -415,11 +413,10 @@ int ip_options_compile(struct net *net, break; } if (timeptr) { - struct timespec tv; - u32 midtime; - getnstimeofday(&tv); - midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC; - put_unaligned_be32(midtime, timeptr); + __be32 midtime; + + midtime = current_nw_timestamp(); + memcpy(timeptr, &midtime, 4); opt->is_changed = 1; } } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) {
On Wednesday 24 February 2016 23:07:09 Deepa Dinamani wrote:
ICMP timestamp messages and IP source route options require timestamps to be in milliseconds modulo 24 hours from midnight UT format.
Timestamps are calculated from realtime by making a call to getnstimeofday() which uses struct timespec. timespec is not y2038 safe. Replace the above calls with y2038 safe current_nw_time() to obtain network timestamps which uses y2038 safe struct timespec64.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com
Reviewed-by: Arnd Bergmann arnd@arndb.de
TCP probe log timestamps use struct timespec which is not y2038 safe. Even though timespec might be good enough here as it is used to represent delta time, the plan is to get rid of all uses of timespec in the kernel. Replace with struct timespec64 which is y2038 safe.
Prints still use unsigned long format and type. This is because long is 64 bit on 64 bit systems and 32 bit on 32 bit systems. Hence, time64_t(64 bit signed number) does not have a specifier that matches on both architectures.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Cc: "David S. Miller" davem@davemloft.net Cc: Alexey Kuznetsov kuznet@ms2.inr.ac.ru Cc: James Morris jmorris@namei.org Cc: Hideaki YOSHIFUJI yoshfuji@linux-ipv6.org Cc: Patrick McHardy kaber@trash.net --- net/ipv4/tcp_probe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index ebf5ff5..f6c50af 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -187,13 +187,13 @@ static int tcpprobe_sprint(char *tbuf, int n) { const struct tcp_log *p = tcp_probe.log + tcp_probe.tail; - struct timespec tv - = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start)); + struct timespec64 ts + = ktime_to_timespec64(ktime_sub(p->tstamp, tcp_probe.start));
return scnprintf(tbuf, n, "%lu.%09lu %pISpc %pISpc %d %#x %#x %u %u %u %u %u\n", - (unsigned long)tv.tv_sec, - (unsigned long)tv.tv_nsec, + (unsigned long)ts.tv_sec, + (unsigned long)ts.tv_nsec, &p->src, &p->dst, p->length, p->snd_nxt, p->snd_una, p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt, p->rcv_wnd); }
On Wednesday 24 February 2016 23:07:10 Deepa Dinamani wrote:
TCP probe log timestamps use struct timespec which is not y2038 safe. Even though timespec might be good enough here as it is used to represent delta time, the plan is to get rid of all uses of timespec in the kernel. Replace with struct timespec64 which is y2038 safe.
Prints still use unsigned long format and type. This is because long is 64 bit on 64 bit systems and 32 bit on 32 bit systems. Hence, time64_t(64 bit signed number) does not have a specifier that matches on both architectures.
Actually time64_t is always 'long long', but tv_sec is time_t (long) instead of time64_t on 64-bit architectures.
Using a %ll format string and a cast to s64 would work as well, but as you say above, it's not important here.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com
Reviewed-by: Arnd Bergmann arnd@arndb.de
On Thu, Feb 25, 2016 at 8:31 PM, Arnd Bergmann arnd@arndb.de wrote:
On Wednesday 24 February 2016 23:07:10 Deepa Dinamani wrote:
TCP probe log timestamps use struct timespec which is not y2038 safe. Even though timespec might be good enough here as it is used to represent delta time, the plan is to get rid of all uses of timespec in the kernel. Replace with struct timespec64 which is y2038 safe.
Prints still use unsigned long format and type. This is because long is 64 bit on 64 bit systems and 32 bit on 32 bit systems. Hence, time64_t(64 bit signed number) does not have a specifier that matches on both architectures.
Actually time64_t is always 'long long', but tv_sec is time_t (long) instead of time64_t on 64-bit architectures.
Using a %ll format string and a cast to s64 would work as well, but as you say above, it's not important here.
You are right. A cast to u64 would work as well. I missed that the size of long long on 64 bit architectures according to all current data models is equivalent to long.
I will leave the prints to be in long format. But, will reword the commit text in v2.
Thanks, -Deepa
SCTP probe log timestamps use struct timespec which is not y2038 safe. Use struct timespec64 which is 2038 safe instead.
Use monotonic time instead of real time as only time differences are logged.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Cc: Vlad Yasevich vyasevich@gmail.com Cc: Neil Horman nhorman@tuxdriver.com Cc: "David S. Miller" davem@davemloft.net Cc: linux-sctp@vger.kernel.org --- net/sctp/probe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/sctp/probe.c b/net/sctp/probe.c index 5e68b94..6cc2152 100644 --- a/net/sctp/probe.c +++ b/net/sctp/probe.c @@ -65,7 +65,7 @@ static struct { struct kfifo fifo; spinlock_t lock; wait_queue_head_t wait; - struct timespec tstart; + struct timespec64 tstart; } sctpw;
static __printf(1, 2) void printl(const char *fmt, ...) @@ -85,7 +85,7 @@ static __printf(1, 2) void printl(const char *fmt, ...) static int sctpprobe_open(struct inode *inode, struct file *file) { kfifo_reset(&sctpw.fifo); - getnstimeofday(&sctpw.tstart); + ktime_get_ts64(&sctpw.tstart);
return 0; } @@ -138,7 +138,7 @@ static sctp_disposition_t jsctp_sf_eat_sack(struct net *net, struct sk_buff *skb = chunk->skb; struct sctp_transport *sp; static __u32 lcwnd = 0; - struct timespec now; + struct timespec64 now;
sp = asoc->peer.primary_path;
@@ -149,8 +149,8 @@ static sctp_disposition_t jsctp_sf_eat_sack(struct net *net, (full || sp->cwnd != lcwnd)) { lcwnd = sp->cwnd;
- getnstimeofday(&now); - now = timespec_sub(now, sctpw.tstart); + ktime_get_ts64(&now); + now = timespec64_sub(now, sctpw.tstart);
printl("%lu.%06lu ", (unsigned long) now.tv_sec, (unsigned long) now.tv_nsec / NSEC_PER_USEC);
On Wed, Feb 24, 2016 at 11:07:11PM -0800, Deepa Dinamani wrote:
SCTP probe log timestamps use struct timespec which is not y2038 safe. Use struct timespec64 which is 2038 safe instead.
Use monotonic time instead of real time as only time differences are logged.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Cc: Vlad Yasevich vyasevich@gmail.com Cc: Neil Horman nhorman@tuxdriver.com Cc: "David S. Miller" davem@davemloft.net Cc: linux-sctp@vger.kernel.org
net/sctp/probe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/sctp/probe.c b/net/sctp/probe.c index 5e68b94..6cc2152 100644 --- a/net/sctp/probe.c +++ b/net/sctp/probe.c @@ -65,7 +65,7 @@ static struct { struct kfifo fifo; spinlock_t lock; wait_queue_head_t wait;
- struct timespec tstart;
- struct timespec64 tstart;
} sctpw; static __printf(1, 2) void printl(const char *fmt, ...) @@ -85,7 +85,7 @@ static __printf(1, 2) void printl(const char *fmt, ...) static int sctpprobe_open(struct inode *inode, struct file *file) { kfifo_reset(&sctpw.fifo);
- getnstimeofday(&sctpw.tstart);
- ktime_get_ts64(&sctpw.tstart);
return 0; } @@ -138,7 +138,7 @@ static sctp_disposition_t jsctp_sf_eat_sack(struct net *net, struct sk_buff *skb = chunk->skb; struct sctp_transport *sp; static __u32 lcwnd = 0;
- struct timespec now;
- struct timespec64 now;
sp = asoc->peer.primary_path; @@ -149,8 +149,8 @@ static sctp_disposition_t jsctp_sf_eat_sack(struct net *net, (full || sp->cwnd != lcwnd)) { lcwnd = sp->cwnd;
getnstimeofday(&now);
now = timespec_sub(now, sctpw.tstart);
ktime_get_ts64(&now);
now = timespec64_sub(now, sctpw.tstart);
printl("%lu.%06lu ", (unsigned long) now.tv_sec, (unsigned long) now.tv_nsec / NSEC_PER_USEC); -- 1.9.1
Acked-by: Neil Horman nhorman@tuxdriver.com
On Wednesday 24 February 2016 23:07:11 Deepa Dinamani wrote:
SCTP probe log timestamps use struct timespec which is not y2038 safe. Use struct timespec64 which is 2038 safe instead.
Use monotonic time instead of real time as only time differences are logged.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com
Reviewed-by: Arnd Bergmann arnd@arndb.de
From: Deepa Dinamani deepa.kernel@gmail.com Date: Wed, 24 Feb 2016 23:07:07 -0800
Introduction:
The series is aimed at transitioning network timestamps to being y2038 safe. All patches can be reviewed and merged independently, except for the [PATCH 2/4], which is dependent on the [PATCH 1/4].
Socket timestamps and ioctl calls will be handled separately.
Thanks to Arnd Bergmann for discussing solution options with me.
Solution:
Data type struct timespec is not y2038 safe. Replace timespec with struct timespec64 which is y2038 safe.
Please respin this, moving the helper into net/ipv4/af_inet.c as per the feedback given.
Thanks.