--- net/core/dev.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) Index: linux-2.6/net/core/dev.c =================================================================== --- linux-2.6.orig/net/core/dev.c 2009-09-14 16:06:46.000000000 -0500 +++ linux-2.6/net/core/dev.c 2009-09-15 13:46:55.000000000 -0500 @@ -5072,28 +5072,47 @@ void netdev_run_todo(void) const struct net_device_stats *dev_get_stats(struct net_device *dev) { const struct net_device_ops *ops = dev->netdev_ops; + struct net_device_stats *stats; + unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; + unsigned int i; + struct netdev_queue *txq; if (ops->ndo_get_stats) - return ops->ndo_get_stats(dev); + stats = ops->ndo_get_stats(dev); else { - unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; - struct net_device_stats *stats = &dev->stats; - unsigned int i; - struct netdev_queue *txq; - + /* Derive basic statistics from queue stats */ + stats = &dev->stats; for (i = 0; i < dev->num_tx_queues; i++) { txq = netdev_get_tx_queue(dev, i); tx_bytes += txq->tx_bytes; tx_packets += txq->tx_packets; tx_dropped += txq->tx_dropped; } - if (tx_bytes || tx_packets || tx_dropped) { + if (tx_bytes || tx_packets) { stats->tx_bytes = tx_bytes; stats->tx_packets = tx_packets; - stats->tx_dropped = tx_dropped; } - return stats; } + + /* + * Driver does not know how many packets were dropped by + * qdisc layer and higher for the network device. Add them + * here to have a complete accounting of losses associated + * with the interface. + */ + for (i = 0; i < dev->num_tx_queues; i++) { + struct Qdisc *q; + + txq = netdev_get_tx_queue(dev, i); + tx_dropped += txq->qdisc_sleeping->qstats.drops; + list_for_each_entry(q, &txq->qdisc_sleeping->list, list) + tx_dropped += q->qstats.drops; + } + + if (tx_dropped) + stats->tx_dropped += tx_dropped; + + return stats; } EXPORT_SYMBOL(dev_get_stats);