diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-08-06 16:58:13 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-08-06 16:58:13 +0200 |
commit | ef113c6f725349a2ab52f3cbef18403f82c84134 (patch) | |
tree | da3ff7453dbb76cf5cf0290135483171842a0b38 | |
parent | e2b530aa729f9c5973e498b45dd6f55ab669d1ac (diff) |
Filter: Allow to use sets in path masks
-rw-r--r-- | filter/config.Y | 4 | ||||
-rw-r--r-- | filter/test.conf | 1 | ||||
-rw-r--r-- | nest/a-path.c | 31 | ||||
-rw-r--r-- | nest/attrs.h | 4 |
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; }; |