net_interface_private: added receive queue and splited device reading from packet processing. Delivering to self no longer is executed in the sender's context, which had some problems with TCP's locking.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21214 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-05-23 07:55:54 +00:00
parent 7e4dc23a7e
commit a1deb55ef5
6 changed files with 133 additions and 54 deletions
+1
View File
@@ -23,6 +23,7 @@ typedef struct net_buffer {
struct sockaddr *source; struct sockaddr *source;
struct sockaddr *destination; struct sockaddr *destination;
struct net_interface *interface; struct net_interface *interface;
int32 type;
union { union {
struct { struct {
uint16 start; uint16 start;
@@ -654,7 +654,8 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
return B_ERROR; return B_ERROR;
} }
return B_ERROR; gBufferModule->free(buffer);
return B_OK;
} }
+15 -29
View File
@@ -13,6 +13,7 @@
#include "interfaces.h" #include "interfaces.h"
#include "routes.h" #include "routes.h"
#include "stack_private.h" #include "stack_private.h"
#include "utility.h"
#include <net_device.h> #include <net_device.h>
#include <KernelExport.h> #include <KernelExport.h>
@@ -54,41 +55,22 @@ device_reader_thread(void *_interface)
status = device->module->receive_data(device, &buffer); status = device->module->receive_data(device, &buffer);
rx_lock.Lock(); rx_lock.Lock();
if (status == B_OK) { if (status == B_OK) {
//dprintf("received buffer of %ld bytes length\n", buffer->size);
// feed device monitors // feed device monitors
DeviceMonitorList::Iterator iterator DeviceMonitorList::Iterator iterator =
= interface->monitor_funcs.GetIterator(); interface->monitor_funcs.GetIterator();
while (iterator.HasNext()) { while (iterator.HasNext()) {
net_device_monitor *monitor = iterator.Next(); net_device_monitor *monitor = iterator.Next();
monitor->receive(monitor, buffer); monitor->receive(monitor, buffer);
} }
int32 type = interface->deframe_func(device, buffer); buffer->interface = NULL;
if (type >= 0) { buffer->type = interface->deframe_func(interface->device, buffer);
// find handler for this packet if (buffer->type < 0) {
DeviceHandlerList::Iterator iterator gNetBufferModule.free(buffer);
= interface->receive_funcs.GetIterator();
status = B_ERROR;
while (iterator.HasNext()) {
net_device_handler *handler = iterator.Next();
if (handler->type == type) {
status = handler->func(handler->cookie, device, buffer);
if (status == B_OK)
break;
}
}
} else
status = type;
if (status == B_OK) {
// the buffer no longer belongs to us
continue; continue;
} }
gNetBufferModule.free(buffer); fifo_enqueue_buffer(&interface->receive_queue, buffer);
} else { } else {
// 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 near real time thread. // time to run since this is a near real time thread.
@@ -336,8 +318,8 @@ datalink_control(net_domain *_domain, int32 option, void *value,
status_t status_t
datalink_send_data(struct net_route *route, net_buffer *buffer) datalink_send_data(struct net_route *route, net_buffer *buffer)
{ {
net_interface *interface = route->interface; net_interface_private *interface =
net_domain *domain = interface->domain; (net_interface_private *)route->interface;
//dprintf("send buffer (%ld bytes) to interface %s (route flags %lx)\n", //dprintf("send buffer (%ld bytes) to interface %s (route flags %lx)\n",
// buffer->size, interface->name, route->flags); // buffer->size, interface->name, route->flags);
@@ -346,8 +328,12 @@ datalink_send_data(struct net_route *route, net_buffer *buffer)
return ENETUNREACH; return ENETUNREACH;
if (route->flags & RTF_LOCAL) { if (route->flags & RTF_LOCAL) {
// we set the interface here so the buffer is delivered directly
// to the domain in interfaces.cpp:device_consumer_thread()
buffer->interface = interface;
// this one goes back to the domain directly // this one goes back to the domain directly
return domain->module->receive_data(buffer); return fifo_enqueue_buffer(
&interface->device_interface->receive_queue, buffer);
} }
if (route->flags & RTF_GATEWAY) { if (route->flags & RTF_GATEWAY) {
+109 -23
View File
@@ -21,6 +21,7 @@
#include <net/if_dl.h> #include <net/if_dl.h>
#include <new> #include <new>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -39,6 +40,51 @@ static uint32 sInterfaceIndex;
static uint32 sDeviceIndex; static uint32 sDeviceIndex;
static status_t
device_consumer_thread(void *_interface)
{
net_device_interface *interface = (net_device_interface *)_interface;
net_device *device = interface->device;
net_buffer *buffer;
while (true) {
ssize_t status = fifo_dequeue_buffer(&interface->receive_queue, 0,
B_INFINITE_TIMEOUT, &buffer);
if (status == B_INTERRUPTED)
continue;
else if (status < B_OK)
break;
if (buffer->interface != NULL) {
// if the interface is already specified this buffer was
// delivered locally.
net_domain *domain = buffer->interface->domain;
if (domain->module->receive_data(buffer) == B_OK)
buffer = NULL;
} else {
// find handler for this packet
DeviceHandlerList::Iterator it2 =
interface->receive_funcs.GetIterator();
while (buffer && it2.HasNext()) {
net_device_handler *handler = it2.Next();
// if the handler returns B_OK, it consumed the buffer
if (handler->type == buffer->type
&& handler->func(handler->cookie, device, buffer) == B_OK)
buffer = NULL;
}
}
if (buffer)
gNetBufferModule.free(buffer);
}
return B_OK;
}
static net_device_interface * static net_device_interface *
find_device_interface(const char *name) find_device_interface(const char *name)
{ {
@@ -65,6 +111,60 @@ domain_receive_adapter(void *cookie, net_device *device, net_buffer *buffer)
} }
static net_device_interface *
allocate_device_interface(net_device *device, net_device_module_info *module)
{
net_device_interface *interface = new (std::nothrow) net_device_interface;
if (interface == NULL)
goto error_0;
if (recursive_lock_init(&interface->rx_lock, "rx lock") < B_OK)
goto error_1;
char name[128];
snprintf(name, sizeof(name), "%s receive queue", device->name);
if (init_fifo(&interface->receive_queue, name, 16 * 1024 * 1024) < B_OK)
goto error_2;
interface->name = device->name;
interface->module = module;
interface->device = device;
interface->up_count = 0;
interface->ref_count = 1;
interface->deframe_func = NULL;
interface->deframe_ref_count = 0;
snprintf(name, sizeof(name), "%s consumer", device->name);
interface->reader_thread = -1;
interface->consumer_thread = spawn_kernel_thread(device_consumer_thread,
name, B_REAL_TIME_DISPLAY_PRIORITY - 10, interface);
if (interface->consumer_thread < B_OK)
goto error_3;
resume_thread(interface->consumer_thread);
// TODO: proper interface index allocation
device->index = ++sDeviceIndex;
device->module = module;
sInterfaces.Add(interface);
return interface;
error_3:
uninit_fifo(&interface->receive_queue);
error_2:
recursive_lock_destroy(&interface->rx_lock);
error_1:
delete interface;
error_0:
return NULL;
}
net_device_interface * net_device_interface *
grab_device_interface(net_device_interface *interface) grab_device_interface(net_device_interface *interface)
{ {
@@ -337,13 +437,15 @@ put_device_interface(struct net_device_interface *interface)
if (atomic_add(&interface->ref_count, -1) != 1) if (atomic_add(&interface->ref_count, -1) != 1)
return; return;
// we need to remove this interface!
{ {
BenaphoreLocker locker(sInterfaceLock); BenaphoreLocker locker(sInterfaceLock);
sInterfaces.Remove(interface); sInterfaces.Remove(interface);
} }
uninit_fifo(&interface->receive_queue);
status_t status;
wait_for_thread(interface->consumer_thread, &status);
interface->module->uninit_device(interface->device); interface->module->uninit_device(interface->device);
put_module(interface->module->info.name); put_module(interface->module->info.name);
@@ -411,27 +513,9 @@ get_device_interface(const char *name, bool create)
net_device *device; net_device *device;
status_t status = module->init_device(name, &device); status_t status = module->init_device(name, &device);
if (status == B_OK) { if (status == B_OK) {
// create new module interface for this interface = allocate_device_interface(device, module);
interface = new (std::nothrow) net_device_interface; if (interface)
if (interface != NULL) { return interface;
if (recursive_lock_init(&interface->rx_lock,
"rx lock") >= B_OK) {
interface->name = device->name;
interface->module = module;
interface->device = device;
interface->up_count = 0;
interface->ref_count = 1;
interface->deframe_func = NULL;
interface->deframe_ref_count = 0;
device->index = ++sDeviceIndex;
device->module = module;
sInterfaces.Add(interface);
return interface;
}
delete interface;
}
module->uninit_device(device); module->uninit_device(device);
} }
put_module(moduleName); put_module(moduleName);
@@ -469,6 +553,8 @@ down_device_interface(net_device_interface *interface)
thread_id reader_thread = interface->reader_thread; thread_id reader_thread = interface->reader_thread;
// TODO when setting the interface down, should we clear the receive queue?
// one of the callers must hold a reference to the net_device_interface // one of the callers must hold a reference to the net_device_interface
// usually it is one of the net_interfaces. // usually it is one of the net_interfaces.
recursive_lock_unlock(&interface->rx_lock); recursive_lock_unlock(&interface->rx_lock);
@@ -27,7 +27,6 @@ typedef DoublyLinkedList<net_device_monitor,
DoublyLinkedListCLink<net_device_monitor> > DeviceMonitorList; DoublyLinkedListCLink<net_device_monitor> > DeviceMonitorList;
struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> { struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
//struct list_link link;
const char *name; const char *name;
struct net_device_module_info *module; struct net_device_module_info *module;
struct net_device *device; struct net_device *device;
@@ -43,6 +42,9 @@ struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
DeviceHandlerList receive_funcs; DeviceHandlerList receive_funcs;
recursive_lock rx_lock; recursive_lock rx_lock;
thread_id consumer_thread;
net_fifo receive_queue;
}; };
typedef DoublyLinkedList<net_device_interface> DeviceInterfaceList; typedef DoublyLinkedList<net_device_interface> DeviceInterfaceList;
@@ -345,6 +345,8 @@ create_buffer(size_t headerSpace)
buffer->flags = 0; buffer->flags = 0;
buffer->size = 0; buffer->size = 0;
buffer->type = -1;
return buffer; return buffer;
} }
@@ -378,6 +380,7 @@ copy_metadata(net_buffer *destination, const net_buffer *source)
destination->offset = source->offset; destination->offset = source->offset;
destination->size = source->size; destination->size = source->size;
destination->protocol = source->protocol; destination->protocol = source->protocol;
destination->type = source->type;
} }