summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/config.Y5
-rw-r--r--filter/filter.c16
-rw-r--r--filter/test.conf5
-rw-r--r--nest/a-set.c43
-rw-r--r--nest/attrs.h4
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