mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 11:16:11 +00:00
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>
This commit is contained in:
parent
2e59af3dcb
commit
6ce9e7b5fe
6 changed files with 30 additions and 11 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue