summaryrefslogtreecommitdiffstats
path: root/usr.sbin/switchctl/parser.c
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2016-11-24 09:23:11 +0000
committerreyk <reyk@openbsd.org>2016-11-24 09:23:11 +0000
commitb423f9d5571f6d10324c59d51a1c41277a699ef8 (patch)
tree16014384e6ba6168c076f488e0bb64fc234a068e /usr.sbin/switchctl/parser.c
parentBetter cast for consistency (diff)
downloadwireguard-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.c237
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));
}