From b7d1c27b752df3e6c5dfe6a5b789d6cb0c87d0f6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 23 Mar 2012 14:41:53 +0200 Subject: [PATCH] move l3 device tracking to interface core to enforce proper order of address/route removal on device or interface state changes --- device.c | 3 +++ interface-event.c | 4 ++-- interface-ip.c | 6 +++--- interface.c | 57 +++++++++++++++++++++++++++++++++++++++++++++---------- interface.h | 4 +++- proto-shell.c | 15 ++------------- ubus.c | 2 +- 7 files changed, 61 insertions(+), 30 deletions(-) diff --git a/device.c b/device.c index 47b5875..0560a70 100644 --- a/device.c +++ b/device.c @@ -466,6 +466,9 @@ void device_add_user(struct device_user *dep, struct device *dev) if (dep->dev) device_remove_user(dep); + if (!dev) + return; + dep->dev = dev; list_add_tail(&dep->list, &dev->users); if (dep->cb && dev->present) { diff --git a/interface-event.c b/interface-event.c index 4e0773d..5ab6240 100644 --- a/interface-event.c +++ b/interface-event.c @@ -57,8 +57,8 @@ call_hotplug(void) current_ev = current->hotplug_ev; list_del_init(¤t->hotplug_list); - if (current_ev == IFEV_UP && current->l3_dev->dev) - device = current->l3_dev->dev->ifname; + if (current_ev == IFEV_UP && current->l3_dev.dev) + device = current->l3_dev.dev->ifname; D(SYSTEM, "Call hotplug handler for interface '%s' (%s)\n", current->name, device ? device : "none"); run_cmd(current->name, device, current_ev == IFEV_UP); diff --git a/interface-ip.c b/interface-ip.c index 8c46168..bbf2ccf 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -128,7 +128,7 @@ interface_update_proto_addr(struct vlist_tree *tree, ip = container_of(tree, struct interface_ip_settings, addr); iface = ip->iface; - dev = iface->l3_dev->dev; + dev = iface->l3_dev.dev; if (node_new) { a_new = container_of(node_new, struct device_addr, node); @@ -193,7 +193,7 @@ interface_update_proto_route(struct vlist_tree *tree, ip = container_of(tree, struct interface_ip_settings, route); iface = ip->iface; - dev = iface->l3_dev->dev; + dev = iface->l3_dev.dev; route_old = container_of(node_old, struct device_route, node); route_new = container_of(node_new, struct device_route, node); @@ -353,7 +353,7 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) struct device *dev; ip->enabled = enabled; - dev = ip->iface->l3_dev->dev; + dev = ip->iface->l3_dev.dev; if (!dev) return; diff --git a/interface.c b/interface.c index f281a9b..902f55b 100644 --- a/interface.c +++ b/interface.c @@ -94,11 +94,10 @@ interface_event(struct interface *iface, enum interface_event ev) static void interface_flush_state(struct interface *iface) { - interface_ip_flush(&iface->proto_ip); if (iface->main_dev.dev) device_release(&iface->main_dev); - if (iface->l3_dev != &iface->main_dev && iface->l3_dev->dev) - device_release(iface->l3_dev); + if (iface->l3_dev.dev) + device_release(&iface->l3_dev); } static void @@ -191,7 +190,7 @@ interface_claim_device(struct interface *iface) !(iface->proto_handler->flags & PROTO_FLAG_NODEV)) { dev = device_get(iface->ifname, true); if (dev) - device_add_user(&iface->main_dev, dev); + interface_set_main_dev(iface, dev); } if (iface->proto_handler->flags & PROTO_FLAG_INIT_AVAILABLE) interface_set_available(iface, true); @@ -211,8 +210,7 @@ interface_cleanup(struct interface *iface, bool reload) interface_clear_errors(iface); if (iface->main_dev.dev && (!reload || !iface->main_dev.hotplug)) - device_remove_user(&iface->main_dev); - iface->l3_dev = &iface->main_dev; + interface_set_main_dev(iface, NULL); interface_set_proto_state(iface, NULL); } @@ -323,7 +321,6 @@ interface_init(struct interface *iface, const char *name, iface->config_ip.enabled = false; iface->main_dev.cb = interface_cb; - iface->l3_dev = &iface->main_dev; blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blob_data(config), blob_len(config)); @@ -356,6 +353,46 @@ interface_add(struct interface *iface, struct blob_attr *config) vlist_add(&interfaces, &iface->node, iface->name); } +void +interface_set_l3_dev(struct interface *iface, struct device *dev) +{ + bool enabled = iface->config_ip.enabled; + bool claimed = iface->l3_dev.claimed; + + if (iface->l3_dev.dev == dev) + return; + + interface_ip_set_enabled(&iface->config_ip, false); + interface_ip_flush(&iface->proto_ip); + device_add_user(&iface->l3_dev, dev); + + if (dev) { + if (claimed) + device_claim(&iface->l3_dev); + interface_ip_set_enabled(&iface->config_ip, enabled); + } +} + +void +interface_set_main_dev(struct interface *iface, struct device *dev) +{ + bool set_l3 = (iface->main_dev.dev == iface->l3_dev.dev); + bool claimed = iface->l3_dev.claimed; + + if (iface->main_dev.dev == dev) + return; + + device_add_user(&iface->main_dev, dev); + if (set_l3) + interface_set_l3_dev(iface, dev); + + if (claimed) + device_claim(&iface->l3_dev); + + if (!iface->l3_dev.dev) + interface_set_l3_dev(iface, dev); +} + int interface_remove_link(struct interface *iface, struct device *dev) { @@ -392,7 +429,7 @@ interface_add_link(struct interface *iface, struct device *dev) return UBUS_STATUS_NOT_SUPPORTED; } - device_add_user(&iface->main_dev, dev); + interface_set_main_dev(iface, dev); iface->main_dev.hotplug = true; return 0; } @@ -477,8 +514,8 @@ interface_update_complete(struct interface *iface) interface_ip_update_complete(&iface->proto_ip); vlist_for_each_element(&iface->config_ip.route, route, node) { - if (iface->l3_dev->dev) { - system_add_route(iface->l3_dev->dev, route); + if (iface->l3_dev.dev) { + system_add_route(iface->l3_dev.dev, route); route->enabled = true; } } diff --git a/interface.h b/interface.h index f0b26f5..b2ecd23 100644 --- a/interface.h +++ b/interface.h @@ -76,7 +76,7 @@ struct interface { struct device_user main_dev; /* interface that layer 3 communication will go through */ - struct device_user *l3_dev; + struct device_user l3_dev; struct blob_attr *config; @@ -111,6 +111,8 @@ int interface_set_up(struct interface *iface); int interface_set_down(struct interface *iface); void __interface_set_down(struct interface *iface, bool force); +void interface_set_main_dev(struct interface *iface, struct device *dev); +void interface_set_l3_dev(struct interface *iface, struct device *dev); void interface_add_user(struct interface_user *dep, struct interface *iface); void interface_remove_user(struct interface_user *dep); diff --git a/proto-shell.c b/proto-shell.c index 8238c0d..b5d436a 100644 --- a/proto-shell.c +++ b/proto-shell.c @@ -41,8 +41,6 @@ struct proto_shell_state { struct proto_shell_handler *handler; struct blob_attr *config; - struct device_user l3_dev; - struct uloop_timeout teardown_timeout; struct netifd_process script_task; @@ -79,9 +77,6 @@ proto_shell_handler(struct interface_proto_state *proto, if (state->sm == S_TEARDOWN) return 0; - if (state->l3_dev.dev) - device_remove_user(&state->l3_dev); - if (state->script_task.uloop.pending) { if (state->sm != S_SETUP_ABORT) { uloop_timeout_set(&state->teardown_timeout, 1000); @@ -204,8 +199,6 @@ proto_shell_free(struct interface_proto_state *proto) struct proto_shell_state *state; state = container_of(proto, struct proto_shell_state, proto); - if (state->l3_dev.dev) - device_remove_user(&state->l3_dev); netifd_kill_process(&state->script_task); netifd_kill_process(&state->proto_task); free(state->config); @@ -305,9 +298,6 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, if (!iface->main_dev.dev) return UBUS_STATUS_INVALID_ARGUMENT; } else { - if (state->l3_dev.dev) - device_remove_user(&state->l3_dev); - devname = blobmsg_data(tb[NOTIFY_IFNAME]); if (tb[NOTIFY_TUNNEL]) { dev = proto_shell_create_tunnel(devname, @@ -320,9 +310,8 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, return UBUS_STATUS_NOT_FOUND; } - device_add_user(&state->l3_dev, dev); - iface->l3_dev = &state->l3_dev; - device_claim(&state->l3_dev); + interface_set_l3_dev(iface, dev); + device_claim(&iface->l3_dev); } interface_update_start(iface); diff --git a/ubus.c b/ubus.c index 6d79a0a..40c6374 100644 --- a/ubus.c +++ b/ubus.c @@ -303,7 +303,7 @@ netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj, if (iface->state == IFS_UP) { time_t cur = system_get_rtime(); blobmsg_add_u32(&b, "uptime", cur - iface->start_time); - blobmsg_add_string(&b, "l3_device", iface->l3_dev->dev->ifname); + blobmsg_add_string(&b, "l3_device", iface->l3_dev.dev->ifname); } dev = iface->main_dev.dev; -- 2.11.0