From 4ed89555c4b5e748ed407f7694b5c9b32eea2e54 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 4 Sep 2011 13:52:56 +0200 Subject: [PATCH] make bridge configuration more dynamic --- bridge.c | 140 ++++++++++++++++++++++++++++-------------------------------- config.c | 39 ++++++++++++++++- device.c | 96 +++++++++++++++++++---------------------- device.h | 19 ++++++++- interface.c | 7 --- interface.h | 2 - 6 files changed, 163 insertions(+), 140 deletions(-) diff --git a/bridge.c b/bridge.c index 24f8069..886fb42 100644 --- 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; @@ -239,48 +276,6 @@ static const struct device_hotplug_ops bridge_ops = { }; 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) { struct bridge_state *bst; @@ -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; -} diff --git a/config.c b/config.c index 1e465c5..7ba6875 100644 --- 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); } } diff --git a/device.c b/device.c index 9d2ec43..bc870c2 100644 --- a/device.c +++ b/device.c @@ -13,18 +13,10 @@ 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; } diff --git a/device.h b/device.h index 733763f..e11df1f 100644 --- 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 diff --git a/interface.c b/interface.c index 3b3e2e3..2b66fb9 100644 --- a/interface.c +++ b/interface.c @@ -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) diff --git a/interface.h b/interface.h index a63997a..9090164 100644 --- a/interface.h +++ b/interface.h @@ -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); -- 2.11.0