summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/config.Y4
-rw-r--r--filter/test.conf1
-rw-r--r--nest/a-path.c31
-rw-r--r--nest/attrs.h4
4 files changed, 38 insertions, 2 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 8171a7c2..a67a72a8 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -801,6 +801,10 @@ bgp_path:
bgp_path_tail:
NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); $$->next = $2; }
| NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); $$->next = $4; }
+ | '[' set_items ']' bgp_path_tail {
+ if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask");
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .set = build_tree($2), .kind = PM_ASN_SET }, }); $$->next = $4;
+ }
| '*' 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_expr bgp_path_tail { $$ = $1; $$->next = $2; }
diff --git a/filter/test.conf b/filter/test.conf
index 9abd76f3..04074965 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -626,6 +626,7 @@ bgppath p2;
bt_assert(p2 !~ [8, ten..(2*ten)]);
bt_assert(p2 ~ [= * 4 3 * 1 =]);
bt_assert(p2 ~ [= (3+2) (2*2) 3 2 1 =]);
+ bt_assert(p2 ~ [= 5 [2, 4, 6] 3 [1..2] 1 =]);
bt_assert(p2 ~ mkpath(5, 4));
bt_assert(p2.len = 5);
diff --git a/nest/a-path.c b/nest/a-path.c
index a1b7c42f..4ee34cf4 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -740,6 +740,31 @@ pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
return 0;
}
+static int
+pm_match_set(struct pm_pos *pos, struct f_tree *set)
+{
+ struct f_val asn = { .type = T_INT };
+
+ if (! pos->set)
+ {
+ asn.val.i = pos->val.asn;
+ return !!find_tree(set, &asn);
+ }
+
+ const u8 *p = pos->val.sp;
+ int len = *p++;
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ asn.val.i = get_as(p + i * BS);
+ if (find_tree(set, &asn))
+ return 1;
+ }
+
+ return 0;
+}
+
static void
pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
{
@@ -824,13 +849,17 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
val2 = mask->item[m].to;
goto step;
case PM_QUESTION:
+ case PM_ASN_SET:
step:
nh = nl = -1;
for (i = h; i >= l; i--)
if (pos[i].mark)
{
pos[i].mark = 0;
- if ((mask->item[m].kind == PM_QUESTION) || pm_match(pos + i, val, val2))
+ if ((mask->item[m].kind == PM_QUESTION) ||
+ ((mask->item[m].kind != PM_ASN_SET) ?
+ pm_match(pos + i, val, val2) :
+ pm_match_set(pos + i, mask->item[m].set)))
pm_mark(pos, i, plen, &nl, &nh);
}
diff --git a/nest/attrs.h b/nest/attrs.h
index 4efcff79..a17b8c05 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -60,16 +60,18 @@ static inline struct adata *as_path_prepend(struct linpool *pool, const struct a
#define PM_ASTERISK 2
#define PM_ASN_EXPR 3
#define PM_ASN_RANGE 4
+#define PM_ASN_SET 5
struct f_path_mask_item {
union {
u32 asn; /* PM_ASN */
struct f_line *expr; /* PM_ASN_EXPR */
+ struct f_tree *set; /* PM_ASN_SET */
struct { /* PM_ASN_RANGE */
u32 from;
u32 to;
};
- };
+ };
int kind;
};