net: udp: add socket option to report RX queue level
Subsystems (12)
PATCH 1/1 net: udp: add socket option to report RX queue level
This adds a new socket option "SO_RXQ_ALLOC" that enables providing the RX queue buffer allocation as ancillary data from the recvmsg() system call. The value reported is a byte number and together with the RX queue size (obtained via getsockopt(SO_RCVBUF) can be used to calculate a percentage value on how full the socket buffer is.
--- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/avr32/include/uapi/asm/socket.h | 2 ++ arch/frv/include/uapi/asm/socket.h | 3 ++- arch/ia64/include/uapi/asm/socket.h | 2 ++ arch/m32r/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/mn10300/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/powerpc/include/uapi/asm/socket.h | 2 ++ arch/s390/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ arch/xtensa/include/uapi/asm/socket.h | 2 ++ include/net/sock.h | 9 +++++++++ include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 8 ++++++++ net/ipv4/udp.c | 1 + net/ipv6/udp.c | 1 + net/socket.c | 12 ++++++++++++ 18 files changed, 57 insertions(+), 1 deletion(-)
arch/alpha/include/uapi/asm/socket.h +2 -0
@@ -99,4 +99,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _UAPI_ASM_SOCKET_H */
arch/avr32/include/uapi/asm/socket.h +2 -0
@@ -92,4 +92,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _UAPI__ASM_AVR32_SOCKET_H */
arch/frv/include/uapi/asm/socket.h +2 -1
@@ -92,5 +92,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 -#endif /* _ASM_SOCKET_H */ +#define SO_RXQ_ALLOC 55 +#endif /* _ASM_SOCKET_H */
arch/ia64/include/uapi/asm/socket.h +2 -0
@@ -101,4 +101,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _ASM_IA64_SOCKET_H */
arch/m32r/include/uapi/asm/socket.h +2 -0
@@ -92,4 +92,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _ASM_M32R_SOCKET_H */
arch/mips/include/uapi/asm/socket.h +2 -0
@@ -110,4 +110,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _UAPI_ASM_SOCKET_H */
arch/mn10300/include/uapi/asm/socket.h +2 -0
@@ -92,4 +92,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _ASM_SOCKET_H */
arch/parisc/include/uapi/asm/socket.h +2 -0
@@ -91,4 +91,6 @@#define SCM_TIMESTAMPING_OPT_STATS 0x402F +#define SO_RXQ_ALLOC 0x4030 +#endif /* _UAPI_ASM_SOCKET_H */
arch/powerpc/include/uapi/asm/socket.h +2 -0
@@ -99,4 +99,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _ASM_POWERPC_SOCKET_H */
arch/s390/include/uapi/asm/socket.h +2 -0
@@ -98,4 +98,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _ASM_SOCKET_H */
arch/sparc/include/uapi/asm/socket.h +2 -0
@@ -88,6 +88,8 @@#define SCM_TIMESTAMPING_OPT_STATS 0x0038 +#define SO_RXQ_ALLOC 0x0039 +/* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
arch/xtensa/include/uapi/asm/socket.h +2 -0
@@ -103,4 +103,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* _XTENSA_SOCKET_H */
include/net/sock.h +9 -0
@@ -758,6 +758,7 @@ enum sock_flags {SOCK_TIMESTAMPING_RX_SOFTWARE ,/* %SOF_TIMESTAMPING_RX_SOFTWARE */ SOCK_FASYNC ,/* fasync() active */ SOCK_RXQ_OVFL , +SOCK_RXQ_ALLOC ,SOCK_ZEROCOPY ,/* buffers from userspace */ SOCK_WIFI_STATUS ,/* push wifi status to userspace */ SOCK_NOFCS, /* Tell NIC not to do the Ethernet FCS.
@@ -2253,6 +2254,14 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, sk->sk_stamp = skb->tstamp; } +void __sock_recv_alloc (struct msghdr *msg,struct sock *sk); + +static inline void sock_recv_alloc (struct msghdr *msg,struct sock *sk) +{ +if (sock_flag (sk,SOCK_RXQ_ALLOC )) +__sock_recv_alloc (msg, sk); +} +void __sock_tx_timestamp (__u16 tsflags,__u8 *tx_flags);/**
include/uapi/asm-generic/socket.h +2 -0
@@ -94,4 +94,6 @@#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_RXQ_ALLOC 55 +#endif /* __ASM_GENERIC_SOCKET_H */
net/core/sock.c +8 -0
@@ -1006,6 +1006,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,sock_valbool_flag (sk,SOCK_RXQ_OVFL , valbool);break ; +case SO_RXQ_ALLOC : +sock_valbool_flag (sk,SOCK_RXQ_ALLOC , valbool); +break ; +case SO_WIFI_STATUS :sock_valbool_flag (sk,SOCK_WIFI_STATUS , valbool);break ;
@@ -1263,6 +1267,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val =sock_flag (sk,SOCK_RXQ_OVFL );break ; +case SO_RXQ_ALLOC : + v.val =sock_flag (sk,SOCK_RXQ_ALLOC ); +break ; +case SO_WIFI_STATUS : v.val =sock_flag (sk,SOCK_WIFI_STATUS );break ;
net/ipv4/udp.c +1 -0
@@ -1470,6 +1470,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, UDP_MIB_INDATAGRAMS, is_udplite);sock_recv_ts_and_drops (msg, sk, skb); +sock_recv_alloc (msg, sk);/* Copy the address. */ if (sin) {
net/ipv6/udp.c +1 -0
@@ -413,6 +413,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, }sock_recv_ts_and_drops (msg, sk, skb); +sock_recv_alloc (msg, sk);/* Copy the address. */ if (msg->msg_name) {
net/socket.c +12 -0
@@ -734,6 +734,18 @@ void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, }EXPORT_SYMBOL_GPL (__sock_recv_ts_and_drops); +void __sock_recv_alloc (struct msghdr *msg,struct sock *sk) +{ +__u32 rmem_alloc; + +if (sock_flag (sk,SOCK_RXQ_ALLOC )) { + rmem_alloc =atomic_read (&sk->sk_rmem_alloc); +put_cmsg (msg,SOL_SOCKET ,SO_RXQ_ALLOC , +sizeof (rmem_alloc), &rmem_alloc); + } +} +EXPORT_SYMBOL_GPL (__sock_recv_alloc); +static inline int sock_recvmsg_nosec (struct socket *sock,struct msghdr *msg,int flags) {
Signature · 1 line
2.12.0.367.g23dc2f6d3c-goog
Quoted 6 lines · Chris Kuiper
This adds a new socket option "
SO_RXQ_ALLOC" that enables providing the RX queue buffer allocation as ancillary data from therecvmsg()system call. The value reported is a byte number and together with the RX queue size (obtained viagetsockopt(SO_RCVBUF)can be used to calculate a percentage value on how full the socket buffer is.
---
Seems a lot of overhead, and only UDP would be supported.
I very much prefer Josh Hunt proposal
( https://patchwork.ozlabs.org/patch/738250/ )
Ie using a separate getsockopt() call instead of adding code to UDP fast path ?
Quoted 8 lines · Eric Dumazet
Quoted 6 lines · Chris Kuiper
This adds a new socket option "
SO_RXQ_ALLOC" that enables providing the RX queue buffer allocation as ancillary data from therecvmsg()system call. The value reported is a byte number and together with the RX queue size (obtained viagetsockopt(SO_RCVBUF)can be used to calculate a percentage value on how full the socket buffer is.
---
Quoted 8 lines
Seems a lot of overhead, and only UDP would be supported.
I very much prefer Josh Hunt proposal
( https://patchwork.ozlabs.org/patch/738250/ )Ie using a separate
getsockopt()call instead of adding code to UDP fast path ?
Yes, let me know and I can send a patch adding a sockopt to return all of the meminfo vars.
Sorry, I have been transferring jobs and had no time to look at this.
Josh Hunt's change seems to solve a different problem. I was looking for something that works the same way as SO_RXQ_OVERFL, providing information as ancillary data to the recvmsg() call. The problem with SO_RXQ_OVERFL alone is that it tells you when things have already gone wrong (you dropped data), so the new option SO_RX_ALLOC acts as a leading indicator to check if you are getting close to hitting such problem.
Regarding only UDP being supported, it is only meaningful for UDP. TCP doesn't drop data and if its buffer gets full it just stops the sender from sending more. The buffer level in that case doesn't even tell you the whole picture, since it doesn't include any information on how much additional buffering is done at the sender side.
In terms of "a lot overhead", logically the overhead of adding additional getsockopt() calls after each recvmsg() is significantly larger than just getting the information as part of recvmsg(). If you don't need it, then don't enable this option. Admitted you can reduce the frequency of calling getsockopt() relative to recvmsg(), but that also increases your risk of missing the point where data is dropped.
-Chris
Quoted 18 lines · Eric Dumazet
Quoted 6 lines · Chris Kuiper
This adds a new socket option "
SO_RXQ_ALLOC" that enables providing the RX queue buffer allocation as ancillary data from therecvmsg()system call. The value reported is a byte number and together with the RX queue size (obtained viagetsockopt(SO_RCVBUF)can be used to calculate a percentage value on how full the socket buffer is.
---Seems a lot of overhead, and only UDP would be supported.
I very much prefer Josh Hunt proposal
( https://patchwork.ozlabs.org/patch/738250/ )Ie using a separate
getsockopt()call instead of adding code to UDP fast path ?
Please do not top post on netdev
Quoted 9 lines · Chris Kuiper
Sorry, I have been transferring jobs and had no time to look at this.
Josh Hunt's change seems to solve a different problem. I was looking for something that works the same way as
SO_RXQ_OVERFL, providing information as ancillary data to therecvmsg()call. The problem withSO_RXQ_OVERFLalone is that it tells you when things have already gone wrong (you dropped data), so the new optionSO_RX_ALLOCacts as a leading indicator to check if you are getting close to hitting such problem.
SO_RXQ_OVERFL gives a very precise info for every skb that was queued.
This is a different indicator, because it can tell you where is the discontinuity point at the time skb were queued, not at the time they are dequeued.
Just tune SO_RCVBUF to not even have to care about this.
By the time you sample the queue occupancy, the information might be completely stale and queue already overflowed.
There is very little point having a super system call gathering all kind of (stale) info
Quoted 7 lines
Regarding only UDP being supported, it is only meaningful for UDP. TCP doesn't drop data and if its buffer gets full it just stops the sender from sending more. The buffer level in that case doesn't even tell you the whole picture, since it doesn't include any information on how much additional buffering is done at the sender side.
We have more protocols than UDP and TCP in linux kernel.
Quoted 6 lines
In terms of "a lot overhead", logically the overhead of adding additional
getsockopt()calls after eachrecvmsg()is significantly larger than just getting the information as part ofrecvmsg(). If you don't need it, then don't enable this option. Admitted you can reduce the frequency of callinggetsockopt()relative torecvmsg(), but that also increases your risk of missing the point where data is dropped.
Your proposal adds overhead for all UDP recvmsg() calls, while most of them absolutely not care about overruns. There is little you can do if you are under attack or if your SO_RCVBUF is too small for the workload.
Some people work hard to reach 2 Millions UDP recvmsg() calls per second on a single UDP socket, so everything added in fast path will be scrutinized.