mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 22:57:45 +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 = \
|
libzebra_la_SOURCES = \
|
||||||
network.c pid_output.c getopt.c getopt1.c daemon.c \
|
network.c pid_output.c getopt.c getopt1.c daemon.c \
|
||||||
checksum.c vector.c linklist.c vty.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 \
|
command.c \
|
||||||
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.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 \
|
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 = \
|
pkginclude_HEADERS = \
|
||||||
buffer.h checksum.h filter.h getopt.h hash.h \
|
buffer.h checksum.h filter.h getopt.h hash.h \
|
||||||
if.h linklist.h log.h \
|
if.h linklist.h log.h \
|
||||||
cmdtree.h \
|
command_graph.h command_match.h grammar_sandbox.h \
|
||||||
command.h \
|
command.h \
|
||||||
memory.h network.h prefix.h routemap.h distribute.h sockunion.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 \
|
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 "workqueue.h"
|
||||||
#include "vrf.h"
|
#include "vrf.h"
|
||||||
|
|
||||||
#include "grammar_sandbox.c"
|
|
||||||
|
|
||||||
/* Command vector which includes some level of command lists. Normally
|
/* Command vector which includes some level of command lists. Normally
|
||||||
each daemon maintains each own cmdvec. */
|
each daemon maintains each own cmdvec. */
|
||||||
vector cmdvec = NULL;
|
vector cmdvec = NULL;
|
||||||
@ -4077,10 +4075,6 @@ cmd_init (int terminal)
|
|||||||
install_element (ENABLE_NODE, &show_version_cmd);
|
install_element (ENABLE_NODE, &show_version_cmd);
|
||||||
install_element (ENABLE_NODE, &show_commandtree_cmd);
|
install_element (ENABLE_NODE, &show_commandtree_cmd);
|
||||||
|
|
||||||
/**/
|
|
||||||
grammar_sandbox_init();
|
|
||||||
/**/
|
|
||||||
|
|
||||||
if (terminal)
|
if (terminal)
|
||||||
{
|
{
|
||||||
install_element (ENABLE_NODE, &config_terminal_length_cmd);
|
install_element (ENABLE_NODE, &config_terminal_length_cmd);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
#include "cmdtree.h"
|
#include "command_graph.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
struct graph_node *
|
struct graph_node *
|
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef COMMAND_GRAPH_H
|
||||||
|
#define COMMAND_GRAPH_H
|
||||||
|
|
||||||
#include "vty.h"
|
#include "vty.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
@ -78,3 +81,5 @@ new_node(enum graph_node_type);
|
|||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
walk_graph(struct graph_node *, int);
|
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 int yylex(void);
|
||||||
extern void yyerror(const char *);
|
extern void yyerror(const char *);
|
||||||
@ -8,16 +18,22 @@ extern void yyerror(const char *);
|
|||||||
#define YYDEBUG 1
|
#define YYDEBUG 1
|
||||||
%}
|
%}
|
||||||
%code provides {
|
%code provides {
|
||||||
extern struct graph_node *cmd_parse_format_new(const char *, const char *, struct graph_node *);
|
extern struct
|
||||||
extern void set_buffer_string(const char *);
|
graph_node *cmd_parse_format(const char *,
|
||||||
|
const char *,
|
||||||
|
struct graph_node *);
|
||||||
|
extern void
|
||||||
|
set_buffer_string(const char *);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* valid types for tokens */
|
||||||
%union{
|
%union{
|
||||||
int integer;
|
int integer;
|
||||||
char *string;
|
char *string;
|
||||||
struct graph_node *node;
|
struct graph_node *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* some helpful state variables */
|
||||||
%{
|
%{
|
||||||
struct graph_node *startnode, // command root node
|
struct graph_node *startnode, // command root node
|
||||||
*currnode, // current node
|
*currnode, // current node
|
||||||
@ -66,7 +82,7 @@ sentence_root: WORD
|
|||||||
$$ = new_node(WORD_GN);
|
$$ = new_node(WORD_GN);
|
||||||
$$->text = strdup(yylval.string);
|
$$->text = strdup(yylval.string);
|
||||||
fprintf(stderr, ">>>>>>>> YYLVAL.STRING: %s\n", yylval.string);
|
fprintf(stderr, ">>>>>>>> YYLVAL.STRING: %s\n", yylval.string);
|
||||||
fprintf(stderr, ">>>>>>>> TEXT: %s\n", $$->text);
|
fprintf(stderr, ">>>>>>>> TEXT: %s\n", $$->text);
|
||||||
|
|
||||||
currnode = $$;
|
currnode = $$;
|
||||||
currnode->is_root = 1;
|
currnode->is_root = 1;
|
||||||
@ -270,7 +286,7 @@ void yyerror(char const *message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct graph_node *
|
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);
|
fprintf(stderr, "parsing: %s\n", string);
|
||||||
|
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include "command_graph.h"
|
||||||
#include "command_parse.h"
|
#include "command_parse.h"
|
||||||
#include "cmdtree.h"
|
#include "command_match.h"
|
||||||
|
|
||||||
#define GRAMMAR_STR "CLI grammar sandbox\n"
|
#define GRAMMAR_STR "CLI grammar sandbox\n"
|
||||||
|
|
||||||
struct graph_node * nodegraph;
|
struct graph_node * nodegraph;
|
||||||
|
|
||||||
DEFUN (grammar_test,
|
/*
|
||||||
grammar_test_cmd,
|
char* combine_vararg(char* argv, int argc) {
|
||||||
"grammar parse .COMMAND",
|
|
||||||
GRAMMAR_STR
|
|
||||||
"command to pass to new parser\n")
|
|
||||||
{
|
|
||||||
size_t linesize = 0;
|
size_t linesize = 0;
|
||||||
for (int i = 0; i < argc; i++)
|
for (int i = 0; i < argc; i++)
|
||||||
linesize += strlen(argv[i]) + 1;
|
linesize += strlen(argv[i]) + 1;
|
||||||
@ -24,8 +21,19 @@ DEFUN (grammar_test,
|
|||||||
strcat(cat, " ");
|
strcat(cat, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
//struct graph_node *result = new_node(NUL_GN);
|
return cat;
|
||||||
cmd_parse_format_new((const char*) cat, "lol", nodegraph);
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
walk_graph(nodegraph, 0);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@ -37,8 +45,20 @@ DEFUN (grammar_test_show,
|
|||||||
GRAMMAR_STR
|
GRAMMAR_STR
|
||||||
"print current accumulated DFA\n")
|
"print current accumulated DFA\n")
|
||||||
{
|
{
|
||||||
walk_graph(nodegraph, 0);
|
walk_graph(nodegraph, 0);
|
||||||
return CMD_SUCCESS;
|
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);
|
nodegraph = new_node(NUL_GN);
|
||||||
install_element (ENABLE_NODE, &grammar_test_cmd);
|
install_element (ENABLE_NODE, &grammar_test_cmd);
|
||||||
install_element (ENABLE_NODE, &grammar_test_show_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 "bgpd/bgp_vty.h"
|
||||||
#include "vrf.h"
|
#include "vrf.h"
|
||||||
|
|
||||||
|
#include "lib/grammar_sandbox.h"
|
||||||
|
|
||||||
/* Struct VTY. */
|
/* Struct VTY. */
|
||||||
struct vty *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, &vtysh_enable_password_text_cmd);
|
||||||
install_element (CONFIG_NODE, &no_vtysh_enable_password_cmd);
|
install_element (CONFIG_NODE, &no_vtysh_enable_password_cmd);
|
||||||
|
|
||||||
|
/* grammar sandbox */
|
||||||
|
grammar_sandbox_init();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user