ip: Report qdisc packet drops
authorEric Dumazet <eric.dumazet@gmail.com>
Thu, 3 Sep 2009 01:05:33 +0000 (18:05 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Sep 2009 01:05:33 +0000 (18:05 -0700)
Christoph Lameter pointed out that packet drops at qdisc level where not
accounted in SNMP counters. Only if application sets IP_RECVERR, drops
are reported to user (-ENOBUFS errors) and SNMP counters updated.

IP_RECVERR is used to enable extended reliable error message passing,
but these are not needed to update system wide SNMP stats.

This patch changes things a bit to allow SNMP counters to be updated,
regardless of IP_RECVERR being set or not on the socket.

Example after an UDP tx flood
# netstat -s
...
IP:
    1487048 outgoing packets dropped
...
Udp:
...
    SndbufErrors: 1487048

send() syscalls, do however still return an OK status, to not
break applications.

Note : send() manual page explicitly says for -ENOBUFS error :

 "The output queue for a network interface was full.
  This generally indicates that the interface has stopped sending,
  but may be caused by transient congestion.
  (Normally, this does not occur in Linux. Packets are just silently
  dropped when a device queue overflows.) "

This is not true for IP_RECVERR enabled sockets : a send() syscall
that hit a qdisc drop returns an ENOBUFS error.

Many thanks to Christoph, David, and last but not least, Alexey !

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_output.c
net/ipv4/raw.c
net/ipv4/udp.c
net/ipv6/ip6_output.c
net/ipv6/raw.c
net/ipv6/udp.c

index 7d08210547291b74bc15d001e55eacdb8dd34281..afae0cbabbf9a87b40bc3ceb32a197e51408a914 100644 (file)
@@ -1302,7 +1302,7 @@ int ip_push_pending_frames(struct sock *sk)
        err = ip_local_out(skb);
        if (err) {
                if (err > 0)
-                       err = inet->recverr ? net_xmit_errno(err) : 0;
+                       err = net_xmit_errno(err);
                if (err)
                        goto error;
        }
index 2979f14bb188844965a59bc0e5013f7d1d374eb2..ebb1e5848bc6639703d88029ea40231b343a06c1 100644 (file)
@@ -375,7 +375,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
                      dst_output);
        if (err > 0)
-               err = inet->recverr ? net_xmit_errno(err) : 0;
+               err = net_xmit_errno(err);
        if (err)
                goto error;
 out:
@@ -386,6 +386,8 @@ error_fault:
        kfree_skb(skb);
 error:
        IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
+       if (err == -ENOBUFS && !inet->recverr)
+               err = 0;
        return err;
 }
 
@@ -576,8 +578,11 @@ back_from_confirm:
                                        &ipc, &rt, msg->msg_flags);
                if (err)
                        ip_flush_pending_frames(sk);
-               else if (!(msg->msg_flags & MSG_MORE))
+               else if (!(msg->msg_flags & MSG_MORE)) {
                        err = ip_push_pending_frames(sk);
+                       if (err == -ENOBUFS && !inet->recverr)
+                               err = 0;
+               }
                release_sock(sk);
        }
 done:
index 29ebb0d27a1ef004514c278cfd44674eacf38d4f..ebaaa7f973d70a8dd4038b30c621adf01a4c6268 100644 (file)
@@ -561,12 +561,18 @@ static int udp_push_pending_frames(struct sock *sk)
 
 send:
        err = ip_push_pending_frames(sk);
+       if (err) {
+               if (err == -ENOBUFS && !inet->recverr) {
+                       UDP_INC_STATS_USER(sock_net(sk),
+                                          UDP_MIB_SNDBUFERRORS, is_udplite);
+                       err = 0;
+               }
+       } else
+               UDP_INC_STATS_USER(sock_net(sk),
+                                  UDP_MIB_OUTDATAGRAMS, is_udplite);
 out:
        up->len = 0;
        up->pending = 0;
-       if (!err)
-               UDP_INC_STATS_USER(sock_net(sk),
-                               UDP_MIB_OUTDATAGRAMS, is_udplite);
        return err;
 }
 
index a931229856b64624922c4ea1729771f26fd9b4e3..cd48801a8d6f465d546b61a2e9629bf6e2091714 100644 (file)
@@ -1511,7 +1511,7 @@ int ip6_push_pending_frames(struct sock *sk)
        err = ip6_local_out(skb);
        if (err) {
                if (err > 0)
-                       err = np->recverr ? net_xmit_errno(err) : 0;
+                       err = net_xmit_errno(err);
                if (err)
                        goto error;
        }
index 506841030fbee0dab9fe980d8f717e407babc06f..7d675b8d82d36813e2229d6abfe31ffdeec7d4be 100644 (file)
@@ -642,7 +642,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
                      dst_output);
        if (err > 0)
-               err = np->recverr ? net_xmit_errno(err) : 0;
+               err = net_xmit_errno(err);
        if (err)
                goto error;
 out:
@@ -653,6 +653,8 @@ error_fault:
        kfree_skb(skb);
 error:
        IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
+       if (err == -ENOBUFS && !np->recverr)
+               err = 0;
        return err;
 }
 
index 20d2ffc15f0d1096acf7021943ec168ddd759068..164040613c2e996760ba756e5db89dd0e4f912a5 100644 (file)
@@ -724,12 +724,18 @@ static int udp_v6_push_pending_frames(struct sock *sk)
 
 send:
        err = ip6_push_pending_frames(sk);
+       if (err) {
+               if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
+                       UDP6_INC_STATS_USER(sock_net(sk),
+                                           UDP_MIB_SNDBUFERRORS, is_udplite);
+                       err = 0;
+               }
+       } else
+               UDP6_INC_STATS_USER(sock_net(sk),
+                                   UDP_MIB_OUTDATAGRAMS, is_udplite);
 out:
        up->len = 0;
        up->pending = 0;
-       if (!err)
-               UDP6_INC_STATS_USER(sock_net(sk),
-                               UDP_MIB_OUTDATAGRAMS, is_udplite);
        return err;
 }
 
This page took 0.034945 seconds and 5 git commands to generate.