diff options
author | Michael Brown | 2008-11-08 03:18:30 +0100 |
---|---|---|
committer | Michael Brown | 2008-11-08 06:30:30 +0100 |
commit | 9a52ba0cfac0fffb39b5a4c148ec7641bcc38381 (patch) | |
tree | 12059ca7f75d37d1b62ffa550798fa8233834590 /src/net/netdevice.c | |
parent | [phantom] Do not halt PEGs on driver shutdown (diff) | |
download | ipxe-9a52ba0cfac0fffb39b5a4c148ec7641bcc38381.tar.gz ipxe-9a52ba0cfac0fffb39b5a4c148ec7641bcc38381.tar.xz ipxe-9a52ba0cfac0fffb39b5a4c148ec7641bcc38381.zip |
[netdevice] Retain and report detailed error breakdowns
netdev_rx_err() and netdev_tx_complete_err() get passed the error
code, but currently use it only in debug messages.
Retain error numbers and frequencey counts for up to
NETDEV_MAX_UNIQUE_ERRORS (4) different errors for each of TX and RX.
This allows the "ifstat" command to report the reasons for TX/RX
errors in most cases, even in non-debug builds.
Diffstat (limited to 'src/net/netdevice.c')
-rw-r--r-- | src/net/netdevice.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 81c4ae88..e8587a9d 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -46,6 +46,45 @@ static struct net_protocol net_protocols_end[0] struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); /** + * Record network device statistic + * + * @v stats Network device statistics + * @v rc Status code + */ +static void netdev_record_stat ( struct net_device_stats *stats, int rc ) { + struct net_device_error *error; + struct net_device_error *least_common_error; + unsigned int i; + + /* If this is not an error, just update the good counter */ + if ( rc == 0 ) { + stats->good++; + return; + } + + /* Update the bad counter */ + stats->bad++; + + /* Locate the appropriate error record */ + least_common_error = &stats->errors[0]; + for ( i = 0 ; i < ( sizeof ( stats->errors ) / + sizeof ( stats->errors[0] ) ) ; i++ ) { + error = &stats->errors[i]; + /* Update matching record, if found */ + if ( error->rc == rc ) { + error->count++; + return; + } + if ( error->count < least_common_error->count ) + least_common_error = error; + } + + /* Overwrite the least common error record */ + least_common_error->rc = rc; + least_common_error->count = 1; +} + +/** * Transmit raw packet via network device * * @v netdev Network device @@ -91,12 +130,11 @@ void netdev_tx_complete_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { /* Update statistics counter */ + netdev_record_stat ( &netdev->tx_stats, rc ); if ( rc == 0 ) { - netdev->stats.tx_ok++; DBGC ( netdev, "NETDEV %p transmission %p complete\n", netdev, iobuf ); } else { - netdev->stats.tx_err++; DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n", netdev, iobuf, strerror ( rc ) ); } @@ -158,7 +196,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { list_add_tail ( &iobuf->list, &netdev->rx_queue ); /* Update statistics counter */ - netdev->stats.rx_ok++; + netdev_record_stat ( &netdev->rx_stats, 0 ); } /** @@ -183,7 +221,7 @@ void netdev_rx_err ( struct net_device *netdev, free_iob ( iobuf ); /* Update statistics counter */ - netdev->stats.rx_err++; + netdev_record_stat ( &netdev->rx_stats, rc ); } /** |