The kernel will refuse to add a vlan device to a bridge when the base
device of that vlan is already a member. This can happen on config
reload.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
bool active;
bool force_active;
bool active;
bool force_active;
+ struct uloop_timeout retry;
struct bridge_member *primary_port;
struct vlist_tree members;
int n_present;
struct bridge_member *primary_port;
struct vlist_tree members;
int n_present;
};
struct bridge_member {
};
struct bridge_member {
bm->present = false;
bst->n_present--;
return ret;
bm->present = false;
bst->n_present--;
return ret;
+bridge_check_retry(struct bridge_state *bst)
+{
+ if (!bst->n_failed)
+ return;
+
+ uloop_timeout_set(&bst->retry, 100);
+}
+
+static void
bridge_member_cb(struct device_user *dev, enum device_event ev)
{
struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
bridge_member_cb(struct device_user *dev, enum device_event ev)
{
struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
vlist_for_each_element(&bst->members, bm, node)
bridge_enable_member(bm);
vlist_for_each_element(&bst->members, bm, node)
bridge_enable_member(bm);
+ bridge_check_retry(bst);
if (!bst->force_active && !bst->n_present) {
/* initialization of all member interfaces failed */
if (!bst->force_active && !bst->n_present) {
/* initialization of all member interfaces failed */
device_set_present(&bst->dev, true);
}
device_set_present(&bst->dev, true);
}
vlist_update(&bst->members);
if (bst->ifnames) {
blobmsg_for_each_attr(cur, bst->ifnames, rem) {
vlist_update(&bst->members);
if (bst->ifnames) {
blobmsg_for_each_attr(cur, bst->ifnames, rem) {
}
}
vlist_flush(&bst->members);
}
}
vlist_flush(&bst->members);
+ bridge_check_retry(bst);
+static void
+bridge_retry_members(struct uloop_timeout *timeout)
+{
+ struct bridge_state *bst = container_of(timeout, struct bridge_state, retry);
+ struct bridge_member *bm;
+
+ bst->n_failed = 0;
+ vlist_for_each_element(&bst->members, bm, node) {
+ if (bm->present)
+ continue;
+
+ if (!bm->dev.dev->present)
+ continue;
+
+ bm->present = true;
+ bridge_enable_member(bm);
+ }
+}
+
static struct device *
bridge_create(const char *name, struct blob_attr *attr)
{
static struct device *
bridge_create(const char *name, struct blob_attr *attr)
{
dev = &bst->dev;
device_init(dev, &bridge_device_type, name);
dev->config_pending = true;
dev = &bst->dev;
device_init(dev, &bridge_device_type, name);
dev->config_pending = true;
+ bst->retry.cb = bridge_retry_members;
bst->set_state = dev->set_state;
dev->set_state = bridge_set_state;
bst->set_state = dev->set_state;
dev->set_state = bridge_set_state;