Implements eval command and minor CLI cleanups.

Implemented eval command can be used to evaluate expressions.

The patch also documents echo command and allows to use log classes
instead of integer as a mask for echo.
This commit is contained in:
Ondrej Zajicek 2013-07-25 13:15:32 +02:00
parent a0b176e3b2
commit 508d936078
8 changed files with 72 additions and 18 deletions

View file

@ -282,7 +282,7 @@ protocol rip {
<tag>include "<m/filename/"</tag> <tag>include "<m/filename/"</tag>
This statement causes inclusion of a new file. The maximal depth is set to 5. This statement causes inclusion of a new file. The maximal depth is set to 5.
<tag>log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag> <tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag>
Set logging of messages having the given class (either <cf/all/ or <cf/{ Set logging of messages having the given class (either <cf/all/ or <cf/{
error, trace }/ etc.) into selected destination (a file specified as a filename string, error, trace }/ etc.) into selected destination (a file specified as a filename string,
syslog with optional name argument, or the stderr output). Classes are: syslog with optional name argument, or the stderr output). Classes are:
@ -651,9 +651,6 @@ This argument can be omitted if there exists only a single instance.
<p>Here is a brief list of supported functions: <p>Here is a brief list of supported functions:
<descrip> <descrip>
<tag>dump resources|sockets|interfaces|neighbors|attributes|routes|protocols</tag>
Dump contents of internal data structures to the debugging output.
<tag>show status</tag> <tag>show status</tag>
Show router status, that is BIRD version, uptime and time from last reconfiguration. Show router status, that is BIRD version, uptime and time from last reconfiguration.
@ -812,6 +809,17 @@ This argument can be omitted if there exists only a single instance.
<tag>debug <m/protocol/|<m/pattern/|all all|off|{ states | routes | filters | events | packets }</tag> <tag>debug <m/protocol/|<m/pattern/|all all|off|{ states | routes | filters | events | packets }</tag>
Control protocol debugging. Control protocol debugging.
<tag>dump resources|sockets|interfaces|neighbors|attributes|routes|protocols</tag>
Dump contents of internal data structures to the debugging output.
<tag>echo all|off|{ <m/list of log classes/ } [ <m/buffer-size/ ]</tag>
Control echoing of log messages to the command-line output.
See <ref id="dsc-log" name="log option"> for a list of log classes.
<tag>eval <m/expr/</tag>
Evaluate given expression.
</descrip> </descrip>
<chapt>Filters <chapt>Filters

View file

@ -31,6 +31,7 @@ Reply codes of BIRD command-line interface
0020 Configuration OK 0020 Configuration OK
0021 Undo requested 0021 Undo requested
0022 Undo scheduled 0022 Undo scheduled
0023 Evaluation of expression
1000 BIRD version 1000 BIRD version
1001 Interface list 1001 Interface list
@ -61,6 +62,7 @@ Reply codes of BIRD command-line interface
8005 Protocol is down => cannot dump 8005 Protocol is down => cannot dump
8006 Reload failed 8006 Reload failed
8007 Access denied 8007 Access denied
8008 Evaluation runtime error
9000 Command too long 9000 Command too long
9001 Parse error 9001 Parse error

View file

@ -440,8 +440,6 @@ val_in_range(struct f_val v1, struct f_val v2)
return CMP_ERROR; return CMP_ERROR;
} }
static void val_print(struct f_val v);
static void static void
tree_node_print(struct f_tree *t, char **sep) tree_node_print(struct f_tree *t, char **sep)
{ {
@ -474,7 +472,7 @@ tree_print(struct f_tree *t)
/* /*
* val_print - format filter value * val_print - format filter value
*/ */
static void void
val_print(struct f_val v) val_print(struct f_val v)
{ {
char buf2[1024]; char buf2[1024];
@ -558,6 +556,8 @@ static struct rate_limit rl_runtime_err;
#define TWOARGS_C TWOARGS \ #define TWOARGS_C TWOARGS \
if (v1.type != v2.type) \ if (v1.type != v2.type) \
runtime( "Can't operate with values of incompatible types" ); runtime( "Can't operate with values of incompatible types" );
#define ACCESS_RTE \
do { if (!f_rte) runtime("No route to access"); } while (0)
/** /**
* interpret * interpret
@ -821,6 +821,7 @@ interpret(struct f_inst *what)
break; break;
case 'a': /* rta access */ case 'a': /* rta access */
{ {
ACCESS_RTE;
struct rta *rta = (*f_rte)->attrs; struct rta *rta = (*f_rte)->attrs;
res.type = what->aux; res.type = what->aux;
switch(res.type) { switch(res.type) {
@ -845,6 +846,7 @@ interpret(struct f_inst *what)
} }
break; break;
case P('a','S'): case P('a','S'):
ACCESS_RTE;
ONEARG; ONEARG;
if (what->aux != v1.type) if (what->aux != v1.type)
runtime( "Attempt to set static attribute to incompatible type" ); runtime( "Attempt to set static attribute to incompatible type" );
@ -877,6 +879,7 @@ interpret(struct f_inst *what)
} }
break; break;
case P('e','a'): /* Access to extended attributes */ case P('e','a'): /* Access to extended attributes */
ACCESS_RTE;
{ {
eattr *e = NULL; eattr *e = NULL;
if (!(f_flags & FF_FORCE_TMPATTR)) if (!(f_flags & FF_FORCE_TMPATTR))
@ -944,6 +947,7 @@ interpret(struct f_inst *what)
} }
break; break;
case P('e','S'): case P('e','S'):
ACCESS_RTE;
ONEARG; ONEARG;
{ {
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
@ -1021,10 +1025,12 @@ interpret(struct f_inst *what)
} }
break; break;
case 'P': case 'P':
ACCESS_RTE;
res.type = T_INT; res.type = T_INT;
res.val.i = (*f_rte)->pref; res.val.i = (*f_rte)->pref;
break; break;
case P('P','S'): case P('P','S'):
ACCESS_RTE;
ONEARG; ONEARG;
if (v1.type != T_INT) if (v1.type != T_INT)
runtime( "Can't set preference to non-integer" ); runtime( "Can't set preference to non-integer" );
@ -1246,6 +1252,7 @@ interpret(struct f_inst *what)
} }
else else
{ {
ACCESS_RTE;
v1.val.px.ip = (*f_rte)->net->n.prefix; v1.val.px.ip = (*f_rte)->net->n.prefix;
v1.val.px.len = (*f_rte)->net->n.pxlen; v1.val.px.len = (*f_rte)->net->n.pxlen;
@ -1478,22 +1485,27 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
return res.val.i; return res.val.i;
} }
struct f_val
f_eval(struct f_inst *expr, struct linpool *tmp_pool)
{
f_flags = 0;
f_tmp_attrs = NULL;
f_rte = NULL;
f_pool = tmp_pool;
log_reset();
return interpret(expr);
}
int int
f_eval_int(struct f_inst *expr) f_eval_int(struct f_inst *expr)
{ {
/* Called independently in parse-time to eval expressions */ /* Called independently in parse-time to eval expressions */
struct f_val res; struct f_val res = f_eval(expr, cfg_mem);
f_flags = 0;
f_tmp_attrs = NULL;
f_rte = NULL;
f_pool = cfg_mem;
log_reset();
res = interpret(expr);
if (res.type != T_INT) if (res.type != T_INT)
cf_error("Integer expression expected"); cf_error("Integer expression expected");
return res.val.i; return res.val.i;
} }

View file

@ -106,6 +106,7 @@ struct ea_list;
struct rte; struct rte;
int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags); int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags);
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
int f_eval_int(struct f_inst *expr); int f_eval_int(struct f_inst *expr);
u32 f_eval_asn(struct f_inst *expr); u32 f_eval_asn(struct f_inst *expr);
@ -117,6 +118,8 @@ int i_same(struct f_inst *f1, struct f_inst *f2);
int val_compare(struct f_val v1, struct f_val v2); int val_compare(struct f_val v1, struct f_val v2);
int tree_compare(const void *p1, const void *p2); int tree_compare(const void *p1, const void *p2);
void val_print(struct f_val v);
#define F_NOP 0 #define F_NOP 0
#define F_NONL 1 #define F_NONL 1
#define F_ACCEPT 2 /* Need to preserve ordering: accepts < rejects! */ #define F_ACCEPT 2 /* Need to preserve ordering: accepts < rejects! */

View file

@ -13,6 +13,7 @@
#include "nest/cmds.h" #include "nest/cmds.h"
#include "lib/string.h" #include "lib/string.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "filter/filter.h"
extern int shutting_down; extern int shutting_down;
extern int configuring; extern int configuring;
@ -90,3 +91,22 @@ cmd_show_memory(void)
print_size("Total:", rmemsize(&root_pool)); print_size("Total:", rmemsize(&root_pool));
cli_msg(0, ""); cli_msg(0, "");
} }
extern const char *log_buffer_ptr;
void
cmd_eval(struct f_inst *expr)
{
struct f_val v = f_eval(expr, this_cli->parser_pool);
log_reset();
if (v.type == T_RETURN)
{
cli_msg(8008, "runtime error");
return;
}
val_print(v);
cli_msg(23, "%s", log_buffer_ptr);
log_reset();
}

View file

@ -11,6 +11,9 @@ struct sym_show_data {
struct symbol *sym; struct symbol *sym;
}; };
struct f_inst;
void cmd_show_status(void); void cmd_show_status(void);
void cmd_show_symbols(struct sym_show_data *sym); void cmd_show_symbols(struct sym_show_data *sym);
void cmd_show_memory(void); void cmd_show_memory(void);
void cmd_eval(struct f_inst *expr);

View file

@ -612,7 +612,11 @@ CF_CLI(DUMP ROUTES,,, [[Dump routing table]])
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
{ protos_dump_all(); cli_msg(0, ""); } ; { protos_dump_all(); cli_msg(0, ""); } ;
CF_CLI(ECHO, echo_mask echo_size, [all | off | <mask>] [<buffer-size>], [[Configure echoing of log messages]]) { CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
{ cmd_eval($2); } ;
CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug | trace | info | remote | warning | error | auth }) [<buffer-size>], [[Control echoing of log messages]]) {
cli_set_log_echo(this_cli, $2, $3); cli_set_log_echo(this_cli, $2, $3);
cli_msg(0, ""); cli_msg(0, "");
} ; } ;
@ -620,7 +624,7 @@ CF_CLI(ECHO, echo_mask echo_size, [all | off | <mask>] [<buffer-size>], [[Config
echo_mask: echo_mask:
ALL { $$ = ~0; } ALL { $$ = ~0; }
| OFF { $$ = 0; } | OFF { $$ = 0; }
| NUM | '{' log_mask_list '}' { $$ = $2; }
; ;
echo_size: echo_size:

View file

@ -70,6 +70,8 @@ static char log_buffer[LOG_BUFFER_SIZE];
static char *log_buffer_pos; static char *log_buffer_pos;
static int log_buffer_remains; static int log_buffer_remains;
const char *log_buffer_ptr = log_buffer;
/** /**
* log_reset - reset the log buffer * log_reset - reset the log buffer