Commit 92f37fd2ee805aa77925c1e64fd56088b46094fc
Committed by
David S. Miller
1 parent
c7a3c5da35
Exists in
master
and in
39 other branches
[NET]: Adding SO_TIMESTAMPNS / SCM_TIMESTAMPNS support
Now that network timestamps use ktime_t infrastructure, we can add a new SOL_SOCKET sockopt SO_TIMESTAMPNS. This command is similar to SO_TIMESTAMP, but permits transmission of a 'timespec struct' instead of a 'timeval struct' control message. (nanosecond resolution instead of microsecond) Control message is labelled SCM_TIMESTAMPNS instead of SCM_TIMESTAMP A socket cannot mix SO_TIMESTAMP and SO_TIMESTAMPNS : the two modes are mutually exclusive. sock_recv_timestamp() became too big to be fully inlined so I added a __sock_recv_timestamp() helper function. Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> CC: linux-arch@vger.kernel.org Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 25 changed files with 101 additions and 13 deletions Side-by-side Diff
- include/asm-alpha/socket.h
- include/asm-arm/socket.h
- include/asm-arm26/socket.h
- include/asm-avr32/socket.h
- include/asm-cris/socket.h
- include/asm-frv/socket.h
- include/asm-h8300/socket.h
- include/asm-i386/socket.h
- include/asm-ia64/socket.h
- include/asm-m32r/socket.h
- include/asm-m68k/socket.h
- include/asm-mips/socket.h
- include/asm-parisc/socket.h
- include/asm-powerpc/socket.h
- include/asm-s390/socket.h
- include/asm-sh/socket.h
- include/asm-sparc/socket.h
- include/asm-sparc64/socket.h
- include/asm-v850/socket.h
- include/asm-x86_64/socket.h
- include/asm-xtensa/socket.h
- include/net/sock.h
- net/compat.c
- net/core/sock.c
- net/socket.c
include/asm-alpha/socket.h
include/asm-arm/socket.h
include/asm-arm26/socket.h
include/asm-avr32/socket.h
include/asm-cris/socket.h
include/asm-frv/socket.h
include/asm-h8300/socket.h
include/asm-i386/socket.h
include/asm-ia64/socket.h
include/asm-m32r/socket.h
include/asm-m68k/socket.h
include/asm-mips/socket.h
include/asm-parisc/socket.h
... | ... | @@ -33,6 +33,8 @@ |
33 | 33 | #define SO_PEERCRED 0x4011 |
34 | 34 | #define SO_TIMESTAMP 0x4012 |
35 | 35 | #define SCM_TIMESTAMP SO_TIMESTAMP |
36 | +#define SO_TIMESTAMPNS 0x4013 | |
37 | +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS | |
36 | 38 | |
37 | 39 | /* Security levels - as per NRL IPv6 - don't actually do anything */ |
38 | 40 | #define SO_SECURITY_AUTHENTICATION 0x4016 |
include/asm-powerpc/socket.h
include/asm-s390/socket.h
include/asm-sh/socket.h
include/asm-sparc/socket.h
... | ... | @@ -49,6 +49,8 @@ |
49 | 49 | |
50 | 50 | #define SO_PEERSEC 0x001e |
51 | 51 | #define SO_PASSSEC 0x001f |
52 | +#define SO_TIMESTAMPNS 0x0021 | |
53 | +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS | |
52 | 54 | |
53 | 55 | /* Security levels - as per NRL IPv6 - don't actually do anything */ |
54 | 56 | #define SO_SECURITY_AUTHENTICATION 0x5001 |
include/asm-sparc64/socket.h
... | ... | @@ -49,6 +49,8 @@ |
49 | 49 | |
50 | 50 | #define SO_PEERSEC 0x001e |
51 | 51 | #define SO_PASSSEC 0x001f |
52 | +#define SO_TIMESTAMPNS 0x0021 | |
53 | +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS | |
52 | 54 | |
53 | 55 | /* Security levels - as per NRL IPv6 - don't actually do anything */ |
54 | 56 | #define SO_SECURITY_AUTHENTICATION 0x5001 |
include/asm-v850/socket.h
include/asm-x86_64/socket.h
include/asm-xtensa/socket.h
include/net/sock.h
... | ... | @@ -390,6 +390,7 @@ |
390 | 390 | SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */ |
391 | 391 | SOCK_DBG, /* %SO_DEBUG setting */ |
392 | 392 | SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */ |
393 | + SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */ | |
393 | 394 | SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ |
394 | 395 | SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ |
395 | 396 | }; |
396 | 397 | |
... | ... | @@ -1283,21 +1284,17 @@ |
1283 | 1284 | return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR; |
1284 | 1285 | } |
1285 | 1286 | |
1287 | +extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, | |
1288 | + struct sk_buff *skb); | |
1289 | + | |
1286 | 1290 | static __inline__ void |
1287 | 1291 | sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) |
1288 | 1292 | { |
1289 | 1293 | ktime_t kt = skb->tstamp; |
1290 | 1294 | |
1291 | - if (sock_flag(sk, SOCK_RCVTSTAMP)) { | |
1292 | - struct timeval tv; | |
1293 | - /* Race occurred between timestamp enabling and packet | |
1294 | - receiving. Fill in the current time for now. */ | |
1295 | - if (kt.tv64 == 0) | |
1296 | - kt = ktime_get_real(); | |
1297 | - skb->tstamp = kt; | |
1298 | - tv = ktime_to_timeval(kt); | |
1299 | - put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(tv), &tv); | |
1300 | - } else | |
1295 | + if (sock_flag(sk, SOCK_RCVTSTAMP)) | |
1296 | + __sock_recv_timestamp(msg, sk, skb); | |
1297 | + else | |
1301 | 1298 | sk->sk_stamp = kt; |
1302 | 1299 | } |
1303 | 1300 |
net/compat.c
... | ... | @@ -215,6 +215,7 @@ |
215 | 215 | int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) |
216 | 216 | { |
217 | 217 | struct compat_timeval ctv; |
218 | + struct compat_timespec cts; | |
218 | 219 | struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; |
219 | 220 | struct compat_cmsghdr cmhdr; |
220 | 221 | int cmlen; |
... | ... | @@ -229,7 +230,14 @@ |
229 | 230 | ctv.tv_sec = tv->tv_sec; |
230 | 231 | ctv.tv_usec = tv->tv_usec; |
231 | 232 | data = &ctv; |
232 | - len = sizeof(struct compat_timeval); | |
233 | + len = sizeof(ctv); | |
234 | + } | |
235 | + if (level == SOL_SOCKET && type == SO_TIMESTAMPNS) { | |
236 | + struct timespec *ts = (struct timespec *)data; | |
237 | + cts.tv_sec = ts->tv_sec; | |
238 | + cts.tv_nsec = ts->tv_nsec; | |
239 | + data = &cts; | |
240 | + len = sizeof(cts); | |
233 | 241 | } |
234 | 242 | |
235 | 243 | cmlen = CMSG_COMPAT_LEN(len); |
net/core/sock.c
... | ... | @@ -521,11 +521,18 @@ |
521 | 521 | break; |
522 | 522 | |
523 | 523 | case SO_TIMESTAMP: |
524 | + case SO_TIMESTAMPNS: | |
524 | 525 | if (valbool) { |
526 | + if (optname == SO_TIMESTAMP) | |
527 | + sock_reset_flag(sk, SOCK_RCVTSTAMPNS); | |
528 | + else | |
529 | + sock_set_flag(sk, SOCK_RCVTSTAMPNS); | |
525 | 530 | sock_set_flag(sk, SOCK_RCVTSTAMP); |
526 | 531 | sock_enable_timestamp(sk); |
527 | - } else | |
532 | + } else { | |
528 | 533 | sock_reset_flag(sk, SOCK_RCVTSTAMP); |
534 | + sock_reset_flag(sk, SOCK_RCVTSTAMPNS); | |
535 | + } | |
529 | 536 | break; |
530 | 537 | |
531 | 538 | case SO_RCVLOWAT: |
... | ... | @@ -715,7 +722,12 @@ |
715 | 722 | break; |
716 | 723 | |
717 | 724 | case SO_TIMESTAMP: |
718 | - v.val = sock_flag(sk, SOCK_RCVTSTAMP); | |
725 | + v.val = sock_flag(sk, SOCK_RCVTSTAMP) && | |
726 | + !sock_flag(sk, SOCK_RCVTSTAMPNS); | |
727 | + break; | |
728 | + | |
729 | + case SO_TIMESTAMPNS: | |
730 | + v.val = sock_flag(sk, SOCK_RCVTSTAMPNS); | |
719 | 731 | break; |
720 | 732 | |
721 | 733 | case SO_RCVTIMEO: |
net/socket.c
... | ... | @@ -585,6 +585,35 @@ |
585 | 585 | return result; |
586 | 586 | } |
587 | 587 | |
588 | +/* | |
589 | + * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) | |
590 | + */ | |
591 | +void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, | |
592 | + struct sk_buff *skb) | |
593 | +{ | |
594 | + ktime_t kt = skb->tstamp; | |
595 | + | |
596 | + if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { | |
597 | + struct timeval tv; | |
598 | + /* Race occurred between timestamp enabling and packet | |
599 | + receiving. Fill in the current time for now. */ | |
600 | + if (kt.tv64 == 0) | |
601 | + kt = ktime_get_real(); | |
602 | + skb->tstamp = kt; | |
603 | + tv = ktime_to_timeval(kt); | |
604 | + put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv); | |
605 | + } else { | |
606 | + struct timespec ts; | |
607 | + /* Race occurred between timestamp enabling and packet | |
608 | + receiving. Fill in the current time for now. */ | |
609 | + if (kt.tv64 == 0) | |
610 | + kt = ktime_get_real(); | |
611 | + skb->tstamp = kt; | |
612 | + ts = ktime_to_timespec(kt); | |
613 | + put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(ts), &ts); | |
614 | + } | |
615 | +} | |
616 | + | |
588 | 617 | static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, |
589 | 618 | struct msghdr *msg, size_t size, int flags) |
590 | 619 | { |