mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Merge commit 'de70474fed139f9acb4ed3f8e925d12de4edcdd0' into thread-next
This commit is contained in:
commit
b0797c2dcd
@ -444,7 +444,7 @@ bytestring_text:
|
|||||||
;
|
;
|
||||||
|
|
||||||
bytestring_expr:
|
bytestring_expr:
|
||||||
symbol_value
|
lvalue { $$ = f_lval_getter(&$1); }
|
||||||
| term_bs
|
| term_bs
|
||||||
| '(' term ')' { $$ = $2; }
|
| '(' term ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
@ -40,16 +40,19 @@ static inline void f_method_call_start(struct f_inst *object)
|
|||||||
cf_error("Too many nested method calls");
|
cf_error("Too many nested method calls");
|
||||||
|
|
||||||
struct sym_scope *scope = f_type_method_scope(object->type);
|
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));
|
cf_error("No methods defined for type %s", f_type_name(object->type));
|
||||||
|
|
||||||
|
if (!scope)
|
||||||
|
scope = config->root_scope->next;
|
||||||
|
|
||||||
/* Replacing the current symbol scope with the appropriate method scope
|
/* Replacing the current symbol scope with the appropriate method scope
|
||||||
for the given type. */
|
for the given type. */
|
||||||
FM = (struct f_method_scope) {
|
FM = (struct f_method_scope) {
|
||||||
.object = object,
|
.object = object,
|
||||||
.main = new_config->current_scope,
|
.main = new_config->current_scope,
|
||||||
.scope = {
|
.scope = {
|
||||||
.next = NULL,
|
.next = scope->next,
|
||||||
.hash = scope->hash,
|
.hash = scope->hash,
|
||||||
.block = 1,
|
.block = 1,
|
||||||
.readonly = 1,
|
.readonly = 1,
|
||||||
@ -241,6 +244,7 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove all new lines and doubled whitespaces
|
* Remove all new lines and doubled whitespaces
|
||||||
* and convert all tabulators to spaces
|
* and convert all tabulators to spaces
|
||||||
@ -299,13 +303,14 @@ static struct f_inst *
|
|||||||
f_lval_getter(struct f_lval *lval)
|
f_lval_getter(struct f_lval *lval)
|
||||||
{
|
{
|
||||||
switch (lval->type) {
|
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_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_SA: return f_new_inst(FI_RTA_GET, lval->rte, lval->sa);
|
||||||
case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->da);
|
case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->rte, lval->da);
|
||||||
case F_LVAL_ATTR_BIT:
|
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)});
|
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));
|
return f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, lval->rte, lval->fab.class), c));
|
||||||
}
|
}
|
||||||
default: bug("Unknown lval type");
|
default: bug("Unknown lval type");
|
||||||
}
|
}
|
||||||
@ -315,20 +320,25 @@ static struct f_inst *
|
|||||||
f_lval_setter(struct f_lval *lval, struct f_inst *expr)
|
f_lval_setter(struct f_lval *lval, struct f_inst *expr)
|
||||||
{
|
{
|
||||||
switch (lval->type) {
|
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_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);
|
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,
|
case F_LVAL_ATTR_BIT: return f_new_inst(FI_CONDITION, expr,
|
||||||
f_new_inst(FI_EA_SET,
|
f_new_inst(FI_EA_SET,
|
||||||
f_new_inst(FI_BITOR,
|
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_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << lval->fab.bit)}),
|
||||||
f_new_inst(FI_EA_GET, lval->fab.class)
|
f_new_inst(FI_EA_GET, lval->rte, lval->fab.class)
|
||||||
),
|
),
|
||||||
lval->fab.class),
|
lval->fab.class),
|
||||||
f_new_inst(FI_EA_SET,
|
f_new_inst(FI_EA_SET,
|
||||||
f_new_inst(FI_BITAND,
|
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_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << lval->fab.bit)}),
|
||||||
f_new_inst(FI_EA_GET, lval->fab.class)
|
f_new_inst(FI_EA_GET, lval->rte, lval->fab.class)
|
||||||
),
|
),
|
||||||
lval->fab.class)
|
lval->fab.class)
|
||||||
);
|
);
|
||||||
@ -371,7 +381,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
|||||||
%nonassoc ELSE
|
%nonassoc ELSE
|
||||||
|
|
||||||
%type <xp> cmds_int cmd_prep
|
%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 <fsa> static_attr
|
%type <fsa> static_attr
|
||||||
%type <f> filter where_filter
|
%type <f> filter where_filter
|
||||||
%type <fl> filter_body function_body
|
%type <fl> filter_body function_body
|
||||||
@ -479,6 +489,7 @@ type:
|
|||||||
| CLIST { $$ = T_CLIST; }
|
| CLIST { $$ = T_CLIST; }
|
||||||
| ECLIST { $$ = T_ECLIST; }
|
| ECLIST { $$ = T_ECLIST; }
|
||||||
| LCLIST { $$ = T_LCLIST; }
|
| LCLIST { $$ = T_LCLIST; }
|
||||||
|
| ROUTE { $$ = T_ROUTE; }
|
||||||
| type SET {
|
| type SET {
|
||||||
switch ($1) {
|
switch ($1) {
|
||||||
case T_INT:
|
case T_INT:
|
||||||
@ -779,7 +790,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
|
|||||||
;
|
;
|
||||||
|
|
||||||
bgp_path_expr:
|
bgp_path_expr:
|
||||||
symbol_value { $$ = $1; }
|
lvalue { $$ = f_lval_getter(&$1); }
|
||||||
| '(' term ')' { $$ = $2; }
|
| '(' term ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -861,23 +872,6 @@ function_call:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
symbol_value: CF_SYM_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:
|
static_attr:
|
||||||
GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
|
GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
|
||||||
@ -900,6 +894,18 @@ method_name_cont:
|
|||||||
} '(' var_list ')' {
|
} '(' var_list ')' {
|
||||||
$$ = f_dispatch_method($1, FM.object, $4, 1);
|
$$ = 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);
|
||||||
|
}
|
||||||
|
| CF_SYM_KNOWN {
|
||||||
|
if ($1->class != SYM_ATTRIBUTE)
|
||||||
|
cf_error("Not a method of %s: %s", f_type_name(FM.object->type), $1->name);
|
||||||
|
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->attribute);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
term:
|
term:
|
||||||
@ -923,11 +929,10 @@ 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_value { $$ = $1; }
|
|
||||||
| constant { $$ = $1; }
|
| constant { $$ = $1; }
|
||||||
| constructor { $$ = $1; }
|
| constructor { $$ = $1; }
|
||||||
|
|
||||||
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
|
| lvalue { $$ = f_lval_getter(&$1); }
|
||||||
|
|
||||||
| term_dot_method
|
| term_dot_method
|
||||||
|
|
||||||
@ -1017,19 +1022,8 @@ cmd:
|
|||||||
cf_pop_block_scope(new_config);
|
cf_pop_block_scope(new_config);
|
||||||
$$ = f_for_cycle($3, $6, $9);
|
$$ = f_for_cycle($3, $6, $9);
|
||||||
}
|
}
|
||||||
| CF_SYM_KNOWN '=' term ';' {
|
| lvalue '=' term ';' {
|
||||||
switch ($1->class) {
|
$$ = f_lval_setter(&$1, $3);
|
||||||
case SYM_VARIABLE_RANGE:
|
|
||||||
$$ = f_new_inst(FI_VAR_SET, $3, $1);
|
|
||||||
break;
|
|
||||||
case SYM_ATTRIBUTE:
|
|
||||||
if ($1->attribute->readonly)
|
|
||||||
cf_error("Attribute %s is read-only", $1->attribute->name);
|
|
||||||
$$ = f_new_inst(FI_EA_SET, $3, $1->attribute);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cf_error("Can't assign to symbol %s", $1->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| RETURN term ';' {
|
| RETURN term ';' {
|
||||||
DBG( "Ook, we'll return the value\n" );
|
DBG( "Ook, we'll return the value\n" );
|
||||||
@ -1047,11 +1041,6 @@ cmd:
|
|||||||
|
|
||||||
$$ = f_new_inst(FI_RETURN, $2);
|
$$ = f_new_inst(FI_RETURN, $2);
|
||||||
}
|
}
|
||||||
| static_attr '=' term ';' {
|
|
||||||
if ($1.readonly)
|
|
||||||
cf_error( "This static attribute is read-only.");
|
|
||||||
$$ = f_new_inst(FI_RTA_SET, $3, $1);
|
|
||||||
}
|
|
||||||
| UNSET '(' CF_SYM_KNOWN ')' ';' {
|
| UNSET '(' CF_SYM_KNOWN ')' ';' {
|
||||||
if ($3->class != SYM_ATTRIBUTE)
|
if ($3->class != SYM_ATTRIBUTE)
|
||||||
cf_error("Can't unset %s", $3->name);
|
cf_error("Can't unset %s", $3->name);
|
||||||
@ -1091,17 +1080,20 @@ lvalue:
|
|||||||
CF_SYM_KNOWN {
|
CF_SYM_KNOWN {
|
||||||
switch ($1->class)
|
switch ($1->class)
|
||||||
{
|
{
|
||||||
|
case SYM_CONSTANT_RANGE:
|
||||||
|
$$ = (struct f_lval) { .type = F_LVAL_CONSTANT, .sym = $1, };
|
||||||
|
break;
|
||||||
case SYM_VARIABLE_RANGE:
|
case SYM_VARIABLE_RANGE:
|
||||||
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
|
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1, };
|
||||||
break;
|
break;
|
||||||
case SYM_ATTRIBUTE:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
cf_error("Variable name or attribute name required");
|
cf_error("Variable name or attribute name required");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
|
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; }
|
||||||
;
|
;
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
@ -60,6 +60,8 @@ static const char * const f_type_str[] = {
|
|||||||
[T_LCLIST] = "lclist",
|
[T_LCLIST] = "lclist",
|
||||||
[T_RD] = "rd",
|
[T_RD] = "rd",
|
||||||
|
|
||||||
|
[T_ROUTE] = "route",
|
||||||
|
|
||||||
[T_SET] = "set",
|
[T_SET] = "set",
|
||||||
[T_PREFIX_SET] = "prefix set",
|
[T_PREFIX_SET] = "prefix set",
|
||||||
};
|
};
|
||||||
@ -200,6 +202,7 @@ val_compare(const struct f_val *v1, const struct f_val *v2)
|
|||||||
return net_compare(v1->val.net, v2->val.net);
|
return net_compare(v1->val.net, v2->val.net);
|
||||||
case T_STRING:
|
case T_STRING:
|
||||||
return strcmp(v1->val.s, v2->val.s);
|
return strcmp(v1->val.s, v2->val.s);
|
||||||
|
case T_ROUTE:
|
||||||
default:
|
default:
|
||||||
return F_CMP_ERROR;
|
return F_CMP_ERROR;
|
||||||
}
|
}
|
||||||
@ -290,6 +293,8 @@ val_same(const struct f_val *v1, const struct f_val *v2)
|
|||||||
return same_tree(v1->val.t, v2->val.t);
|
return same_tree(v1->val.t, v2->val.t);
|
||||||
case T_PREFIX_SET:
|
case T_PREFIX_SET:
|
||||||
return trie_same(v1->val.ti, v2->val.ti);
|
return trie_same(v1->val.ti, v2->val.ti);
|
||||||
|
case T_ROUTE:
|
||||||
|
return rte_same(v1->val.rte, v2->val.rte);
|
||||||
default:
|
default:
|
||||||
bug("Invalid type in val_same(): %x", v1->type);
|
bug("Invalid type in val_same(): %x", v1->type);
|
||||||
}
|
}
|
||||||
@ -563,6 +568,21 @@ val_in_range(const struct f_val *v1, const struct f_val *v2)
|
|||||||
return F_CMP_ERROR;
|
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 via %s",
|
||||||
|
rte->src->global_id, rte->net,
|
||||||
|
rte->sender->req->name,
|
||||||
|
rte->src->owner->name);
|
||||||
|
else
|
||||||
|
buffer_puts(buf, "[No route]");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* val_format - format filter value
|
* val_format - format filter value
|
||||||
*/
|
*/
|
||||||
@ -592,6 +612,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_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_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_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;
|
default: buffer_print(buf, "[unknown type %x]", v->type); return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "lib/type.h"
|
#include "lib/type.h"
|
||||||
|
#include "nest/iface.h"
|
||||||
|
|
||||||
struct f_method {
|
struct f_method {
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
@ -56,6 +57,7 @@ struct f_attr_bit {
|
|||||||
|
|
||||||
/* Filter l-value type */
|
/* Filter l-value type */
|
||||||
enum f_lval_type {
|
enum f_lval_type {
|
||||||
|
F_LVAL_CONSTANT,
|
||||||
F_LVAL_VARIABLE,
|
F_LVAL_VARIABLE,
|
||||||
F_LVAL_SA,
|
F_LVAL_SA,
|
||||||
F_LVAL_EA,
|
F_LVAL_EA,
|
||||||
@ -65,6 +67,7 @@ enum f_lval_type {
|
|||||||
/* Filter l-value */
|
/* Filter l-value */
|
||||||
struct f_lval {
|
struct f_lval {
|
||||||
enum f_lval_type type;
|
enum f_lval_type type;
|
||||||
|
struct f_inst *rte;
|
||||||
union {
|
union {
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
const struct ea_class *da;
|
const struct ea_class *da;
|
||||||
|
@ -666,18 +666,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_RTA_GET, 0, 1) {
|
INST(FI_CURRENT_ROUTE, 0, 1) {
|
||||||
|
NEVER_CONSTANT;
|
||||||
|
ACCESS_RTE;
|
||||||
|
RESULT_TYPE(T_ROUTE);
|
||||||
|
RESULT_VAL([[(struct f_val) { .type = T_ROUTE, .val.rte = fs->rte, }]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
INST(FI_RTA_GET, 1, 1) {
|
||||||
{
|
{
|
||||||
|
ARG(1, T_ROUTE);
|
||||||
STATIC_ATTR;
|
STATIC_ATTR;
|
||||||
ACCESS_RTE;
|
|
||||||
|
struct rte *rte = v1.val.rte;
|
||||||
|
|
||||||
switch (sa.sa_code)
|
switch (sa.sa_code)
|
||||||
{
|
{
|
||||||
case SA_NET: RESULT(sa.type, net, fs->rte->net); break;
|
case SA_NET: RESULT(sa.type, net, rte->net); break;
|
||||||
case SA_PROTO: RESULT(sa.type, s, fs->rte->src->owner->name); break;
|
case SA_PROTO: RESULT(sa.type, s, rte->src->owner->name); break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
struct eattr *nhea = ea_find(fs->rte->attrs, &ea_gen_nexthop);
|
struct eattr *nhea = ea_find(rte->attrs, &ea_gen_nexthop);
|
||||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||||
struct nexthop *nh = nhad ? &nhad->nh : NULL;
|
struct nexthop *nh = nhad ? &nhad->nh : NULL;
|
||||||
|
|
||||||
@ -836,13 +845,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */
|
INST(FI_EA_GET, 1, 1) { /* Access to extended attributes */
|
||||||
|
ARG(1, T_ROUTE);
|
||||||
DYNAMIC_ATTR;
|
DYNAMIC_ATTR;
|
||||||
ACCESS_RTE;
|
|
||||||
RESULT_TYPE(da->type);
|
RESULT_TYPE(da->type);
|
||||||
{
|
{
|
||||||
struct f_val empty;
|
struct f_val empty;
|
||||||
const eattr *e = ea_find(fs->rte->attrs, da->id);
|
const eattr *e = ea_find(v1.val.rte->attrs, da->id);
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -195,7 +195,7 @@ f_implicit_roa_check(struct rtable_config *tab)
|
|||||||
if (!def)
|
if (!def)
|
||||||
bug("Couldn't find BGP AS Path attribute definition.");
|
bug("Couldn't find BGP AS Path attribute definition.");
|
||||||
|
|
||||||
struct f_inst *path_getter = f_new_inst(FI_EA_GET, def);
|
struct f_inst *path_getter = f_new_inst(FI_EA_GET, f_new_inst(FI_CURRENT_ROUTE), def);
|
||||||
struct sym_scope *scope = f_type_method_scope(path_getter->type);
|
struct sym_scope *scope = f_type_method_scope(path_getter->type);
|
||||||
struct symbol *ms = scope ? cf_find_symbol_scope(scope, "last") : NULL;
|
struct symbol *ms = scope ? cf_find_symbol_scope(scope, "last") : NULL;
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ f_implicit_roa_check(struct rtable_config *tab)
|
|||||||
struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1);
|
struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1);
|
||||||
|
|
||||||
return f_new_inst(FI_ROA_CHECK,
|
return f_new_inst(FI_ROA_CHECK,
|
||||||
f_new_inst(FI_RTA_GET, fsa),
|
f_new_inst(FI_RTA_GET, f_new_inst(FI_CURRENT_ROUTE), fsa),
|
||||||
ms->method->new_inst(path_getter, NULL),
|
ms->method->new_inst(path_getter, NULL),
|
||||||
tab);
|
tab);
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,8 @@ static inline rte rte_init_from(const rte *r)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rte_same(const rte *, const rte *);
|
||||||
|
|
||||||
struct rte_src {
|
struct rte_src {
|
||||||
struct rte_src *next; /* Hash chain */
|
struct rte_src *next; /* Hash chain */
|
||||||
struct rte_owner *owner; /* Route source owner */
|
struct rte_owner *owner; /* Route source owner */
|
||||||
|
@ -42,6 +42,7 @@ union bval_long {
|
|||||||
const struct f_trie *ti;
|
const struct f_trie *ti;
|
||||||
const struct f_path_mask *path_mask;
|
const struct f_path_mask *path_mask;
|
||||||
struct f_path_mask_item pmi;
|
struct f_path_mask_item pmi;
|
||||||
|
struct rte *rte;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -54,8 +55,9 @@ enum btype {
|
|||||||
/* Something but inaccessible. */
|
/* Something but inaccessible. */
|
||||||
T_OPAQUE = 0x02, /* Opaque byte string (not filterable) */
|
T_OPAQUE = 0x02, /* Opaque byte string (not filterable) */
|
||||||
T_IFACE = 0x0c, /* Pointer to an interface (inside adata) */
|
T_IFACE = 0x0c, /* Pointer to an interface (inside adata) */
|
||||||
T_NEXTHOP_LIST = 0x2c, /* The whole nexthop block */
|
T_ROUTE = 0x6a, /* One route pointer */
|
||||||
T_HOSTENTRY = 0x2e, /* Hostentry with possible MPLS labels */
|
T_NEXTHOP_LIST = 0x6c, /* The whole nexthop block */
|
||||||
|
T_HOSTENTRY = 0x6e, /* Hostentry with possible MPLS labels */
|
||||||
|
|
||||||
/* Types shared with eattrs */
|
/* Types shared with eattrs */
|
||||||
T_INT = 0x01, /* 32-bit unsigned integer number */
|
T_INT = 0x01, /* 32-bit unsigned integer number */
|
||||||
|
@ -154,7 +154,7 @@ static void rt_delete(void *);
|
|||||||
static void rt_export_used(struct rt_table_exporter *, const char *, const char *);
|
static void rt_export_used(struct rt_table_exporter *, const char *, const char *);
|
||||||
static void rt_export_cleanup(struct rtable_private *tab);
|
static void rt_export_cleanup(struct rtable_private *tab);
|
||||||
|
|
||||||
static int rte_same(const rte *x, const rte *y);
|
int rte_same(const rte *x, const rte *y);
|
||||||
|
|
||||||
const char *rt_import_state_name_array[TIS_MAX] = {
|
const char *rt_import_state_name_array[TIS_MAX] = {
|
||||||
[TIS_DOWN] = "DOWN",
|
[TIS_DOWN] = "DOWN",
|
||||||
@ -1674,12 +1674,15 @@ rte_validate(struct channel *ch, rte *e)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
rte_same(const rte *x, const rte *y)
|
rte_same(const rte *x, const rte *y)
|
||||||
{
|
{
|
||||||
/* rte.flags / rte.pflags are not checked, as they are internal to rtable */
|
/* rte.flags / rte.pflags are not checked, as they are internal to rtable */
|
||||||
return
|
return
|
||||||
x->attrs == y->attrs &&
|
(
|
||||||
|
(x->attrs == y->attrs) ||
|
||||||
|
((!(x->attrs->flags & EALF_CACHED) || !(y->attrs->flags & EALF_CACHED)) && ea_same(x->attrs, y->attrs))
|
||||||
|
) &&
|
||||||
x->src == y->src &&
|
x->src == y->src &&
|
||||||
rte_is_filtered(x) == rte_is_filtered(y);
|
rte_is_filtered(x) == rte_is_filtered(y);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user