diff options
-rw-r--r-- | filter/config.Y | 5 | ||||
-rw-r--r-- | filter/filter.c | 16 | ||||
-rw-r--r-- | filter/test.conf | 5 | ||||
-rw-r--r-- | nest/a-set.c | 43 | ||||
-rw-r--r-- | nest/attrs.h | 4 |
5 files changed, 73 insertions, 0 deletions
diff --git a/filter/config.Y b/filter/config.Y index 6ce89e7a..9cdc8159 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -390,6 +390,7 @@ term: case SYM_VARIABLE | T_IP: case SYM_VARIABLE | T_PATH_MASK: case SYM_VARIABLE | T_PATH: + case SYM_VARIABLE | T_CLIST: $$->code = 'C'; $$->a1.p = $1->aux2; break; @@ -423,7 +424,11 @@ term: | term '.' RESET { } | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } + | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } +/* | ADD '(' term, ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } + | DELETE '(' term, ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } */ + /* | term '.' LEN { $$->code = P('P','l'); } */ diff --git a/filter/filter.c b/filter/filter.c index 267fa166..d9ef65a4 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -483,6 +483,21 @@ interpret(struct f_inst *what) res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i); break; + case P('C','a'): /* Community list add or delete */ + TWOARGS; + if (v1.type != T_CLIST) + runtime("Can't add/delete to non-clist"); + if (v2.type != T_PAIR) + runtime("Can't add/delete non-pair"); + + res.type = T_CLIST; + switch (what->aux) { + case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break; + case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break; + default: bug("unknown Ca operation"); + } + break; + default: bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); } @@ -566,6 +581,7 @@ i_same(struct f_inst *f1, struct f_inst *f2) case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; case P('i','M'): TWOARGS; break; case P('A','p'): TWOARGS; break; + case P('C','a'): TWOARGS; break; default: bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); } diff --git a/filter/test.conf b/filter/test.conf index a39e6a3d..abe9d3fd 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -32,6 +32,7 @@ function fifteen() function paths() bgpmask p; bgppath p2; +clist l; { p = / 4 3 2 1 /; print "Testing path masks: ", p; @@ -46,6 +47,10 @@ bgppath p2; print "Should be false: ", p2 ~ p; print "Should be true: ", p2 ~ / * 4 3 2 1 /, p2, / * 4 3 2 1 /; print "5 = ", p2.len; + + l = - empty -; + l = add( l, (1,2) ); + print "Community list ", l; } function startup() diff --git a/nest/a-set.c b/nest/a-set.c index deef5df8..1d2cebff 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -38,3 +38,46 @@ int_set_format(struct adata *set, byte *buf, unsigned int size) } *buf = 0; } + +struct adata * +int_set_add(struct linpool *pool, struct adata *list, u32 val) +{ + struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4); + res->length = list->length+4; + * (u32 *) res->data = val; + memcpy((char *) res->data + 4, list->data, list->length); + return res; +} + +int +int_set_contains(struct adata *list, u32 val) +{ + u32 *l = &(list->data); + int i; + for (i=0; i<list->length/4; i++) + if (*l++ == val) + return 1; + return 0; +} + +struct adata * +int_set_del(struct linpool *pool, struct adata *list, u32 val) +{ + struct adata *res; + u32 *l, *k; + int i; + + if (!int_set_contains(list, val)) + return list; + + res = lp_alloc(pool, list->length + sizeof(struct adata) - 4); + res->length = list->length-4; + + l = &(list->data); + k = &(res->data); + for (i=0; i<list->length/4; i++) + if (l[i] != val) + *k++ = l[i]; + + return res; +} diff --git a/nest/attrs.h b/nest/attrs.h index ede152ce..630550f3 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -29,5 +29,9 @@ int as_path_match(struct adata *path, struct f_path_mask *mask); /* a-set.c */ void int_set_format(struct adata *set, byte *buf, unsigned int size); +struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val); +int int_set_contains(struct adata *list, u32 val); +struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val); + #endif |