diff options
Diffstat (limited to 'filter')
-rw-r--r-- | filter/config.Y | 43 | ||||
-rw-r--r-- | filter/f-util.c | 144 | ||||
-rw-r--r-- | filter/filter.c | 2 | ||||
-rw-r--r-- | filter/filter.h | 9 |
4 files changed, 184 insertions, 14 deletions
diff --git a/filter/config.Y b/filter/config.Y index d865d11f..c1e74531 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -417,7 +417,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ADD, DELETE, CONTAINS, RESET, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, EMPTY, - FILTER, WHERE, EVAL, + FILTER, WHERE, EVAL, ATTRIBUTE, BT_ASSERT, BT_TEST_SUITE, FORMAT) %nonassoc THEN @@ -455,6 +455,11 @@ filter_eval: EVAL term { f_eval_int($2); } ; +conf: custom_attr ; +custom_attr: ATTRIBUTE type SYM ';' { + cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda); +}; + conf: bt_test_suite ; bt_test_suite: BT_TEST_SUITE '(' SYM ',' text ')' { @@ -834,14 +839,22 @@ function_call: symbol: SYM { - switch ($1->class & 0xff00) { - case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break; - case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break; - default: cf_error("%s: variable expected.", $1->name); + switch ($1->class & 0xffff) { + case SYM_CONSTANT_RANGE: + $$ = f_new_inst(FI_CONSTANT_INDIRECT); + goto cv_common; + case SYM_VARIABLE_RANGE: + $$ = f_new_inst(FI_VARIABLE); + cv_common: + $$->a1.p = $1->def; + $$->a2.p = $1->name; + break; + case SYM_ATTRIBUTE: + $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); + break; + default: + cf_error("%s: variable expected.", $1->name); } - - $$->a1.p = $1->def; - $$->a2.p = $1->name; } static_attr: @@ -1001,11 +1014,15 @@ cmd: } | SYM '=' term ';' { DBG( "Ook, we'll set value\n" ); - if (($1->class & ~T_MASK) != SYM_VARIABLE) - cf_error( "You may set only variables." ); - $$ = f_new_inst(FI_SET); - $$->a1.p = $1; - $$->a2.p = $3; + if ($1->class == SYM_ATTRIBUTE) { + $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def)); + $$->a1.p = $3; + } else if (($1->class & ~T_MASK) == SYM_VARIABLE) { + $$ = f_new_inst(FI_SET); + $$->a1.p = $1; + $$->a2.p = $3; + } else + cf_error( "Symbol `%s' is read-only.", $1->name ); } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); diff --git a/filter/f-util.c b/filter/f-util.c index 6170760b..ee9490b4 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -10,6 +10,9 @@ #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" +#include "lib/idm.h" +#include "nest/protocol.h" +#include "nest/route.h" #define P(a,b) ((a<<8) | b) @@ -105,3 +108,144 @@ filter_name(struct filter *filter) else return filter->name; } + +#define CA_KEY(n) n->name, n->fda.type +#define CA_NEXT(n) n->next +#define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb)) +#define CA_FN(n,t) (mem_hash(n, strlen(n)) ^ (t*0xaae99453U)) +#define CA_ORDER 8 /* Fixed */ + +struct ca_storage { + struct ca_storage *next; + struct f_dynamic_attr fda; + u32 uc; + char name[0]; +}; + +HASH(struct ca_storage) ca_hash; + +static struct idm ca_idm; +static struct ca_storage **ca_storage; +static uint ca_storage_max; + +static void +ca_free(resource *r) +{ + struct custom_attribute *ca = (void *) r; + struct ca_storage *cas = HASH_FIND(ca_hash, CA, ca->name, ca->fda->type); + ASSERT(cas); + + ca->name = NULL; + ca->fda = NULL; + if (!--cas->uc) { + uint id = EA_CUSTOM_ID(cas->fda.ea_code); + idm_free(&ca_idm, id); + HASH_REMOVE(ca_hash, CA, cas); + ca_storage[id] = NULL; + mb_free(cas); + } +} + +static void +ca_dump(resource *r) +{ + struct custom_attribute *ca = (void *) r; + debug("name \"%s\" id 0x%04x ea_type 0x%02x f_type 0x%02x\n", + ca->name, ca->fda->ea_code, ca->fda->type, ca->fda->f_type); +} + +static struct resclass ca_class = { + .name = "Custom attribute", + .size = sizeof(struct custom_attribute), + .free = ca_free, + .dump = ca_dump, + .lookup = NULL, + .memsize = NULL, +}; + +struct custom_attribute * +ca_lookup(pool *p, const char *name, int f_type) +{ + int ea_type; + + switch (f_type) { + case T_INT: + ea_type = EAF_TYPE_INT; + break; + case T_IP: + ea_type = EAF_TYPE_IP_ADDRESS; + break; + case T_QUAD: + ea_type = EAF_TYPE_ROUTER_ID; + break; + case T_PATH: + ea_type = EAF_TYPE_AS_PATH; + break; + case T_CLIST: + ea_type = EAF_TYPE_INT_SET; + break; + case T_ECLIST: + ea_type = EAF_TYPE_EC_SET; + break; + case T_LCLIST: + ea_type = EAF_TYPE_LC_SET; + break; + default: + cf_error("Custom route attribute of unsupported type"); + } + + static int inited = 0; + if (!inited) { + idm_init(&ca_idm, &root_pool, 8); + HASH_INIT(ca_hash, &root_pool, CA_ORDER); + + ca_storage_max = 256; + ca_storage = mb_allocz(&root_pool, sizeof(struct ca_storage *) * ca_storage_max); + + inited++; + } + + struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, ea_type); + if (cas) { + cas->uc++; + } else { + + uint id = idm_alloc(&ca_idm); + + if (id >= EA_CUSTOM_BIT) + cf_error("Too many custom attributes."); + + if (id >= ca_storage_max) { + ca_storage_max *= 2; + ca_storage = mb_realloc(ca_storage, sizeof(struct ca_storage *) * ca_storage_max * 2); + } + + cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1); + cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id)); + cas->uc = 1; + + strcpy(cas->name, name); + ca_storage[id] = cas; + + HASH_INSERT(ca_hash, CA, cas); + } + + struct custom_attribute *ca = ralloc(p, &ca_class); + ca->fda = &(cas->fda); + ca->name = cas->name; + return ca; +} + +const char * +ea_custom_name(uint ea) +{ + uint id = EA_CUSTOM_ID(ea); + if (id >= ca_storage_max) + return NULL; + + if (!ca_storage[id]) + return NULL; + + return ca_storage[id]->name; +} + diff --git a/filter/filter.c b/filter/filter.c index f308e7fd..37cf16a3 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -1063,7 +1063,7 @@ interpret(struct f_inst *what) break; } - switch (what->aux & EAF_TYPE_MASK) { + switch (e->type & EAF_TYPE_MASK) { case EAF_TYPE_INT: res.type = f_type; res.val.i = e->u.data; diff --git a/filter/filter.h b/filter/filter.h index febfdc65..a8c33287 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -287,6 +287,15 @@ struct f_trie #define FF_SILENT 2 /* Silent filter execution */ +/* Custom route attributes */ +struct custom_attribute { + resource r; + struct f_dynamic_attr *fda; + const char *name; +}; + +struct custom_attribute *ca_lookup(pool *p, const char *name, int ea_type); + /* Bird Tests */ struct f_bt_test_suite { node n; /* Node in config->tests */ |