mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 08:49:58 +00:00
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>
This commit is contained in:
parent
340a2b4ac0
commit
9d0662e009
@ -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 \
|
||||
|
@ -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);
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include "cmdtree.h"
|
||||
#include "command_graph.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct graph_node *
|
@ -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
|
174
lib/command_match.c
Normal file
174
lib/command_match.c
Normal file
@ -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;
|
||||
}
|
69
lib/command_match.h
Normal file
69
lib/command_match.h
Normal file
@ -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
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
2
lib/grammar_sandbox.h
Normal file
2
lib/grammar_sandbox.h
Normal file
@ -0,0 +1,2 @@
|
||||
void
|
||||
grammar_sandbox_init(void);
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user