network: Update device statistics (mostly) in the stack.

We bypass device logic in datalink_send_routed_data() in the case
of RTF_LOCAL, so if we don't update the stats there, they'll never
get updated. Furthermore, there's places packets can be dropped
inside the device reader thread. So, we might as well consolidate
the stats-updating logic and get it out of drivers.

(The only remaining case where drivers need to update stats is when
they drop a packet in receive(), as the stack can't tell when an error
from receive() is due to a dropped packet or not.)

Fixes a potential leak on packet drops in the device reader thread,
and fixes loopback statistics for TCP/UDP/etc.
This commit is contained in:
Augustin Cavalier
2023-12-29 12:59:24 -05:00
parent fd2a5629f1
commit 819c51084f
7 changed files with 42 additions and 52 deletions
@@ -448,14 +448,10 @@ dialup_send_data(net_device* _device, net_buffer* buffer)
} }
device->last_closing_flag_sequence_time = system_time(); device->last_closing_flag_sequence_time = system_time();
device->stats.send.packets++;
device->stats.send.bytes += bytesWritten;
status = B_OK; status = B_OK;
goto done; goto done;
err: err:
device->stats.send.errors++;
done: done:
free(ioVectors); free(ioVectors);
free(packet); free(packet);
@@ -502,20 +498,16 @@ dialup_receive_data(net_device* _device, net_buffer** _buffer)
status = gBufferModule->trim(buffer, bytesRead); status = gBufferModule->trim(buffer, bytesRead);
if (status < B_OK) { if (status < B_OK) {
device->stats.receive.dropped++; atomic_add((int32*)&device->stats.receive.dropped, 1);
goto err; goto err;
} }
device->stats.receive.bytes += bytesRead;
device->stats.receive.packets++;
*_buffer = buffer; *_buffer = buffer;
status = B_OK; status = B_OK;
goto done; goto done;
err: err:
gBufferModule->free(buffer); gBufferModule->free(buffer);
device->stats.receive.errors++;
done: done:
free(packet); free(packet);
@@ -313,8 +313,7 @@ ethernet_send_data(net_device *_device, net_buffer *buffer)
if (gBufferModule->count_iovecs(allocated) > 1) { if (gBufferModule->count_iovecs(allocated) > 1) {
dprintf("ethernet_send_data: no write buffer, cannot perform scatter I/O\n"); dprintf("ethernet_send_data: no write buffer, cannot perform scatter I/O\n");
gBufferModule->free(allocated); gBufferModule->free(allocated);
device->stats.send.errors++; return EMSGSIZE;
return B_NOT_SUPPORTED;
} }
gBufferModule->get_iovecs(buffer, &iovec, 1); gBufferModule->get_iovecs(buffer, &iovec, 1);
@@ -328,15 +327,11 @@ ethernet_send_data(net_device *_device, net_buffer *buffer)
//dprintf("sent: %ld\n", bytesWritten); //dprintf("sent: %ld\n", bytesWritten);
if (bytesWritten < 0) { if (bytesWritten < 0) {
atomic_add((int32*)&device->stats.send.errors, 1);
if (allocated) if (allocated)
gBufferModule->free(allocated); gBufferModule->free(allocated);
return errno; return errno;
} }
atomic_add((int32*)&device->stats.send.packets, 1);
atomic_add64((int64*)&device->stats.send.bytes, bytesWritten);
gBufferModule->free(original); gBufferModule->free(original);
if (allocated) if (allocated)
gBufferModule->free(allocated); gBufferModule->free(allocated);
@@ -382,7 +377,6 @@ ethernet_receive_data(net_device *_device, net_buffer **_buffer)
bytesRead = read(device->fd, iovec.iov_base, iovec.iov_len); bytesRead = read(device->fd, iovec.iov_base, iovec.iov_len);
if (bytesRead < 0) { if (bytesRead < 0) {
atomic_add((int32*)&device->stats.receive.errors, 1);
status = errno; status = errno;
goto err; goto err;
} }
@@ -397,9 +391,6 @@ ethernet_receive_data(net_device *_device, net_buffer **_buffer)
goto err; goto err;
} }
atomic_add((int32*)&device->stats.receive.packets, 1);
atomic_add64((int64*)&device->stats.receive.bytes, bytesRead);
*_buffer = buffer; *_buffer = buffer;
return B_OK; return B_OK;
@@ -110,14 +110,7 @@ loopback_control(net_device *device, int32 op, void *argument,
status_t status_t
loopback_send_data(net_device *device, net_buffer *buffer) loopback_send_data(net_device *device, net_buffer *buffer)
{ {
status_t status = sStackModule->device_enqueue_buffer(device, buffer); return sStackModule->device_enqueue_buffer(device, buffer);
if (status == B_OK) {
atomic_add64((int64*)&device->stats.send.bytes, buffer->size);
atomic_add((int32*)&device->stats.send.packets, 1);
} else {
atomic_add((int32*)&device->stats.send.errors, 1);
}
return status;
} }
@@ -247,13 +247,6 @@ tunnel_write(void* _cookie, off_t position, const void* data, size_t* _length)
if (status != B_OK) if (status != B_OK)
gBufferModule->free(buffer); gBufferModule->free(buffer);
if (status == B_OK) {
atomic_add((int32*)&cookie->device->stats.receive.packets, 1);
atomic_add64((int64*)&cookie->device->stats.receive.bytes, buffer->size);
} else {
atomic_add((int32*)&cookie->device->stats.receive.errors, 1);
}
return status; return status;
} }
@@ -468,14 +461,10 @@ tunnel_send_data(net_device* _device, net_buffer* buffer)
status = gStackModule->fifo_enqueue_buffer( status = gStackModule->fifo_enqueue_buffer(
&device->send_queue, buffer); &device->send_queue, buffer);
if (status == B_OK) { if (status == B_OK) {
atomic_add((int32*)&device->stats.send.packets, 1); MutexLocker selectLocker(device->select_lock);
atomic_add64((int64*)&device->stats.send.bytes, buffer->size); notify_select_event_pool(device->select_pool, B_SELECT_READ);
} else {
atomic_add((int32*)&device->stats.send.errors, 1);
} }
MutexLocker selectLocker(device->select_lock);
notify_select_event_pool(device->select_pool, B_SELECT_READ);
return status; return status;
} }
+1 -9
View File
@@ -193,13 +193,11 @@ ppp_send_data(net_device *_device, net_buffer *buffer)
ppp_device *device = (ppp_device *)_device; ppp_device *device = (ppp_device *)_device;
if (buffer->size > device->frame_size || buffer->size < device->header_length) { if (buffer->size > device->frame_size || buffer->size < device->header_length) {
device->stats.send.errors++;
dprintf("sorry! fail send ppp packet, size wrong!\n"); dprintf("sorry! fail send ppp packet, size wrong!\n");
return B_BAD_VALUE; return EMSGSIZE;
} }
if (device->KPPP_Interface == NULL) { if (device->KPPP_Interface == NULL) {
device->stats.send.errors++;
dprintf("Fail send ppp packet, no eth for ppp!\n"); dprintf("Fail send ppp packet, no eth for ppp!\n");
return B_BAD_VALUE; return B_BAD_VALUE;
} }
@@ -209,14 +207,10 @@ ppp_send_data(net_device *_device, net_buffer *buffer)
status_t status = device->KPPP_Interface->Send(buffer, 0x0021); // IP_PROTOCOL 0x0021 status_t status = device->KPPP_Interface->Send(buffer, 0x0021); // IP_PROTOCOL 0x0021
if (status != B_OK) { if (status != B_OK) {
device->stats.send.errors++;
dprintf("KPPP_Interface->Send(buffer, 0x0021 IP) fail\n"); dprintf("KPPP_Interface->Send(buffer, 0x0021 IP) fail\n");
return B_BAD_VALUE; return B_BAD_VALUE;
} }
device->stats.send.packets++;
device->stats.send.bytes += net_buffer_size;
return B_OK; return B_OK;
} }
@@ -239,8 +233,6 @@ ppp_receive_data(net_device *_device, net_buffer **_buffer)
} }
// (*_buffer)->interface_address = NULL; // strange need to put here // (*_buffer)->interface_address = NULL; // strange need to put here
device->stats.receive.bytes += (*_buffer)->size;
device->stats.receive.packets++;
return B_OK; return B_OK;
} }
+24 -2
View File
@@ -194,6 +194,21 @@ fill_address(const sockaddr* from, sockaddr* to, size_t maxLength)
} }
static void
update_device_send_stats(struct net_device* device, status_t status, size_t packetSize)
{
if (status == B_OK) {
atomic_add((int32*)&device->stats.send.packets, 1);
atomic_add64((int64*)&device->stats.send.bytes, packetSize);
} else {
if (status == ENOBUFS || status == EMSGSIZE)
atomic_add((int32*)&device->stats.send.dropped, 1);
else
atomic_add((int32*)&device->stats.send.errors, 1);
}
}
// #pragma mark - datalink module // #pragma mark - datalink module
@@ -411,8 +426,12 @@ datalink_send_routed_data(struct net_route* route, net_buffer* buffer)
} }
// this one goes back to the domain directly // this one goes back to the domain directly
return fifo_enqueue_buffer( const size_t packetSize = buffer->size;
status_t status = fifo_enqueue_buffer(
&interface->DeviceInterface()->receive_queue, buffer); &interface->DeviceInterface()->receive_queue, buffer);
update_device_send_stats(interface->DeviceInterface()->device,
status, packetSize);
return status;
} }
if ((route->flags & RTF_GATEWAY) != 0) { if ((route->flags & RTF_GATEWAY) != 0) {
@@ -721,7 +740,10 @@ interface_protocol_send_data(net_datalink_protocol* _protocol,
if (atomic_get(&interface->DeviceInterface()->monitor_count) > 0) if (atomic_get(&interface->DeviceInterface()->monitor_count) > 0)
device_interface_monitor_receive(interface->DeviceInterface(), buffer); device_interface_monitor_receive(interface->DeviceInterface(), buffer);
return protocol->device_module->send_data(protocol->device, buffer); const size_t packetSize = buffer->size;
status_t status = protocol->device_module->send_data(protocol->device, buffer);
update_device_send_stats(protocol->device, status, packetSize);
return status;
} }
@@ -64,14 +64,25 @@ device_reader_thread(void* _interface)
if (interface->deframe_func(interface->device, buffer) != B_OK) { if (interface->deframe_func(interface->device, buffer) != B_OK) {
gNetBufferModule.free(buffer); gNetBufferModule.free(buffer);
atomic_add((int32*)&device->stats.receive.dropped, 1);
continue; continue;
} }
fifo_enqueue_buffer(&interface->receive_queue, buffer); const size_t packetSize = buffer->size;
status = fifo_enqueue_buffer(&interface->receive_queue, buffer);
if (status == B_OK) {
atomic_add((int32*)&device->stats.receive.packets, 1);
atomic_add64((int64*)&device->stats.receive.bytes, packetSize);
} else {
gNetBufferModule.free(buffer);
atomic_add((int32*)&device->stats.receive.dropped, 1);
}
} else if (status == B_DEVICE_NOT_FOUND) { } else if (status == B_DEVICE_NOT_FOUND) {
device_removed(device); device_removed(device);
return status; return status;
} else { } else {
atomic_add((int32*)&device->stats.receive.errors, 1);
// In case of error, give the other threads some // In case of error, give the other threads some
// time to run since this is a high priority time thread. // time to run since this is a high priority time thread.
snooze(10000); snooze(10000);