mirror of
https://github.com/ipxe/ipxe
synced 2025-12-12 14:32:49 +03:00
[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.
This commit is contained in:
@@ -45,6 +45,45 @@ static struct net_protocol net_protocols_end[0]
|
||||
/** List of network devices */
|
||||
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
|
||||
*
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user