summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2020-05-18 16:25:08 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2020-05-18 16:25:08 +0200
commitec430a7feefd3b32ee39c641a48c44528d0eab25 (patch)
tree2faac868b9ad1daddc3bea6253ac7d1de7560323 /filter
parent5fc8407177fd34f2d57441a8ff9a068f4162fbfb (diff)
Nest: Implement BGP path mask loop operator
Implement regex-like '+' operator in BGP path masks to match previous path mask item multiple times. This is useful as ASNs may appear multiple times in paths due to path prepending for traffic engineering purposes.
Diffstat (limited to 'filter')
-rw-r--r--filter/config.Y1
-rw-r--r--filter/data.c11
-rw-r--r--filter/f-inst.c11
-rw-r--r--filter/test.conf11
4 files changed, 32 insertions, 2 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 77424a8b..557a951f 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -662,6 +662,7 @@ bgp_path_tail:
}
| '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
| '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
+ | '+' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; }
| bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
| { $$ = NULL; }
;
diff --git a/filter/data.c b/filter/data.c
index 62edd9e0..40220255 100644
--- a/filter/data.c
+++ b/filter/data.c
@@ -93,6 +93,8 @@ adata_empty(struct linpool *pool, int l)
static void
pm_format(const struct f_path_mask *p, buffer *buf)
{
+ int loop = 0;
+
buffer_puts(buf, "[= ");
for (uint i=0; i<p->len; i++)
@@ -111,6 +113,10 @@ pm_format(const struct f_path_mask *p, buffer *buf)
buffer_puts(buf, "* ");
break;
+ case PM_LOOP:
+ loop = 1;
+ break;
+
case PM_ASN_RANGE:
buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
break;
@@ -119,6 +125,11 @@ pm_format(const struct f_path_mask *p, buffer *buf)
ASSERT(0);
}
+ if (loop && (p->item[i].kind != PM_LOOP))
+ {
+ buffer_puts(buf, "+ ");
+ loop = 0;
+ }
}
buffer_puts(buf, "=]");
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 63a6bdab..df908e26 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -311,6 +311,17 @@
for (uint i=0; i<whati->varcount; i++) {
switch (vv(i).type) {
case T_PATH_MASK_ITEM:
+ if (vv(i).val.pmi.kind == PM_LOOP)
+ {
+ if (i == 0)
+ runtime("Path mask iterator '+' cannot be first");
+
+ /* We want PM_LOOP as prefix operator */
+ pm->item[i] = pm->item[i - 1];
+ pm->item[i - 1] = vv(i).val.pmi;
+ break;
+ }
+
pm->item[i] = vv(i).val.pmi;
break;
diff --git a/filter/test.conf b/filter/test.conf
index 634816fd..63af25bb 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -646,7 +646,6 @@ int set set12;
bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 1), 2), 4), 5));
bt_assert(filter(p2, [1..3]) = prepend(prepend(prepend(+empty+, 1), 2), 3));
- pm1 = [= 1 2 * 3 4 5 =];
p2 = prepend( + empty +, 5 );
p2 = prepend( p2, 4 );
p2 = prepend( p2, 3 );
@@ -654,9 +653,17 @@ int set set12;
p2 = prepend( p2, 2 );
p2 = prepend( p2, 1 );
- bt_assert(p2 ~ pm1);
+ bt_assert(p2 !~ [= 1 2 3 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 * 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 * 3 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 3+ 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 3+ 4+ 5 =]);
+ bt_assert(p2 !~ [= 1 2 3+ 5+ 4 5 =]);
+ bt_assert(p2 !~ [= 1 2 3 3 5+ 4 5 =]);
bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 5), 4), 2), 1));
bt_assert(delete(p2, [4..5]) = prepend(prepend(prepend(prepend(+empty+, 3), 3), 2), 1));
+
+ bt_assert(format([= 1 2+ 3 =]) = "[= 1 2 + 3 =]");
}
bt_test_suite(t_path, "Testing paths");