diff -Nur 2.4.18/include/linux/sockios.h 2.4.18/include/linux/sockios.h --- 2.4.18/include/linux/sockios.h Wed Nov 7 17:39:36 2001 +++ 2.4.18/include/linux/sockios.h Wed Jun 5 15:55:54 2002 @@ -113,6 +113,10 @@ #define SIOCBONDSLAVEINFOQUERY 0x8993 /* rtn info about slave state */ #define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */ #define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */ + +/* per-socket statistics manipulation */ +#define GIOCSOCKSTATS 0x8996 /* get the per-socket statistics */ +#define SIOCZEROSOCKSTATS 0x8997 /* zero out the per-socket statistics */ /* Device private ioctl calls */ diff -Nur 2.4.18/include/net/sock.h 2.4.18/include/net/sock.h --- 2.4.18/include/net/sock.h Thu May 2 15:32:20 2002 +++ 2.4.18/include/net/sock.h Wed Jun 5 15:58:24 2002 @@ -480,6 +480,16 @@ wait_queue_head_t wq; } socket_lock_t; +/* per-socket statistics. received is the total number of skbuffs received + * on that socket. dropped_no_mem is the number of packets dropped due + * to a lack of space on the socket receive buffer + */ +typedef struct { + __u64 received; + __u32 dropped_no_mem; +} socket_stats; + + #define sock_lock_init(__sk) \ do { spin_lock_init(&((__sk)->lock.slock)); \ (__sk)->lock.users = 0; \ @@ -678,6 +688,10 @@ int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb); void (*destruct)(struct sock *sk); + + + /* per-socket statistics */ + socket_stats stats; }; /* The per-socket spinlock must be held here. */ @@ -1145,11 +1159,15 @@ static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { + sk->stats.received++; + /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) { + sk->stats.dropped_no_mem++; return -ENOMEM; + } #ifdef CONFIG_FILTER if (sk->filter) { @@ -1179,11 +1197,16 @@ static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) { + sk->stats.received++; + /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) { + sk->stats.dropped_no_mem++; return -ENOMEM; + } + skb_set_owner_r(skb, sk); skb_queue_tail(&sk->error_queue,skb); if (!sk->dead) diff -Nur 2.4.18/net/core/sock.c 2.4.18/net/core/sock.c --- 2.4.18/net/core/sock.c Fri Dec 21 12:42:05 2001 +++ 2.4.18/net/core/sock.c Wed Jun 5 13:59:37 2002 @@ -1202,6 +1202,9 @@ sk->rcvlowat = 1; sk->rcvtimeo = MAX_SCHEDULE_TIMEOUT; sk->sndtimeo = MAX_SCHEDULE_TIMEOUT; + + sk->stats.received = 0; + sk->stats.dropped_no_mem = 0; atomic_set(&sk->refcnt, 1); } diff -Nur 2.4.18/net/ipv4/af_inet.c 2.4.18/net/ipv4/af_inet.c --- 2.4.18/net/ipv4/af_inet.c Fri Dec 21 12:42:05 2001 +++ 2.4.18/net/ipv4/af_inet.c Wed Jun 5 15:56:20 2002 @@ -834,6 +834,16 @@ int pid; switch(cmd) { + case GIOCSOCKSTATS: + return copy_to_user((void *)arg, &sk->stats, sizeof(sk->stats)); + case SIOCZEROSOCKSTATS: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + else { + sk->stats.dropped_no_mem = 0; + sk->stats.received = 0; + return (0); + } case FIOSETOWN: case SIOCSPGRP: err = get_user(pid, (int *) arg);