diff options
Diffstat (limited to 'gpxe/src/net/netdevice.c')
-rw-r--r-- | gpxe/src/net/netdevice.c | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c index 3721b334..e8587a9d 100644 --- a/gpxe/src/net/netdevice.c +++ b/gpxe/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 ); } /** @@ -268,7 +306,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) { INIT_LIST_HEAD ( &netdev->rx_queue ); settings_init ( netdev_settings ( netdev ), &netdev_settings_operations, &netdev->refcnt, - netdev->name ); + netdev->name, 0 ); netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); } return netdev; @@ -439,6 +477,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type, */ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; int rc; /* Force a poll on the netdevice to (potentially) clear any @@ -449,8 +488,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, netdev_poll ( netdev ); /* Add link-layer header */ - if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol, - ll_dest ) ) != 0 ) { + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr, + net_protocol->net_proto ) ) != 0 ) { free_iob ( iobuf ); return rc; } @@ -495,8 +534,9 @@ static void net_step ( struct process *process __unused ) { struct net_device *netdev; struct io_buffer *iobuf; struct ll_protocol *ll_protocol; - uint16_t net_proto; + const void *ll_dest; const void *ll_source; + uint16_t net_proto; int rc; /* Poll and process each network device */ @@ -519,9 +559,9 @@ static void net_step ( struct process *process __unused ) { /* Remove link-layer header */ ll_protocol = netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, netdev, - &net_proto, - &ll_source ) ) != 0 ) { + if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, + &ll_source, + &net_proto ) ) != 0 ) { free_iob ( iobuf ); continue; } |