X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=bridge.c;h=7409a5079bc77264d9385987545b108500558410;hp=46967c885e071cfb7c469dc6919f30caf3ae27ea;hb=587655b45085fcfc9c575792640c21c6ffb24f42;hpb=e472b121daaef2efc3301445207e4c9ad69b06ae;ds=sidebyside diff --git a/bridge.c b/bridge.c index 46967c8..7409a50 100644 --- a/bridge.c +++ b/bridge.c @@ -1,3 +1,16 @@ +/* + * netifd - network interface daemon + * Copyright (C) 2012 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #include #include #include @@ -13,6 +26,7 @@ enum { BRIDGE_ATTR_IFNAME, BRIDGE_ATTR_STP, BRIDGE_ATTR_FORWARD_DELAY, + BRIDGE_ATTR_PRIORITY, BRIDGE_ATTR_IGMP_SNOOP, BRIDGE_ATTR_AGEING_TIME, BRIDGE_ATTR_HELLO_TIME, @@ -24,6 +38,7 @@ static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = { [BRIDGE_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY }, [BRIDGE_ATTR_STP] = { "stp", BLOBMSG_TYPE_BOOL }, [BRIDGE_ATTR_FORWARD_DELAY] = { "forward_delay", BLOBMSG_TYPE_INT32 }, + [BRIDGE_ATTR_PRIORITY] = { "priority", BLOBMSG_TYPE_INT32 }, [BRIDGE_ATTR_AGEING_TIME] = { "ageing_time", BLOBMSG_TYPE_INT32 }, [BRIDGE_ATTR_HELLO_TIME] = { "hello_time", BLOBMSG_TYPE_INT32 }, [BRIDGE_ATTR_MAX_AGE] = { "max_age", BLOBMSG_TYPE_INT32 }, @@ -71,6 +86,7 @@ struct bridge_state { bool active; bool force_active; + struct bridge_member *primary_port; struct vlist_tree members; int n_present; }; @@ -83,6 +99,34 @@ struct bridge_member { char name[]; }; +static void +bridge_reset_primary(struct bridge_state *bst) +{ + struct bridge_member *bm; + + if (!bst->primary_port && + (bst->dev.settings.flags & DEV_OPT_MACADDR)) + return; + + bst->primary_port = NULL; + bst->dev.settings.flags &= ~DEV_OPT_MACADDR; + vlist_for_each_element(&bst->members, bm, node) { + uint8_t *macaddr; + + if (!bm->present) + continue; + + bst->primary_port = bm; + if (bm->dev.dev->settings.flags & DEV_OPT_MACADDR) + macaddr = bm->dev.dev->settings.macaddr; + else + macaddr = bm->dev.dev->orig_settings.macaddr; + memcpy(bst->dev.settings.macaddr, macaddr, 6); + bst->dev.settings.flags |= DEV_OPT_MACADDR; + return; + } +} + static int bridge_disable_member(struct bridge_member *bm) { @@ -132,6 +176,9 @@ bridge_remove_member(struct bridge_member *bm) if (!bm->present) return; + if (bm == bst->primary_port); + bridge_reset_primary(bst); + if (bst->dev.active) bridge_disable_member(bm); @@ -144,6 +191,29 @@ bridge_remove_member(struct bridge_member *bm) } static void +bridge_free_member(struct bridge_member *bm) +{ + struct device *dev = bm->dev.dev; + + bridge_remove_member(bm); + device_remove_user(&bm->dev); + + /* + * When reloading the config and moving a device from one bridge to + * another, the other bridge may have tried to claim this device + * before it was removed here. + * Ensure that claiming the device is retried by toggling its present + * state + */ + if (dev->present) { + device_set_present(dev, false); + device_set_present(dev, true); + } + + free(bm); +} + +static void bridge_member_cb(struct device_user *dev, enum device_event ev) { struct bridge_member *bm = container_of(dev, struct bridge_member, dev); @@ -215,6 +285,7 @@ bridge_set_up(struct bridge_state *bst) return -ENOENT; } + bridge_reset_primary(bst); ret = bst->set_state(&bst->dev, true); if (ret < 0) bridge_set_down(bst); @@ -277,9 +348,7 @@ bridge_member_update(struct vlist_tree *tree, struct vlist_node *node_new, if (node_old) { bm = container_of(node_old, struct bridge_member, node); - bridge_remove_member(bm); - device_remove_user(&bm->dev); - free(bm); + bridge_free_member(bm); } } @@ -343,7 +412,6 @@ bridge_free(struct device *dev) { struct bridge_state *bst; - device_cleanup(dev); bst = container_of(dev, struct bridge_state, dev); vlist_flush_all(&bst->members); free(bst); @@ -393,9 +461,10 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) struct blob_attr *cur; /* defaults */ - cfg->stp = true; + cfg->stp = false; cfg->forward_delay = 2; - cfg->igmp_snoop = true; + cfg->igmp_snoop = false; + cfg->priority = 0x7FFF; if ((cur = tb[BRIDGE_ATTR_STP])) cfg->stp = blobmsg_get_bool(cur); @@ -403,6 +472,9 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) if ((cur = tb[BRIDGE_ATTR_FORWARD_DELAY])) cfg->forward_delay = blobmsg_get_u32(cur); + if ((cur = tb[BRIDGE_ATTR_PRIORITY])) + cfg->priority = blobmsg_get_u32(cur); + if ((cur = tb[BRIDGE_ATTR_IGMP_SNOOP])) cfg->igmp_snoop = blobmsg_get_bool(cur); @@ -497,5 +569,3 @@ bridge_create(const char *name, struct blob_attr *attr) return dev; } - -