0
0
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:
Maria Matejka 2023-10-27 15:56:06 +02:00
commit e6baff89f8
6 changed files with 144 additions and 97 deletions

View File

@ -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/.

View File

@ -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 }; }
;

View File

@ -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;
};
};

View File

@ -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);

View File

@ -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;
}

View File

@ -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