diff options
| author | 2016-11-24 09:23:11 +0000 | |
|---|---|---|
| committer | 2016-11-24 09:23:11 +0000 | |
| commit | b423f9d5571f6d10324c59d51a1c41277a699ef8 (patch) | |
| tree | 16014384e6ba6168c076f488e0bb64fc234a068e /usr.sbin/switchctl/parser.c | |
| parent | Better cast for consistency (diff) | |
| download | wireguard-openbsd-b423f9d5571f6d10324c59d51a1c41277a699ef8.tar.xz wireguard-openbsd-b423f9d5571f6d10324c59d51a1c41277a699ef8.zip | |
Add simple client to add flows from switchctl. Not finished yet, but
it is better for rzalamena and me to work on it in the tree.
OK rzalamena@
Diffstat (limited to 'usr.sbin/switchctl/parser.c')
| -rw-r--r-- | usr.sbin/switchctl/parser.c | 237 |
1 files changed, 219 insertions, 18 deletions
diff --git a/usr.sbin/switchctl/parser.c b/usr.sbin/switchctl/parser.c index 7826ae70b8b..fb496440de1 100644 --- a/usr.sbin/switchctl/parser.c +++ b/usr.sbin/switchctl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.5 2016/11/15 08:38:57 reyk Exp $ */ +/* $OpenBSD: parser.c,v 1.6 2016/11/24 09:23:11 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -34,6 +34,7 @@ #include <netdb.h> #include "switchd.h" +#include "ofp_map.h" #include "parser.h" enum token_type { @@ -42,7 +43,16 @@ enum token_type { KEYWORD, PATH, ADDRESS, - URI + URI, + TABLE, + FLOWADD, + FLOWDELETE, + FLOWMODIFY, + FLOWAPPLY, + FLOWWRITE, + FLOWMATCH, + MATCHINPORT, + ACTIONOUTPUT, }; struct token { @@ -57,8 +67,16 @@ 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_switch[]; +static const struct token t_switchreq[]; +static const struct token t_table[]; static const struct token t_dump[]; -static const struct token t_dumpreq[]; +static const struct token t_flow[]; +static const struct token t_flowmod[]; +static const struct token t_flowmatch[]; +static const struct token t_matchinport[]; +static const struct token t_flowaction[]; +static const struct token t_actionoutput[]; static const struct token t_connect[]; static const struct token t_disconnect[]; static const struct token t_forward_to[]; @@ -68,12 +86,15 @@ static const struct token t_main[] = { { KEYWORD, "connect", CONNECT, t_connect }, { KEYWORD, "disconnect", DISCONNECT, t_disconnect }, { KEYWORD, "dump", NONE, t_dump }, + { KEYWORD, "flow", NONE, t_flow }, { 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 }, + { KEYWORD, "switch", NONE, t_switch }, + { KEYWORD, "table", NONE, t_table }, { ENDTOKEN, "", NONE, NULL } }; @@ -93,12 +114,23 @@ static const struct token t_load[] = { { ENDTOKEN, "", NONE, NULL } }; -static const struct token t_dump[] = { - { URI, "", NONE, t_dumpreq }, +static const struct token t_table[] = { + { TABLE, "", NONE, t_main }, { ENDTOKEN, "", NONE, NULL } }; -static const struct token t_dumpreq[] = { +static const struct token t_switch[] = { + { URI, "", NONE, t_main }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_switchreq[] = { + { KEYWORD, "dump", NONE, t_dump }, + { KEYWORD, "flow", NONE, t_flow }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_dump[] = { { KEYWORD, "desc", DUMP_DESC, NULL }, { KEYWORD, "features", DUMP_FEATURES, NULL }, { KEYWORD, "flows", DUMP_FLOWS, NULL }, @@ -106,6 +138,43 @@ static const struct token t_dumpreq[] = { { ENDTOKEN, "", NONE, NULL } }; +static const struct token t_flow[] = { + { FLOWADD, "add", FLOW_ADD, t_flowmod }, + { FLOWDELETE, "delete", FLOW_DELETE, t_flowmod }, + { FLOWMODIFY, "modify", FLOW_MODIFY, t_flowmod }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_flowmod[] = { + { NOTOKEN, "", NONE, NULL }, + { FLOWAPPLY, "apply", NONE, t_flowaction }, + { FLOWWRITE, "write", NONE, t_flowaction }, + { FLOWMATCH, "match", NONE, t_flowmatch }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_flowmatch[] = { + { NOTOKEN, "", NONE, t_flowmod }, + { KEYWORD, "inport", NONE, t_matchinport }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_matchinport[] = { + { MATCHINPORT, "", NONE, t_flowmatch }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_flowaction[] = { + { NOTOKEN, "", NONE, t_flowmod }, + { KEYWORD, "output", NONE, t_actionoutput }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_actionoutput[] = { + { ACTIONOUTPUT, "", NONE, t_flowaction }, + { ENDTOKEN, "", NONE, NULL } +}; + static const struct token t_show[] = { { KEYWORD, "summary", SHOW_SUM, NULL }, { KEYWORD, "switches", SHOW_SWITCHES, NULL }, @@ -134,10 +203,10 @@ static const struct token t_uri[] = { 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 sockaddr_storage *); +const struct token *match_token(char *, const struct token [], int); +void show_valid_args(const struct token [], int); +int parse_addr(const char *, + struct sockaddr_storage *); struct parse_result * parse(int argc, char *argv[]) @@ -147,10 +216,12 @@ parse(int argc, char *argv[]) bzero(&res, sizeof(res)); + res.table = OFP_TABLE_ID_ALL; + while (argc >= 0) { - if ((match = match_token(argv[0], table)) == NULL) { + if ((match = match_token(argv[0], table, 0)) == NULL) { fprintf(stderr, "valid commands/args:\n"); - show_valid_args(table); + show_valid_args(table, 0); return (NULL); } @@ -230,9 +301,12 @@ parse_addr(const char *word, struct sockaddr_storage *ss) const struct token * -match_token(char *word, const struct token table[]) +match_token(char *word, const struct token table[], int level) { - unsigned int i, match = 0; + unsigned int i, j, match = 0; + int64_t val; + struct constmap *cm; + const char *errstr = NULL; const struct token *t = NULL; size_t len; @@ -245,12 +319,102 @@ match_token(char *word, const struct token table[]) } break; case KEYWORD: + case FLOWADD: + case FLOWDELETE: + case FLOWMODIFY: + case FLOWMATCH: + case FLOWAPPLY: + case FLOWWRITE: if (word != NULL && strncmp(word, table[i].keyword, strlen(word)) == 0) { match++; t = &table[i]; if (t->value) res.action = t->value; + switch (table[i].type) { + case FLOWADD: + case FLOWDELETE: + case FLOWMODIFY: + if ((res.fbuf = + oflowmod_open(&res.fctx, + NULL, NULL, 0)) == NULL) + goto flowerr; + + /* Update header */ + if (table[i].type == FLOWDELETE) + res.fctx.ctx_fm->fm_command = + htons(OFP_FLOWCMD_DELETE); + else if (table[i].type == FLOWMODIFY) + res.fctx.ctx_fm->fm_command = + htons(OFP_FLOWCMD_MODIFY); + break; + case FLOWAPPLY: + val = OFP_INSTRUCTION_T_APPLY_ACTIONS; + if (oflowmod_instruction(&res.fctx, + val) == -1) + goto flowerr; + break; + case FLOWWRITE: + val = OFP_INSTRUCTION_T_WRITE_ACTIONS; + if (oflowmod_instruction(&res.fctx, + val) == -1) + goto flowerr; + break; + case FLOWMATCH: + if (oflowmod_mopen(&res.fctx) == -1) + goto flowerr; + break; + default: + break; + } + } + break; + case MATCHINPORT: + case ACTIONOUTPUT: + if (!match && word != NULL && strlen(word) > 0) { + match++; + t = &table[i]; + + val = -1; + + /* Is the port a keyword? */ + cm = ofp_port_map; + for (j = 0; cm[j].cm_name != NULL; j++) { + if (strcasecmp(cm[j].cm_name, + word) == 0) { + val = cm[j].cm_type; + break; + } + } + + /* Is the port a number? */ + if (val == -1) { + val = strtonum(word, 1, + UINT32_MAX, &errstr); + if (errstr != NULL) + val = -1; + } + + if (val == -1) { + fprintf(stderr, + "could not parse port:" + " %s\n", word); + return (NULL); + } + + switch (table[i].type) { + case MATCHINPORT: + if (oxm_inport(res.fbuf, val) == -1) + goto flowerr; + break; + case ACTIONOUTPUT: + if (action_output(res.fbuf, val, + OFP_CONTROLLER_MAXLEN_MAX) == -1) + goto flowerr; + break; + default: + break; + } } break; case PATH: @@ -267,6 +431,16 @@ match_token(char *word, const struct token table[]) t = &table[i]; } break; + case TABLE: + if (word == NULL) + break; + res.table = strtonum(word, 0, + OFP_TABLE_ID_MAX, &errstr); + if (errstr) + res.table = OFP_TABLE_ID_ALL; + t = &table[i]; + match++; + break; case URI: if (!match && word != NULL && strlen(word) > 0) { len = 4; @@ -301,33 +475,57 @@ match_token(char *word, const struct token table[]) 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); + else if (match < 1) { + if (level == 0 && + table[0].type == NOTOKEN && table[0].next) + return (match_token(word, table[0].next, 1)); + else + fprintf(stderr, "unknown argument: %s\n", word); + } return (NULL); } return (t); + + flowerr: + (void)oflowmod_err(&res.fctx, __func__, __LINE__); + fprintf(stderr, "flow invalid\n"); + return (NULL); } void -show_valid_args(const struct token table[]) +show_valid_args(const struct token table[], int level) { int i; for (i = 0; table[i].type != ENDTOKEN; i++) { switch (table[i].type) { case NOTOKEN: - fprintf(stderr, " <cr>\n"); + if (level == 0) + fprintf(stderr, " <cr>\n"); break; case KEYWORD: + case FLOWADD: + case FLOWDELETE: + case FLOWMODIFY: + case FLOWMATCH: + case FLOWAPPLY: + case FLOWWRITE: fprintf(stderr, " %s\n", table[i].keyword); break; + case MATCHINPORT: + case ACTIONOUTPUT: + fprintf(stderr, " <port>\n"); + break; case PATH: fprintf(stderr, " <path>\n"); break; case ADDRESS: fprintf(stderr, " <address>\n"); break; + case TABLE: + fprintf(stderr, " <table>\n"); + break; case URI: fprintf(stderr, " <uri>\n"); break; @@ -335,4 +533,7 @@ show_valid_args(const struct token table[]) break; } } + + if (level == 0 && table[0].type == NOTOKEN && table[0].next) + return (show_valid_args(table[0].next, 1)); } |
