diff options
-rw-r--r-- | package/swconfig/Makefile | 4 | ||||
-rw-r--r-- | package/swconfig/src/Makefile | 2 | ||||
-rw-r--r-- | package/swconfig/src/cli.c | 133 | ||||
-rw-r--r-- | package/swconfig/src/swlib.c | 43 | ||||
-rw-r--r-- | package/swconfig/src/swlib.h | 21 | ||||
-rw-r--r-- | package/swconfig/src/uci.c | 224 |
6 files changed, 363 insertions, 64 deletions
diff --git a/package/swconfig/Makefile b/package/swconfig/Makefile index 058e1e2..e18f556 100644 --- a/package/swconfig/Makefile +++ b/package/swconfig/Makefile @@ -17,7 +17,7 @@ include $(INCLUDE_DIR)/package.mk define Package/swconfig SECTION:=base CATEGORY:=Base system - DEPENDS:=@LINUX_2_6_26||LINUX_2_6_27||LINUX_2_6_28||LINUX_2_6_29 + DEPENDS:=@LINUX_2_6_26||LINUX_2_6_27||LINUX_2_6_28||LINUX_2_6_29 +libuci TITLE:=Switch configuration utility endef @@ -34,7 +34,7 @@ define Build/Compile CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \ $(MAKE) -C $(PKG_BUILD_DIR) \ $(TARGET_CONFIGURE_OPTS) \ - LIBS="$(STAGING_DIR)/usr/lib/libnl.a -lm" + LIBS="-L$(STAGING_DIR)/usr/lib $(STAGING_DIR)/usr/lib/libnl.a -lm -luci" endef define Package/swconfig/install diff --git a/package/swconfig/src/Makefile b/package/swconfig/src/Makefile index 64816af..7b95ca2 100644 --- a/package/swconfig/src/Makefile +++ b/package/swconfig/src/Makefile @@ -8,5 +8,5 @@ all: swconfig %.o: %.c $(CC) $(CFLAGS) -c -o $@ $^ -swconfig: cli.o swlib.o +swconfig: cli.o swlib.o uci.o $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) diff --git a/package/swconfig/src/cli.c b/package/swconfig/src/cli.c index c6035e5..cf3a519 100644 --- a/package/swconfig/src/cli.c +++ b/package/swconfig/src/cli.c @@ -22,6 +22,7 @@ #include <getopt.h> #include <sys/types.h> #include <sys/socket.h> +#include <uci.h> #include <linux/types.h> #include <linux/netlink.h> @@ -32,10 +33,14 @@ #include <linux/switch.h> #include "swlib.h" -#define GET 1 -#define SET 2 +enum { + GET, + SET, + LOAD +}; -void print_attrs(struct switch_attr *attr) +static void +print_attrs(const struct switch_attr *attr) { int i = 0; while (attr) { @@ -62,7 +67,8 @@ void print_attrs(struct switch_attr *attr) } } -void list_attributes(struct switch_dev *dev) +static void +list_attributes(struct switch_dev *dev) { printf("Switch %d: %s(%s), ports: %d, vlans: %d\n", dev->id, dev->dev_name, dev->name, dev->ports, dev->vlans); printf(" --switch\n"); @@ -73,10 +79,38 @@ void list_attributes(struct switch_dev *dev) print_attrs(dev->port_ops); } -void print_usage(void) +static void +print_usage(void) { - printf("swconfig dev <dev> [port <port>|vlan <vlan>] (help|set <key> <value>|get <key>)\n"); - exit(0); + printf("swconfig dev <dev> [port <port>|vlan <vlan>] (help|set <key> <value>|get <key>|load <config>)\n"); + exit(1); +} + +static void +swconfig_load_uci(struct switch_dev *dev, const char *name) +{ + struct uci_context *ctx; + struct uci_package *p = NULL; + struct uci_element *e; + int ret = -1; + + ctx = uci_alloc_context(); + if (!ctx) + return; + + uci_load(ctx, name, &p); + if (!p) { + uci_perror(ctx, "Failed to load config file: "); + goto out; + } + + ret = swlib_apply_from_uci(dev, p); + if (ret < 0) + fprintf(stderr, "Failed to apply configuration for switch '%s'\n", dev->dev_name); + +out: + uci_free_context(ctx); + exit(ret); } int main(int argc, char **argv) @@ -109,22 +143,18 @@ int main(int argc, char **argv) for(i = 3; i < argc; i++) { int p; - if(!strcmp(argv[i], "help")) - { + if (!strcmp(argv[i], "help")) { chelp = 1; continue; } - if(i + 1 >= argc) + if( i + 1 >= argc) print_usage(); p = atoi(argv[i + 1]); - if(!strcmp(argv[i], "port")) - { + if (!strcmp(argv[i], "port")) { cport = p; - } else if(!strcmp(argv[i], "vlan")) - { + } else if (!strcmp(argv[i], "vlan")) { cvlan = p; - } else if(!strcmp(argv[i], "set")) - { + } else if (!strcmp(argv[i], "set")) { if(argc <= i + 1) print_usage(); cmd = SET; @@ -134,11 +164,16 @@ int main(int argc, char **argv) else cvalue = NULL; i++; - } else if(!strcmp(argv[i], "get")) - { + } else if (!strcmp(argv[i], "get")) { cmd = GET; ckey = argv[i + 1]; - } else{ + } else if (!strcmp(argv[i], "load")) { + if ((cport >= 0) || (cvlan >= 0)) + print_usage(); + + ckey = argv[i + 1]; + cmd = LOAD; + } else { print_usage(); } i++; @@ -163,17 +198,19 @@ int main(int argc, char **argv) goto out; } - if(cport > -1) - a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_PORT, ckey); - else if(cvlan > -1) - a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, ckey); - else - a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, ckey); + if (cmd != LOAD) { + if(cport > -1) + a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_PORT, ckey); + else if(cvlan > -1) + a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, ckey); + else + a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, ckey); - if(!a) - { - fprintf(stderr, "Unknown attribute \"%s\"\n", ckey); - goto out; + if(!a) + { + fprintf(stderr, "Unknown attribute \"%s\"\n", ckey); + goto out; + } } switch(cmd) @@ -183,38 +220,10 @@ int main(int argc, char **argv) (cvalue == NULL)) print_usage(); - switch(a->type) { - case SWITCH_TYPE_INT: - val.value.i = atoi(cvalue); - break; - case SWITCH_TYPE_STRING: - val.value.s = cvalue; - break; - case SWITCH_TYPE_PORTS: - val.len = 0; - while(cvalue && *cvalue) - { - ports[val.len].flags = 0; - ports[val.len].id = strtol(cvalue, &cvalue, 10); - while(*cvalue && !isspace(*cvalue)) { - if (*cvalue == 't') - ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED; - cvalue++; - } - if (*cvalue) - cvalue++; - val.len++; - } - val.value.ports = ports; - break; - default: - break; - } if(cvlan > -1) - val.port_vlan = cvlan; - if(cport > -1) - val.port_vlan = cport; - if(swlib_set_attr(dev, a, &val) < 0) + cport = cvlan; + + if(swlib_set_attr_string(dev, a, cport, cvalue) < 0) { fprintf(stderr, "failed\n"); retval = -1; @@ -245,6 +254,10 @@ int main(int argc, char **argv) printf("\n"); break; } + break; + case LOAD: + swconfig_load_uci(dev, ckey); + break; } out: diff --git a/package/swconfig/src/swlib.c b/package/swconfig/src/swlib.c index 3fde816..fbc0365 100644 --- a/package/swconfig/src/swlib.c +++ b/package/swconfig/src/swlib.c @@ -343,6 +343,49 @@ swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_v return swlib_call(cmd, NULL, send_attr_val, val); } +int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *a, int port_vlan, const char *str) +{ + struct switch_port *ports; + struct switch_val val; + char *ptr; + + memset(&val, 0, sizeof(val)); + val.port_vlan = port_vlan; + switch(a->type) { + case SWITCH_TYPE_INT: + val.value.i = atoi(str); + break; + case SWITCH_TYPE_STRING: + val.value.s = str; + break; + case SWITCH_TYPE_PORTS: + ports = alloca(sizeof(struct switch_port) * dev->ports); + memset(ports, 0, sizeof(struct switch_port) * dev->ports); + val.len = 0; + ptr = (char *)str; + while(ptr && *ptr) + { + ports[val.len].flags = 0; + ports[val.len].id = strtoul(ptr, &ptr, 10); + while(*ptr && !isspace(*ptr)) { + if (*ptr == 't') + ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED; + ptr++; + } + if (*ptr) + ptr++; + val.len++; + } + val.value.ports = ports; + break; + case SWITCH_TYPE_NOVAL: + break; + default: + return -1; + } + return swlib_set_attr(dev, a, &val); +} + struct attrlist_arg { int id; diff --git a/package/swconfig/src/swlib.h b/package/swconfig/src/swlib.h index e00ff47..b3c6769 100644 --- a/package/swconfig/src/swlib.h +++ b/package/swconfig/src/swlib.h @@ -1,7 +1,7 @@ /* * swlib.h: Switch configuration API (user space part) * - * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2008-2009 Felix Fietkau <nbd@openwrt.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -110,6 +110,7 @@ struct switch_dev; struct switch_attr; struct switch_port; struct switch_val; +struct uci_package; struct switch_dev { int id; @@ -200,6 +201,17 @@ int swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val); /** + * swlib_set_attr_string: set the value for an attribute with type conversion + * @dev: switch device struct + * @attr: switch attribute struct + * @port_vlan: port or vlan (if applicable) + * @str: string value + * returns 0 on success + */ +int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *attr, + int port_vlan, const char *str); + +/** * swlib_get_attr: get the value for an attribute * @dev: switch device struct * @attr: switch attribute struct @@ -210,4 +222,11 @@ int swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, int swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val); +/** + * swlib_apply_from_uci: set up the switch from a uci configuration + * @dev: switch device struct + * @p: uci package which contains the desired global config + */ +int swlib_apply_from_uci(struct switch_dev *dev, struct uci_package *p); + #endif diff --git a/package/swconfig/src/uci.c b/package/swconfig/src/uci.c new file mode 100644 index 0000000..2df837d --- /dev/null +++ b/package/swconfig/src/uci.c @@ -0,0 +1,224 @@ +/* + * uci.c: UCI binding for the switch configuration utility + * + * Copyright (C) 2009 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 Foundatio. + * + * 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <stdint.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <uci.h> + +#include <linux/types.h> +#include <linux/netlink.h> +#include <linux/genetlink.h> +#include <netlink/netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +#include <linux/switch.h> +#include "swlib.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +struct swlib_setting { + struct switch_attr *attr; + const char *name; + int port_vlan; + const char *val; + struct swlib_setting *next; +}; + +struct swlib_setting early_settings[] = { + { .name = "reset" }, + { .name = "enable_vlan" }, +}; + +static struct swlib_setting *settings; +static struct swlib_setting **head; + +static int +swlib_map_settings(struct switch_dev *dev, int type, int port_vlan, struct uci_section *s) +{ + struct swlib_setting *setting; + struct switch_attr *attr; + struct uci_element *e; + struct uci_option *o; + int i; + + uci_foreach_element(&s->options, e) { + o = uci_to_option(e); + + if (o->type != UCI_TYPE_STRING) + continue; + + if (!strcmp(e->name, "device")) + continue; + + /* map early settings */ + if (type == SWLIB_ATTR_GROUP_GLOBAL) { + int i; + + for (i = 0; i < ARRAY_SIZE(early_settings); i++) { + if (strcmp(e->name, early_settings[i].name) != 0) + continue; + + early_settings[i].val = o->v.string; + goto skip; + } + } + + attr = swlib_lookup_attr(dev, type, e->name); + if (!attr) + continue; + + setting = malloc(sizeof(struct swlib_setting)); + memset(setting, 0, sizeof(struct swlib_setting)); + setting->attr = attr; + setting->port_vlan = port_vlan; + setting->val = o->v.string; + *head = setting; + head = &setting->next; +skip: + continue; + } +} + +int swlib_apply_from_uci(struct switch_dev *dev, struct uci_package *p) +{ + struct switch_attr *attr; + struct uci_context *ctx = p->ctx; + struct uci_element *e; + struct uci_section *s; + struct uci_option *o; + struct switch_val val; + int i; + + settings = NULL; + head = &settings; + + uci_foreach_element(&p->sections, e) { + s = uci_to_section(e); + + if (strcmp(s->type, "switch") != 0) + continue; + + if (strcmp(e->name, dev->dev_name) != 0) + continue; + + goto found; + } + + /* not found */ + return -1; + +found: + /* look up available early options, which need to be taken care + * of in the correct order */ + for (i = 0; i < ARRAY_SIZE(early_settings); i++) { + early_settings[i].attr = swlib_lookup_attr(dev, + SWLIB_ATTR_GROUP_GLOBAL, early_settings[i].name); + } + swlib_map_settings(dev, SWLIB_ATTR_GROUP_GLOBAL, 0, s); + + /* look for port or vlan sections */ + uci_foreach_element(&p->sections, e) { + struct uci_element *os; + s = uci_to_section(e); + + if (!strcmp(s->type, "switch_port")) { + char *devn, *port, *port_err = NULL; + int port_n; + + uci_foreach_element(&s->options, os) { + o = uci_to_option(os); + if (o->type != UCI_TYPE_STRING) + continue; + + if (!strcmp(os->name, "device")) { + devn = o->v.string; + if (strcmp(devn, dev->dev_name) != 0) + devn = NULL; + } else if (!strcmp(os->name, "port")) { + port = o->v.string; + } + } + if (!dev || !port || !port[0]) + continue; + + port_n = strtoul(port, &port_err, 0); + if (port_err && port_err[0]) + continue; + + swlib_map_settings(dev, SWLIB_ATTR_GROUP_PORT, port_n, s); + } else if (!strcmp(s->type, "switch_vlan")) { + char *devn, *vlan, *vlan_err = NULL; + int vlan_n; + + uci_foreach_element(&s->options, os) { + o = uci_to_option(os); + if (o->type != UCI_TYPE_STRING) + continue; + + if (!strcmp(os->name, "device")) { + devn = o->v.string; + if (strcmp(devn, dev->dev_name) != 0) + devn = NULL; + } else if (!strcmp(os->name, "vlan")) { + vlan = o->v.string; + } + } + if (!dev || !vlan || !vlan[0]) + continue; + + vlan_n = strtoul(vlan, &vlan_err, 0); + if (vlan_err && vlan_err[0]) + continue; + + swlib_map_settings(dev, SWLIB_ATTR_GROUP_VLAN, vlan_n, s); + } + } + + for (i = 0; i < ARRAY_SIZE(early_settings); i++) { + struct swlib_setting *st = &early_settings[i]; + if (!st->attr || !st->val) + continue; + swlib_set_attr_string(dev, st->attr, st->port_vlan, st->val); + + } + + while (settings) { + struct swlib_setting *st = settings; + + swlib_set_attr_string(dev, st->attr, st->port_vlan, st->val); + st = st->next; + free(settings); + settings = st; + } + + /* Apply the config */ + attr = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, "apply"); + if (!attr) + return 0; + + memset(&val, 0, sizeof(val)); + swlib_set_attr(dev, attr, &val); + + return 0; +} |