forked from Mirror/frr
lib: Add matching and argv support
Queries may be run against DFA's to find matching cmd_element, and argument lists may be constructed. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
a53fbbf5f0
commit
eceb106640
|
@ -6,8 +6,8 @@
|
||||||
* @author Quentin Young <qlyoung@cumulusnetworks.com>
|
* @author Quentin Young <qlyoung@cumulusnetworks.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zebra.h>
|
|
||||||
#include "command_graph.h"
|
#include "command_graph.h"
|
||||||
|
#include <zebra.h>
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
struct graph_node *
|
struct graph_node *
|
||||||
|
@ -100,7 +100,7 @@ describe_node(struct graph_node *node, char* buffer, unsigned int bufsize)
|
||||||
snprintf(buffer, bufsize, node->text);
|
snprintf(buffer, bufsize, node->text);
|
||||||
break;
|
break;
|
||||||
case NUMBER_GN:
|
case NUMBER_GN:
|
||||||
snprintf(buffer, bufsize, "%d", node->value);
|
snprintf(buffer, bufsize, "%ld", node->value);
|
||||||
break;
|
break;
|
||||||
case SELECTOR_GN:
|
case SELECTOR_GN:
|
||||||
snprintf(buffer, bufsize, "<>");
|
snprintf(buffer, bufsize, "<>");
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#ifndef COMMAND_GRAPH_H
|
#ifndef COMMAND_GRAPH_H
|
||||||
#define COMMAND_GRAPH_H
|
#define COMMAND_GRAPH_H
|
||||||
|
|
||||||
#include "vty.h"
|
#include "command.h"
|
||||||
#include "vector.h"
|
|
||||||
|
|
||||||
enum graph_node_type
|
enum graph_node_type
|
||||||
{
|
{
|
||||||
|
@ -22,18 +21,19 @@ enum graph_node_type
|
||||||
|
|
||||||
struct graph_node
|
struct graph_node
|
||||||
{
|
{
|
||||||
enum graph_node_type type;
|
enum graph_node_type type;// data type this node matches or holds
|
||||||
vector children;
|
int is_start; // whether this node is a start node
|
||||||
int is_root; // true if first token in command
|
vector children; // this node's children
|
||||||
struct graph_node * end; // pointer to end for SELECTOR_GN & OPTION_GN
|
struct graph_node * end; // pointer to end for SELECTOR_GN & OPTION_GN
|
||||||
|
|
||||||
// cmd_element struct pointer, only valid for END_GN
|
|
||||||
struct cmd_element *element;
|
|
||||||
|
|
||||||
/* various data fields for nodes */
|
|
||||||
char* text; // for WORD_GN and VARIABLE_GN
|
char* text; // for WORD_GN and VARIABLE_GN
|
||||||
long value; // for NUMBER_GN
|
long value; // for NUMBER_GN
|
||||||
long min, max; // for RANGE_GN
|
long min, max; // for RANGE_GN
|
||||||
|
|
||||||
|
/* cmd_element struct pointer, only valid for END_GN */
|
||||||
|
struct cmd_element *element;
|
||||||
|
/* used for passing arguments to command functions */
|
||||||
|
char *arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -91,4 +91,11 @@ walk_graph(struct graph_node *, int);
|
||||||
*/
|
*/
|
||||||
extern char *
|
extern char *
|
||||||
describe_node(struct graph_node *, char *, unsigned int);
|
describe_node(struct graph_node *, char *, unsigned int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the data associated with a graph_node.
|
||||||
|
* @param[out] pointer to graph_node to free
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
free_node(struct graph_node *);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,56 +1,55 @@
|
||||||
|
#include "command_match.h"
|
||||||
|
#include "command_parse.h"
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "vector.h"
|
|
||||||
#include "command_match.h"
|
|
||||||
|
|
||||||
/* prototypes */
|
/* matcher helper prototypes */
|
||||||
static int
|
static int
|
||||||
add_nexthops(struct list *, struct graph_node *);
|
add_nexthops(struct list *, struct graph_node *);
|
||||||
|
|
||||||
|
static struct list *
|
||||||
|
match_build_argv_r (struct graph_node *start, vector vline, unsigned int n);
|
||||||
|
|
||||||
|
/* token matcher prototypes */
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv4_match (const char *);
|
match_ipv4 (const char *);
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv4_prefix_match (const char *);
|
match_ipv4_prefix (const char *);
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv6_match (const char *);
|
match_ipv6 (const char *);
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv6_prefix_match (const char *);
|
match_ipv6_prefix (const char *);
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_range_match (struct graph_node *, const char *str);
|
match_range (struct graph_node *, const char *str);
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_word_match (struct graph_node *, enum filter_type, const char *);
|
match_word (struct graph_node *, enum filter_type, const char *);
|
||||||
|
|
||||||
static vector
|
static enum match_type
|
||||||
cmd_make_strvec (const char *);
|
match_number (struct graph_node *, const char *);
|
||||||
|
|
||||||
|
static enum match_type
|
||||||
|
match_variable (struct graph_node *, const char *);
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
match_token (struct graph_node *, char *, enum filter_type);
|
match_token (struct graph_node *, char *, enum filter_type);
|
||||||
|
|
||||||
static vector
|
|
||||||
cmd_make_strvec (const char *);
|
|
||||||
|
|
||||||
/* matching functions */
|
/* matching functions */
|
||||||
|
|
||||||
/**
|
struct cmd_element *
|
||||||
* Attempt to find an exact command match for a line of user input.
|
match_command (struct graph_node *start, const char *line, enum filter_type filter)
|
||||||
*
|
|
||||||
* @return cmd_element found, or NULL if there is no match.
|
|
||||||
*/
|
|
||||||
struct cmd_element
|
|
||||||
match_command (struct graph_node *start, vector *command, enum filter_type filter)
|
|
||||||
{
|
{
|
||||||
// get all possible completions
|
// get all possible completions
|
||||||
struct list completions = match_command_complete (start, command, filter);
|
struct list *completions = match_command_complete (start, line, filter);
|
||||||
|
|
||||||
// one of them should be END_GN if this command matches
|
// one of them should be END_GN if this command matches
|
||||||
struct graph_node *gn;
|
struct graph_node *gn;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
for (ALL_LIST_ELEMENTS_RO(current,node,gn))
|
for (ALL_LIST_ELEMENTS_RO(completions,node,gn))
|
||||||
{
|
{
|
||||||
if (gn->type == END_GN)
|
if (gn->type == END_GN)
|
||||||
break;
|
break;
|
||||||
|
@ -59,32 +58,11 @@ match_command (struct graph_node *start, vector *command, enum filter_type filte
|
||||||
return gn ? gn->element : NULL;
|
return gn ? gn->element : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compiles next-hops for a given line of user input.
|
|
||||||
*
|
|
||||||
* Given a string of input and a start node for a matching DFA, runs the input
|
|
||||||
* against the DFA until the input is exhausted or a mismatch is encountered.
|
|
||||||
*
|
|
||||||
* This function returns all valid next hops away from the current node.
|
|
||||||
* - If the input is a valid prefix to a longer command(s), the set of next
|
|
||||||
* hops determines what tokens are valid to follow the prefix. In other words,
|
|
||||||
* the returned list is a list of possible completions.
|
|
||||||
* - If the input matched a full command, exactly one of the next hops will be
|
|
||||||
* a node of type END_GN and its function pointer will be set.
|
|
||||||
* - If the input did not match any valid token sequence, the returned list
|
|
||||||
* will be empty (there are no transitions away from a nonexistent state).
|
|
||||||
*
|
|
||||||
* @param[in] start the start node of the DFA to match against
|
|
||||||
* @param[in] filter the filtering method
|
|
||||||
* @param[in] input the input string
|
|
||||||
* @return pointer to linked list with all possible next hops from the last
|
|
||||||
* matched token. If this is empty, the input did not match any command.
|
|
||||||
*/
|
|
||||||
struct list *
|
struct list *
|
||||||
match_command_complete (struct graph_node *start, const char *input, enum filter_type filter)
|
match_command_complete (struct graph_node *start, const char *line, enum filter_type filter)
|
||||||
{
|
{
|
||||||
// break command
|
// vectorize command line
|
||||||
vector command = cmd_make_strvec (input);
|
vector vline = cmd_make_strvec (line);
|
||||||
|
|
||||||
// pointer to next input token to match
|
// pointer to next input token to match
|
||||||
char *token;
|
char *token;
|
||||||
|
@ -101,13 +79,13 @@ match_command_complete (struct graph_node *start, const char *input, enum filter
|
||||||
add_nexthops(next, start);
|
add_nexthops(next, start);
|
||||||
|
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
for (idx = 0; idx < vector_active(command) && next->count > 0; idx++)
|
for (idx = 0; idx < vector_active(vline) && next->count > 0; idx++)
|
||||||
{
|
{
|
||||||
list_free (current);
|
list_free (current);
|
||||||
current = next;
|
current = next;
|
||||||
next = list_new();
|
next = list_new();
|
||||||
|
|
||||||
token = vector_slot(command, idx);
|
token = vector_slot(vline, idx);
|
||||||
|
|
||||||
list_delete_all_node(matched);
|
list_delete_all_node(matched);
|
||||||
|
|
||||||
|
@ -131,14 +109,15 @@ match_command_complete (struct graph_node *start, const char *input, enum filter
|
||||||
list_free (current);
|
list_free (current);
|
||||||
list_free (matched);
|
list_free (matched);
|
||||||
|
|
||||||
|
cmd_free_strvec(vline);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds all children that are reachable by one parser hop
|
* Adds all children that are reachable by one parser hop
|
||||||
* to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN
|
* to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN
|
||||||
* nodes are treated as though their children are attached
|
* nodes are treated as transparent.
|
||||||
* to their parent.
|
|
||||||
*
|
*
|
||||||
* @param[out] l the list to add the children to
|
* @param[out] l the list to add the children to
|
||||||
* @param[in] node the node to get the children of
|
* @param[in] node the node to get the children of
|
||||||
|
@ -166,24 +145,73 @@ add_nexthops(struct list *l, struct graph_node *node)
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
struct list *
|
||||||
* Build the appropriate argv for a matched command.
|
match_build_argv (const char *line, struct cmd_element *element)
|
||||||
*
|
|
||||||
* @param[in] command the command element
|
|
||||||
* @param[in] the input line matching this command
|
|
||||||
* @param[out] argv
|
|
||||||
* @return argc
|
|
||||||
*
|
|
||||||
int
|
|
||||||
match_build_argv (struct cmd_element *command, vector *input, char *argv)
|
|
||||||
{
|
{
|
||||||
// build individual command graph
|
struct list *argv = NULL;
|
||||||
|
|
||||||
|
// parse command
|
||||||
struct graph_node *start = new_node(NUL_GN);
|
struct graph_node *start = new_node(NUL_GN);
|
||||||
cmd_parse_format(start, command->string);
|
parse_command_format(start, element);
|
||||||
|
|
||||||
|
vector vline = cmd_make_strvec (line);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < vector_active(start->children); i++)
|
||||||
|
{
|
||||||
|
// call recursive builder on each starting child
|
||||||
|
argv = match_build_argv_r (vector_slot(start->children, i), vline, 0);
|
||||||
|
// if any of them succeed, return their argv (there should only be one)
|
||||||
|
if (argv) break;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct list *
|
||||||
|
match_build_argv_r (struct graph_node *start, vector vline, unsigned int n)
|
||||||
|
{
|
||||||
|
// if we don't match this node, die
|
||||||
|
if (match_token(start, vector_slot(vline, n), FILTER_STRICT) == no_match)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// some stuffs we need
|
||||||
|
struct list *argv = list_new();
|
||||||
|
struct graph_node *gn;
|
||||||
|
struct listnode *ln;
|
||||||
|
|
||||||
|
// append current arg
|
||||||
|
start->arg = strdup(vector_slot(vline, n));
|
||||||
|
listnode_add(argv, start);
|
||||||
|
|
||||||
|
// get all possible nexthops
|
||||||
|
struct list *next = list_new();
|
||||||
|
add_nexthops(next, start);
|
||||||
|
|
||||||
|
// check if one of them is END_GN
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(next,ln,gn))
|
||||||
|
{
|
||||||
|
if (gn->type == END_GN){
|
||||||
|
fprintf(stderr, "Hit END_GN while searching next set of node with text %s\n", start->text);
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have no more input, why even live?
|
||||||
|
if (n+1 >= vector_active(vline)) return NULL;
|
||||||
|
|
||||||
|
// otherwise recurse on all nexthops
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(next,ln,gn))
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < n; i++) fprintf(stderr, "\t");
|
||||||
|
fprintf(stderr, "Recursing on node %s for token %s\n", gn->text, (char*) vector_slot(vline, n+1));
|
||||||
|
struct list *result = match_build_argv_r (gn, vline, n+1);
|
||||||
|
if (result != NULL) {
|
||||||
|
list_add_list (argv, result);
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* matching utility functions */
|
/* matching utility functions */
|
||||||
|
|
||||||
|
@ -192,21 +220,22 @@ match_token (struct graph_node *node, char *token, enum filter_type filter)
|
||||||
{
|
{
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case WORD_GN:
|
case WORD_GN:
|
||||||
return cmd_word_match (node, filter, token);
|
return match_word (node, filter, token);
|
||||||
case IPV4_GN:
|
case IPV4_GN:
|
||||||
return cmd_ipv4_match (token);
|
return match_ipv4 (token);
|
||||||
case IPV4_PREFIX_GN:
|
case IPV4_PREFIX_GN:
|
||||||
return cmd_ipv4_prefix_match (token);
|
return match_ipv4_prefix (token);
|
||||||
case IPV6_GN:
|
case IPV6_GN:
|
||||||
return cmd_ipv6_match (token);
|
return match_ipv6 (token);
|
||||||
case IPV6_PREFIX_GN:
|
case IPV6_PREFIX_GN:
|
||||||
return cmd_ipv6_prefix_match (token);
|
return match_ipv6_prefix (token);
|
||||||
case RANGE_GN:
|
case RANGE_GN:
|
||||||
return cmd_range_match (node, token);
|
return match_range (node, token);
|
||||||
case NUMBER_GN:
|
case NUMBER_GN:
|
||||||
return cmd_number_match (node, token);
|
return match_number (node, token);
|
||||||
case VARIABLE_GN:
|
case VARIABLE_GN:
|
||||||
return cmd_variable_match (node, token);
|
return match_variable (node, token);
|
||||||
|
case END_GN:
|
||||||
default:
|
default:
|
||||||
return no_match;
|
return no_match;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +245,7 @@ match_token (struct graph_node *node, char *token, enum filter_type filter)
|
||||||
#define IPV4_PREFIX_STR "0123456789./"
|
#define IPV4_PREFIX_STR "0123456789./"
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv4_match (const char *str)
|
match_ipv4 (const char *str)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin_dummy;
|
struct sockaddr_in sin_dummy;
|
||||||
|
|
||||||
|
@ -233,7 +262,7 @@ cmd_ipv4_match (const char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv4_prefix_match (const char *str)
|
match_ipv4_prefix (const char *str)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin_dummy;
|
struct sockaddr_in sin_dummy;
|
||||||
const char *delim = "/\0";
|
const char *delim = "/\0";
|
||||||
|
@ -274,7 +303,7 @@ cmd_ipv4_prefix_match (const char *str)
|
||||||
#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
|
#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv6_match (const char *str)
|
match_ipv6 (const char *str)
|
||||||
{
|
{
|
||||||
struct sockaddr_in6 sin6_dummy;
|
struct sockaddr_in6 sin6_dummy;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -294,7 +323,7 @@ cmd_ipv6_match (const char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_ipv6_prefix_match (const char *str)
|
match_ipv6_prefix (const char *str)
|
||||||
{
|
{
|
||||||
struct sockaddr_in6 sin6_dummy;
|
struct sockaddr_in6 sin6_dummy;
|
||||||
const char *delim = "/\0";
|
const char *delim = "/\0";
|
||||||
|
@ -332,10 +361,10 @@ cmd_ipv6_prefix_match (const char *str)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_range_match (struct graph_node *rangenode, const char *str)
|
match_range (struct graph_node *rangenode, const char *str)
|
||||||
{
|
{
|
||||||
char *endptr = NULL;
|
char *endptr = NULL;
|
||||||
signed long long val;
|
signed long val;
|
||||||
|
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -352,11 +381,10 @@ cmd_range_match (struct graph_node *rangenode, const char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum match_type
|
static enum match_type
|
||||||
cmd_word_match(struct graph_node *wordnode,
|
match_word(struct graph_node *wordnode,
|
||||||
enum filter_type filter,
|
enum filter_type filter,
|
||||||
const char *word)
|
const char *word)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (filter == FILTER_RELAXED)
|
if (filter == FILTER_RELAXED)
|
||||||
{
|
{
|
||||||
if (!word || !strlen(word))
|
if (!word || !strlen(word))
|
||||||
|
@ -375,7 +403,8 @@ cmd_word_match(struct graph_node *wordnode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_number_match(struct graph_node *numnode, const char *word)
|
static enum match_type
|
||||||
|
match_number(struct graph_node *numnode, const char *word)
|
||||||
{
|
{
|
||||||
if (!strcmp("\0", word)) return no_match;
|
if (!strcmp("\0", word)) return no_match;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
@ -384,57 +413,11 @@ cmd_number_match(struct graph_node *numnode, const char *word)
|
||||||
return num == numnode->value ? exact_match : no_match;
|
return num == numnode->value ? exact_match : no_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_variable_match(struct graph_node *varnode, const char *word)
|
#define VARIABLE_ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"
|
||||||
|
|
||||||
|
static enum match_type
|
||||||
|
match_variable(struct graph_node *varnode, const char *word)
|
||||||
{
|
{
|
||||||
// I guess this matches whatever?
|
return strlen(word) == strspn(word, VARIABLE_ALPHABET) && isalpha(word[0]) ?
|
||||||
return exact_match;
|
exact_match : no_match;
|
||||||
}
|
|
||||||
|
|
||||||
static vector
|
|
||||||
cmd_make_strvec (const char *string)
|
|
||||||
{
|
|
||||||
const char *cp, *start;
|
|
||||||
char *token;
|
|
||||||
int strlen;
|
|
||||||
vector strvec;
|
|
||||||
|
|
||||||
if (string == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
cp = string;
|
|
||||||
|
|
||||||
/* Skip white spaces. */
|
|
||||||
while (isspace ((int) *cp) && *cp != '\0')
|
|
||||||
cp++;
|
|
||||||
|
|
||||||
/* Return if there is only white spaces */
|
|
||||||
if (*cp == '\0')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (*cp == '!' || *cp == '#')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Prepare return vector. */
|
|
||||||
strvec = vector_init (VECTOR_MIN_SIZE);
|
|
||||||
|
|
||||||
/* Copy each command piece and set into vector. */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
start = cp;
|
|
||||||
while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
|
|
||||||
*cp != '\0')
|
|
||||||
cp++;
|
|
||||||
strlen = cp - start;
|
|
||||||
token = XMALLOC (MTYPE_STRVEC, strlen + 1);
|
|
||||||
memcpy (token, start, strlen);
|
|
||||||
*(token + strlen) = '\0';
|
|
||||||
vector_set (strvec, token);
|
|
||||||
|
|
||||||
while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
|
|
||||||
*cp != '\0')
|
|
||||||
cp++;
|
|
||||||
|
|
||||||
if (*cp == '\0')
|
|
||||||
return strvec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
#ifndef COMMAND_MATCH_H
|
#ifndef COMMAND_MATCH_H
|
||||||
#define COMMAND_MATCH_H
|
#define COMMAND_MATCH_H
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
#include "command_graph.h"
|
#include "command_graph.h"
|
||||||
#include "linklist.h"
|
#include "linklist.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter types. These tell the parser whether to allow
|
/** These definitions exist in command.c in
|
||||||
* partial matching on tokens.
|
* the current engine but will be relocated
|
||||||
*/
|
* here in the new engine*/
|
||||||
enum filter_type
|
enum filter_type
|
||||||
{
|
{
|
||||||
FILTER_RELAXED,
|
FILTER_RELAXED,
|
||||||
FILTER_STRICT
|
FILTER_STRICT
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/* matcher result value. */
|
||||||
* Command matcher result value.
|
|
||||||
*/
|
|
||||||
enum matcher_rv
|
enum matcher_rv
|
||||||
{
|
{
|
||||||
MATCHER_OK,
|
MATCHER_OK,
|
||||||
|
@ -34,8 +33,8 @@ enum match_type
|
||||||
partly_match,
|
partly_match,
|
||||||
exact_match
|
exact_match
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* Defines which matcher_rv values constitute
|
/* Defines which matcher_rv values constitute
|
||||||
* an error. Should be used against matcher_rv
|
* an error. Should be used against matcher_rv
|
||||||
* return values to do basic error checking.
|
* return values to do basic error checking.
|
||||||
*/
|
*/
|
||||||
|
@ -46,7 +45,46 @@ enum match_type
|
||||||
|| (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
|
|| (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to find an exact command match for a line of user input.
|
||||||
|
*
|
||||||
|
* @return cmd_element found, or NULL if there is no match.
|
||||||
|
*/
|
||||||
|
struct cmd_element *
|
||||||
|
match_command (struct graph_node *, const char *, enum filter_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles next-hops for a given line of user input.
|
||||||
|
*
|
||||||
|
* Given a string of input and a start node for a matching DFA, runs the input
|
||||||
|
* against the DFA until the input is exhausted or a mismatch is encountered.
|
||||||
|
*
|
||||||
|
* This function returns all valid next hops away from the current node.
|
||||||
|
* - If the input is a valid prefix to a longer command(s), the set of next
|
||||||
|
* hops determines what tokens are valid to follow the prefix. In other words,
|
||||||
|
* the returned list is a list of possible completions.
|
||||||
|
* - If the input matched a full command, exactly one of the next hops will be
|
||||||
|
* a node of type END_GN and its function pointer will be set.
|
||||||
|
* - If the input did not match any valid token sequence, the returned list
|
||||||
|
* will be empty (there are no transitions away from a nonexistent state).
|
||||||
|
*
|
||||||
|
* @param[in] start the start node of the DFA to match against
|
||||||
|
* @param[in] filter the filtering method
|
||||||
|
* @param[in] input the input string
|
||||||
|
* @return pointer to linked list with all possible next hops from the last
|
||||||
|
* matched token. If this is empty, the input did not match any command.
|
||||||
|
*/
|
||||||
struct list *
|
struct list *
|
||||||
match_command (struct graph_node *, enum filter_type, const char *);
|
match_command_complete (struct graph_node *, const char *, enum filter_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an argument list given a cmd_element and a matching input line.
|
||||||
|
*
|
||||||
|
* @param[in] input line
|
||||||
|
* @param[in] cmd_element struct
|
||||||
|
* @return pointer to argument linked list
|
||||||
|
*/
|
||||||
|
struct list *
|
||||||
|
match_build_argv (const char *, struct cmd_element *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,437 +0,0 @@
|
||||||
/*
|
|
||||||
* Zebra configuration command interface routine
|
|
||||||
* Copyright (C) 1997, 98 Kunihiro Ishiguro
|
|
||||||
*
|
|
||||||
* This file is part of GNU Zebra.
|
|
||||||
*
|
|
||||||
* GNU Zebra is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published
|
|
||||||
* by the Free Software Foundation; either version 2, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with GNU Zebra; see the file COPYING. If not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _ZEBRA_COMMAND_H
|
|
||||||
#define _ZEBRA_COMMAND_H
|
|
||||||
|
|
||||||
#include "vector.h"
|
|
||||||
#include "vty.h"
|
|
||||||
#include "lib/route_types.h"
|
|
||||||
|
|
||||||
/* Host configuration variable */
|
|
||||||
struct host
|
|
||||||
{
|
|
||||||
/* Host name of this router. */
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
/* Password for vty interface. */
|
|
||||||
char *password;
|
|
||||||
char *password_encrypt;
|
|
||||||
|
|
||||||
/* Enable password */
|
|
||||||
char *enable;
|
|
||||||
char *enable_encrypt;
|
|
||||||
|
|
||||||
/* System wide terminal lines. */
|
|
||||||
int lines;
|
|
||||||
|
|
||||||
/* Log filename. */
|
|
||||||
char *logfile;
|
|
||||||
|
|
||||||
/* config file name of this host */
|
|
||||||
char *config;
|
|
||||||
|
|
||||||
/* Flags for services */
|
|
||||||
int advanced;
|
|
||||||
int encrypt;
|
|
||||||
|
|
||||||
/* Banner configuration. */
|
|
||||||
const char *motd;
|
|
||||||
char *motdfile;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* There are some command levels which called from command node. */
|
|
||||||
enum node_type
|
|
||||||
{
|
|
||||||
AUTH_NODE, /* Authentication mode of vty interface. */
|
|
||||||
RESTRICTED_NODE, /* Restricted view mode */
|
|
||||||
VIEW_NODE, /* View node. Default mode of vty interface. */
|
|
||||||
AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
|
|
||||||
ENABLE_NODE, /* Enable node. */
|
|
||||||
CONFIG_NODE, /* Config node. Default mode of config file. */
|
|
||||||
SERVICE_NODE, /* Service node. */
|
|
||||||
DEBUG_NODE, /* Debug node. */
|
|
||||||
VRF_DEBUG_NODE, /* Vrf Debug node. */
|
|
||||||
AAA_NODE, /* AAA node. */
|
|
||||||
KEYCHAIN_NODE, /* Key-chain node. */
|
|
||||||
KEYCHAIN_KEY_NODE, /* Key-chain key node. */
|
|
||||||
VRF_NODE, /* VRF mode node. */
|
|
||||||
INTERFACE_NODE, /* Interface mode node. */
|
|
||||||
ZEBRA_NODE, /* zebra connection node. */
|
|
||||||
TABLE_NODE, /* rtm_table selection node. */
|
|
||||||
RIP_NODE, /* RIP protocol mode node. */
|
|
||||||
RIPNG_NODE, /* RIPng protocol mode node. */
|
|
||||||
BGP_NODE, /* BGP protocol mode which includes BGP4+ */
|
|
||||||
BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
|
|
||||||
BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */
|
|
||||||
BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
|
|
||||||
BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */
|
|
||||||
BGP_IPV6_NODE, /* BGP IPv6 address family */
|
|
||||||
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
|
|
||||||
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
|
|
||||||
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
|
|
||||||
OSPF_NODE, /* OSPF protocol mode */
|
|
||||||
OSPF6_NODE, /* OSPF protocol for IPv6 mode */
|
|
||||||
ISIS_NODE, /* ISIS protocol mode */
|
|
||||||
PIM_NODE, /* PIM protocol mode */
|
|
||||||
MASC_NODE, /* MASC for multicast. */
|
|
||||||
IRDP_NODE, /* ICMP Router Discovery Protocol mode. */
|
|
||||||
IP_NODE, /* Static ip route node. */
|
|
||||||
ACCESS_NODE, /* Access list node. */
|
|
||||||
PREFIX_NODE, /* Prefix list node. */
|
|
||||||
ACCESS_IPV6_NODE, /* Access list node. */
|
|
||||||
PREFIX_IPV6_NODE, /* Prefix list node. */
|
|
||||||
AS_LIST_NODE, /* AS list node. */
|
|
||||||
COMMUNITY_LIST_NODE, /* Community list node. */
|
|
||||||
RMAP_NODE, /* Route map node. */
|
|
||||||
SMUX_NODE, /* SNMP configuration node. */
|
|
||||||
DUMP_NODE, /* Packet dump node. */
|
|
||||||
FORWARDING_NODE, /* IP forwarding node. */
|
|
||||||
PROTOCOL_NODE, /* protocol filtering node */
|
|
||||||
VTY_NODE, /* Vty node. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Node which has some commands and prompt string and configuration
|
|
||||||
function pointer . */
|
|
||||||
struct cmd_node
|
|
||||||
{
|
|
||||||
/* Node index. */
|
|
||||||
enum node_type node;
|
|
||||||
|
|
||||||
/* Prompt character at vty interface. */
|
|
||||||
const char *prompt;
|
|
||||||
|
|
||||||
/* Is this node's configuration goes to vtysh ? */
|
|
||||||
int vtysh;
|
|
||||||
|
|
||||||
/* Node's configuration write function */
|
|
||||||
int (*func) (struct vty *);
|
|
||||||
|
|
||||||
/* Start of this node's command graph */
|
|
||||||
struct graph_node * cmd_graph;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CMD_ATTR_DEPRECATED = 1,
|
|
||||||
CMD_ATTR_HIDDEN,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Structure of command element. */
|
|
||||||
struct cmd_element
|
|
||||||
{
|
|
||||||
const char *string; // command format string
|
|
||||||
const char *doc; // command doc string
|
|
||||||
int daemon; // daemon associated with command
|
|
||||||
u_char attr; // Command attributes
|
|
||||||
|
|
||||||
// function for this command
|
|
||||||
int (*func) (struct cmd_element *, struct vty *, int, const char *[]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* argument to be recorded on argv[] if it's not a literal */
|
|
||||||
#define TERMINAL_RECORD(t) ((t) >= TERMINAL_OPTION)
|
|
||||||
|
|
||||||
/* Return value of the commands. */
|
|
||||||
#define CMD_SUCCESS 0
|
|
||||||
#define CMD_WARNING 1
|
|
||||||
#define CMD_ERR_NO_MATCH 2
|
|
||||||
#define CMD_ERR_AMBIGUOUS 3
|
|
||||||
#define CMD_ERR_INCOMPLETE 4
|
|
||||||
#define CMD_ERR_EXEED_ARGC_MAX 5
|
|
||||||
#define CMD_ERR_NOTHING_TODO 6
|
|
||||||
#define CMD_COMPLETE_FULL_MATCH 7
|
|
||||||
#define CMD_COMPLETE_MATCH 8
|
|
||||||
#define CMD_COMPLETE_LIST_MATCH 9
|
|
||||||
#define CMD_SUCCESS_DAEMON 10
|
|
||||||
#define CMD_ERR_NO_FILE 11
|
|
||||||
|
|
||||||
/* Argc max counts. */
|
|
||||||
#define CMD_ARGC_MAX 25
|
|
||||||
|
|
||||||
/* Turn off these macros when uisng cpp with extract.pl */
|
|
||||||
#ifndef VTYSH_EXTRACT_PL
|
|
||||||
|
|
||||||
/* helper defines for end-user DEFUN* macros */
|
|
||||||
#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
|
|
||||||
struct cmd_element cmdname = \
|
|
||||||
{ \
|
|
||||||
.string = cmdstr, \
|
|
||||||
.doc = helpstr, \
|
|
||||||
.daemon = dnum, \
|
|
||||||
.attr = attrs, \
|
|
||||||
.func = funcname, \
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFUN_CMD_FUNC_DECL(funcname) \
|
|
||||||
static int funcname (struct cmd_element *, struct vty *, int, const char *[]);
|
|
||||||
|
|
||||||
#define DEFUN_CMD_FUNC_TEXT(funcname) \
|
|
||||||
static int funcname \
|
|
||||||
(struct cmd_element *self __attribute__ ((unused)), \
|
|
||||||
struct vty *vty __attribute__ ((unused)), \
|
|
||||||
int argc __attribute__ ((unused)), \
|
|
||||||
const char *argv[] __attribute__ ((unused)) )
|
|
||||||
|
|
||||||
/* DEFUN for vty command interface.
|
|
||||||
*
|
|
||||||
* DEFUN(funcname, cmdname, cmdstr, helpstr)
|
|
||||||
*
|
|
||||||
* funcname
|
|
||||||
* ========
|
|
||||||
* Name of the function that will be defined.
|
|
||||||
*
|
|
||||||
* cmdname
|
|
||||||
* =======
|
|
||||||
* Name of the struct that will be defined for the command.
|
|
||||||
*
|
|
||||||
* cmdstr
|
|
||||||
* ======
|
|
||||||
* The cmdstr defines the command syntax. It is used by the vty subsystem
|
|
||||||
* and vtysh to perform matching and completion in the CLI.
|
|
||||||
*
|
|
||||||
* Syntax Summary
|
|
||||||
* ----------------
|
|
||||||
* <summary>
|
|
||||||
*
|
|
||||||
* Abbreviated BNF
|
|
||||||
* ----------------
|
|
||||||
* <bnf>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* helpstr
|
|
||||||
* =======
|
|
||||||
*
|
|
||||||
* The helpstr is used to show a short explantion for the commands that
|
|
||||||
* are available when the user presses '?' on the CLI. It is the concatenation
|
|
||||||
* of the helpstrings for all the tokens that make up the command.
|
|
||||||
*
|
|
||||||
* There should be one helpstring for each token in the cmdstr except those
|
|
||||||
* containing other tokens, like Multiple or Keyword Tokens. For those, there
|
|
||||||
* will only be the helpstrings of the contained tokens.
|
|
||||||
*
|
|
||||||
* The individual helpstrings are expected to be in the same order as their
|
|
||||||
* respective Tokens appear in the cmdstr. They should each be terminated with
|
|
||||||
* a linefeed. The last helpstring should be terminated with a linefeed as well.
|
|
||||||
*
|
|
||||||
* Care should also be taken to avoid having similar tokens with different
|
|
||||||
* helpstrings. Imagine e.g. the commands "show ip ospf" and "show ip bgp".
|
|
||||||
* they both contain a helpstring for "show", but only one will be displayed
|
|
||||||
* when the user enters "sh?". If those two helpstrings differ, it is not
|
|
||||||
* defined which one will be shown and the behavior is therefore unpredictable.
|
|
||||||
*/
|
|
||||||
#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_FUNC_DECL(funcname) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
|
|
||||||
DEFUN_CMD_FUNC_TEXT(funcname)
|
|
||||||
|
|
||||||
#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
|
|
||||||
DEFUN_CMD_FUNC_DECL(funcname) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
|
|
||||||
DEFUN_CMD_FUNC_TEXT(funcname)
|
|
||||||
|
|
||||||
#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
|
|
||||||
|
|
||||||
#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \
|
|
||||||
|
|
||||||
/* DEFUN_NOSH for commands that vtysh should ignore */
|
|
||||||
#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN(funcname, cmdname, cmdstr, helpstr)
|
|
||||||
|
|
||||||
/* DEFSH for vtysh. */
|
|
||||||
#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \
|
|
||||||
|
|
||||||
#define DEFSH_HIDDEN(daemon, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon) \
|
|
||||||
|
|
||||||
/* DEFUN + DEFSH */
|
|
||||||
#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_FUNC_DECL(funcname) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \
|
|
||||||
DEFUN_CMD_FUNC_TEXT(funcname)
|
|
||||||
|
|
||||||
/* DEFUN + DEFSH with attributes */
|
|
||||||
#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \
|
|
||||||
DEFUN_CMD_FUNC_DECL(funcname) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \
|
|
||||||
DEFUN_CMD_FUNC_TEXT(funcname)
|
|
||||||
|
|
||||||
#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
|
|
||||||
|
|
||||||
#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED)
|
|
||||||
|
|
||||||
/* ALIAS macro which define existing command's alias. */
|
|
||||||
#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
|
|
||||||
|
|
||||||
#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0)
|
|
||||||
|
|
||||||
#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0)
|
|
||||||
|
|
||||||
#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0)
|
|
||||||
|
|
||||||
#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon)
|
|
||||||
|
|
||||||
#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon)
|
|
||||||
|
|
||||||
#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
|
|
||||||
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon)
|
|
||||||
|
|
||||||
#endif /* VTYSH_EXTRACT_PL */
|
|
||||||
|
|
||||||
/* Some macroes */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sometimes #defines create maximum values that
|
|
||||||
* need to have strings created from them that
|
|
||||||
* allow the parser to match against them.
|
|
||||||
* These macros allow that.
|
|
||||||
*/
|
|
||||||
#define CMD_CREATE_STR(s) CMD_CREATE_STR_HELPER(s)
|
|
||||||
#define CMD_CREATE_STR_HELPER(s) #s
|
|
||||||
#define CMD_RANGE_STR(a,s) "<" CMD_CREATE_STR(a) "-" CMD_CREATE_STR(s) ">"
|
|
||||||
|
|
||||||
/* Common descriptions. */
|
|
||||||
#define SHOW_STR "Show running system information\n"
|
|
||||||
#define IP_STR "IP information\n"
|
|
||||||
#define IPV6_STR "IPv6 information\n"
|
|
||||||
#define NO_STR "Negate a command or set its defaults\n"
|
|
||||||
#define REDIST_STR "Redistribute information from another routing protocol\n"
|
|
||||||
#define CLEAR_STR "Reset functions\n"
|
|
||||||
#define RIP_STR "RIP information\n"
|
|
||||||
#define BGP_STR "BGP information\n"
|
|
||||||
#define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n"
|
|
||||||
#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
|
|
||||||
#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
|
|
||||||
#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
|
|
||||||
#define OSPF_STR "OSPF information\n"
|
|
||||||
#define NEIGHBOR_STR "Specify neighbor router\n"
|
|
||||||
#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
|
|
||||||
#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
|
|
||||||
#define ROUTER_STR "Enable a routing process\n"
|
|
||||||
#define AS_STR "AS number\n"
|
|
||||||
#define MBGP_STR "MBGP information\n"
|
|
||||||
#define MATCH_STR "Match values from routing table\n"
|
|
||||||
#define SET_STR "Set values in destination routing protocol\n"
|
|
||||||
#define OUT_STR "Filter outgoing routing updates\n"
|
|
||||||
#define IN_STR "Filter incoming routing updates\n"
|
|
||||||
#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
|
|
||||||
#define OSPF6_NUMBER_STR "Specify by number\n"
|
|
||||||
#define INTERFACE_STR "Interface infomation\n"
|
|
||||||
#define IFNAME_STR "Interface name(e.g. ep0)\n"
|
|
||||||
#define IP6_STR "IPv6 Information\n"
|
|
||||||
#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
|
|
||||||
#define OSPF6_ROUTER_STR "Enable a routing process\n"
|
|
||||||
#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
|
|
||||||
#define SECONDS_STR "<1-65535> Seconds\n"
|
|
||||||
#define ROUTE_STR "Routing Table\n"
|
|
||||||
#define PREFIX_LIST_STR "Build a prefix list\n"
|
|
||||||
#define OSPF6_DUMP_TYPE_LIST \
|
|
||||||
"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
|
|
||||||
#define ISIS_STR "IS-IS information\n"
|
|
||||||
#define AREA_TAG_STR "[area tag]\n"
|
|
||||||
#define COMMUNITY_AANN_STR "Community number where AA and NN are <0-65535>\n"
|
|
||||||
#define COMMUNITY_VAL_STR "Community number in AA:NN format (where AA and NN are <0-65535>) or local-AS|no-advertise|no-export|internet or additive\n"
|
|
||||||
|
|
||||||
#define CONF_BACKUP_EXT ".sav"
|
|
||||||
|
|
||||||
/* IPv4 only machine should not accept IPv6 address for peer's IP
|
|
||||||
address. So we replace VTY command string like below. */
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) "
|
|
||||||
#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) "
|
|
||||||
#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n"
|
|
||||||
#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) "
|
|
||||||
#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) "
|
|
||||||
#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n"
|
|
||||||
#define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n"
|
|
||||||
#else
|
|
||||||
#define NEIGHBOR_CMD "neighbor A.B.C.D "
|
|
||||||
#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D "
|
|
||||||
#define NEIGHBOR_ADDR_STR "Neighbor address\n"
|
|
||||||
#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) "
|
|
||||||
#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) "
|
|
||||||
#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
|
|
||||||
/* Dynamic neighbor (listen range) configuration */
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
#define LISTEN_RANGE_CMD "bgp listen range (A.B.C.D/M|X:X::X:X/M) "
|
|
||||||
#define LISTEN_RANGE_ADDR_STR "Neighbor address\nNeighbor IPv6 address\n"
|
|
||||||
#else
|
|
||||||
#define LISTEN_RANGE_CMD "bgp listen range A.B.C.D/M "
|
|
||||||
#define LISTEN_RANGE_ADDR_STR "Neighbor address\n"
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
|
|
||||||
/* Prototypes. */
|
|
||||||
extern void install_node (struct cmd_node *, int (*) (struct vty *));
|
|
||||||
extern void install_default (enum node_type);
|
|
||||||
extern void install_element (enum node_type, struct cmd_element *);
|
|
||||||
|
|
||||||
/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
|
|
||||||
string with a space between each element (allocated using
|
|
||||||
XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */
|
|
||||||
extern char *argv_concat (const char **argv, int argc, int shift);
|
|
||||||
|
|
||||||
extern vector cmd_make_strvec (const char *);
|
|
||||||
extern void cmd_free_strvec (vector);
|
|
||||||
extern vector cmd_describe_command (vector, struct vty *, int *status);
|
|
||||||
extern char **cmd_complete_command (vector, struct vty *, int *status);
|
|
||||||
extern char **cmd_complete_command_lib (vector, struct vty *, int *status, int islib);
|
|
||||||
extern const char *cmd_prompt (enum node_type);
|
|
||||||
extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node);
|
|
||||||
extern int config_from_file (struct vty *, FILE *, unsigned int *line_num);
|
|
||||||
extern enum node_type node_parent (enum node_type);
|
|
||||||
extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int);
|
|
||||||
extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
|
|
||||||
extern void cmd_init (int);
|
|
||||||
extern void cmd_terminate (void);
|
|
||||||
|
|
||||||
/* Export typical functions. */
|
|
||||||
extern struct cmd_element config_end_cmd;
|
|
||||||
extern struct cmd_element config_exit_cmd;
|
|
||||||
extern struct cmd_element config_quit_cmd;
|
|
||||||
extern struct cmd_element config_help_cmd;
|
|
||||||
extern struct cmd_element config_list_cmd;
|
|
||||||
extern char *host_config_file (void);
|
|
||||||
extern void host_config_set (const char *);
|
|
||||||
|
|
||||||
extern void print_version (const char *);
|
|
||||||
|
|
||||||
extern int cmd_banner_motd_file (const char *);
|
|
||||||
|
|
||||||
/* struct host global, ick */
|
|
||||||
extern struct host host;
|
|
||||||
|
|
||||||
/* "<cr>" global */
|
|
||||||
extern char *command_cr;
|
|
||||||
#endif /* _ZEBRA_COMMAND_H */
|
|
|
@ -9,22 +9,24 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%{
|
%{
|
||||||
#include "command_graph.h"
|
|
||||||
#include "command_new.h"
|
|
||||||
|
|
||||||
extern int yylex(void);
|
extern int yylex(void);
|
||||||
extern void yyerror(const char *);
|
extern void yyerror(const char *);
|
||||||
|
|
||||||
// compile with debugging facilities
|
// compile with debugging facilities
|
||||||
#define YYDEBUG 1
|
#define YYDEBUG 1
|
||||||
%}
|
%}
|
||||||
|
%code requires {
|
||||||
|
#include "command.h"
|
||||||
|
#include "command_graph.h"
|
||||||
|
}
|
||||||
%code provides {
|
%code provides {
|
||||||
extern struct
|
|
||||||
graph_node *cmd_parse_format(const char *, const char *, struct graph_node *);
|
|
||||||
extern void
|
extern void
|
||||||
set_buffer_string(const char *);
|
set_buffer_string(const char *);
|
||||||
|
struct graph_node *
|
||||||
|
parse_command_format(struct graph_node *, struct cmd_element *);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* valid types for tokens */
|
/* valid types for tokens */
|
||||||
%union{
|
%union{
|
||||||
int integer;
|
int integer;
|
||||||
|
@ -45,7 +47,7 @@ struct graph_node *optnode_start, // start node for option set
|
||||||
struct graph_node *selnode_start, // start node for selector set
|
struct graph_node *selnode_start, // start node for selector set
|
||||||
*selnode_end; // end node for selector set
|
*selnode_end; // end node for selector set
|
||||||
|
|
||||||
const struct cmd_element *command; // command we're parsing
|
struct cmd_element *command; // command we're parsing
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%token <node> WORD
|
%token <node> WORD
|
||||||
|
@ -86,12 +88,16 @@ start: sentence_root
|
||||||
struct graph_node *end = new_node(END_GN);
|
struct graph_node *end = new_node(END_GN);
|
||||||
end->element = command;
|
end->element = command;
|
||||||
|
|
||||||
|
// ensure there are no END_GN children
|
||||||
|
for (unsigned int i = 0; i < vector_active(currnode->children); i++)
|
||||||
|
{
|
||||||
|
struct graph_node *child = vector_slot(currnode->children, i);
|
||||||
|
if (child->type == END_GN)
|
||||||
|
yyerror("Duplicate command.");
|
||||||
|
}
|
||||||
|
|
||||||
// add node
|
// add node
|
||||||
end = add_node(currnode, end);
|
end = add_node(currnode, end);
|
||||||
|
|
||||||
// check that we did not get back an existing node
|
|
||||||
if (!strcmp(command->string, end->element->string)
|
|
||||||
yyerror("Duplicate command.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sentence_root: WORD
|
sentence_root: WORD
|
||||||
|
@ -166,12 +172,7 @@ placeholder_token:
|
||||||
// get the numbers out
|
// get the numbers out
|
||||||
strsep(&yylval.string, "(-)");
|
strsep(&yylval.string, "(-)");
|
||||||
$$->min = atoi( strsep(&yylval.string, "(-)") );
|
$$->min = atoi( strsep(&yylval.string, "(-)") );
|
||||||
strsep(&yylval.string, "(-)");
|
|
||||||
$$->max = atoi( strsep(&yylval.string, "(-)") );
|
$$->max = atoi( strsep(&yylval.string, "(-)") );
|
||||||
|
|
||||||
// we could do this a variety of ways with either
|
|
||||||
// the lexer or the parser, but this is the simplest
|
|
||||||
// and involves the least amount of free()
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -304,9 +305,9 @@ void yyerror(char const *message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct graph_node *
|
struct graph_node *
|
||||||
cmd_parse_format(struct graph_node *start, struct cmd_element *cmd)
|
parse_command_format(struct graph_node *start, struct cmd_element *cmd)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "parsing: %s\n", string);
|
fprintf(stderr, "parsing: %s\n", cmd->string);
|
||||||
|
|
||||||
/* clear state pointers */
|
/* clear state pointers */
|
||||||
startnode = currnode = seqhead = NULL;
|
startnode = currnode = seqhead = NULL;
|
||||||
|
@ -318,7 +319,7 @@ cmd_parse_format(struct graph_node *start, struct cmd_element *cmd)
|
||||||
// command string
|
// command string
|
||||||
command = cmd;
|
command = cmd;
|
||||||
// make flex read from a string
|
// make flex read from a string
|
||||||
set_buffer_string(input);
|
set_buffer_string(command->string);
|
||||||
// initialize the start node of this command dfa
|
// initialize the start node of this command dfa
|
||||||
startnode = start;
|
startnode = start;
|
||||||
// parse command into DFA
|
// parse command into DFA
|
||||||
|
|
|
@ -14,11 +14,11 @@ DEFUN (grammar_test,
|
||||||
GRAMMAR_STR
|
GRAMMAR_STR
|
||||||
"command to pass to new parser\n")
|
"command to pass to new parser\n")
|
||||||
{
|
{
|
||||||
|
char* command = argv_concat(argv, argc, 0);
|
||||||
const char* command = argv_concat(argv, argc, 0);
|
struct cmd_element *cmd = malloc(sizeof(struct cmd_element));
|
||||||
cmd_parse_format(command, "lol", nodegraph);
|
cmd->string = command;
|
||||||
|
parse_command_format(nodegraph, cmd);
|
||||||
walk_graph(nodegraph, 0);
|
walk_graph(nodegraph, 0);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +32,15 @@ DEFUN (grammar_test_show,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (grammar_test_match,
|
DEFUN (grammar_test_complete,
|
||||||
grammar_test_match_cmd,
|
grammar_test_complete_cmd,
|
||||||
"grammar match .COMMAND",
|
"grammar complete .COMMAND",
|
||||||
GRAMMAR_STR
|
GRAMMAR_STR
|
||||||
"attempt to match input on DFA\n"
|
"attempt to complete input on DFA\n"
|
||||||
"command to match")
|
"command to complete")
|
||||||
{
|
{
|
||||||
const char* command = argv_concat(argv, argc, 0);
|
const char* command = argv_concat(argv, argc, 0);
|
||||||
struct list *result = match_command(nodegraph, FILTER_STRICT, command);
|
struct list *result = match_command_complete (nodegraph, command, FILTER_STRICT);
|
||||||
|
|
||||||
if (result->count == 0) // invalid command
|
if (result->count == 0) // invalid command
|
||||||
fprintf(stderr, "%% Unknown command\n");
|
fprintf(stderr, "%% Unknown command\n");
|
||||||
|
@ -53,7 +53,7 @@ DEFUN (grammar_test_match,
|
||||||
// print possible next hops, if any
|
// print possible next hops, if any
|
||||||
for (ALL_LIST_ELEMENTS_RO(result,node,cnode)) {
|
for (ALL_LIST_ELEMENTS_RO(result,node,cnode)) {
|
||||||
if (cnode->type == END_GN)
|
if (cnode->type == END_GN)
|
||||||
fprintf(stderr, "<cr>");
|
fprintf(stderr, "<cr>\n");
|
||||||
else
|
else
|
||||||
fprintf(stderr, "%s\n", describe_node(cnode, desc, 50));
|
fprintf(stderr, "%s\n", describe_node(cnode, desc, 50));
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,39 @@ DEFUN (grammar_test_match,
|
||||||
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);
|
||||||
|
struct cmd_element *element = match_command (nodegraph, command, FILTER_STRICT);
|
||||||
|
|
||||||
|
if (element)
|
||||||
|
fprintf(stderr, "Matched: %s\n", element->string);
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Returned NULL\n");
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct list *argvv = match_build_argv (command, element);
|
||||||
|
fprintf(stderr, "num args: %d\n", argvv->count);
|
||||||
|
|
||||||
|
struct listnode *ln;
|
||||||
|
struct graph_node *gn;
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(argvv,ln,gn)) {
|
||||||
|
fprintf(stderr, "node text: %s\n", gn->text);
|
||||||
|
if (gn->arg)
|
||||||
|
fprintf(stderr, "node arg: %s\n", gn->arg);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "No arg.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void grammar_sandbox_init(void);
|
void grammar_sandbox_init(void);
|
||||||
void grammar_sandbox_init() {
|
void grammar_sandbox_init() {
|
||||||
|
@ -72,4 +105,5 @@ void grammar_sandbox_init() {
|
||||||
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);
|
install_element (ENABLE_NODE, &grammar_test_match_cmd);
|
||||||
|
install_element (ENABLE_NODE, &grammar_test_complete_cmd);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue