diff options
author | Thomas Graf <tgr@lsx.localdomain> | 2008-04-29 23:31:30 +0200 |
---|---|---|
committer | Thomas Graf <tgr@lsx.localdomain> | 2008-04-29 23:31:30 +0200 |
commit | 535e83162249ed6274ba46bc72d8cc683ba20e17 (patch) | |
tree | fa3b60b4116668b86d23c11b695ff371d771b997 /src | |
parent | 8ac78f1552fa6b6340776513c8a7c36f7b72e498 (diff) | |
download | libnl-535e83162249ed6274ba46bc72d8cc683ba20e17.tar.gz |
Big routing code rework (API/ABI BREAK!)
Adds all missing routing attributes and brings the routing
related code to a working state. In the process the API
was broken several times with the justification that nobody
is using this code yet.
The changes include new example code which is also a prototype
for how plain CLI tools could look like to control routes.
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 4 | ||||
-rw-r--r-- | src/Makefile | 13 | ||||
-rw-r--r-- | src/f_route.c | 81 | ||||
-rw-r--r-- | src/nl-route-add.c | 116 | ||||
-rw-r--r-- | src/nl-route-del.c | 76 | ||||
-rw-r--r-- | src/nl-route-delete.c | 113 | ||||
-rw-r--r-- | src/nl-route-dump.c | 81 | ||||
-rw-r--r-- | src/nl-route-list.c | 118 | ||||
-rw-r--r-- | src/route-utils.c | 237 | ||||
-rw-r--r-- | src/route-utils.h | 30 | ||||
-rw-r--r-- | src/utils.c | 70 | ||||
-rw-r--r-- | src/utils.h | 2 |
12 files changed, 636 insertions, 305 deletions
diff --git a/src/.gitignore b/src/.gitignore index 11fe5ab..8d71209 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -23,8 +23,8 @@ nl-qdisc-add nl-qdisc-delete nl-qdisc-dump nl-route-add -nl-route-del -nl-route-dump +nl-route-delete +nl-route-list nl-route-get nl-rule-dump nl-tctree-dump diff --git a/src/Makefile b/src/Makefile index ddbe29a..0f1e14e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,36 +6,37 @@ # License as published by the Free Software Foundation version 2.1 # of the License. # -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> +# Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> # ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),) include ../Makefile.opts endif -LDFLAGS += -L../lib -lnl utils.o +LDFLAGS += -L../lib -lnl CIN := $(wildcard nl-*.c) $(wildcard genl-*.c) $(wildcard nf-*.c) TOOLS := $(CIN:%.c=%) all: $(TOOLS) $(TOOLS): utils.o +nl-route-add nl-route-delete nl-route-list: route-utils.o nl-%: nl-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) genl-%: genl-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) nf-%: nf-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) clean: @echo " CLEAN src"; \ - rm -f $(TOOLS) utils.o + rm -f $(TOOLS) *.o distclean: clean diff --git a/src/f_route.c b/src/f_route.c deleted file mode 100644 index 581ff65..0000000 --- a/src/f_route.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * src/f_route.c Routes Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -static void get_filter(struct rtnl_route *r, int ac, char **av, int idx, - struct nl_cache *cache, struct nl_cache *link_cache) -{ - while (ac > idx) { - if (!strcasecmp(av[idx], "src")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_pref_src(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "dst")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_dst(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "via")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_gateway(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "from")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_src(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "tos")) { - if (ac > ++idx) - rtnl_route_set_tos(r, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "prio")) { - if (ac > ++idx) - rtnl_route_set_prio(r, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "scope")) { - if (ac > ++idx) - rtnl_route_set_scope(r, rtnl_str2scope(av[idx++])); - } else if (!strcasecmp(av[idx], "dev")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(link_cache, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_route_set_oif(r, ifindex); - } - } else if (!strcasecmp(av[idx], "table")) { - if (ac > ++idx) - rtnl_route_set_table(r, strtoul(av[idx++], NULL, 0)); - } else { - fprintf(stderr, "What is '%s'?\n", av[idx]); - exit(1); - } - } - - return; - -err_notfound: - fprintf(stderr, "Unable to find device \"%s\"\n", av[idx-1]); - exit(1); -err: - fprintf(stderr, "%s\n", nl_geterror()); - exit(1); -} diff --git a/src/nl-route-add.c b/src/nl-route-add.c index 2686397..eb63a22 100644 --- a/src/nl-route-add.c +++ b/src/nl-route-add.c @@ -1,76 +1,124 @@ /* - * src/nl-route-dump.c Dump route attributes + * src/nl-route-add.c Route addition utility * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include "route-utils.h" + +static struct nl_cache *link_cache, *route_cache; static void print_usage(void) { printf( - "Usage: nl-route-add [<filter>]\n"); + "Usage: nl-route-add [OPTION]... --dst=ADDR --nh=NEXTHOP [--nh=...]\n" + " nl-route-add [OPTION]... ADDR NEXTHOP\n" + "\n" + "Required Options\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nh=NEXTHOP nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + "\n" + " e.g. dev=eth0,via=192.168.1.12\n" + "\n" + "Options\n" + " -s, --src=ADDR source prefix\n" + " -i, --iif=DEV incomming interface\n" + " -P, --pref-src=ADDR preferred source address\n" + " -t, --table=TABLE routing table\n" + " -m, --metric=OPTS metrics\n" + " -p, --prio=NUM priotity\n" + " -S, --scope=SCOPE scope\n" + " -x, --proto=PROTO protocol\n" + " -T, --type=TYPE routing type\n" + " -h, --help show this help\n"); exit(1); } -#include "f_route.c" - int main(int argc, char *argv[]) { struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; struct rtnl_route *route; int err = 1; - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; + nltool_connect(nlh, NETLINK_ROUTE); + link_cache = nltool_alloc_link_cache(nlh); + route_cache = nltool_alloc_route_cache(nlh); route = rtnl_route_alloc(); if (!route) goto errout; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "dst", 1, 0, 'd' }, + { "src", 1, 0, 's' }, + { "iif", 1, 0, 'i' }, + { "nh", 1, 0, 'n' }, + { "pref-src", 1, 0, 'P' }, + { "table", 1, 0, 't' }, + { "metric", 1, 0, 'm' }, + { "prio", 1, 0, 'p' }, + { "scope", 1, 0, 'S' }, + { "proto", 1, 0, 'x' }, + { "type", 1, 0, 'T' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; + c = getopt_long(argc, argv, "d:s:i:n:P:t:m:p:S:x:T:h", long_opts, &optidx); + if (c == -1) + break; - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; + switch (c) { + case 'd': parse_dst(route, optarg); break; + case 's': parse_src(route, optarg); break; + case 'i': parse_iif(route, optarg, link_cache); break; + case 'n': parse_nexthop(route, optarg, link_cache); break; + case 'P': parse_pref_src(route, optarg); break; + case 't': parse_table(route, optarg); break; + case 'm': parse_metric(route, optarg); break; + case 'p': parse_prio(route, optarg); break; + case 'S': parse_scope(route, optarg); break; + case 'x': parse_protocol(route, optarg); break; + case 'T': parse_type(route, optarg); break; + case 'h': print_usage(); break; + } + } - get_filter(route, argc, argv, 1, route_cache, link_cache); + while (optind < argc) { + if (!rtnl_route_get_dst(route)) { + parse_dst(route, argv[optind++]); + continue; + } + + /* This must all be nexthop configuration */ + } if (rtnl_route_add(nlh, route, 0) < 0) { - fprintf(stderr, "rtnl_route_add failed: %s\n", - nl_geterror()); - goto errout_route_cache; + fprintf(stderr, "rtnl_route_add failed: %s\n", nl_geterror()); + goto errout_free; } err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); errout_free: rtnl_route_put(route); errout: + nl_cache_free(route_cache); + nl_cache_free(link_cache); + nl_close(nlh); nl_handle_destroy(nlh); + return err; } diff --git a/src/nl-route-del.c b/src/nl-route-del.c deleted file mode 100644 index 9d912e1..0000000 --- a/src/nl-route-del.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * src/nl-route-del.c Delete Routes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-route-del [<filter>]\n"); - exit(1); -} - -#include "f_route.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; - struct rtnl_route *route; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - route = rtnl_route_alloc(); - if (!route) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; - - get_filter(route, argc, argv, 1, route_cache, link_cache); - - if (rtnl_route_del(nlh, route, 0) < 0) { - fprintf(stderr, "rtnl_route_del failed: %s\n", - nl_geterror()); - goto errout_route_cache; - } - - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-route-delete.c b/src/nl-route-delete.c new file mode 100644 index 0000000..1c97817 --- /dev/null +++ b/src/nl-route-delete.c @@ -0,0 +1,113 @@ +/* + * src/nl-route-delete.c Delete Routes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + */ + +#include "route-utils.h" + +static void print_usage(void) +{ + printf( + "Usage: nl-route-delete [OPTION]...\n" + "\n" + "Options\n" + " -f, --family=FAMILY address family\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nh=NEXTHOP nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -s, --src=ADDR source prefix\n" + " -i, --iif=DEV incomming interface\n" + " -P, --pref-src=ADDR preferred source address\n" + " -t, --table=TABLE routing table\n" + " -m, --metric=OPTS metrics\n" + " -p, --prio=NUM priotity\n" + " -S, --scope=SCOPE scope\n" + " -x, --proto=PROTO protocol\n" + " -T, --type=TYPE routing type\n" + " -D, --dumptype=TYPE { brief | detailed | stats | env }\n" + " -h, --help show this help\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct nl_handle *nlh; + struct nl_cache *link_cache, *route_cache; + struct rtnl_route *route; + int err = 1; + + nlh = nltool_alloc_handle(); + nltool_connect(nlh, NETLINK_ROUTE); + link_cache = nltool_alloc_link_cache(nlh); + route_cache = nltool_alloc_route_cache(nlh); + + route = rtnl_route_alloc(); + if (!route) + goto errout; + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "family", 1, 0, 'f' }, + { "dst", 1, 0, 'd' }, + { "src", 1, 0, 's' }, + { "iif", 1, 0, 'i' }, + { "nh", 1, 0, 'n' }, + { "pref-src", 1, 0, 'P' }, + { "table", 1, 0, 't' }, + { "metric", 1, 0, 'm' }, + { "prio", 1, 0, 'p' }, + { "scope", 1, 0, 'S' }, + { "proto", 1, 0, 'x' }, + { "type", 1, 0, 'T' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:d:s:i:n:P:t:m:p:S:x:T:h", + long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': parse_family(route, optarg); break; + case 'd': parse_dst(route, optarg); break; + case 's': parse_src(route, optarg); break; + case 'i': parse_iif(route, optarg, link_cache); break; + case 'n': parse_nexthop(route, optarg, link_cache); break; + case 'P': parse_pref_src(route, optarg); break; + case 't': parse_table(route, optarg); break; + case 'm': parse_metric(route, optarg); break; + case 'p': parse_prio(route, optarg); break; + case 'S': parse_scope(route, optarg); break; + case 'x': parse_protocol(route, optarg); break; + case 'T': parse_type(route, optarg); break; + case 'h': print_usage(); break; + } + } + + if ((err = rtnl_route_delete(nlh, route, 0)) < 0) + fatal(err, "rtnl_route_del failed: %s\n", nl_geterror()); + + err = 0; + + rtnl_route_put(route); +errout: + nl_cache_free(route_cache); + nl_cache_free(link_cache); + nl_close(nlh); + nl_handle_destroy(nlh); + + return err; +} diff --git a/src/nl-route-dump.c b/src/nl-route-dump.c deleted file mode 100644 index aed9bd2..0000000 --- a/src/nl-route-dump.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * src/nl-route-dump.c Dump route attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-route-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n"); - exit(1); -} - -#include "f_route.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; - struct rtnl_route *route; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - route = rtnl_route_alloc(); - if (!route) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_route_cache; - - get_filter(route, argc, argv, 2, route_cache, link_cache); - - nl_cache_dump_filter(route_cache, ¶ms, (struct nl_object *) route); - - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-route-list.c b/src/nl-route-list.c new file mode 100644 index 0000000..4f70ff7 --- /dev/null +++ b/src/nl-route-list.c @@ -0,0 +1,118 @@ +/* + * src/nl-route-list.c List route attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + */ + +#include "route-utils.h" + +static void print_usage(void) +{ + printf( + "Usage: nl-route-list [OPTION]...\n" + "\n" + "Options\n" + " -f, --family=FAMILY address family\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nh=NEXTHOP nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -s, --src=ADDR source prefix\n" + " -i, --iif=DEV incomming interface\n" + " -P, --pref-src=ADDR preferred source address\n" + " -t, --table=TABLE routing table\n" + " -m, --metric=OPTS metrics\n" + " -p, --prio=NUM priotity\n" + " -S, --scope=SCOPE scope\n" + " -x, --proto=PROTO protocol\n" + " -T, --type=TYPE routing type\n" + " -D, --dumptype=TYPE { brief | detailed | stats | env }\n" + " -h, --help show this help\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct nl_handle *nlh; + struct nl_cache *link_cache, *route_cache; + struct rtnl_route *route; + struct nl_dump_params params = { + .dp_fd = stdout, + .dp_type = NL_DUMP_BRIEF + }; + int err = 1; + + nlh = nltool_alloc_handle(); + nltool_connect(nlh, NETLINK_ROUTE); + link_cache = nltool_alloc_link_cache(nlh); + route_cache = nltool_alloc_route_cache(nlh); + + route = rtnl_route_alloc(); + if (!route) + goto errout; + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "family", 1, 0, 'f' }, + { "dst", 1, 0, 'd' }, + { "src", 1, 0, 's' }, + { "iif", 1, 0, 'i' }, + { "nh", 1, 0, 'n' }, + { "pref-src", 1, 0, 'P' }, + { "table", 1, 0, 't' }, + { "metric", 1, 0, 'm' }, + { "prio", 1, 0, 'p' }, + { "scope", 1, 0, 'S' }, + { "proto", 1, 0, 'x' }, + { "type", 1, 0, 'T' }, + { "dumptype", 1, 0, 'D' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:d:s:i:n:P:t:m:p:S:x:T:D:h", + long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': parse_family(route, optarg); break; + case 'd': parse_dst(route, optarg); break; + case 's': parse_src(route, optarg); break; + case 'i': parse_iif(route, optarg, link_cache); break; + case 'n': parse_nexthop(route, optarg, link_cache); break; + case 'P': parse_pref_src(route, optarg); break; + case 't': parse_table(route, optarg); break; + case 'm': parse_metric(route, optarg); break; + case 'p': parse_prio(route, optarg); break; + case 'S': parse_scope(route, optarg); break; + case 'x': parse_protocol(route, optarg); break; + case 'T': parse_type(route, optarg); break; + case 'D': params.dp_type = nltool_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + } + } + + nl_cache_dump_filter(route_cache, ¶ms, OBJ_CAST(route)); + + err = 0; + + rtnl_route_put(route); +errout: + nl_cache_free(route_cache); + nl_cache_free(link_cache); + nl_close(nlh); + nl_handle_destroy(nlh); + + return err; +} diff --git a/src/route-utils.c b/src/route-utils.c new file mode 100644 index 0000000..61bc9cd --- /dev/null +++ b/src/route-utils.c @@ -0,0 +1,237 @@ +/* + * src/route-utils.c Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#include "route-utils.h" + +void parse_family(struct rtnl_route *route, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) != AF_UNSPEC) + rtnl_route_set_family(route, family); +} + +void parse_dst(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + if ((err = rtnl_route_set_dst(route, addr)) < 0) + fatal(err, nl_geterror()); + + nl_addr_put(addr); +} + +void parse_src(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + if ((err = rtnl_route_set_src(route, addr)) < 0) + fatal(err, nl_geterror()); + + nl_addr_put(addr); +} + +void parse_pref_src(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + if ((err = rtnl_route_set_pref_src(route, addr)) < 0) + fatal(err, nl_geterror()); + + nl_addr_put(addr); +} + +void parse_metric(struct rtnl_route *route, char *subopts) +{ + /* strict equal order to RTAX_* */ + static char *const tokens[] = { + "unspec", + "lock", + "mtu", + "window", + "rtt", + "rttvar", + "sstresh", + "cwnd", + "advmss", + "reordering", + "hoplimit", + "initcwnd", + "features", + NULL, + }; + unsigned long lval; + char *arg, *endptr; + + while (*subopts != '\0') { + int ret = getsubopt(&subopts, tokens, &arg); + if (ret == -1) + fatal(EINVAL, "Unknown metric token \"%s\"", arg); + + if (ret == 0) + fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]); + + if (arg == NULL) + fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]); + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]); + + if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0) + fatal(ret, nl_geterror()); + } +} + +void parse_nexthop(struct rtnl_route *route, char *subopts, + struct nl_cache *link_cache) +{ + enum { + NH_DEV, + NH_VIA, + NH_WEIGHT, + }; + static char *const tokens[] = { + "dev", + "via", + "weight", + NULL, + }; + struct rtnl_nexthop *nh; + unsigned long lval; + struct nl_addr *addr; + int ival; + char *arg, *endptr; + + if (!(nh = rtnl_route_nh_alloc())) + fatal(ENOMEM, "Out of memory"); + + while (*subopts != '\0') { + int ret = getsubopt(&subopts, tokens, &arg); + if (ret == -1) + fatal(EINVAL, "Unknown nexthop token \"%s\"", arg); + + switch (ret) { + case NH_DEV: + ival = rtnl_link_name2i(link_cache, arg); + if (ival == RTNL_LINK_NOT_FOUND) + fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_route_nh_set_ifindex(nh, ival); + break; + + case NH_VIA: + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + rtnl_route_nh_set_gateway(nh, addr); + nl_addr_put(addr); + break; + + case NH_WEIGHT: + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + fatal(EINVAL, "Invalid weight \"%s\", not numeric", arg); + rtnl_route_nh_set_weight(nh, lval); + break; + } + } + + rtnl_route_add_nexthop(route, nh); +} + +void parse_table(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) { + if ((lval = rtnl_route_str2table(arg)) < 0) + fatal(EINVAL, "Unknown table name \"%s\"", arg); + } + + rtnl_route_set_table(route, lval); +} + +void parse_prio(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + fatal(EINVAL, "Invalid priority value, not numeric"); + rtnl_route_set_priority(route, lval); +} + +void parse_scope(struct rtnl_route *route, char *arg) +{ + int ival; + + if ((ival = rtnl_str2scope(arg)) < 0) + fatal(EINVAL, "Unknown routing scope \"%s\"", arg); + + rtnl_route_set_scope(route, ival); +} + +void parse_protocol(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) { + if ((lval = rtnl_route_str2proto(arg)) < 0) + fatal(EINVAL, "Unknown routing protocol name \"%s\"", + arg); + } + + rtnl_route_set_protocol(route, lval); +} + +void parse_type(struct rtnl_route *route, char *arg) +{ + int ival; + + if ((ival = nl_str2rtntype(arg)) < 0) + fatal(EINVAL, "Unknown routing type \"%s\"", arg); + + if ((ival = rtnl_route_set_type(route, ival)) < 0) + fatal(ival, nl_geterror()); +} + +void parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache) +{ + int ival; + + ival = rtnl_link_name2i(link_cache, arg); + if (ival == RTNL_LINK_NOT_FOUND) + fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_route_set_iif(route, ival); +} diff --git a/src/route-utils.h b/src/route-utils.h new file mode 100644 index 0000000..873835c --- /dev/null +++ b/src/route-utils.h @@ -0,0 +1,30 @@ +/* + * src/route-utils.h Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __ROUTE_UTILS_H_ +#define __ROUTE_UTILS_H_ + +#include "utils.h" + +extern void parse_family(struct rtnl_route *, char *); +extern void parse_dst(struct rtnl_route *, char *); +extern void parse_src(struct rtnl_route *, char *); +extern void parse_pref_src(struct rtnl_route *, char *); +extern void parse_metric(struct rtnl_route *, char *); +extern void parse_nexthop(struct rtnl_route *, char *, struct nl_cache *); +extern void parse_table(struct rtnl_route *, char *); +extern void parse_prio(struct rtnl_route *, char *); +extern void parse_scope(struct rtnl_route *, char *); +extern void parse_protocol(struct rtnl_route *, char *); +extern void parse_type(struct rtnl_route *, char *); +extern void parse_iif(struct rtnl_route *, char *, struct nl_cache *); + +#endif diff --git a/src/utils.c b/src/utils.c index b43758a..4695760 100644 --- a/src/utils.c +++ b/src/utils.c @@ -13,6 +13,21 @@ #include <stdlib.h> +void fatal(int err, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "Error: "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + exit(err); +} + int nltool_init(int argc, char *argv[]) { return 0; @@ -24,7 +39,7 @@ int nltool_connect(struct nl_handle *nlh, int protocol) err = nl_connect(nlh, protocol); if (err < 0) - fprintf(stderr, "Unable to connect netlink socket%s\n", + fatal(err, "Unable to connect netlink socket: %s", nl_geterror()); return err; @@ -32,7 +47,12 @@ int nltool_connect(struct nl_handle *nlh, int protocol) struct nl_handle *nltool_alloc_handle(void) { - return nl_handle_alloc(); + struct nl_handle *sock; + + if (!(sock = nl_handle_alloc())) + fatal(ENOBUFS, "Unable to allocate netlink socket"); + + return sock; } struct nl_addr *nltool_addr_parse(const char *str) @@ -71,10 +91,10 @@ struct nl_cache *nltool_alloc_link_cache(struct nl_handle *nlh) cache = rtnl_link_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve link cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve link cache: %s", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -85,10 +105,10 @@ struct nl_cache *nltool_alloc_addr_cache(struct nl_handle *nlh) cache = rtnl_addr_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve address cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve address cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -99,10 +119,10 @@ struct nl_cache *nltool_alloc_neigh_cache(struct nl_handle *nlh) cache = rtnl_neigh_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve neighbour cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve neighbour cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -113,8 +133,8 @@ struct nl_cache *nltool_alloc_neightbl_cache(struct nl_handle *nlh) cache = rtnl_neightbl_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve neighbour table " - "cache: %s\n", nl_geterror()); + fatal(nl_get_errno(), "Unable to retrieve neighbour table " + "cache: %s", nl_geterror()); else nl_cache_mngt_provide(cache); @@ -127,10 +147,10 @@ struct nl_cache *nltool_alloc_route_cache(struct nl_handle *nlh) cache = rtnl_route_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve route cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve route cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -141,10 +161,10 @@ struct nl_cache *nltool_alloc_rule_cache(struct nl_handle *nlh) cache = rtnl_rule_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve rule cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve rule cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -155,10 +175,10 @@ struct nl_cache *nltool_alloc_qdisc_cache(struct nl_handle *nlh) cache = rtnl_qdisc_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve qdisc cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve qdisc cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -169,10 +189,10 @@ struct nl_cache *nltool_alloc_genl_family_cache(struct nl_handle *nlh) cache = genl_ctrl_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve genl family cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve genl family cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } diff --git a/src/utils.h b/src/utils.h index d738ce7..7d85e15 100644 --- a/src/utils.h +++ b/src/utils.h @@ -43,6 +43,8 @@ #include <netlink/genl/mngt.h> #include <netlink/netfilter/ct.h> +extern void fatal(int err, const char *fmt, ...); + extern int nltool_init(int argc, char *argv[]); extern int nltool_connect(struct nl_handle *nlh, int protocol); extern struct nl_addr *nltool_addr_parse(const char *str); |