summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorMaria Matejka <mq@jmq.cz>2018-11-21 20:37:11 +0100
committerJan Maria Matejka <mq@ucw.cz>2018-12-06 09:55:21 +0100
commit265419a3695b9a5c0a01d9fffc60f66fea8bee13 (patch)
tree069d7d7ba9cc5ef23c8babbcd8947e42448dd724 /filter
parent0642fb4d456fe12e1bbeb2ffc2149433f228c02e (diff)
Custom route attributes
For local route marking purposes, local custom route attributes may be defined. These attributes are seamlessly stripped after export filter to every real protocol like Kernel, BGP or OSPF, they however pass through pipes. We currently allow at most 256 custom attributes. This should be much faster than currently used bgp communities for marking routes.
Diffstat (limited to 'filter')
-rw-r--r--filter/config.Y43
-rw-r--r--filter/f-util.c144
-rw-r--r--filter/filter.c2
-rw-r--r--filter/filter.h9
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 */