mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-03 07:31:54 +00:00
Filter: adding explicit route type
This is a split-commit of the neighboring aggregator branch with a bit improved lvalue handling, to have easier merge into v3.
This commit is contained in:
parent
0a729b509c
commit
de70474fed
@ -433,7 +433,7 @@ bytestring_text:
|
||||
;
|
||||
|
||||
bytestring_expr:
|
||||
symbol_value
|
||||
lvalue { $$ = f_lval_getter(&$1); }
|
||||
| term_bs
|
||||
| '(' term ')' { $$ = $2; }
|
||||
;
|
||||
|
@ -38,15 +38,15 @@ static inline void f_method_call_start(struct f_inst *object)
|
||||
cf_error("Too many nested method calls");
|
||||
|
||||
struct sym_scope *scope = f_type_method_scope(object->type);
|
||||
if (!scope)
|
||||
if (!scope && object->type != T_ROUTE)
|
||||
cf_error("No methods defined for type %s", f_type_name(object->type));
|
||||
|
||||
FM = (struct f_method_scope) {
|
||||
.object = object,
|
||||
.main = new_config->current_scope,
|
||||
.scope = {
|
||||
.next = NULL,
|
||||
.hash = scope->hash,
|
||||
.next = scope ? global_root_scope : NULL,
|
||||
.hash = scope ? scope->hash : global_root_scope->hash,
|
||||
.active = 1,
|
||||
.block = 1,
|
||||
.readonly = 1,
|
||||
@ -244,6 +244,7 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove all new lines and doubled whitespaces
|
||||
* and convert all tabulators to spaces
|
||||
@ -302,9 +303,10 @@ static struct f_inst *
|
||||
f_lval_getter(struct f_lval *lval)
|
||||
{
|
||||
switch (lval->type) {
|
||||
case F_LVAL_CONSTANT: return f_new_inst(FI_CONSTANT, *(lval->sym->val));
|
||||
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_SA: return f_new_inst(FI_RTA_GET, lval->rte, lval->sa);
|
||||
case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->rte, lval->da);
|
||||
default: bug("Unknown lval type");
|
||||
}
|
||||
}
|
||||
@ -313,8 +315,13 @@ static struct f_inst *
|
||||
f_lval_setter(struct f_lval *lval, struct f_inst *expr)
|
||||
{
|
||||
switch (lval->type) {
|
||||
case F_LVAL_CONSTANT: cf_error("Constant %s is read-only", lval->sym->name);
|
||||
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_SA:
|
||||
if (lval->sa.readonly)
|
||||
cf_error( "This static attribute is read-only.");
|
||||
return f_new_inst(FI_RTA_SET, expr, lval->sa);
|
||||
|
||||
case F_LVAL_EA: return f_new_inst(FI_EA_SET, expr, lval->da);
|
||||
default: bug("Unknown lval type");
|
||||
}
|
||||
@ -357,7 +364,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 var var_list var_list_r function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
|
||||
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r function_call bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
|
||||
%type <fda> dynamic_attr
|
||||
%type <fsa> static_attr
|
||||
%type <f> filter where_filter
|
||||
@ -447,6 +454,7 @@ type:
|
||||
| CLIST { $$ = T_CLIST; }
|
||||
| ECLIST { $$ = T_ECLIST; }
|
||||
| LCLIST { $$ = T_LCLIST; }
|
||||
| ROUTE { $$ = T_ROUTE; }
|
||||
| type SET {
|
||||
switch ($1) {
|
||||
case T_INT:
|
||||
@ -740,7 +748,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
|
||||
;
|
||||
|
||||
bgp_path_expr:
|
||||
symbol_value { $$ = $1; }
|
||||
lvalue { $$ = f_lval_getter(&$1); }
|
||||
| '(' term ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
@ -822,23 +830,6 @@ function_call:
|
||||
}
|
||||
;
|
||||
|
||||
symbol_value: symbol_known
|
||||
{
|
||||
switch ($1->class) {
|
||||
case SYM_CONSTANT_RANGE:
|
||||
$$ = f_new_inst(FI_CONSTANT, *($1->val));
|
||||
break;
|
||||
case SYM_VARIABLE_RANGE:
|
||||
$$ = f_new_inst(FI_VAR_GET, $1);
|
||||
break;
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = f_new_inst(FI_EA_GET, *$1->attribute);
|
||||
break;
|
||||
default:
|
||||
cf_error("Can't get value of symbol %s", $1->name);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
static_attr:
|
||||
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
|
||||
@ -866,6 +857,16 @@ method_name_cont:
|
||||
} '(' var_list ')' {
|
||||
$$ = f_dispatch_method($1, FM.object, $4, 1);
|
||||
}
|
||||
| static_attr {
|
||||
if (FM.object->type != T_ROUTE)
|
||||
cf_error("Getting a route attribute from %s, need a route", f_type_name(FM.object->type));
|
||||
$$ = f_new_inst(FI_RTA_GET, FM.object, $1);
|
||||
}
|
||||
| dynamic_attr {
|
||||
if (FM.object->type != T_ROUTE)
|
||||
cf_error("Getting a route attribute from %s, need a route", f_type_name(FM.object->type));
|
||||
$$ = f_new_inst(FI_EA_GET, FM.object, $1);
|
||||
}
|
||||
;
|
||||
|
||||
term:
|
||||
@ -887,13 +888,10 @@ term:
|
||||
| '!' term { $$ = f_new_inst(FI_NOT, $2); }
|
||||
| DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
|
||||
|
||||
| symbol_value { $$ = $1; }
|
||||
| constant { $$ = $1; }
|
||||
| constructor { $$ = $1; }
|
||||
|
||||
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
|
||||
|
||||
| dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
|
||||
| lvalue { $$ = f_lval_getter(&$1); }
|
||||
|
||||
| term_dot_method
|
||||
|
||||
@ -902,7 +900,7 @@ term:
|
||||
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_ECLIST)); }
|
||||
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_LCLIST)); }
|
||||
|
||||
| PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); }
|
||||
| PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); }
|
||||
| ADD '(' term ',' term ')' { $$ = f_dispatch_method_x("add", $3->type, $3, $5); }
|
||||
| DELETE '(' term ',' term ')' { $$ = f_dispatch_method_x("delete", $3->type, $3, $5); }
|
||||
| FILTER '(' term ',' term ')' { $$ = f_dispatch_method_x("filter", $3->type, $3, $5); }
|
||||
@ -963,17 +961,8 @@ cmd:
|
||||
cf_pop_block_scope(new_config);
|
||||
$$ = f_for_cycle($3, $6, $9);
|
||||
}
|
||||
| symbol_known '=' term ';' {
|
||||
switch ($1->class) {
|
||||
case SYM_VARIABLE_RANGE:
|
||||
$$ = f_new_inst(FI_VAR_SET, $3, $1);
|
||||
break;
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
|
||||
break;
|
||||
default:
|
||||
cf_error("Can't assign to symbol %s", $1->name);
|
||||
}
|
||||
| lvalue '=' term ';' {
|
||||
$$ = f_lval_setter(&$1, $3);
|
||||
}
|
||||
| RETURN term ';' {
|
||||
DBG( "Ook, we'll return the value\n" );
|
||||
@ -991,14 +980,6 @@ cmd:
|
||||
|
||||
$$ = f_new_inst(FI_RETURN, $2);
|
||||
}
|
||||
| dynamic_attr '=' term ';' {
|
||||
$$ = f_new_inst(FI_EA_SET, $3, $1);
|
||||
}
|
||||
| static_attr '=' term ';' {
|
||||
if ($1.readonly)
|
||||
cf_error( "This static attribute is read-only.");
|
||||
$$ = f_new_inst(FI_RTA_SET, $3, $1);
|
||||
}
|
||||
| UNSET '(' dynamic_attr ')' ';' {
|
||||
$$ = f_new_inst(FI_EA_UNSET, $3);
|
||||
}
|
||||
@ -1043,17 +1024,21 @@ lvalue:
|
||||
CF_SYM_KNOWN {
|
||||
switch ($1->class)
|
||||
{
|
||||
case SYM_CONSTANT_RANGE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_CONSTANT, .sym = $1, };
|
||||
break;
|
||||
case SYM_VARIABLE_RANGE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
|
||||
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1, };
|
||||
break;
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute) };
|
||||
$$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute), .rte = f_new_inst(FI_CURRENT_ROUTE), };
|
||||
break;
|
||||
default:
|
||||
cf_error("Variable name or custom attribute name required");
|
||||
}
|
||||
}
|
||||
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
|
||||
| dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
|
||||
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; }
|
||||
| dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; }
|
||||
;
|
||||
|
||||
CF_END
|
||||
|
@ -56,6 +56,8 @@ static const char * const f_type_str[] = {
|
||||
[T_LC] = "lc",
|
||||
[T_LCLIST] = "lclist",
|
||||
[T_RD] = "rd",
|
||||
|
||||
[T_ROUTE] = "route",
|
||||
};
|
||||
|
||||
const char *
|
||||
@ -206,6 +208,7 @@ val_compare(const struct f_val *v1, const struct f_val *v2)
|
||||
return net_compare(v1->val.net, v2->val.net);
|
||||
case T_STRING:
|
||||
return strcmp(v1->val.s, v2->val.s);
|
||||
case T_ROUTE:
|
||||
default:
|
||||
return F_CMP_ERROR;
|
||||
}
|
||||
@ -296,6 +299,8 @@ val_same(const struct f_val *v1, const struct f_val *v2)
|
||||
return same_tree(v1->val.t, v2->val.t);
|
||||
case T_PREFIX_SET:
|
||||
return trie_same(v1->val.ti, v2->val.ti);
|
||||
case T_ROUTE:
|
||||
return rte_same(v1->val.rte, v2->val.rte);
|
||||
default:
|
||||
bug("Invalid type in val_same(): %x", v1->type);
|
||||
}
|
||||
@ -569,6 +574,21 @@ val_in_range(const struct f_val *v1, const struct f_val *v2)
|
||||
return F_CMP_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* rte_format - format route information
|
||||
*/
|
||||
static void
|
||||
rte_format(const struct rte *rte, buffer *buf)
|
||||
{
|
||||
if (rte)
|
||||
buffer_print(buf, "Route [%d] to %N from %s.%s via %s",
|
||||
rte->src->global_id, rte->net->n.addr,
|
||||
rte->sender->proto->name, rte->sender->name,
|
||||
rte->src->proto->name);
|
||||
else
|
||||
buffer_puts(buf, "[No route]");
|
||||
}
|
||||
|
||||
/*
|
||||
* val_format - format filter value
|
||||
*/
|
||||
@ -598,6 +618,7 @@ val_format(const struct f_val *v, buffer *buf)
|
||||
case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
|
||||
case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
|
||||
case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
|
||||
case T_ROUTE: rte_format(v->val.rte, buf); return;
|
||||
default: buffer_print(buf, "[unknown type %x]", v->type); return;
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ enum f_type {
|
||||
T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */
|
||||
T_BYTESTRING = 0x2c,
|
||||
|
||||
T_ROUTE = 0x78,
|
||||
T_SET = 0x80,
|
||||
T_PREFIX_SET = 0x81,
|
||||
} PACKED;
|
||||
@ -90,6 +91,10 @@ struct f_val {
|
||||
const struct adata *ad;
|
||||
const struct f_path_mask *path_mask;
|
||||
struct f_path_mask_item pmi;
|
||||
struct {
|
||||
rte *rte;
|
||||
ea_list *eattrs;
|
||||
};
|
||||
} val;
|
||||
};
|
||||
|
||||
@ -127,6 +132,7 @@ struct f_static_attr {
|
||||
|
||||
/* Filter l-value type */
|
||||
enum f_lval_type {
|
||||
F_LVAL_CONSTANT,
|
||||
F_LVAL_VARIABLE,
|
||||
F_LVAL_PREFERENCE,
|
||||
F_LVAL_SA,
|
||||
@ -136,6 +142,7 @@ enum f_lval_type {
|
||||
/* Filter l-value */
|
||||
struct f_lval {
|
||||
enum f_lval_type type;
|
||||
struct f_inst *rte;
|
||||
union {
|
||||
struct symbol *sym;
|
||||
struct f_dynamic_attr da;
|
||||
|
@ -654,11 +654,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
INST(FI_RTA_GET, 0, 1) {
|
||||
INST(FI_CURRENT_ROUTE, 0, 1) {
|
||||
NEVER_CONSTANT;
|
||||
ACCESS_EATTRS;
|
||||
RESULT_TYPE(T_ROUTE);
|
||||
RESULT_VAL([[(struct f_val) { .type = T_ROUTE, .val.rte = *fs->rte, .val.eattrs = *fs->eattrs, }]]);
|
||||
}
|
||||
|
||||
INST(FI_RTA_GET, 1, 1) {
|
||||
{
|
||||
STATIC_ATTR;
|
||||
ACCESS_RTE;
|
||||
struct rta *rta = (*fs->rte)->attrs;
|
||||
ARG(1, T_ROUTE);
|
||||
STATIC_ATTR;
|
||||
|
||||
struct rta *rta = v1.val.rte->attrs;
|
||||
|
||||
switch (sa.sa_code)
|
||||
{
|
||||
@ -797,13 +806,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */
|
||||
DYNAMIC_ATTR;
|
||||
INST(FI_EA_GET, 1, 1) { /* Access to extended attributes */
|
||||
ACCESS_RTE;
|
||||
ACCESS_EATTRS;
|
||||
ARG(1, T_ROUTE);
|
||||
DYNAMIC_ATTR;
|
||||
RESULT_TYPE(da.f_type);
|
||||
{
|
||||
eattr *e = ea_find(*fs->eattrs, da.ea_code);
|
||||
struct ea_list *eal = v1.val.eattrs;
|
||||
eattr *e = ea_find(eal, da.ea_code);
|
||||
|
||||
if (!e) {
|
||||
RESULT_VAL(val_empty(da.f_type));
|
||||
|
@ -326,6 +326,8 @@ void rt_refresh_begin(rtable *t, struct channel *c);
|
||||
void rt_refresh_end(rtable *t, struct channel *c);
|
||||
void rt_modify_stale(rtable *t, struct channel *c);
|
||||
void rt_schedule_prune(rtable *t);
|
||||
int rte_same(rte *, rte *);
|
||||
int rta_same(struct rta *, struct rta *);
|
||||
void rte_dump(rte *);
|
||||
void rte_free(rte *);
|
||||
rte *rte_do_cow(rte *);
|
||||
|
@ -1126,7 +1126,7 @@ rta_hash(rta *a)
|
||||
return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs);
|
||||
}
|
||||
|
||||
static inline int
|
||||
int
|
||||
rta_same(rta *x, rta *y)
|
||||
{
|
||||
return (x->source == y->source &&
|
||||
|
@ -1206,12 +1206,15 @@ rte_free_quick(rte *e)
|
||||
sl_free(e);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
rte_same(rte *x, rte *y)
|
||||
{
|
||||
/* rte.flags / rte.pflags are not checked, as they are internal to rtable */
|
||||
return
|
||||
x->attrs == y->attrs &&
|
||||
(
|
||||
(x->attrs == y->attrs) ||
|
||||
((!x->attrs->cached || !y->attrs->cached) && rta_same(x->attrs, y->attrs))
|
||||
) &&
|
||||
x->src == y->src &&
|
||||
rte_is_filtered(x) == rte_is_filtered(y);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user