mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 12:48:43 +00:00
Merge commit '5951dfbd' into thread-next
This commit is contained in:
commit
e6baff89f8
@ -1654,7 +1654,8 @@ in the foot).
|
||||
|
||||
Statement <cf><m/P/ = prepend(<m/P/, <m/A/);</cf> can be shortened to
|
||||
<cf><m/P/.prepend(<m/A/);</cf> if <m/P/ is appropriate route attribute
|
||||
(for example <cf/bgp_path/). Similarly for <cf/delete/ and <cf/filter/.
|
||||
(for example <cf/bgp_path/) or a local variable.
|
||||
Similarly for <cf/delete/ and <cf/filter/.
|
||||
|
||||
<tag><label id="type-bgpmask">bgpmask</tag>
|
||||
BGP masks are patterns used for BGP path matching (using <cf>path
|
||||
@ -1703,7 +1704,8 @@ in the foot).
|
||||
|
||||
Statement <cf><m/C/ = add(<m/C/, <m/P/);</cf> can be shortened to
|
||||
<cf><m/C/.add(<m/P/);</cf> if <m/C/ is appropriate route attribute (for
|
||||
example <cf/bgp_community/). Similarly for <cf/delete/ and <cf/filter/.
|
||||
example <cf/bgp_community/) or a local variable.
|
||||
Similarly for <cf/delete/ and <cf/filter/.
|
||||
|
||||
<cf><m/C/.min</cf> returns the minimum element of clist <m/C/.
|
||||
|
||||
|
186
filter/config.Y
186
filter/config.Y
@ -19,18 +19,27 @@ static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
|
||||
static inline u32 pair_a(u32 p) { return p >> 16; }
|
||||
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
|
||||
|
||||
#define f_generate_complex(fi_code, da, arg) \
|
||||
f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
|
||||
static struct f_method_scope {
|
||||
struct f_inst *object;
|
||||
} f_method_scope_stack[32];
|
||||
static int f_method_scope_pos = -1;
|
||||
|
||||
#define f_generate_complex_sym(fi_code, sym, arg) ({ \
|
||||
if (sym->class != SYM_ATTRIBUTE) \
|
||||
cf_error("Can't empty %s: not an attribute", sym->name); \
|
||||
f_generate_complex(fi_code, sym->attribute, arg); \
|
||||
})
|
||||
#define FM (f_method_scope_stack[f_method_scope_pos])
|
||||
|
||||
#define f_generate_complex_default(fi_code, da, arg, def) \
|
||||
f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_DEFAULT, f_new_inst(FI_EA_GET, da), f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = def })), arg), da)
|
||||
|
||||
static inline void f_push_method_scope(struct f_inst *object)
|
||||
{
|
||||
if (++f_method_scope_pos >= (int) ARRAY_SIZE(f_method_scope_stack))
|
||||
cf_error("Too many nested method calls");
|
||||
FM = (struct f_method_scope) {
|
||||
.object = object,
|
||||
};
|
||||
}
|
||||
|
||||
static inline void f_pop_method_scope(void)
|
||||
{
|
||||
ASSERT_DIE(f_method_scope_pos >= 0);
|
||||
f_method_scope_pos--;
|
||||
}
|
||||
|
||||
static int
|
||||
f_new_var(struct sym_scope *s)
|
||||
@ -283,28 +292,54 @@ assert_done(struct f_inst *expr, const char *start, const char *end)
|
||||
: "???");
|
||||
}
|
||||
|
||||
static struct f_inst *
|
||||
f_lval_getter(struct f_lval *lval)
|
||||
{
|
||||
switch (lval->type) {
|
||||
case F_LVAL_VARIABLE: return f_new_inst(FI_VAR_GET, lval->sym);
|
||||
case F_LVAL_SA: return f_new_inst(FI_RTA_GET, lval->sa);
|
||||
case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->da);
|
||||
case F_LVAL_ATTR_BIT:
|
||||
{
|
||||
struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << lval->fab.bit)});
|
||||
return f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, lval->fab.class), c));
|
||||
}
|
||||
default: bug("Unknown lval type");
|
||||
}
|
||||
}
|
||||
|
||||
static struct f_inst *
|
||||
f_lval_setter(struct f_lval *lval, struct f_inst *expr)
|
||||
{
|
||||
switch (lval->type) {
|
||||
case F_LVAL_VARIABLE: return f_new_inst(FI_VAR_SET, expr, lval->sym);
|
||||
case F_LVAL_SA: return f_new_inst(FI_RTA_SET, expr, lval->sa);
|
||||
case F_LVAL_EA: return f_new_inst(FI_EA_SET, expr, lval->da);
|
||||
case F_LVAL_ATTR_BIT: return f_new_inst(FI_CONDITION, expr,
|
||||
f_new_inst(FI_EA_SET,
|
||||
f_new_inst(FI_BITOR,
|
||||
f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << lval->fab.bit)}),
|
||||
f_new_inst(FI_EA_GET, lval->fab.class)
|
||||
),
|
||||
lval->fab.class),
|
||||
f_new_inst(FI_EA_SET,
|
||||
f_new_inst(FI_BITAND,
|
||||
f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << lval->fab.bit)}),
|
||||
f_new_inst(FI_EA_GET, lval->fab.class)
|
||||
),
|
||||
lval->fab.class)
|
||||
);
|
||||
default: bug("Unknown lval type");
|
||||
}
|
||||
}
|
||||
|
||||
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_VAR_SET, expr, lval->sym);
|
||||
getter = f_new_inst(FI_VAR_GET, lval->sym);
|
||||
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");
|
||||
}
|
||||
struct f_inst *setter = f_lval_setter(lval, expr),
|
||||
*getter = f_lval_getter(lval);
|
||||
|
||||
checker = f_new_inst(FI_EQ, expr, getter);
|
||||
struct f_inst *checker = f_new_inst(FI_EQ, expr, getter);
|
||||
setter->next = checker;
|
||||
|
||||
return assert_done(setter, start, end);
|
||||
@ -337,7 +372,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
%nonassoc ELSE
|
||||
|
||||
%type <xp> cmds_int cmd_prep
|
||||
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
|
||||
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail method_cmd method_term
|
||||
%type <fsa> static_attr
|
||||
%type <f> filter where_filter
|
||||
%type <fl> filter_body function_body
|
||||
@ -834,6 +869,35 @@ static_attr:
|
||||
| GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
|
||||
;
|
||||
|
||||
method_term:
|
||||
IS_V4 { $$ = f_new_inst(FI_IS_V4, FM.object); }
|
||||
| TYPE { $$ = f_new_inst(FI_TYPE, FM.object); }
|
||||
| IP { $$ = f_new_inst(FI_IP, FM.object); }
|
||||
| RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, FM.object); }
|
||||
| LEN { $$ = f_new_inst(FI_LENGTH, FM.object); }
|
||||
| MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, FM.object); }
|
||||
| ASN { $$ = f_new_inst(FI_ASN, FM.object); }
|
||||
| SRC { $$ = f_new_inst(FI_NET_SRC, FM.object); }
|
||||
| DST { $$ = f_new_inst(FI_NET_DST, FM.object); }
|
||||
| MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, FM.object, $3); }
|
||||
| FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, FM.object); }
|
||||
| LAST { $$ = f_new_inst(FI_AS_PATH_LAST, FM.object); }
|
||||
| LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, FM.object); }
|
||||
| DATA { $$ = f_new_inst(FI_PAIR_DATA, FM.object); }
|
||||
| DATA1 { $$ = f_new_inst(FI_LC_DATA1, FM.object); }
|
||||
| DATA2 { $$ = f_new_inst(FI_LC_DATA2, FM.object); }
|
||||
| MIN { $$ = f_new_inst(FI_MIN, FM.object); }
|
||||
| MAX { $$ = f_new_inst(FI_MAX, FM.object); }
|
||||
;
|
||||
|
||||
method_cmd:
|
||||
EMPTY { $$ = f_new_inst(FI_CONSTANT, f_get_empty(FM.object->i_FI_EA_GET.da->type)); }
|
||||
| PREPEND '(' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, FM.object, $3 ); }
|
||||
| ADD '(' term ')' { $$ = f_new_inst(FI_CLIST_ADD, FM.object, $3 ); }
|
||||
| DELETE '(' term ')' { $$ = f_new_inst(FI_CLIST_DEL, FM.object, $3 ); }
|
||||
| FILTER '(' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, FM.object, $3 ); }
|
||||
;
|
||||
|
||||
term:
|
||||
'(' term ')' { $$ = $2; }
|
||||
| term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
|
||||
@ -861,32 +925,12 @@ term:
|
||||
|
||||
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
|
||||
|
||||
| term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
|
||||
| term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
|
||||
| term '.' IP { $$ = f_new_inst(FI_IP, $1); }
|
||||
| term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
|
||||
| term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
|
||||
| term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
|
||||
| term '.' ASN { $$ = f_new_inst(FI_ASN, $1); }
|
||||
| term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
|
||||
| term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
|
||||
| term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
|
||||
| term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
|
||||
| term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
|
||||
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
|
||||
| term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); }
|
||||
| term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); }
|
||||
| term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); }
|
||||
| term '.' MIN { $$ = f_new_inst(FI_MIN, $1); }
|
||||
| term '.' MAX { $$ = f_new_inst(FI_MAX, $1); }
|
||||
|
||||
/* Communities */
|
||||
/* This causes one shift/reduce conflict
|
||||
| dynamic_attr '.' ADD '(' term ')' { }
|
||||
| dynamic_attr '.' DELETE '(' term ')' { }
|
||||
| dynamic_attr '.' CONTAINS '(' term ')' { }
|
||||
| dynamic_attr '.' RESET{ }
|
||||
*/
|
||||
| term '.' {
|
||||
f_push_method_scope($1);
|
||||
} method_term {
|
||||
f_pop_method_scope();
|
||||
$$ = $4;
|
||||
}
|
||||
|
||||
| '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_PATH)); }
|
||||
| '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_CLIST)); }
|
||||
@ -1017,11 +1061,12 @@ cmd:
|
||||
$$ = f_new_inst(FI_SWITCH, $2, $4);
|
||||
}
|
||||
|
||||
| CF_SYM_KNOWN '.' EMPTY ';' { $$ = f_generate_empty($1); }
|
||||
| CF_SYM_KNOWN '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); }
|
||||
| CF_SYM_KNOWN '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); }
|
||||
| CF_SYM_KNOWN '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); }
|
||||
| CF_SYM_KNOWN '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); }
|
||||
| lvalue '.' {
|
||||
f_push_method_scope(f_lval_getter(&$1));
|
||||
} method_cmd ';' {
|
||||
f_pop_method_scope();
|
||||
$$ = f_lval_setter(&$1, $4);
|
||||
}
|
||||
| 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); }
|
||||
;
|
||||
@ -1033,15 +1078,18 @@ get_cf_position:
|
||||
|
||||
lvalue:
|
||||
CF_SYM_KNOWN {
|
||||
switch ($1->class) {
|
||||
case SYM_VARIABLE_RANGE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
|
||||
break;
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1->attribute };
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch ($1->class)
|
||||
{
|
||||
case SYM_VARIABLE_RANGE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
|
||||
break;
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1->attribute };
|
||||
break;
|
||||
default:
|
||||
cf_error("Variable name or attribute name required");
|
||||
}
|
||||
}
|
||||
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
|
||||
;
|
||||
|
||||
|
@ -39,11 +39,19 @@ struct f_static_attr {
|
||||
int readonly:1; /* Don't allow writing */
|
||||
};
|
||||
|
||||
struct f_attr_bit {
|
||||
const struct ea_class *class;
|
||||
uint bit;
|
||||
};
|
||||
|
||||
#define f_new_dynamic_attr_bit(_bit, _name) ((struct f_attr_bit) { .bit = _bit, .class = ea_class_find(_name) })
|
||||
|
||||
/* Filter l-value type */
|
||||
enum f_lval_type {
|
||||
F_LVAL_VARIABLE,
|
||||
F_LVAL_SA,
|
||||
F_LVAL_EA,
|
||||
F_LVAL_ATTR_BIT,
|
||||
};
|
||||
|
||||
/* Filter l-value */
|
||||
@ -53,6 +61,7 @@ struct f_lval {
|
||||
struct symbol *sym;
|
||||
const struct ea_class *da;
|
||||
struct f_static_attr sa;
|
||||
struct f_attr_bit fab;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -99,13 +99,6 @@ static inline struct f_static_attr f_new_static_attr(btype type, int code, int r
|
||||
{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
|
||||
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
|
||||
|
||||
struct f_attr_bit {
|
||||
const struct ea_class *class;
|
||||
uint bit;
|
||||
};
|
||||
|
||||
#define f_new_dynamic_attr_bit(_bit, _name) ((struct f_attr_bit) { .bit = _bit, .class = ea_class_find(_name) })
|
||||
|
||||
/* Hook for call bt_assert() function in configuration */
|
||||
extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
|
||||
|
||||
|
@ -9,6 +9,9 @@ router id 62.168.0.1;
|
||||
/* We have to setup any protocol */
|
||||
protocol device { }
|
||||
|
||||
attribute bgppath mypath;
|
||||
attribute lclist mylclist;
|
||||
|
||||
/* Setting some custom attributes, enough to force BIRD to reallocate the attribute idmap */
|
||||
attribute int test_ca_int1;
|
||||
attribute int test_ca_int2;
|
||||
@ -1851,6 +1854,15 @@ filter vpn_filter
|
||||
bgp_ext_community.add((ro, 135, 999));
|
||||
bgp_large_community.add((6464156, 89646354, 8675643));
|
||||
|
||||
mypath.prepend(65533);
|
||||
mylclist.add((1234, 5678, 90123));
|
||||
|
||||
bgppath locpath;
|
||||
lclist loclclist;
|
||||
|
||||
locpath.prepend(65533);
|
||||
loclclist.add((1234, 5678, 90123));
|
||||
|
||||
accept;
|
||||
}
|
||||
|
||||
|
@ -44,25 +44,8 @@ attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ;
|
||||
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ;
|
||||
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ;
|
||||
|
||||
/* Getting attribute bits (moved here to not confuse Bison on *BSD) */
|
||||
term:
|
||||
attr_bit {
|
||||
struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)});
|
||||
$$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1.class), c));
|
||||
}
|
||||
;
|
||||
|
||||
/* Setting attribute bits (moved here to not confuse Bison on *BSD) */
|
||||
cmd:
|
||||
attr_bit '=' term ';' {
|
||||
$$ = f_new_inst(FI_CONDITION, $3,
|
||||
f_generate_complex_default(FI_BITOR, $1.class,
|
||||
f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)}), 0),
|
||||
f_generate_complex_default(FI_BITAND, $1.class,
|
||||
f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << $1.bit)}), 0)
|
||||
);
|
||||
}
|
||||
;
|
||||
/* Using attribute bits in filters (moved here to not confuse Bison on *BSD) */
|
||||
lvalue: attr_bit { $$ = (struct f_lval) { .type = F_LVAL_ATTR_BIT, .fab = $1 }; };
|
||||
|
||||
CF_CODE
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user