table ip x { set y { type inet_service flags interval elements = { 10, 20-30, 40, 50-60 } } } # nft get element x y { 20-40 } table ip x { set y { type inet_service flags interval elements = { 20-40 } } } 20 and 40 exist in the tree, but they are part of different ranges. This patch adds a new get_set_decompose() function to validate that the left and the right side of the range. Reported-by: Phil Sutter <phil@xxxxxx> Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/expression.h | 2 +- src/netlink.c | 5 +++-- src/segtree.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/include/expression.h b/include/expression.h index fb52abfea76e..d6977c3ae62e 100644 --- a/include/expression.h +++ b/include/expression.h @@ -453,7 +453,7 @@ extern void interval_map_decompose(struct expr *set); extern struct expr *get_set_intervals(const struct set *set, const struct expr *init); struct table; -extern void get_set_decompose(struct table *table, struct set *set); +extern int get_set_decompose(struct table *table, struct set *set); extern struct expr *mapping_expr_alloc(const struct location *loc, struct expr *from, struct expr *to); diff --git a/src/netlink.c b/src/netlink.c index f795d984084b..7c3082bb4dc5 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1361,8 +1361,9 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h, nftnl_set_free(nls_out); ctx->set = NULL; - if (set->flags & NFT_SET_INTERVAL) - get_set_decompose(table, set); + if (set->flags & NFT_SET_INTERVAL && + get_set_decompose(table, set) < 0) + return -1; return 0; } diff --git a/src/segtree.c b/src/segtree.c index 8a8aa71e8a6e..0e40635a592d 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -641,6 +641,43 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) return new_init; } +static struct expr *get_set_interval_find(const struct table *table, + const char *set_name, + struct expr *left, + struct expr *right) +{ + struct expr *range = NULL; + struct set *set; + mpz_t low, high; + struct expr *i; + + set = set_lookup(table, set_name); + mpz_init2(low, set->key->len); + mpz_init2(high, set->key->len); + + list_for_each_entry(i, &set->init->expressions, list) { + switch (i->key->ops->type) { + case EXPR_RANGE: + range_expr_value_low(low, i); + range_expr_value_high(high, i); + if (mpz_cmp(left->key->value, low) >= 0 && + mpz_cmp(right->key->value, high) <= 0) + range = range_expr_alloc(&internal_location, + expr_clone(left->key), + expr_clone(right->key)); + break; + break; + default: + break; + } + } + + mpz_clear(low); + mpz_clear(high); + + return range; +} + static struct expr *get_set_interval_end(const struct table *table, const char *set_name, struct expr *left) @@ -675,7 +712,7 @@ static struct expr *get_set_interval_end(const struct table *table, return left; } -void get_set_decompose(struct table *table, struct set *set) +int get_set_decompose(struct table *table, struct set *set) { struct expr *i, *next, *new; struct expr *left = NULL; @@ -688,7 +725,13 @@ void get_set_decompose(struct table *table, struct set *set) list_del(&left->list); list_del(&i->list); mpz_sub_ui(i->key->value, i->key->value, 1); - new = range_expr_alloc(&internal_location, left, i); + new = get_set_interval_find(table, set->handle.set.name, + left, i); + if (!new) { + errno = ENOENT; + return -1; + } + compound_expr_add(new_init, new); left = NULL; } else { @@ -707,6 +750,8 @@ void get_set_decompose(struct table *table, struct set *set) } set->init = new_init; + + return 0; } static bool range_is_prefix(const mpz_t range) -- 2.11.0