summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2016-07-19 21:14:27 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2016-07-19 21:14:27 +0000
commit9d0662e009c0cf4532b88c9a1fb0f7c0dc174584 (patch)
treeab301ab5ec4b58a249df43e09fbc21154e879499
parent340a2b4ac0bcc737e24aa6c0e383f1188aaaaf61 (diff)
lib: Break up functions, begin matcher
Moved test hook out of command.c into vtysh.c, renamed graph modules, added matching code Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/command.c6
-rw-r--r--lib/command_graph.c (renamed from lib/cmdtree.c)2
-rw-r--r--lib/command_graph.h (renamed from lib/cmdtree.h)5
-rw-r--r--lib/command_match.c174
-rw-r--r--lib/command_match.h69
-rw-r--r--lib/command_parse.y26
-rw-r--r--lib/grammar_sandbox.c43
-rw-r--r--lib/grammar_sandbox.h2
-rw-r--r--vtysh/vtysh.c4
10 files changed, 310 insertions, 25 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 126303622f..2df5ed61f4 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -11,7 +11,7 @@ libzebra_la_LDFLAGS = -version-info 0:0:0
libzebra_la_SOURCES = \
network.c pid_output.c getopt.c getopt1.c daemon.c \
checksum.c vector.c linklist.c vty.c \
- cmdtree.c command_parse.y command_lex.l \
+ command_graph.c command_parse.y command_lex.l command_match.c grammar_sandbox.c \
command.c \
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
@@ -28,7 +28,7 @@ libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@
pkginclude_HEADERS = \
buffer.h checksum.h filter.h getopt.h hash.h \
if.h linklist.h log.h \
- cmdtree.h \
+ command_graph.h command_match.h grammar_sandbox.h \
command.h \
memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
diff --git a/lib/command.c b/lib/command.c
index 4b571ba75d..490c2a0690 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -34,8 +34,6 @@ Boston, MA 02111-1307, USA. */
#include "workqueue.h"
#include "vrf.h"
-#include "grammar_sandbox.c"
-
/* Command vector which includes some level of command lists. Normally
each daemon maintains each own cmdvec. */
vector cmdvec = NULL;
@@ -4077,10 +4075,6 @@ cmd_init (int terminal)
install_element (ENABLE_NODE, &show_version_cmd);
install_element (ENABLE_NODE, &show_commandtree_cmd);
- /**/
- grammar_sandbox_init();
- /**/
-
if (terminal)
{
install_element (ENABLE_NODE, &config_terminal_length_cmd);
diff --git a/lib/cmdtree.c b/lib/command_graph.c
index 38632dca40..9b91eaf242 100644
--- a/lib/cmdtree.c
+++ b/lib/command_graph.c
@@ -7,7 +7,7 @@
*/
#include <zebra.h>
-#include "cmdtree.h"
+#include "command_graph.h"
#include "memory.h"
struct graph_node *
diff --git a/lib/cmdtree.h b/lib/command_graph.h
index 3d2366b008..8d23577d37 100644
--- a/lib/cmdtree.h
+++ b/lib/command_graph.h
@@ -1,3 +1,6 @@
+#ifndef COMMAND_GRAPH_H
+#define COMMAND_GRAPH_H
+
#include "vty.h"
#include "vector.h"
@@ -78,3 +81,5 @@ new_node(enum graph_node_type);
*/
extern void
walk_graph(struct graph_node *, int);
+
+#endif
diff --git a/lib/command_match.c b/lib/command_match.c
new file mode 100644
index 0000000000..bcc28bdc5b
--- /dev/null
+++ b/lib/command_match.c
@@ -0,0 +1,174 @@
+#include <zebra.h>
+#include "memory.h"
+#include "command_match.h"
+
+enum match_type
+match_command (struct graph_node *start, enum filter_type filter, const char *input)
+{
+ // match input on DFA
+ return exact_match;
+}
+
+
+#define IPV4_ADDR_STR "0123456789."
+#define IPV4_PREFIX_STR "0123456789./"
+
+enum match_type
+cmd_ipv4_match (const char *str)
+{
+ struct sockaddr_in sin_dummy;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV4_ADDR_STR) != strlen (str))
+ return no_match;
+
+ if (inet_pton(AF_INET, str, &sin_dummy.sin_addr) != 1)
+ return no_match;
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv4_prefix_match (const char *str)
+{
+ struct sockaddr_in sin_dummy;
+ const char *delim = "/\0";
+ char *dupe, *prefix, *mask, *context, *endptr;
+ int nmask = -1;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV4_PREFIX_STR) != strlen (str))
+ return no_match;
+
+ /* tokenize to address + mask */
+ dupe = XMALLOC(MTYPE_TMP, strlen(str)+1);
+ strncpy(dupe, str, strlen(str)+1);
+ prefix = strtok_r(dupe, delim, &context);
+ mask = strtok_r(NULL, delim, &context);
+
+ if (!mask)
+ return partly_match;
+
+ /* validate prefix */
+ if (inet_pton(AF_INET, prefix, &sin_dummy.sin_addr) != 1)
+ return no_match;
+
+ /* validate mask */
+ nmask = strtol (mask, &endptr, 10);
+ if (*endptr != '\0' || nmask < 0 || nmask > 32)
+ return no_match;
+
+ XFREE(MTYPE_TMP, dupe);
+
+ return exact_match;
+}
+
+#define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
+#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
+
+#ifdef HAVE_IPV6
+enum match_type
+cmd_ipv6_match (const char *str)
+{
+ struct sockaddr_in6 sin6_dummy;
+ int ret;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_ADDR_STR) != strlen (str))
+ return no_match;
+
+ ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
+
+ if (ret == 1)
+ return exact_match;
+
+ return no_match;
+}
+
+enum match_type
+cmd_ipv6_prefix_match (const char *str)
+{
+ struct sockaddr_in6 sin6_dummy;
+ const char *delim = "/\0";
+ char *dupe, *prefix, *mask, *context, *endptr;
+ int nmask = -1;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
+ return no_match;
+
+ /* tokenize to address + mask */
+ dupe = XMALLOC(MTYPE_TMP, strlen(str)+1);
+ strncpy(dupe, str, strlen(str)+1);
+ prefix = strtok_r(dupe, delim, &context);
+ mask = strtok_r(NULL, delim, &context);
+
+ if (!mask)
+ return partly_match;
+
+ /* validate prefix */
+ if (inet_pton(AF_INET6, prefix, &sin6_dummy.sin6_addr) != 1)
+ return no_match;
+
+ /* validate mask */
+ nmask = strtol (mask, &endptr, 10);
+ if (*endptr != '\0' || nmask < 0 || nmask > 128)
+ return no_match;
+
+ XFREE(MTYPE_TMP, dupe);
+
+ return exact_match;
+}
+#endif
+
+enum match_type
+cmd_range_match (struct graph_node *rangenode, const char *str)
+{
+ char *endptr = NULL;
+ signed long long val;
+
+ if (str == NULL)
+ return 1;
+
+ val = strtoll (str, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+ val = llabs(val);
+
+ if (val < rangenode->min || val > rangenode->max)
+ return no_match;
+ else
+ return exact_match;
+}
+
+enum match_type
+cmd_word_match(struct graph_node *wordnode,
+ enum filter_type filter,
+ const char *word)
+{
+ if (filter == FILTER_RELAXED)
+ if (!word || !strlen(word))
+ return partly_match;
+
+ if (!word)
+ return no_match;
+
+ if (filter == FILTER_RELAXED && !strncmp(wordnode->text, word, strlen(word)))
+ {
+ if (!strcmp(wordnode->text, word))
+ return exact_match;
+ return partly_match;
+ }
+ if (filter == FILTER_STRICT && !strcmp(wordnode->text, word))
+ return exact_match;
+
+ return no_match;
+}
diff --git a/lib/command_match.h b/lib/command_match.h
new file mode 100644
index 0000000000..cddeb08af7
--- /dev/null
+++ b/lib/command_match.h
@@ -0,0 +1,69 @@
+#ifndef COMMAND_MATCH_H
+#define COMMAND_MATCH_H
+
+#include "command_graph.h"
+
+/**
+ * Filter types. These tell the parser whether to allow
+ * partial matching on tokens.
+ */
+enum filter_type
+{
+ FILTER_RELAXED,
+ FILTER_STRICT
+};
+
+/**
+ * Command matcher result value.
+ */
+enum matcher_rv
+{
+ MATCHER_OK,
+ MATCHER_COMPLETE,
+ MATCHER_INCOMPLETE,
+ MATCHER_NO_MATCH,
+ MATCHER_AMBIGUOUS,
+ MATCHER_EXCEED_ARGC_MAX
+};
+
+/* Completion match types. */
+enum match_type
+{
+ no_match,
+ partly_match,
+ exact_match
+};
+/**
+ * Defines which matcher_rv values constitute
+ * an error. Should be used against matcher_rv
+ * return values to do basic error checking.
+ */
+#define MATCHER_ERROR(matcher_rv) \
+ ( (matcher_rv) == MATCHER_INCOMPLETE \
+ || (matcher_rv) == MATCHER_NO_MATCH \
+ || (matcher_rv) == MATCHER_AMBIGUOUS \
+ || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
+ )
+
+enum match_type
+cmd_ipv4_match (const char *);
+
+enum match_type
+cmd_ipv4_prefix_match (const char *);
+
+enum match_type
+cmd_ipv6_match (const char *);
+
+enum match_type
+cmd_ipv6_prefix_match (const char *);
+
+enum match_type
+cmd_range_match (struct graph_node *, const char *str);
+
+enum match_type
+cmd_word_match (struct graph_node *, enum filter_type, const char *);
+
+enum match_type
+match_command (struct graph_node *, enum filter_type, const char *);
+
+#endif
diff --git a/lib/command_parse.y b/lib/command_parse.y
index cf2cd95bdd..80487af7cd 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -1,5 +1,15 @@
+/*
+ * Command format string parser.
+ *
+ * Turns a command definition into a DFA that together with the functions
+ * provided in command_match.c may be used to map command line input to a
+ * function.
+ *
+ * @author Quentin Young <qlyoung@cumulusnetworks.com>
+ */
+
%{
-#include "cmdtree.h"
+#include "command_graph.h"
extern int yylex(void);
extern void yyerror(const char *);
@@ -8,16 +18,22 @@ extern void yyerror(const char *);
#define YYDEBUG 1
%}
%code provides {
-extern struct graph_node *cmd_parse_format_new(const char *, const char *, struct graph_node *);
-extern void set_buffer_string(const char *);
+extern struct
+graph_node *cmd_parse_format(const char *,
+ const char *,
+ struct graph_node *);
+extern void
+set_buffer_string(const char *);
}
+/* valid types for tokens */
%union{
int integer;
char *string;
struct graph_node *node;
}
+/* some helpful state variables */
%{
struct graph_node *startnode, // command root node
*currnode, // current node
@@ -66,7 +82,7 @@ sentence_root: WORD
$$ = new_node(WORD_GN);
$$->text = strdup(yylval.string);
fprintf(stderr, ">>>>>>>> YYLVAL.STRING: %s\n", yylval.string);
- fprintf(stderr, ">>>>>>>> TEXT: %s\n", $$->text);
+ fprintf(stderr, ">>>>>>>> TEXT: %s\n", $$->text);
currnode = $$;
currnode->is_root = 1;
@@ -270,7 +286,7 @@ void yyerror(char const *message) {
}
struct graph_node *
-cmd_parse_format_new(const char *string, const char *desc, struct graph_node *start)
+cmd_parse_format(const char *string, const char *desc, struct graph_node *start)
{
fprintf(stderr, "parsing: %s\n", string);
diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c
index 807ada9d98..1e6a76c69c 100644
--- a/lib/grammar_sandbox.c
+++ b/lib/grammar_sandbox.c
@@ -1,17 +1,14 @@
#include "command.h"
+#include "command_graph.h"
#include "command_parse.h"
-#include "cmdtree.h"
+#include "command_match.h"
#define GRAMMAR_STR "CLI grammar sandbox\n"
struct graph_node * nodegraph;
-DEFUN (grammar_test,
- grammar_test_cmd,
- "grammar parse .COMMAND",
- GRAMMAR_STR
- "command to pass to new parser\n")
-{
+/*
+char* combine_vararg(char* argv, int argc) {
size_t linesize = 0;
for (int i = 0; i < argc; i++)
linesize += strlen(argv[i]) + 1;
@@ -24,8 +21,19 @@ DEFUN (grammar_test,
strcat(cat, " ");
}
- //struct graph_node *result = new_node(NUL_GN);
- cmd_parse_format_new((const char*) cat, "lol", nodegraph);
+ return cat;
+}
+*/
+
+DEFUN (grammar_test,
+ grammar_test_cmd,
+ "grammar parse .COMMAND",
+ GRAMMAR_STR
+ "command to pass to new parser\n")
+{
+
+ const char* command = argv_concat(argv, argc, 0);
+ cmd_parse_format(command, "lol", nodegraph);
walk_graph(nodegraph, 0);
return CMD_SUCCESS;
@@ -37,8 +45,20 @@ DEFUN (grammar_test_show,
GRAMMAR_STR
"print current accumulated DFA\n")
{
- walk_graph(nodegraph, 0);
- return CMD_SUCCESS;
+ walk_graph(nodegraph, 0);
+ return CMD_SUCCESS;
+}
+
+DEFUN (grammar_test_match,
+ grammar_test_match_cmd,
+ "grammar match .COMMAND",
+ GRAMMAR_STR
+ "attempt to match input on DFA\n"
+ "command to match")
+{
+ const char* command = argv_concat(argv, argc, 0);
+ match_command(nodegraph, FILTER_STRICT, command);
+ return CMD_SUCCESS;
}
@@ -48,4 +68,5 @@ void grammar_sandbox_init() {
nodegraph = new_node(NUL_GN);
install_element (ENABLE_NODE, &grammar_test_cmd);
install_element (ENABLE_NODE, &grammar_test_show_cmd);
+ install_element (ENABLE_NODE, &grammar_test_match_cmd);
}
diff --git a/lib/grammar_sandbox.h b/lib/grammar_sandbox.h
new file mode 100644
index 0000000000..2b2c742461
--- /dev/null
+++ b/lib/grammar_sandbox.h
@@ -0,0 +1,2 @@
+void
+grammar_sandbox_init(void);
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index ecb6c5c6ac..9d4061cfcf 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -42,6 +42,8 @@
#include "bgpd/bgp_vty.h"
#include "vrf.h"
+#include "lib/grammar_sandbox.h"
+
/* Struct VTY. */
struct vty *vty;
@@ -3076,4 +3078,6 @@ vtysh_init_vty (void)
install_element (CONFIG_NODE, &vtysh_enable_password_text_cmd);
install_element (CONFIG_NODE, &no_vtysh_enable_password_cmd);
+ /* grammar sandbox */
+ grammar_sandbox_init();
}