aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-09-02 21:05:33 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-02 21:05:33 -0400
commit6ce9e7b5fe3195d1ae6e3a0753d4ddcac5cd699e (patch)
treed7228b3ea7000bc29b959556d8cb264b12365586
parent2e59af3dcbdf11635c03f22bfc9706744465d589 (diff)
ip: Report qdisc packet drops
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>
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/raw.c9
-rw-r--r--net/ipv4/udp.c12
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/raw.c4
-rw-r--r--net/ipv6/udp.c12
6 files changed, 30 insertions, 11 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 7d0821054729..afae0cbabbf9 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1302,7 +1302,7 @@ int ip_push_pending_frames(struct sock *sk)
1302 err = ip_local_out(skb); 1302 err = ip_local_out(skb);
1303 if (err) { 1303 if (err) {
1304 if (err > 0) 1304 if (err > 0)
1305 err = inet->recverr ? net_xmit_errno(err) : 0; 1305 err = net_xmit_errno(err);
1306 if (err) 1306 if (err)
1307 goto error; 1307 goto error;
1308 } 1308 }
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2979f14bb188..ebb1e5848bc6 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -375,7 +375,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
375 err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, 375 err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
376 dst_output); 376 dst_output);
377 if (err > 0) 377 if (err > 0)
378 err = inet->recverr ? net_xmit_errno(err) : 0; 378 err = net_xmit_errno(err);
379 if (err) 379 if (err)
380 goto error; 380 goto error;
381out: 381out:
@@ -386,6 +386,8 @@ error_fault:
386 kfree_skb(skb); 386 kfree_skb(skb);
387error: 387error:
388 IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); 388 IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
389 if (err == -ENOBUFS && !inet->recverr)
390 err = 0;
389 return err; 391 return err;
390} 392}
391 393
@@ -576,8 +578,11 @@ back_from_confirm:
576 &ipc, &rt, msg->msg_flags); 578 &ipc, &rt, msg->msg_flags);
577 if (err) 579 if (err)
578 ip_flush_pending_frames(sk); 580 ip_flush_pending_frames(sk);
579 else if (!(msg->msg_flags & MSG_MORE)) 581 else if (!(msg->msg_flags & MSG_MORE)) {
580 err = ip_push_pending_frames(sk); 582 err = ip_push_pending_frames(sk);
583 if (err == -ENOBUFS && !inet->recverr)
584 err = 0;
585 }
581 release_sock(sk); 586 release_sock(sk);
582 } 587 }
583done: 588done:
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 29ebb0d27a1e..ebaaa7f973d7 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -561,12 +561,18 @@ static int udp_push_pending_frames(struct sock *sk)
561 561
562send: 562send:
563 err = ip_push_pending_frames(sk); 563 err = ip_push_pending_frames(sk);
564 if (err) {
565 if (err == -ENOBUFS && !inet->recverr) {
566 UDP_INC_STATS_USER(sock_net(sk),
567 UDP_MIB_SNDBUFERRORS, is_udplite);
568 err = 0;
569 }
570 } else
571 UDP_INC_STATS_USER(sock_net(sk),
572 UDP_MIB_OUTDATAGRAMS, is_udplite);
564out: 573out:
565 up->len = 0; 574 up->len = 0;
566 up->pending = 0; 575 up->pending = 0;
567 if (!err)
568 UDP_INC_STATS_USER(sock_net(sk),
569 UDP_MIB_OUTDATAGRAMS, is_udplite);
570 return err; 576 return err;
571} 577}
572 578
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index a931229856b6..cd48801a8d6f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1511,7 +1511,7 @@ int ip6_push_pending_frames(struct sock *sk)
1511 err = ip6_local_out(skb); 1511 err = ip6_local_out(skb);
1512 if (err) { 1512 if (err) {
1513 if (err > 0) 1513 if (err > 0)
1514 err = np->recverr ? net_xmit_errno(err) : 0; 1514 err = net_xmit_errno(err);
1515 if (err) 1515 if (err)
1516 goto error; 1516 goto error;
1517 } 1517 }
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 506841030fbe..7d675b8d82d3 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -642,7 +642,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
642 err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, 642 err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
643 dst_output); 643 dst_output);
644 if (err > 0) 644 if (err > 0)
645 err = np->recverr ? net_xmit_errno(err) : 0; 645 err = net_xmit_errno(err);
646 if (err) 646 if (err)
647 goto error; 647 goto error;
648out: 648out:
@@ -653,6 +653,8 @@ error_fault:
653 kfree_skb(skb); 653 kfree_skb(skb);
654error: 654error:
655 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); 655 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
656 if (err == -ENOBUFS && !np->recverr)
657 err = 0;
656 return err; 658 return err;
657} 659}
658 660
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 20d2ffc15f0d..164040613c2e 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -724,12 +724,18 @@ static int udp_v6_push_pending_frames(struct sock *sk)
724 724
725send: 725send:
726 err = ip6_push_pending_frames(sk); 726 err = ip6_push_pending_frames(sk);
727 if (err) {
728 if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
729 UDP6_INC_STATS_USER(sock_net(sk),
730 UDP_MIB_SNDBUFERRORS, is_udplite);
731 err = 0;
732 }
733 } else
734 UDP6_INC_STATS_USER(sock_net(sk),
735 UDP_MIB_OUTDATAGRAMS, is_udplite);
727out: 736out:
728 up->len = 0; 737 up->len = 0;
729 up->pending = 0; 738 up->pending = 0;
730 if (!err)
731 UDP6_INC_STATS_USER(sock_net(sk),
732 UDP_MIB_OUTDATAGRAMS, is_udplite);
733 return err; 739 return err;
734} 740}
735 741