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->stats.send.packets++;
device->stats.send.bytes += bytesWritten;
status = B_OK;
goto done;
err:
device->stats.send.errors++;
done:
free(ioVectors);
free(packet);
@@ -502,20 +498,16 @@ dialup_receive_data(net_device* _device, net_buffer** _buffer)
status = gBufferModule->trim(buffer, bytesRead);
if (status < B_OK) {
device->stats.receive.dropped++;
atomic_add((int32*)&device->stats.receive.dropped, 1);
goto err;
}
device->stats.receive.bytes += bytesRead;
device->stats.receive.packets++;
*_buffer = buffer;
status = B_OK;
goto done;
err:
gBufferModule->free(buffer);
device->stats.receive.errors++;
done:
free(packet);
@@ -313,8 +313,7 @@ ethernet_send_data(net_device *_device, net_buffer *buffer)
if (gBufferModule->count_iovecs(allocated) > 1) {
dprintf("ethernet_send_data: no write buffer, cannot perform scatter I/O\n");
gBufferModule->free(allocated);
device->stats.send.errors++;
return B_NOT_SUPPORTED;
return EMSGSIZE;
}
gBufferModule->get_iovecs(buffer, &iovec, 1);
@@ -328,15 +327,11 @@ ethernet_send_data(net_device *_device, net_buffer *buffer)
//dprintf("sent: %ld\n", bytesWritten);
if (bytesWritten < 0) {
atomic_add((int32*)&device->stats.send.errors, 1);
if (allocated)
gBufferModule->free(allocated);
return errno;
}
atomic_add((int32*)&device->stats.send.packets, 1);
atomic_add64((int64*)&device->stats.send.bytes, bytesWritten);
gBufferModule->free(original);
if (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);
if (bytesRead < 0) {
atomic_add((int32*)&device->stats.receive.errors, 1);
status = errno;
goto err;
}
@@ -397,9 +391,6 @@ ethernet_receive_data(net_device *_device, net_buffer **_buffer)
goto err;
}
atomic_add((int32*)&device->stats.receive.packets, 1);
atomic_add64((int64*)&device->stats.receive.bytes, bytesRead);
*_buffer = buffer;
return B_OK;
@@ -110,14 +110,7 @@ loopback_control(net_device *device, int32 op, void *argument,
status_t
loopback_send_data(net_device *device, net_buffer *buffer)
{
status_t status = 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;
return sStackModule->device_enqueue_buffer(device, buffer);
}
@@ -247,13 +247,6 @@ tunnel_write(void* _cookie, off_t position, const void* data, size_t* _length)
if (status != B_OK)
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;
}
@@ -468,14 +461,10 @@ tunnel_send_data(net_device* _device, net_buffer* buffer)
status = gStackModule->fifo_enqueue_buffer(
&device->send_queue, buffer);
if (status == B_OK) {
atomic_add((int32*)&device->stats.send.packets, 1);
atomic_add64((int64*)&device->stats.send.bytes, buffer->size);
} else {
atomic_add((int32*)&device->stats.send.errors, 1);
MutexLocker selectLocker(device->select_lock);
notify_select_event_pool(device->select_pool, B_SELECT_READ);
}
MutexLocker selectLocker(device->select_lock);
notify_select_event_pool(device->select_pool, B_SELECT_READ);
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;
if (buffer->size > device->frame_size || buffer->size < device->header_length) {
device->stats.send.errors++;
dprintf("sorry! fail send ppp packet, size wrong!\n");
return B_BAD_VALUE;
return EMSGSIZE;
}
if (device->KPPP_Interface == NULL) {
device->stats.send.errors++;
dprintf("Fail send ppp packet, no eth for ppp!\n");
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
if (status != B_OK) {
device->stats.send.errors++;
dprintf("KPPP_Interface->Send(buffer, 0x0021 IP) fail\n");
return B_BAD_VALUE;
}
device->stats.send.packets++;
device->stats.send.bytes += net_buffer_size;
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
device->stats.receive.bytes += (*_buffer)->size;
device->stats.receive.packets++;
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
@@ -411,8 +426,12 @@ datalink_send_routed_data(struct net_route* route, net_buffer* buffer)
}
// 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);
update_device_send_stats(interface->DeviceInterface()->device,
status, packetSize);
return status;
}
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)
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) {
gNetBufferModule.free(buffer);
atomic_add((int32*)&device->stats.receive.dropped, 1);
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) {
device_removed(device);
return status;
} else {
atomic_add((int32*)&device->stats.receive.errors, 1);
// In case of error, give the other threads some
// time to run since this is a high priority time thread.
snooze(10000);