diff options
| author | 2016-07-19 16:54:26 +0000 | |
|---|---|---|
| committer | 2016-07-19 16:54:26 +0000 | |
| commit | d24c1ddb59f93e30ff64fdd3703cf88de9c8e584 (patch) | |
| tree | 57cf9e2fff53e04fe06029216d70c0bc35ae70ad /usr.sbin/switchctl/parser.c | |
| parent | Since the mdoc/man parser unification, the parser is always allocated (diff) | |
| download | wireguard-openbsd-d24c1ddb59f93e30ff64fdd3703cf88de9c8e584.tar.xz wireguard-openbsd-d24c1ddb59f93e30ff64fdd3703cf88de9c8e584.zip | |
Import switchd(8), a basic WIP OpenFlow implementation for OpenBSD.
switchd consists of two parts:
1. switchd(8) and switchctl(8), an OpenFlow controller or "vswitch".
2. switch(4), an OpenFlow-aware kernel "bridge".
This the 1st part, the driver will be imported later. The code will
remain disabled for a while, but it helps development to have it in
the tree. switchd currently supports partial OpenFlow 1.0, but the
goal is to use OpenFlow 1.3.5 instead (switch(4) already does 1.3.5).
For more background information see:
http://www.openbsd.org/papers/bsdcan2016-switchd.pdf
https://youtu.be/Cuo0qT-lqig
With help from yasuoka@ goda@
Import discussed with deraadt@
Diffstat (limited to 'usr.sbin/switchctl/parser.c')
| -rw-r--r-- | usr.sbin/switchctl/parser.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/usr.sbin/switchctl/parser.c b/usr.sbin/switchctl/parser.c new file mode 100644 index 00000000000..ee671c8adb6 --- /dev/null +++ b/usr.sbin/switchctl/parser.c @@ -0,0 +1,284 @@ +/* $OpenBSD: parser.c,v 1.1 2016/07/19 16:54:26 reyk Exp $ */ + +/* + * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2004 Esben Norby <norby@openbsd.org> + * 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 <sys/socket.h> +#include <sys/queue.h> +#include <sys/tree.h> + +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <event.h> +#include <netdb.h> + +#include "switchd.h" +#include "parser.h" + +enum token_type { + NOTOKEN, + ENDTOKEN, + KEYWORD, + PATH, + ADDRESS, + FQDN, + DEVICE, + URI +}; + +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_reset[]; +static const struct token t_log[]; +static const struct token t_load[]; +static const struct token t_show[]; +static const struct token t_device[]; +static const struct token t_device_add[]; +static const struct token t_device_remove[]; +static const struct token t_connect_to[]; +static const struct token t_uri[]; + +static const struct token t_main[] = { + { KEYWORD, "device", NONE, t_device }, + { KEYWORD, "load", LOAD, t_load }, + { KEYWORD, "log", NONE, t_log }, + { KEYWORD, "monitor", MONITOR, NULL }, + { KEYWORD, "reload", RELOAD, NULL }, + { KEYWORD, "reset", NONE, t_reset }, + { KEYWORD, "show", NONE, t_show }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_log[] = { + { KEYWORD, "verbose", LOG_VERBOSE, NULL }, + { KEYWORD, "brief", LOG_BRIEF, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_reset[] = { + { KEYWORD, "all", RESETALL, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_load[] = { + { PATH, "", NONE, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_opt_path[] = { + { NOTOKEN, "", NONE, NULL }, + { PATH, "", NONE, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_show[] = { + { KEYWORD, "summary", SHOW_SUM, NULL }, + { KEYWORD, "switches", SHOW_SWITCHES, NULL }, + { KEYWORD, "macs", SHOW_MACS, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; +static const struct token t_device[] = { + { KEYWORD, "add", ADD_DEVICE, t_device_add }, + { KEYWORD, "remove", REMOVE_DEVICE, t_device_remove }, + { ENDTOKEN, "", NONE, NULL } +}; +static const struct token t_device_add[] = { + { DEVICE, "", NONE, t_connect_to }, + { ENDTOKEN, "", NONE, NULL } +}; +static const struct token t_device_remove[] = { + { DEVICE, "", NONE, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; +static const struct token t_connect_to[] = { + { KEYWORD, "connect-to", NONE, t_uri }, + { ENDTOKEN, "", NONE, NULL } +}; +static const struct token t_uri[] = { + { URI, "", NONE, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; + +static struct parse_result res; + +const struct token *match_token(char *, const struct token []); +void show_valid_args(const struct token []); +int parse_addr(const char *); + +struct parse_result * +parse(int argc, char *argv[]) +{ + const struct token *table = t_main; + const struct token *match; + + bzero(&res, sizeof(res)); + + while (argc >= 0) { + if ((match = match_token(argv[0], table)) == NULL) { + fprintf(stderr, "valid commands/args:\n"); + show_valid_args(table); + return (NULL); + } + + argc--; + argv++; + + if (match->type == NOTOKEN || match->next == NULL) + break; + + table = match->next; + } + + if (argc > 0) { + fprintf(stderr, "superfluous argument: %s\n", argv[0]); + return (NULL); + } + + return (&res); +} + +int +parse_addr(const char *word) +{ + struct addrinfo hints, *r; + + bzero(&hints, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; /* dummy */ + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(word, "0", &hints, &r) == 0) { + return (0); + } + + return (1); +} + + +const struct token * +match_token(char *word, const struct token table[]) +{ + unsigned int i, match = 0; + const struct token *t = NULL; + + 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 DEVICE: + case PATH: + if (!match && word != NULL && strlen(word) > 0) { + res.path = strdup(word); + match++; + t = &table[i]; + } + break; + case ADDRESS: + case FQDN: + if (!match && word != NULL && strlen(word) > 0) { + parse_addr(word); + res.host = strdup(word); + if (parse_addr(word) == 0) + res.htype = HOST_IPADDR; + else + res.htype = HOST_FQDN; + match++; + t = &table[i]; + } + break; + case URI: + if (!match && word != NULL && strlen(word) > 0) { + res.uri = strdup(word); + match++; + t = &table[i]; + } + break; + case ENDTOKEN: + break; + } + } + + if (match != 1) { + if (word == NULL) + fprintf(stderr, "missing argument:\n"); + else if (match > 1) + fprintf(stderr, "ambiguous argument: %s\n", word); + else 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 NOTOKEN: + fprintf(stderr, " <cr>\n"); + break; + case KEYWORD: + fprintf(stderr, " %s\n", table[i].keyword); + break; + case PATH: + fprintf(stderr, " <path>\n"); + break; + case ADDRESS: + fprintf(stderr, " <ipaddr>\n"); + break; + case FQDN: + fprintf(stderr, " <fqdn>\n"); + break; + case DEVICE: + fprintf(stderr, " <device>\n"); + break; + case URI: + fprintf(stderr, " <uri>\n"); + break; + case ENDTOKEN: + break; + } + } +} |
