make bridge configuration more dynamic
authorFelix Fietkau <nbd@openwrt.org>
Sun, 4 Sep 2011 11:52:56 +0000 (13:52 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 4 Sep 2011 11:52:56 +0000 (13:52 +0200)
bridge.c
config.c
device.c
device.h
interface.c
interface.h

index 24f8069aaebfbac29ba62ec55724b7f52a04e919..886fb420c9f55eec8417da9c0033b02a74695e1f 100644 (file)
--- a/bridge.c
+++ b/bridge.c
@@ -9,6 +9,43 @@
 #include "interface.h"
 #include "system.h"
 
+enum {
+       BRIDGE_ATTR_IFNAME,
+       BRIDGE_ATTR_STP,
+       __BRIDGE_ATTR_MAX
+};
+
+static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = {
+       [BRIDGE_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY },
+       [BRIDGE_ATTR_STP] = { "stp", BLOBMSG_TYPE_BOOL },
+};
+
+static const union config_param_info bridge_attr_info[__BRIDGE_ATTR_MAX] = {
+       [BRIDGE_ATTR_IFNAME] = { .type = BLOBMSG_TYPE_STRING },
+};
+
+static const struct config_param_list bridge_attr_list = {
+       .n_params = __BRIDGE_ATTR_MAX,
+       .params = bridge_attrs,
+       .info = bridge_attr_info,
+
+       .n_next = 1,
+       .next = { &device_attr_list },
+};
+
+static struct device *bridge_create(struct blob_attr *attr);
+static void bridge_free(struct device *dev);
+static void bridge_dump_status(struct device *dev, struct blob_buf *b);
+
+const struct device_type bridge_device_type = {
+       .name = "Bridge",
+       .config_params = &bridge_attr_list,
+
+       .create = bridge_create,
+       .free = bridge_free,
+       .dump_status = bridge_dump_status,
+};
+
 struct bridge_state {
        struct device dev;
        device_state_cb set_state;
@@ -238,48 +275,6 @@ static const struct device_hotplug_ops bridge_ops = {
        .del = bridge_hotplug_del
 };
 
-static void
-bridge_parse_config(struct bridge_state *bst, struct uci_section *s)
-{
-       struct uci_element *e;
-       struct uci_option *o;
-       char buf[IFNAMSIZ + 1];
-       char *p, *end;
-       int len;
-
-       o = uci_lookup_option(uci_ctx, s, "ifname");
-       if (!o)
-               return;
-
-       if (o->type == UCI_TYPE_LIST) {
-               uci_foreach_element(&o->v.list, e)
-                       bridge_add_member(bst, e->name);
-       } else {
-               p = o->v.string;
-               do {
-                       if (!*p)
-                               break;
-
-                       if (*p == ' ')
-                               continue;
-
-                       end = strchr(p, ' ');
-                       if (!end) {
-                               bridge_add_member(bst, p);
-                               break;
-                       }
-
-                       len = end - p;
-                       if (len <= IFNAMSIZ) {
-                               memcpy(buf, p, len);
-                               buf[len] = 0;
-                               bridge_add_member(bst, buf);
-                       }
-                       p = end;
-               } while (p++);
-       }
-}
-
 static void
 bridge_free(struct device *dev)
 {
@@ -310,53 +305,50 @@ bridge_dump_status(struct device *dev, struct blob_buf *b)
        blobmsg_close_array(b, list);
 }
 
-struct device *
-bridge_create(const char *name, struct uci_section *s)
+static struct device *
+bridge_create(struct blob_attr *attr)
 {
-       static const struct device_type bridge_type = {
-               .name = "Bridge",
-               .free = bridge_free,
-               .dump_status = bridge_dump_status,
-       };
+       struct blob_attr *tb_dev[__DEV_ATTR_MAX];
+       struct blob_attr *tb_br[__BRIDGE_ATTR_MAX];
+       struct blob_attr *cur;
        struct bridge_state *bst;
-       struct device *dev;
+       struct device *dev = NULL;
+       const char *name;
+       int rem;
 
-       dev = device_get(name, false);
-       if (dev)
+       blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev,
+               blob_data(attr), blob_len(attr));
+       blobmsg_parse(bridge_attrs, __BRIDGE_ATTR_MAX, tb_br,
+               blob_data(attr), blob_len(attr));
+
+       if (!tb_dev[DEV_ATTR_NAME])
+               return NULL;
+
+       if (!tb_br[BRIDGE_ATTR_IFNAME])
                return NULL;
 
+       name = blobmsg_data(tb_dev[DEV_ATTR_NAME]);
+
        bst = calloc(1, sizeof(*bst));
        if (!bst)
                return NULL;
 
-       device_init(&bst->dev, &bridge_type, name);
+       dev = &bst->dev;
+       device_init(dev, &bridge_device_type, name);
+       device_init_settings(dev, tb_dev);
 
-       bst->set_state = bst->dev.set_state;
-       bst->dev.set_state = bridge_set_state;
+       bst->set_state = dev->set_state;
+       dev->set_state = bridge_set_state;
 
-       bst->dev.hotplug_ops = &bridge_ops;
+       dev->hotplug_ops = &bridge_ops;
 
        INIT_LIST_HEAD(&bst->members);
 
-       if (s)
-               bridge_parse_config(bst, s);
+       blobmsg_for_each_attr(cur, tb_br[BRIDGE_ATTR_IFNAME], rem) {
+               bridge_add_member(bst, blobmsg_data(cur));
+       }
 
-       return &bst->dev;
+       return dev;
 }
 
-int
-interface_attach_bridge(struct interface *iface, struct uci_section *s)
-{
-       struct device *dev;
-       char brname[IFNAMSIZ];
-
-       snprintf(brname, IFNAMSIZ - 1, "br-%s", iface->name);
-       brname[IFNAMSIZ - 1] = 0;
 
-       dev = bridge_create(brname, s);
-       if (!dev)
-               return -1;
-
-       device_add_user(&iface->main_dev, dev);
-       return 0;
-}
index 1e465c5be0702f8d601d44c85c7747a056069124..7ba687517618016b72fc13e17687d05ba7e06461 100644 (file)
--- a/config.c
+++ b/config.c
@@ -117,12 +117,39 @@ static void uci_to_blob(struct blob_buf *b, struct uci_section *s,
                uci_to_blob(b, s, p->next[i]);
 }
 
+static int
+config_parse_bridge_interface(struct uci_section *s)
+{
+       char *name;
+
+       name = alloca(strlen(s->e.name) + 4);
+       sprintf(name, "br-%s", s->e.name);
+       blobmsg_add_string(&b, "name", name);
+
+       uci_to_blob(&b, s, bridge_device_type.config_params);
+       if (!bridge_device_type.create(b.head)) {
+               DPRINTF("Failed to create bridge for interface '%s'\n", s->e.name);
+               return -EINVAL;
+       }
+
+       blob_buf_init(&b, 0);
+       blobmsg_add_string(&b, "ifname", name);
+       return 0;
+}
+
 static void
 config_parse_interface(struct uci_section *s)
 {
+       const char *type;
        DPRINTF("Create interface '%s'\n", s->e.name);
 
        blob_buf_init(&b, 0);
+
+       type = uci_lookup_option_string(uci_ctx, s, "type");
+       if (type && !strcmp(type, "bridge"))
+               if (config_parse_bridge_interface(s))
+                       return;
+
        uci_to_blob(&b, s, &interface_attr_list);
        interface_alloc(s->e.name, s, b.head);
 }
@@ -134,13 +161,21 @@ config_init_devices(void)
 
        uci_foreach_element(&uci_network->sections, e) {
                struct uci_section *s = uci_to_section(e);
+               const struct device_type *devtype;
+               const char *type;
 
                if (strcmp(s->type, "device") != 0)
                        continue;
 
                blob_buf_init(&b, 0);
-               uci_to_blob(&b, s, &device_attr_list);
-               device_create(b.head, s);
+               type = uci_lookup_option_string(uci_ctx, s, "type");
+               if (type && !strcmp(type, "bridge"))
+                       devtype = &bridge_device_type;
+               else
+                       devtype = &simple_device_type;
+
+               uci_to_blob(&b, s, devtype->config_params);
+               devtype->create(b.head);
        }
 }
 
index 9d2ec439307fdf96ab60849b73bd11074fdb7f58..bc870c24eb74fce34953ee462839bf88f9e4eadb 100644 (file)
--- a/device.c
+++ b/device.c
 
 static struct avl_tree devices;
 
-enum {
-       DEV_ATTR_NAME,
-       DEV_ATTR_TYPE,
-       DEV_ATTR_MTU,
-       DEV_ATTR_MACADDR,
-       DEV_ATTR_TXQUEUELEN,
-       __DEV_ATTR_MAX,
-};
-
 static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
-       [DEV_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
        [DEV_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING },
+       [DEV_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
+       [DEV_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY },
        [DEV_ATTR_MTU] = { "mtu", BLOBMSG_TYPE_INT32 },
        [DEV_ATTR_MACADDR] = { "macaddr", BLOBMSG_TYPE_STRING },
        [DEV_ATTR_TXQUEUELEN] = { "txqueuelen", BLOBMSG_TYPE_INT32 },
@@ -35,7 +27,46 @@ const struct config_param_list device_attr_list = {
        .params = dev_attrs,
 };
 
-static void
+static struct device *
+simple_device_create(struct blob_attr *attr)
+{
+       struct blob_attr *tb[__DEV_ATTR_MAX];
+       struct device *dev = NULL;
+       const char *name;
+
+       blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, blob_data(attr), blob_len(attr));
+       if (!tb[DEV_ATTR_NAME])
+               return NULL;
+
+       name = blobmsg_data(tb[DEV_ATTR_NAME]);
+       if (!name)
+               return NULL;
+
+       dev = device_get(name, true);
+       if (!dev)
+               return NULL;
+
+       device_init_settings(dev, tb);
+
+       return dev;
+}
+
+static void simple_device_free(struct device *dev)
+{
+       device_cleanup(dev);
+       free(dev);
+}
+
+const struct device_type simple_device_type = {
+       .name = "Network device",
+       .config_params = &device_attr_list,
+
+       .create = simple_device_create,
+       .check_state = system_if_check,
+       .free = simple_device_free,
+};
+
+void
 device_init_settings(struct device *dev, struct blob_attr **tb)
 {
        struct blob_attr *cur;
@@ -62,46 +93,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
        }
 }
 
-struct device *
-device_create(struct blob_attr *attr, struct uci_section *s)
-{
-       struct blob_attr *tb[__DEV_ATTR_MAX];
-       struct blob_attr *cur;
-       struct device *dev = NULL;
-       const char *name;
-
-       blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, blob_data(attr), blob_len(attr));
-       if (!tb[DEV_ATTR_NAME])
-               return NULL;
-
-       name = blobmsg_data(tb[DEV_ATTR_NAME]);
-       if ((cur = tb[DEV_ATTR_TYPE])) {
-               if (!strcmp(blobmsg_data(cur), "bridge"))
-                       dev = bridge_create(name, s);
-       } else {
-               dev = device_get(name, true);
-       }
-
-       if (!dev)
-               return NULL;
-
-       device_init_settings(dev, tb);
-
-       return dev;
-}
-
-
 static void __init dev_init(void)
 {
        avl_init(&devices, avl_strcmp, false, NULL);
 }
 
-static void free_simple_device(struct device *dev)
-{
-       device_cleanup(dev);
-       free(dev);
-}
-
 static void device_broadcast_event(struct device *dev, enum device_event ev)
 {
        struct device_user *dep, *tmp;
@@ -199,14 +195,8 @@ int device_init(struct device *dev, const struct device_type *type, const char *
 
 struct device *device_get(const char *name, bool create)
 {
-       static const struct device_type simple_type = {
-               .name = "Device",
-               .check_state = system_if_check,
-               .free = free_simple_device,
-       };
        struct device *dev;
 
-
        if (strchr(name, '.'))
                return get_vlan_device_chain(name, create);
 
@@ -218,7 +208,7 @@ struct device *device_get(const char *name, bool create)
                return NULL;
 
        dev = calloc(1, sizeof(*dev));
-       device_init(dev, &simple_type, name);
+       device_init(dev, &simple_device_type, name);
 
        return dev;
 }
index 733763f753f82619423059df8de95e7e9363cd5f..e11df1f224e8de0b69ceb189fe4b7edd8938188b 100644 (file)
--- a/device.h
+++ b/device.h
@@ -9,9 +9,23 @@ struct device_hotplug_ops;
 
 typedef int (*device_state_cb)(struct device *, bool up);
 
+enum {
+       DEV_ATTR_TYPE,
+       DEV_ATTR_NAME,
+       DEV_ATTR_IFNAME,
+       DEV_ATTR_MTU,
+       DEV_ATTR_MACADDR,
+       DEV_ATTR_TXQUEUELEN,
+       __DEV_ATTR_MAX,
+};
+
 struct device_type {
+       struct list_head list;
        const char *name;
 
+       const struct config_param_list *config_params;
+
+       struct device *(*create)(struct blob_attr *attr);
        void (*dump_status)(struct device *, struct blob_buf *buf);
        int (*check_state)(struct device *);
        void (*free)(struct device *);
@@ -120,8 +134,10 @@ struct device_hotplug_ops {
 };
 
 extern const struct config_param_list device_attr_list;
+extern const struct device_type simple_device_type;
+extern const struct device_type bridge_device_type;
 
-struct device *device_create(struct blob_attr *attr, struct uci_section *s);
+void device_init_settings(struct device *dev, struct blob_attr **tb);
 
 void device_init_virtual(struct device *dev, const struct device_type *type, const char *name);
 int device_init(struct device *iface, const struct device_type *type, const char *ifname);
@@ -144,6 +160,5 @@ device_free(struct device *dev)
 void device_free_all(void);
 
 struct device *get_vlan_device_chain(const char *ifname, bool create);
-struct device *bridge_create(const char *name, struct uci_section *s);
 
 #endif
index 3b3e2e306a88511d972c09c414b7dfc6b01c6f60..2b66fb9267c86a0a200c450a2b124d3cb3b5708e 100644 (file)
@@ -12,7 +12,6 @@
 static LIST_HEAD(interfaces);
 
 enum {
-       IFACE_ATTR_TYPE,
        IFACE_ATTR_IFNAME,
        IFACE_ATTR_PROTO,
        IFACE_ATTR_AUTO,
@@ -24,7 +23,6 @@ static const union config_param_info iface_attr_info[IFACE_ATTR_MAX] = {
 };
 
 static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
-       [IFACE_ATTR_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_ARRAY },
        [IFACE_ATTR_AUTO] = { .name = "auto", .type = BLOBMSG_TYPE_BOOL },
@@ -230,11 +228,6 @@ interface_alloc(const char *name, struct uci_section *s, struct blob_attr *attr)
        blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb,
                      blob_data(attr), blob_len(attr));
 
-       if ((cur = tb[IFACE_ATTR_TYPE])) {
-               if (!strcmp(blobmsg_data(cur), "bridge"))
-                       interface_attach_bridge(iface, s);
-       }
-
        if ((cur = tb[IFACE_ATTR_IFNAME])) {
                dev = device_get(blobmsg_data(cur), true);
                if (dev)
index a63997ad6cb8f30a5b1ac4df5155938720e55aca..9090164080ab008688319a1833c80b6fa2dd172b 100644 (file)
@@ -74,8 +74,6 @@ void interface_remove_link(struct interface *iface, struct device *llif);
 void interface_add_error(struct interface *iface, const char *subsystem,
                         const char *code, const char **data, int n_data);
 
-int interface_attach_bridge(struct interface *iface, struct uci_section *s);
-
 int interface_add_address(struct interface *iface, struct device_addr *addr);
 void interface_del_address(struct interface *iface, struct device_addr *addr);
 void interface_del_ctx_addr(struct interface *iface, void *ctx);