Linux – “cat /proc/net/dev” and “ip -s link” show different statistics. Which one is lying

iplinuxnetworking

I notice that /proc/net/dev says eth3 has 1753 drops. ip -s link shows 0 dropped. Why is there a difference? Where is the different data coming from? Which one is correct?

I've stripped the out extra data.

# uname -a
Linux example09 2.6.32-5-amd64 #1 SMP Thu Mar 22 17:26:33 UTC 2012 x86_64 GNU/Linux

# lsb_release -a
Distributor ID: Debian
Description:    Debian GNU/Linux 6.0.4 (squeeze)
Release:        6.0.4
Codename:       squeeze

# cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth3:1258629839430 12545003042    0 1753    0     0          0  10594858 6666255952912 10026428444    0    0    0     0       0          0

# ip -s link
5: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:15:17:96:0b:61 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    244248462  3955476484 0       0       0       10595400
    TX: bytes  packets  errors  dropped carrier collsns
    683632524  1436809416 0       0       0       0

Best Answer

On a Squeeze machine, trust /proc/net/dev. It's a more straightforward and reliable way of looking at the same data.

For the particular case of the dropped count, I can't explain the exact issue, but I can observe it on other Squeeze boxes. If I cared, I would report it as a bug to Debian (and suggest someone does and reports back here).

Both take the number from the tx_dropped field of net_device_stats. In /proc/net/dev, the line is generated by dev_seq_printf_stats from net/core/dev.c.

ip goes, as usual, through netlink, and more precisely for network device statistics, rtnetlink. The structure passed to userspace, rtnl_link_stats.

The native structure uses unsigned longs, rtnetlink uses __u32, an more or less implicit conversion is done in copy_rtnl_link_stats.

It's pretty easy to catch the 32-bit version is being used from the beginning of the structure, rx_packets: whilst /proc/net/dev shows 1258629839430, ip shows 244248462, which corresponds roughly to the last 32 bits (plus a few more bytes between commands); same thing with the packet count.

Here's the number crunching for those 2 first fields:

% echo '1258629839430 % (2^32)'|bc; echo 244248462
204421702
244248462
% echo '12545003042 % (2^32)'|bc; echo 3955476484 
3955068450
3955476484

Things got better around the introduction of IFLA_STATS64:

  • in the kernel (from commit 10708f37ae729baba9b67bd134c3720709d4ae62, available upstream in v2.6.35 and later)
  • in iproute2 (from commit 8864ac9dc5bd5ce049280337deb21191673a02d0, available upstream in v2.6.33-36 and later).