Only update resolv.conf if changed (avoid logspam)
[project/netifd.git] / bridge.c
index 035619b..1d02f83 100644 (file)
--- a/bridge.c
+++ b/bridge.c
@@ -1,3 +1,16 @@
+/*
+ * netifd - network interface daemon
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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 <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -71,6 +84,7 @@ struct bridge_state {
        bool active;
        bool force_active;
 
+       struct bridge_member *primary_port;
        struct vlist_tree members;
        int n_present;
 };
@@ -83,6 +97,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 +174,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 +189,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 +283,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 +346,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 +410,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,8 +459,8 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb)
        struct blob_attr *cur;
 
        /* defaults */
-       cfg->stp = true;
-       cfg->forward_delay = 1;
+       cfg->stp = false;
+       cfg->forward_delay = 2;
        cfg->igmp_snoop = true;
 
        if ((cur = tb[BRIDGE_ATTR_STP]))