Merge branch 'mq-filter-stack' of gitlab.labs.nic.cz:labs/bird into mq-filter-stack
This commit is contained in:
commit
8816b6cdd9
17 changed files with 453 additions and 258 deletions
|
@ -64,7 +64,9 @@ CF_DECLS
|
|||
struct rtable_config *r;
|
||||
struct channel_config *cc;
|
||||
struct f_inst *x;
|
||||
struct f_inst *xp[2];
|
||||
struct {
|
||||
struct f_inst *begin, *end;
|
||||
} xp;
|
||||
enum filter_return fret;
|
||||
enum ec_subtype ecs;
|
||||
struct f_dynamic_attr fda;
|
||||
|
|
|
@ -447,7 +447,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
|||
%nonassoc ELSE
|
||||
|
||||
%type <xp> cmds_int
|
||||
%type <x> term block cmd cmds constant constructor print_one print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
|
||||
%type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
|
||||
%type <fda> dynamic_attr
|
||||
%type <fsa> static_attr
|
||||
%type <f> filter where_filter
|
||||
|
@ -621,11 +621,21 @@ function_def:
|
|||
/* Programs */
|
||||
|
||||
cmds: /* EMPTY */ { $$ = NULL; }
|
||||
| cmds_int { $$ = $1[0]; }
|
||||
| cmds_int { $$ = $1.begin; }
|
||||
;
|
||||
|
||||
cmds_int: cmd { $$[0] = $$[1] = $1; }
|
||||
| cmds_int cmd { $$[1] = $2; $1[1]->next = $2; $$[0] = $1[0]; }
|
||||
cmds_int: cmd {
|
||||
$$.begin = $$.end = $1;
|
||||
while ($$.end->next)
|
||||
$$.end = $$.end->next;
|
||||
}
|
||||
| cmds_int cmd {
|
||||
$$.begin = $1.begin;
|
||||
$1.end->next = $2;
|
||||
$$.end = $2;
|
||||
while ($$.end->next)
|
||||
$$.end = $$.end->next;
|
||||
}
|
||||
;
|
||||
|
||||
block:
|
||||
|
@ -960,17 +970,13 @@ break_command:
|
|||
| PRINTN { $$ = F_NONL; }
|
||||
;
|
||||
|
||||
print_one:
|
||||
term { $$ = f_new_inst(FI_PRINT, $1); }
|
||||
;
|
||||
|
||||
print_list: /* EMPTY */ { $$ = NULL; }
|
||||
| print_one { $$ = $1; }
|
||||
| print_one ',' print_list {
|
||||
if ($1) {
|
||||
$1->next = $3;
|
||||
$$ = $1;
|
||||
} else $$ = $3;
|
||||
| term { $$ = $1; }
|
||||
| term ',' print_list {
|
||||
ASSERT($1);
|
||||
ASSERT($1->next == NULL);
|
||||
$1->next = $3;
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1011,7 +1017,22 @@ cmd:
|
|||
| UNSET '(' dynamic_attr ')' ';' {
|
||||
$$ = f_new_inst(FI_EA_UNSET, $3);
|
||||
}
|
||||
| break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); }
|
||||
| break_command print_list ';' {
|
||||
struct f_inst *breaker = NULL;
|
||||
struct f_inst *printer = NULL;
|
||||
if ($2)
|
||||
printer = f_new_inst(FI_PRINT, $2);
|
||||
if ($1 != F_NONL)
|
||||
breaker = f_new_inst(FI_DIE, $1);
|
||||
|
||||
if (printer && breaker)
|
||||
printer->next = breaker;
|
||||
|
||||
if (printer)
|
||||
$$ = printer;
|
||||
else
|
||||
$$ = breaker;
|
||||
}
|
||||
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
|
||||
| CASE term '{' switch_body '}' {
|
||||
$$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
|
||||
|
|
437
filter/decl.m4
437
filter/decl.m4
|
@ -6,177 +6,123 @@ m4_divert(-1)m4_dnl
|
|||
#
|
||||
# Can be freely distributed and used under the terms of the GNU GPL.
|
||||
#
|
||||
# THIS IS A M4 MACRO FILE GENERATING 3 FILES ALTOGETHER.
|
||||
# KEEP YOUR HANDS OFF UNLESS YOU KNOW WHAT YOU'RE DOING.
|
||||
# EDITING AND DEBUGGING THIS FILE MAY DAMAGE YOUR BRAIN SERIOUSLY.
|
||||
#
|
||||
# Global Diversions:
|
||||
# 4 enum fi_code
|
||||
# 5 enum fi_code to string
|
||||
# 6 dump line item
|
||||
# 7 dump line item callers
|
||||
# 8 linearize
|
||||
# 9 same (filter comparator)
|
||||
# 1 union in struct f_inst
|
||||
# 3 constructors + interpreter
|
||||
# But you're welcome to read and edit and debug if you aren't scared.
|
||||
#
|
||||
# Uncomment the following line to get exhaustive debug output.
|
||||
# m4_debugmode(aceflqtx)
|
||||
#
|
||||
# How it works:
|
||||
# 1) Instruction to code conversion (uses diversions 100..199)
|
||||
# 2) Code wrapping (uses diversions 1..99)
|
||||
# 3) Final preparation (uses diversions 200..299)
|
||||
# 4) Shipout
|
||||
#
|
||||
# See below for detailed description.
|
||||
#
|
||||
#
|
||||
# 1) Instruction to code conversion
|
||||
# The code provided in f-inst.c between consecutive INST() calls
|
||||
# is interleaved for many different places. It is here processed
|
||||
# and split into separate instances where split-by-instruction
|
||||
# happens. These parts are stored in temporary diversions listed:
|
||||
#
|
||||
# Per-inst Diversions:
|
||||
# 101 content of per-inst struct
|
||||
# 102 constructor arguments
|
||||
# 103 constructor body
|
||||
# 104 dump line item content
|
||||
# (there may be nothing in dump-line content and
|
||||
# it must be handled specially in phase 2)
|
||||
# 105 linearize body
|
||||
# 106 comparator body
|
||||
# 107 struct f_line_item content
|
||||
# 108 interpreter body
|
||||
#
|
||||
# Final diversions
|
||||
# 200+ completed text before it is flushed to output
|
||||
|
||||
m4_dnl m4_debugmode(aceflqtx)
|
||||
|
||||
m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */')
|
||||
m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)')
|
||||
m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)')
|
||||
m4_define(FID_NEW, `FID_ZONE(3, Constructor)')
|
||||
m4_define(FID_ENUM, `FID_ZONE(4, Code enum)')
|
||||
m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)')
|
||||
m4_define(FID_DUMP, `FID_ZONE(6, Dump line)')
|
||||
m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)')
|
||||
m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)')
|
||||
m4_define(FID_SAME, `FID_ZONE(9, Comparison)')
|
||||
|
||||
# Here are macros to allow you to _divert to the right directions.
|
||||
m4_define(FID_STRUCT_IN, `m4_divert(101)')
|
||||
m4_define(FID_NEW_ARGS, `m4_divert(102)')
|
||||
m4_define(FID_NEW_BODY, `m4_divert(103)')
|
||||
m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])')
|
||||
m4_define(FID_LINEARIZE_BODY, `m4_divert(105)m4_define([[FID_LINEARIZE_BODY_EXISTS]])')
|
||||
m4_define(FID_LINEARIZE_BODY, `m4_divert(105)')
|
||||
m4_define(FID_SAME_BODY, `m4_divert(106)')
|
||||
m4_define(FID_LINE_IN, `m4_divert(107)')
|
||||
m4_define(FID_INTERPRET_BODY, `m4_divert(108)')
|
||||
|
||||
m4_define(FID_ALL, `FID_INTERPRET_BODY');
|
||||
# Sometimes you want slightly different code versions in different
|
||||
# outputs.
|
||||
# Use FID_HIC(code for inst-gen.h, code for inst-gen.c, code for inst-interpret.c)
|
||||
# and put it into [[ ]] quotes if it shall contain commas.
|
||||
m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], [[$1]], TARGET, [[I]], [[$2]], TARGET, [[C]], [[$3]])')
|
||||
|
||||
# In interpreter code, this is quite common.
|
||||
m4_define(FID_INTERPRET_EXEC, `FID_HIC(,[[FID_INTERPRET_BODY()]],[[m4_divert(-1)]])')
|
||||
m4_define(FID_INTERPRET_NEW, `FID_HIC(,[[m4_divert(-1)]],[[FID_INTERPRET_BODY()]])')
|
||||
|
||||
# If the instruction is never converted to constant, the interpret
|
||||
# code is not produced at all for constructor
|
||||
m4_define(NEVER_CONSTANT, `m4_define([[INST_NEVER_CONSTANT]])')
|
||||
m4_define(FID_IFCONST, `m4_ifdef([[INST_NEVER_CONSTANT]],[[$2]],[[$1]])')
|
||||
|
||||
m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[
|
||||
FID_ENUM
|
||||
INST_NAME(),
|
||||
FID_ENUM_STR
|
||||
[INST_NAME()] = "INST_NAME()",
|
||||
FID_INST
|
||||
struct {
|
||||
m4_undivert(101)
|
||||
} i_[[]]INST_NAME();
|
||||
FID_LINE
|
||||
struct {
|
||||
m4_undivert(107)
|
||||
} i_[[]]INST_NAME();
|
||||
FID_NEW
|
||||
FID_HIC(
|
||||
[[
|
||||
struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
|
||||
m4_undivert(102)
|
||||
);]],
|
||||
[[
|
||||
case INST_NAME():
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]])
|
||||
m4_undivert(108)
|
||||
#undef whati
|
||||
break;
|
||||
]],
|
||||
[[
|
||||
struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
|
||||
m4_undivert(102)
|
||||
)
|
||||
{
|
||||
struct f_inst *what = fi_new(fi_code);
|
||||
FID_IFCONST([[uint constargs = 1;]])
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
m4_undivert(103)
|
||||
FID_IFCONST([[if (!constargs)]])
|
||||
return what;
|
||||
FID_IFCONST([[m4_undivert(108)]])
|
||||
#undef whati
|
||||
}
|
||||
]])
|
||||
|
||||
FID_DUMP_CALLER
|
||||
case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break;
|
||||
|
||||
FID_DUMP
|
||||
m4_ifdef([[FID_DUMP_BODY_EXISTS]],
|
||||
[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]],
|
||||
[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]])
|
||||
m4_undefine([[FID_DUMP_BODY_EXISTS]])
|
||||
{
|
||||
#define item (&(item_->i_]]INST_NAME()[[))
|
||||
m4_undivert(104)
|
||||
#undef item
|
||||
}
|
||||
|
||||
FID_LINEARIZE
|
||||
case INST_NAME(): {
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
#define item (&(dest->items[pos].i_]]INST_NAME()[[))
|
||||
m4_undivert(105)
|
||||
#undef whati
|
||||
#undef item
|
||||
dest->items[pos].fi_code = what->fi_code;
|
||||
dest->items[pos].lineno = what->lineno;
|
||||
break;
|
||||
}
|
||||
m4_undefine([[FID_LINEARIZE_BODY_EXISTS]])
|
||||
|
||||
FID_SAME
|
||||
case INST_NAME():
|
||||
#define f1 (&(f1_->i_]]INST_NAME()[[))
|
||||
#define f2 (&(f2_->i_]]INST_NAME()[[))
|
||||
m4_undivert(106)
|
||||
#undef f1
|
||||
#undef f2
|
||||
break;
|
||||
m4_divert(-1)FID_FLUSH(101,200)
|
||||
]])')
|
||||
|
||||
m4_define(INST, `m4_dnl
|
||||
INST_FLUSH()m4_dnl
|
||||
m4_define([[INST_NAME]], [[$1]])m4_dnl
|
||||
m4_define([[INST_INVAL]], [[$2]])m4_dnl
|
||||
m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl
|
||||
FID_ALL() m4_dnl
|
||||
')
|
||||
|
||||
# If the instruction has some attributes (here called members),
|
||||
# these are typically carried with the instruction from constructor
|
||||
# to interpreter. This yields a line of code everywhere on the path.
|
||||
# FID_MEMBER is a macro to help with this task.
|
||||
m4_define(FID_MEMBER, `m4_dnl
|
||||
FID_LINE_IN
|
||||
$1 $2;
|
||||
FID_STRUCT_IN
|
||||
$1 $2;
|
||||
FID_NEW_ARGS
|
||||
, $1 $2
|
||||
FID_NEW_BODY
|
||||
FID_LINE_IN()m4_dnl
|
||||
$1 $2;
|
||||
FID_STRUCT_IN()m4_dnl
|
||||
$1 $2;
|
||||
FID_NEW_ARGS()m4_dnl
|
||||
, $1 $2
|
||||
FID_NEW_BODY()m4_dnl
|
||||
whati->$2 = $2;
|
||||
FID_LINEARIZE_BODY
|
||||
FID_LINEARIZE_BODY()m4_dnl
|
||||
item->$2 = whati->$2;
|
||||
m4_ifelse($3,,,[[
|
||||
FID_SAME_BODY
|
||||
FID_SAME_BODY()m4_dnl
|
||||
if ($3) return 0;
|
||||
]])
|
||||
m4_ifelse($4,,,[[
|
||||
FID_DUMP_BODY
|
||||
FID_DUMP_BODY()m4_dnl
|
||||
debug("%s$4\n", INDENT, $5);
|
||||
]])
|
||||
FID_INTERPRET_EXEC
|
||||
FID_INTERPRET_EXEC()m4_dnl
|
||||
const $1 $2 = whati->$2
|
||||
FID_ALL')
|
||||
FID_INTERPRET_BODY')
|
||||
|
||||
m4_define(FID_MEMBER_IN, `m4_dnl
|
||||
FID_LINE_IN()m4_dnl
|
||||
$1 $2;
|
||||
FID_STRUCT_IN()m4_dnl
|
||||
$1 $2;
|
||||
FID_LINEARIZE_BODY()m4_dnl
|
||||
item->$2 = whati->$2;
|
||||
m4_ifelse($3,,,[[
|
||||
FID_SAME_BODY()m4_dnl
|
||||
if ($3) return 0;
|
||||
]])
|
||||
m4_ifelse($4,,,[[
|
||||
FID_DUMP_BODY()m4_dnl
|
||||
debug("%s$4\n", INDENT, $5);
|
||||
]])
|
||||
FID_INTERPRET_EXEC()m4_dnl
|
||||
const $1 $2 = whati->$2
|
||||
FID_INTERPRET_BODY')
|
||||
|
||||
# Instruction arguments are needed only until linearization is done.
|
||||
# This puts the arguments into the filter line to be executed before
|
||||
# the instruction itself.
|
||||
#
|
||||
# To achieve this, ARG_ANY must be called before anything writes into
|
||||
# the instruction line as it moves the instruction pointer forward.
|
||||
m4_define(ARG_ANY, `
|
||||
FID_STRUCT_IN
|
||||
struct f_inst * f$1;
|
||||
FID_NEW_ARGS
|
||||
, struct f_inst * f$1
|
||||
FID_STRUCT_IN()m4_dnl
|
||||
struct f_inst * f$1;
|
||||
FID_NEW_ARGS()m4_dnl
|
||||
, struct f_inst * f$1
|
||||
FID_NEW_BODY
|
||||
whati->f$1 = f$1;
|
||||
for (const struct f_inst *child = f$1; child; child = child->next) {
|
||||
|
@ -188,14 +134,17 @@ FID_IFCONST([[
|
|||
}
|
||||
FID_LINEARIZE_BODY
|
||||
pos = linearize(dest, whati->f$1, pos);
|
||||
FID_ALL()')
|
||||
FID_INTERPRET_BODY()')
|
||||
|
||||
# Some arguments need to check their type. After that, ARG_ANY is called.
|
||||
m4_define(ARG, `ARG_ANY($1)
|
||||
FID_INTERPRET_EXEC()
|
||||
FID_INTERPRET_EXEC()m4_dnl
|
||||
if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl
|
||||
FID_ALL()')
|
||||
FID_INTERPRET_BODY()')
|
||||
|
||||
m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_ALL()')
|
||||
# Executing another filter line. This replaces the recursion
|
||||
# that was needed in the former implementation.
|
||||
m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()')
|
||||
m4_define(LINEX_, `do {
|
||||
fstk->estk[fstk->ecnt].pos = 0;
|
||||
fstk->estk[fstk->ecnt].line = $1;
|
||||
|
@ -206,47 +155,212 @@ m4_define(LINEX_, `do {
|
|||
} while (0)')
|
||||
|
||||
m4_define(LINE, `
|
||||
FID_LINE_IN
|
||||
const struct f_line * fl$1;
|
||||
FID_STRUCT_IN
|
||||
struct f_inst * f$1;
|
||||
FID_NEW_ARGS
|
||||
, struct f_inst * f$1
|
||||
FID_NEW_BODY
|
||||
FID_LINE_IN()m4_dnl
|
||||
const struct f_line * fl$1;
|
||||
FID_STRUCT_IN()m4_dnl
|
||||
struct f_inst * f$1;
|
||||
FID_NEW_ARGS()m4_dnl
|
||||
, struct f_inst * f$1
|
||||
FID_NEW_BODY()m4_dnl
|
||||
whati->f$1 = f$1;
|
||||
FID_DUMP_BODY
|
||||
FID_DUMP_BODY()m4_dnl
|
||||
f_dump_line(item->fl$1, indent + 1);
|
||||
FID_LINEARIZE_BODY
|
||||
FID_LINEARIZE_BODY()m4_dnl
|
||||
item->fl$1 = f_linearize(whati->f$1);
|
||||
FID_SAME_BODY
|
||||
FID_SAME_BODY()m4_dnl
|
||||
if (!f_same(f1->fl$1, f2->fl$1)) return 0;
|
||||
FID_INTERPRET_EXEC
|
||||
FID_INTERPRET_EXEC()m4_dnl
|
||||
do { if (whati->fl$1) {
|
||||
LINEX_(whati->fl$1);
|
||||
} } while(0)
|
||||
FID_INTERPRET_NEW
|
||||
FID_INTERPRET_NEW()m4_dnl
|
||||
return whati->f$1
|
||||
FID_ALL()')
|
||||
FID_INTERPRET_BODY()')
|
||||
|
||||
# Some of the instructions have a result. These constructions
|
||||
# state the result and put it to the right place.
|
||||
m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
|
||||
m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]],
|
||||
[[return fi_constant(what, $1)]])')
|
||||
m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])')
|
||||
|
||||
m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym,
|
||||
[[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)')
|
||||
# Some common filter instruction members
|
||||
m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name)')
|
||||
m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name)')
|
||||
m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)')
|
||||
m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)')
|
||||
m4_define(ACCESS_RTE, `NEVER_CONSTANT()')
|
||||
|
||||
# 2) Code wrapping
|
||||
# The code produced in 1xx temporary diversions is a raw code without
|
||||
# any auxiliary commands and syntactical structures around. When the
|
||||
# instruction is done, INST_FLUSH is called. More precisely, it is called
|
||||
# at the beginning of INST() call and at the end of file.
|
||||
#
|
||||
# INST_FLUSH picks all the temporary diversions, wraps their content
|
||||
# into appropriate headers and structures and saves them into global
|
||||
# diversions listed:
|
||||
#
|
||||
# 4 enum fi_code
|
||||
# 5 enum fi_code to string
|
||||
# 6 dump line item
|
||||
# 7 dump line item callers
|
||||
# 8 linearize
|
||||
# 9 same (filter comparator)
|
||||
# 1 union in struct f_inst
|
||||
# 3 constructors + interpreter
|
||||
#
|
||||
# These global diversions contain blocks of code that can be directly
|
||||
# put into the final file, yet it still can't be written out now as
|
||||
# every instruction writes to all of these diversions.
|
||||
|
||||
# Code wrapping diversion names. Here we want an explicit newline
|
||||
# after the C comment.
|
||||
m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */
|
||||
')
|
||||
m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)')
|
||||
m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)')
|
||||
m4_define(FID_NEW, `FID_ZONE(3, Constructor)')
|
||||
m4_define(FID_ENUM, `FID_ZONE(4, Code enum)')
|
||||
m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)')
|
||||
m4_define(FID_DUMP, `FID_ZONE(6, Dump line)')
|
||||
m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)')
|
||||
m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)')
|
||||
m4_define(FID_SAME, `FID_ZONE(9, Comparison)')
|
||||
|
||||
# This macro does all the code wrapping. See inline comments.
|
||||
m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[
|
||||
FID_ENUM()m4_dnl Contents of enum fi_code { ... }
|
||||
INST_NAME(),
|
||||
FID_ENUM_STR()m4_dnl Contents of const char * indexed by enum fi_code
|
||||
[INST_NAME()] = "INST_NAME()",
|
||||
FID_INST()m4_dnl Anonymous structure inside struct f_inst
|
||||
struct {
|
||||
m4_undivert(101)m4_dnl
|
||||
} i_[[]]INST_NAME();
|
||||
FID_LINE()m4_dnl Anonymous structure inside struct f_line_item
|
||||
struct {
|
||||
m4_undivert(107)m4_dnl
|
||||
} i_[[]]INST_NAME();
|
||||
FID_NEW()m4_dnl Constructor and interpreter code together
|
||||
FID_HIC(
|
||||
[[m4_dnl Public declaration of constructor in H file
|
||||
struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
|
||||
m4_undivert(102)m4_dnl
|
||||
);]],
|
||||
[[m4_dnl The one case in The Big Switch inside interpreter
|
||||
case INST_NAME():
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]])
|
||||
m4_undivert(108)m4_dnl
|
||||
#undef whati
|
||||
break;
|
||||
]],
|
||||
[[m4_dnl Constructor itself
|
||||
struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
|
||||
m4_undivert(102)m4_dnl
|
||||
)
|
||||
{
|
||||
/* Allocate the structure */
|
||||
struct f_inst *what = fi_new(fi_code);
|
||||
FID_IFCONST([[uint constargs = 1;]])
|
||||
|
||||
/* Initialize all the members */
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
m4_undivert(103)m4_dnl
|
||||
|
||||
/* If not constant, return the instruction itself */
|
||||
FID_IFCONST([[if (!constargs)]])
|
||||
return what;
|
||||
|
||||
/* Try to pre-calculate the result */
|
||||
FID_IFCONST([[m4_undivert(108)]])m4_dnl
|
||||
#undef whati
|
||||
}
|
||||
]])
|
||||
|
||||
FID_DUMP_CALLER()m4_dnl Case in another big switch used in instruction dumping (debug)
|
||||
case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break;
|
||||
|
||||
FID_DUMP()m4_dnl The dumper itself
|
||||
m4_ifdef([[FID_DUMP_BODY_EXISTS]],
|
||||
[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]],
|
||||
[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]])
|
||||
m4_undefine([[FID_DUMP_BODY_EXISTS]])
|
||||
{
|
||||
#define item (&(item_->i_]]INST_NAME()[[))
|
||||
m4_undivert(104)m4_dnl
|
||||
#undef item
|
||||
}
|
||||
|
||||
FID_LINEARIZE()m4_dnl The linearizer
|
||||
case INST_NAME(): {
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
#define item (&(dest->items[pos].i_]]INST_NAME()[[))
|
||||
m4_undivert(105)m4_dnl
|
||||
#undef whati
|
||||
#undef item
|
||||
dest->items[pos].fi_code = what->fi_code;
|
||||
dest->items[pos].lineno = what->lineno;
|
||||
break;
|
||||
}
|
||||
|
||||
FID_SAME()m4_dnl This code compares two f_line"s while reconfiguring
|
||||
case INST_NAME():
|
||||
#define f1 (&(f1_->i_]]INST_NAME()[[))
|
||||
#define f2 (&(f2_->i_]]INST_NAME()[[))
|
||||
m4_undivert(106)m4_dnl
|
||||
#undef f1
|
||||
#undef f2
|
||||
break;
|
||||
|
||||
m4_divert(-1)FID_FLUSH(101,200)m4_dnl And finally this flushes all the unused diversions
|
||||
]])')
|
||||
|
||||
m4_define(INST, `m4_dnl This macro is called on beginning of each instruction.
|
||||
INST_FLUSH()m4_dnl First, old data is flushed
|
||||
m4_define([[INST_NAME]], [[$1]])m4_dnl Then we store instruction name,
|
||||
m4_define([[INST_INVAL]], [[$2]])m4_dnl instruction input value count
|
||||
m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl and reset NEVER_CONSTANT trigger.
|
||||
FID_INTERPRET_BODY()m4_dnl By default, every code is interpreter code.
|
||||
')
|
||||
|
||||
# 3) Final preparation
|
||||
#
|
||||
# Now we prepare all the code around the global diversions.
|
||||
# It must be here, not in m4wrap, as we want M4 to mark the code
|
||||
# by #line directives correctly, not to claim that every single line
|
||||
# is at the beginning of the m4wrap directive.
|
||||
#
|
||||
# This part is split by the final file.
|
||||
# H for inst-gen.h
|
||||
# I for inst-interpret.c
|
||||
# C for inst-gen.c
|
||||
#
|
||||
# So we in cycle:
|
||||
# A. open a diversion
|
||||
# B. send there some code
|
||||
# C. close that diversion
|
||||
# D. flush a global diversion
|
||||
# E. open another diversion and goto B.
|
||||
#
|
||||
# Final diversions
|
||||
# 200+ completed text before it is flushed to output
|
||||
|
||||
# This is a list of output diversions
|
||||
m4_define(FID_WR_PUT_LIST)
|
||||
|
||||
# This macro does the steps C to E, see before.
|
||||
m4_define(FID_WR_PUT_ALSO, `m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST()[[FID_WR_DPUT(]]FID_WR_DIDX[[)FID_WR_DPUT(]]$1[[)]])m4_define([[FID_WR_DIDX]],m4_eval(FID_WR_DIDX+1))m4_divert(FID_WR_DIDX)')
|
||||
|
||||
# These macros do the splitting between H/I/C
|
||||
m4_define(FID_WR_DIRECT, `m4_ifelse(TARGET,[[$1]],[[FID_WR_INIT()]],[[FID_WR_STOP()]])')
|
||||
m4_define(FID_WR_INIT, `m4_define([[FID_WR_DIDX]],200)m4_define([[FID_WR_PUT]],[[FID_WR_PUT_ALSO($]][[@)]])m4_divert(200)')
|
||||
m4_define(FID_WR_STOP, `m4_define([[FID_WR_PUT]])m4_divert(-1)')
|
||||
|
||||
# Here is the direct code to be put into the output files
|
||||
# together with the undiversions, being hidden under FID_WR_PUT()
|
||||
|
||||
m4_changequote([[,]])
|
||||
FID_WR_DIRECT(I)
|
||||
FID_WR_PUT(3)
|
||||
|
@ -395,7 +509,7 @@ FID_WR_PUT(9)
|
|||
FID_WR_DIRECT(H)
|
||||
/* Filter instruction codes */
|
||||
enum f_instruction_code {
|
||||
FID_WR_PUT(4)
|
||||
FID_WR_PUT(4)m4_dnl
|
||||
} PACKED;
|
||||
|
||||
/* Filter instruction structure for config */
|
||||
|
@ -405,7 +519,7 @@ struct f_inst {
|
|||
int size; /* How many instructions are underneath */
|
||||
int lineno; /* Line number */
|
||||
union {
|
||||
FID_WR_PUT(1)
|
||||
FID_WR_PUT(1)m4_dnl
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -415,19 +529,30 @@ struct f_line_item {
|
|||
enum f_instruction_flags flags; /* Flags, instruction-specific */
|
||||
uint lineno; /* Where */
|
||||
union {
|
||||
FID_WR_PUT(2)
|
||||
FID_WR_PUT(2)m4_dnl
|
||||
};
|
||||
};
|
||||
|
||||
/* Instruction constructors */
|
||||
FID_WR_PUT(3)
|
||||
|
||||
m4_divert(-1)
|
||||
|
||||
# 4) Shipout
|
||||
#
|
||||
# Everything is prepared in FID_WR_PUT_LIST now. Let's go!
|
||||
|
||||
m4_changequote(`,')
|
||||
|
||||
# Flusher auxiliary macro
|
||||
m4_define(FID_FLUSH, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_FLUSH(m4_eval($1+1),$2)]])')
|
||||
|
||||
# Defining the macro used in FID_WR_PUT_LIST
|
||||
m4_define(FID_WR_DPUT, `m4_undivert($1)')
|
||||
|
||||
# After the code is read and parsed, we:
|
||||
m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_FLUSH(1,200)')
|
||||
|
||||
m4_changequote([[,]])
|
||||
# And now M4 is going to parse f-inst.c, fill the diversions
|
||||
# and after the file is done, the content of m4_m4wrap (see before)
|
||||
# is executed.
|
||||
|
|
|
@ -167,13 +167,13 @@
|
|||
}
|
||||
whati->f1 = NULL;
|
||||
}
|
||||
FID_ALL
|
||||
FID_INTERPRET_BODY
|
||||
|
||||
FID_INTERPRET_EXEC
|
||||
if (fstk->vcnt < whati->count) /* TODO: make this check systematic */
|
||||
runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count);
|
||||
|
||||
#define pv fstk->vstk[fstk->vcnt - count + i]
|
||||
#define pv fstk->vstk[fstk->vcnt - whati->count + i]
|
||||
|
||||
FID_INTERPRET_NEW
|
||||
#define pv items[i]->i_FI_CONSTANT.val
|
||||
|
@ -198,7 +198,7 @@
|
|||
|
||||
FID_INTERPRET_EXEC
|
||||
fstk->vcnt -= whati->count;
|
||||
FID_ALL
|
||||
FID_INTERPRET_BODY
|
||||
|
||||
pm->len = whati->count;
|
||||
RESULT(T_PATH_MASK, path_mask, pm);
|
||||
|
@ -320,11 +320,6 @@
|
|||
|
||||
RESULT_VAL(val);
|
||||
}
|
||||
INST(FI_PRINT, 1, 0) {
|
||||
NEVER_CONSTANT;
|
||||
ARG_ANY(1);
|
||||
val_format(&(v1), &fs->buf);
|
||||
}
|
||||
INST(FI_CONDITION, 1, 0) {
|
||||
ARG(1, T_BOOL);
|
||||
if (v1.val.i)
|
||||
|
@ -332,28 +327,37 @@
|
|||
else
|
||||
LINE(3,1);
|
||||
}
|
||||
INST(FI_PRINT_AND_DIE, 0, 0) {
|
||||
|
||||
INST(FI_PRINT, 0, 0) {
|
||||
NEVER_CONSTANT;
|
||||
FID_LINEARIZE_BODY
|
||||
{
|
||||
uint opos = pos;
|
||||
FID_ALL
|
||||
|
||||
ARG_ANY(1);
|
||||
FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count);
|
||||
|
||||
FID_LINEARIZE_BODY
|
||||
if (opos < pos)
|
||||
dest->items[pos].flags |= FIF_PRINTED;
|
||||
}
|
||||
FID_ALL
|
||||
FID_NEW_BODY
|
||||
uint len = 0;
|
||||
for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
|
||||
;
|
||||
whati->count = len;
|
||||
|
||||
FID_INTERPRET_BODY
|
||||
|
||||
#define pv fstk->vstk[fstk->vcnt - whati->count + i]
|
||||
if (whati->count)
|
||||
for (uint i=0; i<whati->count; i++)
|
||||
val_format(&(pv), &fs->buf);
|
||||
#undef pv
|
||||
|
||||
fstk->vcnt -= whati->count;
|
||||
}
|
||||
|
||||
INST(FI_DIE, 0, 0) {
|
||||
NEVER_CONSTANT;
|
||||
FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret));
|
||||
|
||||
if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) &&
|
||||
!(fs->flags & FF_SILENT))
|
||||
if (fs->buf.start < fs->buf.pos)
|
||||
log_commit(*L_INFO, &fs->buf);
|
||||
|
||||
switch (fret) {
|
||||
switch (whati->fret) {
|
||||
case F_QUITBIRD:
|
||||
die( "Filter asked me to die" );
|
||||
case F_ACCEPT:
|
||||
|
@ -361,7 +365,6 @@
|
|||
case F_ERROR:
|
||||
case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
|
||||
return fret; /* We have to return now, no more processing. */
|
||||
case F_NONL:
|
||||
case F_NOP:
|
||||
break;
|
||||
default:
|
||||
|
@ -1045,7 +1048,8 @@
|
|||
INST(FI_ASSERT, 1, 0) { /* Birdtest Assert */
|
||||
NEVER_CONSTANT;
|
||||
ARG(1, T_BOOL);
|
||||
FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s);
|
||||
|
||||
FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], string %s, item->s);
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
|
|
|
@ -80,8 +80,10 @@ static inline struct f_line *f_linearize(const struct f_inst *root)
|
|||
void f_dump_line(const struct f_line *, uint indent);
|
||||
|
||||
struct filter *f_new_where(struct f_inst *);
|
||||
static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
|
||||
{ return (struct f_dynamic_attr) { .type = type, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
|
||||
static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
|
||||
{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
|
||||
static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
|
||||
{ return (struct f_dynamic_attr) { .type = EAF_TYPE_BITFIELD, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
|
||||
static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
|
||||
{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
|
||||
struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument);
|
||||
|
|
|
@ -33,17 +33,17 @@ filter_name(const struct filter *filter)
|
|||
struct filter *f_new_where(struct f_inst *where)
|
||||
{
|
||||
struct f_inst acc = {
|
||||
.fi_code = FI_PRINT_AND_DIE,
|
||||
.fi_code = FI_DIE,
|
||||
.lineno = ifs->lino,
|
||||
.size = 1,
|
||||
.i_FI_PRINT_AND_DIE = { .fret = F_ACCEPT, },
|
||||
.i_FI_DIE = { .fret = F_ACCEPT, },
|
||||
};
|
||||
|
||||
struct f_inst rej = {
|
||||
.fi_code = FI_PRINT_AND_DIE,
|
||||
.fi_code = FI_DIE,
|
||||
.lineno = ifs->lino,
|
||||
.size = 1,
|
||||
.i_FI_PRINT_AND_DIE = { .fret = F_REJECT, },
|
||||
.i_FI_DIE = { .fret = F_REJECT, },
|
||||
};
|
||||
|
||||
struct f_inst i = {
|
||||
|
@ -174,7 +174,7 @@ ca_lookup(pool *p, const char *name, int f_type)
|
|||
}
|
||||
|
||||
cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1);
|
||||
cas->fda = f_new_dynamic_attr(ea_type, 0, f_type, EA_CUSTOM(id));
|
||||
cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id));
|
||||
cas->uc = 1;
|
||||
|
||||
strcpy(cas->name, name);
|
||||
|
|
|
@ -482,3 +482,41 @@ filter_commit(struct config *new, struct config *old)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void filters_dump_all(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
WALK_LIST(sym, config->symbols) {
|
||||
switch (sym->class) {
|
||||
case SYM_FILTER:
|
||||
debug("Named filter %s:\n", sym->name);
|
||||
f_dump_line(sym->filter->root, 1);
|
||||
break;
|
||||
case SYM_FUNCTION:
|
||||
debug("Function %s:\n", sym->name);
|
||||
f_dump_line(sym->function, 1);
|
||||
break;
|
||||
case SYM_PROTO:
|
||||
{
|
||||
debug("Protocol %s:\n", sym->name);
|
||||
struct channel *c;
|
||||
WALK_LIST(c, sym->proto->proto->channels) {
|
||||
debug(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]);
|
||||
if (c->in_filter == FILTER_ACCEPT)
|
||||
debug(" ALL\n");
|
||||
else if (c->in_filter == FILTER_REJECT)
|
||||
debug(" NONE\n");
|
||||
else if (c->in_filter == FILTER_UNDEF)
|
||||
debug(" UNDEF\n");
|
||||
else if (c->in_filter->sym) {
|
||||
ASSERT(c->in_filter->sym->filter == c->in_filter);
|
||||
debug(" named filter %s\n", c->in_filter->sym->name);
|
||||
} else {
|
||||
debug("\n");
|
||||
f_dump_line(c->in_filter->root, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,9 +64,11 @@ int f_same(const struct f_line *f1, const struct f_line *f2);
|
|||
|
||||
void filter_commit(struct config *new, struct config *old);
|
||||
|
||||
void filters_dump_all(void);
|
||||
|
||||
#define FILTER_ACCEPT NULL
|
||||
#define FILTER_REJECT ((void *) 1)
|
||||
#define FILTER_UNDEF ((void *) 2) /* Used in BGP */
|
||||
#define FILTER_REJECT ((struct filter *) 1)
|
||||
#define FILTER_UNDEF ((struct filter *) 2) /* Used in BGP */
|
||||
|
||||
#define FF_SILENT 2 /* Silent filter execution */
|
||||
|
||||
|
|
|
@ -271,7 +271,6 @@ as_path_to_old(struct linpool *pool, const struct adata *path)
|
|||
/*
|
||||
* Cut the path to the length @num, measured to the usual path metric. Note that
|
||||
* AS_CONFED_* segments have zero length and must be added if they are on edge.
|
||||
* In contrast to other as_path_* functions, @path is modified in place.
|
||||
*/
|
||||
struct adata *
|
||||
as_path_cut(struct linpool *pool, const struct adata *path, uint num)
|
||||
|
|
|
@ -731,6 +731,8 @@ CF_CLI(DUMP ROUTES,,, [[Dump routing table]])
|
|||
{ rt_dump_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
|
||||
{ protos_dump_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]])
|
||||
{ filters_dump_all(); cli_msg(0, ""); } ;
|
||||
|
||||
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
|
||||
{ cmd_eval(f_linearize($2)); } ;
|
||||
|
@ -791,7 +793,7 @@ proto_patt2:
|
|||
| TEXT { $$.ptr = $1; $$.patt = 1; }
|
||||
;
|
||||
|
||||
dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_GEN_IGP_METRIC); } ;
|
||||
dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ;
|
||||
|
||||
|
||||
CF_CODE
|
||||
|
|
|
@ -125,7 +125,7 @@ babel_iface_opt_list:
|
|||
babel_iface:
|
||||
babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish;
|
||||
|
||||
dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_BABEL_METRIC); } ;
|
||||
dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BABEL_METRIC); } ;
|
||||
|
||||
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
|
||||
|
||||
|
|
|
@ -272,29 +272,29 @@ bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end;
|
|||
|
||||
|
||||
dynamic_attr: BGP_ORIGIN
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ;
|
||||
dynamic_attr: BGP_PATH
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, 0, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ;
|
||||
dynamic_attr: BGP_NEXT_HOP
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ;
|
||||
dynamic_attr: BGP_MED
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ;
|
||||
dynamic_attr: BGP_LOCAL_PREF
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ;
|
||||
dynamic_attr: BGP_ATOMIC_AGGR
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, 0, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ;
|
||||
dynamic_attr: BGP_AGGREGATOR
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
|
||||
dynamic_attr: BGP_COMMUNITY
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ;
|
||||
dynamic_attr: BGP_ORIGINATOR_ID
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ;
|
||||
dynamic_attr: BGP_CLUSTER_LIST
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, 0, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ;
|
||||
dynamic_attr: BGP_EXT_COMMUNITY
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, 0, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ;
|
||||
dynamic_attr: BGP_LARGE_COMMUNITY
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, 0, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
|
||||
{ $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -498,10 +498,10 @@ ospf_iface:
|
|||
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
|
||||
;
|
||||
|
||||
dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC1); } ;
|
||||
dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_METRIC2); } ;
|
||||
dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_OSPF_TAG); } ;
|
||||
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, 0, T_QUAD, EA_OSPF_ROUTER_ID); } ;
|
||||
dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ;
|
||||
dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ;
|
||||
dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ;
|
||||
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ;
|
||||
|
||||
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
|
||||
CF_CLI(SHOW OSPF, optproto, [<name>], [[Show information about OSPF protocol]])
|
||||
|
|
|
@ -332,8 +332,8 @@ radv_sensitive:
|
|||
| SENSITIVE bool { $$ = $2; }
|
||||
;
|
||||
|
||||
dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ;
|
||||
dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RA_LIFETIME); } ;
|
||||
dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ;
|
||||
dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } ;
|
||||
|
||||
CF_CODE
|
||||
|
||||
|
|
|
@ -186,8 +186,8 @@ rip_iface:
|
|||
rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish;
|
||||
|
||||
|
||||
dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_METRIC); } ;
|
||||
dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_RIP_TAG); } ;
|
||||
dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_METRIC); } ;
|
||||
dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG); } ;
|
||||
|
||||
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
|
||||
|
||||
|
|
|
@ -26,39 +26,39 @@ kern_sys_item:
|
|||
| METRIC expr { THIS_KRT->sys.metric = $2; }
|
||||
;
|
||||
|
||||
dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, 0, T_IP, EA_KRT_PREFSRC); } ;
|
||||
dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REALM); } ;
|
||||
dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SCOPE); } ;
|
||||
dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ;
|
||||
dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } ;
|
||||
dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } ;
|
||||
|
||||
dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_MTU); } ;
|
||||
dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_WINDOW); } ;
|
||||
dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTT); } ;
|
||||
dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTTVAR); } ;
|
||||
dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SSTRESH); } ;
|
||||
dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_CWND); } ;
|
||||
dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_ADVMSS); } ;
|
||||
dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_REORDERING); } ;
|
||||
dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_HOPLIMIT); } ;
|
||||
dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITCWND); } ;
|
||||
dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_RTO_MIN); } ;
|
||||
dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_INITRWND); } ;
|
||||
dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_QUICKACK); } ;
|
||||
dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } ;
|
||||
dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } ;
|
||||
dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } ;
|
||||
dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } ;
|
||||
dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } ;
|
||||
dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } ;
|
||||
dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } ;
|
||||
dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } ;
|
||||
dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } ;
|
||||
dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } ;
|
||||
dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ;
|
||||
dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ;
|
||||
dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ;
|
||||
|
||||
/* Bits of EA_KRT_LOCK, based on RTAX_* constants */
|
||||
|
||||
dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 2, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 4, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 5, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 6, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 7, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 8, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 9, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 10, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 13, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, T_BOOL, EA_KRT_LOCK); } ;
|
||||
dynamic_attr: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, T_BOOL, EA_KRT_LOCK); } ;
|
||||
|
||||
dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 0, T_BOOL, EA_KRT_FEATURES); } ;
|
||||
dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, 3, T_BOOL, EA_KRT_FEATURES); } ;
|
||||
dynamic_attr: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, T_BOOL, EA_KRT_FEATURES); } ;
|
||||
dynamic_attr: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(3, T_BOOL, EA_KRT_FEATURES); } ;
|
||||
|
||||
|
||||
CF_CODE
|
||||
|
|
|
@ -122,8 +122,8 @@ kif_iface:
|
|||
kif_iface_start iface_patt_list_nopx kif_iface_opt_list;
|
||||
|
||||
|
||||
dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_SOURCE); } ;
|
||||
dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, 0, T_INT, EA_KRT_METRIC); } ;
|
||||
dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SOURCE); } ;
|
||||
dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_METRIC); } ;
|
||||
|
||||
CF_CODE
|
||||
|
||||
|
|
Loading…
Reference in a new issue