Browse Source

[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.
tags/v0.9.6
Michael Brown 15 years ago
parent
commit
9a52ba0cfa
5 changed files with 104 additions and 31 deletions
  1. 21
    10
      src/include/gpxe/netdevice.h
  2. 12
    10
      src/interface/efi/efi_snp.c
  3. 6
    5
      src/interface/pxe/pxe_undi.c
  4. 42
    4
      src/net/netdevice.c
  5. 23
    2
      src/usr/ifmgmt.c

+ 21
- 10
src/include/gpxe/netdevice.h View File

193
 	void ( * irq ) ( struct net_device *netdev, int enable );
193
 	void ( * irq ) ( struct net_device *netdev, int enable );
194
 };
194
 };
195
 
195
 
196
+/** Network device error */
197
+struct net_device_error {
198
+	/** Error status code */
199
+	int rc;
200
+	/** Error count */
201
+	unsigned int count;
202
+};
203
+
204
+/** Maximum number of unique errors that we will keep track of */
205
+#define NETDEV_MAX_UNIQUE_ERRORS 4
206
+
196
 /** Network device statistics */
207
 /** Network device statistics */
197
 struct net_device_stats {
208
 struct net_device_stats {
198
-	/** Count of successfully completed transmissions */
199
-	unsigned int tx_ok;
200
-	/** Count of transmission errors */
201
-	unsigned int tx_err;
202
-	/** Count of successfully received packets */
203
-	unsigned int rx_ok;
204
-	/** Count of reception errors */
205
-	unsigned int rx_err;
209
+	/** Count of successful completions */
210
+	unsigned int good;
211
+	/** Count of error completions */
212
+	unsigned int bad;
213
+	/** Error breakdowns */
214
+	struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS];
206
 };
215
 };
207
 
216
 
208
 /**
217
 /**
250
 	struct list_head tx_queue;
259
 	struct list_head tx_queue;
251
 	/** RX packet queue */
260
 	/** RX packet queue */
252
 	struct list_head rx_queue;
261
 	struct list_head rx_queue;
253
-	/** Device statistics */
254
-	struct net_device_stats stats;
262
+	/** TX statistics */
263
+	struct net_device_stats tx_stats;
264
+	/** RX statistics */
265
+	struct net_device_stats rx_stats;
255
 
266
 
256
 	/** Configuration settings applicable to this device */
267
 	/** Configuration settings applicable to this device */
257
 	struct simple_settings settings;
268
 	struct simple_settings settings;

+ 12
- 10
src/interface/efi/efi_snp.c View File

317
 
317
 
318
 	/* Gather statistics */
318
 	/* Gather statistics */
319
 	memset ( &stats_buf, 0, sizeof ( stats_buf ) );
319
 	memset ( &stats_buf, 0, sizeof ( stats_buf ) );
320
-	stats_buf.TxGoodFrames = snpdev->netdev->stats.tx_ok;
321
-	stats_buf.TxDroppedFrames = snpdev->netdev->stats.tx_err;
322
-	stats_buf.TxTotalFrames = ( snpdev->netdev->stats.tx_ok +
323
-				    snpdev->netdev->stats.tx_err );
324
-	stats_buf.RxGoodFrames = snpdev->netdev->stats.rx_ok;
325
-	stats_buf.RxDroppedFrames = snpdev->netdev->stats.rx_err;
326
-	stats_buf.RxTotalFrames = ( snpdev->netdev->stats.rx_ok +
327
-				    snpdev->netdev->stats.rx_err );
320
+	stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
321
+	stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
322
+	stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
323
+				    snpdev->netdev->tx_stats.bad );
324
+	stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
325
+	stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
326
+	stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
327
+				    snpdev->netdev->rx_stats.bad );
328
 	if ( *stats_len > sizeof ( stats_buf ) )
328
 	if ( *stats_len > sizeof ( stats_buf ) )
329
 		*stats_len = sizeof ( stats_buf );
329
 		*stats_len = sizeof ( stats_buf );
330
 	if ( stats )
330
 	if ( stats )
332
 
332
 
333
 	/* Reset statistics if requested to do so */
333
 	/* Reset statistics if requested to do so */
334
 	if ( reset ) {
334
 	if ( reset ) {
335
-		memset ( &snpdev->netdev->stats, 0,
336
-			 sizeof ( snpdev->netdev->stats ) );
335
+		memset ( &snpdev->netdev->tx_stats, 0,
336
+			 sizeof ( snpdev->netdev->tx_stats ) );
337
+		memset ( &snpdev->netdev->rx_stats, 0,
338
+			 sizeof ( snpdev->netdev->rx_stats ) );
337
 	}
339
 	}
338
 
340
 
339
 	return 0;
341
 	return 0;

+ 6
- 5
src/interface/pxe/pxe_undi.c View File

392
 					 *undi_get_statistics ) {
392
 					 *undi_get_statistics ) {
393
 	DBG ( "PXENV_UNDI_GET_STATISTICS" );
393
 	DBG ( "PXENV_UNDI_GET_STATISTICS" );
394
 
394
 
395
-	undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok;
396
-	undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok;
397
-	undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err;
398
-	undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err;
395
+	undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
396
+	undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
397
+	undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
398
+	undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
399
 
399
 
400
 	undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
400
 	undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
401
 	return PXENV_EXIT_SUCCESS;
401
 	return PXENV_EXIT_SUCCESS;
409
 					   *undi_clear_statistics ) {
409
 					   *undi_clear_statistics ) {
410
 	DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
410
 	DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
411
 
411
 
412
-	memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) );
412
+	memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
413
+	memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
413
 
414
 
414
 	undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
415
 	undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
415
 	return PXENV_EXIT_SUCCESS;
416
 	return PXENV_EXIT_SUCCESS;

+ 42
- 4
src/net/netdevice.c View File

45
 /** List of network devices */
45
 /** List of network devices */
46
 struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
46
 struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
47
 
47
 
48
+/**
49
+ * Record network device statistic
50
+ *
51
+ * @v stats		Network device statistics
52
+ * @v rc		Status code
53
+ */
54
+static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
55
+	struct net_device_error *error;
56
+	struct net_device_error *least_common_error;
57
+	unsigned int i;
58
+
59
+	/* If this is not an error, just update the good counter */
60
+	if ( rc == 0 ) {
61
+		stats->good++;
62
+		return;
63
+	}
64
+
65
+	/* Update the bad counter */
66
+	stats->bad++;
67
+
68
+	/* Locate the appropriate error record */
69
+	least_common_error = &stats->errors[0];
70
+	for ( i = 0 ; i < ( sizeof ( stats->errors ) /
71
+			    sizeof ( stats->errors[0] ) ) ; i++ ) {
72
+		error = &stats->errors[i];
73
+		/* Update matching record, if found */
74
+		if ( error->rc == rc ) {
75
+			error->count++;
76
+			return;
77
+		}
78
+		if ( error->count < least_common_error->count )
79
+			least_common_error = error;
80
+	}
81
+
82
+	/* Overwrite the least common error record */
83
+	least_common_error->rc = rc;
84
+	least_common_error->count = 1;
85
+}
86
+
48
 /**
87
 /**
49
  * Transmit raw packet via network device
88
  * Transmit raw packet via network device
50
  *
89
  *
91
 			      struct io_buffer *iobuf, int rc ) {
130
 			      struct io_buffer *iobuf, int rc ) {
92
 
131
 
93
 	/* Update statistics counter */
132
 	/* Update statistics counter */
133
+	netdev_record_stat ( &netdev->tx_stats, rc );
94
 	if ( rc == 0 ) {
134
 	if ( rc == 0 ) {
95
-		netdev->stats.tx_ok++;
96
 		DBGC ( netdev, "NETDEV %p transmission %p complete\n",
135
 		DBGC ( netdev, "NETDEV %p transmission %p complete\n",
97
 		       netdev, iobuf );
136
 		       netdev, iobuf );
98
 	} else {
137
 	} else {
99
-		netdev->stats.tx_err++;
100
 		DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
138
 		DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
101
 		       netdev, iobuf, strerror ( rc ) );
139
 		       netdev, iobuf, strerror ( rc ) );
102
 	}
140
 	}
158
 	list_add_tail ( &iobuf->list, &netdev->rx_queue );
196
 	list_add_tail ( &iobuf->list, &netdev->rx_queue );
159
 
197
 
160
 	/* Update statistics counter */
198
 	/* Update statistics counter */
161
-	netdev->stats.rx_ok++;
199
+	netdev_record_stat ( &netdev->rx_stats, 0 );
162
 }
200
 }
163
 
201
 
164
 /**
202
 /**
183
 	free_iob ( iobuf );
221
 	free_iob ( iobuf );
184
 
222
 
185
 	/* Update statistics counter */
223
 	/* Update statistics counter */
186
-	netdev->stats.rx_err++;
224
+	netdev_record_stat ( &netdev->rx_stats, rc );
187
 }
225
 }
188
 
226
 
189
 /**
227
 /**

+ 23
- 2
src/usr/ifmgmt.c View File

58
 	netdev_close ( netdev );
58
 	netdev_close ( netdev );
59
 }
59
 }
60
 
60
 
61
+/**
62
+ * Print network device error breakdown
63
+ *
64
+ * @v stats		Network device statistics
65
+ * @v prefix		Message prefix
66
+ */
67
+static void ifstat_errors ( struct net_device_stats *stats,
68
+			    const char *prefix ) {
69
+	unsigned int i;
70
+
71
+	for ( i = 0 ; i < ( sizeof ( stats->errors ) /
72
+			    sizeof ( stats->errors[0] ) ) ; i++ ) {
73
+		if ( stats->errors[i].count )
74
+			printf ( "  [%s: %d x \"%s\"]\n", prefix,
75
+				 stats->errors[i].count,
76
+				 strerror ( stats->errors[i].rc ) );
77
+	}
78
+}
79
+
61
 /**
80
 /**
62
  * Print status of network device
81
  * Print status of network device
63
  *
82
  *
69
 		 netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name,
88
 		 netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name,
70
 		 ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
89
 		 ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
71
 		 ( netdev_link_ok ( netdev ) ? "up" : "down" ),
90
 		 ( netdev_link_ok ( netdev ) ? "up" : "down" ),
72
-		 netdev->stats.tx_ok, netdev->stats.tx_err,
73
-		 netdev->stats.rx_ok, netdev->stats.rx_err );
91
+		 netdev->tx_stats.good, netdev->tx_stats.bad,
92
+		 netdev->rx_stats.good, netdev->rx_stats.bad );
93
+	ifstat_errors ( &netdev->tx_stats, "TXE" );
94
+	ifstat_errors ( &netdev->rx_stats, "RXE" );
74
 }
95
 }
75
 
96
 
76
 /**
97
 /**

Loading…
Cancel
Save