summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2004-01-21 23:45:19 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2004-01-21 23:45:19 +0000
commit5b2c6c8403760622408244c7ab09fe3be78a2a80 (patch)
treec2a34ed327f917f389f610dd4a67e5b5a7d4c805
parentebb2ffc8e85899bbaee09799b6cdce3d0b4a4b6a (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/Makefile6
-rw-r--r--usr.sbin/bgpctl/bgpctl.c186
-rw-r--r--usr.sbin/bgpctl/parser.c253
-rw-r--r--usr.sbin/bgpctl/parser.h47
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 *[]);