started some work to properly handle device_removed() and setting interfaces down in general.

- remove all routes that use interfaces going down.
 - when a device is going down, remove associated domain interfaces.
 - interfaces weren't getting a properly referenced device interface, fixed.
 - down call down_device_interface when deleting a interface, instead set it down and let the upcounts do its job.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20600 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos 2007-04-06 06:23:35 +00:00
parent 0b10ed0573
commit c64fecca78
7 changed files with 135 additions and 11 deletions

View File

@ -332,10 +332,7 @@ datalink_control(net_domain *_domain, int32 option, void *value,
if (((uint32)request.ifr_flags & IFF_UP)
!= (interface->flags & IFF_UP)) {
if ((interface->flags & IFF_UP) != 0) {
// bring the interface down
interface->flags &= ~(IFF_UP | IFF_LINK);
interface->first_info->interface_down(
interface->first_protocol);
interface_set_down(interface);
} else {
// bring it up
status = interface->first_info->interface_up(
@ -564,6 +561,8 @@ interface_protocol_down(net_datalink_protocol *_protocol)
deviceInterface->up_count--;
domain_interface_went_down(protocol->interface);
if (deviceInterface->up_count > 0)
return;

View File

@ -225,6 +225,49 @@ domain_interfaces_link_changed(net_device *device)
}
void
domain_interface_went_down(net_interface *interface)
{
// the domain should be locked here. always check
// all callers to be sure. We get here via
// interface_set_down().
dprintf("domain_interface_went_down(%i, %s)\n",
interface->domain->family, interface->name);
// domain might have been locked by:
// - domain_removed_device_interface() <--- here
// remove_interface_from_domain()
// delete_interface()
// interface_set_down()
// - datalink_control() <--- here
// interface_set_down()
invalidate_routes(interface->domain, interface);
}
void
domain_removed_device_interface(net_device_interface *interface)
{
BenaphoreLocker locker(sDomainLock);
net_domain_private *domain = NULL;
while (true) {
domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
if (domain == NULL)
break;
BenaphoreLocker locker(domain->lock);
net_interface_private *priv = find_interface(domain, interface->name);
if (priv == NULL)
continue;
remove_interface_from_domain(priv);
}
}
status_t
register_domain(int family, const char *name,
struct net_protocol_module_info *module,

View File

@ -16,6 +16,9 @@
#include <util/DoublyLinkedList.h>
struct net_device_interface;
struct net_domain_private : net_domain {
struct list_link link;
@ -34,6 +37,8 @@ status_t list_domain_interfaces(void *buffer, size_t *_bufferSize);
status_t add_interface_to_domain(net_domain *domain, struct ifreq& request);
status_t remove_interface_from_domain(net_interface *interface);
void domain_interfaces_link_changed(net_device *device);
void domain_interface_went_down(net_interface *);
void domain_removed_device_interface(net_device_interface *);
net_domain *get_domain(int family);
status_t register_domain(int family, const char *name,

View File

@ -63,6 +63,16 @@ domain_receive_adapter(void *cookie, net_buffer *buffer)
}
net_device_interface *
grab_device_interface(net_device_interface *interface)
{
if (interface == NULL || atomic_add(&interface->ref_count, 1) == 0)
return NULL;
return interface;
}
// #pragma mark - interfaces
@ -135,7 +145,7 @@ create_interface(net_domain *domain, const char *name, const char *baseName,
interface->type = 0;
interface->mtu = deviceInterface->device->mtu;
interface->metric = 0;
interface->device_interface = deviceInterface;
interface->device_interface = grab_device_interface(deviceInterface);
status_t status = get_domain_datalink_protocols(interface);
if (status < B_OK) {
@ -153,14 +163,33 @@ create_interface(net_domain *domain, const char *name, const char *baseName,
}
void
interface_set_down(net_interface *interface)
{
if ((interface->flags & IFF_UP) == 0)
return;
// TODO: IFF_LINK should belong in device only
interface->flags &= ~(IFF_UP | IFF_LINK);
interface->first_info->interface_down(interface->first_protocol);
}
void
delete_interface(net_interface_private *interface)
{
if ((interface->flags & IFF_UP) != 0) {
// the interface is still up - we need to change that before deleting it
interface->flags &= ~IFF_UP;
down_device_interface(interface->device_interface);
}
// deleting an interface is fairly complex as we need
// to clear all references to it throughout the stack
// this will possibly call (if IFF_UP):
// interface_protocol_down()
// domain_interface_went_down()
// invalidate_routes()
// remove_route()
// update_route_infos()
// get_route_internal()
// down_device_interface() -- if upcount reaches 0
interface_set_down(interface);
put_device_interface(interface->device_interface);
@ -388,9 +417,15 @@ down_device_interface(net_device_interface *interface)
{
net_device *device = interface->device;
dprintf("down_device_interface(%s)\n", interface->name);
device->flags &= ~IFF_UP;
interface->module->down(device);
// TODO: there is a race condition between the previous
// ->down and device->module->receive_data which
// locks us here waiting for the reader_thread
// make sure the reader thread is gone before shutting down the interface
status_t status;
wait_for_thread(interface->reader_thread, &status);
@ -600,7 +635,25 @@ status_t
device_removed(net_device *device)
{
BenaphoreLocker locker(sInterfaceLock);
// TODO: all what this function should do is to clear the IFF_UP flag of the interfaces.
net_device_interface *interface = find_device_interface(device->name);
if (interface == NULL)
return ENODEV;
// Propagate the loss of the device throughout the stack.
// This is very complex, refer to delete_interface() for
// further details.
// this will possibly call:
// remove_interface_from_domain() [domain gets locked]
// delete_interface()
// ... [see delete_interface()]
domain_removed_device_interface(interface);
// TODO: make sure all readers are gone
// make sure all watchers are gone
// remove device interface
return B_OK;
}

View File

@ -69,6 +69,7 @@ status_t create_interface(net_domain *domain, const char *name,
const char *baseName, net_device_interface *deviceInterface,
struct net_interface_private **_interface);
void delete_interface(net_interface_private *interface);
void interface_set_down(net_interface *);
// device interfaces
void get_device_interface_address(net_device_interface *interface,

View File

@ -493,6 +493,28 @@ get_route_information(struct net_domain *_domain, void *value, size_t length)
}
void
invalidate_routes(net_domain *_domain, net_interface *interface)
{
// this function is called with the domain locked
// (see domain_interface_went_down)
net_domain_private *domain = (net_domain_private *)_domain;
dprintf("invalidate_routes(%i, %s)\n", domain->family, interface->name);
RouteList::Iterator iterator = domain->routes.GetIterator();
while (iterator.HasNext()) {
net_route *route = iterator.Next();
// TODO handle refcounting, if the route needs to linger
// for some reason we should set interface or
// something of the sorts that invalidates it's reference
if (route->interface == interface)
remove_route(domain, route);
}
}
struct net_route *
get_route(struct net_domain *_domain, const struct sockaddr *address)
{

View File

@ -39,6 +39,7 @@ status_t remove_route(struct net_domain *domain,
const struct net_route *route);
status_t get_route_information(struct net_domain *domain, void *buffer,
size_t length);
void invalidate_routes(net_domain *, net_interface *);
struct net_route *get_route(struct net_domain *domain,
const struct sockaddr *address);
void put_route(struct net_domain *domain, struct net_route *route);