diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2004-01-21 23:45:19 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2004-01-21 23:45:19 +0000 |
commit | 5b2c6c8403760622408244c7ab09fe3be78a2a80 (patch) | |
tree | c2a34ed327f917f389f610dd4a67e5b5a7d4c805 | |
parent | ebb2ffc8e85899bbaee09799b6cdce3d0b4a4b6a (diff) |
new parser.
completely table driven and not wired into the action code like the
previous parser...
i wanted to do this for some time, and now it was just due.
ok claudio@
-rw-r--r-- | usr.sbin/bgpctl/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/bgpctl/bgpctl.c | 186 | ||||
-rw-r--r-- | usr.sbin/bgpctl/parser.c | 253 | ||||
-rw-r--r-- | usr.sbin/bgpctl/parser.h | 47 |
4 files changed, 324 insertions, 168 deletions
diff --git a/usr.sbin/bgpctl/Makefile b/usr.sbin/bgpctl/Makefile index 8a4e9f014f0..a9856469cc6 100644 --- a/usr.sbin/bgpctl/Makefile +++ b/usr.sbin/bgpctl/Makefile @@ -1,15 +1,15 @@ -# $OpenBSD: Makefile,v 1.1 2004/01/02 02:22:52 henning Exp $ +# $OpenBSD: Makefile,v 1.2 2004/01/21 23:45:18 henning Exp $ .PATH: ${.CURDIR}/../bgpd/ PROG= bgpctl -SRCS= bgpctl.c buffer.c imsg.c log.c +SRCS= bgpctl.c parser.c buffer.c imsg.c log.c CFLAGS+= -Wall CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CLFAGS+= -Wmissing-declarations -Wredundant-decls CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+= -Wsign-compare -CFLAGS+= -I${.CURDIR}/../bgpd/ +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../bgpd MAN= bgpctl.8 .include <bsd.prog.mk> diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c index 7601e1ba56d..794fd72788d 100644 --- a/usr.sbin/bgpctl/bgpctl.c +++ b/usr.sbin/bgpctl/bgpctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpctl.c,v 1.32 2004/01/20 13:11:39 henning Exp $ */ +/* $OpenBSD: bgpctl.c,v 1.33 2004/01/21 23:45:18 henning Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -31,68 +31,16 @@ #include "bgpd.h" #include "session.h" #include "log.h" - -enum actions { - NONE, - SHOW, - SHOW_SUMMARY, - SHOW_NEIGHBOR, - SHOW_NEIGHBOR_TIMERS, - SHOW_FIB, - SHOW_NEXTHOP, - SHOW_INTERFACE, - RELOAD, - FIB, - FIB_COUPLE, - FIB_DECOUPLE, - NEIGHBOR, - NEIGHBOR_UP, - NEIGHBOR_DOWN -}; +#include "parser.h" enum neighbor_views { NV_DEFAULT, NV_TIMERS }; -struct keywords { - const char *keyword; - int value; -}; - -static const struct keywords keywords_main[] = { - { "reload", RELOAD}, - { "show", SHOW}, - { "fib", FIB}, - { "neighbor", NEIGHBOR} -}; - -static const struct keywords keywords_show[] = { - { "neighbor", SHOW_NEIGHBOR}, - { "summary", SHOW_SUMMARY}, - { "fib", SHOW_FIB}, - { "nexthop", SHOW_NEXTHOP}, - { "interfaces", SHOW_INTERFACE} -}; - -static const struct keywords keywords_show_neighbor[] = { - { "timers", SHOW_NEIGHBOR_TIMERS}, - { "messages", SHOW_NEIGHBOR} -}; - -static const struct keywords keywords_fib[] = { - { "couple", FIB_COUPLE}, - { "decouple", FIB_DECOUPLE} -}; - -static const struct keywords keywords_neighbor[] = { - { "up", NEIGHBOR_UP}, - { "down", NEIGHBOR_DOWN} -}; void usage(void); int main(int, char *[]); -int match_keyword(const char *, const struct keywords [], size_t); void show_summary_head(void); int show_summary_msg(struct imsg *); int show_neighbor_msg(struct imsg *, enum neighbor_views); @@ -101,7 +49,6 @@ void print_neighbor_timers(struct peer *); void print_timer(const char *, time_t, u_int); static char *fmt_timeframe(time_t t); static char *fmt_timeframe_core(time_t t); -int parse_addr(const char *, struct bgpd_addr *); void show_fib_head(void); int show_fib_msg(struct imsg *); void show_nexthop_head(void); @@ -120,7 +67,7 @@ usage(void) extern char *__progname; fprintf(stderr, "usage: %s <command> [arg [...]]\n", __progname); - exit (1); + exit(1); } int @@ -128,10 +75,11 @@ main(int argc, char *argv[]) { struct sockaddr_un sun; int fd, n, done; - int i, flags; struct imsg imsg; - enum actions action = NONE; - struct bgpd_addr addr; + struct parse_result *res; + + if ((res = parse(argc, argv)) == NULL) + exit(1); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { err(1, "control_init: socket"); @@ -149,49 +97,22 @@ main(int argc, char *argv[]) imsg_init(&ibuf, fd); done = 0; - if (argc >= 2) - action = match_keyword(argv[1], keywords_main, - sizeof(keywords_main)/sizeof(keywords_main[0])); - -again: - switch (action) { + switch (res->action) { case NONE: usage(); /* not reached */ case SHOW: - if (argc >= 3) { - action = match_keyword(argv[2], keywords_show, - sizeof(keywords_show)/sizeof(keywords_show[0])); - goto again; - } - /* fallthrough */ case SHOW_SUMMARY: - if (argc >= 4) - errx(1, "\"show summary\" does not take arguments"); imsg_compose(&ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, NULL, 0); show_summary_head(); break; case SHOW_FIB: - flags = 0; - bzero(&addr, sizeof(addr)); - for (i = 3; i < argc; i++) - if (!strncmp(argv[i], "connected", strlen(argv[i]))) - flags |= F_CONNECTED; - else if (!strncmp(argv[i], "static", strlen(argv[i]))) - flags |= F_STATIC; - else if (!strncmp(argv[i], "bgp", strlen(argv[i]))) - flags |= F_BGPD_INSERTED; - else if (!strncmp(argv[i], "nexthop", strlen(argv[i]))) - flags |= F_NEXTHOP; - else if (!parse_addr(argv[i], &addr)) - errx(1, "usage: \"show fib connected|static|" - "bgp|nexthop|[address]"); - if (!addr.af) - imsg_compose(&ibuf, IMSG_CTL_KROUTE, 0, &flags, - sizeof(flags)); + if (!res->addr.af) + imsg_compose(&ibuf, IMSG_CTL_KROUTE, 0, &res->flags, + sizeof(res->flags)); else - imsg_compose(&ibuf, IMSG_CTL_KROUTE_ADDR, 0, &addr, - sizeof(addr)); + imsg_compose(&ibuf, IMSG_CTL_KROUTE_ADDR, 0, &res->addr, + sizeof(res->addr)); show_fib_head(); break; case SHOW_NEXTHOP: @@ -204,68 +125,42 @@ again: break; case SHOW_NEIGHBOR: case SHOW_NEIGHBOR_TIMERS: - /* get ip address of neighbor, limit query to that */ - if (argc >= 4) { - if (!parse_addr(argv[3], &addr)) - errx(1, "%s: not an IP address", argv[3]); + if (res->addr.af) imsg_compose(&ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, - &addr, sizeof(addr)); - } else + &res->addr, sizeof(res->addr)); + else imsg_compose(&ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, NULL, 0); - - if (argc >= 5) - action = match_keyword(argv[4], keywords_show_neighbor, - sizeof(keywords_show_neighbor)/ - sizeof(keywords_show_neighbor[0])); break; case RELOAD: - if (argc >= 3) - errx(1, "\"reload\" takes no options"); imsg_compose(&ibuf, IMSG_CTL_RELOAD, 0, NULL, 0); printf("reload request sent.\n"); done = 1; break; case FIB: - if (argc >= 3) { - action = match_keyword(argv[2], keywords_fib, - sizeof(keywords_fib)/sizeof(keywords_fib[0])); - goto again; - } else - errx(1, "fib [couple|decouple]"); + errx(1, "action==FIB"); break; case FIB_COUPLE: - if (argc >= 4) - errx(1, "\"fib couple\" takes no options"); imsg_compose(&ibuf, IMSG_CTL_FIB_COUPLE, 0, NULL, 0); printf("couple request sent.\n"); done = 1; break; case FIB_DECOUPLE: - if (argc >= 4) - errx(1, "\"fib decouple\" takes no options"); imsg_compose(&ibuf, IMSG_CTL_FIB_DECOUPLE, 0, NULL, 0); printf("decouple request sent.\n"); done = 1; break; case NEIGHBOR: - if (argc < 4) - errx(1, "usage: neighbor address command"); - if (!parse_addr(argv[2], &addr)) - errx(1, "%s: not an IP address", argv[2]); - action = match_keyword(argv[3], keywords_neighbor, - sizeof(keywords_neighbor)/ - sizeof(keywords_neighbor[0])); - goto again; + errx(1, "action==NEIGHBOR"); break; case NEIGHBOR_UP: imsg_compose(&ibuf, IMSG_CTL_NEIGHBOR_UP, 0, - &addr, sizeof(addr)); + &res->addr, sizeof(res->addr)); printf("request sent.\n"); done = 1; break; case NEIGHBOR_DOWN: imsg_compose(&ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, - &addr, sizeof(addr)); + &res->addr, sizeof(res->addr)); printf("request sent.\n"); done = 1; break; @@ -286,7 +181,7 @@ again: errx(1, "imsg_get error"); if (n == 0) break; - switch (action) { + switch (res->action) { case SHOW: case SHOW_SUMMARY: done = show_summary_msg(&imsg); @@ -322,28 +217,6 @@ again: close(fd); } -int -match_keyword(const char *word, const struct keywords table[], size_t cnt) -{ - u_int match, res, i; - - match = res = 0; - - for (i = 0; i < cnt; i++) - if (strncmp(word, table[i].keyword, - strlen(word)) == 0) { - match++; - res = table[i].value; - } - - if (match > 1) - errx(1, "ambigous command: %s", word); - if (match < 1) - errx(1, "unknown command: %s", word); - - return (res); -} - void show_summary_head(void) { @@ -531,23 +404,6 @@ fmt_timeframe_core(time_t t) return (buf); } -int -parse_addr(const char *word, struct bgpd_addr *addr) -{ - struct in_addr ina; - - bzero(addr, sizeof(struct bgpd_addr)); - bzero(&ina, sizeof(ina)); - - if (inet_pton(AF_INET, word, &ina)) { - addr->af = AF_INET; - addr->v4 = ina; - return (1); - } - - return (0); -} - void show_fib_head(void) { diff --git a/usr.sbin/bgpctl/parser.c b/usr.sbin/bgpctl/parser.c new file mode 100644 index 00000000000..695ee28209a --- /dev/null +++ b/usr.sbin/bgpctl/parser.c @@ -0,0 +1,253 @@ +/* $OpenBSD: parser.c,v 1.1 2004/01/21 23:45:18 henning Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "parser.h" + +enum token_type { + NOTOKEN, + ENDTOKEN, + KEYWORD, + ADDRESS, + FLAG +}; + +struct token { + enum token_type type; + const char *keyword; + int value; + const struct token *next; +}; + +static const struct token t_main[]; +static const struct token t_show[]; +static const struct token t_show_fib[]; +static const struct token t_show_neighbor[]; +static const struct token t_show_neighbor_modifiers[]; +static const struct token t_fib[]; +static const struct token t_neighbor[]; +static const struct token t_neighbor_modifiers[]; + +static const struct token t_main[] = { + { KEYWORD, "reload", RELOAD, NULL}, + { KEYWORD, "show", SHOW, t_show}, + { KEYWORD, "fib", FIB, t_fib}, + { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_show[] = { + { NOTOKEN, "", NONE, NULL}, + { KEYWORD, "fib", SHOW_FIB, t_show_fib}, + { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, + { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, + { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, + { KEYWORD, "summary", SHOW_SUMMARY, NULL}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_show_fib[] = { + { NOTOKEN, "", NONE, NULL}, + { FLAG, "connected", F_CONNECTED, t_show_fib}, + { FLAG, "static", F_STATIC, t_show_fib}, + { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, + { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, + { ADDRESS, "", NONE, NULL}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_show_neighbor[] = { + { NOTOKEN, "", NONE, NULL}, + { ADDRESS, "", NONE, t_show_neighbor_modifiers}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_show_neighbor_modifiers[] = { + { NOTOKEN, "", NONE, NULL}, + { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, + { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_fib[] = { + { KEYWORD, "couple", FIB_COUPLE, NULL}, + { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_neighbor[] = { + { ADDRESS, "", NONE, t_neighbor_modifiers}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_neighbor_modifiers[] = { + { KEYWORD, "up", NEIGHBOR_UP, NULL}, + { KEYWORD, "down", NEIGHBOR_DOWN, NULL}, + { ENDTOKEN, "", NONE, NULL} +}; + +static struct parse_result res; + +const struct token *match_token(const char *, const struct token []); +void show_valid_args(const struct token []); +int parse_addr(const char *, struct bgpd_addr *); + +struct parse_result * +parse(int argc, char *argv[]) +{ + int curarg = 1; + const struct token *table = t_main; + const struct token *match; + char *word; + + bzero(&res, sizeof(res)); + if (argc == 1) + return (&res); + + for (;;) { + if (argc > curarg) + word = argv[curarg]; + else + word = NULL; + + if ((match = match_token(word, table)) == NULL) { + fprintf(stderr, "valid commands/args:\n"); + show_valid_args(table); + return (NULL); + } + + curarg++; + + if (match->type == NOTOKEN) + break; + + if (match->next == NULL) + break; + + table = match->next; + } + + if (curarg < argc) { + fprintf(stderr, "superflous argument: %s\n", argv[curarg]); + return (NULL); + } + + return (&res); +} + +const struct token * +match_token(const char *word, const struct token table[]) +{ + u_int i, match; + const struct token *t = NULL; + + match = 0; + + for (i = 0; table[i].type != ENDTOKEN; i++) { + switch (table[i].type) { + case NOTOKEN: + if (word == NULL || strlen(word) == 0) { + match++; + t = &table[i]; + } + break; + case KEYWORD: + if (word != NULL && strncmp(word, table[i].keyword, + strlen(word)) == 0) { + match++; + t = &table[i]; + if (t->value) + res.action = t->value; + } + break; + case FLAG: + if (word != NULL && strncmp(word, table[i].keyword, + strlen(word)) == 0) { + match++; + t = &table[i]; + res.flags |= t->value; + } + break; + case ADDRESS: + if (parse_addr(word, &res.addr)) { + match++; + t = &table[i]; + if (t->value) + res.action = t->value; + } + break; + case ENDTOKEN: + break; + } + } + + if (match != 1) { + if (match > 1) + fprintf(stderr, "ambiguous argument: %s\n", word); + if (match < 1) + fprintf(stderr, "unknown argument: %s\n", word); + return (NULL); + } + + return (t); +} + +void +show_valid_args(const struct token table[]) +{ + int i; + + for (i = 0; table[i].type != ENDTOKEN; i++) { + switch (table[i].type) { + case NONE: + fprintf(stderr, " (nothing)\n"); + break; + case KEYWORD: + case FLAG: + fprintf(stderr, " %s\n", table[i].keyword); + break; + case ADDRESS: + fprintf(stderr, " <address>\n"); + break; + case ENDTOKEN: + break; + } + } +} + +int +parse_addr(const char *word, struct bgpd_addr *addr) +{ + struct in_addr ina; + + if (word == NULL) + return (0); + + bzero(addr, sizeof(struct bgpd_addr)); + bzero(&ina, sizeof(ina)); + + if (inet_pton(AF_INET, word, &ina)) { + addr->af = AF_INET; + addr->v4 = ina; + return (1); + } + + return (0); +} diff --git a/usr.sbin/bgpctl/parser.h b/usr.sbin/bgpctl/parser.h new file mode 100644 index 00000000000..c61310be192 --- /dev/null +++ b/usr.sbin/bgpctl/parser.h @@ -0,0 +1,47 @@ +/* $OpenBSD: parser.h,v 1.1 2004/01/21 23:45:18 henning Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include "bgpd.h" + +enum actions { + NONE, + SHOW, + SHOW_SUMMARY, + SHOW_NEIGHBOR, + SHOW_NEIGHBOR_TIMERS, + SHOW_FIB, + SHOW_NEXTHOP, + SHOW_INTERFACE, + RELOAD, + FIB, + FIB_COUPLE, + FIB_DECOUPLE, + NEIGHBOR, + NEIGHBOR_UP, + NEIGHBOR_DOWN +}; + +struct parse_result { + enum actions action; + int flags; + struct bgpd_addr addr; +}; + +struct parse_result *parse(int, char *[]); |