Skip to content

Commit 3b88578

Browse files
nhormandavem330
authored andcommitted
net: Generalize socket rx gap / receive queue overflow cmsg
Create a new socket level option to report number of queue overflows Recently I augmented the AF_PACKET protocol to report the number of frames lost on the socket receive queue between any two enqueued frames. This value was exported via a SOL_PACKET level cmsg. AFter I completed that work it was requested that this feature be generalized so that any datagram oriented socket could make use of this option. As such I've created this patch, It creates a new SOL_SOCKET level option called SO_RXQ_OVFL, which when enabled exports a SOL_SOCKET level cmsg that reports the nubmer of times the sk_receive_queue overflowed between any two given frames. It also augments the AF_PACKET protocol to take advantage of this new feature (as it previously did not touch sk->sk_drops, which this patch uses to record the overflow count). Tested successfully by me. Notes: 1) Unlike my previous patch, this patch simply records the sk_drops value, which is not a number of drops between packets, but rather a total number of drops. Deltas must be computed in user space. 2) While this patch currently works with datagram oriented protocols, it will also be accepted by non-datagram oriented protocols. I'm not sure if thats agreeable to everyone, but my argument in favor of doing so is that, for those protocols which aren't applicable to this option, sk_drops will always be zero, and reporting no drops on a receive queue that isn't used for those non-participating protocols seems reasonable to me. This also saves us having to code in a per-protocol opt in mechanism. 3) This applies cleanly to net-next assuming that commit 9777500 (my af packet cmsg patch) is reverted Signed-off-by: Neil Horman <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d5e63bd commit 3b88578

File tree

36 files changed

+88
-21
lines changed

36 files changed

+88
-21
lines changed

arch/alpha/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
#define SO_TIMESTAMPING 37
6868
#define SCM_TIMESTAMPING SO_TIMESTAMPING
6969

70+
#define SO_RXQ_OVFL 40
71+
7072
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
7173
* have to define SOCK_NONBLOCK to a different value here.
7274
*/

arch/arm/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* _ASM_SOCKET_H */

arch/avr32/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* __ASM_AVR32_SOCKET_H */

arch/cris/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
#define SO_PROTOCOL 38
6363
#define SO_DOMAIN 39
6464

65+
#define SO_RXQ_OVFL 40
66+
6567
#endif /* _ASM_SOCKET_H */
6668

6769

arch/frv/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,7 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* _ASM_SOCKET_H */
6466

arch/h8300/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* _ASM_SOCKET_H */

arch/ia64/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,6 @@
6969
#define SO_PROTOCOL 38
7070
#define SO_DOMAIN 39
7171

72+
#define SO_RXQ_OVFL 40
73+
7274
#endif /* _ASM_IA64_SOCKET_H */

arch/m32r/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* _ASM_M32R_SOCKET_H */

arch/m68k/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* _ASM_SOCKET_H */

arch/mips/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
8080
#define SO_TIMESTAMPING 37
8181
#define SCM_TIMESTAMPING SO_TIMESTAMPING
8282

83+
#define SO_RXQ_OVFL 40
84+
8385
#ifdef __KERNEL__
8486

8587
/** sock_type - Socket types

arch/mn10300/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@
6060
#define SO_PROTOCOL 38
6161
#define SO_DOMAIN 39
6262

63+
#define SO_RXQ_OVFL 40
64+
6365
#endif /* _ASM_SOCKET_H */

arch/parisc/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
#define SO_TIMESTAMPING 0x4020
6060
#define SCM_TIMESTAMPING SO_TIMESTAMPING
6161

62+
#define SO_RXQ_OVFL 0x4021
63+
6264
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
6365
* have to define SOCK_NONBLOCK to a different value here.
6466
*/

arch/powerpc/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,6 @@
6767
#define SO_PROTOCOL 38
6868
#define SO_DOMAIN 39
6969

70+
#define SO_RXQ_OVFL 40
71+
7072
#endif /* _ASM_POWERPC_SOCKET_H */

arch/s390/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,6 @@
6868
#define SO_PROTOCOL 38
6969
#define SO_DOMAIN 39
7070

71+
#define SO_RXQ_OVFL 40
72+
7173
#endif /* _ASM_SOCKET_H */

arch/sparc/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
#define SO_TIMESTAMPING 0x0023
5757
#define SCM_TIMESTAMPING SO_TIMESTAMPING
5858

59+
#define SO_RXQ_OVFL 0x0024
60+
5961
/* Security levels - as per NRL IPv6 - don't actually do anything */
6062
#define SO_SECURITY_AUTHENTICATION 0x5001
6163
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002

arch/xtensa/include/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,6 @@
7171
#define SO_PROTOCOL 38
7272
#define SO_DOMAIN 39
7373

74+
#define SO_RXQ_OVFL 40
75+
7476
#endif /* _XTENSA_SOCKET_H */

include/asm-generic/socket.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@
6363
#define SO_PROTOCOL 38
6464
#define SO_DOMAIN 39
6565

66+
#define SO_RXQ_OVFL 40
6667
#endif /* __ASM_GENERIC_SOCKET_H */

include/linux/skbuff.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,10 @@ struct sk_buff {
389389
#ifdef CONFIG_NETWORK_SECMARK
390390
__u32 secmark;
391391
#endif
392-
393-
__u32 mark;
392+
union {
393+
__u32 mark;
394+
__u32 dropcount;
395+
};
394396

395397
__u16 vlan_tci;
396398

include/net/sock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ enum sock_flags {
505505
SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */
506506
SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */
507507
SOCK_FASYNC, /* fasync() active */
508+
SOCK_RXQ_OVFL,
508509
};
509510

510511
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1493,6 +1494,8 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
14931494
sk->sk_stamp = kt;
14941495
}
14951496

1497+
extern void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb);
1498+
14961499
/**
14971500
* sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
14981501
* @msg: outgoing packet

net/atm/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
496496
error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
497497
if (error)
498498
return error;
499-
sock_recv_timestamp(msg, sk, skb);
499+
sock_recv_ts_and_drops(msg, sk, skb);
500500
pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
501501
atm_return(vcc, skb->truesize);
502502
skb_free_datagram(sk, skb);

net/bluetooth/af_bluetooth.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
257257
skb_reset_transport_header(skb);
258258
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
259259
if (err == 0)
260-
sock_recv_timestamp(msg, sk, skb);
260+
sock_recv_ts_and_drops(msg, sk, skb);
261261

262262
skb_free_datagram(sk, skb);
263263

net/bluetooth/rfcomm/sock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
703703
copied += chunk;
704704
size -= chunk;
705705

706-
sock_recv_timestamp(msg, sk, skb);
706+
sock_recv_ts_and_drops(msg, sk, skb);
707707

708708
if (!(flags & MSG_PEEK)) {
709709
atomic_sub(chunk, &sk->sk_rmem_alloc);

net/can/bcm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1534,7 +1534,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
15341534
return err;
15351535
}
15361536

1537-
sock_recv_timestamp(msg, sk, skb);
1537+
sock_recv_ts_and_drops(msg, sk, skb);
15381538

15391539
if (msg->msg_name) {
15401540
msg->msg_namelen = sizeof(struct sockaddr_can);

net/can/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
702702
return err;
703703
}
704704

705-
sock_recv_timestamp(msg, sk, skb);
705+
sock_recv_ts_and_drops(msg, sk, skb);
706706

707707
if (msg->msg_name) {
708708
msg->msg_namelen = sizeof(struct sockaddr_can);

net/core/sock.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
276276
{
277277
int err = 0;
278278
int skb_len;
279+
unsigned long flags;
280+
struct sk_buff_head *list = &sk->sk_receive_queue;
279281

280282
/* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
281283
number of warnings when compiling with -W --ANK
@@ -305,7 +307,10 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
305307
*/
306308
skb_len = skb->len;
307309

308-
skb_queue_tail(&sk->sk_receive_queue, skb);
310+
spin_lock_irqsave(&list->lock, flags);
311+
skb->dropcount = atomic_read(&sk->sk_drops);
312+
__skb_queue_tail(list, skb);
313+
spin_unlock_irqrestore(&list->lock, flags);
309314

310315
if (!sock_flag(sk, SOCK_DEAD))
311316
sk->sk_data_ready(sk, skb_len);
@@ -702,6 +707,12 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
702707

703708
/* We implement the SO_SNDLOWAT etc to
704709
not be settable (1003.1g 5.3) */
710+
case SO_RXQ_OVFL:
711+
if (valbool)
712+
sock_set_flag(sk, SOCK_RXQ_OVFL);
713+
else
714+
sock_reset_flag(sk, SOCK_RXQ_OVFL);
715+
break;
705716
default:
706717
ret = -ENOPROTOOPT;
707718
break;
@@ -901,6 +912,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
901912
v.val = sk->sk_mark;
902913
break;
903914

915+
case SO_RXQ_OVFL:
916+
v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
917+
break;
918+
904919
default:
905920
return -ENOPROTOOPT;
906921
}

net/ieee802154/dgram.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
303303
if (err)
304304
goto done;
305305

306-
sock_recv_timestamp(msg, sk, skb);
306+
sock_recv_ts_and_drops(msg, sk, skb);
307307

308308
if (flags & MSG_TRUNC)
309309
copied = skb->len;

net/ieee802154/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
191191
if (err)
192192
goto done;
193193

194-
sock_recv_timestamp(msg, sk, skb);
194+
sock_recv_ts_and_drops(msg, sk, skb);
195195

196196
if (flags & MSG_TRUNC)
197197
copied = skb->len;

net/ipv4/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
682682
if (err)
683683
goto done;
684684

685-
sock_recv_timestamp(msg, sk, skb);
685+
sock_recv_ts_and_drops(msg, sk, skb);
686686

687687
/* Copy the address. */
688688
if (sin) {

net/ipv4/udp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
955955
UDP_INC_STATS_USER(sock_net(sk),
956956
UDP_MIB_INDATAGRAMS, is_udplite);
957957

958-
sock_recv_timestamp(msg, sk, skb);
958+
sock_recv_ts_and_drops(msg, sk, skb);
959959

960960
/* Copy the address. */
961961
if (sin) {

net/ipv6/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
497497
sin6->sin6_scope_id = IP6CB(skb)->iif;
498498
}
499499

500-
sock_recv_timestamp(msg, sk, skb);
500+
sock_recv_ts_and_drops(msg, sk, skb);
501501

502502
if (np->rxopt.all)
503503
datagram_recv_ctl(sk, msg, skb);

net/ipv6/udp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
252252
UDP_MIB_INDATAGRAMS, is_udplite);
253253
}
254254

255-
sock_recv_timestamp(msg, sk, skb);
255+
sock_recv_ts_and_drops(msg, sk, skb);
256256

257257
/* Copy the address. */
258258
if (msg->msg_name) {

net/key/af_key.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3606,7 +3606,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
36063606
if (err)
36073607
goto out_free;
36083608

3609-
sock_recv_timestamp(msg, sk, skb);
3609+
sock_recv_ts_and_drops(msg, sk, skb);
36103610

36113611
err = (flags & MSG_TRUNC) ? skb->len : copied;
36123612

net/packet/af_packet.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -627,15 +627,14 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
627627

628628
spin_lock(&sk->sk_receive_queue.lock);
629629
po->stats.tp_packets++;
630+
skb->dropcount = atomic_read(&sk->sk_drops);
630631
__skb_queue_tail(&sk->sk_receive_queue, skb);
631632
spin_unlock(&sk->sk_receive_queue.lock);
632633
sk->sk_data_ready(sk, skb->len);
633634
return 0;
634635

635636
drop_n_acct:
636-
spin_lock(&sk->sk_receive_queue.lock);
637-
po->stats.tp_drops++;
638-
spin_unlock(&sk->sk_receive_queue.lock);
637+
po->stats.tp_drops = atomic_inc_return(&sk->sk_drops);
639638

640639
drop_n_restore:
641640
if (skb_head != skb->data && skb_shared(skb)) {
@@ -1478,7 +1477,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
14781477
if (err)
14791478
goto out_free;
14801479

1481-
sock_recv_timestamp(msg, sk, skb);
1480+
sock_recv_ts_and_drops(msg, sk, skb);
14821481

14831482
if (msg->msg_name)
14841483
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,

net/rxrpc/ar-recvmsg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
146146
memcpy(msg->msg_name,
147147
&call->conn->trans->peer->srx,
148148
sizeof(call->conn->trans->peer->srx));
149-
sock_recv_timestamp(msg, &rx->sk, skb);
149+
sock_recv_ts_and_drops(msg, &rx->sk, skb);
150150
}
151151

152152
/* receive the message */

net/sctp/socket.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1958,7 +1958,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
19581958
if (err)
19591959
goto out_free;
19601960

1961-
sock_recv_timestamp(msg, sk, skb);
1961+
sock_recv_ts_and_drops(msg, sk, skb);
19621962
if (sctp_ulpevent_is_notification(event)) {
19631963
msg->msg_flags |= MSG_NOTIFICATION;
19641964
sp->pf->event_msgname(event, msg->msg_name, addr_len);

net/socket.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,21 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
668668

669669
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
670670

671+
inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
672+
{
673+
if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount)
674+
put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
675+
sizeof(__u32), &skb->dropcount);
676+
}
677+
678+
void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
679+
struct sk_buff *skb)
680+
{
681+
sock_recv_timestamp(msg, sk, skb);
682+
sock_recv_drops(msg, sk, skb);
683+
}
684+
EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops);
685+
671686
static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
672687
struct msghdr *msg, size_t size, int flags)
673688
{

0 commit comments

Comments
 (0)