diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2020-05-18 16:25:08 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2020-05-18 16:25:08 +0200 |
commit | ec430a7feefd3b32ee39c641a48c44528d0eab25 (patch) | |
tree | 2faac868b9ad1daddc3bea6253ac7d1de7560323 /filter | |
parent | 5fc8407177fd34f2d57441a8ff9a068f4162fbfb (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.Y | 1 | ||||
-rw-r--r-- | filter/data.c | 11 | ||||
-rw-r--r-- | filter/f-inst.c | 11 | ||||
-rw-r--r-- | filter/test.conf | 11 |
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"); |