Filter + Config: Fix bugs, tests and split symbols by type
This commit is contained in:
parent
713658798d
commit
c0e958e022
16 changed files with 224 additions and 152 deletions
|
@ -285,7 +285,18 @@ else: {
|
||||||
}
|
}
|
||||||
|
|
||||||
cf_lval.s = cf_get_symbol(yytext);
|
cf_lval.s = cf_get_symbol(yytext);
|
||||||
return SYM;
|
switch (cf_lval.s->class) {
|
||||||
|
case SYM_VOID: return CF_SYM_VOID;
|
||||||
|
case SYM_PROTO: return CF_SYM_PROTO;
|
||||||
|
case SYM_TEMPLATE: return CF_SYM_TEMPLATE;
|
||||||
|
case SYM_FUNCTION: return CF_SYM_FUNCTION;
|
||||||
|
case SYM_FILTER: return CF_SYM_FILTER;
|
||||||
|
case SYM_TABLE: return CF_SYM_TABLE;
|
||||||
|
case SYM_ATTRIBUTE: return CF_SYM_ATTRIBUTE;
|
||||||
|
case SYM_VARIABLE_RANGE: return CF_SYM_VARIABLE;
|
||||||
|
case SYM_CONSTANT_RANGE: return CF_SYM_CONSTANT;
|
||||||
|
default: bug("Unknown symbol class %d", cf_lval.s->class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<CLI>(.|\n) {
|
<CLI>(.|\n) {
|
||||||
|
@ -723,9 +734,6 @@ cf_pop_scope(void)
|
||||||
char *
|
char *
|
||||||
cf_symbol_class_name(struct symbol *sym)
|
cf_symbol_class_name(struct symbol *sym)
|
||||||
{
|
{
|
||||||
if (cf_symbol_is_constant(sym))
|
|
||||||
return "constant";
|
|
||||||
|
|
||||||
switch (sym->class)
|
switch (sym->class)
|
||||||
{
|
{
|
||||||
case SYM_VOID:
|
case SYM_VOID:
|
||||||
|
@ -740,6 +748,12 @@ cf_symbol_class_name(struct symbol *sym)
|
||||||
return "filter";
|
return "filter";
|
||||||
case SYM_TABLE:
|
case SYM_TABLE:
|
||||||
return "routing table";
|
return "routing table";
|
||||||
|
case SYM_ATTRIBUTE:
|
||||||
|
return "custom attribute";
|
||||||
|
case SYM_CONSTANT_RANGE:
|
||||||
|
return "constant";
|
||||||
|
case SYM_VARIABLE_RANGE:
|
||||||
|
return "variable";
|
||||||
default:
|
default:
|
||||||
return "unknown type";
|
return "unknown type";
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,10 +165,6 @@ void cf_push_scope(struct symbol *);
|
||||||
void cf_pop_scope(void);
|
void cf_pop_scope(void);
|
||||||
char *cf_symbol_class_name(struct symbol *sym);
|
char *cf_symbol_class_name(struct symbol *sym);
|
||||||
|
|
||||||
static inline int cf_symbol_is_constant(struct symbol *sym)
|
|
||||||
{ return (sym->class & 0xff00) == SYM_CONSTANT; }
|
|
||||||
|
|
||||||
|
|
||||||
/* Parser */
|
/* Parser */
|
||||||
|
|
||||||
extern char *cf_text;
|
extern char *cf_text;
|
||||||
|
|
|
@ -55,6 +55,7 @@ CF_DECLS
|
||||||
enum ec_subtype ecs;
|
enum ec_subtype ecs;
|
||||||
struct f_dynamic_attr fda;
|
struct f_dynamic_attr fda;
|
||||||
struct f_static_attr fsa;
|
struct f_static_attr fsa;
|
||||||
|
struct f_lval flv;
|
||||||
struct filter *f;
|
struct filter *f;
|
||||||
struct f_tree *e;
|
struct f_tree *e;
|
||||||
struct f_trie *trie;
|
struct f_trie *trie;
|
||||||
|
@ -81,7 +82,7 @@ CF_DECLS
|
||||||
%token <ip4> IP4
|
%token <ip4> IP4
|
||||||
%token <ip6> IP6
|
%token <ip6> IP6
|
||||||
%token <i64> VPN_RD
|
%token <i64> VPN_RD
|
||||||
%token <s> SYM
|
%token <s> CF_SYM_VOID CF_SYM_PROTO CF_SYM_TEMPLATE CF_SYM_FUNCTION CF_SYM_FILTER CF_SYM_TABLE CF_SYM_ATTRIBUTE CF_SYM_VARIABLE CF_SYM_CONSTANT
|
||||||
%token <t> TEXT
|
%token <t> TEXT
|
||||||
%type <iface> ipa_scope
|
%type <iface> ipa_scope
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ CF_DECLS
|
||||||
%type <mls> label_stack_start label_stack
|
%type <mls> label_stack_start label_stack
|
||||||
|
|
||||||
%type <t> text opttext
|
%type <t> text opttext
|
||||||
|
%type <s> symbol
|
||||||
|
|
||||||
%nonassoc PREFIX_DUMMY
|
%nonassoc PREFIX_DUMMY
|
||||||
%left AND OR
|
%left AND OR
|
||||||
|
@ -125,7 +127,7 @@ conf: ';' ;
|
||||||
conf: definition ;
|
conf: definition ;
|
||||||
|
|
||||||
definition:
|
definition:
|
||||||
DEFINE SYM '=' term ';' {
|
DEFINE CF_SYM_VOID '=' term ';' {
|
||||||
struct f_val *val = cfg_alloc(sizeof(struct f_val));
|
struct f_val *val = cfg_alloc(sizeof(struct f_val));
|
||||||
if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
|
if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
|
||||||
cf_define_symbol($2, SYM_CONSTANT | val->type, val);
|
cf_define_symbol($2, SYM_CONSTANT | val->type, val);
|
||||||
|
@ -135,18 +137,29 @@ definition:
|
||||||
expr:
|
expr:
|
||||||
NUM
|
NUM
|
||||||
| '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
|
| '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
|
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
|
||||||
$$ = SYM_VAL($1).i; }
|
$$ = SYM_VAL($1).i; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
expr_us:
|
expr_us:
|
||||||
expr S { $$ = $1 S_; }
|
expr S { $$ = $1 S_; }
|
||||||
| expr MS { $$ = $1 MS_; }
|
| expr MS { $$ = $1 MS_; }
|
||||||
| expr US { $$ = $1 US_; }
|
| expr US { $$ = $1 US_; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
symbol:
|
||||||
|
CF_SYM_VOID
|
||||||
|
| CF_SYM_PROTO
|
||||||
|
| CF_SYM_TEMPLATE
|
||||||
|
| CF_SYM_FUNCTION
|
||||||
|
| CF_SYM_FILTER
|
||||||
|
| CF_SYM_TABLE
|
||||||
|
| CF_SYM_ATTRIBUTE
|
||||||
|
| CF_SYM_VARIABLE
|
||||||
|
| CF_SYM_CONSTANT
|
||||||
|
;
|
||||||
|
|
||||||
/* Switches */
|
/* Switches */
|
||||||
|
|
||||||
bool:
|
bool:
|
||||||
|
@ -164,7 +177,7 @@ bool:
|
||||||
ipa:
|
ipa:
|
||||||
IP4 { $$ = ipa_from_ip4($1); }
|
IP4 { $$ = ipa_from_ip4($1); }
|
||||||
| IP6 { $$ = ipa_from_ip6($1); }
|
| IP6 { $$ = ipa_from_ip6($1); }
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected");
|
if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected");
|
||||||
$$ = SYM_VAL($1).ip;
|
$$ = SYM_VAL($1).ip;
|
||||||
}
|
}
|
||||||
|
@ -172,7 +185,7 @@ ipa:
|
||||||
|
|
||||||
ipa_scope:
|
ipa_scope:
|
||||||
/* empty */ { $$ = NULL; }
|
/* empty */ { $$ = NULL; }
|
||||||
| '%' SYM { $$ = if_get_by_name($2->name); }
|
| '%' symbol { $$ = if_get_by_name($2->name); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,7 +292,7 @@ net_:
|
||||||
|
|
||||||
net_ip6:
|
net_ip6:
|
||||||
net_ip6_
|
net_ip6_
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
|
if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
|
||||||
cf_error("IPv6 network expected");
|
cf_error("IPv6 network expected");
|
||||||
$$ = * SYM_VAL($1).net;
|
$$ = * SYM_VAL($1).net;
|
||||||
|
@ -288,7 +301,7 @@ net_ip6:
|
||||||
|
|
||||||
net_ip:
|
net_ip:
|
||||||
net_ip_
|
net_ip_
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
|
if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
|
||||||
cf_error("IP network expected");
|
cf_error("IP network expected");
|
||||||
$$ = * SYM_VAL($1).net;
|
$$ = * SYM_VAL($1).net;
|
||||||
|
@ -297,7 +310,7 @@ net_ip:
|
||||||
|
|
||||||
net_any:
|
net_any:
|
||||||
net_
|
net_
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class != (SYM_CONSTANT | T_NET))
|
if ($1->class != (SYM_CONSTANT | T_NET))
|
||||||
cf_error("Network expected");
|
cf_error("Network expected");
|
||||||
$$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
|
$$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
|
||||||
|
@ -309,7 +322,7 @@ net_or_ipa:
|
||||||
| net_ip6_
|
| net_ip6_
|
||||||
| IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
|
| IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
|
||||||
| IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
|
| IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class == (SYM_CONSTANT | T_IP))
|
if ($1->class == (SYM_CONSTANT | T_IP))
|
||||||
net_fill_ip_host(&($$), SYM_VAL($1).ip);
|
net_fill_ip_host(&($$), SYM_VAL($1).ip);
|
||||||
else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
|
else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
|
||||||
|
@ -346,7 +359,7 @@ time:
|
||||||
|
|
||||||
text:
|
text:
|
||||||
TEXT
|
TEXT
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected");
|
if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected");
|
||||||
$$ = SYM_VAL($1).s;
|
$$ = SYM_VAL($1).s;
|
||||||
}
|
}
|
||||||
|
|
144
filter/config.Y
144
filter/config.Y
|
@ -17,7 +17,7 @@ static inline u32 pair_a(u32 p) { return p >> 16; }
|
||||||
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
|
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
|
||||||
|
|
||||||
#define f_generate_complex(fi_code, da, arg) \
|
#define f_generate_complex(fi_code, da, arg) \
|
||||||
f_new_inst(FI_EA_SET, da, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg))
|
f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets and their items are during parsing handled as lists, linked
|
* Sets and their items are during parsing handled as lists, linked
|
||||||
|
@ -179,7 +179,7 @@ f_generate_empty(struct f_dynamic_attr dyn)
|
||||||
cf_error("Can't empty that attribute");
|
cf_error("Can't empty that attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
return f_new_inst(FI_EA_SET, dyn, f_new_inst(FI_CONSTANT, empty));
|
return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -389,6 +389,37 @@ assert_done(struct f_inst *expr, const char *start, const char *end)
|
||||||
: "???");
|
: "???");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct f_inst *
|
||||||
|
assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
|
||||||
|
{
|
||||||
|
struct f_inst *setter, *getter, *checker;
|
||||||
|
switch (lval->type) {
|
||||||
|
case F_LVAL_VARIABLE:
|
||||||
|
setter = f_new_inst(FI_SET, expr, lval->sym);
|
||||||
|
getter = f_new_inst(FI_VARIABLE, lval->sym);
|
||||||
|
break;
|
||||||
|
case F_LVAL_PREFERENCE:
|
||||||
|
setter = f_new_inst(FI_PREF_SET, expr);
|
||||||
|
getter = f_new_inst(FI_PREF_GET);
|
||||||
|
break;
|
||||||
|
case F_LVAL_SA:
|
||||||
|
setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
|
||||||
|
getter = f_new_inst(FI_RTA_GET, lval->sa);
|
||||||
|
break;
|
||||||
|
case F_LVAL_EA:
|
||||||
|
setter = f_new_inst(FI_EA_SET, expr, lval->da);
|
||||||
|
getter = f_new_inst(FI_EA_GET, lval->da);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bug("Unknown lval type");
|
||||||
|
}
|
||||||
|
|
||||||
|
checker = f_new_inst(FI_EQ, expr, getter);
|
||||||
|
f_inst_next(setter, checker);
|
||||||
|
|
||||||
|
return assert_done(setter, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||||
|
@ -407,17 +438,18 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||||
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
|
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
|
||||||
EMPTY,
|
EMPTY,
|
||||||
FILTER, WHERE, EVAL, ATTRIBUTE,
|
FILTER, WHERE, EVAL, ATTRIBUTE,
|
||||||
BT_ASSERT, BT_TEST_SUITE, FORMAT)
|
BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, FORMAT)
|
||||||
|
|
||||||
%nonassoc THEN
|
%nonassoc THEN
|
||||||
%nonassoc ELSE
|
%nonassoc ELSE
|
||||||
|
|
||||||
%type <xc> function_params declsn
|
%type <xc> function_params declsn
|
||||||
%type <xp> cmds_int function_body
|
%type <xp> cmds_int function_body
|
||||||
%type <x> term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail one_decl decls
|
%type <x> term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls
|
||||||
%type <fda> dynamic_attr
|
%type <fda> dynamic_attr
|
||||||
%type <fsa> static_attr
|
%type <fsa> static_attr
|
||||||
%type <f> filter filter_body where_filter
|
%type <f> filter filter_body where_filter
|
||||||
|
%type <flv> lvalue
|
||||||
%type <i> type
|
%type <i> type
|
||||||
%type <ecs> ec_kind
|
%type <ecs> ec_kind
|
||||||
%type <fret> break_command
|
%type <fret> break_command
|
||||||
|
@ -432,7 +464,7 @@ CF_GRAMMAR
|
||||||
|
|
||||||
conf: filter_def ;
|
conf: filter_def ;
|
||||||
filter_def:
|
filter_def:
|
||||||
FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
|
FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
|
||||||
filter_body {
|
filter_body {
|
||||||
$2->def = $4;
|
$2->def = $4;
|
||||||
$4->name = $2->name;
|
$4->name = $2->name;
|
||||||
|
@ -447,16 +479,13 @@ filter_eval:
|
||||||
;
|
;
|
||||||
|
|
||||||
conf: custom_attr ;
|
conf: custom_attr ;
|
||||||
custom_attr: ATTRIBUTE type SYM ';' {
|
custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
|
||||||
cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda);
|
cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda);
|
||||||
};
|
};
|
||||||
|
|
||||||
conf: bt_test_suite ;
|
conf: bt_test_suite ;
|
||||||
bt_test_suite:
|
bt_test_suite:
|
||||||
BT_TEST_SUITE '(' SYM ',' text ')' {
|
BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' {
|
||||||
if (!($3->class & SYM_FUNCTION))
|
|
||||||
cf_error("Function expected");
|
|
||||||
|
|
||||||
struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
|
struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
|
||||||
t->fn = $3->def;
|
t->fn = $3->def;
|
||||||
t->fn_name = $3->name;
|
t->fn_name = $3->name;
|
||||||
|
@ -505,7 +534,7 @@ type:
|
||||||
;
|
;
|
||||||
|
|
||||||
one_decl:
|
one_decl:
|
||||||
type SYM {
|
type CF_SYM_VOID {
|
||||||
struct f_val * val = cfg_alloc(sizeof(struct f_val));
|
struct f_val * val = cfg_alloc(sizeof(struct f_val));
|
||||||
val->type = T_VOID;
|
val->type = T_VOID;
|
||||||
$2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
|
$2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
|
||||||
|
@ -545,8 +574,7 @@ filter_body:
|
||||||
;
|
;
|
||||||
|
|
||||||
filter:
|
filter:
|
||||||
SYM {
|
CF_SYM_FILTER {
|
||||||
if ($1->class != SYM_FILTER) cf_error("No such filter.");
|
|
||||||
$$ = $1->def;
|
$$ = $1->def;
|
||||||
}
|
}
|
||||||
| filter_body
|
| filter_body
|
||||||
|
@ -573,7 +601,7 @@ function_body:
|
||||||
|
|
||||||
conf: function_def ;
|
conf: function_def ;
|
||||||
function_def:
|
function_def:
|
||||||
FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
|
FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
|
||||||
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
|
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
|
||||||
cf_push_scope($2);
|
cf_push_scope($2);
|
||||||
} function_params function_body {
|
} function_params function_body {
|
||||||
|
@ -647,8 +675,7 @@ set_atom:
|
||||||
if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
|
if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
|
||||||
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
|
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
|
||||||
}
|
}
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
|
|
||||||
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
|
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
|
||||||
$$ = *(struct f_val *)($1->def);
|
$$ = *(struct f_val *)($1->def);
|
||||||
}
|
}
|
||||||
|
@ -764,7 +791,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
bgp_path_expr:
|
bgp_path_expr:
|
||||||
symbol { $$ = $1; }
|
symbol_value { $$ = $1; }
|
||||||
| '(' term ')' { $$ = $2; }
|
| '(' term ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -806,31 +833,17 @@ constructor:
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
rtadot: /* EMPTY, we are not permitted RTA. prefix */
|
|
||||||
;
|
|
||||||
|
|
||||||
function_call:
|
function_call:
|
||||||
SYM '(' var_list ')' {
|
CF_SYM_FUNCTION '(' var_list ')' {
|
||||||
$$ = f_new_inst(FI_CALL, $1, $3);
|
$$ = f_new_inst(FI_CALL, $1, $3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
symbol:
|
symbol_value:
|
||||||
SYM {
|
CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); }
|
||||||
switch ($1->class & 0xffff) {
|
| CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); }
|
||||||
case SYM_CONSTANT_RANGE:
|
| CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); }
|
||||||
$$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def);
|
;
|
||||||
break;
|
|
||||||
case SYM_VARIABLE_RANGE:
|
|
||||||
$$ = f_new_inst(FI_VARIABLE, $1);
|
|
||||||
break;
|
|
||||||
case SYM_ATTRIBUTE:
|
|
||||||
$$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cf_error("%s: variable expected.", $1->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static_attr:
|
static_attr:
|
||||||
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
|
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
|
||||||
|
@ -863,15 +876,15 @@ term:
|
||||||
| '!' term { $$ = f_new_inst(FI_NOT, $2); }
|
| '!' term { $$ = f_new_inst(FI_NOT, $2); }
|
||||||
| DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
|
| DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
|
||||||
|
|
||||||
| symbol { $$ = $1; }
|
| symbol_value { $$ = $1; }
|
||||||
| constant { $$ = $1; }
|
| constant { $$ = $1; }
|
||||||
| constructor { $$ = $1; }
|
| constructor { $$ = $1; }
|
||||||
|
|
||||||
| PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
|
| PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
|
||||||
|
|
||||||
| rtadot static_attr { $$ = f_new_inst(FI_RTA_GET, $2); }
|
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
|
||||||
|
|
||||||
| rtadot dynamic_attr { $$ = f_new_inst(FI_EA_GET, $2); }
|
| dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
|
||||||
|
|
||||||
| term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
|
| term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
|
||||||
| term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
|
| term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
|
||||||
|
@ -888,10 +901,10 @@ term:
|
||||||
|
|
||||||
/* Communities */
|
/* Communities */
|
||||||
/* This causes one shift/reduce conflict
|
/* This causes one shift/reduce conflict
|
||||||
| rtadot dynamic_attr '.' ADD '(' term ')' { }
|
| dynamic_attr '.' ADD '(' term ')' { }
|
||||||
| rtadot dynamic_attr '.' DELETE '(' term ')' { }
|
| dynamic_attr '.' DELETE '(' term ')' { }
|
||||||
| rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
|
| dynamic_attr '.' CONTAINS '(' term ')' { }
|
||||||
| rtadot dynamic_attr '.' RESET{ }
|
| dynamic_attr '.' RESET{ }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
| '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
|
| '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
|
||||||
|
@ -956,32 +969,29 @@ cmd:
|
||||||
| IF term THEN block ELSE block {
|
| IF term THEN block ELSE block {
|
||||||
$$ = f_new_inst(FI_CONDITION, $2, $4, $6);
|
$$ = f_new_inst(FI_CONDITION, $2, $4, $6);
|
||||||
}
|
}
|
||||||
| SYM '=' term ';' {
|
| CF_SYM_ATTRIBUTE '=' term ';' {
|
||||||
DBG( "Ook, we'll set value\n" );
|
$$ = f_new_inst(FI_EA_SET, $3, *((struct f_dynamic_attr *) $1->def));
|
||||||
if ($1->class == SYM_ATTRIBUTE) {
|
}
|
||||||
$$ = f_new_inst(FI_EA_SET, *((struct f_dynamic_attr *) $1->def), $3);
|
| CF_SYM_VARIABLE '=' term ';' {
|
||||||
} else if (($1->class & ~T_MASK) == SYM_VARIABLE) {
|
$$ = f_new_inst(FI_SET, $3, $1);
|
||||||
$$ = f_new_inst(FI_SET, $3, $1);
|
|
||||||
} else
|
|
||||||
cf_error( "Symbol `%s' is read-only.", $1->name );
|
|
||||||
}
|
}
|
||||||
| RETURN term ';' {
|
| RETURN term ';' {
|
||||||
DBG( "Ook, we'll return the value\n" );
|
DBG( "Ook, we'll return the value\n" );
|
||||||
$$ = f_new_inst(FI_RETURN, $2);
|
$$ = f_new_inst(FI_RETURN, $2);
|
||||||
}
|
}
|
||||||
| rtadot dynamic_attr '=' term ';' {
|
| dynamic_attr '=' term ';' {
|
||||||
$$ = f_new_inst(FI_EA_SET, $2, $4);
|
$$ = f_new_inst(FI_EA_SET, $3, $1);
|
||||||
}
|
}
|
||||||
| rtadot static_attr '=' term ';' {
|
| static_attr '=' term ';' {
|
||||||
if ($2.readonly)
|
if ($1.readonly)
|
||||||
cf_error( "This static attribute is read-only.");
|
cf_error( "This static attribute is read-only.");
|
||||||
$$ = f_new_inst(FI_RTA_SET, $2, $4);
|
$$ = f_new_inst(FI_RTA_SET, $3, $1);
|
||||||
}
|
}
|
||||||
| PREFERENCE '=' term ';' {
|
| PREFERENCE '=' term ';' {
|
||||||
$$ = f_new_inst(FI_PREF_SET, $3);
|
$$ = f_new_inst(FI_PREF_SET, $3);
|
||||||
}
|
}
|
||||||
| UNSET '(' rtadot dynamic_attr ')' ';' {
|
| UNSET '(' dynamic_attr ')' ';' {
|
||||||
$$ = f_new_inst(FI_EA_UNSET, $4);
|
$$ = f_new_inst(FI_EA_UNSET, $3);
|
||||||
}
|
}
|
||||||
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
|
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
|
||||||
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
|
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
|
||||||
|
@ -989,12 +999,13 @@ cmd:
|
||||||
$$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
|
$$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
|
||||||
}
|
}
|
||||||
|
|
||||||
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
|
| dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
|
||||||
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); }
|
| dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
|
||||||
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); }
|
| dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
|
||||||
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); }
|
| dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
|
||||||
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); }
|
| dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
|
||||||
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
|
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
|
||||||
|
| BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
get_cf_position:
|
get_cf_position:
|
||||||
|
@ -1002,5 +1013,10 @@ get_cf_position:
|
||||||
$$ = cf_text;
|
$$ = cf_text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lvalue:
|
||||||
|
CF_SYM_VARIABLE { $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
|
||||||
|
| PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
|
||||||
|
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
|
||||||
|
| dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
COUNT(2);
|
COUNT(2);
|
||||||
|
|
||||||
NEW([[]], [[
|
NEW(, [[
|
||||||
uint len = 0;
|
uint len = 0;
|
||||||
uint dyn = 0;
|
uint dyn = 0;
|
||||||
for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
|
for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
|
||||||
|
@ -329,9 +329,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_RTA_SET, 1, 0) {
|
INST(FI_RTA_SET, 1, 0) {
|
||||||
STATIC_ATTR;
|
|
||||||
ACCESS_RTE;
|
ACCESS_RTE;
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
|
STATIC_ATTR;
|
||||||
if (sa.f_type != v1.type)
|
if (sa.f_type != v1.type)
|
||||||
runtime( "Attempt to set static attribute to incompatible type" );
|
runtime( "Attempt to set static attribute to incompatible type" );
|
||||||
|
|
||||||
|
@ -475,10 +475,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_EA_SET, 1, 0) {
|
INST(FI_EA_SET, 1, 0) {
|
||||||
DYNAMIC_ATTR;
|
|
||||||
ACCESS_RTE;
|
ACCESS_RTE;
|
||||||
ACCESS_EATTRS;
|
ACCESS_EATTRS;
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
|
DYNAMIC_ATTR;
|
||||||
{
|
{
|
||||||
struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
|
struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
|
||||||
|
|
||||||
|
@ -719,7 +719,7 @@
|
||||||
/* Then push the arguments */
|
/* Then push the arguments */
|
||||||
LINE(1,1);
|
LINE(1,1);
|
||||||
|
|
||||||
NEW([[]], [[
|
NEW(, [[
|
||||||
if (sym->class != SYM_FUNCTION)
|
if (sym->class != SYM_FUNCTION)
|
||||||
cf_error("You can't call something which is not a function. Really.");
|
cf_error("You can't call something which is not a function. Really.");
|
||||||
|
|
||||||
|
@ -984,5 +984,8 @@
|
||||||
INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
|
INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
|
||||||
ARG(1, T_BOOL);
|
ARG(1, T_BOOL);
|
||||||
STRING;
|
STRING;
|
||||||
CALL(bt_assert_hook, res.val.i, what);
|
if (!bt_assert_hook)
|
||||||
|
runtime("No bt_assert hook registered, can't assert");
|
||||||
|
|
||||||
|
bt_assert_hook(res.val.i, what);
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,24 @@ enum filter_return {
|
||||||
F_QUITBIRD,
|
F_QUITBIRD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Filter l-value type */
|
||||||
|
enum f_lval_type {
|
||||||
|
F_LVAL_VARIABLE,
|
||||||
|
F_LVAL_PREFERENCE,
|
||||||
|
F_LVAL_SA,
|
||||||
|
F_LVAL_EA,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Filter l-value */
|
||||||
|
struct f_lval {
|
||||||
|
enum f_lval_type type;
|
||||||
|
union {
|
||||||
|
const struct symbol *sym;
|
||||||
|
struct f_dynamic_attr da;
|
||||||
|
struct f_static_attr sa;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/* Filter instruction declarations */
|
/* Filter instruction declarations */
|
||||||
#define FI__LIST \
|
#define FI__LIST \
|
||||||
F(FI_NOP) \
|
F(FI_NOP) \
|
||||||
|
@ -159,9 +177,9 @@ enum filter_return {
|
||||||
F(FI_CONDITION, ARG, LINE, LINE) \
|
F(FI_CONDITION, ARG, LINE, LINE) \
|
||||||
F(FI_PRINT_AND_DIE, ARG, FRET) \
|
F(FI_PRINT_AND_DIE, ARG, FRET) \
|
||||||
F(FI_RTA_GET, SA) \
|
F(FI_RTA_GET, SA) \
|
||||||
F(FI_RTA_SET, SA, ARG) \
|
F(FI_RTA_SET, ARG, SA) \
|
||||||
F(FI_EA_GET, EA) \
|
F(FI_EA_GET, EA) \
|
||||||
F(FI_EA_SET, EA, ARG) \
|
F(FI_EA_SET, ARG, EA) \
|
||||||
F(FI_EA_UNSET, EA) \
|
F(FI_EA_UNSET, EA) \
|
||||||
F(FI_PREF_GET) \
|
F(FI_PREF_GET) \
|
||||||
F(FI_PREF_SET, ARG) \
|
F(FI_PREF_SET, ARG) \
|
||||||
|
|
|
@ -22,19 +22,21 @@
|
||||||
#define BT_CONFIG_FILE "filter/test.conf"
|
#define BT_CONFIG_FILE "filter/test.conf"
|
||||||
|
|
||||||
|
|
||||||
static struct config *
|
struct parse_config_file_arg {
|
||||||
parse_config_file(const void *filename_void)
|
struct config **cp;
|
||||||
|
const char *filename;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_config_file(const void *argv)
|
||||||
{
|
{
|
||||||
bt_bird_init();
|
const struct parse_config_file_arg *arg = argv;
|
||||||
|
size_t fn_size = strlen(arg->filename) + 1;
|
||||||
size_t fn_size = strlen((const char *) filename_void) + 1;
|
|
||||||
char *filename = alloca(fn_size);
|
char *filename = alloca(fn_size);
|
||||||
strncpy(filename, filename_void, fn_size);
|
strncpy(filename, arg->filename, fn_size);
|
||||||
|
|
||||||
struct config *c = bt_config_file_parse(filename);
|
*(arg->cp) = bt_config_file_parse(filename);
|
||||||
bt_bird_cleanup();
|
return !!*(arg->cp);
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -68,13 +70,18 @@ int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
bt_init(argc, argv);
|
bt_init(argc, argv);
|
||||||
|
bt_bird_init();
|
||||||
|
|
||||||
struct config *c = parse_config_file(BT_CONFIG_FILE);
|
bt_assert_hook = bt_assert_filter;
|
||||||
|
|
||||||
|
struct config *c = NULL;
|
||||||
|
struct parse_config_file_arg pcfa = { .cp = &c, .filename = BT_CONFIG_FILE };
|
||||||
|
bt_test_suite_base(parse_config_file, "conf", (const void *) &pcfa, 0, 0, "parse config file");
|
||||||
|
|
||||||
|
bt_bird_cleanup();
|
||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
{
|
{
|
||||||
bt_assert_hook = bt_assert_filter;
|
|
||||||
|
|
||||||
struct f_bt_test_suite *t;
|
struct f_bt_test_suite *t;
|
||||||
WALK_LIST(t, c->tests)
|
WALK_LIST(t, c->tests)
|
||||||
bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
|
bt_test_suite_base(run_function, t->fn_name, t->fn, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
|
||||||
|
|
|
@ -1336,7 +1336,7 @@ bt_test_suite(t_mixed_prefix, "Testing mixed net types");
|
||||||
|
|
||||||
filter vpn_filter
|
filter vpn_filter
|
||||||
{
|
{
|
||||||
bt_assert(format(net) = "0:1:2 10.1.10.0/24");
|
bt_assert(format(net) = "1:2 10.1.10.0/24");
|
||||||
bt_assert(net.type = NET_VPN4);
|
bt_assert(net.type = NET_VPN4);
|
||||||
bt_assert(net.type != NET_IP4);
|
bt_assert(net.type != NET_IP4);
|
||||||
bt_assert(net.type != NET_IP6);
|
bt_assert(net.type != NET_IP6);
|
||||||
|
@ -1347,6 +1347,15 @@ filter vpn_filter
|
||||||
NET_IP6: print "IPV6";
|
NET_IP6: print "IPV6";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# aoiufahkejtrhaweifdsbhydkfj,ysdnm
|
||||||
|
|
||||||
|
bt_check_assign(from, 10.20.30.40);
|
||||||
|
bt_check_assign(gw, 55.55.55.44);
|
||||||
|
|
||||||
|
bgp_community.add((3,5));
|
||||||
|
bgp_ext_community.add((ro, 135, 999));
|
||||||
|
bgp_large_community.add((6464156, 89646354, 8675643));
|
||||||
|
|
||||||
accept;
|
accept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
|
||||||
%type <i32> idval
|
%type <i32> idval
|
||||||
%type <f> imexport
|
%type <f> imexport
|
||||||
%type <r> rtable
|
%type <r> rtable
|
||||||
%type <s> optsym
|
%type <s> optproto sym_proto_or_template
|
||||||
%type <ra> r_args
|
%type <ra> r_args
|
||||||
%type <sd> sym_args
|
%type <sd> sym_args
|
||||||
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm
|
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm
|
||||||
|
@ -114,7 +114,7 @@ idval:
|
||||||
NUM { $$ = $1; }
|
NUM { $$ = $1; }
|
||||||
| '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
|
| '(' term ')' { $$ = f_eval_int(f_postfixify($2)); }
|
||||||
| IP4 { $$ = ip4_to_u32($1); }
|
| IP4 { $$ = ip4_to_u32($1); }
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
|
if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
|
||||||
$$ = SYM_VAL($1).i;
|
$$ = SYM_VAL($1).i;
|
||||||
else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
|
else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
|
||||||
|
@ -156,7 +156,7 @@ table_sorted:
|
||||||
| SORTED { $$ = 1; }
|
| SORTED { $$ = 1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
table: net_type TABLE SYM table_sorted {
|
table: net_type TABLE CF_SYM_VOID table_sorted {
|
||||||
struct rtable_config *cf;
|
struct rtable_config *cf;
|
||||||
cf = rt_new_table($3, $1);
|
cf = rt_new_table($3, $1);
|
||||||
cf->sorted = $4;
|
cf->sorted = $4;
|
||||||
|
@ -173,6 +173,8 @@ proto_start:
|
||||||
| TEMPLATE { $$ = SYM_TEMPLATE; }
|
| TEMPLATE { $$ = SYM_TEMPLATE; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
sym_proto_or_template: CF_SYM_PROTO | CF_SYM_TEMPLATE ;
|
||||||
|
|
||||||
proto_name:
|
proto_name:
|
||||||
/* EMPTY */ {
|
/* EMPTY */ {
|
||||||
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
|
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
|
||||||
|
@ -180,11 +182,11 @@ proto_name:
|
||||||
s->def = this_proto;
|
s->def = this_proto;
|
||||||
this_proto->name = s->name;
|
this_proto->name = s->name;
|
||||||
}
|
}
|
||||||
| SYM {
|
| CF_SYM_VOID {
|
||||||
cf_define_symbol($1, this_proto->class, this_proto);
|
cf_define_symbol($1, this_proto->class, this_proto);
|
||||||
this_proto->name = $1->name;
|
this_proto->name = $1->name;
|
||||||
}
|
}
|
||||||
| FROM SYM {
|
| FROM sym_proto_or_template {
|
||||||
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
|
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
|
||||||
s->class = this_proto->class;
|
s->class = this_proto->class;
|
||||||
s->def = this_proto;
|
s->def = this_proto;
|
||||||
|
@ -193,7 +195,7 @@ proto_name:
|
||||||
if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
|
if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
|
||||||
proto_copy_config(this_proto, $2->def);
|
proto_copy_config(this_proto, $2->def);
|
||||||
}
|
}
|
||||||
| SYM FROM SYM {
|
| CF_SYM_VOID FROM sym_proto_or_template {
|
||||||
cf_define_symbol($1, this_proto->class, this_proto);
|
cf_define_symbol($1, this_proto->class, this_proto);
|
||||||
this_proto->name = $1->name;
|
this_proto->name = $1->name;
|
||||||
|
|
||||||
|
@ -254,12 +256,7 @@ channel_end:
|
||||||
proto_channel: channel_start channel_opt_list channel_end;
|
proto_channel: channel_start channel_opt_list channel_end;
|
||||||
|
|
||||||
|
|
||||||
rtable:
|
rtable: CF_SYM_TABLE { $$ = $1->def; } ;
|
||||||
SYM {
|
|
||||||
if ($1->class != SYM_TABLE) cf_error("Table expected");
|
|
||||||
$$ = $1->def;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
imexport:
|
imexport:
|
||||||
FILTER filter { $$ = $2; }
|
FILTER filter { $$ = $2; }
|
||||||
|
@ -512,8 +509,8 @@ CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing
|
||||||
CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
|
CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
|
||||||
{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
|
{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
|
||||||
|
|
||||||
optsym:
|
optproto:
|
||||||
SYM
|
CF_SYM_PROTO
|
||||||
| /* empty */ { $$ = NULL; }
|
| /* empty */ { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -545,9 +542,8 @@ r_args:
|
||||||
$$->show_for = 1;
|
$$->show_for = 1;
|
||||||
$$->addr = $3;
|
$$->addr = $3;
|
||||||
}
|
}
|
||||||
| r_args TABLE SYM {
|
| r_args TABLE CF_SYM_TABLE {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name);
|
|
||||||
rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
|
rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
|
||||||
$$->tables_defined_by = RSD_TDB_DIRECT;
|
$$->tables_defined_by = RSD_TDB_DIRECT;
|
||||||
}
|
}
|
||||||
|
@ -558,10 +554,10 @@ r_args:
|
||||||
rt_show_add_table($$, t->table);
|
rt_show_add_table($$, t->table);
|
||||||
$$->tables_defined_by = RSD_TDB_ALL;
|
$$->tables_defined_by = RSD_TDB_ALL;
|
||||||
}
|
}
|
||||||
| r_args IMPORT TABLE SYM '.' r_args_channel {
|
| r_args IMPORT TABLE CF_SYM_PROTO '.' r_args_channel {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
struct proto_config *cf = (void *) $4->def;
|
struct proto_config *cf = (void *) $4->def;
|
||||||
if ($4->class != SYM_PROTO || !cf->proto) cf_error("%s is not a protocol", $4->name);
|
if (!cf->proto) cf_error("%s is not a protocol", $4->name);
|
||||||
struct channel *c = proto_find_channel_by_name(cf->proto, $6);
|
struct channel *c = proto_find_channel_by_name(cf->proto, $6);
|
||||||
if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
|
if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
|
||||||
if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6);
|
if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6);
|
||||||
|
@ -590,30 +586,30 @@ r_args:
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->filtered = 1;
|
$$->filtered = 1;
|
||||||
}
|
}
|
||||||
| r_args export_mode SYM {
|
| r_args export_mode CF_SYM_PROTO {
|
||||||
struct proto_config *c = (struct proto_config *) $3->def;
|
struct proto_config *c = (struct proto_config *) $3->def;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
if ($$->export_mode) cf_error("Export specified twice");
|
if ($$->export_mode) cf_error("Export specified twice");
|
||||||
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
|
if (!c->proto) cf_error("%s is not a protocol", $3->name);
|
||||||
$$->export_mode = $2;
|
$$->export_mode = $2;
|
||||||
$$->export_protocol = c->proto;
|
$$->export_protocol = c->proto;
|
||||||
$$->tables_defined_by = RSD_TDB_INDIRECT;
|
$$->tables_defined_by = RSD_TDB_INDIRECT;
|
||||||
}
|
}
|
||||||
| r_args export_mode SYM '.' r_args_channel {
|
| r_args export_mode CF_SYM_PROTO '.' r_args_channel {
|
||||||
struct proto_config *c = (struct proto_config *) $3->def;
|
struct proto_config *c = (struct proto_config *) $3->def;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
if ($$->export_mode) cf_error("Export specified twice");
|
if ($$->export_mode) cf_error("Export specified twice");
|
||||||
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
|
if (!c->proto) cf_error("%s is not a protocol", $3->name);
|
||||||
$$->export_mode = $2;
|
$$->export_mode = $2;
|
||||||
$$->export_channel = proto_find_channel_by_name(c->proto, $5);
|
$$->export_channel = proto_find_channel_by_name(c->proto, $5);
|
||||||
if (!$$->export_channel) cf_error("Export channel not found");
|
if (!$$->export_channel) cf_error("Export channel not found");
|
||||||
$$->tables_defined_by = RSD_TDB_INDIRECT;
|
$$->tables_defined_by = RSD_TDB_INDIRECT;
|
||||||
}
|
}
|
||||||
| r_args PROTOCOL SYM {
|
| r_args PROTOCOL CF_SYM_PROTO {
|
||||||
struct proto_config *c = (struct proto_config *) $3->def;
|
struct proto_config *c = (struct proto_config *) $3->def;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
if ($$->show_protocol) cf_error("Protocol specified twice");
|
if ($$->show_protocol) cf_error("Protocol specified twice");
|
||||||
if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
|
if (!c->proto) cf_error("%s is not a protocol", $3->name);
|
||||||
$$->show_protocol = c->proto;
|
$$->show_protocol = c->proto;
|
||||||
$$->tables_defined_by = RSD_TDB_INDIRECT;
|
$$->tables_defined_by = RSD_TDB_INDIRECT;
|
||||||
}
|
}
|
||||||
|
@ -647,7 +643,7 @@ r_args_for:
|
||||||
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
|
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
|
||||||
net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
|
net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
|
||||||
}
|
}
|
||||||
| SYM {
|
| CF_SYM_CONSTANT {
|
||||||
if ($1->class == (SYM_CONSTANT | T_IP))
|
if ($1->class == (SYM_CONSTANT | T_IP))
|
||||||
{
|
{
|
||||||
$$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
|
$$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
|
||||||
|
@ -709,7 +705,7 @@ sym_args:
|
||||||
| sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
|
| sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
|
||||||
| sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
|
| sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
|
||||||
| sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
|
| sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
|
||||||
| sym_args SYM { $$ = $1; $$->sym = $2; }
|
| sym_args symbol { $$ = $1; $$->sym = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -779,13 +775,13 @@ CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
|
||||||
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
|
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
|
||||||
|
|
||||||
proto_patt:
|
proto_patt:
|
||||||
SYM { $$.ptr = $1; $$.patt = 0; }
|
CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; }
|
||||||
| ALL { $$.ptr = NULL; $$.patt = 1; }
|
| ALL { $$.ptr = NULL; $$.patt = 1; }
|
||||||
| TEXT { $$.ptr = $1; $$.patt = 1; }
|
| TEXT { $$.ptr = $1; $$.patt = 1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
proto_patt2:
|
proto_patt2:
|
||||||
SYM { $$.ptr = $1; $$.patt = 0; }
|
CF_SYM_PROTO { $$.ptr = $1; $$.patt = 0; }
|
||||||
| { $$.ptr = NULL; $$.patt = 1; }
|
| { $$.ptr = NULL; $$.patt = 1; }
|
||||||
| TEXT { $$.ptr = $1; $$.patt = 1; }
|
| TEXT { $$.ptr = $1; $$.patt = 1; }
|
||||||
;
|
;
|
||||||
|
|
|
@ -129,16 +129,16 @@ dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
|
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
|
||||||
|
|
||||||
CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])
|
CF_CLI(SHOW BABEL INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])
|
||||||
{ babel_show_interfaces(proto_get_named($4, &proto_babel), $5); };
|
{ babel_show_interfaces(proto_get_named($4, &proto_babel), $5); };
|
||||||
|
|
||||||
CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about Babel neighbors]])
|
CF_CLI(SHOW BABEL NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel neighbors]])
|
||||||
{ babel_show_neighbors(proto_get_named($4, &proto_babel), $5); };
|
{ babel_show_neighbors(proto_get_named($4, &proto_babel), $5); };
|
||||||
|
|
||||||
CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
|
CF_CLI(SHOW BABEL ENTRIES, optproto opttext, [<name>], [[Show information about Babel prefix entries]])
|
||||||
{ babel_show_entries(proto_get_named($4, &proto_babel)); };
|
{ babel_show_entries(proto_get_named($4, &proto_babel)); };
|
||||||
|
|
||||||
CF_CLI(SHOW BABEL ROUTES, optsym opttext, [<name>], [[Show information about Babel route entries]])
|
CF_CLI(SHOW BABEL ROUTES, optproto opttext, [<name>], [[Show information about Babel route entries]])
|
||||||
{ babel_show_routes(proto_get_named($4, &proto_babel)); };
|
{ babel_show_routes(proto_get_named($4, &proto_babel)); };
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
|
@ -134,7 +134,7 @@ bfd_multihop:
|
||||||
|
|
||||||
bfd_neigh_iface:
|
bfd_neigh_iface:
|
||||||
/* empty */ { $$ = NULL; }
|
/* empty */ { $$ = NULL; }
|
||||||
| '%' SYM { $$ = if_get_by_name($2->name); }
|
| '%' symbol { $$ = if_get_by_name($2->name); }
|
||||||
| DEV text { $$ = if_get_by_name($2); }
|
| DEV text { $$ = if_get_by_name($2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop
|
||||||
|
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]);
|
CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]);
|
||||||
CF_CLI(SHOW BFD SESSIONS, optsym, [<name>], [[Show information about BFD sessions]])
|
CF_CLI(SHOW BFD SESSIONS, optproto, [<name>], [[Show information about BFD sessions]])
|
||||||
{ bfd_show_sessions(proto_get_named($4, &proto_bfd)); };
|
{ bfd_show_sessions(proto_get_named($4, &proto_bfd)); };
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
|
@ -504,29 +504,29 @@ dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF
|
||||||
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ;
|
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ;
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
|
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
|
||||||
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]])
|
CF_CLI(SHOW OSPF, optproto, [<name>], [[Show information about OSPF protocol]])
|
||||||
{ ospf_sh(proto_get_named($3, &proto_ospf)); };
|
{ ospf_sh(proto_get_named($3, &proto_ospf)); };
|
||||||
|
|
||||||
CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])
|
CF_CLI(SHOW OSPF NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])
|
||||||
{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); };
|
{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); };
|
||||||
|
|
||||||
CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
|
CF_CLI(SHOW OSPF INTERFACE, optproto opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
|
||||||
{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
|
{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [<name>], [[Show information about OSPF network topology]])
|
CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [<name>], [[Show information about OSPF network topology]])
|
||||||
|
|
||||||
CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [<name>], [[Show information about reachable OSPF network topology]])
|
CF_CLI(SHOW OSPF TOPOLOGY, optproto opttext, [<name>], [[Show information about reachable OSPF network topology]])
|
||||||
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); };
|
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); };
|
||||||
|
|
||||||
CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [<name>], [[Show information about all OSPF network topology]])
|
CF_CLI(SHOW OSPF TOPOLOGY ALL, optproto opttext, [<name>], [[Show information about all OSPF network topology]])
|
||||||
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); };
|
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); };
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW OSPF STATE, [all] [<name>], [[Show information about OSPF network state]])
|
CF_CLI_HELP(SHOW OSPF STATE, [all] [<name>], [[Show information about OSPF network state]])
|
||||||
|
|
||||||
CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[Show information about reachable OSPF network state]])
|
CF_CLI(SHOW OSPF STATE, optproto opttext, [<name>], [[Show information about reachable OSPF network state]])
|
||||||
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); };
|
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); };
|
||||||
|
|
||||||
CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [<name>], [[Show information about all OSPF network state]])
|
CF_CLI(SHOW OSPF STATE ALL, optproto opttext, [<name>], [[Show information about all OSPF network state]])
|
||||||
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); };
|
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); };
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]);
|
CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]);
|
||||||
|
@ -544,7 +544,7 @@ lsadb_args:
|
||||||
| lsadb_args LSID idval { $$ = $1; $$->lsid = $3; }
|
| lsadb_args LSID idval { $$ = $1; $$->lsid = $3; }
|
||||||
| lsadb_args SELF { $$ = $1; $$->router = SH_ROUTER_SELF; }
|
| lsadb_args SELF { $$ = $1; $$->router = SH_ROUTER_SELF; }
|
||||||
| lsadb_args ROUTER idval { $$ = $1; $$->router = $3; }
|
| lsadb_args ROUTER idval { $$ = $1; $$->router = $3; }
|
||||||
| lsadb_args SYM { $$ = $1; $$->name = $2; }
|
| lsadb_args CF_SYM_PROTO { $$ = $1; $$->proto = (struct ospf_proto *) proto_get_named($2, &proto_ospf); }
|
||||||
;
|
;
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
|
@ -1402,7 +1402,7 @@ lsa_compare_for_lsadb(const void *p1, const void *p2)
|
||||||
void
|
void
|
||||||
ospf_sh_lsadb(struct lsadb_show_data *ld)
|
ospf_sh_lsadb(struct lsadb_show_data *ld)
|
||||||
{
|
{
|
||||||
struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
|
struct ospf_proto *p = ld->proto;
|
||||||
uint num = p->gr->hash_entries;
|
uint num = p->gr->hash_entries;
|
||||||
uint i, j;
|
uint i, j;
|
||||||
int last_dscope = -1;
|
int last_dscope = -1;
|
||||||
|
|
|
@ -900,7 +900,7 @@ struct ospf_lsreq_header
|
||||||
#define SH_ROUTER_SELF 0xffffffff
|
#define SH_ROUTER_SELF 0xffffffff
|
||||||
|
|
||||||
struct lsadb_show_data {
|
struct lsadb_show_data {
|
||||||
struct symbol *name; /* Protocol to request data from */
|
struct ospf_proto *proto; /* Protocol to request data from */
|
||||||
u16 type; /* LSA Type, 0 -> all */
|
u16 type; /* LSA Type, 0 -> all */
|
||||||
u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */
|
u16 scope; /* Scope, 0 -> all, hack to handle link scope as 1 */
|
||||||
u32 area; /* Specified for area scope */
|
u32 area; /* Specified for area scope */
|
||||||
|
|
|
@ -191,10 +191,10 @@ dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_T
|
||||||
|
|
||||||
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
|
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
|
||||||
|
|
||||||
CF_CLI(SHOW RIP INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])
|
CF_CLI(SHOW RIP INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])
|
||||||
{ rip_show_interfaces(proto_get_named($4, &proto_rip), $5); };
|
{ rip_show_interfaces(proto_get_named($4, &proto_rip), $5); };
|
||||||
|
|
||||||
CF_CLI(SHOW RIP NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about RIP neighbors]])
|
CF_CLI(SHOW RIP NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP neighbors]])
|
||||||
{ rip_show_neighbors(proto_get_named($4, &proto_rip), $5); };
|
{ rip_show_neighbors(proto_get_named($4, &proto_rip), $5); };
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ stat_route_opt_list:
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
CF_CLI(SHOW STATIC, optsym, [<name>], [[Show details of static protocol]])
|
CF_CLI(SHOW STATIC, optproto, [<name>], [[Show details of static protocol]])
|
||||||
{ static_show(proto_get_named($3, &proto_static)); } ;
|
{ static_show(proto_get_named($3, &proto_static)); } ;
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
Loading…
Reference in a new issue